@atolljs/core 0.1.7 → 0.1.9

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 (59) hide show
  1. package/README.md +1 -1
  2. package/dist/contract/memoryDevtools.d.ts +30 -0
  3. package/dist/contract/sharedMemory.d.ts +4 -2
  4. package/dist/contract/types.d.ts +11 -0
  5. package/dist/devtools.d.ts +127 -4
  6. package/dist/index.d.ts +8 -4
  7. package/dist/index.js +19 -17
  8. package/dist/index10.js +29 -14
  9. package/dist/index11.js +14 -307
  10. package/dist/index12.js +29 -50
  11. package/dist/index13.js +46 -60
  12. package/dist/index14.js +56 -22
  13. package/dist/index15.js +332 -55
  14. package/dist/index16.js +246 -45
  15. package/dist/index17.js +56 -51
  16. package/dist/index18.js +9 -39
  17. package/dist/index19.js +56 -80
  18. package/dist/index20.js +24 -53
  19. package/dist/index21.js +56 -52
  20. package/dist/index22.js +48 -0
  21. package/dist/index23.js +68 -0
  22. package/dist/index24.js +41 -0
  23. package/dist/index25.js +46 -0
  24. package/dist/index26.js +113 -0
  25. package/dist/index27.js +60 -0
  26. package/dist/index28.js +57 -0
  27. package/dist/index5.js +135 -64
  28. package/dist/index6.js +160 -35
  29. package/dist/index7.js +45 -503
  30. package/dist/index8.js +513 -19
  31. package/dist/index9.js +19 -33
  32. package/dist/pool/dedicatedWorker.d.ts +63 -0
  33. package/dist/pool/devtoolsCommands.d.ts +54 -0
  34. package/dist/pool/subWorkerClient.d.ts +50 -0
  35. package/dist/pool/workerChannel.d.ts +44 -0
  36. package/dist/pool/workerClient.d.ts +36 -8
  37. package/dist/pool/workerPool.d.ts +10 -1
  38. package/dist/reactive.d.ts +15 -0
  39. package/dist/reactiveGraph.d.ts +9 -0
  40. package/dist/userTiming.d.ts +27 -0
  41. package/package.json +4 -3
  42. package/src/contract/memoryDevtools.ts +249 -0
  43. package/src/contract/sharedMemory.ts +20 -6
  44. package/src/contract/types.ts +11 -0
  45. package/src/devtools.ts +251 -6
  46. package/src/index.ts +13 -1
  47. package/src/log.ts +22 -0
  48. package/src/observable.ts +16 -3
  49. package/src/pool/dedicatedWorker.ts +332 -0
  50. package/src/pool/devtoolsCommands.ts +165 -0
  51. package/src/pool/subWorkerClient.ts +70 -0
  52. package/src/pool/workerChannel.ts +99 -0
  53. package/src/pool/workerClient.ts +61 -15
  54. package/src/pool/workerPool.ts +75 -45
  55. package/src/reactive.ts +87 -12
  56. package/src/reactiveGraph.ts +91 -0
  57. package/src/testing/inProcessWorker.ts +4 -3
  58. package/src/userTiming.ts +71 -0
  59. package/src/worker/workerBootstrap.ts +33 -5
