@offmain/workerkit 0.14.1 → 1.0.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.
Files changed (58) hide show
  1. package/README.md +208 -40
  2. package/dist/define-worker.cjs +1 -0
  3. package/dist/define-worker.js +4 -0
  4. package/dist/index-2AONniOz.js +59 -0
  5. package/dist/index-CXKVsLvY.cjs +1 -0
  6. package/dist/index.cjs +196 -44
  7. package/dist/index.js +913 -631
  8. package/dist/types/tools/collect-results/collect-results.d.ts +26 -0
  9. package/dist/types/tools/collect-results/index.d.ts +2 -0
  10. package/dist/types/tools/collect-results/types.d.ts +10 -0
  11. package/dist/types/tools/define-worker/define-worker.d.ts +31 -0
  12. package/dist/types/tools/define-worker/define-worker.test.d.ts +1 -0
  13. package/dist/types/tools/define-worker/index.d.ts +1 -0
  14. package/dist/types/tools/define-worker-config/define-worker-config.d.ts +23 -0
  15. package/dist/types/tools/define-worker-config/index.d.ts +1 -0
  16. package/dist/types/tools/extract-transferable/extract-transferable.d.ts +15 -0
  17. package/dist/types/tools/extract-transferable/extract-transferable.test.d.ts +1 -0
  18. package/dist/types/tools/extract-transferable/index.d.ts +1 -0
  19. package/dist/types/tools/index.d.ts +2 -0
  20. package/dist/types/tools/logger/index.d.ts +2 -0
  21. package/dist/types/tools/logger/logger.d.ts +21 -0
  22. package/dist/types/tools/logger/logger.test.d.ts +1 -0
  23. package/dist/types/tools/logger/types.d.ts +6 -0
  24. package/dist/types/tools/main-worker-factory/main-worker-factory.d.ts +87 -244
  25. package/dist/types/tools/main-worker-factory/types.d.ts +54 -4
  26. package/dist/types/tools/memory-store/index.d.ts +3 -0
  27. package/dist/types/tools/memory-store/memory-store.d.ts +50 -0
  28. package/dist/types/tools/memory-store/memory-store.test.d.ts +1 -0
  29. package/dist/types/tools/memory-store/memory-worker-proxy.d.ts +75 -0
  30. package/dist/types/tools/memory-store/memory-worker.d.ts +11 -0
  31. package/dist/types/tools/orchestrator/index.d.ts +2 -0
  32. package/dist/types/tools/orchestrator/orchestrator.d.ts +21 -0
  33. package/dist/types/tools/orchestrator/orchestrator.test.d.ts +1 -0
  34. package/dist/types/tools/orchestrator/types.d.ts +10 -0
  35. package/dist/types/tools/partition-array/index.d.ts +1 -0
  36. package/dist/types/tools/partition-array/partition-array.d.ts +14 -0
  37. package/dist/types/tools/partition-array/partition-array.test.d.ts +1 -0
  38. package/dist/types/tools/persistent-manager/index.d.ts +2 -0
  39. package/dist/types/tools/persistent-manager/persistent-manager.d.ts +25 -0
  40. package/dist/types/tools/persistent-manager/persistent-manager.test.d.ts +1 -0
  41. package/dist/types/tools/persistent-manager/types.d.ts +9 -0
  42. package/dist/types/tools/pipeline/index.d.ts +2 -0
  43. package/dist/types/tools/pipeline/pipeline.d.ts +17 -0
  44. package/dist/types/tools/pipeline/pipeline.test.d.ts +1 -0
  45. package/dist/types/tools/pipeline/types.d.ts +13 -0
  46. package/dist/types/tools/run-worker/index.d.ts +2 -0
  47. package/dist/types/tools/run-worker/run-worker.d.ts +26 -0
  48. package/dist/types/tools/run-worker/run-worker.test.d.ts +1 -0
  49. package/dist/types/tools/run-worker/types.d.ts +14 -0
  50. package/dist/types/tools/worker-factory/index.d.ts +1 -1
  51. package/dist/types/tools/worker-factory/worker-factory.d.ts +7 -1
  52. package/dist/types/workers/initiator.d.ts +1 -1
  53. package/dist/types/workers/initiator.test.d.ts +1 -0
  54. package/package.json +11 -5
  55. package/dist/types/tools/define-worker.d.ts +0 -21
  56. package/dist/types/tools/main-worker-factory/memory-store.d.ts +0 -45
  57. package/dist/types/tools/main-worker-factory/memory-worker.d.ts +0 -7
  58. /package/dist/types/tools/{define-worker.test.d.ts → collect-results/collect-results.test.d.ts} +0 -0
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
- var x = Object.defineProperty;
2
- var O = (l, e, r) => e in l ? x(l, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : l[e] = r;
3
- var _ = (l, e, r) => O(l, typeof e != "symbol" ? e + "" : e, r);
4
- const j = (l) => `
1
+ var C = Object.defineProperty;
2
+ var O = (o, e, r) => e in o ? C(o, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : o[e] = r;
3
+ var y = (o, e, r) => O(o, typeof e != "symbol" ? e + "" : e, r);
4
+ import { e as E } from "./index-2AONniOz.js";
5
+ import { d as ie } from "./index-2AONniOz.js";
6
+ const R = `
5
7
  const extractTransferables = (value, seen = new Set()) => {
6
8
  if (value === null || typeof value !== 'object') return [];
7
9
  if (seen.has(value)) return [];
@@ -15,31 +17,73 @@ const extractTransferables = (value, seen = new Set()) => {
15
17
  if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
16
18
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
17
19
  };
18
-
20
+ `, U = (o) => `
21
+ ${R}
19
22
  self.addEventListener('message', async (event) => {
20
23
  try {
21
- const output = await ${l}(event.data);
24
+ const output = await ${o}(event.data);
22
25
  self.postMessage({ ok: true, data: output }, extractTransferables(output));
23
26
  } catch (err) {
24
27
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
25
28
  }
26
29
  })
27
- `, L = (l) => `
28
- const extractTransferables = (value, seen = new Set()) => {
29
- if (value === null || typeof value !== 'object') return [];
30
- if (seen.has(value)) return [];
31
- seen.add(value);
32
- if (value instanceof ArrayBuffer || value instanceof MessagePort ||
33
- (typeof ImageBitmap !== 'undefined' && value instanceof ImageBitmap) ||
34
- (typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas)) {
35
- return [value];
30
+ `, N = (o) => `
31
+ ${R}
32
+ const workerFn = ${o};
33
+ let memPort = null;
34
+ let factoryToken = null;
35
+ let pendingPayload = null;
36
+
37
+ async function runAndStore(payload) {
38
+ try {
39
+ const output = await workerFn(payload);
40
+ if (!memPort) {
41
+ // Fallback: no port provided, post data directly (legacy / opt-out path)
42
+ self.postMessage({ ok: true, data: output }, extractTransferables(output));
43
+ return;
44
+ }
45
+ // Store directly into MemoryWorker
46
+ const ref = 'mem_' + crypto.randomUUID();
47
+ await new Promise((resolve, reject) => {
48
+ memPort.onmessage = (e) => {
49
+ if (e.data && e.data.ref === ref) {
50
+ if (e.data.ok) resolve(e.data.ref);
51
+ else reject(new Error(e.data.error || 'MemoryWorker SET failed'));
52
+ }
53
+ };
54
+ memPort.postMessage({ action: 'SET', factoryToken, ref, data: output });
55
+ });
56
+ // Only the token reaches the main thread
57
+ self.postMessage({ ok: true, __memory_ref__: ref });
58
+ } catch (err) {
59
+ self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
36
60
  }
37
- if (ArrayBuffer.isView(value)) return [value.buffer];
38
- if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
39
- return Object.values(value).flatMap(v => extractTransferables(v, seen));
40
- };
61
+ }
41
62
 
42
- const workerFn = ${l};
63
+ self.addEventListener('message', async (event) => {
64
+ // Init message: receive the MemoryWorker port and factory token
65
+ if (event.data && event.data.__init_memory_port__) {
66
+ memPort = event.ports[0] ?? event.data.memPort;
67
+ factoryToken = event.data.factoryToken;
68
+ if (memPort) memPort.start();
69
+ // If a payload arrived before the port, process it now
70
+ if (pendingPayload !== null) {
71
+ const p = pendingPayload;
72
+ pendingPayload = null;
73
+ await runAndStore(p);
74
+ }
75
+ return;
76
+ }
77
+ // If port not yet received, queue the payload
78
+ if (!memPort) {
79
+ pendingPayload = event.data;
80
+ return;
81
+ }
82
+ await runAndStore(event.data);
83
+ });
84
+ `, j = (o) => `
85
+ ${R}
86
+ const workerFn = ${o};
43
87
  let outputPort = null;
44
88
  let inputPort = null;
45
89
  let pendingData = null;
@@ -104,22 +148,9 @@ self.addEventListener('message', (event) => {
104
148
  pendingData = event.data;
105
149
  }
106
150
  });
107
- `, C = (l) => `
108
- const extractTransferables = (value, seen = new Set()) => {
109
- if (value === null || typeof value !== 'object') return [];
110
- if (seen.has(value)) return [];
111
- seen.add(value);
112
- if (value instanceof ArrayBuffer || value instanceof MessagePort ||
113
- (typeof ImageBitmap !== 'undefined' && value instanceof ImageBitmap) ||
114
- (typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas)) {
115
- return [value];
116
- }
117
- if (ArrayBuffer.isView(value)) return [value.buffer];
118
- if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
119
- return Object.values(value).flatMap(v => extractTransferables(v, seen));
120
- };
121
-
122
- const workerFn = ${l};
151
+ `, G = (o) => `
152
+ ${R}
153
+ const workerFn = ${o};
123
154
  let cachedDataset = null;
124
155
 
125
156
  self.addEventListener('message', async (event) => {
@@ -161,13 +192,14 @@ self.addEventListener('message', async (event) => {
161
192
  }
162
193
  });
163
194
  `;
164
- var P = /* @__PURE__ */ ((l) => (l.Default = "default", l.Pipeline = "pipeline", l.Persistent = "persistent", l))(P || {});
165
- const F = Object.freeze({
166
- persistent: C,
167
- pipeline: L,
168
- default: j
195
+ var D = /* @__PURE__ */ ((o) => (o.Default = "default", o.Pipeline = "pipeline", o.Persistent = "persistent", o.Memory = "memory", o))(D || {});
196
+ const q = Object.freeze({
197
+ persistent: G,
198
+ pipeline: j,
199
+ default: U,
200
+ memory: N
169
201
  });
170
- class M {
202
+ class b {
171
203
  /**
172
204
  * Creates a new `Worker` from the given function or factory option.
173
205
  *
@@ -177,14 +209,14 @@ class M {
177
209
  * @param options - Optional configuration containing `createWorker` or `mode`.
178
210
  */
179
211
  constructor(e, r) {
180
- _(this, "_worker");
212
+ y(this, "_worker");
181
213
  if (r != null && r.createWorker)
182
214
  this._worker = r.createWorker();
183
215
  else if (e) {
184
- const a = (r == null ? void 0 : r.mode) ?? "default", t = F[a](e.toString()), i = new Blob([t], {
216
+ const a = (r == null ? void 0 : r.mode) ?? "default", t = q[a](e.toString()), l = new Blob([t], {
185
217
  type: "application/javascript"
186
218
  });
187
- this._worker = new Worker(URL.createObjectURL(i));
219
+ this._worker = new Worker(URL.createObjectURL(l));
188
220
  } else
189
221
  throw new Error(
190
222
  "Either workerFunction or options.createWorker must be provided to WorkerFactory."
@@ -200,58 +232,43 @@ class M {
200
232
  return this._worker;
201
233
  }
202
234
  }
203
- class I {
204
- constructor(e) {
205
- this.results = e;
206
- }
207
- }
208
- class $ {
235
+ class z {
209
236
  constructor() {
210
- _(this, "store", /* @__PURE__ */ new Map());
237
+ y(this, "store", /* @__PURE__ */ new Map());
211
238
  }
212
239
  /**
213
- * Stores a dataset in RAM under an unguessable reference ID.
240
+ * Registers a ref in the registry.
214
241
  *
215
- * @param data - The dataset to store.
216
- * @param refId - Optional reference ID; if omitted, a UUID will be generated.
217
- * @returns The reference ID under which the dataset is stored.
242
+ * @param ref - The memory reference ID (generated by MemoryWorkerProxy).
243
+ * @param metadata - Optional metadata (size hint, type tag, etc.).
218
244
  */
219
- set(e, r) {
220
- const a = r ?? `mem_${crypto.randomUUID()}`;
221
- return this.store.set(a, e), a;
245
+ register(e, r = {}) {
246
+ this.store.set(e, r);
222
247
  }
223
248
  /**
224
- * Retrieves a dataset from RAM by its reference ID.
225
- *
226
- * @param refId - The reference ID to retrieve.
227
- * @returns The stored dataset, or undefined if not found.
249
+ * Checks if a reference ID is registered.
250
+ * @param refId - The reference ID to check.
228
251
  */
229
- get(e) {
230
- return this.store.get(e);
252
+ has(e) {
253
+ return this.store.has(e);
231
254
  }
232
255
  /**
233
- * Deletes a dataset reference from RAM.
256
+ * Unregisters a reference ID.
234
257
  *
235
- * @param refId - The reference ID to delete.
258
+ * @param refId - The reference ID to unregister.
236
259
  * @returns `true` if the key existed and was removed, `false` otherwise.
237
260
  */
238
261
  delete(e) {
239
262
  return this.store.delete(e);
240
263
  }
241
264
  /**
242
- * Clears all dataset handles from RAM.
265
+ * Clears all registered references.
243
266
  */
244
267
  clear() {
245
268
  this.store.clear();
246
269
  }
247
270
  /**
248
- * Checks if a reference ID exists in RAM.
249
- */
250
- has(e) {
251
- return this.store.has(e);
252
- }
253
- /**
254
- * Returns statistics about current memory handles.
271
+ * Returns statistics about current registered handles.
255
272
  */
256
273
  stats() {
257
274
  return {
@@ -260,708 +277,973 @@ class $ {
260
277
  };
261
278
  }
262
279
  }
263
- function w(l, e = /* @__PURE__ */ new Set()) {
264
- return l === null || typeof l != "object" ? [] : e.has(l) ? [] : (e.add(l), l instanceof ArrayBuffer || l instanceof MessagePort || typeof ImageBitmap < "u" && l instanceof ImageBitmap || typeof OffscreenCanvas < "u" && l instanceof OffscreenCanvas ? [l] : ArrayBuffer.isView(l) ? [l.buffer] : Array.isArray(l) ? l.flatMap((r) => w(r, e)) : Object.values(l).flatMap(
265
- (r) => w(r, e)
266
- ));
280
+ const K = `
281
+ const store = new Map();
282
+
283
+ function handleMessage(msg, replyTarget) {
284
+ if (!msg || typeof msg !== 'object') return;
285
+
286
+ const { action, factoryToken, expectedToken, ref, data, id } = msg;
287
+
288
+ // Initial handshake to set expected token if needed
289
+ if (action === 'INIT_TOKEN') {
290
+ self.__expectedToken = expectedToken;
291
+ replyTarget.postMessage({ ok: true, action: 'INIT_TOKEN_ACK' });
292
+ return;
293
+ }
294
+
295
+ // Validate factory token
296
+ if (self.__expectedToken && factoryToken !== self.__expectedToken) {
297
+ replyTarget.postMessage({ ok: false, error: 'Unauthorized: invalid factory token', id });
298
+ return;
299
+ }
300
+
301
+ try {
302
+ switch (action) {
303
+ case 'SET': {
304
+ const refId = ref || ('mem_' + crypto.randomUUID());
305
+ store.set(refId, data);
306
+ replyTarget.postMessage({ ok: true, ref: refId, id });
307
+ break;
308
+ }
309
+ case 'GET': {
310
+ const resultData = store.get(ref);
311
+ const exists = store.has(ref);
312
+ replyTarget.postMessage({ ok: true, exists, data: resultData, ref, id });
313
+ break;
314
+ }
315
+ case 'DELETE': {
316
+ const deleted = store.delete(ref);
317
+ replyTarget.postMessage({ ok: true, deleted, ref, id });
318
+ break;
319
+ }
320
+ case 'CLEAR': {
321
+ store.clear();
322
+ replyTarget.postMessage({ ok: true, action: 'CLEAR_ACK', id });
323
+ break;
324
+ }
325
+ case 'STATS': {
326
+ replyTarget.postMessage({
327
+ ok: true,
328
+ stats: {
329
+ count: store.size,
330
+ refs: Array.from(store.keys()),
331
+ },
332
+ id,
333
+ });
334
+ break;
335
+ }
336
+ case 'REGISTER_PORT': {
337
+ // Register a MessagePort from a computing or reducer worker.
338
+ // All messages arriving on this port are handled with the same
339
+ // store operations, enabling direct worker-to-MemoryWorker data flow.
340
+ const port = msg.port;
341
+ if (!port) {
342
+ replyTarget.postMessage({ ok: false, error: 'REGISTER_PORT requires a port', id });
343
+ break;
344
+ }
345
+ port.onmessage = (event) => handleMessage(event.data, port);
346
+ port.start();
347
+ replyTarget.postMessage({ ok: true, action: 'PORT_REGISTERED', id });
348
+ break;
349
+ }
350
+ default:
351
+ replyTarget.postMessage({ ok: false, error: 'Unknown action: ' + action, id });
352
+ }
353
+ } catch (err) {
354
+ replyTarget.postMessage({
355
+ ok: false,
356
+ error: err instanceof Error ? err.message : String(err),
357
+ id,
358
+ });
359
+ }
267
360
  }
268
- class q {
269
- /**
270
- * Creates a new `MainWorkerFactory`.
271
- *
272
- * @param options - Configuration object containing the `workers` registry.
273
- */
361
+
362
+ self.addEventListener('message', (event) => {
363
+ // Handle REGISTER_PORT specially — the port itself is a Transferable in event.ports
364
+ if (event.data && event.data.action === 'REGISTER_PORT') {
365
+ const port = event.ports[0] ?? event.data.port;
366
+ const msg = { ...event.data, port };
367
+ handleMessage(msg, self);
368
+ return;
369
+ }
370
+ handleMessage(event.data, self);
371
+ });
372
+ `;
373
+ class H {
274
374
  constructor(e) {
275
- _(this, "_workers");
276
- _(this, "_threads");
277
- _(this, "_persistentWorkers", /* @__PURE__ */ new Map());
278
- _(this, "_activeWorkers", /* @__PURE__ */ new Set());
279
- _(this, "_memoryStore", new $());
280
- _(this, "_isTerminated", !1);
281
- this._workers = e.workers, this._threads = navigator.hardwareConcurrency;
375
+ y(this, "worker");
376
+ y(this, "factoryToken");
377
+ y(this, "pending", /* @__PURE__ */ new Map());
378
+ this.factoryToken = e;
379
+ const r = new Blob([K], {
380
+ type: "application/javascript"
381
+ });
382
+ this.worker = new Worker(URL.createObjectURL(r)), this.worker.onmessage = (a) => {
383
+ const { id: t } = a.data ?? {};
384
+ if (t && this.pending.has(t)) {
385
+ const l = this.pending.get(t);
386
+ this.pending.delete(t), l(a.data);
387
+ }
388
+ }, this.worker.postMessage({
389
+ action: "INIT_TOKEN",
390
+ expectedToken: e
391
+ });
392
+ }
393
+ send(e, r = {}) {
394
+ return new Promise((a) => {
395
+ const t = `req_${crypto.randomUUID()}`;
396
+ this.pending.set(t, a), this.worker.postMessage({
397
+ action: e,
398
+ factoryToken: this.factoryToken,
399
+ id: t,
400
+ ...r
401
+ });
402
+ });
282
403
  }
283
404
  /**
284
- * Returns `true` if the factory has been terminated.
405
+ * Stores a dataset in the MemoryWorker.
406
+ *
407
+ * @param data - The dataset to store.
408
+ * @param ref - Optional ref ID; if omitted, MemoryWorker generates one.
409
+ * @returns The ref ID under which the data is stored.
285
410
  */
286
- get isTerminated() {
287
- return this._isTerminated;
411
+ async set(e, r) {
412
+ const a = await this.send("SET", { data: e, ref: r });
413
+ if (!a.ok) throw new Error(a.error);
414
+ return a.ref;
288
415
  }
289
416
  /**
290
- * Registers an active worker instance for lifecycle tracking.
417
+ * Retrieves a dataset from the MemoryWorker by ref ID.
418
+ *
419
+ * @param ref - The ref ID to retrieve.
420
+ * @returns The stored dataset, or `undefined` if not found.
291
421
  */
292
- trackWorker(e) {
293
- if (this._isTerminated)
294
- throw e.terminate(), new Error("MainWorkerFactory has been terminated");
295
- return this._activeWorkers.add(e), e;
422
+ async get(e) {
423
+ const r = await this.send("GET", { ref: e });
424
+ if (!r.ok) throw new Error(r.error);
425
+ return r.data;
296
426
  }
297
427
  /**
298
- * Terminates a worker instance and removes it from tracking.
428
+ * Checks if a ref ID exists in the MemoryWorker.
429
+ * @param ref - The ref ID to check.
299
430
  */
300
- terminateWorker(e) {
301
- this._activeWorkers.delete(e);
302
- try {
303
- e.terminate();
304
- } catch {
305
- }
431
+ async has(e) {
432
+ const r = await this.send("GET", { ref: e });
433
+ if (!r.ok) throw new Error(r.error);
434
+ return !!r.exists;
306
435
  }
307
436
  /**
308
- * Instantiates a {@link WorkerFactory} for the given worker configuration.
437
+ * Deletes a ref from the MemoryWorker.
309
438
  *
310
- * @param config - The worker configuration containing `func` or `createWorker`.
311
- * @returns A new `WorkerFactory` wrapping the worker.
439
+ * @param ref - The ref ID to delete.
440
+ * @returns `true` if the ref existed and was deleted.
312
441
  */
313
- initWorker(e) {
314
- const r = new M(e.func, {
315
- createWorker: e.createWorker
316
- });
317
- return this.trackWorker(r.getWorker), r;
442
+ async delete(e) {
443
+ const r = await this.send("DELETE", { ref: e });
444
+ if (!r.ok) throw new Error(r.error);
445
+ return !!r.deleted;
318
446
  }
319
447
  /**
320
- * Splits an array into up to `numChunks` evenly-sized sub-arrays.
321
- *
322
- * When the array length is not evenly divisible, the first `remainder`
323
- * chunks receive one extra element so no data is lost.
324
- *
325
- * @param array - The source array to partition.
326
- * @param numChunks - Maximum number of chunks to produce.
327
- * Clamped to `array.length` so you never get empty chunks.
328
- * @returns An array of sub-arrays. Returns `[]` when `array` is empty.
329
- * @throws {Error} When `numChunks` is not a positive integer.
330
- *
331
- * @example
332
- * partitionArray([1, 2, 3, 4, 5], 3);
333
- * // → [[1, 2], [3, 4], [5]]
448
+ * Clears all data from the MemoryWorker.
334
449
  */
335
- partitionArray(e, r) {
336
- if (!e.length) return [];
337
- if (r <= 0) throw new Error("numChunks must be positive");
338
- const a = Math.min(r, e.length), t = Math.floor(e.length / a), i = e.length % a, f = [];
339
- let d = 0;
340
- for (let s = 0; s < a; s++) {
341
- const o = t + (s < i ? 1 : 0);
342
- f.push(e.slice(d, d + o)), d += o;
343
- }
344
- return f;
450
+ async clear() {
451
+ const e = await this.send("CLEAR");
452
+ if (!e.ok) throw new Error(e.error);
345
453
  }
346
454
  /**
347
- * Looks up a registered worker configuration by name.
348
- *
349
- * @param name - The `name` field of the target {@link WorkerConfig}.
350
- * @returns The matching config, or `undefined` if not found.
455
+ * Returns statistics about data held in the MemoryWorker.
351
456
  */
352
- findWorkerByName(e) {
353
- return this._workers.find((r) => r.name === e);
457
+ async stats() {
458
+ const e = await this.send("STATS");
459
+ if (!e.ok) throw new Error(e.error);
460
+ return e.stats;
354
461
  }
355
462
  /**
356
- * Runs a named worker against the provided data, distributing work across
357
- * threads when the worker is configured for partitioning.
358
- *
359
- * When `config.partition` is `true` and `srcData` is an array with more
360
- * than one element, the array is split into up to `maxConcurrency` (or
361
- * `navigator.hardwareConcurrency`) shards and each shard is processed by
362
- * a separate worker thread in parallel.
363
- *
364
- * All threads are awaited with `Promise.allSettled`, so a failure in one
365
- * shard does not cancel the others. Use {@link collectResults} to merge
366
- * the settled output.
463
+ * Allocates a direct `MessagePort` to the MemoryWorker for a computing or
464
+ * reducer worker.
367
465
  *
368
- * @typeParam TName - The literal name of the worker to run (inferred from
369
- * the registered `workers` tuple).
466
+ * Creates a `MessageChannel` and registers one port with MemoryWorker via
467
+ * `REGISTER_PORT`. The other port (the "worker-side" port) is returned as a
468
+ * `Transferable` — it should be passed to the target worker via
469
+ * `postMessage(..., [workerPort])` so the worker can communicate with
470
+ * MemoryWorker directly without routing through the main thread.
370
471
  *
371
- * @param workerName - Name of the worker as declared in the `workers` config.
372
- * @param params - Object containing `srcData` (the payload) plus any
373
- * additional key/value pairs forwarded to the worker verbatim.
374
- *
375
- * @returns A {@link TypedSettledResults} wrapping the settled promises from
376
- * all spawned worker threads.
377
- *
378
- * @example
379
- * const settled = await foreman.runWorker('sum', { srcData: [1, 2, 3] });
472
+ * @returns The worker-side `MessagePort` ready to be transferred.
380
473
  */
381
- async runWorker(e, r) {
382
- if (this._isTerminated)
383
- return Promise.reject(new Error("MainWorkerFactory has been terminated"));
384
- const a = this.findWorkerByName(e);
385
- if (!a)
386
- return Promise.reject(new Error(`Worker "${e}" not found`));
387
- let { srcData: t, ...i } = r || {};
388
- const f = i.__memory_ref__, d = !!i.deleteMemory;
389
- if (t === void 0 && f) {
390
- if (!this._memoryStore.has(f))
391
- return Promise.reject(
392
- new Error(`Memory reference "${f}" not found in MemoryStore`)
393
- );
394
- t = this._memoryStore.get(f), delete i.__memory_ref__, delete i.deleteMemory;
395
- } else
396
- delete i.deleteMemory;
397
- const s = a.maxConcurrency ?? this._threads, o = !!(Array.isArray(t) && a.partition), u = o ? this.partitionArray(t, s) : t, m = o && Array.isArray(u) ? u.length : s, p = this.createWorkerPromises(
398
- a,
399
- e,
400
- { data: u, ...i },
401
- m,
402
- o
403
- ), c = await Promise.allSettled(p);
404
- return d && f && this._memoryStore.delete(f), (a.memoryOnly || a.memory) && this.storeWorkerMemoryResult(c, {
405
- memoryOnly: !!a.memoryOnly,
406
- shouldPartition: o
407
- }), new I(c);
474
+ async allocateWorkerPort() {
475
+ const e = new MessageChannel(), { port1: r, port2: a } = e, t = `req_${crypto.randomUUID()}`;
476
+ return this.pending.set(t, () => {
477
+ }), this.worker.postMessage(
478
+ {
479
+ action: "REGISTER_PORT",
480
+ factoryToken: this.factoryToken,
481
+ id: t
482
+ },
483
+ [r]
484
+ ), await new Promise((l) => {
485
+ const f = this.pending.get(t);
486
+ this.pending.set(t, (m) => {
487
+ f(m), l();
488
+ });
489
+ }), a;
408
490
  }
409
491
  /**
410
- * Deletes a specific memory reference from the factory's memory store.
411
- *
412
- * @param ref - The `__memory_ref__` token string to delete.
413
- * @returns A promise that resolves to `true` if deleted, `false` otherwise.
492
+ * Terminates the MemoryWorker thread and clears all pending requests.
414
493
  */
415
- async deleteMemory(e) {
416
- return this._memoryStore.delete(e);
494
+ terminate() {
495
+ this.pending.clear(), this.worker.terminate();
417
496
  }
418
- /**
419
- * Clears all stored dataset references from the factory's memory store.
420
- */
421
- async clearMemory() {
422
- this._memoryStore.clear();
497
+ }
498
+ class J {
499
+ constructor(e = "error") {
500
+ y(this, "level");
501
+ this.level = e;
423
502
  }
424
- /**
425
- * Saves the output of a completed worker execution into MemoryStore
426
- * and modifies the returned settled results with a `__memory_ref__` token.
427
- */
428
- storeWorkerMemoryResult(e, {
429
- memoryOnly: r,
430
- shouldPartition: a
431
- }) {
432
- const t = e.filter(
433
- (s) => s.status === "fulfilled" && !!s.value.successResult
503
+ setLevel(e) {
504
+ this.level = e;
505
+ }
506
+ verbose(...e) {
507
+ this.level === "verbose" && console.debug("[WorkerManager]", ...e);
508
+ }
509
+ info(...e) {
510
+ (this.level === "verbose" || this.level === "info") && console.info("[WorkerManager]", ...e);
511
+ }
512
+ error(...e) {
513
+ this.level !== "silent" && console.error("[WorkerManager]", ...e);
514
+ }
515
+ }
516
+ class V {
517
+ constructor(e) {
518
+ this.results = e;
519
+ }
520
+ }
521
+ function B(o, e) {
522
+ if (!o.length) return [];
523
+ if (e <= 0) throw new Error("numChunks must be positive");
524
+ const r = Math.min(e, o.length), a = Math.floor(o.length / r), t = o.length % r, l = [];
525
+ let f = 0;
526
+ for (let m = 0; m < r; m++) {
527
+ const i = a + (m < t ? 1 : 0);
528
+ l.push(o.slice(f, f + i)), f += i;
529
+ }
530
+ return l;
531
+ }
532
+ async function x(o, e = {}, r) {
533
+ if (r.isTerminated())
534
+ throw r.logger.error(
535
+ "Attempted to collect results after MainWorkerFactory was terminated"
536
+ ), new Error("MainWorkerFactory has been terminated");
537
+ const a = o.results.filter(
538
+ (n) => n.status === "fulfilled"
539
+ ), t = o.results.filter(
540
+ (n) => n.status === "rejected"
541
+ );
542
+ if (a.length === 0)
543
+ return {
544
+ data: [],
545
+ succeeded: 0,
546
+ failed: t.length,
547
+ errors: t
548
+ };
549
+ const l = a.map((n) => {
550
+ var k;
551
+ const c = (k = n.value.successResult) == null ? void 0 : k.data;
552
+ return c == null ? void 0 : c.__memory_ref__;
553
+ }), f = l.every((n) => typeof n == "string"), m = e.reducer ? e.reducer.toString() : "(shards) => shards.flat()";
554
+ let i;
555
+ if (f && typeof Worker < "u" && typeof Blob < "u" && typeof MessageChannel < "u") {
556
+ const n = await r.memoryWorkerProxy.allocateWorkerPort(), c = `
557
+ const refs = ${JSON.stringify(l)};
558
+ const factoryToken = ${JSON.stringify(r.factoryToken)};
559
+ const reducer = ${m};
560
+
561
+ // collect-results.ts
562
+
563
+ self.addEventListener('message', async (event) => {
564
+ // event.ports[0] is the direct line to MemoryWorker
565
+ const memPort = event.ports[0];
566
+ if (!memPort) {
567
+ self.postMessage({ ok: false, error: 'No MemoryWorker port provided' });
568
+ self.close();
569
+ return;
570
+ }
571
+ memPort.start();
572
+
573
+ try {
574
+ // Fetch each shard directly from MemoryWorker
575
+ const shards = await Promise.all(refs.map((ref) =>
576
+ new Promise((resolve, reject) => {
577
+ const reqId = 'fetch_' + ref;
578
+ memPort.addEventListener('message', function handler(e) {
579
+ if (e.data && e.data.ref === ref) {
580
+ memPort.removeEventListener('message', handler);
581
+ if (e.data.ok) resolve(e.data.data);
582
+ else reject(new Error(e.data.error));
583
+ }
584
+ });
585
+ memPort.postMessage({ action: 'GET', factoryToken, ref, id: reqId });
586
+ })
587
+ ));
588
+
589
+ const result = reducer(shards);
590
+ self.postMessage({ ok: true, data: result });
591
+ } catch (error) {
592
+ self.postMessage({ ok: false, error: String(error) });
593
+ } finally {
594
+ self.close();
595
+ }
596
+ });
597
+ `;
598
+ try {
599
+ i = await new Promise((k, d) => {
600
+ const p = new Blob([c], { type: "application/javascript" }), s = r.trackWorker(
601
+ new Worker(URL.createObjectURL(p))
602
+ );
603
+ s.onmessage = (u) => {
604
+ r.terminateWorker(s), u.data.ok ? k(u.data.data) : (r.logger.error(
605
+ "Collect results reducer worker failed",
606
+ u.data.error
607
+ ), d(new Error(u.data.error)));
608
+ }, s.onerror = (u) => {
609
+ r.terminateWorker(s), r.logger.error(
610
+ "Collect results reducer worker encountered an error event",
611
+ u
612
+ ), d(u);
613
+ }, s.postMessage({ __start__: !0 }, [n]);
614
+ });
615
+ } catch {
616
+ const k = await Promise.all(
617
+ l.map((s) => r.memoryWorkerProxy.get(s))
618
+ ), d = (s) => s.flat();
619
+ i = (e.reducer ?? d)(k);
620
+ }
621
+ } else if (f) {
622
+ const n = await Promise.all(
623
+ l.map((d) => r.memoryWorkerProxy.get(d))
624
+ ), c = (d) => d.flat();
625
+ i = (e.reducer ?? c)(n);
626
+ } else {
627
+ const n = a.map((d) => d.value.successResult.data), c = (d) => d.flat();
628
+ i = (e.reducer ?? c)(n);
629
+ }
630
+ return {
631
+ data: i,
632
+ succeeded: a.length,
633
+ failed: t.length,
634
+ errors: t
635
+ };
636
+ }
637
+ async function X(o, e, r) {
638
+ var v, S;
639
+ if (r.isTerminated())
640
+ return r.logger.error(
641
+ "Attempted to execute worker after MainWorkerFactory was terminated"
642
+ ), Promise.reject(new Error("MainWorkerFactory has been terminated"));
643
+ const a = r.findWorkerByName(o);
644
+ if (!a)
645
+ return r.logger.error(`Worker config not found for worker: "${o}"`), Promise.reject(new Error(`Worker "${o}" not found`));
646
+ const {
647
+ srcData: t,
648
+ reducer: l,
649
+ autoCollect: f = !0,
650
+ ...m
651
+ } = e || {};
652
+ let i = t;
653
+ const n = m.__memory_ref__, c = !!m.deleteMemory;
654
+ if (i === void 0 && n) {
655
+ if (!r.memoryStore.has(n))
656
+ return r.logger.error(
657
+ `Attempted to use invalid memory reference: "${n}"`
658
+ ), Promise.reject(
659
+ new Error(`Memory reference "${n}" not found in MemoryStore`)
660
+ );
661
+ i = await r.memoryWorkerProxy.get(n), delete m.__memory_ref__, delete m.deleteMemory;
662
+ } else
663
+ delete m.deleteMemory;
664
+ const k = a.maxConcurrency ?? r.threads, d = !!(Array.isArray(i) && a.partition), p = d ? B(i, k) : i, s = d && Array.isArray(p) ? p.length : k, u = r.orchestrator.createWorkerPromises(
665
+ a,
666
+ o,
667
+ { data: p, ...m },
668
+ s,
669
+ d
670
+ ), h = await Promise.allSettled(u);
671
+ c && n && (await r.memoryWorkerProxy.delete(n), r.memoryStore.delete(n));
672
+ for (const g of h)
673
+ if (g.status === "fulfilled") {
674
+ const W = (v = g.value.successResult) == null ? void 0 : v.data, w = W == null ? void 0 : W.__memory_ref__;
675
+ w && r.memoryStore.register(w);
676
+ }
677
+ const _ = new V(h);
678
+ if (!f) {
679
+ const g = h.filter((w) => w.status === "fulfilled").length, W = h.filter(
680
+ (w) => w.status === "rejected"
434
681
  );
435
- if (t.length === 0) return;
436
- const i = t.map(
437
- (s) => s.value.successResult.data
438
- ), f = a && i.every(Array.isArray) ? i.flat() : i.length === 1 ? i[0] : i, d = this._memoryStore.set(f);
439
- for (const s of t) {
440
- const o = r ? { __memory_ref__: d } : { data: s.value.successResult.data, __memory_ref__: d };
441
- s.value.successResult = new MessageEvent("message", {
442
- data: o
682
+ return {
683
+ data: _,
684
+ succeeded: g,
685
+ failed: W.length,
686
+ errors: W
687
+ };
688
+ }
689
+ const T = await x(
690
+ _,
691
+ { reducer: l },
692
+ {
693
+ isTerminated: () => r.isTerminated(),
694
+ trackWorker: r.orchestrator.context ? (g) => g : (g) => g,
695
+ terminateWorker: (g) => {
696
+ },
697
+ logger: r.logger,
698
+ memoryWorkerProxy: r.memoryWorkerProxy,
699
+ factoryToken: r.factoryToken
700
+ }
701
+ ), M = !!(a.memory || a.memoryOnly);
702
+ for (const g of h)
703
+ if (g.status === "fulfilled") {
704
+ const W = (S = g.value.successResult) == null ? void 0 : S.data, w = W == null ? void 0 : W.__memory_ref__;
705
+ w && (r.memoryStore.delete(w), await r.memoryWorkerProxy.delete(w));
706
+ }
707
+ if (M) {
708
+ const g = await r.memoryWorkerProxy.set(T.data);
709
+ return r.memoryStore.register(g), { ...T, __memory_ref__: g };
710
+ }
711
+ return T;
712
+ }
713
+ async function Q(o, e) {
714
+ if (e.isTerminated())
715
+ throw e.logger.error(
716
+ "Attempted to execute pipeline after MainWorkerFactory was terminated"
717
+ ), new Error("MainWorkerFactory has been terminated");
718
+ if (o.length === 0)
719
+ throw e.logger.error("Attempted to execute an empty pipeline"), new Error("Pipeline requires at least one step");
720
+ if (o.length === 1) {
721
+ const r = o[0], { worker: a, srcData: t, ...l } = r, f = e.findWorkerByName(r.worker);
722
+ if (!f)
723
+ throw e.logger.error(
724
+ `Pipeline step config not found for worker: "${r.worker}"`
725
+ ), new Error(`Worker "${r.worker}" not found`);
726
+ const m = new b(f.func, {
727
+ createWorker: f.createWorker
728
+ });
729
+ e.trackWorker(m.getWorker);
730
+ const i = m.getWorker;
731
+ return new Promise((n, c) => {
732
+ i.onmessage = (p) => {
733
+ var s, u;
734
+ e.terminateWorker(i), ((s = p.data) == null ? void 0 : s.ok) === !1 ? (e.logger.error(
735
+ `Pipeline step ${r.worker} failed`,
736
+ p.data.error
737
+ ), c(new Error(p.data.error))) : n({
738
+ data: (u = p.data) == null ? void 0 : u.data,
739
+ succeeded: 1,
740
+ failed: 0,
741
+ errors: []
742
+ });
743
+ }, i.onerror = (p) => {
744
+ e.terminateWorker(i), e.logger.error(
745
+ `Pipeline step ${r.worker} encountered an error event`,
746
+ p
747
+ ), c(p);
748
+ };
749
+ const d = { data: t ?? {}, ...l, index: 0 };
750
+ e.logger.verbose(
751
+ `Starting single-step pipeline for worker ${r.worker}`
752
+ ), i.postMessage(d, E(d));
753
+ });
754
+ }
755
+ return new Promise(async (r, a) => {
756
+ const t = [], l = [];
757
+ for (const s of o) {
758
+ const u = e.findWorkerByName(s.worker);
759
+ if (!u) {
760
+ e.logger.error(
761
+ `Pipeline step config not found for worker: "${s.worker}"`
762
+ ), a(new Error(`Worker "${s.worker}" not found`));
763
+ return;
764
+ }
765
+ const h = new b(u.func, {
766
+ mode: D.Pipeline,
767
+ createWorker: u.createWorker
768
+ }), _ = e.trackWorker(h.getWorker);
769
+ t.push(_);
770
+ }
771
+ for (let s = 0; s < t.length - 1; s++)
772
+ l.push(new MessageChannel());
773
+ for (let s = 0; s < t.length; s++) {
774
+ const {
775
+ worker: u,
776
+ srcData: h,
777
+ ..._
778
+ } = o[s], T = [], M = {};
779
+ if (s > 0 && (M.inputPort = l[s - 1].port1, T.push(M.inputPort)), s < t.length - 1 && (M.outputPort = l[s].port2, T.push(M.outputPort)), t[s].postMessage(
780
+ { __pipeline_ports__: !0, stepParams: _, ...M },
781
+ T
782
+ ), s < t.length - 1) {
783
+ const v = t[s], S = t[s + 1], {
784
+ worker: g,
785
+ srcData: W,
786
+ ...w
787
+ } = o[s + 1];
788
+ v.onmessage = (P) => {
789
+ var I, F;
790
+ if (P.data && P.data.__pipeline_ports__) return;
791
+ if (((I = P.data) == null ? void 0 : I.ok) === !1) {
792
+ e.logger.error(
793
+ `Pipeline step ${o[s].worker} failed`,
794
+ P.data.error
795
+ ), t.forEach((L) => e.terminateWorker(L)), a(new Error(P.data.error));
796
+ return;
797
+ }
798
+ const $ = { data: ((F = P.data) == null ? void 0 : F.ok) !== void 0 ? P.data.data : P.data, ...w, index: 0 };
799
+ S.postMessage($, E($));
800
+ }, v.onerror = (P) => {
801
+ e.logger.error(
802
+ `Pipeline step ${o[s].worker} encountered an error event`,
803
+ P
804
+ ), t.forEach((A) => e.terminateWorker(A)), a(P);
805
+ };
806
+ }
807
+ }
808
+ const f = t[t.length - 1];
809
+ f.onmessage = (s) => {
810
+ var u, h;
811
+ t.forEach((_) => e.terminateWorker(_)), ((u = s.data) == null ? void 0 : u.ok) === !1 ? (e.logger.error("Final pipeline step failed", s.data.error), a(new Error(s.data.error))) : r({
812
+ data: (h = s.data) == null ? void 0 : h.data,
813
+ succeeded: 1,
814
+ failed: 0,
815
+ errors: []
443
816
  });
817
+ }, f.onerror = (s) => {
818
+ t.forEach((u) => e.terminateWorker(u)), e.logger.error(
819
+ "Final pipeline step encountered an error event",
820
+ s
821
+ ), a(s);
822
+ };
823
+ const {
824
+ worker: m,
825
+ srcData: i,
826
+ ...n
827
+ } = o[0];
828
+ let c = i;
829
+ const k = n.__memory_ref__, d = !!n.deleteMemory;
830
+ if (c === void 0 && k) {
831
+ if (!e.memoryStore.has(k)) {
832
+ t.forEach((s) => e.terminateWorker(s)), e.logger.error(
833
+ `Memory reference "${k}" not found in MemoryStore`
834
+ ), a(
835
+ new Error(`Memory reference "${k}" not found in MemoryStore`)
836
+ );
837
+ return;
838
+ }
839
+ c = await e.memoryWorkerProxy.get(k), d && (e.memoryStore.delete(k), await e.memoryWorkerProxy.delete(k)), delete n.__memory_ref__, delete n.deleteMemory;
444
840
  }
841
+ c === void 0 && (c = {});
842
+ const p = {
843
+ data: c,
844
+ ...n,
845
+ index: 0
846
+ };
847
+ e.logger.verbose(`Starting full pipeline with ${o.length} steps`), t[0].postMessage(p, E(p));
848
+ });
849
+ }
850
+ class Y {
851
+ constructor(e) {
852
+ y(this, "_persistentWorkers", /* @__PURE__ */ new Map());
853
+ this.context = e;
445
854
  }
446
- /**
447
- * Returns statistics about active memory references in the factory.
448
- */
449
- async getMemoryStats() {
450
- return this._memoryStore.stats();
855
+ async runPersistent(e, r) {
856
+ if (this.context.isTerminated())
857
+ throw this.context.logger.error(
858
+ "Attempted to run persistent worker after MainWorkerFactory was terminated"
859
+ ), new Error("MainWorkerFactory has been terminated");
860
+ const a = this.context.findWorkerByName(e);
861
+ if (!a)
862
+ throw this.context.logger.error(
863
+ `Persistent worker config not found for worker: "${e}"`
864
+ ), new Error(`Worker "${e}" not found`);
865
+ let t = this._persistentWorkers.get(e);
866
+ if (!t) {
867
+ const l = new b(a.func, {
868
+ mode: D.Persistent,
869
+ createWorker: a.createWorker
870
+ });
871
+ t = this.context.trackWorker(l.getWorker), this.context.logger.verbose(
872
+ `Created persistent worker for ${e}`
873
+ ), this._persistentWorkers.set(e, t);
874
+ }
875
+ return new Promise((l, f) => {
876
+ t.onmessage = (i) => {
877
+ var n, c;
878
+ ((n = i.data) == null ? void 0 : n.ok) === !1 ? (this.context.logger.error(
879
+ `Persistent worker ${e} failed`,
880
+ i.data.error
881
+ ), f(new Error(i.data.error))) : l((c = i.data) == null ? void 0 : c.data);
882
+ }, t.onerror = (i) => {
883
+ this.context.logger.error(
884
+ `Persistent worker ${e} encountered an error event`,
885
+ i
886
+ ), f(i);
887
+ };
888
+ const m = {
889
+ type: "run",
890
+ config: r.config
891
+ };
892
+ r.dataset !== void 0 && (m.dataset = r.dataset), t.postMessage(m, E(m));
893
+ });
451
894
  }
452
- /**
453
- * Builds the array of per-thread worker promises for a single `runWorker`
454
- * call.
455
- *
456
- * When `isPartitioned` is `true`, each promise receives its own slice of
457
- * `srcData`; otherwise every thread receives the full payload.
458
- *
459
- * @param config - The resolved {@link WorkerConfig} for this run.
460
- * @param workerName - Name used in error/retry logging.
461
- * @param srcWorkerData - Combined `{ data, ...otherParams }` payload.
462
- * @param threadCount - Number of parallel worker threads to spawn.
463
- * @param isPartitioned - Whether `data` is a pre-split array of shards.
464
- * @returns An array of promises, one per thread.
465
- */
466
- createWorkerPromises(e, r, a, t, i) {
467
- const { data: f, ...d } = a;
468
- return Array.from({ length: t }, (s, o) => {
469
- const u = i && Array.isArray(f) ? f[o] : f;
895
+ release(e) {
896
+ const r = this._persistentWorkers.get(e);
897
+ if (r) {
898
+ try {
899
+ r.postMessage({ type: "release" });
900
+ } catch {
901
+ }
902
+ this.context.terminateWorker(r), this._persistentWorkers.delete(e);
903
+ }
904
+ }
905
+ terminateAll() {
906
+ for (const e of this._persistentWorkers.values()) {
907
+ try {
908
+ e.postMessage({ type: "release" });
909
+ } catch {
910
+ }
911
+ this.context.terminateWorker(e);
912
+ }
913
+ this._persistentWorkers.clear();
914
+ }
915
+ }
916
+ class Z {
917
+ constructor(e) {
918
+ this.context = e;
919
+ }
920
+ createWorkerPromises(e, r, a, t, l) {
921
+ const { data: f, ...m } = a;
922
+ return Array.from({ length: t }, (i, n) => {
923
+ const c = l && Array.isArray(f) ? f[n] : f;
470
924
  return this.runWorkerWithRetry(
471
925
  {
472
926
  workerFunc: e.func,
473
927
  createWorker: e.createWorker,
474
928
  workerName: r,
475
- index: o,
476
- data: { data: u, ...d }
929
+ index: n,
930
+ data: { data: c, ...m }
477
931
  },
478
932
  e.retries
479
933
  );
480
934
  });
481
935
  }
482
- /**
483
- * Runs a single worker instance, retrying on failure up to `retryCount`
484
- * times before re-throwing the last error.
485
- *
486
- * Each retry is logged to `console.error` with the remaining attempt count
487
- * so failures are visible during development.
488
- *
489
- * @param instanceConfig - Full configuration for the worker instance.
490
- * @param retryCount - Remaining retry attempts (default `2`).
491
- * @returns The successful {@link WorkerResult} once the worker resolves.
492
- * @throws The last caught error when all retries are exhausted.
493
- */
494
936
  async runWorkerWithRetry(e, r = 2) {
495
937
  try {
496
938
  return await this.initiateWorker(e);
497
939
  } catch (a) {
498
940
  if (r > 0)
499
- return console.error(
941
+ return this.context.logger.info(
500
942
  `Worker ${e.index} failed, retrying (${r} left):`,
501
943
  a
502
944
  ), this.runWorkerWithRetry(e, r - 1);
503
- throw console.error("Worker failed after all retries:", a), a;
945
+ throw this.context.logger.error("Worker failed after all retries:", a), a;
504
946
  }
505
947
  }
506
- /**
507
- * Spawns a single worker thread, posts the payload, and resolves or rejects
508
- * based on the message the worker sends back.
509
- *
510
- * The worker is expected to respond with either:
511
- * - `{ ok: true, data: T }` — success; resolves with a {@link WorkerResult}.
512
- * - `{ ok: false, error: string }` — logical failure; rejects with a
513
- * structured error object.
514
- *
515
- * Any transferable objects found in the payload are moved (not copied) to
516
- * the worker via the `transfer` list of `postMessage`.
517
- *
518
- * The underlying `Worker` is always terminated after the message completes.
519
- *
520
- * @param instanceConfig - Worker function, factory, name, shard index, and data.
521
- * @returns A promise that resolves with the worker's result.
522
- */
523
- initiateWorker({
948
+ async initiateWorker({
524
949
  workerFunc: e,
525
950
  createWorker: r,
526
951
  workerName: a,
527
952
  index: t,
528
- data: i
953
+ data: l
529
954
  }) {
530
- return new Promise((f, d) => {
531
- const o = this.initWorker({
532
- name: a,
533
- role: "",
534
- func: e,
535
- createWorker: r
536
- }).getWorker;
537
- o.onerror = (m) => {
538
- this.terminateWorker(o), d({
955
+ const f = await this.context.memoryWorkerProxy.allocateWorkerPort();
956
+ return new Promise((m, i) => {
957
+ if (this.context.isTerminated()) {
958
+ i(new Error("MainWorkerFactory has been terminated"));
959
+ return;
960
+ }
961
+ const n = new b(e, {
962
+ createWorker: r,
963
+ mode: D.Memory
964
+ }), c = this.context.trackWorker(n.getWorker);
965
+ c.onerror = (d) => {
966
+ this.context.terminateWorker(c), i({
539
967
  index: t,
540
968
  workerConfigs: {
541
969
  workerFunc: e,
542
970
  createWorker: r,
543
971
  workerName: a,
544
972
  index: t,
545
- data: i
973
+ data: l
546
974
  },
547
- failedResult: m
975
+ failedResult: d
548
976
  });
549
- }, o.onmessage = (m) => {
550
- var c, n;
551
- if (((c = m.data) == null ? void 0 : c.ok) === !1) {
552
- this.terminateWorker(o), d({
977
+ }, c.onmessage = (d) => {
978
+ var u, h, _;
979
+ if (((u = d.data) == null ? void 0 : u.ok) === !1) {
980
+ this.context.terminateWorker(c), i({
553
981
  index: t,
554
982
  workerConfigs: {
555
983
  workerFunc: e,
556
984
  createWorker: r,
557
985
  workerName: a,
558
986
  index: t,
559
- data: i
987
+ data: l
560
988
  },
561
989
  failedResult: new ErrorEvent("error", {
562
- message: m.data.error
990
+ message: d.data.error
563
991
  })
564
992
  });
565
993
  return;
566
994
  }
567
- const p = ((n = m.data) == null ? void 0 : n.ok) !== void 0 ? m.data.data : m.data;
568
- f({
995
+ const p = (h = d.data) == null ? void 0 : h.__memory_ref__, s = p !== void 0 ? { __memory_ref__: p } : ((_ = d.data) == null ? void 0 : _.ok) !== void 0 ? d.data.data : d.data;
996
+ m({
569
997
  index: t,
570
998
  workerConfigs: {
571
999
  workerFunc: e,
572
1000
  createWorker: r,
573
1001
  workerName: a,
574
1002
  index: t,
575
- data: i
1003
+ data: l
576
1004
  },
577
1005
  successResult: new MessageEvent("message", {
578
- data: p
1006
+ data: s
579
1007
  })
580
- }), this.terminateWorker(o);
1008
+ }), this.context.terminateWorker(c);
581
1009
  };
582
- const u = {
1010
+ const k = {
583
1011
  index: t,
584
- ...Array.isArray(i) ? { data: i } : i
1012
+ ...Array.isArray(l) ? { data: l } : l
585
1013
  };
586
- o.postMessage(u, w(u));
1014
+ c.postMessage(
1015
+ {
1016
+ __init_memory_port__: !0,
1017
+ factoryToken: this.context.factoryToken
1018
+ },
1019
+ [f]
1020
+ ), c.postMessage(k, E(k));
587
1021
  });
588
1022
  }
1023
+ }
1024
+ class te {
589
1025
  /**
590
- * Collects and merges the settled results from {@link runWorker} — off the
591
- * main thread.
592
- *
593
- * Fulfilled shards are extracted and passed to the `reducer` function, which
594
- * runs inside a dedicated inline worker so the merge itself never blocks the
595
- * main thread. Failed shards are counted and their raw rejection reasons are
596
- * preserved in `errors`.
597
- *
598
- * @typeParam T - The per-shard data type (inferred from `settled`).
599
- * @typeParam R - The final merged output type (defaults to a flat array of
600
- * `T` items when no custom reducer is provided).
1026
+ * Initializes a new MainWorkerFactory.
601
1027
  *
602
- * @param settled - The {@link TypedSettledResults} returned by `runWorker`.
603
- * @param options - Optional {@link CollectOptions}. Supply a `reducer` to
604
- * control how shards are merged. The reducer **must be self-contained**
605
- * (no closures over external variables) because it is serialised and run
606
- * inside a worker.
607
- *
608
- * @returns A {@link CollectedResult} with the merged `data`, counts of
609
- * `succeeded`/`failed` shards, and the raw `errors` array.
610
- *
611
- * @example
612
- * // default: flat array of all shard data
613
- * const { data, succeeded, failed } = await foreman.collectResults(res);
614
- *
615
- * @example
616
- * // custom reducer: sum numbers across shards
617
- * const { data } = await foreman.collectResults<number[], number>(res, {
618
- * reducer: (shards) => shards.flat().reduce((a, b) => a + b, 0),
619
- * });
1028
+ * @param options - Configuration options.
1029
+ * @param options.workers - The list of worker configurations.
1030
+ * @param options.logLevel - Optional logging level (defaults to 'error').
620
1031
  */
621
- async collectResults(e, r = {}) {
1032
+ constructor(e) {
1033
+ y(this, "_workers");
1034
+ y(this, "_threads");
1035
+ y(this, "_activeWorkers", /* @__PURE__ */ new Set());
1036
+ y(this, "_memoryStore", new z());
1037
+ y(this, "_memoryWorkerProxy");
1038
+ y(this, "_factoryToken");
1039
+ y(this, "_isTerminated", !1);
1040
+ y(this, "_persistentManager");
1041
+ y(this, "_orchestrator");
1042
+ /**
1043
+ * The logger instance used by this factory.
1044
+ */
1045
+ y(this, "logger");
1046
+ this._workers = e.workers, this.logger = new J(e.logLevel ?? "error"), this._threads = typeof navigator < "u" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4, this._factoryToken = crypto.randomUUID(), this._memoryWorkerProxy = new H(this._factoryToken);
1047
+ const r = {
1048
+ isTerminated: () => this.isTerminated,
1049
+ findWorkerByName: this.findWorkerByName.bind(this),
1050
+ trackWorker: this.trackWorker.bind(this),
1051
+ terminateWorker: this.terminateWorker.bind(this),
1052
+ logger: this.logger,
1053
+ memoryWorkerProxy: this._memoryWorkerProxy,
1054
+ factoryToken: this._factoryToken
1055
+ };
1056
+ this._persistentManager = new Y(r), this._orchestrator = new Z(r);
1057
+ }
1058
+ /**
1059
+ * Indicates whether the factory has been terminated.
1060
+ */
1061
+ get isTerminated() {
1062
+ return this._isTerminated;
1063
+ }
1064
+ trackWorker(e) {
622
1065
  if (this._isTerminated)
623
- throw new Error("MainWorkerFactory has been terminated");
624
- const a = e.results.filter(
625
- (p) => p.status === "fulfilled"
626
- ), t = e.results.filter(
627
- (p) => p.status === "rejected"
628
- );
629
- if (a.length > 0 && a.every((p) => {
630
- var n;
631
- const c = (n = p.value.successResult) == null ? void 0 : n.data;
632
- return c && typeof c == "object" && "__memory_ref__" in c && !("data" in c);
633
- }))
634
- return {
635
- data: a[0].value.successResult.data,
636
- succeeded: a.length,
637
- failed: t.length,
638
- errors: t
639
- };
640
- const f = a.length > 0 && a.every((p) => {
641
- var n;
642
- const c = (n = p.value.successResult) == null ? void 0 : n.data;
643
- return c && typeof c == "object" && "__memory_ref__" in c && "data" in c;
644
- }), d = f ? a[0].value.successResult.data.__memory_ref__ : void 0, s = a.map((p) => {
645
- const c = p.value.successResult.data;
646
- return f && c && typeof c == "object" && "data" in c ? c.data : c;
647
- }), o = r.reducer ? r.reducer.toString() : "(shards) => shards.flat()";
648
- let u;
649
- if (typeof Worker < "u" && typeof Blob < "u" && typeof URL < "u" && typeof URL.createObjectURL == "function")
650
- try {
651
- u = await new Promise((p, c) => {
652
- const n = `
653
- const reducer = ${o};
654
- self.addEventListener('message', (event) => {
655
- try {
656
- const result = reducer(event.data);
657
- self.postMessage({ ok: true, data: result });
658
- } catch (error) {
659
- self.postMessage({ ok: false, error: String(error) });
660
- }
661
- });
662
- `, h = new Blob([n], {
663
- type: "application/javascript"
664
- }), y = this.trackWorker(
665
- new Worker(URL.createObjectURL(h))
666
- );
667
- y.onmessage = (k) => {
668
- this.terminateWorker(y), k.data.ok ? p(k.data.data) : c(new Error(k.data.error));
669
- }, y.onerror = (k) => {
670
- this.terminateWorker(y), c(k);
671
- }, y.postMessage(s);
672
- });
673
- } catch {
674
- const p = (n) => n.flat();
675
- u = (r.reducer ?? p)(s);
676
- }
677
- else {
678
- const p = (n) => n.flat();
679
- u = (r.reducer ?? p)(s);
1066
+ throw e.terminate(), new Error("MainWorkerFactory has been terminated");
1067
+ return this._activeWorkers.add(e), e;
1068
+ }
1069
+ terminateWorker(e) {
1070
+ this._activeWorkers.delete(e);
1071
+ try {
1072
+ e.terminate();
1073
+ } catch {
680
1074
  }
681
- return {
682
- data: f ? { data: u, __memory_ref__: d } : u,
683
- succeeded: a.length,
684
- failed: t.length,
685
- errors: t
686
- };
687
1075
  }
688
1076
  /**
689
- * Runs a chain of workers where each step's output feeds directly into the
690
- * next step — **without passing through the main thread**.
691
- *
692
- * Internally, adjacent workers are connected via `MessageChannel` ports.
693
- * Only the final result is sent back to the main thread, minimising
694
- * serialisation overhead for large intermediate data.
1077
+ * Helper utility to partition an array into a specified number of chunks.
695
1078
  *
696
- * @typeParam TResult - The expected type of the final pipeline output.
697
- * Defaults to `unknown` if not specified.
1079
+ * @param array - The array to partition.
1080
+ * @param numChunks - The desired number of chunks.
1081
+ * @returns An array of array chunks.
1082
+ * @template T - The type of elements in the array.
1083
+ */
1084
+ partitionArray(e, r) {
1085
+ return B(e, r);
1086
+ }
1087
+ findWorkerByName(e) {
1088
+ return this._workers.find((r) => r.name === e);
1089
+ }
1090
+ /**
1091
+ * Dispatches a worker task with the given parameters.
698
1092
  *
699
- * @param steps - An ordered array of {@link PipelineStep} objects. The first
700
- * step must include `srcData`; subsequent steps receive the previous
701
- * step's output as `{ data: previousOutput, index: 0 }`.
1093
+ * Workers store their results directly in the `MemoryWorker` thread large data
1094
+ * never touches the main thread heap. Results are auto-collected and merged in a
1095
+ * dedicated reducer worker. Returns a `CollectedResult<R>` directly.
702
1096
  *
703
- * @returns A promise that resolves with the final step's output.
704
- * @throws {Error} When `steps` is empty or a worker name is not found.
1097
+ * Pass `autoCollect: false` in `rawParams` to skip auto-collection and receive
1098
+ * the raw settled state (escape hatch for advanced custom reducers).
705
1099
  *
706
- * @example
707
- * const result = await foreman.pipeline<FilteredPost[]>([
708
- * { worker: 'fetchPosts', srcData: { url: '/api/posts' } },
709
- * { worker: 'transformPosts' },
710
- * { worker: 'filterPosts' },
711
- * ]);
712
- * console.log(result); // final transformed + filtered data
1100
+ * @param workerName - The name of the registered worker to execute.
1101
+ * @param rawParams - The payload, options, and reducer for the worker.
1102
+ * @returns A promise resolving to a CollectedResult with merged data and shard stats.
1103
+ * @template TName - The name of the registered worker.
1104
+ * @template T - The return type of the worker function.
1105
+ * @template R - The merged return type after reducing shards.
713
1106
  */
714
- async pipeline(e) {
715
- if (this._isTerminated)
716
- throw new Error("MainWorkerFactory has been terminated");
717
- if (e.length === 0)
718
- throw new Error("Pipeline requires at least one step");
719
- if (e.length === 1) {
720
- const r = e[0], { worker: a, srcData: t, ...i } = r, f = this.findWorkerByName(r.worker);
721
- if (!f) throw new Error(`Worker "${r.worker}" not found`);
722
- const s = this.initWorker(f).getWorker;
723
- return new Promise((o, u) => {
724
- s.onmessage = (c) => {
725
- var n, h;
726
- this.terminateWorker(s), ((n = c.data) == null ? void 0 : n.ok) === !1 ? u(new Error(c.data.error)) : o((h = c.data) == null ? void 0 : h.data);
727
- }, s.onerror = (c) => {
728
- this.terminateWorker(s), u(c);
729
- };
730
- const p = { data: t ?? {}, ...i, index: 0 };
731
- s.postMessage(p, w(p));
732
- });
733
- }
734
- return new Promise((r, a) => {
735
- const t = [], i = [];
736
- for (const n of e) {
737
- const h = this.findWorkerByName(n.worker);
738
- if (!h) {
739
- a(new Error(`Worker "${n.worker}" not found`));
740
- return;
741
- }
742
- const y = new M(h.func, {
743
- mode: P.Pipeline,
744
- createWorker: h.createWorker
745
- }), k = this.trackWorker(y.getWorker);
746
- t.push(k);
747
- }
748
- for (let n = 0; n < t.length - 1; n++)
749
- i.push(new MessageChannel());
750
- for (let n = 0; n < t.length; n++) {
751
- const {
752
- worker: h,
753
- srcData: y,
754
- ...k
755
- } = e[n], v = [], W = {};
756
- if (n > 0 && (W.inputPort = i[n - 1].port1, v.push(W.inputPort)), n < t.length - 1 && (W.outputPort = i[n].port2, v.push(W.outputPort)), t[n].postMessage(
757
- { __pipeline_ports__: !0, stepParams: k, ...W },
758
- v
759
- ), n < t.length - 1) {
760
- const b = t[n], A = t[n + 1], {
761
- worker: U,
762
- srcData: z,
763
- ...T
764
- } = e[n + 1];
765
- b.onmessage = (g) => {
766
- var S, R;
767
- if (g.data && g.data.__pipeline_ports__) return;
768
- if (((S = g.data) == null ? void 0 : S.ok) === !1) {
769
- t.forEach((B) => this.terminateWorker(B)), a(new Error(g.data.error));
770
- return;
771
- }
772
- const E = { data: ((R = g.data) == null ? void 0 : R.ok) !== void 0 ? g.data.data : g.data, ...T, index: 0 };
773
- A.postMessage(E, w(E));
774
- }, b.onerror = (g) => {
775
- t.forEach((D) => this.terminateWorker(D)), a(g);
776
- };
777
- }
778
- }
779
- const f = t[t.length - 1];
780
- f.onmessage = (n) => {
781
- var h, y;
782
- t.forEach((k) => this.terminateWorker(k)), ((h = n.data) == null ? void 0 : h.ok) === !1 ? a(new Error(n.data.error)) : r((y = n.data) == null ? void 0 : y.data);
783
- }, f.onerror = (n) => {
784
- t.forEach((h) => this.terminateWorker(h)), a(n);
785
- };
786
- const {
787
- worker: d,
788
- srcData: s,
789
- ...o
790
- } = e[0];
791
- let u = s;
792
- const m = o.__memory_ref__, p = !!o.deleteMemory;
793
- if (u === void 0 && m) {
794
- if (!this._memoryStore.has(m)) {
795
- t.forEach((n) => this.terminateWorker(n)), a(
796
- new Error(
797
- `Memory reference "${m}" not found in MemoryStore`
798
- )
799
- );
800
- return;
801
- }
802
- u = this._memoryStore.get(m), p && this._memoryStore.delete(m), delete o.__memory_ref__, delete o.deleteMemory;
803
- }
804
- u === void 0 && (u = {});
805
- const c = {
806
- data: u,
807
- ...o,
808
- index: 0
809
- };
810
- t[0].postMessage(c, w(c));
1107
+ async runWorker(e, r) {
1108
+ return X(e, r, {
1109
+ isTerminated: () => this.isTerminated,
1110
+ findWorkerByName: this.findWorkerByName.bind(this),
1111
+ memoryStore: this._memoryStore,
1112
+ memoryWorkerProxy: this._memoryWorkerProxy,
1113
+ factoryToken: this._factoryToken,
1114
+ threads: this._threads,
1115
+ orchestrator: this._orchestrator,
1116
+ logger: this.logger
811
1117
  });
812
1118
  }
813
1119
  /**
814
- * Runs a persistent worker that caches its dataset between calls.
1120
+ * Deletes a specific reference from the memory store and MemoryWorker.
815
1121
  *
816
- * On the first call, provide both `dataset` and `config`. The worker stores
817
- * the dataset in memory. On subsequent calls, only `config` is needed — the
818
- * worker reuses the cached dataset and reprocesses it with the new config.
819
- *
820
- * The worker stays alive until {@link release} is called.
821
- *
822
- * @param workerName - Name of the registered worker.
823
- * @param params - Object with optional `dataset` and required `config`.
824
- * @returns The worker function's return value.
1122
+ * @param ref - The memory reference ID to delete.
1123
+ * @returns True if the reference existed and was deleted, false otherwise.
1124
+ */
1125
+ async deleteMemory(e) {
1126
+ return this._memoryStore.delete(e), this._memoryWorkerProxy.delete(e);
1127
+ }
1128
+ /**
1129
+ * Clears all references from the memory store and MemoryWorker.
1130
+ */
1131
+ async clearMemory() {
1132
+ this._memoryStore.clear(), await this._memoryWorkerProxy.clear();
1133
+ }
1134
+ /**
1135
+ * Retrieves statistics about the currently stored memory handles.
825
1136
  *
826
- * @example
827
- * // First call: send dataset + config
828
- * const r1 = await factory.runPersistent('transform', {
829
- * dataset: largeArray,
830
- * config: { multiplier: 2 },
831
- * });
1137
+ * @returns The MemoryStats containing count and active reference IDs.
1138
+ */
1139
+ async getMemoryStats() {
1140
+ return this._memoryWorkerProxy.stats();
1141
+ }
1142
+ /**
1143
+ * Collects and reduces the results from a `runWorker` execution.
832
1144
  *
833
- * // Subsequent calls: only config, dataset is cached
834
- * const r2 = await factory.runPersistent('transform', {
835
- * config: { multiplier: 5 },
836
- * });
1145
+ * @deprecated `runWorker` now auto-collects results. This method is kept as
1146
+ * an escape hatch for advanced cases where `autoCollect: false` was passed to
1147
+ * `runWorker`. In the common case, the return value of `runWorker` already
1148
+ * contains the merged `CollectedResult`.
837
1149
  *
838
- * // Update dataset when needed
839
- * const r3 = await factory.runPersistent('transform', {
840
- * dataset: newArray,
841
- * config: { multiplier: 3 },
842
- * });
1150
+ * @param settled - The settled results from `runWorker` (when `autoCollect: false`).
1151
+ * @param options - Options containing the reducer function.
1152
+ * @returns A structured CollectedResult object.
1153
+ * @template T - The type of the worker result data.
1154
+ * @template R - The type of the merged result data.
1155
+ */
1156
+ async collectResults(e, r = {}) {
1157
+ return x(e, r, {
1158
+ isTerminated: () => this.isTerminated,
1159
+ trackWorker: this.trackWorker.bind(this),
1160
+ terminateWorker: this.terminateWorker.bind(this),
1161
+ logger: this.logger,
1162
+ memoryWorkerProxy: this._memoryWorkerProxy,
1163
+ factoryToken: this._factoryToken
1164
+ });
1165
+ }
1166
+ /**
1167
+ * Executes a sequential pipeline of worker steps.
1168
+ * Passes the output of one step as the input to the next step.
843
1169
  *
844
- * // Release when done
845
- * factory.release('transform');
1170
+ * @param steps - An array of PipelineStep configurations.
1171
+ * @returns A CollectedResult containing the final pipeline output and shard stats,
1172
+ * consistent with the shape returned by `runWorker()`.
1173
+ * @template TResult - The type of the pipeline result.
846
1174
  */
847
- async runPersistent(e, r) {
848
- if (this._isTerminated)
849
- throw new Error("MainWorkerFactory has been terminated");
850
- const a = this.findWorkerByName(e);
851
- if (!a) throw new Error(`Worker "${e}" not found`);
852
- let t = this._persistentWorkers.get(e);
853
- if (!t) {
854
- const i = new M(a.func, {
855
- mode: P.Persistent,
856
- createWorker: a.createWorker
857
- });
858
- t = this.trackWorker(i.getWorker), this._persistentWorkers.set(e, t);
859
- }
860
- return new Promise((i, f) => {
861
- t.onmessage = (s) => {
862
- var o, u;
863
- ((o = s.data) == null ? void 0 : o.ok) === !1 ? f(new Error(s.data.error)) : i((u = s.data) == null ? void 0 : u.data);
864
- }, t.onerror = (s) => {
865
- f(s);
866
- };
867
- const d = {
868
- type: "run",
869
- config: r.config
870
- };
871
- r.dataset !== void 0 && (d.dataset = r.dataset), t.postMessage(d, w(d));
1175
+ async pipeline(e) {
1176
+ return Q(e, {
1177
+ memoryStore: this._memoryStore,
1178
+ memoryWorkerProxy: this._memoryWorkerProxy,
1179
+ isTerminated: () => this.isTerminated,
1180
+ findWorkerByName: this.findWorkerByName.bind(this),
1181
+ trackWorker: this.trackWorker.bind(this),
1182
+ terminateWorker: this.terminateWorker.bind(this),
1183
+ logger: this.logger
872
1184
  });
873
1185
  }
874
1186
  /**
875
- * Releases a persistent worker, freeing its cached dataset and terminating
876
- * the thread.
1187
+ * Executes a task on a persistent (long-lived) worker thread.
1188
+ * Useful for workers that maintain local state (like WebAssembly modules or databases)
1189
+ * across multiple invocations.
877
1190
  *
878
- * After calling `release`, subsequent `runPersistent` calls for this worker
879
- * will create a fresh instance (requiring a new dataset).
1191
+ * @param workerName - The name of the persistent worker to run.
1192
+ * @param params - The input data and configuration for the task.
1193
+ * @returns The result from the persistent worker thread.
1194
+ * @template TResult - The expected type of the result from the worker thread.
1195
+ */
1196
+ async runPersistent(e, r) {
1197
+ return this._persistentManager.runPersistent(e, r);
1198
+ }
1199
+ /**
1200
+ * Releases and terminates a persistent worker by name.
880
1201
  *
881
- * @param workerName - Name of the persistent worker to release.
1202
+ * @param workerName - The name of the persistent worker to release.
882
1203
  */
883
1204
  release(e) {
884
- const r = this._persistentWorkers.get(e);
885
- if (r) {
886
- try {
887
- r.postMessage({ type: "release" });
888
- } catch {
889
- }
890
- this.terminateWorker(r), this._persistentWorkers.delete(e);
891
- }
1205
+ this._persistentManager.release(e);
892
1206
  }
893
1207
  /**
894
- * Terminates the factory and all active and persistent worker instances.
895
- *
896
- * Calling `terminate()` immediately stops all running worker threads, releases
897
- * cached persistent workers, and clears all internal worker state.
1208
+ * Terminates all active worker threads, persistent workers, MemoryWorker, and clears the memory store.
1209
+ * Marks this factory instance as terminated.
898
1210
  */
899
1211
  terminate() {
900
- this._isTerminated = !0;
901
- for (const e of this._persistentWorkers.values()) {
902
- try {
903
- e.postMessage({ type: "release" });
904
- } catch {
905
- }
906
- this.terminateWorker(e);
907
- }
908
- this._persistentWorkers.clear();
1212
+ this._isTerminated = !0, this._persistentManager.terminateAll();
909
1213
  for (const e of Array.from(this._activeWorkers))
910
1214
  this.terminateWorker(e);
911
- this._activeWorkers.clear(), this._memoryStore.clear();
1215
+ this._activeWorkers.clear(), this._memoryStore.clear(), this._memoryWorkerProxy.terminate();
912
1216
  }
913
1217
  /**
914
- * Alias for {@link terminate}. Terminates the factory and all worker instances.
1218
+ * Alias for {@link terminate}. Terminates all active resources.
915
1219
  */
916
1220
  destroy() {
917
1221
  this.terminate();
918
1222
  }
919
1223
  /**
920
- * Resets the factory by terminating all active and persistent workers
921
- * and resetting the factory state, allowing new worker instances to be initiated.
1224
+ * Terminates all resources and resets the factory to an active state.
922
1225
  */
923
1226
  reset() {
924
1227
  this.terminate(), this._isTerminated = !1;
925
1228
  }
926
1229
  /**
927
- * Alias for {@link reset}. Resets the factory state to initiate new worker instances.
1230
+ * Alias for {@link reset}. Terminates and reactivates the factory.
928
1231
  */
929
1232
  restart() {
930
1233
  this.reset();
931
1234
  }
932
1235
  }
933
- function N(l) {
934
- if (typeof self > "u") return;
935
- let e = null, r = null, a = null, t = {};
936
- const i = (d, s) => {
937
- self.postMessage(d, s);
938
- };
939
- async function f(d) {
940
- try {
941
- const s = typeof d == "object" && d !== null && "data" in d ? { ...t, ...d } : { data: d, ...t, index: 0 }, o = await l(s), u = { ok: !0, data: o }, m = w(o);
942
- e ? e.postMessage(u, m) : i(u, m);
943
- } catch (s) {
944
- const o = {
945
- ok: !1,
946
- error: s instanceof Error ? s.message : String(s)
947
- };
948
- e ? e.postMessage(o) : i(o);
949
- }
950
- }
951
- self.addEventListener("message", (d) => {
952
- const s = d.data;
953
- if (s && s.__pipeline_ports__) {
954
- s.stepParams && (t = s.stepParams), s.outputPort && (e = s.outputPort), s.inputPort && (r = s.inputPort, r.onmessage = (o) => {
955
- var u;
956
- o.data && o.data.ok === !1 ? e ? e.postMessage(o.data) : i(o.data) : f({ data: (u = o.data) == null ? void 0 : u.data, ...t, index: 0 });
957
- }), a !== null && (f(a), a = null);
958
- return;
959
- }
960
- r ? a = s : f(s);
961
- });
1236
+ function oe(o) {
1237
+ return o === void 0 ? (e) => e : o;
1238
+ }
1239
+ function ae(...o) {
1240
+ return o;
962
1241
  }
963
1242
  export {
964
- q as MainWorkerFactory,
965
- M as WorkerFactory,
966
- N as defineWorker
1243
+ te as MainWorkerFactory,
1244
+ b as WorkerFactory,
1245
+ D as WorkerMode,
1246
+ ie as defineWorker,
1247
+ oe as defineWorkerConfig,
1248
+ ae as defineWorkerConfigs
967
1249
  };