From 4792a41e30f10bb01bc3587da3a0848d3d6f2bfe Mon Sep 17 00:00:00 2001 From: mys1024 Date: Sun, 21 Apr 2024 15:56:51 +0800 Subject: [PATCH] feat!: refactor with @mys/m-rpc --- .vscode/settings.json | 3 +- deno.json | 6 +- deno.lock | 8 ++ npm/package.json | 3 + npm/pnpm-lock.yaml | 9 ++ npm/tsconfig.json | 2 + src/define.ts | 53 ++------- src/rpc/rpc.ts | 240 -------------------------------------- src/rpc/types.ts | 55 --------- src/rpc/utils.ts | 24 ---- src/types.ts | 54 +++------ src/use.ts | 81 ++++++------- test/basic.test.ts | 50 ++------ test/basic.test.worker.ts | 6 - 14 files changed, 102 insertions(+), 492 deletions(-) delete mode 100644 src/rpc/rpc.ts delete mode 100644 src/rpc/types.ts delete mode 100644 src/rpc/utils.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 681146c..b1b41c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,11 +31,12 @@ "denoland", "lcov", "minzip", - "tsup", + "mrpc", "okikio", "pnpx", "runtimes", "Transferables", + "tsup", "typeof" ] } diff --git a/deno.json b/deno.json index 6b8080e..acbe265 100644 --- a/deno.json +++ b/deno.json @@ -6,13 +6,15 @@ "run:watch": "deno run --watch src/main.ts", "cache": "deno cache --lock-write src/**/*.ts test/**/*.ts", "cache:reload": "deno cache --lock-write --reload src/**/*.ts test/**/*.ts", - "check": "deno check src/**/*.ts test/**/*.ts && deno lint && deno fmt --check", "test": "deno test -A", "test:watch": "deno test -A --watch", "test:lcov": "deno test -A --coverage && deno coverage --lcov --output=cov.lcov", - "bump": "deno task check && deno task test && deno publish --dry-run && pnpm i -C npm && pnpm run -C npm build && pnpm publish -C npm --no-git-checks --dry-run && pnpm run -C npm clean && echo && echo ✅ Checks passed, start bumping... && echo && deno run -A jsr:@mys/bump@1" + "check:lint": "deno check src/**/*.ts test/**/*.ts && deno lint && deno fmt --check", + "check:all": "deno task check:lint && deno task test && deno publish --allow-dirty --dry-run && cd npm && pnpm i && pnpm run build && pnpm publish --no-git-checks --dry-run && pnpm run clean && echo && echo ✅ All checks passed && echo", + "bump": "deno task check:all && deno run -A jsr:@mys/bump@1" }, "imports": { + "@mys/m-rpc": "jsr:@mys/m-rpc@^0.12.1", "@okikio/transferables": "jsr:@okikio/transferables@^1.0.2", "@std/assert": "jsr:@std/assert@0.217" }, diff --git a/deno.lock b/deno.lock index 3cd0c7f..d220ec1 100644 --- a/deno.lock +++ b/deno.lock @@ -2,12 +2,19 @@ "version": "3", "packages": { "specifiers": { + "jsr:@mys/m-rpc@^0.12.1": "jsr:@mys/m-rpc@0.12.1", "jsr:@okikio/transferables@^1.0.2": "jsr:@okikio/transferables@1.0.2", "jsr:@std/assert@0.217": "jsr:@std/assert@0.217.0", "jsr:@std/fmt@^0.217.0": "jsr:@std/fmt@0.217.0", "npm:@types/node": "npm:@types/node@18.16.19" }, "jsr": { + "@mys/m-rpc@0.12.1": { + "integrity": "19a1f8e1fed7552d32bfd5be5d26f982e8cd65e4b0666d05e88fcbb1fb4be20a", + "dependencies": [ + "jsr:@okikio/transferables@^1.0.2" + ] + }, "@okikio/transferables@1.0.2": { "integrity": "46a80015a1c4672b0b246e38838b3ea1e2edc6c775a235184a2f8eb49a8314f7" }, @@ -31,6 +38,7 @@ "remote": {}, "workspace": { "dependencies": [ + "jsr:@mys/m-rpc@^0.12.1", "jsr:@okikio/transferables@^1.0.2", "jsr:@std/assert@0.217" ] diff --git a/npm/package.json b/npm/package.json index ae8e6a7..2848566 100644 --- a/npm/package.json +++ b/npm/package.json @@ -42,6 +42,9 @@ "types": "./dist/main.d.ts" } }, + "dependencies": { + "@mys/m-rpc": "npm:@mys-x/m-rpc@^0.12.1" + }, "devDependencies": { "@okikio/transferables": "npm:@jsr/okikio__transferables@^1.0.2", "tsup": "^8.0.2", diff --git a/npm/pnpm-lock.yaml b/npm/pnpm-lock.yaml index cd04d65..9cf49d0 100644 --- a/npm/pnpm-lock.yaml +++ b/npm/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + '@mys/m-rpc': + specifier: npm:@mys-x/m-rpc@^0.12.1 + version: /@mys-x/m-rpc@0.12.1 + devDependencies: '@okikio/transferables': specifier: npm:@jsr/okikio__transferables@^1.0.2 @@ -270,6 +275,10 @@ packages: resolution: {integrity: sha512-Ssz8Hd7/GtM1vIX3vRBr08d2eOBHnGG8KmW1pKe5pYvvfv7Gh8sCHWorBDOWIr9r+CoSQbKU1N5yymNh9sWsXA==, tarball: https://npm.jsr.io/~/7/@jsr/okikio__transferables/1.0.2.tgz} dev: true + /@mys-x/m-rpc@0.12.1: + resolution: {integrity: sha512-TLKU3pA3ua6AwaTNnij2nW23z5ndL4qmJHhVfPruNozQ+7A4zfCtU0i+Gvmu22mRimqzDnwV0/gbUFeV/5fhhw==} + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} diff --git a/npm/tsconfig.json b/npm/tsconfig.json index d8c3d4d..df7a033 100644 --- a/npm/tsconfig.json +++ b/npm/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", "allowImportingTsExtensions": true } } diff --git a/src/define.ts b/src/define.ts index 12e13e8..72c0262 100644 --- a/src/define.ts +++ b/src/define.ts @@ -1,10 +1,5 @@ -import type { AnyFn, DefineWorkerFnOpts, InternalFns } from "./types.ts"; -import type { MsgPort, MsgPortNormalized } from "./rpc/types.ts"; -import { RpcAgent } from "./rpc/rpc.ts"; - -/* -------------------------------------------------- common -------------------------------------------------- */ - -const _global = Function("return this")() as MsgPortNormalized; +import { MRpc } from "@mys/m-rpc"; +import type { AnyFn, DefineOptions, WorkerGlobalScope } from "./types.ts"; /* -------------------------------------------------- defineWorkerFn() -------------------------------------------------- */ @@ -18,15 +13,14 @@ const _global = Function("return this")() as MsgPortNormalized; export function defineWorkerFn( name: string, fn: FN, - options: DefineWorkerFnOpts = {}, + options: DefineOptions = {}, ): void { - const { transfer, port = _global } = options; - const rpcAgent = RpcAgent.getRpcAgent(port); - ensureInternalFns(port); - rpcAgent.defineLocalFn(name, fn, { - namespace: "fn", - transfer, - }); + const { + port = globalThis as unknown as WorkerGlobalScope, + ...restOptions + } = options; + const rpc = MRpc.ensureMRpc(port); + rpc.defineLocalFn(name, fn, restOptions); } /* -------------------------------------------------- defineWorkerFns() -------------------------------------------------- */ @@ -40,37 +34,10 @@ export function defineWorkerFn( export function defineWorkerFns>( functions: FNS, options: { - [NAME in keyof FNS]?: DefineWorkerFnOpts; + [NAME in keyof FNS]?: DefineOptions; } = {}, ): void { for (const [name, fn] of Object.entries(functions)) { defineWorkerFn(name, fn, options[name]); } } - -/* -------------------------------------------------- internal functions -------------------------------------------------- */ - -const INTERNAL_FNS_DEFINED = Symbol("internalFnsDefined"); - -/** - * Ensure that internal functions are defined. - */ -function ensureInternalFns(port: MsgPort) { - // prevent double usage - if ((port as any)[INTERNAL_FNS_DEFINED]) { - return; - } - (port as any)[INTERNAL_FNS_DEFINED] = true; - // get RpcAgent instance - const rpcAgent = RpcAgent.getRpcAgent(port); - // define internal functions - const internalFns: InternalFns = { - /** - * @returns Names of defined worker functions - */ - names: () => rpcAgent.getLocalFnNames("fn"), - }; - for (const [name, fn] of Object.entries(internalFns)) { - rpcAgent.defineLocalFn(name, fn, { namespace: "fn-internal" }); - } -} diff --git a/src/rpc/rpc.ts b/src/rpc/rpc.ts deleted file mode 100644 index 4bdb700..0000000 --- a/src/rpc/rpc.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { getTransferables, isSupported } from "@okikio/transferables"; -import type { - AnyFn, - AwaitedRet, - MsgPort, - MsgPortNormalized, - RpcCallMsg, - RpcReturnMsg, -} from "./types.ts"; -import { isRpcCallMsg, isRpcReturnMsg, toMsgPortNormalized } from "./utils.ts"; - -const DEFAULT_NAMESPACE = "rpc"; -const RPC_AGENT = Symbol("rpcAgent"); - -// Support flags for features like streams and channels, -// we want to confirm if streams and channels are transferable -// transferables aren't supported the same way across all browsers and runtimes, -// in some runtimes it's more like partial support -let supportFlags: Awaited> = { - streams: false, - channel: false, -}; -isSupported().then((res) => (supportFlags = res)); - -export class RpcAgent { - #msgPort: MsgPortNormalized; - #callCount = 0; - - /** namespace -> name -> fnConf */ - #localFns = new Map< - string, - Map Transferable[]); - }> - >(); - - /** namespace -> key -> callCtx */ - #remoteFnCalls = new Map< - string, - Map void; - reject: (err: any) => void; - }> - >(); - - static getRpcAgent(msgPort: MsgPort): RpcAgent { - return (msgPort as any)[RPC_AGENT] || new RpcAgent(msgPort); - } - - constructor(msgPort: MsgPort) { - // prevent double usage - if ((msgPort as any)[RPC_AGENT]) { - throw new Error( - "The MsgPort has already been used by another RpcAgent instance, invoke `RpcAgent.getRpcAgent()` to get that RpcAgent instance instead.", - ); - } - (msgPort as any)[RPC_AGENT] = this; - // init properties - this.#msgPort = toMsgPortNormalized(msgPort); - // start listening to messages - this.#startListening(); - } - - defineLocalFn(name: string, fn: FN, options: { - namespace?: string; - transfer?: boolean | ((ctx: { ret: ReturnType }) => Transferable[]); - } = {}) { - const { namespace = DEFAULT_NAMESPACE, transfer = true } = options; - - const nameFnMap = this.#getNameFnMap(namespace, true); - - if (nameFnMap.has(name)) { - throw new Error( - `The name "${name}" has already been defined in namespace "${namespace}".`, - ); - } else { - nameFnMap.set(name, { fn, transfer }); - } - } - - callRemoteFn(name: string, args: Parameters, options: { - namespace?: string; - transfer?: boolean | ((ctx: { args: Parameters }) => Transferable[]); - } = {}) { - const { namespace = DEFAULT_NAMESPACE, transfer = true } = options; - - const keyCallMap = this.#getKeyCallMap(namespace, true); - - const key = ++this.#callCount; - const ret = new Promise>((resolve, reject) => { - keyCallMap.set(key, { resolve, reject }); - }); - - this.#sendCallMsg({ - ns: namespace, - name, - key, - type: "call", - args, - }, { - transfer: transfer - ? transfer === true - ? getTransferables(args, supportFlags.streams) - : transfer?.({ args }) - : undefined, - }); - - return ret; - } - - getLocalFnNames(namespace = DEFAULT_NAMESPACE) { - const nameFnMap = this.#getNameFnMap(namespace, false); - return nameFnMap ? Array.from(nameFnMap.keys()) : []; - } - - #getNameFnMap(namespace: string, ensure: E) { - let nameFnMap = this.#localFns.get(namespace); - if (!nameFnMap && ensure) { - nameFnMap = new Map(); - this.#localFns.set(namespace, nameFnMap); - } - return nameFnMap as E extends true ? Exclude - : typeof nameFnMap; - } - - #getKeyCallMap(namespace: string, ensure: E) { - let keyCallMap = this.#remoteFnCalls.get(namespace); - if (!keyCallMap && ensure) { - keyCallMap = new Map(); - this.#remoteFnCalls.set(namespace, keyCallMap); - } - return keyCallMap as E extends true ? Exclude - : typeof keyCallMap; - } - - #sendCallMsg(msg: RpcCallMsg, options: { - transfer?: Transferable[]; - } = {}) { - const { transfer } = options; - this.#msgPort.postMessage(msg, { transfer }); - } - - #sendReturnMsg(msg: RpcReturnMsg, options: { - transfer?: Transferable[]; - } = {}) { - const { transfer } = options; - this.#msgPort.postMessage(msg, { transfer }); - } - - #startListening() { - this.#msgPort.addEventListener("message", async (event) => { - if (isRpcCallMsg(event.data)) { - const { ns, name, key, args } = event.data; - // get the local function - const nameFnMap = this.#getNameFnMap(ns, false); - if (!nameFnMap) { - this.#sendReturnMsg({ - type: "return", - ns, - name, - key, - ok: false, - err: new Error(`The namespace "${ns}" is not defined.`), - }); - return; - } - const fnConf = nameFnMap.get(name); - if (!fnConf) { - this.#sendReturnMsg({ - type: "return", - ns, - name, - key, - ok: false, - err: new Error( - `The name "${name}" is not defined in namespace "${ns}".`, - ), - }); - return; - } - const { fn, transfer } = fnConf; - // invoke the local function - try { - const ret = await fn(...args); - this.#sendReturnMsg({ - type: "return", - ns, - name, - key, - ok: true, - ret, - }, { - // If the function is marked for transferring data, it uses `getTransferables` to grab none cloneable data, - // transferables exist due to them not being able to be cloned, so to ensure in a complex object we grab all the - // transferables that can't be cloned we traverse the entire object finding all transferables, and listing them to be transferred - transfer: transfer - ? transfer === true - ? getTransferables(ret, supportFlags.streams) - : transfer?.({ ret }) - : undefined, - }); - } catch (err) { - this.#sendReturnMsg({ - type: "return", - ns, - name, - key, - ok: false, - err, - }); - } - } else if (isRpcReturnMsg(event.data)) { - const { ns, name, key, ok, ret, err } = event.data; - // get the promise resolvers - const keyCallMap = this.#getKeyCallMap(ns, false); - if (!keyCallMap) { - return; - } - const callCtx = keyCallMap.get(key); - if (!callCtx) { - return; - } - // resolve the promise - const { resolve, reject } = callCtx; - if (ok) { - resolve(ret); - } else { - reject( - new Error(`The worker function "${name}" throws an exception.`, { - cause: err, - }), - ); - } - // clean up - keyCallMap.delete(key); - } - }); - } -} diff --git a/src/rpc/types.ts b/src/rpc/types.ts deleted file mode 100644 index 8077f4a..0000000 --- a/src/rpc/types.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* -------------------------------------------------- general -------------------------------------------------- */ - -export type AnyFn = (...args: any[]) => any; - -export type AwaitedRet = Awaited>; - -/* -------------------------------------------------- msg -------------------------------------------------- */ - -/** - * Worker - */ -export interface MsgPortNormalized { - postMessage( - message: any, - options?: { - transfer?: Transferable[]; - }, - ): void; - addEventListener: ( - type: "message", - listener: (event: { data: any }) => any, - ) => void; -} - -/** - * node:worker_threads - */ -export interface MsgPortNode { - postMessage(value: any): void; - on(event: "message", listener: (value: any) => void): void; -} - -export type MsgPort = MsgPortNormalized | MsgPortNode; - -/* -------------------------------------------------- RPC -------------------------------------------------- */ - -export type RpcCallMsg = { - type: "call"; - ns: string; - name: string; - key: number; - args: Parameters; -}; - -export type RpcReturnMsg = - & { - type: "return"; - ns: string; - name: string; - key: number; - } - & ( - | { ok: true; ret: Awaited>; err?: undefined } - | { ok: false; ret?: undefined; err: any } - ); diff --git a/src/rpc/utils.ts b/src/rpc/utils.ts deleted file mode 100644 index e7526e0..0000000 --- a/src/rpc/utils.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { - MsgPort, - MsgPortNormalized, - RpcCallMsg, - RpcReturnMsg, -} from "./types.ts"; - -export function isRpcCallMsg(val: any): val is RpcCallMsg { - return val?.type === "call"; -} - -export function isRpcReturnMsg(val: any): val is RpcReturnMsg { - return val?.type === "return"; -} - -export function toMsgPortNormalized(msgPort: MsgPort): MsgPortNormalized { - return "on" in msgPort - ? { - postMessage: (msg) => msgPort.postMessage(msg), - addEventListener: (type, listener) => - msgPort.on(type, (value) => listener({ data: value })), - } - : msgPort; -} diff --git a/src/types.ts b/src/types.ts index a00b9fc..f6f6e69 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,10 @@ -import type { MsgPort } from "./rpc/types.ts"; +import type { + MRpcCallOptions, + MRpcDefineOptions, + NodeWorkerOrNodeMessagePort, +} from "@mys/m-rpc"; -/* -------------------------------------------------- general -------------------------------------------------- */ +/* -------------------------------------------------- common -------------------------------------------------- */ export type AnyFn = (...args: any[]) => any; @@ -14,43 +18,21 @@ export type ProxyFns> = { [P in keyof FNS]: ProxyFn; }; -/* -------------------------------------------------- internal functions -------------------------------------------------- */ - -export type InternalFns = { - names: () => string[]; -}; +/** + * @see https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope + */ +export interface WorkerGlobalScope { + self: WorkerGlobalScope; // for preventing type error + postMessage: Worker["postMessage"]; + addEventListener: Worker["addEventListener"]; + removeEventListener: Worker["removeEventListener"]; +} /* -------------------------------------------------- options -------------------------------------------------- */ -export interface DefineWorkerFnOpts { - /** - * A boolean value indicating whether to transfer the transferable objects exist in the return value of the worker function, - * or a function that returns transferable objects should be transferred. - * - * @default true - * @see https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage#transfer - */ - transfer?: boolean | ((ctx: { ret: ReturnType }) => Transferable[]); - - /** - * The message port to communicate with the main thread. - * - * @default self - * @example - * // In Node.js - * import { parentPort } from "node:worker_threads"; - * defineWorkerFn("add", add, { port: parentPort! }); - */ - port?: MsgPort; +export interface CallOptions extends MRpcCallOptions { } -export interface UseWorkerFnOpts { - /** - * A boolean value indicating whether to transfer the transferable objects exist in the arguments, - * or a function that returns transferable objects should be transferred. - * - * @default true - * @see https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage#transfer - */ - transfer?: boolean | ((ctx: { args: Parameters }) => Transferable[]); +export interface DefineOptions extends MRpcDefineOptions { + port?: WorkerGlobalScope | NodeWorkerOrNodeMessagePort; } diff --git a/src/use.ts b/src/use.ts index 6821864..40ab322 100644 --- a/src/use.ts +++ b/src/use.ts @@ -1,12 +1,5 @@ -import type { MsgPort } from "./rpc/types.ts"; -import { RpcAgent } from "./rpc/rpc.ts"; -import type { - AnyFn, - InternalFns, - ProxyFn, - ProxyFns, - UseWorkerFnOpts, -} from "./types.ts"; +import { MRpc, type NodeWorkerOrNodeMessagePort } from "@mys/m-rpc"; +import type { AnyFn, CallOptions, ProxyFn, ProxyFns } from "./types.ts"; /* -------------------------------------------------- useWorkerFn() -------------------------------------------------- */ @@ -20,18 +13,26 @@ import type { */ export function useWorkerFn( name: string, - worker: MsgPort, - options: UseWorkerFnOpts = {}, + worker: Worker | NodeWorkerOrNodeMessagePort, + options?: CallOptions, ): ProxyFn { - const { transfer } = options; - const rpcAgent = RpcAgent.getRpcAgent(worker); - // the proxy function - function fn(...args: Parameters) { - return rpcAgent.callRemoteFn(name, args, { - namespace: "fn", - transfer, - }); - } + const rpc = MRpc.ensureMRpc(worker); + const _fn = rpc.useRemoteFn(name, options); + const fn = (async (...args) => { + try { + return await _fn(...args); + } catch (err) { + // overwrite the error message + if ( + err instanceof Error && + err.message === + `The remote threw an error when calling the function "${name}".` + ) { + err.message = `The worker function "${name}" throws an error.`; + } + throw err; + } + }) as ProxyFn; return fn; } @@ -45,26 +46,13 @@ export function useWorkerFn( * @returns Proxy functions. */ export function useWorkerFns>( - worker: MsgPort, - options: { - [NAME in keyof FNS]?: UseWorkerFnOpts; - } = {}, + worker: Worker | NodeWorkerOrNodeMessagePort, + options?: { + [NAME in keyof FNS]?: CallOptions; + }, ): ProxyFns { - const memo = new Map>(); - const fns = new Proxy({}, { - get(_target, name) { - if (typeof name !== "string") { - throw new Error("The name must be a string.", { cause: name }); - } - if (memo.has(name)) { - return memo.get(name); - } - const fn = useWorkerFn(name, worker, options[name]); - memo.set(name, fn); - return fn; - }, - }); - return fns as ProxyFns; + const rpc = MRpc.ensureMRpc(worker); + return rpc.useRemoteFns(options); } /* -------------------------------------------------- inspectWorker() -------------------------------------------------- */ @@ -75,12 +63,13 @@ export function useWorkerFns>( * @param worker A worker instance. * @returns Information about the worker. */ -export async function inspectWorker(worker: MsgPort): Promise<{ - names: string[]; +export async function inspectWorker( + worker: Worker | NodeWorkerOrNodeMessagePort, +): Promise<{ + names: string[] | undefined; }> { - const rpcAgent = RpcAgent.getRpcAgent(worker); - const names = await rpcAgent.callRemoteFn("names", [], { - namespace: "fn-internal", - }); - return { names }; + const rpc = MRpc.ensureMRpc(worker); + return { + names: await rpc.getRemoteFnNames(), + }; } diff --git a/test/basic.test.ts b/test/basic.test.ts index ac9f34e..7182898 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1,6 +1,6 @@ -import { assertEquals } from "@std/assert"; +import { assertEquals, assertIsError } from "@std/assert"; import { useWorkerFn } from "../src/main.ts"; -import type { Add, Fib, Redefine, ThrowErr } from "./basic.test.worker.ts"; +import type { Add, Fib, ThrowErr } from "./basic.test.worker.ts"; import type { Add as Add2 } from "./basic.test.worker.another.ts"; Deno.test({ @@ -48,43 +48,15 @@ Deno.test({ try { await throwErr("This is an error threw by the worker function!"); } catch (err) { - assertEquals( - (err as Error).message, - 'The worker function "throwErr" throws an exception.', - ); - } - }); - - await t.step("no undefined name", async () => { - const undefinedName = useWorkerFn( - "undefinedName", - new Worker(new URL("./basic.test.worker.ts", import.meta.url), { - type: "module", - }), - ); - try { - await undefinedName(); - } catch (err) { - assertEquals( - ((err as Error).cause as Error).message, - 'The name "undefinedName" is not defined in namespace "fn".', + assertIsError( + err, + undefined, + 'The worker function "throwErr" throws an error.', ); - } - }); - - await t.step("no redefined name", async () => { - const redefine = useWorkerFn( - "redefine", - new Worker(new URL("./basic.test.worker.ts", import.meta.url), { - type: "module", - }), - ); - try { - await redefine(); - } catch (err) { - assertEquals( - ((err as Error).cause as Error).message, - 'The name "redefine" has already been defined in namespace "fn".', + assertIsError( + err.cause, + undefined, + "This is an error threw by the worker function!", ); } }); @@ -112,7 +84,7 @@ Deno.test({ } catch (err) { assertEquals( ((err as Error).cause as Error).message, - 'The name "fib" is not defined in namespace "fn".', + 'The function name "fib" is not defined.', ); } }); diff --git a/test/basic.test.worker.ts b/test/basic.test.worker.ts index f91bdc7..903ddb3 100644 --- a/test/basic.test.worker.ts +++ b/test/basic.test.worker.ts @@ -12,16 +12,10 @@ function throwErr(msg: string) { throw new Error(msg); } -function redefine() { - defineWorkerFn("redefine", redefine); -} - defineWorkerFn("add", add); defineWorkerFn("fib", fib); defineWorkerFn("throwErr", throwErr); -defineWorkerFn("redefine", redefine); export type Add = typeof add; export type Fib = typeof fib; export type ThrowErr = typeof throwErr; -export type Redefine = typeof redefine;