@shelchin/threadx 0.1.0

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.
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/protocol.ts", "../src/mock-worker.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Communication protocol types between main thread and worker\n */\n\n// ============ Main Thread → Worker ============\n\nexport interface CallMessage {\n $type: 'CALL';\n $id: number;\n method: string;\n args: unknown[];\n}\n\nexport interface CancelMessage {\n $type: 'CANCEL';\n $id: number;\n}\n\nexport type MainToWorkerMessage = CallMessage | CancelMessage;\n\n// ============ Worker → Main Thread ============\n\nexport interface ReadyMessage {\n $type: 'READY';\n methods: string[];\n}\n\nexport interface ResolveMessage {\n $type: 'RESOLVE';\n $id: number;\n value: unknown;\n}\n\nexport interface RejectMessage {\n $type: 'REJECT';\n $id: number;\n error: SerializedError;\n}\n\nexport interface YieldMessage {\n $type: 'YIELD';\n $id: number;\n value: unknown;\n}\n\nexport interface DoneMessage {\n $type: 'DONE';\n $id: number;\n}\n\nexport type WorkerToMainMessage =\n | ReadyMessage\n | ResolveMessage\n | RejectMessage\n | YieldMessage\n | DoneMessage;\n\n// ============ Error Serialization ============\n\nexport interface SerializedError {\n name: string;\n message: string;\n stack?: string;\n}\n\nexport function serializeError(error: unknown): SerializedError {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n }\n return {\n name: 'Error',\n message: String(error),\n };\n}\n",
6
+ "/**\n * Mock Worker for testing\n * Simulates Worker message passing in the same thread\n */\n\nimport type { MainToWorkerMessage, WorkerToMainMessage } from './protocol.js';\nimport { serializeError } from './protocol.js';\n\ntype MessageHandler = (event: MessageEvent<WorkerToMainMessage>) => void;\n\nexport interface MockWorkerMethods {\n [key: string]: (...args: unknown[]) => unknown;\n}\n\n/**\n * Create a mock Worker that runs in the same thread\n * Useful for testing without actual Worker threads\n */\nexport function createMockWorker(methods: MockWorkerMethods): Worker {\n let onmessageHandler: MessageHandler | null = null;\n let onerrorHandler: ((event: ErrorEvent) => void) | null = null;\n let isTerminated = false;\n\n // Track active generators for cancellation\n const activeGenerators = new Map<number, Generator | AsyncGenerator>();\n\n const mockWorker = {\n postMessage(data: MainToWorkerMessage, _transfer?: Transferable[]) {\n if (isTerminated) return;\n\n // Simulate async message passing\n queueMicrotask(async () => {\n if (isTerminated) return;\n\n if (data.$type === 'CANCEL') {\n const gen = activeGenerators.get(data.$id);\n if (gen && 'return' in gen && typeof gen.return === 'function') {\n try {\n gen.return(undefined);\n } catch {\n // Ignore\n }\n }\n activeGenerators.delete(data.$id);\n return;\n }\n\n if (data.$type === 'CALL') {\n const { $id, method, args } = data;\n const fn = methods[method];\n\n if (!fn) {\n sendMessage({\n $type: 'REJECT',\n $id,\n error: { name: 'Error', message: `Method '${method}' not found` },\n });\n return;\n }\n\n try {\n const result = fn(...args);\n\n // Check if generator\n if (isGenerator(result)) {\n activeGenerators.set($id, result);\n\n try {\n for await (const value of result as AsyncIterable<unknown>) {\n if (!activeGenerators.has($id) || isTerminated) break;\n sendMessage({ $type: 'YIELD', $id, value });\n }\n\n if (activeGenerators.has($id) && !isTerminated) {\n sendMessage({ $type: 'DONE', $id });\n }\n } finally {\n activeGenerators.delete($id);\n }\n } else {\n const value = await result;\n if (!isTerminated) {\n sendMessage({ $type: 'RESOLVE', $id, value });\n }\n }\n } catch (error) {\n if (!isTerminated) {\n sendMessage({ $type: 'REJECT', $id, error: serializeError(error) });\n }\n }\n }\n });\n },\n\n set onmessage(handler: MessageHandler | null) {\n onmessageHandler = handler;\n },\n\n get onmessage() {\n return onmessageHandler;\n },\n\n set onerror(handler: ((event: ErrorEvent) => void) | null) {\n onerrorHandler = handler;\n },\n\n get onerror() {\n return onerrorHandler;\n },\n\n terminate() {\n isTerminated = true;\n activeGenerators.clear();\n },\n\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent() {\n return true;\n },\n };\n\n function sendMessage(message: WorkerToMainMessage) {\n if (onmessageHandler && !isTerminated) {\n onmessageHandler({ data: message } as MessageEvent<WorkerToMainMessage>);\n }\n }\n\n function isGenerator(value: unknown): value is Generator | AsyncGenerator {\n if (value === null || typeof value !== 'object') return false;\n return (\n typeof (value as Generator).next === 'function' &&\n (typeof (value as Generator)[Symbol.iterator] === 'function' ||\n typeof (value as AsyncGenerator)[Symbol.asyncIterator] === 'function')\n );\n }\n\n // Send READY message after a microtask (simulating Worker startup)\n queueMicrotask(() => {\n if (!isTerminated) {\n sendMessage({ $type: 'READY', methods: Object.keys(methods) });\n }\n });\n\n return mockWorker as unknown as Worker;\n}\n\n/**\n * Create a mock Worker that delays READY message\n */\nexport function createSlowStartWorker(methods: MockWorkerMethods, delay: number): Worker {\n const worker = createMockWorker(methods);\n const originalOnmessage = Object.getOwnPropertyDescriptor(worker, 'onmessage');\n\n // Intercept the first READY message and delay it\n let readyDelayed = false;\n let pendingReady: WorkerToMainMessage | null = null;\n let actualHandler: MessageHandler | null = null;\n\n Object.defineProperty(worker, 'onmessage', {\n set(handler: MessageHandler | null) {\n actualHandler = handler;\n if (originalOnmessage?.set) {\n originalOnmessage.set.call(worker, (event: MessageEvent<WorkerToMainMessage>) => {\n if (!readyDelayed && event.data.$type === 'READY') {\n pendingReady = event.data;\n readyDelayed = true;\n setTimeout(() => {\n if (actualHandler && pendingReady) {\n actualHandler({ data: pendingReady } as MessageEvent<WorkerToMainMessage>);\n }\n }, delay);\n } else if (actualHandler) {\n actualHandler(event);\n }\n });\n }\n },\n get() {\n return actualHandler;\n },\n });\n\n return worker;\n}\n\n/**\n * Create a mock Worker that fails on initialization\n */\nexport function createFailingWorker(errorMessage: string): Worker {\n let onerrorHandler: ((event: ErrorEvent) => void) | null = null;\n\n const mockWorker = {\n postMessage() {},\n set onmessage(_handler: MessageHandler | null) {},\n get onmessage() {\n return null;\n },\n set onerror(handler: ((event: ErrorEvent) => void) | null) {\n onerrorHandler = handler;\n // Trigger error after microtask\n queueMicrotask(() => {\n if (onerrorHandler) {\n onerrorHandler({ message: errorMessage } as ErrorEvent);\n }\n });\n },\n get onerror() {\n return onerrorHandler;\n },\n terminate() {},\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent() {\n return true;\n },\n };\n\n return mockWorker as unknown as Worker;\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "A291C1DCC73E48BC64756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Communication protocol types between main thread and worker
3
+ */
4
+ export interface CallMessage {
5
+ $type: 'CALL';
6
+ $id: number;
7
+ method: string;
8
+ args: unknown[];
9
+ }
10
+ export interface CancelMessage {
11
+ $type: 'CANCEL';
12
+ $id: number;
13
+ }
14
+ export type MainToWorkerMessage = CallMessage | CancelMessage;
15
+ export interface ReadyMessage {
16
+ $type: 'READY';
17
+ methods: string[];
18
+ }
19
+ export interface ResolveMessage {
20
+ $type: 'RESOLVE';
21
+ $id: number;
22
+ value: unknown;
23
+ }
24
+ export interface RejectMessage {
25
+ $type: 'REJECT';
26
+ $id: number;
27
+ error: SerializedError;
28
+ }
29
+ export interface YieldMessage {
30
+ $type: 'YIELD';
31
+ $id: number;
32
+ value: unknown;
33
+ }
34
+ export interface DoneMessage {
35
+ $type: 'DONE';
36
+ $id: number;
37
+ }
38
+ export type WorkerToMainMessage = ReadyMessage | ResolveMessage | RejectMessage | YieldMessage | DoneMessage;
39
+ export interface SerializedError {
40
+ name: string;
41
+ message: string;
42
+ stack?: string;
43
+ }
44
+ export declare function serializeError(error: unknown): SerializedError;
45
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,aAAa,CAAC;AAI9D,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,cAAc,GACd,aAAa,GACb,YAAY,GACZ,WAAW,CAAC;AAIhB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAY9D"}
@@ -0,0 +1,19 @@
1
+ // src/protocol.ts
2
+ function serializeError(error) {
3
+ if (error instanceof Error) {
4
+ return {
5
+ name: error.name,
6
+ message: error.message,
7
+ stack: error.stack
8
+ };
9
+ }
10
+ return {
11
+ name: "Error",
12
+ message: String(error)
13
+ };
14
+ }
15
+ export {
16
+ serializeError
17
+ };
18
+
19
+ //# debugId=285A9B781F2A586864756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/protocol.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Communication protocol types between main thread and worker\n */\n\n// ============ Main Thread → Worker ============\n\nexport interface CallMessage {\n $type: 'CALL';\n $id: number;\n method: string;\n args: unknown[];\n}\n\nexport interface CancelMessage {\n $type: 'CANCEL';\n $id: number;\n}\n\nexport type MainToWorkerMessage = CallMessage | CancelMessage;\n\n// ============ Worker → Main Thread ============\n\nexport interface ReadyMessage {\n $type: 'READY';\n methods: string[];\n}\n\nexport interface ResolveMessage {\n $type: 'RESOLVE';\n $id: number;\n value: unknown;\n}\n\nexport interface RejectMessage {\n $type: 'REJECT';\n $id: number;\n error: SerializedError;\n}\n\nexport interface YieldMessage {\n $type: 'YIELD';\n $id: number;\n value: unknown;\n}\n\nexport interface DoneMessage {\n $type: 'DONE';\n $id: number;\n}\n\nexport type WorkerToMainMessage =\n | ReadyMessage\n | ResolveMessage\n | RejectMessage\n | YieldMessage\n | DoneMessage;\n\n// ============ Error Serialization ============\n\nexport interface SerializedError {\n name: string;\n message: string;\n stack?: string;\n}\n\nexport function serializeError(error: unknown): SerializedError {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n }\n return {\n name: 'Error',\n message: String(error),\n };\n}\n"
6
+ ],
7
+ "mappings": ";AAiEO,SAAS,cAAc,CAAC,OAAiC;AAAA,EAC9D,IAAI,iBAAiB,OAAO;AAAA,IAC1B,OAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,OAAO,KAAK;AAAA,EACvB;AAAA;",
8
+ "debugId": "285A9B781F2A586864756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Failing Worker - throws immediately on load (for InitError testing)
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=test-fail.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-fail.worker.d.ts","sourceRoot":"","sources":["../src/test-fail.worker.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,4 @@
1
+ // src/test-fail.worker.ts
2
+ throw new Error("Worker script failed to load");
3
+
4
+ //# debugId=4343472169047D3F64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/test-fail.worker.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Failing Worker - throws immediately on load (for InitError testing)\n */\n\nthrow new Error('Worker script failed to load');\n"
6
+ ],
7
+ "mappings": ";AAIA,MAAM,IAAI,MAAM,8BAA8B;",
8
+ "debugId": "4343472169047D3F64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Test Worker - contains all methods needed for unit tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=test.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.worker.d.ts","sourceRoot":"","sources":["../src/test.worker.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,198 @@
1
+ // src/protocol.ts
2
+ function serializeError(error) {
3
+ if (error instanceof Error) {
4
+ return {
5
+ name: error.name,
6
+ message: error.message,
7
+ stack: error.stack
8
+ };
9
+ }
10
+ return {
11
+ name: "Error",
12
+ message: String(error)
13
+ };
14
+ }
15
+
16
+ // src/transfer.ts
17
+ var TRANSFER = Symbol("threadx.transfer");
18
+ function isTransferDescriptor(value) {
19
+ return typeof value === "object" && value !== null && TRANSFER in value;
20
+ }
21
+
22
+ // src/worker.ts
23
+ function isSyncGenerator(value) {
24
+ if (value === null || typeof value !== "object")
25
+ return false;
26
+ return typeof value.next === "function" && typeof value[Symbol.iterator] === "function" && typeof value[Symbol.asyncIterator] !== "function";
27
+ }
28
+ function isAsyncGenerator(value) {
29
+ if (value === null || typeof value !== "object")
30
+ return false;
31
+ return typeof value.next === "function" && typeof value[Symbol.asyncIterator] === "function";
32
+ }
33
+ function isGenerator(value) {
34
+ return isSyncGenerator(value) || isAsyncGenerator(value);
35
+ }
36
+ function postMessage(message, value) {
37
+ if (isTransferDescriptor(value)) {
38
+ self.postMessage(message, value.transferables);
39
+ } else {
40
+ self.postMessage(message);
41
+ }
42
+ }
43
+ function expose(methods) {
44
+ const methodNames = Object.keys(methods);
45
+ const activeGenerators = new Map;
46
+ self.postMessage({ $type: "READY", methods: methodNames });
47
+ self.onmessage = async (event) => {
48
+ const msg = event.data;
49
+ if (msg.$type === "CANCEL") {
50
+ const gen = activeGenerators.get(msg.$id);
51
+ if (gen && "return" in gen && typeof gen.return === "function") {
52
+ try {
53
+ gen.return(undefined);
54
+ } catch {}
55
+ }
56
+ activeGenerators.delete(msg.$id);
57
+ return;
58
+ }
59
+ if (msg.$type === "CALL") {
60
+ const { $id, method, args } = msg;
61
+ const fn = methods[method];
62
+ if (!fn) {
63
+ postMessage({
64
+ $type: "REJECT",
65
+ $id,
66
+ error: { name: "Error", message: `Method '${method}' not found` }
67
+ });
68
+ return;
69
+ }
70
+ try {
71
+ const result = fn(...args);
72
+ if (isGenerator(result) || isAsyncGenerator(result)) {
73
+ activeGenerators.set($id, result);
74
+ try {
75
+ for await (const value of result) {
76
+ if (!activeGenerators.has($id)) {
77
+ break;
78
+ }
79
+ postMessage({ $type: "YIELD", $id, value }, value);
80
+ }
81
+ if (activeGenerators.has($id)) {
82
+ postMessage({ $type: "DONE", $id });
83
+ }
84
+ } finally {
85
+ activeGenerators.delete($id);
86
+ }
87
+ } else {
88
+ const value = await result;
89
+ postMessage({ $type: "RESOLVE", $id, value }, value);
90
+ }
91
+ } catch (error) {
92
+ postMessage({
93
+ $type: "REJECT",
94
+ $id,
95
+ error: serializeError(error)
96
+ });
97
+ }
98
+ }
99
+ };
100
+ }
101
+
102
+ // src/test.worker.ts
103
+ var pendingResolvers = new Map;
104
+ expose({
105
+ add(a, b) {
106
+ return a + b;
107
+ },
108
+ multiply(a, b) {
109
+ return a * b;
110
+ },
111
+ async fetchData(id) {
112
+ await new Promise((r) => setTimeout(r, 10));
113
+ return { id, name: "test" };
114
+ },
115
+ getTime() {
116
+ return 1234567890;
117
+ },
118
+ doSomething() {
119
+ return;
120
+ },
121
+ getNull() {
122
+ return null;
123
+ },
124
+ transform(data) {
125
+ return {
126
+ result: data.items.map((n) => `${data.prefix}${n}`),
127
+ count: data.items.length
128
+ };
129
+ },
130
+ failingMethod() {
131
+ throw new Error("Something went wrong");
132
+ },
133
+ throwTypeError() {
134
+ throw new TypeError("Invalid type");
135
+ },
136
+ async slowMethod() {
137
+ await new Promise((r) => setTimeout(r, 1000));
138
+ return "done";
139
+ },
140
+ async fastMethod() {
141
+ await new Promise((r) => setTimeout(r, 10));
142
+ return "fast";
143
+ },
144
+ method() {
145
+ return "result";
146
+ },
147
+ *countdown(from) {
148
+ for (let i = from;i >= 0; i--) {
149
+ yield i;
150
+ }
151
+ },
152
+ async* asyncStream(count) {
153
+ for (let i = 0;i < count; i++) {
154
+ await new Promise((r) => setTimeout(r, 5));
155
+ yield i * 10;
156
+ }
157
+ },
158
+ async* infiniteStream() {
159
+ let i = 0;
160
+ while (true) {
161
+ await new Promise((r) => setTimeout(r, 10));
162
+ yield i++;
163
+ }
164
+ },
165
+ async* slowStream() {
166
+ let i = 0;
167
+ while (true) {
168
+ await new Promise((r) => setTimeout(r, 100));
169
+ yield i++;
170
+ }
171
+ },
172
+ *empty() {},
173
+ *failingGenerator() {
174
+ yield 1;
175
+ yield 2;
176
+ throw new Error("Generator failed");
177
+ },
178
+ slowMethodWithCallback() {
179
+ return new Promise((resolve) => {
180
+ pendingResolvers.set("slowMethodWithCallback", () => resolve(42));
181
+ });
182
+ },
183
+ resolveSlowMethod() {
184
+ const resolver = pendingResolvers.get("slowMethodWithCallback");
185
+ if (resolver) {
186
+ resolver();
187
+ pendingResolvers.delete("slowMethodWithCallback");
188
+ }
189
+ },
190
+ processBuffer(buffer) {
191
+ return buffer.byteLength;
192
+ },
193
+ combineBuffers(buf1, buf2) {
194
+ return buf1.byteLength + buf2.byteLength;
195
+ }
196
+ });
197
+
198
+ //# debugId=E72E1A6102C7BF2D64756E2164756E21
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/protocol.ts", "../src/transfer.ts", "../src/worker.ts", "../src/test.worker.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Communication protocol types between main thread and worker\n */\n\n// ============ Main Thread → Worker ============\n\nexport interface CallMessage {\n $type: 'CALL';\n $id: number;\n method: string;\n args: unknown[];\n}\n\nexport interface CancelMessage {\n $type: 'CANCEL';\n $id: number;\n}\n\nexport type MainToWorkerMessage = CallMessage | CancelMessage;\n\n// ============ Worker → Main Thread ============\n\nexport interface ReadyMessage {\n $type: 'READY';\n methods: string[];\n}\n\nexport interface ResolveMessage {\n $type: 'RESOLVE';\n $id: number;\n value: unknown;\n}\n\nexport interface RejectMessage {\n $type: 'REJECT';\n $id: number;\n error: SerializedError;\n}\n\nexport interface YieldMessage {\n $type: 'YIELD';\n $id: number;\n value: unknown;\n}\n\nexport interface DoneMessage {\n $type: 'DONE';\n $id: number;\n}\n\nexport type WorkerToMainMessage =\n | ReadyMessage\n | ResolveMessage\n | RejectMessage\n | YieldMessage\n | DoneMessage;\n\n// ============ Error Serialization ============\n\nexport interface SerializedError {\n name: string;\n message: string;\n stack?: string;\n}\n\nexport function serializeError(error: unknown): SerializedError {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n }\n return {\n name: 'Error',\n message: String(error),\n };\n}\n",
6
+ "/**\n * Transferable marking utility\n */\n\n/** Symbol to identify transfer descriptors */\nexport const TRANSFER = Symbol('threadx.transfer');\n\n/** Descriptor for transferable values */\nexport interface TransferDescriptor<T = unknown> {\n [TRANSFER]: true;\n value: T;\n transferables: Transferable[];\n}\n\n/**\n * Mark a value as Transferable for zero-copy transfer to Worker\n *\n * @example\n * // Single transferable\n * const buffer = new ArrayBuffer(1024)\n * await worker.process(t(buffer))\n * // buffer.byteLength === 0 (transferred)\n *\n * @example\n * // Object with specified transferables\n * const data = { image: buffer, meta: info }\n * await worker.process(t(data, [buffer]))\n */\nexport function t<T extends Transferable>(value: T): TransferDescriptor<T>;\nexport function t<T>(value: T, transferables: Transferable[]): TransferDescriptor<T>;\nexport function t<T>(value: T, transferables?: Transferable[]): TransferDescriptor<T> {\n return {\n [TRANSFER]: true,\n value,\n transferables: transferables ?? [value as unknown as Transferable],\n };\n}\n\n/**\n * Check if a value is a transfer descriptor\n */\nexport function isTransferDescriptor(value: unknown): value is TransferDescriptor {\n return typeof value === 'object' && value !== null && TRANSFER in value;\n}\n\n/**\n * Process arguments to extract transferables\n */\nexport function prepareArgs(args: unknown[]): { args: unknown[]; transfer: Transferable[] } {\n const transfer: Transferable[] = [];\n const processedArgs = args.map((arg) => {\n if (isTransferDescriptor(arg)) {\n transfer.push(...arg.transferables);\n return arg.value;\n }\n return arg;\n });\n return { args: processedArgs, transfer };\n}\n",
7
+ "/**\n * Worker-side API for ThreadX\n */\n\nimport type { MainToWorkerMessage, WorkerToMainMessage } from './protocol.js';\nimport { serializeError } from './protocol.js';\nimport { isTransferDescriptor } from './transfer.js';\n\n// Re-export t() for Worker-side use\nexport { t } from './transfer.js';\n\ntype AnyFunction = (...args: unknown[]) => unknown;\ntype MethodMap = Record<string, AnyFunction>;\n\n/**\n * Check if a value is a Generator (sync)\n * Uses duck typing - checks for next() and Symbol.iterator\n */\nfunction isSyncGenerator(value: unknown): value is Generator {\n if (value === null || typeof value !== 'object') return false;\n return (\n typeof (value as Generator).next === 'function' &&\n typeof (value as Generator)[Symbol.iterator] === 'function' &&\n // Exclude AsyncGenerator (which also has next and Symbol.iterator)\n typeof (value as AsyncGenerator)[Symbol.asyncIterator] !== 'function'\n );\n}\n\n/**\n * Check if a value is an AsyncGenerator\n * Uses duck typing - checks for next() and Symbol.asyncIterator\n */\nfunction isAsyncGenerator(value: unknown): value is AsyncGenerator {\n if (value === null || typeof value !== 'object') return false;\n return (\n typeof (value as AsyncGenerator).next === 'function' &&\n typeof (value as AsyncGenerator)[Symbol.asyncIterator] === 'function'\n );\n}\n\n/**\n * Check if a value is any kind of Generator (sync or async)\n */\nfunction isGenerator(value: unknown): value is Generator | AsyncGenerator {\n return isSyncGenerator(value) || isAsyncGenerator(value);\n}\n\n/**\n * Post a message with optional transferables\n */\nfunction postMessage(message: WorkerToMainMessage, value?: unknown): void {\n if (isTransferDescriptor(value)) {\n self.postMessage(message, value.transferables);\n } else {\n self.postMessage(message);\n }\n}\n\n/**\n * Expose methods to the main thread\n *\n * @example\n * import { expose } from '@shelchin/threadx/worker'\n *\n * expose({\n * add(a: number, b: number) {\n * return a + b\n * },\n *\n * async heavyTask(data: ArrayBuffer) {\n * // Long running computation...\n * return result\n * },\n *\n * *progress(total: number) {\n * for (let i = 0; i <= total; i++) {\n * yield i\n * }\n * }\n * })\n */\nexport function expose<T extends MethodMap>(methods: T): void {\n const methodNames = Object.keys(methods);\n\n // Track active generators for cancellation\n const activeGenerators = new Map<number, Generator | AsyncGenerator>();\n\n // Send ready message\n self.postMessage({ $type: 'READY', methods: methodNames } satisfies WorkerToMainMessage);\n\n // Handle incoming messages\n self.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {\n const msg = event.data;\n\n // Handle cancellation\n if (msg.$type === 'CANCEL') {\n const gen = activeGenerators.get(msg.$id);\n if (gen && 'return' in gen && typeof gen.return === 'function') {\n try {\n gen.return(undefined);\n } catch {\n // Ignore errors during cancellation\n }\n }\n activeGenerators.delete(msg.$id);\n return;\n }\n\n // Handle method call\n if (msg.$type === 'CALL') {\n const { $id, method, args } = msg;\n const fn = methods[method];\n\n // Method not found\n if (!fn) {\n postMessage({\n $type: 'REJECT',\n $id,\n error: { name: 'Error', message: `Method '${method}' not found` },\n });\n return;\n }\n\n try {\n const result = fn(...args);\n\n // Handle Generator/AsyncGenerator → streaming\n if (isGenerator(result) || isAsyncGenerator(result)) {\n activeGenerators.set($id, result);\n\n try {\n // Use for-await to handle both sync and async generators\n for await (const value of result as AsyncIterable<unknown>) {\n // Check if cancelled\n if (!activeGenerators.has($id)) {\n break;\n }\n postMessage({ $type: 'YIELD', $id, value }, value);\n }\n\n // Only send DONE if not cancelled\n if (activeGenerators.has($id)) {\n postMessage({ $type: 'DONE', $id });\n }\n } finally {\n activeGenerators.delete($id);\n }\n } else {\n // Handle Promise/value → single response\n const value = await result;\n postMessage({ $type: 'RESOLVE', $id, value }, value);\n }\n } catch (error) {\n postMessage({\n $type: 'REJECT',\n $id,\n error: serializeError(error),\n });\n }\n }\n };\n}\n",
8
+ "/**\n * Test Worker - contains all methods needed for unit tests\n */\n\nimport { expose } from './worker.js';\n\n// For testing pending resolution\nlet pendingResolvers: Map<string, () => void> = new Map();\n\nexpose({\n // === Basic RPC ===\n add(a: number, b: number): number {\n return a + b;\n },\n\n multiply(a: number, b: number): number {\n return a * b;\n },\n\n async fetchData(id: number): Promise<{ id: number; name: string }> {\n await new Promise((r) => setTimeout(r, 10));\n return { id, name: 'test' };\n },\n\n getTime(): number {\n return 1234567890;\n },\n\n doSomething(): void {\n return undefined;\n },\n\n getNull(): null {\n return null;\n },\n\n transform(data: { items: number[]; prefix: string }): { result: string[]; count: number } {\n return {\n result: data.items.map((n) => `${data.prefix}${n}`),\n count: data.items.length,\n };\n },\n\n // === Error handling ===\n failingMethod(): void {\n throw new Error('Something went wrong');\n },\n\n throwTypeError(): void {\n throw new TypeError('Invalid type');\n },\n\n // === Timeout ===\n async slowMethod(): Promise<string> {\n await new Promise((r) => setTimeout(r, 1000));\n return 'done';\n },\n\n async fastMethod(): Promise<string> {\n await new Promise((r) => setTimeout(r, 10));\n return 'fast';\n },\n\n method(): string {\n return 'result';\n },\n\n // === Streaming (generators) ===\n *countdown(from: number) {\n for (let i = from; i >= 0; i--) {\n yield i;\n }\n },\n\n async *asyncStream(count: number) {\n for (let i = 0; i < count; i++) {\n await new Promise((r) => setTimeout(r, 5));\n yield i * 10;\n }\n },\n\n async *infiniteStream() {\n let i = 0;\n while (true) {\n await new Promise((r) => setTimeout(r, 10));\n yield i++;\n }\n },\n\n // Slow stream for timeout testing - yields every 100ms\n async *slowStream() {\n let i = 0;\n while (true) {\n await new Promise((r) => setTimeout(r, 100));\n yield i++;\n }\n },\n\n *empty() {\n // yields nothing\n },\n\n *failingGenerator() {\n yield 1;\n yield 2;\n throw new Error('Generator failed');\n },\n\n // === State hooks ===\n slowMethodWithCallback(): Promise<number> {\n return new Promise<number>((resolve) => {\n pendingResolvers.set('slowMethodWithCallback', () => resolve(42));\n });\n },\n\n resolveSlowMethod(): void {\n const resolver = pendingResolvers.get('slowMethodWithCallback');\n if (resolver) {\n resolver();\n pendingResolvers.delete('slowMethodWithCallback');\n }\n },\n\n // === Transferables ===\n processBuffer(buffer: ArrayBuffer): number {\n return buffer.byteLength;\n },\n\n combineBuffers(buf1: ArrayBuffer, buf2: ArrayBuffer): number {\n return buf1.byteLength + buf2.byteLength;\n },\n});\n"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "E72E1A6102C7BF2D64756E2164756E21",
12
+ "names": []
13
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Transferable marking utility
3
+ */
4
+ /** Symbol to identify transfer descriptors */
5
+ export declare const TRANSFER: unique symbol;
6
+ /** Descriptor for transferable values */
7
+ export interface TransferDescriptor<T = unknown> {
8
+ [TRANSFER]: true;
9
+ value: T;
10
+ transferables: Transferable[];
11
+ }
12
+ /**
13
+ * Mark a value as Transferable for zero-copy transfer to Worker
14
+ *
15
+ * @example
16
+ * // Single transferable
17
+ * const buffer = new ArrayBuffer(1024)
18
+ * await worker.process(t(buffer))
19
+ * // buffer.byteLength === 0 (transferred)
20
+ *
21
+ * @example
22
+ * // Object with specified transferables
23
+ * const data = { image: buffer, meta: info }
24
+ * await worker.process(t(data, [buffer]))
25
+ */
26
+ export declare function t<T extends Transferable>(value: T): TransferDescriptor<T>;
27
+ export declare function t<T>(value: T, transferables: Transferable[]): TransferDescriptor<T>;
28
+ /**
29
+ * Check if a value is a transfer descriptor
30
+ */
31
+ export declare function isTransferDescriptor(value: unknown): value is TransferDescriptor;
32
+ /**
33
+ * Process arguments to extract transferables
34
+ */
35
+ export declare function prepareArgs(args: unknown[]): {
36
+ args: unknown[];
37
+ transfer: Transferable[];
38
+ };
39
+ //# sourceMappingURL=transfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../src/transfer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,eAA6B,CAAC;AAEnD,yCAAyC;AACzC,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,OAAO;IAC7C,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;IACT,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,CAAC,CAAC,CAAC,SAAS,YAAY,EAAE,KAAK,EAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAC3E,wBAAgB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AASrF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,CAU1F"}
@@ -0,0 +1,31 @@
1
+ // src/transfer.ts
2
+ var TRANSFER = Symbol("threadx.transfer");
3
+ function t(value, transferables) {
4
+ return {
5
+ [TRANSFER]: true,
6
+ value,
7
+ transferables: transferables ?? [value]
8
+ };
9
+ }
10
+ function isTransferDescriptor(value) {
11
+ return typeof value === "object" && value !== null && TRANSFER in value;
12
+ }
13
+ function prepareArgs(args) {
14
+ const transfer = [];
15
+ const processedArgs = args.map((arg) => {
16
+ if (isTransferDescriptor(arg)) {
17
+ transfer.push(...arg.transferables);
18
+ return arg.value;
19
+ }
20
+ return arg;
21
+ });
22
+ return { args: processedArgs, transfer };
23
+ }
24
+ export {
25
+ t,
26
+ prepareArgs,
27
+ isTransferDescriptor,
28
+ TRANSFER
29
+ };
30
+
31
+ //# debugId=43C12BB8E9DAF14864756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/transfer.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Transferable marking utility\n */\n\n/** Symbol to identify transfer descriptors */\nexport const TRANSFER = Symbol('threadx.transfer');\n\n/** Descriptor for transferable values */\nexport interface TransferDescriptor<T = unknown> {\n [TRANSFER]: true;\n value: T;\n transferables: Transferable[];\n}\n\n/**\n * Mark a value as Transferable for zero-copy transfer to Worker\n *\n * @example\n * // Single transferable\n * const buffer = new ArrayBuffer(1024)\n * await worker.process(t(buffer))\n * // buffer.byteLength === 0 (transferred)\n *\n * @example\n * // Object with specified transferables\n * const data = { image: buffer, meta: info }\n * await worker.process(t(data, [buffer]))\n */\nexport function t<T extends Transferable>(value: T): TransferDescriptor<T>;\nexport function t<T>(value: T, transferables: Transferable[]): TransferDescriptor<T>;\nexport function t<T>(value: T, transferables?: Transferable[]): TransferDescriptor<T> {\n return {\n [TRANSFER]: true,\n value,\n transferables: transferables ?? [value as unknown as Transferable],\n };\n}\n\n/**\n * Check if a value is a transfer descriptor\n */\nexport function isTransferDescriptor(value: unknown): value is TransferDescriptor {\n return typeof value === 'object' && value !== null && TRANSFER in value;\n}\n\n/**\n * Process arguments to extract transferables\n */\nexport function prepareArgs(args: unknown[]): { args: unknown[]; transfer: Transferable[] } {\n const transfer: Transferable[] = [];\n const processedArgs = args.map((arg) => {\n if (isTransferDescriptor(arg)) {\n transfer.push(...arg.transferables);\n return arg.value;\n }\n return arg;\n });\n return { args: processedArgs, transfer };\n}\n"
6
+ ],
7
+ "mappings": ";AAKO,IAAM,WAAW,OAAO,kBAAkB;AAyB1C,SAAS,CAAI,CAAC,OAAU,eAAuD;AAAA,EACpF,OAAO;AAAA,KACJ,WAAW;AAAA,IACZ;AAAA,IACA,eAAe,iBAAiB,CAAC,KAAgC;AAAA,EACnE;AAAA;AAMK,SAAS,oBAAoB,CAAC,OAA6C;AAAA,EAChF,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,YAAY;AAAA;AAM7D,SAAS,WAAW,CAAC,MAAgE;AAAA,EAC1F,MAAM,WAA2B,CAAC;AAAA,EAClC,MAAM,gBAAgB,KAAK,IAAI,CAAC,QAAQ;AAAA,IACtC,IAAI,qBAAqB,GAAG,GAAG;AAAA,MAC7B,SAAS,KAAK,GAAG,IAAI,aAAa;AAAA,MAClC,OAAO,IAAI;AAAA,IACb;AAAA,IACA,OAAO;AAAA,GACR;AAAA,EACD,OAAO,EAAE,MAAM,eAAe,SAAS;AAAA;",
8
+ "debugId": "43C12BB8E9DAF14864756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Type utilities for ThreadX
3
+ */
4
+ /**
5
+ * Worker state
6
+ */
7
+ export type WorkerState = 'init' | 'ready' | 'dead';
8
+ /**
9
+ * Options for wrap()
10
+ */
11
+ export interface WrapOptions {
12
+ /** Default timeout in milliseconds (default: 30000) */
13
+ timeout?: number;
14
+ /** Debug name for logging */
15
+ name?: string;
16
+ }
17
+ /**
18
+ * Marker interface for TransferDescriptor (avoids circular import)
19
+ * Must include the symbol marker to ensure type safety
20
+ */
21
+ interface TransferMarker<T> {
22
+ readonly [key: symbol]: true;
23
+ readonly value: T;
24
+ readonly transferables: Transferable[];
25
+ }
26
+ /**
27
+ * Allow a parameter to be the original type or wrapped in TransferDescriptor
28
+ */
29
+ type MaybeTransfer<T> = T | TransferMarker<T>;
30
+ /**
31
+ * Convert each parameter to allow TransferDescriptor wrapping
32
+ */
33
+ type TransferableArgs<A extends unknown[]> = {
34
+ [K in keyof A]: MaybeTransfer<A[K]>;
35
+ };
36
+ /**
37
+ * Convert a function type to its wrapped version:
38
+ * - Generator<T> → AsyncIterable<T>
39
+ * - AsyncGenerator<T> → AsyncIterable<T>
40
+ * - T | Promise<T> → Promise<T>
41
+ * - Parameters can be wrapped with t() for transfer
42
+ */
43
+ export type Promisify<T> = T extends (...args: infer A) => Generator<infer Y, unknown, unknown> ? (...args: TransferableArgs<A>) => AsyncIterable<Y> : T extends (...args: infer A) => AsyncGenerator<infer Y, unknown, unknown> ? (...args: TransferableArgs<A>) => AsyncIterable<Y> : T extends (...args: infer A) => infer R ? (...args: TransferableArgs<A>) => Promise<Awaited<R>> : never;
44
+ /**
45
+ * Convert a module of functions to wrapped versions
46
+ */
47
+ export type WrapModule<T> = {
48
+ [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: Promisify<T[K]>;
49
+ };
50
+ /**
51
+ * The wrapped worker proxy type with state hooks
52
+ */
53
+ export type WrappedWorker<T> = WrapModule<T> & {
54
+ /** Current worker state */
55
+ readonly $state: WorkerState;
56
+ /** Number of pending calls */
57
+ readonly $pending: number;
58
+ /** Original Worker instance (escape hatch) */
59
+ readonly $worker: Worker;
60
+ };
61
+ export {};
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,UAAU,cAAc,CAAC,CAAC;IACxB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,aAAa,EAAE,YAAY,EAAE,CAAC;CACxC;AAED;;GAEG;AACH,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;AAE9C;;GAEG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI;KAC1C,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAC3F,CAAC,GAAG,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,GAClD,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GACvE,CAAC,GAAG,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,GAClD,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GACrC,CAAC,GAAG,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GACrD,KAAK,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;KAEzB,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpF,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IAC7C,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,8BAA8B;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# debugId=738E8C95A4978BED64756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "738E8C95A4978BED64756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Worker-side API for ThreadX
3
+ */
4
+ export { t } from './transfer.js';
5
+ type AnyFunction = (...args: unknown[]) => unknown;
6
+ type MethodMap = Record<string, AnyFunction>;
7
+ /**
8
+ * Expose methods to the main thread
9
+ *
10
+ * @example
11
+ * import { expose } from '@shelchin/threadx/worker'
12
+ *
13
+ * expose({
14
+ * add(a: number, b: number) {
15
+ * return a + b
16
+ * },
17
+ *
18
+ * async heavyTask(data: ArrayBuffer) {
19
+ * // Long running computation...
20
+ * return result
21
+ * },
22
+ *
23
+ * *progress(total: number) {
24
+ * for (let i = 0; i <= total; i++) {
25
+ * yield i
26
+ * }
27
+ * }
28
+ * })
29
+ */
30
+ export declare function expose<T extends MethodMap>(methods: T): void;
31
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,KAAK,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AACnD,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AA8C7C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAgF5D"}