Comparing version 6.5.3 to 6.5.4-rc.0
import { CustomError } from 'ts-custom-error'; | ||
import { snakeCase, camelCase } from 'change-case'; | ||
import WebSocket from 'ws'; | ||
import { on } from 'events-to-async'; | ||
import { snakeCase, camelCase } from 'change-case'; | ||
@@ -276,107 +276,42 @@ class MastoUnexpectedError extends CustomError { | ||
class HttpActionDispatcher { | ||
constructor(http, params = {}) { | ||
constructor(http, hook) { | ||
this.http = http; | ||
this.params = params; | ||
this.waitForMediaAttachment = (id) => __awaiter(this, void 0, void 0, function* () { | ||
let media; | ||
const signal = AbortSignal.timeout(this.mediaTimeout); | ||
while (media == undefined) { | ||
if (signal.aborted) { | ||
throw new MastoTimeoutError(`Media processing timed out of ${this.mediaTimeout}ms`); | ||
} | ||
try { | ||
yield sleep(1000); | ||
const processing = yield this.http.get(`/api/v1/media/${id}`); | ||
if (processing.url != undefined) { | ||
media = processing; | ||
} | ||
} | ||
catch (error) { | ||
if (error instanceof MastoHttpError && error.statusCode === 404) { | ||
continue; | ||
} | ||
throw error; | ||
} | ||
} | ||
return media; | ||
}); | ||
this.hook = hook; | ||
} | ||
dispatch(action) { | ||
const actionType = this.toPrimitiveAction(action.type); | ||
const path = this.isPrimitiveAction(action.type) | ||
? action.path | ||
: action.path + "/" + snakeCase(action.type); | ||
const encoding = this.inferEncoding(actionType, path); | ||
const meta = Object.assign(Object.assign({}, action.meta), { encoding }); | ||
switch (actionType) { | ||
if (this.hook != undefined) { | ||
action = this.hook.beforeDispatch(action); | ||
} | ||
let result; | ||
switch (action.type) { | ||
case "fetch": { | ||
return this.http.get(path, action.data, meta); | ||
result = this.http.get(action.path, action.data, action.meta); | ||
break; | ||
} | ||
case "create": { | ||
if (path === "/api/v2/media") { | ||
return this.http | ||
.post(path, action.data, meta) | ||
.then((media) => { | ||
return this.waitForMediaAttachment(media.id); | ||
}); | ||
} | ||
return this.http.post(path, action.data, meta); | ||
result = this.http.post(action.path, action.data, action.meta); | ||
break; | ||
} | ||
case "update": { | ||
return this.http.patch(path, action.data, meta); | ||
result = this.http.patch(action.path, action.data, action.meta); | ||
break; | ||
} | ||
case "remove": { | ||
return this.http.delete(path, action.data, meta); | ||
result = this.http.delete(action.path, action.data, action.meta); | ||
break; | ||
} | ||
case "list": { | ||
return new PaginatorHttp(this.http, path, action.data); | ||
result = new PaginatorHttp(this.http, action.path, action.data); | ||
break; | ||
} | ||
} | ||
} | ||
isPrimitiveAction(action) { | ||
switch (action) { | ||
case "fetch": | ||
case "create": | ||
case "update": | ||
case "remove": | ||
case "list": { | ||
return true; | ||
} | ||
default: { | ||
return false; | ||
} | ||
/* eslint-disable unicorn/prefer-ternary, prettier/prettier */ | ||
if (result instanceof Promise) { | ||
return result.then((result) => { var _a; return (_a = this.hook) === null || _a === void 0 ? void 0 : _a.afterDispatch(action, result); }); | ||
} | ||
} | ||
toPrimitiveAction(action) { | ||
if (this.isPrimitiveAction(action)) { | ||
return action; | ||
else { | ||
return this.hook.afterDispatch(action, result); | ||
} | ||
switch (action) { | ||
case "lookup": | ||
case "verify_credentials": { | ||
return "fetch"; | ||
} | ||
case "update_credentials": { | ||
return "update"; | ||
} | ||
default: { | ||
return "create"; | ||
} | ||
} | ||
/* eslint-enable unicorn/prefer-ternary, prettier/prettier */ | ||
} | ||
inferEncoding(action, path) { | ||
if ((action === "create" && path === "/api/v1/accounts") || | ||
(action === "update" && path === "/api/v1/accounts/update_credentials") || | ||
(action === "create" && path === "/api/v1/email") || | ||
(action === "create" && path === "/api/v1/featured_tag") || | ||
(action === "create" && path === "/api/v1/media") || | ||
(action === "create" && path === "/api/v2/media")) { | ||
return "multipart-form"; | ||
} | ||
return "json"; | ||
} | ||
get mediaTimeout() { | ||
var _a; | ||
return (_a = this.params.mediaTimeout) !== null && _a !== void 0 ? _a : 60 * 1000; | ||
} | ||
} | ||
@@ -676,7 +611,13 @@ | ||
const createActionProxy = (actionDispatcher, context = []) => { | ||
return new Proxy(noop, { | ||
const createActionProxy = (actionDispatcher, options = {}) => { | ||
const { context = [], applicable = false } = options; | ||
let target = {}; | ||
const handler = { | ||
get: get(actionDispatcher, context), | ||
apply: apply(actionDispatcher, context), | ||
}); | ||
}; | ||
if (applicable) { | ||
target = noop; | ||
handler.apply = apply(actionDispatcher, context); | ||
} | ||
return new Proxy(target, handler); | ||
}; | ||
@@ -709,12 +650,16 @@ const SPECIAL_PROPERTIES = new Set([ | ||
} | ||
if (property === "$select") { | ||
return createActionProxy(actionDispatcher, [...context, property]); | ||
if (property.startsWith("$")) { | ||
return createActionProxy(actionDispatcher, { | ||
context: [...context, property], | ||
applicable: true, | ||
}); | ||
} | ||
return createActionProxy(actionDispatcher, [ | ||
...context, | ||
snakeCase(property), | ||
]); | ||
return createActionProxy(actionDispatcher, { | ||
context: [...context, snakeCase(property)], | ||
applicable: true, | ||
}); | ||
}; | ||
const apply = (actionDispatcher, context) => (_1, _2, args) => { | ||
const action = context.pop(); | ||
/* istanbul ignore next */ | ||
if (action == undefined) { | ||
@@ -724,6 +669,6 @@ throw new Error("No action specified"); | ||
if (action === "$select") { | ||
return createActionProxy(actionDispatcher, [ | ||
...context, | ||
...args, | ||
]); | ||
return createActionProxy(actionDispatcher, { | ||
context: [...context, ...args], | ||
applicable: true, | ||
}); | ||
} | ||
@@ -740,2 +685,81 @@ const path = "/" + context.join("/"); | ||
function isHttpActionType(actionType) { | ||
return ["fetch", "create", "update", "remove", "list"].includes(actionType); | ||
} | ||
function toHttpActionType(action) { | ||
if (isHttpActionType(action)) { | ||
return action; | ||
} | ||
switch (action) { | ||
case "lookup": | ||
case "verify_credentials": { | ||
return "fetch"; | ||
} | ||
case "update_credentials": { | ||
return "update"; | ||
} | ||
default: { | ||
return "create"; | ||
} | ||
} | ||
} | ||
function inferEncoding(action, path) { | ||
if ((action === "create" && path === "/api/v1/accounts") || | ||
(action === "update" && path === "/api/v1/accounts/update_credentials") || | ||
(action === "create" && path === "/api/v1/email") || | ||
(action === "create" && path === "/api/v1/featured_tag") || | ||
(action === "create" && path === "/api/v1/media") || | ||
(action === "create" && path === "/api/v2/media")) { | ||
return "multipart-form"; | ||
} | ||
return "json"; | ||
} | ||
function waitForMediaAttachment(id, timeout, http) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let media; | ||
const signal = AbortSignal.timeout(timeout); | ||
while (media == undefined) { | ||
if (signal.aborted) { | ||
throw new MastoTimeoutError(`Media processing timed out of ${timeout}ms`); | ||
} | ||
try { | ||
yield sleep(1000); | ||
const processing = yield http.get(`/api/v1/media/${id}`); | ||
if (processing.url != undefined) { | ||
media = processing; | ||
} | ||
} | ||
catch (error) { | ||
if (error instanceof MastoHttpError && error.statusCode === 404) { | ||
continue; | ||
} | ||
throw error; | ||
} | ||
} | ||
return media; | ||
}); | ||
} | ||
class HttpActionDispatcherHookMastodon { | ||
constructor(http, mediaTimeout = 1000 * 60) { | ||
this.http = http; | ||
this.mediaTimeout = mediaTimeout; | ||
} | ||
beforeDispatch(action) { | ||
const type = toHttpActionType(action.type); | ||
const path = isHttpActionType(action.type) | ||
? action.path | ||
: action.path + "/" + snakeCase(action.type); | ||
const encoding = inferEncoding(type, path); | ||
const meta = Object.assign(Object.assign({}, action.meta), { encoding }); | ||
return { type, path, data: action.data, meta }; | ||
} | ||
afterDispatch(action, result) { | ||
if (action.type === "create" && action.path === "/api/v2/media") { | ||
const media = result; | ||
return waitForMediaAttachment(media.id, this.mediaTimeout, this.http); | ||
} | ||
return result; | ||
} | ||
} | ||
const mergeAbortSignals = (signals) => { | ||
@@ -1151,6 +1175,7 @@ const abortController = new AbortController(); | ||
const http = new HttpNativeImpl(serializer, config, logger); | ||
const actionDispatcher = new HttpActionDispatcher(http); | ||
const actionProxy = createActionProxy(actionDispatcher, [ | ||
"api", | ||
]); | ||
const hook = new HttpActionDispatcherHookMastodon(http); | ||
const actionDispatcher = new HttpActionDispatcher(http, hook); | ||
const actionProxy = createActionProxy(actionDispatcher, { | ||
context: ["api"], | ||
}); | ||
return actionProxy; | ||
@@ -1163,6 +1188,7 @@ }; | ||
const http = new HttpNativeImpl(serializer, config, logger); | ||
const actionDispatcher = new HttpActionDispatcher(http); | ||
const actionProxy = createActionProxy(actionDispatcher, [ | ||
"oauth", | ||
]); | ||
const hook = new HttpActionDispatcherHookMastodon(http); | ||
const actionDispatcher = new HttpActionDispatcher(http, hook); | ||
const actionProxy = createActionProxy(actionDispatcher, { | ||
context: ["oauth"], | ||
}); | ||
return actionProxy; | ||
@@ -1169,0 +1195,0 @@ }; |
@@ -5,3 +5,3 @@ { | ||
"private": false, | ||
"version": "6.5.3", | ||
"version": "6.5.4-rc.0", | ||
"author": "Ryo Igarashi <n33t5hin@gmail.com>", | ||
@@ -16,3 +16,6 @@ "license": "MIT", | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"types": { | ||
"require": "./dist/index.d.cts", | ||
"import": "./dist/index.d.ts" | ||
}, | ||
"require": "./dist/index.cjs", | ||
@@ -28,3 +31,3 @@ "import": "./dist/index.js" | ||
"lint:eslint": "eslint --ext ts --report-unused-disable-directives --cache '{src,tests,test-utils}/**/*'", | ||
"lint:spellcheck": "cspell '{src,test,test-utils}/**/*.{ts,tsx,js,json,md}'", | ||
"lint:spellcheck": "cspell --quiet '{src,test,test-utils}/**/*.{ts,tsx,js,json,md}'", | ||
"build": "rollup -c rollup.config.js", | ||
@@ -40,24 +43,24 @@ "prepublishOnly": "yarn run build", | ||
"ts-custom-error": "^3.3.1", | ||
"ws": "^8.13.0" | ||
"ws": "^8.16.0" | ||
}, | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "^25.0.7", | ||
"@rollup/plugin-json": "^6.0.1", | ||
"@rollup/plugin-typescript": "^11.1.5", | ||
"@rollup/plugin-json": "^6.1.0", | ||
"@rollup/plugin-typescript": "^11.1.6", | ||
"@semantic-release/changelog": "^6.0.3", | ||
"@semantic-release/git": "^10.0.1", | ||
"@size-limit/preset-small-lib": "^10.0.1", | ||
"@types/jest": "^29.5.6", | ||
"@types/node": "^20.8.9", | ||
"@types/ws": "^8.5.8", | ||
"@typescript-eslint/eslint-plugin": "^6.9.0", | ||
"@typescript-eslint/parser": "^6.9.0", | ||
"@size-limit/preset-small-lib": "^11.0.2", | ||
"@types/jest": "^29.5.12", | ||
"@types/node": "^20.11.19", | ||
"@types/ws": "^8.5.10", | ||
"@typescript-eslint/eslint-plugin": "^7.0.2", | ||
"@typescript-eslint/parser": "^7.0.2", | ||
"conventional-changelog-conventionalcommits": "^7.0.1", | ||
"cspell": "^7.3.8", | ||
"eslint": "^8.52.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-import": "^2.29.0", | ||
"eslint-plugin-prettier": "^5.0.1", | ||
"eslint-plugin-simple-import-sort": "^10.0.0", | ||
"eslint-plugin-unicorn": "^48.0.1", | ||
"cspell": "^8.4.1", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-import": "^2.29.1", | ||
"eslint-plugin-prettier": "^5.1.3", | ||
"eslint-plugin-simple-import-sort": "^12.0.0", | ||
"eslint-plugin-unicorn": "^51.0.1", | ||
"get-port": "^5.1.1", | ||
@@ -68,4 +71,4 @@ "ioredis": "^5.3.2", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^3.0.3", | ||
"rollup": "^4.1.4", | ||
"prettier": "^3.2.5", | ||
"rollup": "^4.12.0", | ||
"rollup-plugin-auto-external": "^2.0.0", | ||
@@ -75,7 +78,7 @@ "rollup-plugin-dts": "^6.1.0", | ||
"semantic-release": "^22.0.5", | ||
"size-limit": "^10.0.1", | ||
"ts-jest": "^29.1.1", | ||
"size-limit": "^11.0.2", | ||
"ts-jest": "^29.1.2", | ||
"tslib": "^2.6.2", | ||
"typedoc": "^0.25.2", | ||
"typescript": "^5.2.2", | ||
"typedoc": "^0.25.8", | ||
"typescript": "^5.3.3", | ||
"undici": "^6.6.2" | ||
@@ -109,3 +112,8 @@ }, | ||
} | ||
] | ||
], | ||
"resolutions": { | ||
"string-width": "4.2.3", | ||
"strip-ansi": "6.0.1", | ||
"wrap-ansi": "7.0.0" | ||
} | ||
} |
@@ -24,3 +24,3 @@ <p align="center"> | ||
- ๐ **Universal:** Works in Node.js, browsers, and Deno | ||
- ๐ฆ **Lightweight:** Less runtime codes, [7kB+ minified and gzipped](https://bundlephobia.com/package/masto@6.0.0-alpha.7) | ||
- ๐ฆ **Lightweight:** Less runtime codes, [6kB+ minified and gzipped](https://bundlephobia.com/package/masto) | ||
- ๐ **TypeScript:** Written in TypeScript, and provides type definitions | ||
@@ -27,0 +27,0 @@ - ๐งช **Tested:** 99% test coverage using a real Mastodon server |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
447821
7
6451
1
Updatedws@^8.16.0