package/dist/index11.js CHANGED
@@ -1,313 +1,20 @@
1
- import { devtoolsEnabled as e, emitDevtools as t, forwardDevtools as n, nextDevtoolsId as r } from "./index5.js";
2
- import { fmtBytes as i, scoped as a } from "./index6.js";
3
- import { MemoryManager as o } from "./index9.js";
4
- import { PoolQueueFullError as s, TaskAbortedError as c, TaskTimeoutError as l, WorkerCrashedError as u } from "./index10.js";
5
- //#region src/pool/workerPool.ts
6
- var d = a("pool"), f = a("task"), p = () => ({
7
- count: 0,
8
- mean: 0,
9
- max: 0,
10
- add(e) {
11
- this.count++, this.mean += (e - this.mean) / this.count, e > this.max && (this.max = e);
1
+ //#region src/pool/errors.ts
2
+ var e = class extends Error {
3
+ constructor(e = "WorkerPool task queue is full") {
4
+ super(e), this.name = "PoolQueueFullError";
12
5
  }
13
- }), m = class {
14
- slots = [];
15
- pending = /* @__PURE__ */ new Map();
16
- nextMessageId = 0;
17
- queue = [];
18
- memoryManager;
19
- workerUrl;
20
- spawn;
21
- concurrency;
22
- maxQueue;
23
- respawn;
24
- taskTimeout;
25
- closed = !1;
26
- drainWaiters = [];
27
- statsAgg = {
28
- completed: 0,
29
- failed: 0,
30
- aborted: 0,
31
- waitMs: p(),
32
- runMs: p()
33
- };
34
- poolId = r("pool");
35
- label;
36
- nextCallId = 0;
37
- sharedMemory;
38
- persistence;
39
- constructor(e) {
40
- if (e.sharedMemory && (typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated)) throw Error("WorkerPool requires SharedArrayBuffer in a cross-origin isolated context — serve the page with COOP/COEP headers.");
41
- if (!e.workerUrl && !e.createWorker) throw Error("WorkerPool requires either `workerUrl` or `createWorker` in its config.");
42
- this.workerUrl = e.workerUrl, this.spawn = e.createWorker ?? (() => new Worker(this.workerUrl, { type: "module" })), this.concurrency = e.concurrency ?? 1, this.maxQueue = e.maxQueue ?? Infinity, this.respawn = e.respawn ?? !0, this.taskTimeout = e.taskTimeout, this.label = e.name, e.sharedMemory && (this.sharedMemory = e.sharedMemory, this.memoryManager = new o(e.memory), this.memoryManager.ensureCapacity(this.sharedMemory.totalBytes), this.sharedMemory.bind(this.memoryManager.getBuffer()), this.persistence = e.persistence?.(e.sharedMemory));
43
- let n = e.poolSize ?? "auto", r = n === "auto" ? navigator.hardwareConcurrency ?? 4 : n;
44
- d.info(this.sharedMemory ? `spawning ${r} worker(s) with ${i(this.sharedMemory.totalBytes)} shared buffer` : `spawning ${r} worker(s), message-only`, { workerUrl: e.workerUrl ? String(e.workerUrl) : "createWorker()" }), d.debug("tip: setLogLevel('trace') for per-task detail"), t({
45
- type: "pool:init",
46
- poolId: this.poolId,
47
- label: this.label,
48
- poolSize: r,
49
- concurrency: this.concurrency,
50
- memoryBytes: this.sharedMemory?.totalBytes
51
- });
52
- for (let e = 0; e < r; e++) this.addWorker(this.spawn());
53
- let a = e.tasks ?? {};
54
- for (let [e, t] of Object.entries(a)) {
55
- if (e in this) {
56
- d.warn(`task "${e}" collides with a WorkerPool member — not installed`);
57
- continue;
58
- }
59
- this[e] = (...e) => this.runTask(t, ...e);
60
- }
61
- Object.keys(a).length > 0 && d.info(`task methods: ${Object.keys(a).join(", ")}`);
6
+ }, t = class extends Error {
7
+ constructor(e = "task aborted") {
8
+ super(e), this.name = "AbortError";
62
9
  }
63
- addWorker(r) {
64
- let i = {
65
- worker: r,
66
- inFlight: 0
67
- };
68
- return r.addEventListener("message", (e) => {
69
- let t = e.data;
70
- if (t.type === "ATOLL_DEVTOOLS" && t.event) {
71
- n({
72
- ...t.event,
73
- worker: {
74
- poolId: this.poolId,
75
- slot: this.slots.indexOf(i)
76
- }
77
- });
78
- return;
79
- }
80
- this.handleReply(i, t);
81
- }), r.addEventListener("error", (e) => {
82
- this.handleWorkerError(i, e);
83
- }), this.memoryManager ? r.postMessage({
84
- type: "INIT_MEMORY",
85
- memory: this.memoryManager.memory,
86
- devtools: e()
87
- }) : r.postMessage({
88
- type: "INIT",
89
- devtools: e()
90
- }), this.slots.push(i), d.debug(`worker spawned, ${this.memoryManager ? "INIT_MEMORY" : "INIT"} sent`), t({
91
- type: "worker:spawn",
92
- poolId: this.poolId,
93
- slot: this.slots.indexOf(i)
94
- }), i;
10
+ }, n = class extends Error {
11
+ constructor(e = "task timed out") {
12
+ super(e), this.name = "TaskTimeoutError";
95
13
  }
96
- handleReply(e, n) {
97
- let r = n.messageId === void 0 ? void 0 : this.pending.get(n.messageId);
98
- if (r) {
99
- if (this.pending.delete(n.messageId), e.inFlight--, this.detach(r), !r.done) {
100
- r.done = !0;
101
- let e = performance.now() - (r.sentAt ?? r.enqueuedAt);
102
- this.statsAgg.runMs.add(e), n.success ? (this.statsAgg.completed++, f.debug(`← ${r.contract.taskId} ok`), t({
103
- type: "task:settle",
104
- poolId: this.poolId,
105
- callId: r.callId,
106
- taskId: r.contract.taskId,
107
- outcome: "ok",
108
- runMs: e
109
- }), r.resolve(n.result)) : (this.statsAgg.failed++, f.warn(`← ${r.contract.taskId} failed: ${n.error}`), t({
110
- type: "task:settle",
111
- poolId: this.poolId,
112
- callId: r.callId,
113
- taskId: r.contract.taskId,
114
- outcome: "error",
115
- runMs: e,
116
- error: n.error
117
- }), r.reject(Error(n.error)));
118
- }
119
- this.drainQueue(), this.checkDrained();
120
- }
121
- }
122
- handleWorkerError(e, n) {
123
- if (this.closed) return;
124
- let r = n, i = r?.message ?? (r?.error ? String(r.error) : "worker error");
125
- d.warn(`worker error: ${i}`);
126
- let a = this.slots.indexOf(e);
127
- t({
128
- type: "worker:error",
129
- poolId: this.poolId,
130
- slot: a,
131
- message: i
132
- });
133
- for (let [n, r] of [...this.pending]) if (r.slot === e) {
134
- if (this.pending.delete(n), this.detach(r), r.done) continue;
135
- r.done = !0, this.statsAgg.failed++, t({
136
- type: "task:settle",
137
- poolId: this.poolId,
138
- callId: r.callId,
139
- taskId: r.contract.taskId,
140
- outcome: "crashed",
141
- error: i
142
- }), r.reject(new u(i));
143
- }
144
- if (a >= 0 && this.slots.splice(a, 1), e.worker.terminate(), this.respawn) d.info("respawning crashed worker"), this.addWorker(this.spawn()), t({
145
- type: "worker:respawn",
146
- poolId: this.poolId,
147
- slot: this.slots.length - 1
148
- });
149
- else if (this.slots.length === 0) for (let e of this.queue.splice(0)) e.done = !0, this.detach(e), this.statsAgg.failed++, t({
150
- type: "task:settle",
151
- poolId: this.poolId,
152
- callId: e.callId,
153
- taskId: e.contract.taskId,
154
- outcome: "crashed",
155
- error: i
156
- }), e.reject(new u(i));
157
- this.drainQueue(), this.checkDrained();
158
- }
159
- pickWorker() {
160
- let e;
161
- for (let t of this.slots) t.inFlight >= this.concurrency || (!e || t.inFlight < e.inFlight) && (e = t);
162
- return e;
163
- }
164
- drainQueue() {
165
- let e;
166
- for (; this.queue.length > 0 && (e = this.pickWorker());) {
167
- let t = this.queue.shift();
168
- t.done || this.send(e, t);
169
- }
170
- }
171
- send(e, n) {
172
- let r = this.nextMessageId++;
173
- n.messageId = r, n.slot = e, n.sentAt = performance.now();
174
- let i = n.sentAt - n.enqueuedAt;
175
- this.statsAgg.waitMs.add(i), e.inFlight++, this.pending.set(r, n);
176
- let a = this.slots.indexOf(e);
177
- f.debug(`→ ${n.contract.taskId}`, {
178
- worker: a,
179
- args: n.args
180
- }), t({
181
- type: "task:dispatch",
182
- poolId: this.poolId,
183
- callId: n.callId,
184
- taskId: n.contract.taskId,
185
- slot: a,
186
- waitMs: i
187
- }), e.worker.postMessage({
188
- type: "EXECUTE_TASK",
189
- messageId: r,
190
- taskId: n.contract.taskId,
191
- args: n.args
192
- });
193
- }
194
- detach(e) {
195
- e.timer && clearTimeout(e.timer), e.signal && e.onSignalAbort && e.signal.removeEventListener("abort", e.onSignalAbort);
196
- }
197
- cancel(e, n) {
198
- if (e.done) return;
199
- let r = this.queue.indexOf(e);
200
- r >= 0 && this.queue.splice(r, 1), e.done = !0, this.detach(e), this.statsAgg.aborted++, t({
201
- type: "task:settle",
202
- poolId: this.poolId,
203
- callId: e.callId,
204
- taskId: e.contract.taskId,
205
- outcome: n instanceof l ? "timeout" : "aborted"
206
- }), e.reject(n), this.drainQueue(), this.checkDrained();
207
- }
208
- checkDrained() {
209
- if (this.queue.length === 0 && this.pending.size === 0) {
210
- let e = this.drainWaiters.splice(0);
211
- for (let t of e) t();
212
- }
213
- }
214
- dispatch(e, n, r) {
215
- return this.closed || this.slots.length === 0 ? Promise.reject(new u("WorkerPool has been terminated — no workers available.")) : r?.signal?.aborted ? Promise.reject(new c()) : new Promise((i, a) => {
216
- let o = {
217
- contract: e,
218
- args: n,
219
- callId: ++this.nextCallId,
220
- enqueuedAt: performance.now(),
221
- resolve: i,
222
- reject: a,
223
- done: !1,
224
- signal: r?.signal
225
- };
226
- r?.signal && (o.onSignalAbort = () => this.cancel(o, new c()), r.signal.addEventListener("abort", o.onSignalAbort, { once: !0 }));
227
- let u = r?.timeout ?? this.taskTimeout;
228
- u !== void 0 && (o.timer = setTimeout(() => this.cancel(o, new l()), u)), t({
229
- type: "task:enqueue",
230
- poolId: this.poolId,
231
- callId: o.callId,
232
- taskId: e.taskId
233
- });
234
- let d = this.pickWorker();
235
- if (d) this.send(d, o);
236
- else if (this.queue.length >= this.maxQueue) {
237
- o.done = !0, this.detach(o), t({
238
- type: "task:settle",
239
- poolId: this.poolId,
240
- callId: o.callId,
241
- taskId: e.taskId,
242
- outcome: "queue-full"
243
- }), a(new s());
244
- return;
245
- } else this.queue.push(o);
246
- });
247
- }
248
- runTask(e, ...t) {
249
- return this.dispatch(e, t);
250
- }
251
- get sharedBuffer() {
252
- return this.memoryManager?.getBuffer();
253
- }
254
- get workers() {
255
- return this.slots.map((e) => e.worker);
256
- }
257
- stats() {
258
- return {
259
- workers: this.slots.length,
260
- idle: this.slots.filter((e) => e.inFlight === 0).length,
261
- inFlight: this.pending.size,
262
- queued: this.queue.length,
263
- completed: this.statsAgg.completed,
264
- failed: this.statsAgg.failed,
265
- aborted: this.statsAgg.aborted,
266
- waitMs: {
267
- count: this.statsAgg.waitMs.count,
268
- mean: this.statsAgg.waitMs.mean,
269
- max: this.statsAgg.waitMs.max
270
- },
271
- runMs: {
272
- count: this.statsAgg.runMs.count,
273
- mean: this.statsAgg.runMs.mean,
274
- max: this.statsAgg.runMs.max
275
- }
276
- };
277
- }
278
- close() {
279
- return this.queue.length === 0 && this.pending.size === 0 ? (this.terminate(), Promise.resolve()) : new Promise((e) => {
280
- this.drainWaiters.push(() => {
281
- this.terminate(), e();
282
- });
283
- });
284
- }
285
- terminate() {
286
- this.closed = !0, this.persistence?.stop()?.catch?.((e) => d.warn("memory persistence stop failed", e)), d.info(`terminating ${this.slots.length} worker(s)`), t({
287
- type: "pool:terminate",
288
- poolId: this.poolId
289
- });
290
- let e = new u("pool terminated");
291
- for (let [, n] of this.pending) this.detach(n), !n.done && (n.done = !0, this.statsAgg.failed++, t({
292
- type: "task:settle",
293
- poolId: this.poolId,
294
- callId: n.callId,
295
- taskId: n.contract.taskId,
296
- outcome: "crashed",
297
- error: "pool terminated"
298
- }), n.reject(e));
299
- this.pending.clear();
300
- for (let n of this.queue.splice(0)) n.done = !0, this.detach(n), this.statsAgg.failed++, t({
301
- type: "task:settle",
302
- poolId: this.poolId,
303
- callId: n.callId,
304
- taskId: n.contract.taskId,
305
- outcome: "crashed",
306
- error: "pool terminated"
307
- }), n.reject(e);
308
- for (let e of this.slots) e.worker.terminate();
309
- this.slots = [], this.checkDrained();
14
+ }, r = class extends Error {
15
+ constructor(e = "worker crashed") {
16
+ super(e), this.name = "WorkerCrashedError";
310
17
  }
311
18
  };
312
19
  //#endregion
313
- export { m as WorkerPool };
20
+ export { e as PoolQueueFullError, t as TaskAbortedError, n as TaskTimeoutError, r as WorkerCrashedError };
package/dist/index12.js CHANGED
@@ -1,51 +1,30 @@
1
- import { WorkerPool as e } from "./index11.js";
2
- //#region src/pool/workerClient.ts
3
- var t = (e, n, r, i) => {
4
- let a = /* @__PURE__ */ new Map();
5
- return new Proxy(() => {}, {
6
- get(o, s) {
7
- if (s === "then" || typeof s == "symbol") return;
8
- if (s === "with") return (i) => t(e, n, r, i);
9
- if (e.length === 0 && r && s in r) return Reflect.get(r, s);
10
- let c = a.get(s);
11
- return c || (c = t([...e, s], n, r, i), a.set(s, c)), c;
12
- },
13
- apply(t, r, a) {
14
- let o = n(), s = { taskId: e.join(".") };
15
- return o.dispatch ? o.dispatch(s, a, i) : o.runTask(s, ...a);
16
- }
17
- });
18
- };
19
- function n(e) {
20
- let n;
21
- return t([], typeof e == "function" ? () => n ??= e() : () => e);
22
- }
23
- function r(n) {
24
- let r = null, i = () => r ??= new e({
25
- sharedMemory: n.sharedMemory,
26
- createWorker: typeof n.worker == "function" ? n.worker : () => new Worker(n.worker, { type: "module" }),
27
- poolSize: n.poolSize,
28
- name: n.name,
29
- memory: n.memory,
30
- concurrency: n.concurrency,
31
- maxQueue: n.maxQueue,
32
- respawn: n.respawn,
33
- taskTimeout: n.taskTimeout
34
- });
35
- return n.lazy === !1 && i(), t([], i, {
36
- start: () => {
37
- i();
38
- },
39
- terminate: () => {
40
- r?.terminate(), r = null;
41
- },
42
- get pool() {
43
- return r;
44
- },
45
- get sharedMemory() {
46
- return n.sharedMemory;
47
- }
48
- });
49
- }
1
+ //#region src/userTiming.ts
2
+ var e = (e, t, n, r) => {
3
+ let i = globalThis.performance;
4
+ if (typeof i?.measure == "function") try {
5
+ i.measure(e, {
6
+ start: t,
7
+ end: Math.max(n, t),
8
+ detail: { devtools: {
9
+ dataType: "track-entry",
10
+ track: r.track,
11
+ trackGroup: "atoll",
12
+ color: r.color ?? "primary",
13
+ properties: r.properties,
14
+ tooltipText: r.tooltipText
15
+ } }
16
+ }), i.clearMeasures?.(e);
17
+ } catch {}
18
+ }, t = (t, n, r, i, a, o, s) => e(`atoll task ${n}`, a, o, {
19
+ track: t,
20
+ color: s ? "primary" : "error",
21
+ properties: [
22
+ ["runner", t],
23
+ ["slot", i],
24
+ ["call", r],
25
+ ["outcome", s ? "ok" : "error"]
26
+ ],
27
+ tooltipText: `${n} on ${t}#${i}: ${(o - a).toFixed(1)}ms`
28
+ });
50
29
  //#endregion
51
- export { r as connectWorker, n as workerClient };
30
+ export { e as measureAtoll, t as measureTaskCall };
package/dist/index13.js CHANGED
@@ -1,64 +1,50 @@
1
- import { scoped as e } from "./index6.js";
2
- //#region src/shared/sharedWorkerClient.ts
3
- var t = e("shared-client"), n = e("task"), r = class {
4
- clientIndex;
5
- sharedMemory;
6
- port;
7
- constructor(e, n, r) {
8
- this.clientIndex = n, this.port = e, this.sharedMemory = r.sharedMemory;
9
- let i = r.tasks ?? {};
10
- for (let [e, n] of Object.entries(i)) {
11
- if (e in this) {
12
- t.warn(`task "${e}" collides with a SharedWorkerClient member — not installed`);
13
- continue;
14
- }
15
- this[e] = (...e) => this.runTask(n, ...e);
16
- }
17
- Object.keys(i).length > 0 && t.info(`task methods: ${Object.keys(i).join(", ")}`);
18
- }
19
- runTask(e, ...t) {
20
- return new Promise((r, i) => {
21
- let a = Math.random().toString(36).substring(2), o = performance.now();
22
- n.debug(`→ ${e.taskId}`, { args: t });
23
- let s = (t) => {
24
- let c = t.data;
25
- if (c.messageId === a) {
26
- this.port.removeEventListener("message", s);
27
- let t = (performance.now() - o).toFixed(1);
28
- c.success ? (n.debug(`← ${e.taskId} ok`, { ms: +t }), r(c.result)) : (n.warn(`← ${e.taskId} failed: ${c.error}`, { ms: +t }), i(Error(c.error)));
29
- }
30
- };
31
- this.port.addEventListener("message", s), this.port.postMessage({
32
- type: "EXECUTE_TASK",
33
- messageId: a,
34
- taskId: e.taskId,
35
- args: t
36
- });
37
- });
38
- }
39
- disconnect() {
40
- try {
41
- this.port.postMessage({ type: "SHARED_DISCONNECT" });
42
- } finally {
43
- this.port.close();
1
+ import { devtoolsEnabled as e, forwardDevtools as t } from "./index5.js";
2
+ import { MemoryManager as n } from "./index10.js";
3
+ //#region src/pool/workerChannel.ts
4
+ function r(e, t) {
5
+ if ((e.sharedMemory || e.sharedBuffer !== void 0) && (typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated)) throw Error(`${t} requires SharedArrayBuffer in a cross-origin isolated context — serve the page with COOP/COEP headers.`);
6
+ let r;
7
+ if (e.sharedBuffer !== void 0 && (r = typeof e.sharedBuffer == "function" ? e.sharedBuffer() : e.sharedBuffer, !r)) throw Error(`${t}: \`sharedBuffer\` resolved to an empty buffer — the producing pool or contract has no bound memory yet.`);
8
+ if (!e.sharedMemory) return {
9
+ sharedMemory: void 0,
10
+ injectedBuffer: r,
11
+ persistence: void 0
12
+ };
13
+ let i = e.sharedMemory, a;
14
+ return r ? i.bind(r) : (a = new n(e.memory), a.ensureCapacity(i.totalBytes), i.bind(a.getBuffer())), {
15
+ sharedMemory: i,
16
+ memoryManager: a,
17
+ injectedBuffer: r,
18
+ persistence: e.persistence?.(i)
19
+ };
20
+ }
21
+ function i(t, n) {
22
+ return n.memoryManager ? (t.postMessage({
23
+ type: "INIT_MEMORY",
24
+ memory: n.memoryManager.memory,
25
+ devtools: e()
26
+ }), "INIT_MEMORY") : n.injectedBuffer ? (t.postMessage({
27
+ type: "INIT_MEMORY",
28
+ buffer: n.injectedBuffer,
29
+ devtools: e()
30
+ }), "INIT_MEMORY") : (t.postMessage({
31
+ type: "INIT",
32
+ devtools: e()
33
+ }), "INIT");
34
+ }
35
+ function a(e, n, r) {
36
+ let i = (t) => `${e}#${n}~${t}`;
37
+ t({
38
+ ...r,
39
+ ...r.poolId === void 0 ? {} : { poolId: i(r.poolId) },
40
+ worker: r.worker === void 0 ? {
41
+ poolId: e,
42
+ slot: n
43
+ } : {
44
+ poolId: i(r.worker.poolId),
45
+ slot: r.worker.slot
44
46
  }
45
- }
46
- };
47
- async function i(e) {
48
- if (typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated) throw Error("connectSharedWorker requires SharedArrayBuffer in a cross-origin isolated context — serve the page with COOP/COEP headers.");
49
- if (!e.port && !e.workerUrl && !e.createWorker) throw Error("connectSharedWorker requires `workerUrl`, `createWorker`, or `port` in its config.");
50
- let n = e.port ?? (e.createWorker ? e.createWorker().port : new SharedWorker(e.workerUrl, { type: "module" }).port);
51
- return n.start(), await new Promise((i, a) => {
52
- let o = setTimeout(() => a(/* @__PURE__ */ Error("connectSharedWorker: timed out waiting for the shared worker — is the host module calling sharedWorkerHost()?")), e.connectTimeoutMs ?? 1e4), s = (a) => {
53
- let c = a.data;
54
- c?.type === "SHARED_MEMORY" && (n.removeEventListener("message", s), clearTimeout(o), e.sharedMemory.bind(c.buffer), t.info(`connected as client #${c.clientIndex}`, { bytes: c.buffer.byteLength }), i(new r(n, c.clientIndex, e)));
55
- };
56
- n.addEventListener("message", s), n.postMessage({
57
- type: "SHARED_CONNECT",
58
- memoryBytes: e.sharedMemory.totalBytes,
59
- memory: e.memory
60
- });
61
47
  });
62
48
  }
63
49
  //#endregion
64
- export { i as connectSharedWorker };
50
+ export { a as forwardWorkerDevtools, i as sendInit, r as setupChannelMemory };
package/dist/index14.js CHANGED
@@ -1,25 +1,59 @@
1
- import { scoped as e } from "./index6.js";
2
- //#region src/worker/registry.ts
3
- var t = e("registry"), n = class {
4
- static tasks = /* @__PURE__ */ new Map();
5
- static register(e, n) {
6
- this.tasks.set(e.taskId, {
7
- contract: e,
8
- handler: n
9
- }), t.debug(`registered "${e.taskId}"`, {
10
- args: e.argsSchema ? "validated" : "unvalidated",
11
- result: e.resultSchema ? "validated" : "unvalidated"
12
- });
13
- }
14
- static getContract(e) {
15
- return this.tasks.get(e)?.contract;
16
- }
17
- static async execute(e, ...t) {
18
- let n = this.tasks.get(e);
19
- if (!n) throw Error(`Task handler not found for id: ${e}`);
20
- let { contract: r, handler: i } = n, a = await i(...r.argsSchema ? r.argsSchema.parse(t) : t);
21
- return r.resultSchema ? r.resultSchema.parse(a) : a;
1
+ import { registerDevtoolsCommand as e } from "./index5.js";
2
+ //#region src/pool/devtoolsCommands.ts
3
+ var t = "chaos: injected failure", n = "killed from devtools", r = /* @__PURE__ */ new Map(), i = null, a = (e) => {
4
+ let t = e.poolId;
5
+ if (typeof t != "string") throw Error("poolId (string) is required");
6
+ let n = r.get(t);
7
+ if (!n) throw Error(t.includes("~") ? `runner '${t}' lives inside a worker: nested pools are not controllable from the dashboard` : `no live runner '${t}' on this thread`);
8
+ return n;
9
+ }, o = (e, t) => {
10
+ if (e != null) {
11
+ if (typeof e != "number" || !Number.isFinite(e) || e < 0 || e > 1) throw Error(`${t} must be a number in 0..1`);
12
+ return e || void 0;
22
13
  }
14
+ }, s = (e) => {
15
+ let { delayMs: t } = e;
16
+ if (t != null && (typeof t != "number" || !Number.isFinite(t) || t < 0)) throw Error("delayMs must be a non-negative number");
17
+ let n = o(e.failRate, "failRate"), r = o(e.timeoutRate, "timeoutRate");
18
+ if ((n ?? 0) + (r ?? 0) > 1) throw Error("failRate + timeoutRate must not exceed 1");
19
+ let i = {};
20
+ return t && (i.delayMs = t), n && (i.failRate = n), r && (i.timeoutRate = r), Object.keys(i).length ? i : null;
21
+ }, c = () => [...r.values()].map((e) => ({
22
+ poolId: e.poolId,
23
+ label: e.label ?? e.poolId,
24
+ size: e.size(),
25
+ dedicated: e.dedicated,
26
+ chaos: e.getChaos()
27
+ })), l = () => {
28
+ let t = [
29
+ e("pool.list", () => c()),
30
+ e("pool.stats", (e) => a(e).stats()),
31
+ e("worker.kill", (e) => {
32
+ let t = a(e), n = e.slot ?? 0;
33
+ if (typeof n != "number" || !Number.isInteger(n) || n < 0) throw Error("slot must be a non-negative integer");
34
+ return t.kill(n), {
35
+ poolId: t.poolId,
36
+ slot: n,
37
+ killed: !0
38
+ };
39
+ }),
40
+ e("pool.chaos", (e) => {
41
+ let t = a(e);
42
+ return t.setChaos(s(e)), t.getChaos();
43
+ })
44
+ ];
45
+ return () => t.forEach((e) => e());
46
+ }, u = (e) => (r.set(e.poolId, e), i ??= l(), () => {
47
+ r.get(e.poolId) === e && (r.delete(e.poolId), r.size === 0 && i && (i(), i = null));
48
+ }), d = (e, t) => {
49
+ let n = Math.random(), r = n < (e.failRate ?? 0), i = !r && n < (e.failRate ?? 0) + (e.timeoutRate ?? 0);
50
+ if (!e.delayMs && !r && !i) return t.post();
51
+ setTimeout(() => {
52
+ if (t.live()) {
53
+ if (r) return t.fail();
54
+ i && t.timeout(), t.post();
55
+ }
56
+ }, e.delayMs ?? 0);
23
57
  };
24
58
  //#endregion
25
- export { n as TaskRegistry };
59
+ export { t as CHAOS_FAILURE, n as KILL_MESSAGE, d as applyChaos, s as parseChaos, u as registerDevtoolsRunner };