@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.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var O=Object.defineProperty;var x=(l,e,r)=>e in l?O(l,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):l[e]=r;var _=(l,e,r)=>x(l,typeof e!="symbol"?e+"":e,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=l=>`
1
+ "use strict";var L=Object.defineProperty;var O=(o,e,r)=>e in o?L(o,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):o[e]=r;var y=(o,e,r)=>O(o,typeof e!="symbol"?e+"":e,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("./index-CXKVsLvY.cjs"),D=`
2
2
  const extractTransferables = (value, seen = new Set()) => {
3
3
  if (value === null || typeof value !== 'object') return [];
4
4
  if (seen.has(value)) return [];
@@ -12,31 +12,73 @@ const extractTransferables = (value, seen = new Set()) => {
12
12
  if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
13
13
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
14
14
  };
15
-
15
+ `,U=o=>`
16
+ ${D}
16
17
  self.addEventListener('message', async (event) => {
17
18
  try {
18
- const output = await ${l}(event.data);
19
+ const output = await ${o}(event.data);
19
20
  self.postMessage({ ok: true, data: output }, extractTransferables(output));
20
21
  } catch (err) {
21
22
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
22
23
  }
23
24
  })
24
- `,F=l=>`
25
- const extractTransferables = (value, seen = new Set()) => {
26
- if (value === null || typeof value !== 'object') return [];
27
- if (seen.has(value)) return [];
28
- seen.add(value);
29
- if (value instanceof ArrayBuffer || value instanceof MessagePort ||
30
- (typeof ImageBitmap !== 'undefined' && value instanceof ImageBitmap) ||
31
- (typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas)) {
32
- return [value];
25
+ `,N=o=>`
26
+ ${D}
27
+ const workerFn = ${o};
28
+ let memPort = null;
29
+ let factoryToken = null;
30
+ let pendingPayload = null;
31
+
32
+ async function runAndStore(payload) {
33
+ try {
34
+ const output = await workerFn(payload);
35
+ if (!memPort) {
36
+ // Fallback: no port provided, post data directly (legacy / opt-out path)
37
+ self.postMessage({ ok: true, data: output }, extractTransferables(output));
38
+ return;
39
+ }
40
+ // Store directly into MemoryWorker
41
+ const ref = 'mem_' + crypto.randomUUID();
42
+ await new Promise((resolve, reject) => {
43
+ memPort.onmessage = (e) => {
44
+ if (e.data && e.data.ref === ref) {
45
+ if (e.data.ok) resolve(e.data.ref);
46
+ else reject(new Error(e.data.error || 'MemoryWorker SET failed'));
47
+ }
48
+ };
49
+ memPort.postMessage({ action: 'SET', factoryToken, ref, data: output });
50
+ });
51
+ // Only the token reaches the main thread
52
+ self.postMessage({ ok: true, __memory_ref__: ref });
53
+ } catch (err) {
54
+ self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
33
55
  }
34
- if (ArrayBuffer.isView(value)) return [value.buffer];
35
- if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
36
- return Object.values(value).flatMap(v => extractTransferables(v, seen));
37
- };
56
+ }
38
57
 
39
- const workerFn = ${l};
58
+ self.addEventListener('message', async (event) => {
59
+ // Init message: receive the MemoryWorker port and factory token
60
+ if (event.data && event.data.__init_memory_port__) {
61
+ memPort = event.ports[0] ?? event.data.memPort;
62
+ factoryToken = event.data.factoryToken;
63
+ if (memPort) memPort.start();
64
+ // If a payload arrived before the port, process it now
65
+ if (pendingPayload !== null) {
66
+ const p = pendingPayload;
67
+ pendingPayload = null;
68
+ await runAndStore(p);
69
+ }
70
+ return;
71
+ }
72
+ // If port not yet received, queue the payload
73
+ if (!memPort) {
74
+ pendingPayload = event.data;
75
+ return;
76
+ }
77
+ await runAndStore(event.data);
78
+ });
79
+ `,j=o=>`
80
+ ${D}
81
+ const workerFn = ${o};
40
82
  let outputPort = null;
41
83
  let inputPort = null;
42
84
  let pendingData = null;
@@ -101,22 +143,9 @@ self.addEventListener('message', (event) => {
101
143
  pendingData = event.data;
102
144
  }
103
145
  });
104
- `,L=l=>`
105
- const extractTransferables = (value, seen = new Set()) => {
106
- if (value === null || typeof value !== 'object') return [];
107
- if (seen.has(value)) return [];
108
- seen.add(value);
109
- if (value instanceof ArrayBuffer || value instanceof MessagePort ||
110
- (typeof ImageBitmap !== 'undefined' && value instanceof ImageBitmap) ||
111
- (typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas)) {
112
- return [value];
113
- }
114
- if (ArrayBuffer.isView(value)) return [value.buffer];
115
- if (Array.isArray(value)) return value.flatMap(i => extractTransferables(i, seen));
116
- return Object.values(value).flatMap(v => extractTransferables(v, seen));
117
- };
118
-
119
- const workerFn = ${l};
146
+ `,G=o=>`
147
+ ${D}
148
+ const workerFn = ${o};
120
149
  let cachedDataset = null;
121
150
 
122
151
  self.addEventListener('message', async (event) => {
@@ -157,14 +186,137 @@ self.addEventListener('message', async (event) => {
157
186
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
158
187
  }
159
188
  });
160
- `;var P=(l=>(l.Default="default",l.Pipeline="pipeline",l.Persistent="persistent",l))(P||{});const C=Object.freeze({persistent:L,pipeline:F,default:j});class v{constructor(e,r){_(this,"_worker");if(r!=null&&r.createWorker)this._worker=r.createWorker();else if(e){const a=(r==null?void 0:r.mode)??"default",t=C[a](e.toString()),i=new Blob([t],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(i))}else throw new Error("Either workerFunction or options.createWorker must be provided to WorkerFactory.")}get getWorker(){return this._worker}}class I{constructor(e){this.results=e}}class ${constructor(){_(this,"store",new Map)}set(e,r){const a=r??`mem_${crypto.randomUUID()}`;return this.store.set(a,e),a}get(e){return this.store.get(e)}delete(e){return this.store.delete(e)}clear(){this.store.clear()}has(e){return this.store.has(e)}stats(){return{count:this.store.size,refs:Array.from(this.store.keys())}}}function w(l,e=new Set){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(r=>w(r,e)))}class U{constructor(e){_(this,"_workers");_(this,"_threads");_(this,"_persistentWorkers",new Map);_(this,"_activeWorkers",new Set);_(this,"_memoryStore",new $);_(this,"_isTerminated",!1);this._workers=e.workers,this._threads=navigator.hardwareConcurrency}get isTerminated(){return this._isTerminated}trackWorker(e){if(this._isTerminated)throw e.terminate(),new Error("MainWorkerFactory has been terminated");return this._activeWorkers.add(e),e}terminateWorker(e){this._activeWorkers.delete(e);try{e.terminate()}catch{}}initWorker(e){const r=new v(e.func,{createWorker:e.createWorker});return this.trackWorker(r.getWorker),r}partitionArray(e,r){if(!e.length)return[];if(r<=0)throw new Error("numChunks must be positive");const a=Math.min(r,e.length),t=Math.floor(e.length/a),i=e.length%a,f=[];let d=0;for(let s=0;s<a;s++){const o=t+(s<i?1:0);f.push(e.slice(d,d+o)),d+=o}return f}findWorkerByName(e){return this._workers.find(r=>r.name===e)}async runWorker(e,r){if(this._isTerminated)return Promise.reject(new Error("MainWorkerFactory has been terminated"));const a=this.findWorkerByName(e);if(!a)return Promise.reject(new Error(`Worker "${e}" not found`));let{srcData:t,...i}=r||{};const f=i.__memory_ref__,d=!!i.deleteMemory;if(t===void 0&&f){if(!this._memoryStore.has(f))return Promise.reject(new Error(`Memory reference "${f}" not found in MemoryStore`));t=this._memoryStore.get(f),delete i.__memory_ref__,delete i.deleteMemory}else delete i.deleteMemory;const s=a.maxConcurrency??this._threads,o=!!(Array.isArray(t)&&a.partition),u=o?this.partitionArray(t,s):t,p=o&&Array.isArray(u)?u.length:s,m=this.createWorkerPromises(a,e,{data:u,...i},p,o),c=await Promise.allSettled(m);return d&&f&&this._memoryStore.delete(f),(a.memoryOnly||a.memory)&&this.storeWorkerMemoryResult(c,{memoryOnly:!!a.memoryOnly,shouldPartition:o}),new I(c)}async deleteMemory(e){return this._memoryStore.delete(e)}async clearMemory(){this._memoryStore.clear()}storeWorkerMemoryResult(e,{memoryOnly:r,shouldPartition:a}){const t=e.filter(s=>s.status==="fulfilled"&&!!s.value.successResult);if(t.length===0)return;const i=t.map(s=>s.value.successResult.data),f=a&&i.every(Array.isArray)?i.flat():i.length===1?i[0]:i,d=this._memoryStore.set(f);for(const s of t){const o=r?{__memory_ref__:d}:{data:s.value.successResult.data,__memory_ref__:d};s.value.successResult=new MessageEvent("message",{data:o})}}async getMemoryStats(){return this._memoryStore.stats()}createWorkerPromises(e,r,a,t,i){const{data:f,...d}=a;return Array.from({length:t},(s,o)=>{const u=i&&Array.isArray(f)?f[o]:f;return this.runWorkerWithRetry({workerFunc:e.func,createWorker:e.createWorker,workerName:r,index:o,data:{data:u,...d}},e.retries)})}async runWorkerWithRetry(e,r=2){try{return await this.initiateWorker(e)}catch(a){if(r>0)return console.error(`Worker ${e.index} failed, retrying (${r} left):`,a),this.runWorkerWithRetry(e,r-1);throw console.error("Worker failed after all retries:",a),a}}initiateWorker({workerFunc:e,createWorker:r,workerName:a,index:t,data:i}){return new Promise((f,d)=>{const o=this.initWorker({name:a,role:"",func:e,createWorker:r}).getWorker;o.onerror=p=>{this.terminateWorker(o),d({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:i},failedResult:p})},o.onmessage=p=>{var c,n;if(((c=p.data)==null?void 0:c.ok)===!1){this.terminateWorker(o),d({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:i},failedResult:new ErrorEvent("error",{message:p.data.error})});return}const m=((n=p.data)==null?void 0:n.ok)!==void 0?p.data.data:p.data;f({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:i},successResult:new MessageEvent("message",{data:m})}),this.terminateWorker(o)};const u={index:t,...Array.isArray(i)?{data:i}:i};o.postMessage(u,w(u))})}async collectResults(e,r={}){if(this._isTerminated)throw new Error("MainWorkerFactory has been terminated");const a=e.results.filter(m=>m.status==="fulfilled"),t=e.results.filter(m=>m.status==="rejected");if(a.length>0&&a.every(m=>{var n;const c=(n=m.value.successResult)==null?void 0:n.data;return c&&typeof c=="object"&&"__memory_ref__"in c&&!("data"in c)}))return{data:a[0].value.successResult.data,succeeded:a.length,failed:t.length,errors:t};const f=a.length>0&&a.every(m=>{var n;const c=(n=m.value.successResult)==null?void 0:n.data;return c&&typeof c=="object"&&"__memory_ref__"in c&&"data"in c}),d=f?a[0].value.successResult.data.__memory_ref__:void 0,s=a.map(m=>{const c=m.value.successResult.data;return f&&c&&typeof c=="object"&&"data"in c?c.data:c}),o=r.reducer?r.reducer.toString():"(shards) => shards.flat()";let u;if(typeof Worker<"u"&&typeof Blob<"u"&&typeof URL<"u"&&typeof URL.createObjectURL=="function")try{u=await new Promise((m,c)=>{const n=`
161
- const reducer = ${o};
162
- self.addEventListener('message', (event) => {
163
- try {
164
- const result = reducer(event.data);
165
- self.postMessage({ ok: true, data: result });
166
- } catch (error) {
167
- self.postMessage({ ok: false, error: String(error) });
168
- }
169
- });
170
- `,h=new Blob([n],{type:"application/javascript"}),y=this.trackWorker(new Worker(URL.createObjectURL(h)));y.onmessage=k=>{this.terminateWorker(y),k.data.ok?m(k.data.data):c(new Error(k.data.error))},y.onerror=k=>{this.terminateWorker(y),c(k)},y.postMessage(s)})}catch{const m=n=>n.flat();u=(r.reducer??m)(s)}else{const m=n=>n.flat();u=(r.reducer??m)(s)}return{data:f?{data:u,__memory_ref__:d}:u,succeeded:a.length,failed:t.length,errors:t}}async pipeline(e){if(this._isTerminated)throw new Error("MainWorkerFactory has been terminated");if(e.length===0)throw new Error("Pipeline requires at least one step");if(e.length===1){const r=e[0],{worker:a,srcData:t,...i}=r,f=this.findWorkerByName(r.worker);if(!f)throw new Error(`Worker "${r.worker}" not found`);const s=this.initWorker(f).getWorker;return new Promise((o,u)=>{s.onmessage=c=>{var n,h;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)},s.onerror=c=>{this.terminateWorker(s),u(c)};const m={data:t??{},...i,index:0};s.postMessage(m,w(m))})}return new Promise((r,a)=>{const t=[],i=[];for(const n of e){const h=this.findWorkerByName(n.worker);if(!h){a(new Error(`Worker "${n.worker}" not found`));return}const y=new v(h.func,{mode:P.Pipeline,createWorker:h.createWorker}),k=this.trackWorker(y.getWorker);t.push(k)}for(let n=0;n<t.length-1;n++)i.push(new MessageChannel);for(let n=0;n<t.length;n++){const{worker:h,srcData:y,...k}=e[n],M=[],W={};if(n>0&&(W.inputPort=i[n-1].port1,M.push(W.inputPort)),n<t.length-1&&(W.outputPort=i[n].port2,M.push(W.outputPort)),t[n].postMessage({__pipeline_ports__:!0,stepParams:k,...W},M),n<t.length-1){const b=t[n],T=t[n+1],{worker:V,srcData:q,...A}=e[n+1];b.onmessage=g=>{var S,R;if(g.data&&g.data.__pipeline_ports__)return;if(((S=g.data)==null?void 0:S.ok)===!1){t.forEach(B=>this.terminateWorker(B)),a(new Error(g.data.error));return}const E={data:((R=g.data)==null?void 0:R.ok)!==void 0?g.data.data:g.data,...A,index:0};T.postMessage(E,w(E))},b.onerror=g=>{t.forEach(D=>this.terminateWorker(D)),a(g)}}}const f=t[t.length-1];f.onmessage=n=>{var h,y;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)},f.onerror=n=>{t.forEach(h=>this.terminateWorker(h)),a(n)};const{worker:d,srcData:s,...o}=e[0];let u=s;const p=o.__memory_ref__,m=!!o.deleteMemory;if(u===void 0&&p){if(!this._memoryStore.has(p)){t.forEach(n=>this.terminateWorker(n)),a(new Error(`Memory reference "${p}" not found in MemoryStore`));return}u=this._memoryStore.get(p),m&&this._memoryStore.delete(p),delete o.__memory_ref__,delete o.deleteMemory}u===void 0&&(u={});const c={data:u,...o,index:0};t[0].postMessage(c,w(c))})}async runPersistent(e,r){if(this._isTerminated)throw new Error("MainWorkerFactory has been terminated");const a=this.findWorkerByName(e);if(!a)throw new Error(`Worker "${e}" not found`);let t=this._persistentWorkers.get(e);if(!t){const i=new v(a.func,{mode:P.Persistent,createWorker:a.createWorker});t=this.trackWorker(i.getWorker),this._persistentWorkers.set(e,t)}return new Promise((i,f)=>{t.onmessage=s=>{var o,u;((o=s.data)==null?void 0:o.ok)===!1?f(new Error(s.data.error)):i((u=s.data)==null?void 0:u.data)},t.onerror=s=>{f(s)};const d={type:"run",config:r.config};r.dataset!==void 0&&(d.dataset=r.dataset),t.postMessage(d,w(d))})}release(e){const r=this._persistentWorkers.get(e);if(r){try{r.postMessage({type:"release"})}catch{}this.terminateWorker(r),this._persistentWorkers.delete(e)}}terminate(){this._isTerminated=!0;for(const e of this._persistentWorkers.values()){try{e.postMessage({type:"release"})}catch{}this.terminateWorker(e)}this._persistentWorkers.clear();for(const e of Array.from(this._activeWorkers))this.terminateWorker(e);this._activeWorkers.clear(),this._memoryStore.clear()}destroy(){this.terminate()}reset(){this.terminate(),this._isTerminated=!1}restart(){this.reset()}}function z(l){if(typeof self>"u")return;let e=null,r=null,a=null,t={};const i=(d,s)=>{self.postMessage(d,s)};async function f(d){try{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},p=w(o);e?e.postMessage(u,p):i(u,p)}catch(s){const o={ok:!1,error:s instanceof Error?s.message:String(s)};e?e.postMessage(o):i(o)}}self.addEventListener("message",d=>{const s=d.data;if(s&&s.__pipeline_ports__){s.stepParams&&(t=s.stepParams),s.outputPort&&(e=s.outputPort),s.inputPort&&(r=s.inputPort,r.onmessage=o=>{var u;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})}),a!==null&&(f(a),a=null);return}r?a=s:f(s)})}exports.MainWorkerFactory=U;exports.WorkerFactory=v;exports.defineWorker=z;
189
+ `;var S=(o=>(o.Default="default",o.Pipeline="pipeline",o.Persistent="persistent",o.Memory="memory",o))(S||{});const q=Object.freeze({persistent:G,pipeline:j,default:U,memory:N});class b{constructor(e,r){y(this,"_worker");if(r!=null&&r.createWorker)this._worker=r.createWorker();else if(e){const a=(r==null?void 0:r.mode)??"default",t=q[a](e.toString()),l=new Blob([t],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(l))}else throw new Error("Either workerFunction or options.createWorker must be provided to WorkerFactory.")}get getWorker(){return this._worker}}class z{constructor(){y(this,"store",new Map)}register(e,r={}){this.store.set(e,r)}has(e){return this.store.has(e)}delete(e){return this.store.delete(e)}clear(){this.store.clear()}stats(){return{count:this.store.size,refs:Array.from(this.store.keys())}}}const K=`
190
+ const store = new Map();
191
+
192
+ function handleMessage(msg, replyTarget) {
193
+ if (!msg || typeof msg !== 'object') return;
194
+
195
+ const { action, factoryToken, expectedToken, ref, data, id } = msg;
196
+
197
+ // Initial handshake to set expected token if needed
198
+ if (action === 'INIT_TOKEN') {
199
+ self.__expectedToken = expectedToken;
200
+ replyTarget.postMessage({ ok: true, action: 'INIT_TOKEN_ACK' });
201
+ return;
202
+ }
203
+
204
+ // Validate factory token
205
+ if (self.__expectedToken && factoryToken !== self.__expectedToken) {
206
+ replyTarget.postMessage({ ok: false, error: 'Unauthorized: invalid factory token', id });
207
+ return;
208
+ }
209
+
210
+ try {
211
+ switch (action) {
212
+ case 'SET': {
213
+ const refId = ref || ('mem_' + crypto.randomUUID());
214
+ store.set(refId, data);
215
+ replyTarget.postMessage({ ok: true, ref: refId, id });
216
+ break;
217
+ }
218
+ case 'GET': {
219
+ const resultData = store.get(ref);
220
+ const exists = store.has(ref);
221
+ replyTarget.postMessage({ ok: true, exists, data: resultData, ref, id });
222
+ break;
223
+ }
224
+ case 'DELETE': {
225
+ const deleted = store.delete(ref);
226
+ replyTarget.postMessage({ ok: true, deleted, ref, id });
227
+ break;
228
+ }
229
+ case 'CLEAR': {
230
+ store.clear();
231
+ replyTarget.postMessage({ ok: true, action: 'CLEAR_ACK', id });
232
+ break;
233
+ }
234
+ case 'STATS': {
235
+ replyTarget.postMessage({
236
+ ok: true,
237
+ stats: {
238
+ count: store.size,
239
+ refs: Array.from(store.keys()),
240
+ },
241
+ id,
242
+ });
243
+ break;
244
+ }
245
+ case 'REGISTER_PORT': {
246
+ // Register a MessagePort from a computing or reducer worker.
247
+ // All messages arriving on this port are handled with the same
248
+ // store operations, enabling direct worker-to-MemoryWorker data flow.
249
+ const port = msg.port;
250
+ if (!port) {
251
+ replyTarget.postMessage({ ok: false, error: 'REGISTER_PORT requires a port', id });
252
+ break;
253
+ }
254
+ port.onmessage = (event) => handleMessage(event.data, port);
255
+ port.start();
256
+ replyTarget.postMessage({ ok: true, action: 'PORT_REGISTERED', id });
257
+ break;
258
+ }
259
+ default:
260
+ replyTarget.postMessage({ ok: false, error: 'Unknown action: ' + action, id });
261
+ }
262
+ } catch (err) {
263
+ replyTarget.postMessage({
264
+ ok: false,
265
+ error: err instanceof Error ? err.message : String(err),
266
+ id,
267
+ });
268
+ }
269
+ }
270
+
271
+ self.addEventListener('message', (event) => {
272
+ // Handle REGISTER_PORT specially — the port itself is a Transferable in event.ports
273
+ if (event.data && event.data.action === 'REGISTER_PORT') {
274
+ const port = event.ports[0] ?? event.data.port;
275
+ const msg = { ...event.data, port };
276
+ handleMessage(msg, self);
277
+ return;
278
+ }
279
+ handleMessage(event.data, self);
280
+ });
281
+ `;class H{constructor(e){y(this,"worker");y(this,"factoryToken");y(this,"pending",new Map);this.factoryToken=e;const r=new Blob([K],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(r)),this.worker.onmessage=a=>{const{id:t}=a.data??{};if(t&&this.pending.has(t)){const l=this.pending.get(t);this.pending.delete(t),l(a.data)}},this.worker.postMessage({action:"INIT_TOKEN",expectedToken:e})}send(e,r={}){return new Promise(a=>{const t=`req_${crypto.randomUUID()}`;this.pending.set(t,a),this.worker.postMessage({action:e,factoryToken:this.factoryToken,id:t,...r})})}async set(e,r){const a=await this.send("SET",{data:e,ref:r});if(!a.ok)throw new Error(a.error);return a.ref}async get(e){const r=await this.send("GET",{ref:e});if(!r.ok)throw new Error(r.error);return r.data}async has(e){const r=await this.send("GET",{ref:e});if(!r.ok)throw new Error(r.error);return!!r.exists}async delete(e){const r=await this.send("DELETE",{ref:e});if(!r.ok)throw new Error(r.error);return!!r.deleted}async clear(){const e=await this.send("CLEAR");if(!e.ok)throw new Error(e.error)}async stats(){const e=await this.send("STATS");if(!e.ok)throw new Error(e.error);return e.stats}async allocateWorkerPort(){const e=new MessageChannel,{port1:r,port2:a}=e,t=`req_${crypto.randomUUID()}`;return this.pending.set(t,()=>{}),this.worker.postMessage({action:"REGISTER_PORT",factoryToken:this.factoryToken,id:t},[r]),await new Promise(l=>{const f=this.pending.get(t);this.pending.set(t,m=>{f(m),l()})}),a}terminate(){this.pending.clear(),this.worker.terminate()}}class J{constructor(e="error"){y(this,"level");this.level=e}setLevel(e){this.level=e}verbose(...e){this.level==="verbose"&&console.debug("[WorkerManager]",...e)}info(...e){(this.level==="verbose"||this.level==="info")&&console.info("[WorkerManager]",...e)}error(...e){this.level!=="silent"&&console.error("[WorkerManager]",...e)}}class V{constructor(e){this.results=e}}function x(o,e){if(!o.length)return[];if(e<=0)throw new Error("numChunks must be positive");const r=Math.min(e,o.length),a=Math.floor(o.length/r),t=o.length%r,l=[];let f=0;for(let m=0;m<r;m++){const i=a+(m<t?1:0);l.push(o.slice(f,f+i)),f+=i}return l}async function B(o,e={},r){if(r.isTerminated())throw r.logger.error("Attempted to collect results after MainWorkerFactory was terminated"),new Error("MainWorkerFactory has been terminated");const a=o.results.filter(n=>n.status==="fulfilled"),t=o.results.filter(n=>n.status==="rejected");if(a.length===0)return{data:[],succeeded:0,failed:t.length,errors:t};const l=a.map(n=>{var k;const c=(k=n.value.successResult)==null?void 0:k.data;return c==null?void 0:c.__memory_ref__}),f=l.every(n=>typeof n=="string"),m=e.reducer?e.reducer.toString():"(shards) => shards.flat()";let i;if(f&&typeof Worker<"u"&&typeof Blob<"u"&&typeof MessageChannel<"u"){const n=await r.memoryWorkerProxy.allocateWorkerPort(),c=`
282
+ const refs = ${JSON.stringify(l)};
283
+ const factoryToken = ${JSON.stringify(r.factoryToken)};
284
+ const reducer = ${m};
285
+
286
+ // collect-results.ts
287
+
288
+ self.addEventListener('message', async (event) => {
289
+ // event.ports[0] is the direct line to MemoryWorker
290
+ const memPort = event.ports[0];
291
+ if (!memPort) {
292
+ self.postMessage({ ok: false, error: 'No MemoryWorker port provided' });
293
+ self.close();
294
+ return;
295
+ }
296
+ memPort.start();
297
+
298
+ try {
299
+ // Fetch each shard directly from MemoryWorker
300
+ const shards = await Promise.all(refs.map((ref) =>
301
+ new Promise((resolve, reject) => {
302
+ const reqId = 'fetch_' + ref;
303
+ memPort.addEventListener('message', function handler(e) {
304
+ if (e.data && e.data.ref === ref) {
305
+ memPort.removeEventListener('message', handler);
306
+ if (e.data.ok) resolve(e.data.data);
307
+ else reject(new Error(e.data.error));
308
+ }
309
+ });
310
+ memPort.postMessage({ action: 'GET', factoryToken, ref, id: reqId });
311
+ })
312
+ ));
313
+
314
+ const result = reducer(shards);
315
+ self.postMessage({ ok: true, data: result });
316
+ } catch (error) {
317
+ self.postMessage({ ok: false, error: String(error) });
318
+ } finally {
319
+ self.close();
320
+ }
321
+ });
322
+ `;try{i=await new Promise((k,d)=>{const p=new Blob([c],{type:"application/javascript"}),s=r.trackWorker(new Worker(URL.createObjectURL(p)));s.onmessage=u=>{r.terminateWorker(s),u.data.ok?k(u.data.data):(r.logger.error("Collect results reducer worker failed",u.data.error),d(new Error(u.data.error)))},s.onerror=u=>{r.terminateWorker(s),r.logger.error("Collect results reducer worker encountered an error event",u),d(u)},s.postMessage({__start__:!0},[n])})}catch{const k=await Promise.all(l.map(s=>r.memoryWorkerProxy.get(s))),d=s=>s.flat();i=(e.reducer??d)(k)}}else if(f){const n=await Promise.all(l.map(d=>r.memoryWorkerProxy.get(d))),c=d=>d.flat();i=(e.reducer??c)(n)}else{const n=a.map(d=>d.value.successResult.data),c=d=>d.flat();i=(e.reducer??c)(n)}return{data:i,succeeded:a.length,failed:t.length,errors:t}}async function X(o,e,r){var E,R;if(r.isTerminated())return r.logger.error("Attempted to execute worker after MainWorkerFactory was terminated"),Promise.reject(new Error("MainWorkerFactory has been terminated"));const a=r.findWorkerByName(o);if(!a)return r.logger.error(`Worker config not found for worker: "${o}"`),Promise.reject(new Error(`Worker "${o}" not found`));const{srcData:t,reducer:l,autoCollect:f=!0,...m}=e||{};let i=t;const n=m.__memory_ref__,c=!!m.deleteMemory;if(i===void 0&&n){if(!r.memoryStore.has(n))return r.logger.error(`Attempted to use invalid memory reference: "${n}"`),Promise.reject(new Error(`Memory reference "${n}" not found in MemoryStore`));i=await r.memoryWorkerProxy.get(n),delete m.__memory_ref__,delete m.deleteMemory}else delete m.deleteMemory;const k=a.maxConcurrency??r.threads,d=!!(Array.isArray(i)&&a.partition),p=d?x(i,k):i,s=d&&Array.isArray(p)?p.length:k,u=r.orchestrator.createWorkerPromises(a,o,{data:p,...m},s,d),h=await Promise.allSettled(u);c&&n&&(await r.memoryWorkerProxy.delete(n),r.memoryStore.delete(n));for(const g of h)if(g.status==="fulfilled"){const W=(E=g.value.successResult)==null?void 0:E.data,w=W==null?void 0:W.__memory_ref__;w&&r.memoryStore.register(w)}const _=new V(h);if(!f){const g=h.filter(w=>w.status==="fulfilled").length,W=h.filter(w=>w.status==="rejected");return{data:_,succeeded:g,failed:W.length,errors:W}}const T=await B(_,{reducer:l},{isTerminated:()=>r.isTerminated(),trackWorker:r.orchestrator.context?g=>g:g=>g,terminateWorker:g=>{},logger:r.logger,memoryWorkerProxy:r.memoryWorkerProxy,factoryToken:r.factoryToken}),M=!!(a.memory||a.memoryOnly);for(const g of h)if(g.status==="fulfilled"){const W=(R=g.value.successResult)==null?void 0:R.data,w=W==null?void 0:W.__memory_ref__;w&&(r.memoryStore.delete(w),await r.memoryWorkerProxy.delete(w))}if(M){const g=await r.memoryWorkerProxy.set(T.data);return r.memoryStore.register(g),{...T,__memory_ref__:g}}return T}async function Q(o,e){if(e.isTerminated())throw e.logger.error("Attempted to execute pipeline after MainWorkerFactory was terminated"),new Error("MainWorkerFactory has been terminated");if(o.length===0)throw e.logger.error("Attempted to execute an empty pipeline"),new Error("Pipeline requires at least one step");if(o.length===1){const r=o[0],{worker:a,srcData:t,...l}=r,f=e.findWorkerByName(r.worker);if(!f)throw e.logger.error(`Pipeline step config not found for worker: "${r.worker}"`),new Error(`Worker "${r.worker}" not found`);const m=new b(f.func,{createWorker:f.createWorker});e.trackWorker(m.getWorker);const i=m.getWorker;return new Promise((n,c)=>{i.onmessage=p=>{var s,u;e.terminateWorker(i),((s=p.data)==null?void 0:s.ok)===!1?(e.logger.error(`Pipeline step ${r.worker} failed`,p.data.error),c(new Error(p.data.error))):n({data:(u=p.data)==null?void 0:u.data,succeeded:1,failed:0,errors:[]})},i.onerror=p=>{e.terminateWorker(i),e.logger.error(`Pipeline step ${r.worker} encountered an error event`,p),c(p)};const d={data:t??{},...l,index:0};e.logger.verbose(`Starting single-step pipeline for worker ${r.worker}`),i.postMessage(d,v.extractTransferable(d))})}return new Promise(async(r,a)=>{const t=[],l=[];for(const s of o){const u=e.findWorkerByName(s.worker);if(!u){e.logger.error(`Pipeline step config not found for worker: "${s.worker}"`),a(new Error(`Worker "${s.worker}" not found`));return}const h=new b(u.func,{mode:S.Pipeline,createWorker:u.createWorker}),_=e.trackWorker(h.getWorker);t.push(_)}for(let s=0;s<t.length-1;s++)l.push(new MessageChannel);for(let s=0;s<t.length;s++){const{worker:u,srcData:h,..._}=o[s],T=[],M={};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({__pipeline_ports__:!0,stepParams:_,...M},T),s<t.length-1){const E=t[s],R=t[s+1],{worker:g,srcData:W,...w}=o[s+1];E.onmessage=P=>{var F,I;if(P.data&&P.data.__pipeline_ports__)return;if(((F=P.data)==null?void 0:F.ok)===!1){e.logger.error(`Pipeline step ${o[s].worker} failed`,P.data.error),t.forEach(C=>e.terminateWorker(C)),a(new Error(P.data.error));return}const $={data:((I=P.data)==null?void 0:I.ok)!==void 0?P.data.data:P.data,...w,index:0};R.postMessage($,v.extractTransferable($))},E.onerror=P=>{e.logger.error(`Pipeline step ${o[s].worker} encountered an error event`,P),t.forEach(A=>e.terminateWorker(A)),a(P)}}}const f=t[t.length-1];f.onmessage=s=>{var u,h;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({data:(h=s.data)==null?void 0:h.data,succeeded:1,failed:0,errors:[]})},f.onerror=s=>{t.forEach(u=>e.terminateWorker(u)),e.logger.error("Final pipeline step encountered an error event",s),a(s)};const{worker:m,srcData:i,...n}=o[0];let c=i;const k=n.__memory_ref__,d=!!n.deleteMemory;if(c===void 0&&k){if(!e.memoryStore.has(k)){t.forEach(s=>e.terminateWorker(s)),e.logger.error(`Memory reference "${k}" not found in MemoryStore`),a(new Error(`Memory reference "${k}" not found in MemoryStore`));return}c=await e.memoryWorkerProxy.get(k),d&&(e.memoryStore.delete(k),await e.memoryWorkerProxy.delete(k)),delete n.__memory_ref__,delete n.deleteMemory}c===void 0&&(c={});const p={data:c,...n,index:0};e.logger.verbose(`Starting full pipeline with ${o.length} steps`),t[0].postMessage(p,v.extractTransferable(p))})}class Y{constructor(e){y(this,"_persistentWorkers",new Map);this.context=e}async runPersistent(e,r){if(this.context.isTerminated())throw this.context.logger.error("Attempted to run persistent worker after MainWorkerFactory was terminated"),new Error("MainWorkerFactory has been terminated");const a=this.context.findWorkerByName(e);if(!a)throw this.context.logger.error(`Persistent worker config not found for worker: "${e}"`),new Error(`Worker "${e}" not found`);let t=this._persistentWorkers.get(e);if(!t){const l=new b(a.func,{mode:S.Persistent,createWorker:a.createWorker});t=this.context.trackWorker(l.getWorker),this.context.logger.verbose(`Created persistent worker for ${e}`),this._persistentWorkers.set(e,t)}return new Promise((l,f)=>{t.onmessage=i=>{var n,c;((n=i.data)==null?void 0:n.ok)===!1?(this.context.logger.error(`Persistent worker ${e} failed`,i.data.error),f(new Error(i.data.error))):l((c=i.data)==null?void 0:c.data)},t.onerror=i=>{this.context.logger.error(`Persistent worker ${e} encountered an error event`,i),f(i)};const m={type:"run",config:r.config};r.dataset!==void 0&&(m.dataset=r.dataset),t.postMessage(m,v.extractTransferable(m))})}release(e){const r=this._persistentWorkers.get(e);if(r){try{r.postMessage({type:"release"})}catch{}this.context.terminateWorker(r),this._persistentWorkers.delete(e)}}terminateAll(){for(const e of this._persistentWorkers.values()){try{e.postMessage({type:"release"})}catch{}this.context.terminateWorker(e)}this._persistentWorkers.clear()}}class Z{constructor(e){this.context=e}createWorkerPromises(e,r,a,t,l){const{data:f,...m}=a;return Array.from({length:t},(i,n)=>{const c=l&&Array.isArray(f)?f[n]:f;return this.runWorkerWithRetry({workerFunc:e.func,createWorker:e.createWorker,workerName:r,index:n,data:{data:c,...m}},e.retries)})}async runWorkerWithRetry(e,r=2){try{return await this.initiateWorker(e)}catch(a){if(r>0)return this.context.logger.info(`Worker ${e.index} failed, retrying (${r} left):`,a),this.runWorkerWithRetry(e,r-1);throw this.context.logger.error("Worker failed after all retries:",a),a}}async initiateWorker({workerFunc:e,createWorker:r,workerName:a,index:t,data:l}){const f=await this.context.memoryWorkerProxy.allocateWorkerPort();return new Promise((m,i)=>{if(this.context.isTerminated()){i(new Error("MainWorkerFactory has been terminated"));return}const n=new b(e,{createWorker:r,mode:S.Memory}),c=this.context.trackWorker(n.getWorker);c.onerror=d=>{this.context.terminateWorker(c),i({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:l},failedResult:d})},c.onmessage=d=>{var u,h,_;if(((u=d.data)==null?void 0:u.ok)===!1){this.context.terminateWorker(c),i({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:l},failedResult:new ErrorEvent("error",{message:d.data.error})});return}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;m({index:t,workerConfigs:{workerFunc:e,createWorker:r,workerName:a,index:t,data:l},successResult:new MessageEvent("message",{data:s})}),this.context.terminateWorker(c)};const k={index:t,...Array.isArray(l)?{data:l}:l};c.postMessage({__init_memory_port__:!0,factoryToken:this.context.factoryToken},[f]),c.postMessage(k,v.extractTransferable(k))})}}class ee{constructor(e){y(this,"_workers");y(this,"_threads");y(this,"_activeWorkers",new Set);y(this,"_memoryStore",new z);y(this,"_memoryWorkerProxy");y(this,"_factoryToken");y(this,"_isTerminated",!1);y(this,"_persistentManager");y(this,"_orchestrator");y(this,"logger");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);const r={isTerminated:()=>this.isTerminated,findWorkerByName:this.findWorkerByName.bind(this),trackWorker:this.trackWorker.bind(this),terminateWorker:this.terminateWorker.bind(this),logger:this.logger,memoryWorkerProxy:this._memoryWorkerProxy,factoryToken:this._factoryToken};this._persistentManager=new Y(r),this._orchestrator=new Z(r)}get isTerminated(){return this._isTerminated}trackWorker(e){if(this._isTerminated)throw e.terminate(),new Error("MainWorkerFactory has been terminated");return this._activeWorkers.add(e),e}terminateWorker(e){this._activeWorkers.delete(e);try{e.terminate()}catch{}}partitionArray(e,r){return x(e,r)}findWorkerByName(e){return this._workers.find(r=>r.name===e)}async runWorker(e,r){return X(e,r,{isTerminated:()=>this.isTerminated,findWorkerByName:this.findWorkerByName.bind(this),memoryStore:this._memoryStore,memoryWorkerProxy:this._memoryWorkerProxy,factoryToken:this._factoryToken,threads:this._threads,orchestrator:this._orchestrator,logger:this.logger})}async deleteMemory(e){return this._memoryStore.delete(e),this._memoryWorkerProxy.delete(e)}async clearMemory(){this._memoryStore.clear(),await this._memoryWorkerProxy.clear()}async getMemoryStats(){return this._memoryWorkerProxy.stats()}async collectResults(e,r={}){return B(e,r,{isTerminated:()=>this.isTerminated,trackWorker:this.trackWorker.bind(this),terminateWorker:this.terminateWorker.bind(this),logger:this.logger,memoryWorkerProxy:this._memoryWorkerProxy,factoryToken:this._factoryToken})}async pipeline(e){return Q(e,{memoryStore:this._memoryStore,memoryWorkerProxy:this._memoryWorkerProxy,isTerminated:()=>this.isTerminated,findWorkerByName:this.findWorkerByName.bind(this),trackWorker:this.trackWorker.bind(this),terminateWorker:this.terminateWorker.bind(this),logger:this.logger})}async runPersistent(e,r){return this._persistentManager.runPersistent(e,r)}release(e){this._persistentManager.release(e)}terminate(){this._isTerminated=!0,this._persistentManager.terminateAll();for(const e of Array.from(this._activeWorkers))this.terminateWorker(e);this._activeWorkers.clear(),this._memoryStore.clear(),this._memoryWorkerProxy.terminate()}destroy(){this.terminate()}reset(){this.terminate(),this._isTerminated=!1}restart(){this.reset()}}function re(o){return o===void 0?e=>e:o}function te(...o){return o}exports.defineWorker=v.defineWorker;exports.MainWorkerFactory=ee;exports.WorkerFactory=b;exports.WorkerMode=S;exports.defineWorkerConfig=re;exports.defineWorkerConfigs=te;