@offmain/workerkit 0.11.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,14 +57,68 @@ console.log(data); // [15]
57
57
 
58
58
  ## WorkerConfig Options
59
59
 
60
- | Option | Type | Default | Description |
61
- | ---------------- | ---------- | ------------------------------- | --------------------------------------------------------------------------------------------------- |
62
- | `name` | `string` | — | Unique identifier used to call the worker |
63
- | `role` | `string` | — | Logical grouping label |
64
- | `func` | `Function` | — | The exported worker function to run |
65
- | `maxConcurrency` | `number` | `navigator.hardwareConcurrency` | Max parallel worker instances defaults to the number of logical CPU cores reported by the browser |
66
- | `retries` | `number` | `0` | How many times to retry a failed shard before marking it as rejected |
67
- | `partition` | `boolean` | `false` | Split array input across multiple workers automatically |
60
+ | Option | Type | Default | Description |
61
+ | ---------------- | --------------- | ------------------------------- | --------------------------------------------------------------------------------------------------- |
62
+ | `name` | `string` | — | Unique identifier used to call the worker |
63
+ | `role` | `string` | — | Logical grouping label |
64
+ | `func` | `Function` | — | The exported worker function to run (optional if `workerURL` is provided) |
65
+ | `workerURL` | `string \| URL` | — | Worker script URL or `new URL(..., import.meta.url)` for module bundlers |
66
+ | `maxConcurrency` | `number` | `navigator.hardwareConcurrency` | Max parallel worker instances — defaults to the number of logical CPU cores reported by the browser |
67
+ | `retries` | `number` | `0` | How many times to retry a failed shard before marking it as rejected |
68
+ | `partition` | `boolean` | `false` | Split array input across multiple workers automatically |
69
+
70
+ ---
71
+
72
+ ## Module Bundler Integration (`workerURL`)
73
+
74
+ When worker logic relies on external npm packages (such as Luxon, `date-fns`, `i18next`, or custom data transformation modules), dynamic inline stringification (`.toString()`) cannot access those closed-over imports.
75
+
76
+ Passing `workerURL` enables modern module bundlers (Webpack 5, Vite, Rollup, Parcel) to analyze and bundle the worker file along with all of its dependencies into a dedicated ES module worker chunk.
77
+
78
+ ### Dedicated Worker Script
79
+
80
+ ```ts
81
+ // transform-data.worker.ts
82
+ import { format } from 'date-fns';
83
+ import { t } from './i18n.ts';
84
+
85
+ self.addEventListener('message', (event) => {
86
+ try {
87
+ const { items, locale } = event.data.data;
88
+ const result = items.map((item: any) => ({
89
+ ...item,
90
+ formattedDate: format(new Date(item.timestamp), 'yyyy-MM-dd'),
91
+ label: t('transaction', locale),
92
+ }));
93
+
94
+ self.postMessage({ ok: true, data: result });
95
+ } catch (err) {
96
+ self.postMessage({ ok: false, error: (err as Error).message });
97
+ }
98
+ });
99
+ ```
100
+
101
+ ### Registering with `workerURL`
102
+
103
+ ```ts
104
+ import { MainWorkerFactory } from '@offmain/workerkit';
105
+
106
+ const factory = new MainWorkerFactory({
107
+ workers: [
108
+ {
109
+ name: 'transformData',
110
+ role: 'compute',
111
+ // Webpack 5 / Vite statically analyzes new URL(..., import.meta.url)
112
+ workerURL: new URL('./transform-data.worker.ts', import.meta.url),
113
+ maxConcurrency: 4,
114
+ },
115
+ ] as const,
116
+ });
117
+
118
+ const settled = await factory.runWorker('transformData', {
119
+ srcData: { locale: 'es', items: [{ timestamp: Date.now() }] },
120
+ });
121
+ ```
68
122
 
69
123
  ---
