@atolljs/core 0.1.6 → 0.1.8

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 +6 -2
  4. package/dist/contract/types.d.ts +13 -0
  5. package/dist/devtools.d.ts +346 -0
  6. package/dist/index.d.ts +8 -2
  7. package/dist/index.js +19 -16
  8. package/dist/index10.js +28 -184
  9. package/dist/index11.js +18 -48
  10. package/dist/index12.js +29 -63
  11. package/dist/index13.js +49 -24
  12. package/dist/index14.js +57 -59
  13. package/dist/index15.js +335 -45
  14. package/dist/index16.js +242 -47
  15. package/dist/index17.js +57 -38
  16. package/dist/index18.js +9 -86
  17. package/dist/index19.js +58 -48
  18. package/dist/index20.js +24 -56
  19. package/dist/index21.js +61 -0
  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 +227 -35
  28. package/dist/index6.js +143 -471
  29. package/dist/index7.js +51 -20
  30. package/dist/index8.js +507 -27
  31. package/dist/index9.js +19 -18
  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 +38 -8
  37. package/dist/pool/workerPool.d.ts +13 -0
  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 +2 -1
  42. package/src/contract/memoryDevtools.ts +249 -0
  43. package/src/contract/sharedMemory.ts +39 -9
  44. package/src/contract/types.ts +13 -0
  45. package/src/devtools.ts +735 -0
  46. package/src/index.ts +27 -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 +64 -15
  54. package/src/pool/workerPool.ts +115 -36
  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 +29 -3
