@kirill.konshin/worker 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -13
- package/dist/worker.js +238 -220
- package/dist/worker.js.map +1 -1
- package/dist/workerUtils.js +22 -26
- package/dist/workerUtils.js.map +1 -1
- package/dist/wrpc.d.ts +1 -0
- package/dist/wrpc.d.ts.map +1 -1
- package/dist/wrpc.fixture.d.ts +26 -22
- package/dist/wrpc.fixture.d.ts.map +1 -1
- package/dist/wrpc.js +238 -235
- package/dist/wrpc.js.map +1 -1
- package/package.json +14 -4
- package/.ctirc +0 -20
- package/.turbo/turbo-build.log +0 -22
- package/.turbo/turbo-test.log +0 -97
- package/CHANGELOG.md +0 -7
- package/dist/index.js.map +0 -1
- package/src/index.ts +0 -3
- package/src/worker.test.ts +0 -197
- package/src/worker.ts +0 -347
- package/src/workerUtils.ts +0 -32
- package/src/wrpc.fixture.ts +0 -106
- package/src/wrpc.test.ts +0 -225
- package/src/wrpc.ts +0 -377
- package/tsconfig.json +0 -10
- package/turbo.json +0 -10
- package/vite.config.ts +0 -2
package/dist/workerUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workerUtils.js","sources":["../src/workerUtils.ts"],"sourcesContent":["const g = globalThis;\n\n// @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\nconst transferrable = [\n g.ArrayBuffer,\n g.MessagePort,\n g.ReadableStream,\n g.WritableStream,\n g.TransformStream,\n // WebTransportReceiveStream, // ReferenceError: WebTransportReceiveStream is not defined\n // WebTransportSendStream, // ReferenceError: WebTransportReceiveStream is not defined\n // AudioData, // TS2304: Cannot find name AudioData\n g.ImageBitmap,\n g.VideoFrame,\n g.OffscreenCanvas,\n g.RTCDataChannel,\n g.MediaSourceHandle,\n // MIDIAccess, // ReferenceError: MIDIAccess is not defined\n].filter(Boolean);\n\nexport function isTransferable(obj: any): typeof obj | null {\n return transferrable.some((t) => obj instanceof t) ? obj : null;\n}\n\nexport function getTransferrable(data: any = {}): Transferable[] {\n if (!data) return [];\n return Object.values<any>(data)\n .reduce((r, v) => {\n return Array.isArray(v) ? [...r, ...v.map(isTransferable)] : [...r, isTransferable(v)];\n }, [])\n .filter(Boolean);\n}\n"],"
|
|
1
|
+
{"version":3,"file":"workerUtils.js","names":[],"sources":["../src/workerUtils.ts"],"sourcesContent":["const g = globalThis;\n\n// @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\nconst transferrable = [\n g.ArrayBuffer,\n g.MessagePort,\n g.ReadableStream,\n g.WritableStream,\n g.TransformStream,\n // WebTransportReceiveStream, // ReferenceError: WebTransportReceiveStream is not defined\n // WebTransportSendStream, // ReferenceError: WebTransportReceiveStream is not defined\n // AudioData, // TS2304: Cannot find name AudioData\n g.ImageBitmap,\n g.VideoFrame,\n g.OffscreenCanvas,\n g.RTCDataChannel,\n g.MediaSourceHandle,\n // MIDIAccess, // ReferenceError: MIDIAccess is not defined\n].filter(Boolean);\n\nexport function isTransferable(obj: any): typeof obj | null {\n return transferrable.some((t) => obj instanceof t) ? obj : null;\n}\n\nexport function getTransferrable(data: any = {}): Transferable[] {\n if (!data) return [];\n return Object.values<any>(data)\n .reduce((r, v) => {\n return Array.isArray(v) ? [...r, ...v.map(isTransferable)] : [...r, isTransferable(v)];\n }, [])\n .filter(Boolean);\n}\n"],"mappings":";AAAA,IAAM,IAAI;AAGV,IAAM,gBAAgB;CAClB,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CAIF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;AAEN,CAAC,CAAC,OAAO,OAAO;AAEhB,SAAgB,eAAe,KAA6B;CACxD,OAAO,cAAc,MAAM,MAAM,eAAe,CAAC,IAAI,MAAM;AAC/D;AAEA,SAAgB,iBAAiB,OAAY,CAAC,GAAmB;CAC7D,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,OAAO,OAAO,OAAY,IAAI,CAAC,CAC1B,QAAQ,GAAG,MAAM;EACd,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,EAAE,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;CACzF,GAAG,CAAC,CAAC,CAAC,CACL,OAAO,OAAO;AACvB"}
|
package/dist/wrpc.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export declare enum LogLevel {
|
|
|
32
32
|
}
|
|
33
33
|
export declare function deriveController(signal?: AbortSignal): [AbortController, AbortSignal];
|
|
34
34
|
export declare function rejectOnSignal(promise: Promise<any>, signal: AbortSignal): Promise<Event['data']>;
|
|
35
|
+
export declare const RESERVED_NAMES: string[];
|
|
35
36
|
export declare function wrpc({ debug, name, }?: {
|
|
36
37
|
debug?: LogLevel;
|
|
37
38
|
name?: string;
|
package/dist/wrpc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrpc.d.ts","sourceRoot":"","sources":["../src/wrpc.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;CAAE,CAAC;AAErH,MAAM,MAAM,OAAO,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,GAAG,GAAG,KAAK,CAAA;CAAE,CAAC,CAAC;AAEzE,MAAM,MAAM,UAAU,GAAG;IACrB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACzD,gBAAgB,EAAE,CACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,EAC1B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KACjD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC;CAC5E,GAAG,GAAG,CAAC;AAER,oBAAY,QAAQ;IAChB,QAAQ,IAAI;IACZ,KAAK,IAAI;IACT,SAAS,IAAI;IACb,MAAM,IAAI;IACV,SAAS,IAAI;CAChB;AAID,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC,CAGrF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"wrpc.d.ts","sourceRoot":"","sources":["../src/wrpc.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;CAAE,CAAC;AAErH,MAAM,MAAM,OAAO,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,GAAG,GAAG,KAAK,CAAA;CAAE,CAAC,CAAC;AAEzE,MAAM,MAAM,UAAU,GAAG;IACrB,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACzD,gBAAgB,EAAE,CACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,EAC1B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KACjD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC;CAC5E,GAAG,GAAG,CAAC;AAER,oBAAY,QAAQ;IAChB,QAAQ,IAAI;IACZ,KAAK,IAAI;IACT,SAAS,IAAI;IACb,MAAM,IAAI;IACV,SAAS,IAAI;CAChB;AAID,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC,CAGrF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAajG;AAOD,eAAO,MAAM,cAAc,EAAE,MAAM,EAAsE,CAAC;AAU1G,wBAAgB,IAAI,CAAC,EACjB,KAAyB,EACzB,IAAiE,GACpE,GAAE;IACC,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACZ,GAAG;IACL,eAAe,EAAE,CAAC,CAAC,SAAS,UAAU,EAClC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,CAAC,KACZ;QACD,UAAU,EAAE,CAAC,CAAC;QACd,IAAI,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IACF,YAAY,EAAE,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;CAChF,CA6VA"}
|
package/dist/wrpc.fixture.d.ts
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
|
+
declare const responders: {
|
|
2
|
+
test: ({ buf, signal }?: {
|
|
3
|
+
signal?: AbortSignal;
|
|
4
|
+
buf?: ArrayBuffer;
|
|
5
|
+
}) => Generator<{
|
|
6
|
+
progress: number;
|
|
7
|
+
aborted?: boolean;
|
|
8
|
+
}, string, unknown>;
|
|
9
|
+
returnYield: () => Generator<1 | 3 | 2, any, unknown>;
|
|
10
|
+
bidirectional: (prefix?: number) => Generator<string, string, number>;
|
|
11
|
+
error: () => AsyncGenerator<never, never, unknown>;
|
|
12
|
+
promise: () => Promise<{
|
|
13
|
+
test: string;
|
|
14
|
+
}>;
|
|
15
|
+
promiseError: () => Promise<never>;
|
|
16
|
+
setTimeout: ({ timeout }?: {
|
|
17
|
+
timeout?: number;
|
|
18
|
+
}) => Promise<unknown>;
|
|
19
|
+
setInterval: ({ timeout }?: {
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}) => AsyncGenerator<unknown, never, unknown>;
|
|
22
|
+
cleanupGen: () => AsyncGenerator<number, void, unknown>;
|
|
23
|
+
wasCleaned: () => Promise<boolean>;
|
|
24
|
+
};
|
|
1
25
|
export declare const responder: {
|
|
2
|
-
responders:
|
|
3
|
-
test: ({ buf, signal }?: {
|
|
4
|
-
signal?: AbortSignal;
|
|
5
|
-
buf?: ArrayBuffer;
|
|
6
|
-
}) => Generator<{
|
|
7
|
-
progress: number;
|
|
8
|
-
aborted?: boolean;
|
|
9
|
-
}, string, unknown>;
|
|
10
|
-
returnYield: () => Generator<1 | 3 | 2, any, unknown>;
|
|
11
|
-
bidirectional: (prefix?: any) => Generator<string, string, number>;
|
|
12
|
-
error: () => AsyncGenerator<never, never, unknown>;
|
|
13
|
-
promise: () => Promise<{
|
|
14
|
-
test: string;
|
|
15
|
-
}>;
|
|
16
|
-
promiseError: () => Promise<never>;
|
|
17
|
-
setTimeout: ({ timeout }?: {
|
|
18
|
-
timeout?: number;
|
|
19
|
-
}) => Promise<unknown>;
|
|
20
|
-
setInterval: ({ timeout }?: {
|
|
21
|
-
timeout?: number;
|
|
22
|
-
}) => AsyncGenerator<any, never, unknown>;
|
|
23
|
-
};
|
|
26
|
+
responders: typeof responders;
|
|
24
27
|
stop: () => void;
|
|
25
28
|
};
|
|
29
|
+
export {};
|
|
26
30
|
//# sourceMappingURL=wrpc.fixture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrpc.fixture.d.ts","sourceRoot":"","sources":["../src/wrpc.fixture.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrpc.fixture.d.ts","sourceRoot":"","sources":["../src/wrpc.fixture.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,UAAU;6BAEsB;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,GAAG,CAAC,EAAE,WAAW,CAAA;KAAE,KAAQ,SAAS,CAC1F;QACI,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,OAAO,CAAC;KACrB,EACD,MAAM,EACN,OAAO,CACV;uBAO0B,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC;wCAKtB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;iBAS7C,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC;mBAGpC,OAAO,CAAC;QAChC,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC;wBAG+B,OAAO,CAAC,KAAK,CAAC;+BAGR;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAQ,OAAO,CAAC,OAAO,CAAC;gCAGjC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAQ,cAAc,CACxF,OAAO,EACP,KAAK,EACL,OAAO,CACV;sBAM+B,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;sBAW/C,OAAO,CAAC,OAAO,CAAC;CACzC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE;IAAE,UAAU,EAAE,OAAO,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAA6C,CAAC"}
|
package/dist/wrpc.js
CHANGED
|
@@ -1,241 +1,244 @@
|
|
|
1
1
|
import { getTransferrable } from "./workerUtils.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
//#region src/wrpc.ts
|
|
3
|
+
var LogLevel = /* @__PURE__ */ function(LogLevel) {
|
|
4
|
+
LogLevel[LogLevel["disabled"] = 0] = "disabled";
|
|
5
|
+
LogLevel[LogLevel["error"] = 1] = "error";
|
|
6
|
+
LogLevel[LogLevel["lifecycle"] = 2] = "lifecycle";
|
|
7
|
+
LogLevel[LogLevel["detail"] = 3] = "detail";
|
|
8
|
+
LogLevel[LogLevel["transport"] = 4] = "transport";
|
|
9
|
+
return LogLevel;
|
|
10
|
+
}({});
|
|
10
11
|
function deriveController(signal) {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
return [controller, AbortSignal.any([controller.signal, signal].filter(Boolean))];
|
|
13
14
|
}
|
|
14
15
|
function rejectOnSignal(promise, signal) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
})
|
|
20
|
-
]);
|
|
16
|
+
if (signal.aborted) return Promise.reject("RaceAborted:" + signal.reason);
|
|
17
|
+
return Promise.race([promise, new Promise((resolve, reject) => {
|
|
18
|
+
signal.addEventListener("abort", () => reject("RaceAborted:" + signal.reason), { once: true });
|
|
19
|
+
})]);
|
|
21
20
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
const log = logger("log");
|
|
34
|
-
const logWarn = logger("warn");
|
|
35
|
-
const logError = logger("error");
|
|
36
|
-
function send(worker, ctx, payload) {
|
|
37
|
-
log(4, ctx, "SEND", payload, typeof payload);
|
|
38
|
-
worker.postMessage({ ctx, payload }, getTransferrable(payload));
|
|
39
|
-
}
|
|
40
|
-
function listen(worker, context, listener, signal, once = false) {
|
|
41
|
-
signal.addEventListener(
|
|
42
|
-
"abort",
|
|
43
|
-
() => logWarn(3, context, "LISTEN SIGNAL ABORT", signal.reason),
|
|
44
|
-
{
|
|
45
|
-
signal,
|
|
46
|
-
once: true
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
worker.addEventListener(
|
|
50
|
-
"message",
|
|
51
|
-
({ data }) => {
|
|
52
|
-
log(4, context, "LISTEN EVENT", data);
|
|
53
|
-
if (!context || data?.ctx?.message === context.message && data.ctx?.id === context.id) listener(data);
|
|
54
|
-
},
|
|
55
|
-
{ signal, once }
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
function waitFor(worker, ctx, condition = (data) => true, signal) {
|
|
59
|
-
const [waitController, waitSignal] = deriveController(signal);
|
|
60
|
-
return new Promise(
|
|
61
|
-
(res) => listen(
|
|
62
|
-
worker,
|
|
63
|
-
ctx,
|
|
64
|
-
(data) => {
|
|
65
|
-
if (!condition(data)) return;
|
|
66
|
-
waitController.abort("WaitFinished");
|
|
67
|
-
res(data);
|
|
68
|
-
},
|
|
69
|
-
waitSignal
|
|
70
|
-
)
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
function createResponder(worker, responders) {
|
|
74
|
-
const mainController = new AbortController();
|
|
75
|
-
worker.addEventListener("messageerror", (e) => logError(1, null, "MESSAGE ERROR", e), {
|
|
76
|
-
signal: mainController.signal
|
|
77
|
-
});
|
|
78
|
-
listen(
|
|
79
|
-
worker,
|
|
80
|
-
null,
|
|
81
|
-
async ({ ctx, payload = {} }) => {
|
|
82
|
-
if (!ctx || !ctx.message || !ctx.id || ctx.abort || ctx.ack) return;
|
|
83
|
-
try {
|
|
84
|
-
const responder = responders[ctx.message];
|
|
85
|
-
if (!responder) throw new Error("Unknown responder", { cause: ctx });
|
|
86
|
-
const [subController, subSignal] = deriveController(mainController.signal);
|
|
87
|
-
if (ctx.signalName) payload[ctx.signalName] = subSignal;
|
|
88
|
-
const iterator = responder(payload);
|
|
89
|
-
log(2, ctx, "START", iterator);
|
|
90
|
-
if (!iterator[Symbol.asyncIterator] && !iterator[Symbol.iterator]) {
|
|
91
|
-
send(worker, { ...ctx, promise: true }, await rejectOnSignal(iterator, subSignal));
|
|
92
|
-
log(3, ctx, "PROMISE RESOLVED");
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
listen(
|
|
97
|
-
worker,
|
|
98
|
-
ctx,
|
|
99
|
-
(data) => {
|
|
100
|
-
if (!data.ctx.abort) return;
|
|
101
|
-
subController.abort(data.ctx.abort);
|
|
102
|
-
logWarn(2, ctx, "GOT ABORT");
|
|
103
|
-
},
|
|
104
|
-
subSignal
|
|
105
|
-
);
|
|
106
|
-
let res;
|
|
107
|
-
let nextPayload = payload;
|
|
108
|
-
do {
|
|
109
|
-
res = await rejectOnSignal(iterator.next(nextPayload), subSignal);
|
|
110
|
-
send(worker, { ...ctx, done: res.done }, res.value);
|
|
111
|
-
if (res.done) {
|
|
112
|
-
subController.abort("Done");
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
const nextData = await rejectOnSignal(
|
|
116
|
-
waitFor(worker, ctx, (data) => !!data.ctx.ack, subSignal),
|
|
117
|
-
subSignal
|
|
118
|
-
);
|
|
119
|
-
nextPayload = nextData.payload;
|
|
120
|
-
log(3, ctx, "LOOP ACK");
|
|
121
|
-
} while (!res.done && !subSignal.aborted);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
if (!subSignal.aborted && !e.message.includes("RaceAborted")) {
|
|
124
|
-
logError(1, ctx, "LOOP ERROR", e);
|
|
125
|
-
send(worker, { ...ctx, error: true, done: true }, e);
|
|
126
|
-
}
|
|
127
|
-
} finally {
|
|
128
|
-
log(3, ctx, "LOOP DONE");
|
|
129
|
-
}
|
|
130
|
-
} catch (e) {
|
|
131
|
-
logError(1, ctx, "ERROR", e);
|
|
132
|
-
send(worker, { ...ctx, error: true, done: true }, e);
|
|
133
|
-
} finally {
|
|
134
|
-
log(3, ctx, "DONE");
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
mainController.signal
|
|
138
|
-
);
|
|
139
|
-
function stop() {
|
|
140
|
-
mainController.abort("Stop");
|
|
141
|
-
}
|
|
142
|
-
return { responders, stop };
|
|
143
|
-
}
|
|
144
|
-
function createCaller(worker, responders) {
|
|
145
|
-
worker.addEventListener("messageerror", (e) => logError(1, null, "MESSAGE ERROR", e));
|
|
146
|
-
return new Proxy(responders, {
|
|
147
|
-
get(target, prop, receiver) {
|
|
148
|
-
function gen(payload) {
|
|
149
|
-
const ctx = { message: prop.toString(), id: crypto.randomUUID() };
|
|
150
|
-
let signal = null;
|
|
151
|
-
if (payload && Object.is(payload, Object(payload))) {
|
|
152
|
-
for (const [key, value] of Object.entries(payload)) {
|
|
153
|
-
if (value instanceof AbortSignal) {
|
|
154
|
-
log(3, ctx, "FOUND SIGNAL", key);
|
|
155
|
-
ctx.signalName = key;
|
|
156
|
-
signal = value;
|
|
157
|
-
payload[key] = null;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
const [mainController, mainSignal] = deriveController(signal);
|
|
162
|
-
const cancel = (notify, reason = "") => {
|
|
163
|
-
if (mainController.signal.aborted) return;
|
|
164
|
-
logWarn(2, ctx, "CANCEL", reason, notify);
|
|
165
|
-
if (reason) mainController.abort(reason);
|
|
166
|
-
if (notify) send(worker, { ...ctx, abort: reason });
|
|
167
|
-
};
|
|
168
|
-
const [promiseController, promiseSignal] = deriveController(mainSignal);
|
|
169
|
-
const promise = waitFor(
|
|
170
|
-
worker,
|
|
171
|
-
ctx,
|
|
172
|
-
(data) => !!data.ctx.promise || !!data.ctx.error,
|
|
173
|
-
promiseSignal
|
|
174
|
-
).then(({ ctx: ctx2, payload: payload2 }) => {
|
|
175
|
-
if (ctx2.error) {
|
|
176
|
-
logError(1, ctx2, "PROMISE ERROR", payload2);
|
|
177
|
-
throw payload2;
|
|
178
|
-
}
|
|
179
|
-
log(2, ctx2, "PROMISE RESOLVED", payload2);
|
|
180
|
-
return payload2;
|
|
181
|
-
});
|
|
182
|
-
async function* generator() {
|
|
183
|
-
let done = false;
|
|
184
|
-
try {
|
|
185
|
-
mainSignal.addEventListener("abort", () => cancel(true, mainSignal.reason), {
|
|
186
|
-
once: true,
|
|
187
|
-
signal: mainSignal
|
|
188
|
-
});
|
|
189
|
-
log(3, ctx, "GENERATOR START");
|
|
190
|
-
promiseController.abort("GeneratorUsed");
|
|
191
|
-
do {
|
|
192
|
-
const data = await rejectOnSignal(
|
|
193
|
-
waitFor(worker, ctx, void 0, mainSignal),
|
|
194
|
-
mainSignal
|
|
195
|
-
);
|
|
196
|
-
const { ctx: ctxIn, payload: value } = data;
|
|
197
|
-
log(2, ctx, "EVENT", mainSignal.aborted, ctxIn, value);
|
|
198
|
-
if (ctxIn.promise) {
|
|
199
|
-
logError(1, ctx, "ERROR", "Unexpected promise in generator", data);
|
|
200
|
-
throw new Error("Unexpected promise in generator", { cause: data });
|
|
201
|
-
}
|
|
202
|
-
if (ctxIn.error) {
|
|
203
|
-
logError(1, ctx, "ERROR", data);
|
|
204
|
-
cancel(false, "Error");
|
|
205
|
-
throw value;
|
|
206
|
-
}
|
|
207
|
-
if (ctxIn.done) {
|
|
208
|
-
done = true;
|
|
209
|
-
return value;
|
|
210
|
-
} else {
|
|
211
|
-
const nextPayload = yield value;
|
|
212
|
-
if (!mainSignal.aborted) send(worker, { ...ctx, ack: true }, nextPayload);
|
|
213
|
-
}
|
|
214
|
-
} while (!mainSignal.aborted);
|
|
215
|
-
} finally {
|
|
216
|
-
log(3, ctx, "DONE");
|
|
217
|
-
cancel(true, mainSignal.aborted ? mainSignal.reason : done ? "Done" : "Break");
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const iterator = generator();
|
|
221
|
-
send(worker, ctx, payload);
|
|
222
|
-
iterator["then"] = promise.then.bind(promise);
|
|
223
|
-
iterator["catch"] = promise.catch.bind(promise);
|
|
224
|
-
iterator["finally"] = promise.finally.bind(promise);
|
|
225
|
-
return iterator;
|
|
226
|
-
}
|
|
227
|
-
Object.defineProperty(gen, "name", { value: prop.toString() });
|
|
228
|
-
target[prop] = gen;
|
|
229
|
-
return gen;
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
return { createResponder, createCaller };
|
|
21
|
+
var RESERVED_NAMES = [
|
|
22
|
+
"then",
|
|
23
|
+
"catch",
|
|
24
|
+
"finally",
|
|
25
|
+
"toJSON",
|
|
26
|
+
"toString",
|
|
27
|
+
"constructor"
|
|
28
|
+
];
|
|
29
|
+
function validateResponders(responders) {
|
|
30
|
+
for (const key of Object.keys(responders)) if (RESERVED_NAMES.includes(key)) throw new Error(`Responder name "${key}" is reserved`);
|
|
234
31
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
32
|
+
function wrpc({ debug = 0, name = globalThis.importScripts ? "RESPONDER" : "CALLER" } = {}) {
|
|
33
|
+
function logger(type) {
|
|
34
|
+
return (level, ctx, ...args) => {
|
|
35
|
+
if (!debug || debug < level) return;
|
|
36
|
+
const { id, message, ...restCtx } = ctx ?? {};
|
|
37
|
+
console[type](name, message ?? "*", id ?? "*", ...args, restCtx);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const log = logger("log");
|
|
41
|
+
const logWarn = logger("warn");
|
|
42
|
+
const logError = logger("error");
|
|
43
|
+
function send(worker, ctx, payload) {
|
|
44
|
+
log(4, ctx, "SEND", payload, typeof payload);
|
|
45
|
+
worker.postMessage({
|
|
46
|
+
ctx,
|
|
47
|
+
payload
|
|
48
|
+
}, getTransferrable(payload));
|
|
49
|
+
}
|
|
50
|
+
function listen(worker, context, listener, signal, once = false) {
|
|
51
|
+
signal.addEventListener("abort", () => logWarn(3, context, "LISTEN SIGNAL ABORT", signal.reason), { once: true });
|
|
52
|
+
worker.addEventListener("message", ({ data }) => {
|
|
53
|
+
log(4, context, "LISTEN EVENT", data);
|
|
54
|
+
if (!context || data?.ctx?.message === context.message && data.ctx?.id === context.id) listener(data);
|
|
55
|
+
}, {
|
|
56
|
+
signal,
|
|
57
|
+
once
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function waitFor(worker, ctx, condition = (data) => true, signal) {
|
|
61
|
+
const [waitController, waitSignal] = deriveController(signal);
|
|
62
|
+
return new Promise((resolve) => listen(worker, ctx, (data) => {
|
|
63
|
+
if (!condition(data)) return;
|
|
64
|
+
waitController.abort("WaitFinished");
|
|
65
|
+
resolve(data);
|
|
66
|
+
}, waitSignal));
|
|
67
|
+
}
|
|
68
|
+
function createResponder(worker, responders) {
|
|
69
|
+
validateResponders(responders);
|
|
70
|
+
const mainController = new AbortController();
|
|
71
|
+
worker.addEventListener("messageerror", (e) => logError(1, null, "MESSAGE ERROR", e), { signal: mainController.signal });
|
|
72
|
+
listen(worker, null, async ({ ctx, payload = {} }) => {
|
|
73
|
+
if (!ctx?.message || !ctx.id || ctx.abort || ctx.ack) return;
|
|
74
|
+
try {
|
|
75
|
+
const responder = responders[ctx.message];
|
|
76
|
+
if (!responder) throw new Error("Unknown responder", { cause: ctx });
|
|
77
|
+
const [subController, subSignal] = deriveController(mainController.signal);
|
|
78
|
+
if (ctx.signalName) payload[ctx.signalName] = subSignal;
|
|
79
|
+
const iterator = responder.call(responders, payload);
|
|
80
|
+
log(2, ctx, "START", iterator);
|
|
81
|
+
if (!iterator[Symbol.asyncIterator] && !iterator[Symbol.iterator]) {
|
|
82
|
+
send(worker, {
|
|
83
|
+
...ctx,
|
|
84
|
+
promise: true
|
|
85
|
+
}, await rejectOnSignal(iterator, subSignal));
|
|
86
|
+
log(3, ctx, "PROMISE RESOLVED");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
let res;
|
|
90
|
+
try {
|
|
91
|
+
listen(worker, ctx, (data) => {
|
|
92
|
+
if (!data.ctx.abort) return;
|
|
93
|
+
subController.abort(data.ctx.abort);
|
|
94
|
+
logWarn(2, ctx, "GOT ABORT");
|
|
95
|
+
}, subSignal);
|
|
96
|
+
let nextPayload = payload;
|
|
97
|
+
do {
|
|
98
|
+
res = await rejectOnSignal(iterator.next(nextPayload), subSignal);
|
|
99
|
+
send(worker, {
|
|
100
|
+
...ctx,
|
|
101
|
+
done: res.done
|
|
102
|
+
}, res.value);
|
|
103
|
+
if (res.done) {
|
|
104
|
+
subController.abort("Done");
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
nextPayload = (await rejectOnSignal(waitFor(worker, ctx, (data) => !!data.ctx.ack, subSignal), subSignal)).payload;
|
|
108
|
+
log(3, ctx, "LOOP ACK");
|
|
109
|
+
} while (!res.done && !subSignal.aborted);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
if (!subSignal.aborted && !e.message.includes("RaceAborted")) {
|
|
112
|
+
logError(1, ctx, "LOOP ERROR", e);
|
|
113
|
+
send(worker, {
|
|
114
|
+
...ctx,
|
|
115
|
+
error: true,
|
|
116
|
+
done: true
|
|
117
|
+
}, e);
|
|
118
|
+
}
|
|
119
|
+
} finally {
|
|
120
|
+
if (!res?.done) try {
|
|
121
|
+
Promise.resolve(iterator.return?.(void 0)).catch(() => {});
|
|
122
|
+
} catch {}
|
|
123
|
+
log(3, ctx, "LOOP DONE");
|
|
124
|
+
}
|
|
125
|
+
} catch (e) {
|
|
126
|
+
logError(1, ctx, "ERROR", e);
|
|
127
|
+
send(worker, {
|
|
128
|
+
...ctx,
|
|
129
|
+
error: true,
|
|
130
|
+
done: true
|
|
131
|
+
}, e);
|
|
132
|
+
} finally {
|
|
133
|
+
log(3, ctx, "DONE");
|
|
134
|
+
}
|
|
135
|
+
}, mainController.signal);
|
|
136
|
+
function stop() {
|
|
137
|
+
mainController.abort("Stop");
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
responders,
|
|
141
|
+
stop
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function createCaller(worker, responders) {
|
|
145
|
+
validateResponders(responders);
|
|
146
|
+
worker.addEventListener("messageerror", (e) => logError(1, null, "MESSAGE ERROR", e));
|
|
147
|
+
return new Proxy(responders, { get(target, prop, receiver) {
|
|
148
|
+
if (typeof prop !== "string" || RESERVED_NAMES.includes(prop)) return Reflect.get(target, prop, receiver);
|
|
149
|
+
function gen(payload) {
|
|
150
|
+
const ctx = {
|
|
151
|
+
message: prop.toString(),
|
|
152
|
+
id: crypto.randomUUID()
|
|
153
|
+
};
|
|
154
|
+
let signal = null;
|
|
155
|
+
if (payload && Object.is(payload, Object(payload))) {
|
|
156
|
+
for (const [key, value] of Object.entries(payload)) if (value instanceof AbortSignal) {
|
|
157
|
+
log(3, ctx, "FOUND SIGNAL", key);
|
|
158
|
+
ctx.signalName = key;
|
|
159
|
+
signal = value;
|
|
160
|
+
payload[key] = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const [mainController, mainSignal] = deriveController(signal);
|
|
164
|
+
const cancel = (notify, reason = "") => {
|
|
165
|
+
if (mainController.signal.aborted) return;
|
|
166
|
+
logWarn(2, ctx, "CANCEL", reason, notify);
|
|
167
|
+
if (reason) mainController.abort(reason);
|
|
168
|
+
if (notify) send(worker, {
|
|
169
|
+
...ctx,
|
|
170
|
+
abort: reason
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
const [promiseController, promiseSignal] = deriveController(mainSignal);
|
|
174
|
+
const promise = waitFor(worker, ctx, void 0, promiseSignal).then((data) => {
|
|
175
|
+
const { ctx: ctxIn, payload } = data;
|
|
176
|
+
if (ctxIn.error) {
|
|
177
|
+
logError(1, ctx, "PROMISE ERROR", payload);
|
|
178
|
+
throw payload;
|
|
179
|
+
}
|
|
180
|
+
if (ctxIn.promise) {
|
|
181
|
+
log(2, ctx, "PROMISE RESOLVED", payload);
|
|
182
|
+
return payload;
|
|
183
|
+
}
|
|
184
|
+
logError(1, ctx, "ERROR", "Cannot await a generator method", data);
|
|
185
|
+
cancel(true, "AwaitedGenerator");
|
|
186
|
+
throw new Error("Cannot await a generator method, use `for await ... of`", { cause: data });
|
|
187
|
+
});
|
|
188
|
+
promise.catch(() => {});
|
|
189
|
+
async function* generator() {
|
|
190
|
+
let done = false;
|
|
191
|
+
try {
|
|
192
|
+
mainSignal.addEventListener("abort", () => cancel(true, mainSignal.reason), { once: true });
|
|
193
|
+
log(3, ctx, "GENERATOR START");
|
|
194
|
+
promiseController.abort("GeneratorUsed");
|
|
195
|
+
do {
|
|
196
|
+
const data = await rejectOnSignal(waitFor(worker, ctx, void 0, mainSignal), mainSignal);
|
|
197
|
+
const { ctx: ctxIn, payload: value } = data;
|
|
198
|
+
log(2, ctx, "EVENT", mainSignal.aborted, ctxIn, value);
|
|
199
|
+
if (ctxIn.promise) {
|
|
200
|
+
logError(1, ctx, "ERROR", "Unexpected promise in generator", data);
|
|
201
|
+
throw new Error("Unexpected promise in generator", { cause: data });
|
|
202
|
+
}
|
|
203
|
+
if (ctxIn.error) {
|
|
204
|
+
logError(1, ctx, "ERROR", data);
|
|
205
|
+
cancel(false, "Error");
|
|
206
|
+
throw value;
|
|
207
|
+
}
|
|
208
|
+
if (ctxIn.done) {
|
|
209
|
+
done = true;
|
|
210
|
+
return value;
|
|
211
|
+
} else {
|
|
212
|
+
const nextPayload = yield value;
|
|
213
|
+
if (!mainSignal.aborted) send(worker, {
|
|
214
|
+
...ctx,
|
|
215
|
+
ack: true
|
|
216
|
+
}, nextPayload);
|
|
217
|
+
}
|
|
218
|
+
} while (!mainSignal.aborted);
|
|
219
|
+
} finally {
|
|
220
|
+
log(3, ctx, "DONE");
|
|
221
|
+
cancel(true, mainSignal.aborted ? mainSignal.reason : done ? "Done" : "Break");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const iterator = generator();
|
|
225
|
+
send(worker, ctx, payload);
|
|
226
|
+
iterator["then"] = promise.then.bind(promise);
|
|
227
|
+
iterator["catch"] = promise.catch.bind(promise);
|
|
228
|
+
iterator["finally"] = promise.finally.bind(promise);
|
|
229
|
+
return iterator;
|
|
230
|
+
}
|
|
231
|
+
Object.defineProperty(gen, "name", { value: prop.toString() });
|
|
232
|
+
target[prop] = gen;
|
|
233
|
+
return gen;
|
|
234
|
+
} });
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
createResponder,
|
|
238
|
+
createCaller
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
export { LogLevel, RESERVED_NAMES, deriveController, rejectOnSignal, wrpc };
|
|
243
|
+
|
|
244
|
+
//# sourceMappingURL=wrpc.js.map
|