70
124
 
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var y=Object.defineProperty;var m=(s,e,t)=>e in s?y(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var h=(s,e,t)=>m(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=s=>`
1
+ "use strict";var v=Object.defineProperty;var y=(n,e,r)=>e in n?v(n,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):n[e]=r;var k=(n,e,r)=>y(n,typeof e!="symbol"?e+"":e,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=n=>`
2
2
  const extractTransferables = (value, seen = new Set()) => {
3
3
  if (value === null || typeof value !== 'object') return [];
4
4
  if (seen.has(value)) return [];
@@ -15,13 +15,13 @@ const extractTransferables = (value, seen = new Set()) => {
15
15
 
16
16
  self.addEventListener('message', async (event) => {
17
17
  try {
18
- const output = await ${s}(event.data);
18
+ const output = await ${n}(event.data);
19
19
  self.postMessage({ ok: true, data: output }, extractTransferables(output));
20
20
  } catch (err) {
21
21
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
22
22
  }
23
23
  })
24
- `,P=s=>`
24
+ `,P=n=>`
25
25
  const extractTransferables = (value, seen = new Set()) => {
26
26
  if (value === null || typeof value !== 'object') return [];
27
27
  if (seen.has(value)) return [];
@@ -36,7 +36,7 @@ const extractTransferables = (value, seen = new Set()) => {
36
36
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
37
37
  };
38
38
 
39
- const workerFn = ${s};
39
+ const workerFn = ${n};
40
40
  let outputPort = null;
41
41
  let inputPort = null;
42
42
  let pendingData = null;
@@ -93,7 +93,7 @@ self.addEventListener('message', (event) => {
93
93
  pendingData = event.data;
94
94
  }
95
95
  });
96
- `,M=s=>`
96
+ `,W=n=>`
97
97
  const extractTransferables = (value, seen = new Set()) => {
98
98
  if (value === null || typeof value !== 'object') return [];
99
99
  if (seen.has(value)) return [];
@@ -108,7 +108,7 @@ const extractTransferables = (value, seen = new Set()) => {
108
108
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
109
109
  };
110
110
 
111
- const workerFn = ${s};
111
+ const workerFn = ${n};
112
112
  let cachedDataset = null;
113
113
 
114
114
  self.addEventListener('message', async (event) => {
@@ -149,8 +149,8 @@ self.addEventListener('message', async (event) => {
149
149
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
150
150
  }
151
151
  });
152
- `;var v=(s=>(s.Default="default",s.Pipeline="pipeline",s.Persistent="persistent",s))(v||{});const W=Object.freeze({persistent:M,pipeline:P,default:w});class k{constructor(e,t){h(this,"_worker");const n=(t==null?void 0:t.mode)??"default",a=W[n](e.toString()),u=new Blob([a],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(u))}get getWorker(){return this._worker}}class b{constructor(e){this.results=e}}function p(s,e=new Set){return s===null||typeof s!="object"?[]:e.has(s)?[]:(e.add(s),s instanceof ArrayBuffer||s instanceof MessagePort||typeof ImageBitmap<"u"&&s instanceof ImageBitmap||typeof OffscreenCanvas<"u"&&s instanceof OffscreenCanvas?[s]:ArrayBuffer.isView(s)?[s.buffer]:Array.isArray(s)?s.flatMap(t=>p(t,e)):Object.values(s).flatMap(t=>p(t,e)))}class A{constructor(e){h(this,"_workers");h(this,"_threads");h(this,"_persistentWorkers",new Map);this._workers=e.workers,this._threads=navigator.hardwareConcurrency}initWorker(e){return new k(e)}partitionArray(e,t){if(!e.length)return[];if(t<=0)throw new Error("numChunks must be positive");const n=Math.min(t,e.length),a=Math.floor(e.length/n),u=e.length%n,f=[];let l=0;for(let r=0;r<n;r++){const o=a+(r<u?1:0);f.push(e.slice(l,l+o)),l+=o}return f}findWorkerByName(e){return this._workers.find(t=>t.name===e)}async runWorker(e,{srcData:t,...n}){const a=this.findWorkerByName(e);if(!a)return Promise.reject(new Error(`Worker "${e}" not found`));const u=a.maxConcurrency??this._threads,f=!!(Array.isArray(t)&&t.length>1&&a.partition),l=f?this.partitionArray(t,u):t,r=this.createWorkerPromises(a,e,{data:l,...n},u,f),o=await Promise.allSettled(r);return new b(o)}createWorkerPromises(e,t,n,a,u){const{data:f,...l}=n;return Array.from({length:a},(r,o)=>{const i=u&&Array.isArray(f)?f[o]:f;return this.runWorkerWithRetry({workerFunc:e.func,workerName:t,index:o,data:{data:i,...l}},e.retries)})}async runWorkerWithRetry(e,t=2){try{return await this.initiateWorker(e)}catch(n){if(t>0)return console.error(`Worker ${e.index} failed, retrying (${t} left):`,n),this.runWorkerWithRetry(e,t-1);throw console.error("Worker failed after all retries:",n),n}}initiateWorker({workerFunc:e,workerName:t,index:n,data:a}){return new Promise((u,f)=>{const r=this.initWorker(e).getWorker;r.onerror=i=>{r.terminate(),f({index:n,workerConfigs:{workerFunc:e,workerName:t,index:n,data:a},failedResult:i})},r.onmessage=i=>{var c,d;if(((c=i.data)==null?void 0:c.ok)===!1){r.terminate(),f({index:n,workerConfigs:{workerFunc:e,workerName:t,index:n,data:a},failedResult:new ErrorEvent("error",{message:i.data.error})});return}u({index:n,workerConfigs:{workerFunc:e,workerName:t,index:n,data:a},successResult:new MessageEvent("message",{data:(d=i.data)==null?void 0:d.data})}),r.terminate()};const o={index:n,...Array.isArray(a)?{data:a}:a};r.postMessage(o,p(o))})}async collectResults(e,t={}){const n=e.results.filter(r=>r.status==="fulfilled"),a=e.results.filter(r=>r.status==="rejected"),u=n.map(r=>r.value.successResult.data),f=t.reducer?t.reducer.toString():"(shards) => shards.flat()";return{data:await new Promise((r,o)=>{const i=`
153
- const reducer = ${f};
152
+ `;var w=(n=>(n.Default="default",n.Pipeline="pipeline",n.Persistent="persistent",n))(w||{});const M=Object.freeze({persistent:W,pipeline:P,default:m});class h{constructor(e,r){k(this,"_worker");if(r!=null&&r.workerURL)this._worker=new Worker(r.workerURL,{type:"module"});else if(e){const o=(r==null?void 0:r.mode)??"default",a=M[o](e.toString()),i=new Blob([a],{type:"application/javascript"});this._worker=new Worker(URL.createObjectURL(i))}else throw new Error("Either workerFunction or options.workerURL must be provided to WorkerFactory.")}get getWorker(){return this._worker}}class b{constructor(e){this.results=e}}function g(n,e=new Set){return n===null||typeof n!="object"?[]:e.has(n)?[]:(e.add(n),n instanceof ArrayBuffer||n instanceof MessagePort||typeof ImageBitmap<"u"&&n instanceof ImageBitmap||typeof OffscreenCanvas<"u"&&n instanceof OffscreenCanvas?[n]:ArrayBuffer.isView(n)?[n.buffer]:Array.isArray(n)?n.flatMap(r=>g(r,e)):Object.values(n).flatMap(r=>g(r,e)))}class E{constructor(e){k(this,"_workers");k(this,"_threads");k(this,"_persistentWorkers",new Map);this._workers=e.workers,this._threads=navigator.hardwareConcurrency}initWorker(e){return new h(e.func,{workerURL:e.workerURL})}partitionArray(e,r){if(!e.length)return[];if(r<=0)throw new Error("numChunks must be positive");const o=Math.min(r,e.length),a=Math.floor(e.length/o),i=e.length%o,l=[];let f=0;for(let t=0;t<o;t++){const s=a+(t<i?1:0);l.push(e.slice(f,f+s)),f+=s}return l}findWorkerByName(e){return this._workers.find(r=>r.name===e)}async runWorker(e,{srcData:r,...o}){const a=this.findWorkerByName(e);if(!a)return Promise.reject(new Error(`Worker "${e}" not found`));const i=a.maxConcurrency??this._threads,l=!!(Array.isArray(r)&&r.length>1&&a.partition),f=l?this.partitionArray(r,i):r,t=this.createWorkerPromises(a,e,{data:f,...o},i,l),s=await Promise.allSettled(t);return new b(s)}createWorkerPromises(e,r,o,a,i){const{data:l,...f}=o;return Array.from({length:a},(t,s)=>{const u=i&&Array.isArray(l)?l[s]:l;return this.runWorkerWithRetry({workerFunc:e.func,workerURL:e.workerURL,workerName:r,index:s,data:{data:u,...f}},e.retries)})}async runWorkerWithRetry(e,r=2){try{return await this.initiateWorker(e)}catch(o){if(r>0)return console.error(`Worker ${e.index} failed, retrying (${r} left):`,o),this.runWorkerWithRetry(e,r-1);throw console.error("Worker failed after all retries:",o),o}}initiateWorker({workerFunc:e,workerURL:r,workerName:o,index:a,data:i}){return new Promise((l,f)=>{const s=this.initWorker({name:o,role:"",func:e,workerURL:r}).getWorker;s.onerror=c=>{s.terminate(),f({index:a,workerConfigs:{workerFunc:e,workerName:o,index:a,data:i},failedResult:c})},s.onmessage=c=>{var d,p;if(((d=c.data)==null?void 0:d.ok)===!1){s.terminate(),f({index:a,workerConfigs:{workerFunc:e,workerName:o,index:a,data:i},failedResult:new ErrorEvent("error",{message:c.data.error})});return}l({index:a,workerConfigs:{workerFunc:e,workerName:o,index:a,data:i},successResult:new MessageEvent("message",{data:(p=c.data)==null?void 0:p.data})}),s.terminate()};const u={index:a,...Array.isArray(i)?{data:i}:i};s.postMessage(u,g(u))})}async collectResults(e,r={}){const o=e.results.filter(t=>t.status==="fulfilled"),a=e.results.filter(t=>t.status==="rejected"),i=o.map(t=>t.value.successResult.data),l=r.reducer?r.reducer.toString():"(shards) => shards.flat()";return{data:await new Promise((t,s)=>{const u=`
153
+ const reducer = ${l};
154
154
  self.addEventListener('message', (event) => {
155
155
  try {
156
156
  const result = reducer(event.data);
@@ -159,4 +159,4 @@ self.addEventListener('message', async (event) => {
159
159
  self.postMessage({ ok: false, error: String(err) });
160
160
  }
161
161
  });
162
- `,c=new Blob([i],{type:"application/javascript"}),d=new Worker(URL.createObjectURL(c));d.onmessage=g=>{d.terminate(),g.data.ok?r(g.data.data):o(new Error(g.data.error))},d.onerror=g=>{d.terminate(),o(g)},d.postMessage(u)}),succeeded:n.length,failed:a.length,errors:a}}async pipeline(e){if(e.length===0)throw new Error("Pipeline requires at least one step");if(e.length===1){const t=e[0],n=this.findWorkerByName(t.worker);if(!n)throw new Error(`Worker "${t.worker}" not found`);const u=this.initWorker(n.func).getWorker;return new Promise((f,l)=>{u.onmessage=o=>{var i,c;u.terminate(),((i=o.data)==null?void 0:i.ok)===!1?l(new Error(o.data.error)):f((c=o.data)==null?void 0:c.data)},u.onerror=o=>{u.terminate(),l(o)};const r=t.srcData??{};u.postMessage({data:r,index:0},p(r))})}return new Promise((t,n)=>{const a=[],u=[];for(const r of e){const o=this.findWorkerByName(r.worker);if(!o){n(new Error(`Worker "${r.worker}" not found`));return}const i=new k(o.func,{mode:v.Pipeline});a.push(i.getWorker)}for(let r=0;r<a.length-1;r++)u.push(new MessageChannel);for(let r=0;r<a.length;r++){const o=[],i={};r>0&&(i.inputPort=u[r-1].port1,o.push(i.inputPort)),r<a.length-1&&(i.outputPort=u[r].port2,o.push(i.outputPort)),a[r].postMessage({__pipeline_ports__:!0,...i},o)}const f=a[a.length-1];f.onmessage=r=>{var o,i;a.forEach(c=>c.terminate()),((o=r.data)==null?void 0:o.ok)===!1?n(new Error(r.data.error)):t((i=r.data)==null?void 0:i.data)},f.onerror=r=>{a.forEach(o=>o.terminate()),n(r)};const l=e[0].srcData??{};a[0].postMessage({data:l,index:0},p(l))})}async runPersistent(e,t){const n=this.findWorkerByName(e);if(!n)throw new Error(`Worker "${e}" not found`);let a=this._persistentWorkers.get(e);return a||(a=new k(n.func,{mode:v.Persistent}).getWorker,this._persistentWorkers.set(e,a)),new Promise((u,f)=>{a.onmessage=r=>{var o,i;((o=r.data)==null?void 0:o.ok)===!1?f(new Error(r.data.error)):u((i=r.data)==null?void 0:i.data)},a.onerror=r=>{f(r)};const l={type:"run",config:t.config};t.dataset!==void 0&&(l.dataset=t.dataset),a.postMessage(l,p(l))})}release(e){const t=this._persistentWorkers.get(e);t&&(t.postMessage({type:"release"}),t.terminate(),this._persistentWorkers.delete(e))}}exports.MainWorkerFactory=A;exports.WorkerFactory=k;
162
+ `,c=new Blob([u],{type:"application/javascript"}),d=new Worker(URL.createObjectURL(c));d.onmessage=p=>{d.terminate(),p.data.ok?t(p.data.data):s(new Error(p.data.error))},d.onerror=p=>{d.terminate(),s(p)},d.postMessage(i)}),succeeded:o.length,failed:a.length,errors:a}}async pipeline(e){if(e.length===0)throw new Error("Pipeline requires at least one step");if(e.length===1){const r=e[0],o=this.findWorkerByName(r.worker);if(!o)throw new Error(`Worker "${r.worker}" not found`);const i=this.initWorker(o).getWorker;return new Promise((l,f)=>{i.onmessage=s=>{var u,c;i.terminate(),((u=s.data)==null?void 0:u.ok)===!1?f(new Error(s.data.error)):l((c=s.data)==null?void 0:c.data)},i.onerror=s=>{i.terminate(),f(s)};const t=r.srcData??{};i.postMessage({data:t,index:0},g(t))})}return new Promise((r,o)=>{const a=[],i=[];for(const t of e){const s=this.findWorkerByName(t.worker);if(!s){o(new Error(`Worker "${t.worker}" not found`));return}const u=new h(s.func,{mode:w.Pipeline,workerURL:s.workerURL});a.push(u.getWorker)}for(let t=0;t<a.length-1;t++)i.push(new MessageChannel);for(let t=0;t<a.length;t++){const s=[],u={};t>0&&(u.inputPort=i[t-1].port1,s.push(u.inputPort)),t<a.length-1&&(u.outputPort=i[t].port2,s.push(u.outputPort)),a[t].postMessage({__pipeline_ports__:!0,...u},s)}const l=a[a.length-1];l.onmessage=t=>{var s,u;a.forEach(c=>c.terminate()),((s=t.data)==null?void 0:s.ok)===!1?o(new Error(t.data.error)):r((u=t.data)==null?void 0:u.data)},l.onerror=t=>{a.forEach(s=>s.terminate()),o(t)};const f=e[0].srcData??{};a[0].postMessage({data:f,index:0},g(f))})}async runPersistent(e,r){const o=this.findWorkerByName(e);if(!o)throw new Error(`Worker "${e}" not found`);let a=this._persistentWorkers.get(e);return a||(a=new h(o.func,{mode:w.Persistent,workerURL:o.workerURL}).getWorker,this._persistentWorkers.set(e,a)),new Promise((i,l)=>{a.onmessage=t=>{var s,u;((s=t.data)==null?void 0:s.ok)===!1?l(new Error(t.data.error)):i((u=t.data)==null?void 0:u.data)},a.onerror=t=>{l(t)};const f={type:"run",config:r.config};r.dataset!==void 0&&(f.dataset=r.dataset),a.postMessage(f,g(f))})}release(e){const r=this._persistentWorkers.get(e);r&&(r.postMessage({type:"release"}),r.terminate(),this._persistentWorkers.delete(e))}}exports.MainWorkerFactory=E;exports.WorkerFactory=h;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- var w = Object.defineProperty;
2
- var m = (s, e, t) => e in s ? w(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
- var h = (s, e, t) => m(s, typeof e != "symbol" ? e + "" : e, t);
4
- const y = (s) => `
1
+ var v = Object.defineProperty;
2
+ var m = (n, e, r) => e in n ? v(n, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : n[e] = r;
3
+ var h = (n, e, r) => m(n, typeof e != "symbol" ? e + "" : e, r);
4
+ const y = (n) => `
5
5
  const extractTransferables = (value, seen = new Set()) => {
6
6
  if (value === null || typeof value !== 'object') return [];
7
7
  if (seen.has(value)) return [];
@@ -18,13 +18,13 @@ const extractTransferables = (value, seen = new Set()) => {
18
18
 
19
19
  self.addEventListener('message', async (event) => {
20
20
  try {
21
- const output = await ${s}(event.data);
21
+ const output = await ${n}(event.data);
22
22
  self.postMessage({ ok: true, data: output }, extractTransferables(output));
23
23
  } catch (err) {
24
24
  self.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
25
25
  }
26
26
  })
27
- `, P = (s) => `
27
+ `, P = (n) => `
28
28
  const extractTransferables = (value, seen = new Set()) => {
29
29
  if (value === null || typeof value !== 'object') return [];
30
30
  if (seen.has(value)) return [];
@@ -39,7 +39,7 @@ const extractTransferables = (value, seen = new Set()) => {
39
39
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
40
40
  };
41
41
 
42
- const workerFn = ${s};
42
+ const workerFn = ${n};
43
43
  let outputPort = null;
44
44
  let inputPort = null;
45
45
  let pendingData = null;
@@ -96,7 +96,7 @@ self.addEventListener('message', (event) => {
96
96
  pendingData = event.data;
97
97
  }
98
98
  });
99
- `, M = (s) => `
99
+ `, W = (n) => `
100
100
  const extractTransferables = (value, seen = new Set()) => {
101
101
  if (value === null || typeof value !== 'object') return [];
102
102
  if (seen.has(value)) return [];
@@ -111,7 +111,7 @@ const extractTransferables = (value, seen = new Set()) => {
111
111
  return Object.values(value).flatMap(v => extractTransferables(v, seen));
112
112
  };
113
113
 
114
- const workerFn = ${s};
114
+ const workerFn = ${n};
115
115
  let cachedDataset = null;
116
116
 
117
117
  self.addEventListener('message', async (event) => {
@@ -153,9 +153,9 @@ self.addEventListener('message', async (event) => {
153
153
  }
154
154
  });
155
155
  `;
156
- var v = /* @__PURE__ */ ((s) => (s.Default = "default", s.Pipeline = "pipeline", s.Persistent = "persistent", s))(v || {});
157
- const W = Object.freeze({
158
- persistent: M,
156
+ var w = /* @__PURE__ */ ((n) => (n.Default = "default", n.Pipeline = "pipeline", n.Persistent = "persistent", n))(w || {});
157
+ const M = Object.freeze({
158
+ persistent: W,
159
159
  pipeline: P,
160
160
  default: y
161
161
  });
@@ -168,16 +168,23 @@ class k {
168
168
  *
169
169
  * @param workerFunction - The function to run inside the worker thread.
170
170
  * Must be self-contained — it cannot reference variables from the outer
171
- * scope because it is serialised via `.toString()`.
171
+ * scope because it is serialized via `.toString()`.
172
172
  * @param options - Optional configuration. Set `mode` to control the
173
173
  * worker execution mode (default, pipeline, or persistent).
174
174
  */
175
- constructor(e, t) {
175
+ constructor(e, r) {
176
176
  h(this, "_worker");
177
- const n = (t == null ? void 0 : t.mode) ?? "default", a = W[n](e.toString()), f = new Blob([a], {
178
- type: "application/javascript"
179
- });
180
- this._worker = new Worker(URL.createObjectURL(f));
177
+ if (r != null && r.workerURL)
178
+ this._worker = new Worker(r.workerURL, { type: "module" });
179
+ else if (e) {
180
+ const o = (r == null ? void 0 : r.mode) ?? "default", a = M[o](e.toString()), i = new Blob([a], {
181
+ type: "application/javascript"
182
+ });
183
+ this._worker = new Worker(URL.createObjectURL(i));
184
+ } else
185
+ throw new Error(
186
+ "Either workerFunction or options.workerURL must be provided to WorkerFactory."
187
+ );
181
188
  }
182
189
  /**
183
190
  * Returns the underlying native `Worker` instance.
@@ -194,12 +201,12 @@ class b {
194
201
  this.results = e;
195
202
  }
196
203
  }
197
- function p(s, e = /* @__PURE__ */ new Set()) {
198
- return s === null || typeof s != "object" ? [] : e.has(s) ? [] : (e.add(s), s instanceof ArrayBuffer || s instanceof MessagePort || typeof ImageBitmap < "u" && s instanceof ImageBitmap || typeof OffscreenCanvas < "u" && s instanceof OffscreenCanvas ? [s] : ArrayBuffer.isView(s) ? [s.buffer] : Array.isArray(s) ? s.flatMap((t) => p(t, e)) : Object.values(s).flatMap(
199
- (t) => p(t, e)
204
+ function g(n, e = /* @__PURE__ */ new Set()) {
205
+ return n === null || typeof n != "object" ? [] : e.has(n) ? [] : (e.add(n), n instanceof ArrayBuffer || n instanceof MessagePort || typeof ImageBitmap < "u" && n instanceof ImageBitmap || typeof OffscreenCanvas < "u" && n instanceof OffscreenCanvas ? [n] : ArrayBuffer.isView(n) ? [n.buffer] : Array.isArray(n) ? n.flatMap((r) => g(r, e)) : Object.values(n).flatMap(
206
+ (r) => g(r, e)
200
207
  ));
201
208
  }
202
- class B {
209
+ class A {
203
210
  /**
204
211
  * Creates a new `MainWorkerFactory`.
205
212
  *
@@ -212,13 +219,15 @@ class B {
212
219
  this._workers = e.workers, this._threads = navigator.hardwareConcurrency;
213
220
  }
214
221
  /**
215
- * Instantiates a {@link WorkerFactory} for the given worker function.
222
+ * Instantiates a {@link WorkerFactory} for the given worker configuration.
216
223
  *
217
- * @param workerFunction - The function to run inside the worker thread.
224
+ * @param config - The worker configuration containing `func` or `workerURL`.
218
225
  * @returns A new `WorkerFactory` wrapping the worker.
219
226
  */
220
227
  initWorker(e) {
221
- return new k(e);
228
+ return new k(e.func, {
229
+ workerURL: e.workerURL
230
+ });
222
231
  }
223
232
  /**
224
233
  * Splits an array into up to `numChunks` evenly-sized sub-arrays.
@@ -236,16 +245,16 @@ class B {
236
245
  * partitionArray([1, 2, 3, 4, 5], 3);
237
246
  * // → [[1, 2], [3, 4], [5]]
238
247
  */
239
- partitionArray(e, t) {
248
+ partitionArray(e, r) {
240
249
  if (!e.length) return [];
241
- if (t <= 0) throw new Error("numChunks must be positive");
242
- const n = Math.min(t, e.length), a = Math.floor(e.length / n), f = e.length % n, u = [];
250
+ if (r <= 0) throw new Error("numChunks must be positive");
251
+ const o = Math.min(r, e.length), a = Math.floor(e.length / o), i = e.length % o, f = [];
243
252
  let l = 0;
244
- for (let r = 0; r < n; r++) {
245
- const o = a + (r < f ? 1 : 0);
246
- u.push(e.slice(l, l + o)), l += o;
253
+ for (let t = 0; t < o; t++) {
254
+ const s = a + (t < i ? 1 : 0);
255
+ f.push(e.slice(l, l + s)), l += s;
247
256
  }
248
- return u;
257
+ return f;
249
258
  }
250
259
  /**
251
260
  * Looks up a registered worker configuration by name.
@@ -254,7 +263,7 @@ class B {
254
263
  * @returns The matching config, or `undefined` if not found.
255
264
  */
256
265
  findWorkerByName(e) {
257
- return this._workers.find((t) => t.name === e);
266
+ return this._workers.find((r) => r.name === e);
258
267
  }
259
268
  /**
260
269
  * Runs a named worker against the provided data, distributing work across
@@ -283,20 +292,20 @@ class B {
283
292
  * const settled = await foreman.runWorker('sum', { srcData: [1, 2, 3] });
284
293
  */
285
294
  async runWorker(e, {
286
- srcData: t,
287
- ...n
295
+ srcData: r,
296
+ ...o
288
297
  }) {
289
298
  const a = this.findWorkerByName(e);
290
299
  if (!a)
291
300
  return Promise.reject(new Error(`Worker "${e}" not found`));
292
- const f = a.maxConcurrency ?? this._threads, u = !!(Array.isArray(t) && t.length > 1 && a.partition), l = u ? this.partitionArray(t, f) : t, r = this.createWorkerPromises(
301
+ const i = a.maxConcurrency ?? this._threads, f = !!(Array.isArray(r) && r.length > 1 && a.partition), l = f ? this.partitionArray(r, i) : r, t = this.createWorkerPromises(
293
302
  a,
294
303
  e,
295
- { data: l, ...n },
296
- f,
297
- u
298
- ), o = await Promise.allSettled(r);
299
- return new b(o);
304
+ { data: l, ...o },
305
+ i,
306
+ f
307
+ ), s = await Promise.allSettled(t);
308
+ return new b(s);
300
309
  }
301
310
  /**
302
311
  * Builds the array of per-thread worker promises for a single `runWorker`
@@ -312,16 +321,17 @@ class B {
312
321
  * @param isPartitioned - Whether `data` is a pre-split array of shards.
313
322
  * @returns An array of promises, one per thread.
314
323
  */
315
- createWorkerPromises(e, t, n, a, f) {
316
- const { data: u, ...l } = n;
317
- return Array.from({ length: a }, (r, o) => {
318
- const i = f && Array.isArray(u) ? u[o] : u;
324
+ createWorkerPromises(e, r, o, a, i) {
325
+ const { data: f, ...l } = o;
326
+ return Array.from({ length: a }, (t, s) => {
327
+ const u = i && Array.isArray(f) ? f[s] : f;
319
328
  return this.runWorkerWithRetry(
320
329
  {
321
330
  workerFunc: e.func,
322
- workerName: t,
323
- index: o,
324
- data: { data: i, ...l }
331
+ workerURL: e.workerURL,
332
+ workerName: r,
333
+ index: s,
334
+ data: { data: u, ...l }
325
335
  },
326
336
  e.retries
327
337
  );
@@ -339,16 +349,16 @@ class B {
339
349
  * @returns The successful {@link WorkerResult} once the worker resolves.
340
350
  * @throws The last caught error when all retries are exhausted.
341
351
  */
342
- async runWorkerWithRetry(e, t = 2) {
352
+ async runWorkerWithRetry(e, r = 2) {
343
353
  try {
344
354
  return await this.initiateWorker(e);
345
- } catch (n) {
346
- if (t > 0)
355
+ } catch (o) {
356
+ if (r > 0)
347
357
  return console.error(
348
- `Worker ${e.index} failed, retrying (${t} left):`,
349
- n
350
- ), this.runWorkerWithRetry(e, t - 1);
351
- throw console.error("Worker failed after all retries:", n), n;
358
+ `Worker ${e.index} failed, retrying (${r} left):`,
359
+ o
360
+ ), this.runWorkerWithRetry(e, r - 1);
361
+ throw console.error("Worker failed after all retries:", o), o;
352
362
  }
353
363
  }
354
364
  /**
@@ -366,48 +376,54 @@ class B {
366
376
  * The underlying `Worker` is always terminated after the first message,
367
377
  * whether it succeeded or failed.
368
378
  *
369
- * @param instanceConfig - Worker function, name, shard index, and data.
379
+ * @param instanceConfig - Worker function, URL, name, shard index, and data.
370
380
  * @returns A promise that resolves with the worker's result.
371
381
  */
372
382
  initiateWorker({
373
383
  workerFunc: e,
374
- workerName: t,
375
- index: n,
376
- data: a
384
+ workerURL: r,
385
+ workerName: o,
386
+ index: a,
387
+ data: i
377
388
  }) {
378
- return new Promise((f, u) => {
379
- const r = this.initWorker(e).getWorker;
380
- r.onerror = (i) => {
381
- r.terminate(), u({
382
- index: n,
383
- workerConfigs: { workerFunc: e, workerName: t, index: n, data: a },
384
- failedResult: i
389
+ return new Promise((f, l) => {
390
+ const s = this.initWorker({
391
+ name: o,
392
+ role: "",
393
+ func: e,
394
+ workerURL: r
395
+ }).getWorker;
396
+ s.onerror = (c) => {
397
+ s.terminate(), l({
398
+ index: a,
399
+ workerConfigs: { workerFunc: e, workerName: o, index: a, data: i },
400
+ failedResult: c
385
401
  });
386
- }, r.onmessage = (i) => {
387
- var c, d;
388
- if (((c = i.data) == null ? void 0 : c.ok) === !1) {
389
- r.terminate(), u({
390
- index: n,
391
- workerConfigs: { workerFunc: e, workerName: t, index: n, data: a },
402
+ }, s.onmessage = (c) => {
403
+ var d, p;
404
+ if (((d = c.data) == null ? void 0 : d.ok) === !1) {
405
+ s.terminate(), l({
406
+ index: a,
407
+ workerConfigs: { workerFunc: e, workerName: o, index: a, data: i },
392
408
  failedResult: new ErrorEvent("error", {
393
- message: i.data.error
409
+ message: c.data.error
394
410
  })
395
411
  });
396
412
  return;
397
413
  }
398
414
  f({
399
- index: n,
400
- workerConfigs: { workerFunc: e, workerName: t, index: n, data: a },
415
+ index: a,
416
+ workerConfigs: { workerFunc: e, workerName: o, index: a, data: i },
401
417
  successResult: new MessageEvent("message", {
402
- data: (d = i.data) == null ? void 0 : d.data
418
+ data: (p = c.data) == null ? void 0 : p.data
403
419
  })
404
- }), r.terminate();
420
+ }), s.terminate();
405
421
  };
406
- const o = {
407
- index: n,
408
- ...Array.isArray(a) ? { data: a } : a
422
+ const u = {
423
+ index: a,
424
+ ...Array.isArray(i) ? { data: i } : i
409
425
  };
410
- r.postMessage(o, p(o));
426
+ s.postMessage(u, g(u));
411
427
  });
412
428
  }
413
429
  /**
@@ -442,16 +458,16 @@ class B {
442
458
  * reducer: (shards) => shards.flat().reduce((a, b) => a + b, 0),
443
459
  * });
444
460
  */
445
- async collectResults(e, t = {}) {
446
- const n = e.results.filter(
447
- (r) => r.status === "fulfilled"
461
+ async collectResults(e, r = {}) {
462
+ const o = e.results.filter(
463
+ (t) => t.status === "fulfilled"
448
464
  ), a = e.results.filter(
449
- (r) => r.status === "rejected"
450
- ), f = n.map((r) => r.value.successResult.data), u = t.reducer ? t.reducer.toString() : "(shards) => shards.flat()";
465
+ (t) => t.status === "rejected"
466
+ ), i = o.map((t) => t.value.successResult.data), f = r.reducer ? r.reducer.toString() : "(shards) => shards.flat()";
451
467
  return {
452
- data: await new Promise((r, o) => {
453
- const i = `
454
- const reducer = ${u};
468
+ data: await new Promise((t, s) => {
469
+ const u = `
470
+ const reducer = ${f};
455
471
  self.addEventListener('message', (event) => {
456
472
  try {
457
473
  const result = reducer(event.data);
@@ -460,14 +476,14 @@ class B {
460
476
  self.postMessage({ ok: false, error: String(err) });
461
477
  }
462
478
  });
463
- `, c = new Blob([i], { type: "application/javascript" }), d = new Worker(URL.createObjectURL(c));
464
- d.onmessage = (g) => {
465
- d.terminate(), g.data.ok ? r(g.data.data) : o(new Error(g.data.error));
466
- }, d.onerror = (g) => {
467
- d.terminate(), o(g);
468
- }, d.postMessage(f);
479
+ `, c = new Blob([u], { type: "application/javascript" }), d = new Worker(URL.createObjectURL(c));
480
+ d.onmessage = (p) => {
481
+ d.terminate(), p.data.ok ? t(p.data.data) : s(new Error(p.data.error));
482
+ }, d.onerror = (p) => {
483
+ d.terminate(), s(p);
484
+ }, d.postMessage(i);
469
485
  }),
470
- succeeded: n.length,
486
+ succeeded: o.length,
471
487
  failed: a.length,
472
488
  errors: a
473
489
  };
@@ -502,56 +518,57 @@ class B {
502
518
  if (e.length === 0)
503
519
  throw new Error("Pipeline requires at least one step");
504
520
  if (e.length === 1) {
505
- const t = e[0], n = this.findWorkerByName(t.worker);
506
- if (!n) throw new Error(`Worker "${t.worker}" not found`);
507
- const f = this.initWorker(n.func).getWorker;
508
- return new Promise((u, l) => {
509
- f.onmessage = (o) => {
510
- var i, c;
511
- f.terminate(), ((i = o.data) == null ? void 0 : i.ok) === !1 ? l(new Error(o.data.error)) : u((c = o.data) == null ? void 0 : c.data);
512
- }, f.onerror = (o) => {
513
- f.terminate(), l(o);
521
+ const r = e[0], o = this.findWorkerByName(r.worker);
522
+ if (!o) throw new Error(`Worker "${r.worker}" not found`);
523
+ const i = this.initWorker(o).getWorker;
524
+ return new Promise((f, l) => {
525
+ i.onmessage = (s) => {
526
+ var u, c;
527
+ i.terminate(), ((u = s.data) == null ? void 0 : u.ok) === !1 ? l(new Error(s.data.error)) : f((c = s.data) == null ? void 0 : c.data);
528
+ }, i.onerror = (s) => {
529
+ i.terminate(), l(s);
514
530
  };
515
- const r = t.srcData ?? {};
516
- f.postMessage(
517
- { data: r, index: 0 },
518
- p(r)
531
+ const t = r.srcData ?? {};
532
+ i.postMessage(
533
+ { data: t, index: 0 },
534
+ g(t)
519
535
  );
520
536
  });
521
537
  }
522
- return new Promise((t, n) => {
523
- const a = [], f = [];
524
- for (const r of e) {
525
- const o = this.findWorkerByName(r.worker);
526
- if (!o) {
527
- n(new Error(`Worker "${r.worker}" not found`));
538
+ return new Promise((r, o) => {
539
+ const a = [], i = [];
540
+ for (const t of e) {
541
+ const s = this.findWorkerByName(t.worker);
542
+ if (!s) {
543
+ o(new Error(`Worker "${t.worker}" not found`));
528
544
  return;
529
545
  }
530
- const i = new k(o.func, {
531
- mode: v.Pipeline
546
+ const u = new k(s.func, {
547
+ mode: w.Pipeline,
548
+ workerURL: s.workerURL
532
549
  });
533
- a.push(i.getWorker);
550
+ a.push(u.getWorker);
534
551
  }
535
- for (let r = 0; r < a.length - 1; r++)
536
- f.push(new MessageChannel());
537
- for (let r = 0; r < a.length; r++) {
538
- const o = [], i = {};
539
- r > 0 && (i.inputPort = f[r - 1].port1, o.push(i.inputPort)), r < a.length - 1 && (i.outputPort = f[r].port2, o.push(i.outputPort)), a[r].postMessage(
540
- { __pipeline_ports__: !0, ...i },
541
- o
552
+ for (let t = 0; t < a.length - 1; t++)
553
+ i.push(new MessageChannel());
554
+ for (let t = 0; t < a.length; t++) {
555
+ const s = [], u = {};
556
+ t > 0 && (u.inputPort = i[t - 1].port1, s.push(u.inputPort)), t < a.length - 1 && (u.outputPort = i[t].port2, s.push(u.outputPort)), a[t].postMessage(
557
+ { __pipeline_ports__: !0, ...u },
558
+ s
542
559
  );
543
560
  }
544
- const u = a[a.length - 1];
545
- u.onmessage = (r) => {
546
- var o, i;
547
- a.forEach((c) => c.terminate()), ((o = r.data) == null ? void 0 : o.ok) === !1 ? n(new Error(r.data.error)) : t((i = r.data) == null ? void 0 : i.data);
548
- }, u.onerror = (r) => {
549
- a.forEach((o) => o.terminate()), n(r);
561
+ const f = a[a.length - 1];
562
+ f.onmessage = (t) => {
563
+ var s, u;
564
+ a.forEach((c) => c.terminate()), ((s = t.data) == null ? void 0 : s.ok) === !1 ? o(new Error(t.data.error)) : r((u = t.data) == null ? void 0 : u.data);
565
+ }, f.onerror = (t) => {
566
+ a.forEach((s) => s.terminate()), o(t);
550
567
  };
551
568
  const l = e[0].srcData ?? {};
552
569
  a[0].postMessage(
553
570
  { data: l, index: 0 },
554
- p(l)
571
+ g(l)
555
572
  );
556
573
  });
557
574
  }
@@ -589,24 +606,25 @@ class B {
589
606
  * // Release when done
590
607
  * factory.release('transform');
591
608
  */
592
- async runPersistent(e, t) {
593
- const n = this.findWorkerByName(e);
594
- if (!n) throw new Error(`Worker "${e}" not found`);
609
+ async runPersistent(e, r) {
610
+ const o = this.findWorkerByName(e);
611
+ if (!o) throw new Error(`Worker "${e}" not found`);
595
612
  let a = this._persistentWorkers.get(e);
596
- return a || (a = new k(n.func, {
597
- mode: v.Persistent
598
- }).getWorker, this._persistentWorkers.set(e, a)), new Promise((f, u) => {
599
- a.onmessage = (r) => {
600
- var o, i;
601
- ((o = r.data) == null ? void 0 : o.ok) === !1 ? u(new Error(r.data.error)) : f((i = r.data) == null ? void 0 : i.data);
602
- }, a.onerror = (r) => {
603
- u(r);
613
+ return a || (a = new k(o.func, {
614
+ mode: w.Persistent,
615
+ workerURL: o.workerURL
616
+ }).getWorker, this._persistentWorkers.set(e, a)), new Promise((i, f) => {
617
+ a.onmessage = (t) => {
618
+ var s, u;
619
+ ((s = t.data) == null ? void 0 : s.ok) === !1 ? f(new Error(t.data.error)) : i((u = t.data) == null ? void 0 : u.data);
620
+ }, a.onerror = (t) => {
621
+ f(t);
604
622
  };
605
623
  const l = {
606
624
  type: "run",
607
- config: t.config
625
+ config: r.config
608
626
  };
609
- t.dataset !== void 0 && (l.dataset = t.dataset), a.postMessage(l, p(l));
627
+ r.dataset !== void 0 && (l.dataset = r.dataset), a.postMessage(l, g(l));
610
628
  });
611
629
  }
612
630
  /**
@@ -619,11 +637,11 @@ class B {
619
637
  * @param workerName - Name of the persistent worker to release.
620
638
  */
621
639
  release(e) {
622
- const t = this._persistentWorkers.get(e);
623
- t && (t.postMessage({ type: "release" }), t.terminate(), this._persistentWorkers.delete(e));
640
+ const r = this._persistentWorkers.get(e);
641
+ r && (r.postMessage({ type: "release" }), r.terminate(), this._persistentWorkers.delete(e));
624
642
  }
625
643
  }
626
644
  export {
627
- B as MainWorkerFactory,
645
+ A as MainWorkerFactory,
628
646
  k as WorkerFactory
629
647
  };
@@ -45,9 +45,9 @@ declare class MainWorkerFactory<TConfigs extends readonly WorkerConfig<WorkerFun
45
45
  workers: TConfigs;
46
46
  });
47
47
  /**
48
- * Instantiates a {@link WorkerFactory} for the given worker function.
48
+ * Instantiates a {@link WorkerFactory} for the given worker configuration.
49
49
  *
50
- * @param workerFunction - The function to run inside the worker thread.
50
+ * @param config - The worker configuration containing `func` or `workerURL`.
51
51
  * @returns A new `WorkerFactory` wrapping the worker.
52
52
  */
53
53
  private initWorker;
@@ -147,7 +147,7 @@ declare class MainWorkerFactory<TConfigs extends readonly WorkerConfig<WorkerFun
147
147
  * The underlying `Worker` is always terminated after the first message,
148
148
  * whether it succeeded or failed.
149
149
  *
150
- * @param instanceConfig - Worker function, name, shard index, and data.
150
+ * @param instanceConfig - Worker function, URL, name, shard index, and data.
151
151
  * @returns A promise that resolves with the worker's result.
152
152
  */
153
153
  private initiateWorker;
@@ -23,8 +23,13 @@ export interface WorkerConfig<TFunc extends WorkerFunction = WorkerFunction> {
23
23
  name: WorkerName;
24
24
  /** Human-readable role label (e.g. `'compute'`, `'transform'`). */
25
25
  role: WorkerRole;
26
- /** The worker function that will be serialised and run in a thread. */
27
- func: TFunc;
26
+ /** The worker function that will be serialised and run in a thread. Optional if `workerURL` is provided. */
27
+ func?: TFunc;
28
+ /**
29
+ * The worker script URL (or `URL` object created via `new URL(..., import.meta.url)`).
30
+ * Enables module bundlers like Webpack 5, Vite, Rollup, and Parcel to bundle worker code and its dependencies.
31
+ */
32
+ workerURL?: string | URL;
28
33
  /**
29
34
  * Maximum number of parallel threads to spawn for this worker.
30
35
  * Defaults to `navigator.hardwareConcurrency` when omitted.
@@ -41,6 +46,11 @@ export interface WorkerConfig<TFunc extends WorkerFunction = WorkerFunction> {
41
46
  * array.
42
47
  */
43
48
  partition?: boolean;
49
+ /**
50
+ * A list of worker functions that must complete before this worker can start.
51
+ * If any dependency fails, this worker will not run.
52
+ */
53
+ dependencies?: Array<() => void>;
44
54
  }
45
55
  /**
46
56
  * Derives a `name → function` map from a readonly tuple of
@@ -52,9 +62,11 @@ export interface WorkerConfig<TFunc extends WorkerFunction = WorkerFunction> {
52
62
  * @typeParam T - The readonly tuple of `WorkerConfig` values.
53
63
  */
54
64
  export type WorkerConfigMap<T extends readonly WorkerConfig<WorkerFunction<any, any>>[]> = {
55
- [K in T[number]['name']]: Extract<T[number], {
65
+ [K in T[number]['name']]: NonNullable<Extract<T[number], {
66
+ name: K;
67
+ }>['func']> extends WorkerFunction ? NonNullable<Extract<T[number], {
56
68
  name: K;
57
- }>['func'];
69
+ }>['func']> : WorkerFunction;
58
70
  };
59
71
  /**
60
72
  * Extracts the `params` type from a {@link WorkerFunction}.
@@ -91,8 +103,10 @@ export interface MainWorkerFactoryWorker extends WorkerConfig {
91
103
  export interface WorkerInstanceConfig<TFunc extends WorkerFunction = WorkerFunction> {
92
104
  /** Name of the parent worker config, used in logs and error objects. */
93
105
  workerName: WorkerName;
94
- /** The function serialised and executed inside the thread. */
95
- workerFunc: TFunc;
106
+ /** The function serialised and executed inside the thread (optional if `workerURL` is set). */
107
+ workerFunc?: TFunc;
108
+ /** Worker script URL (string or URL object). */
109
+ workerURL?: string | URL;
96
110
  /** Zero-based shard index assigned to this thread. */
97
111
  index: number;
98
112
  /** The data payload (full or partitioned shard) sent to the thread. */
@@ -7,9 +7,11 @@ export declare enum WorkerMode {
7
7
  export interface WorkerFactoryOptions {
8
8
  /** The worker execution mode. Defaults to `WorkerMode.Default`. */
9
9
  mode?: WorkerMode;
10
+ /** The worker URL to use instead of creating a worker from a function. */
11
+ workerURL?: string | URL;
10
12
  }
11
13
  /**
12
- * Low-level factory that serialises a {@link WorkerFunction} into a Blob URL
14
+ * Low-level factory that serializes a {@link WorkerFunction} into a Blob URL
13
15
  * and spawns a native `Worker` from it.
14
16
  *
15
17
  * `WorkerFactory` is an internal building block used by `MainWorkerFactory`.
@@ -39,11 +41,11 @@ declare class WorkerFactory {
39
41
  *
40
42
  * @param workerFunction - The function to run inside the worker thread.
41
43
  * Must be self-contained — it cannot reference variables from the outer
42
- * scope because it is serialised via `.toString()`.
44
+ * scope because it is serialized via `.toString()`.
43
45
  * @param options - Optional configuration. Set `mode` to control the
44
46
  * worker execution mode (default, pipeline, or persistent).
45
47
  */
46
- constructor(workerFunction: WorkerFunction, options?: WorkerFactoryOptions);
48
+ constructor(workerFunction?: WorkerFunction, options?: WorkerFactoryOptions);
47
49
  /**
48
50
  * Returns the underlying native `Worker` instance.
49
51
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@offmain/workerkit",
3
- "version": "0.11.0",
3
+ "version": "0.12.2",
4
4
  "description": "A lightweight manager for running functions in Web Workers with partitioning, retries, and concurrency control",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -76,6 +76,9 @@
76
76
  "typescript": "^5.7.2",
77
77
  "vite": "^6.3.3",
78
78
  "vite-plugin-dts": "^4.5.4",
79
- "vitest": "^1.0.0"
79
+ "vitest": "^1.0.0",
80
+ "luxon": "^3.7.2",
81
+ "i18next": "^25.5.1",
82
+ "@types/luxon": "^3.7.2"
80
83
  }
81
84
  }