package/dist/index10.js CHANGED
@@ -1,191 +1,35 @@
1
- import { fmtBytes as e, scoped as t } from "./index5.js";
2
- import { MemoryManager as n } from "./index8.js";
3
- import { PoolQueueFullError as r, TaskAbortedError as i, TaskTimeoutError as a, WorkerCrashedError as o } from "./index9.js";
4
- //#region src/pool/workerPool.ts
5
- var s = t("pool"), c = t("task"), l = () => ({
6
- count: 0,
7
- mean: 0,
8
- max: 0,
9
- add(e) {
10
- this.count++, this.mean += (e - this.mean) / this.count, e > this.max && (this.max = e);
11
- }
12
- }), u = class {
13
- slots = [];
14
- pending = /* @__PURE__ */ new Map();
15
- nextMessageId = 0;
16
- queue = [];
17
- memoryManager;
18
- workerUrl;
19
- spawn;
20
- concurrency;
21
- maxQueue;
22
- respawn;
23
- taskTimeout;
24
- closed = !1;
25
- drainWaiters = [];
26
- statsAgg = {
27
- completed: 0,
28
- failed: 0,
29
- aborted: 0,
30
- waitMs: l(),
31
- runMs: l()
32
- };
33
- sharedMemory;
34
- persistence;
35
- constructor(t) {
36
- if (t.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.");
37
- if (!t.workerUrl && !t.createWorker) throw Error("WorkerPool requires either `workerUrl` or `createWorker` in its config.");
38
- this.workerUrl = t.workerUrl, this.spawn = t.createWorker ?? (() => new Worker(this.workerUrl, { type: "module" })), this.concurrency = t.concurrency ?? 1, this.maxQueue = t.maxQueue ?? Infinity, this.respawn = t.respawn ?? !0, this.taskTimeout = t.taskTimeout, t.sharedMemory && (this.sharedMemory = t.sharedMemory, this.memoryManager = new n(t.memory), this.memoryManager.ensureCapacity(this.sharedMemory.totalBytes), this.sharedMemory.bind(this.memoryManager.getBuffer()), this.persistence = t.persistence?.(t.sharedMemory));
39
- let r = t.poolSize ?? "auto", i = r === "auto" ? navigator.hardwareConcurrency ?? 4 : r;
40
- s.info(this.sharedMemory ? `spawning ${i} worker(s) with ${e(this.sharedMemory.totalBytes)} shared buffer` : `spawning ${i} worker(s), message-only`, { workerUrl: t.workerUrl ? String(t.workerUrl) : "createWorker()" }), s.debug("tip: setLogLevel('trace') for per-task detail");
41
- for (let e = 0; e < i; e++) this.addWorker(this.spawn());
42
- let a = t.tasks ?? {};
43
- for (let [e, t] of Object.entries(a)) {
44
- if (e in this) {
45
- s.warn(`task "${e}" collides with a WorkerPool member — not installed`);
46
- continue;
47
- }
48
- this[e] = (...e) => this.runTask(t, ...e);
49
- }
50
- Object.keys(a).length > 0 && s.info(`task methods: ${Object.keys(a).join(", ")}`);
51
- }
52
- addWorker(e) {
53
- let t = {
54
- worker: e,
55
- inFlight: 0
56
- };
57
- return e.addEventListener("message", (e) => {
58
- this.handleReply(t, e.data);
59
- }), e.addEventListener("error", (e) => {
60
- this.handleWorkerError(t, e);
61
- }), this.memoryManager ? e.postMessage({
62
- type: "INIT_MEMORY",
63
- memory: this.memoryManager.memory
64
- }) : e.postMessage({ type: "INIT" }), this.slots.push(t), s.debug(`worker spawned, ${this.memoryManager ? "INIT_MEMORY" : "INIT"} sent`), t;
65
- }
66
- handleReply(e, t) {
67
- let n = t.messageId === void 0 ? void 0 : this.pending.get(t.messageId);
68
- n && (this.pending.delete(t.messageId), e.inFlight--, this.detach(n), n.done || (n.done = !0, this.statsAgg.runMs.add(performance.now() - (n.sentAt ?? n.enqueuedAt)), t.success ? (this.statsAgg.completed++, c.debug(`← ${n.contract.taskId} ok`), n.resolve(t.result)) : (this.statsAgg.failed++, c.warn(`← ${n.contract.taskId} failed: ${t.error}`), n.reject(Error(t.error)))), this.drainQueue(), this.checkDrained());
69
- }
70
- handleWorkerError(e, t) {
71
- if (this.closed) return;
72
- let n = t, r = n?.message ?? (n?.error ? String(n.error) : "worker error");
73
- s.warn(`worker error: ${r}`);
74
- for (let [t, n] of [...this.pending]) if (n.slot === e) {
75
- if (this.pending.delete(t), this.detach(n), n.done) continue;
76
- n.done = !0, this.statsAgg.failed++, n.reject(new o(r));
77
- }
78
- let i = this.slots.indexOf(e);
79
- if (i >= 0 && this.slots.splice(i, 1), e.worker.terminate(), this.respawn) s.info("respawning crashed worker"), this.addWorker(this.spawn());
80
- else if (this.slots.length === 0) for (let e of this.queue.splice(0)) e.done = !0, this.detach(e), this.statsAgg.failed++, e.reject(new o(r));
81
- this.drainQueue(), this.checkDrained();
82
- }
83
- pickWorker() {
84
- let e;
85
- for (let t of this.slots) t.inFlight >= this.concurrency || (!e || t.inFlight < e.inFlight) && (e = t);
86
- return e;
87
- }
88
- drainQueue() {
89
- let e;
90
- for (; this.queue.length > 0 && (e = this.pickWorker());) {
91
- let t = this.queue.shift();
92
- t.done || this.send(e, t);
93
- }
94
- }
95
- send(e, t) {
96
- let n = this.nextMessageId++;
97
- t.messageId = n, t.slot = e, t.sentAt = performance.now(), this.statsAgg.waitMs.add(performance.now() - t.enqueuedAt), e.inFlight++, this.pending.set(n, t), c.debug(`→ ${t.contract.taskId}`, {
98
- worker: this.slots.indexOf(e),
99
- args: t.args
100
- }), e.worker.postMessage({
101
- type: "EXECUTE_TASK",
102
- messageId: n,
103
- taskId: t.contract.taskId,
104
- args: t.args
1
+ //#region src/pool/memory.ts
2
+ var e = class {
3
+ memory;
4
+ maxPages;
5
+ constructor(e = {}) {
6
+ let t = e.initialPages ?? 16;
7
+ this.maxPages = e.maximumPages ?? 16384, this.memory = new WebAssembly.Memory({
8
+ initial: t,
9
+ maximum: this.maxPages,
10
+ shared: !0
105
11
  });
106
12
  }
107
- detach(e) {
108
- e.timer && clearTimeout(e.timer), e.signal && e.onSignalAbort && e.signal.removeEventListener("abort", e.onSignalAbort);
109
- }
110
- cancel(e, t) {
111
- if (e.done) return;
112
- let n = this.queue.indexOf(e);
113
- n >= 0 && this.queue.splice(n, 1), e.done = !0, this.detach(e), this.statsAgg.aborted++, e.reject(t), this.drainQueue(), this.checkDrained();
114
- }
115
- checkDrained() {
116
- if (this.queue.length === 0 && this.pending.size === 0) {
117
- let e = this.drainWaiters.splice(0);
118
- for (let t of e) t();
13
+ ensureCapacity(e) {
14
+ let t = this.memory.buffer.byteLength;
15
+ if (t >= e) return;
16
+ let n = e - t, r = Math.ceil(n / 65536);
17
+ if (this.memory.buffer.byteLength / 65536 + r > this.maxPages) throw Error(`Cannot grow memory: exceeds maximum page limit of ${this.maxPages}`);
18
+ this.memory.grow(r);
19
+ }
20
+ getView(e, t = 0, n) {
21
+ let r = this.memory.buffer;
22
+ switch (e) {
23
+ case "Int32": return new Int32Array(r, t, n);
24
+ case "Float64": return new Float64Array(r, t, n);
25
+ case "BigInt64": return new BigInt64Array(r, t, n);
26
+ case "Uint8": return new Uint8Array(r, t, n);
27
+ default: throw Error(`Unsupported view type: ${e}`);
119
28
  }
120
29
  }
121
- dispatch(e, t, n) {
122
- return this.closed || this.slots.length === 0 ? Promise.reject(new o("WorkerPool has been terminated — no workers available.")) : n?.signal?.aborted ? Promise.reject(new i()) : new Promise((o, s) => {
123
- let c = {
124
- contract: e,
125
- args: t,
126
- enqueuedAt: performance.now(),
127
- resolve: o,
128
- reject: s,
129
- done: !1,
130
- signal: n?.signal
131
- };
132
- n?.signal && (c.onSignalAbort = () => this.cancel(c, new i()), n.signal.addEventListener("abort", c.onSignalAbort, { once: !0 }));
133
- let l = n?.timeout ?? this.taskTimeout;
134
- l !== void 0 && (c.timer = setTimeout(() => this.cancel(c, new a()), l));
135
- let u = this.pickWorker();
136
- if (u) this.send(u, c);
137
- else if (this.queue.length >= this.maxQueue) {
138
- c.done = !0, this.detach(c), s(new r());
139
- return;
140
- } else this.queue.push(c);
141
- });
142
- }
143
- runTask(e, ...t) {
144
- return this.dispatch(e, t);
145
- }
146
- get sharedBuffer() {
147
- return this.memoryManager?.getBuffer();
148
- }
149
- get workers() {
150
- return this.slots.map((e) => e.worker);
151
- }
152
- stats() {
153
- return {
154
- workers: this.slots.length,
155
- idle: this.slots.filter((e) => e.inFlight === 0).length,
156
- inFlight: this.pending.size,
157
- queued: this.queue.length,
158
- completed: this.statsAgg.completed,
159
- failed: this.statsAgg.failed,
160
- aborted: this.statsAgg.aborted,
161
- waitMs: {
162
- count: this.statsAgg.waitMs.count,
163
- mean: this.statsAgg.waitMs.mean,
164
- max: this.statsAgg.waitMs.max
165
- },
166
- runMs: {
167
- count: this.statsAgg.runMs.count,
168
- mean: this.statsAgg.runMs.mean,
169
- max: this.statsAgg.runMs.max
170
- }
171
- };
172
- }
173
- close() {
174
- return this.queue.length === 0 && this.pending.size === 0 ? (this.terminate(), Promise.resolve()) : new Promise((e) => {
175
- this.drainWaiters.push(() => {
176
- this.terminate(), e();
177
- });
178
- });
179
- }
180
- terminate() {
181
- this.closed = !0, this.persistence?.stop()?.catch?.((e) => s.warn("memory persistence stop failed", e)), s.info(`terminating ${this.slots.length} worker(s)`);
182
- let e = new o("pool terminated");
183
- for (let [, t] of this.pending) this.detach(t), !t.done && (t.done = !0, this.statsAgg.failed++, t.reject(e));
184
- this.pending.clear();
185
- for (let t of this.queue.splice(0)) t.done = !0, this.detach(t), this.statsAgg.failed++, t.reject(e);
186
- for (let e of this.slots) e.worker.terminate();
187
- this.slots = [], this.checkDrained();
30
+ getBuffer() {
31
+ return this.memory.buffer;
188
32
  }
189
33
  };
190
34
  //#endregion
191
- export { u as WorkerPool };
35
+ export { e as MemoryManager };
package/dist/index11.js CHANGED
@@ -1,50 +1,20 @@
1
- import { WorkerPool as e } from "./index10.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
- });
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";
5
+ }
6
+ }, t = class extends Error {
7
+ constructor(e = "task aborted") {
8
+ super(e), this.name = "AbortError";
9
+ }
10
+ }, n = class extends Error {
11
+ constructor(e = "task timed out") {
12
+ super(e), this.name = "TaskTimeoutError";
13
+ }
14
+ }, r = class extends Error {
15
+ constructor(e = "worker crashed") {
16
+ super(e), this.name = "WorkerCrashedError";
17
+ }
18
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
- memory: n.memory,
29
- concurrency: n.concurrency,
30
- maxQueue: n.maxQueue,
31
- respawn: n.respawn,
32
- taskTimeout: n.taskTimeout
33
- });
34
- return n.lazy === !1 && i(), t([], i, {
35
- start: () => {
36
- i();
37
- },
38
- terminate: () => {
39
- r?.terminate(), r = null;
40
- },
41
- get pool() {
42
- return r;
43
- },
44
- get sharedMemory() {
45
- return n.sharedMemory;
46
- }
47
- });
48
- }
49
19
  //#endregion
50
- export { r as connectWorker, n as workerClient };
20
+ export { e as PoolQueueFullError, t as TaskAbortedError, n as TaskTimeoutError, r as WorkerCrashedError };
package/dist/index12.js CHANGED
@@ -1,64 +1,30 @@
1
- import { scoped as e } from "./index5.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();
44
- }
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
- });
62
- }
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
+ });
63
29
  //#endregion
64
- export { i as connectSharedWorker };
30
+ export { e as measureAtoll, t as measureTaskCall };
package/dist/index13.js CHANGED
@@ -1,25 +1,50 @@
1
- import { scoped as e } from "./index5.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;
22
- }
23
- };
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
46
+ }
47
+ });
48
+ }
24
49
  //#endregion
25
- export { n as TaskRegistry };
50
+ export { a as forwardWorkerDevtools, i as sendInit, r as setupChannelMemory };
package/dist/index14.js CHANGED
@@ -1,61 +1,59 @@
1
- import { fmtBytes as e, scoped as t } from "./index5.js";
2
- import { bindSharedMemories as n } from "./index6.js";
3
- import { MemoryManager as r } from "./index8.js";
4
- import { TaskRegistry as i } from "./index13.js";
5
- //#region src/shared/sharedWorkerHost.ts
6
- var a = t("shared-worker"), o = null, s = 0;
7
- function c(t, i) {
8
- if (o) return o.buffer.byteLength < t && a.warn(`client requested ${e(t)} but buffer is ${e(o.buffer.byteLength)} — first client's capacity wins`), o;
9
- let s = new r(i);
10
- return s.ensureCapacity(t), o = s.memory, n(s.getBuffer()), a.info(`shared buffer allocated (${e(o.buffer.byteLength)})`), o;
11
- }
12
- function l(e) {
13
- let t = ++s;
14
- a.info(`client #${t} connected`), e.onmessage = async (n) => {
15
- let r = n.data;
16
- if (r?.type === "SHARED_CONNECT") {
17
- let n = c(r.memoryBytes ?? 0, r.memory);
18
- e.postMessage({
19
- type: "SHARED_MEMORY",
20
- buffer: n.buffer,
21
- clientIndex: t
22
- });
23
- return;
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;
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();
24
55
  }
25
- if (r?.type === "EXECUTE_TASK") {
26
- let { messageId: n, taskId: s, args: c } = r;
27
- if (!o) {
28
- e.postMessage({
29
- messageId: n,
30
- success: !1,
31
- error: "Shared memory not initialized in worker."
32
- });
33
- return;
34
- }
35
- let l = performance.now();
36
- try {
37
- let r = await i.execute(s, ...c || []);
38
- a.debug(`task ${s} → ${(performance.now() - l).toFixed(1)}ms (client #${t})`), e.postMessage({
39
- messageId: n,
40
- success: !0,
41
- result: r
42
- });
43
- } catch (t) {
44
- a.warn(`task ${s} failed: ${t.message || String(t)}`), e.postMessage({
45
- messageId: n,
46
- success: !1,
47
- error: t.message || String(t)
48
- });
49
- }
50
- return;
51
- }
52
- r?.type === "SHARED_DISCONNECT" && (e.close(), a.info(`client #${t} disconnected`));
53
- }, e.start();
54
- }
55
- function u() {
56
- self.onconnect = (e) => {
57
- l(e.ports[0]);
58
- };
59
- }
56
+ }, e.delayMs ?? 0);
57
+ };
60
58
  //#endregion
61
- export { l as attachSharedPort, u as sharedWorkerHost };
59
+ export { t as CHAOS_FAILURE, n as KILL_MESSAGE, d as applyChaos, s as parseChaos, u as registerDevtoolsRunner };