@mmstack/worker 22.0.0 → 22.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -20
- package/fesm2022/mmstack-worker-host.mjs +43 -87
- package/fesm2022/mmstack-worker-host.mjs.map +1 -1
- package/fesm2022/mmstack-worker-protocol.mjs +0 -1
- package/fesm2022/mmstack-worker-protocol.mjs.map +1 -1
- package/fesm2022/mmstack-worker.mjs +118 -110
- package/fesm2022/mmstack-worker.mjs.map +1 -1
- package/package.json +2 -2
- package/types/mmstack-worker-host.d.ts +7 -0
- package/types/mmstack-worker-protocol.d.ts +6 -23
- package/types/mmstack-worker.d.ts +19 -12
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { generateId, deserializeError, closePort, takeTransferables } from '@mmstack/worker/protocol';
|
|
2
2
|
export * from '@mmstack/worker/protocol';
|
|
3
3
|
import { inject, Injector, runInInjectionContext, PLATFORM_ID, signal, DestroyRef, computed, effect, untracked } from '@angular/core';
|
|
4
|
-
import { injectTransitionScope, toStore,
|
|
4
|
+
import { injectTransitionScope, toStore, opSync } from '@mmstack/primitives';
|
|
5
|
+
import { createWatch } from '@angular/core/primitives/signals';
|
|
5
6
|
|
|
6
7
|
/** Thrown into a task/write promise when it is aborted. `name` is `'AbortError'` (DOM convention). */
|
|
7
8
|
class WorkerAbortError extends Error {
|
|
@@ -45,16 +46,16 @@ function build$2(spawn, opt) {
|
|
|
45
46
|
let attempt = 0;
|
|
46
47
|
let runIdSeq = 0;
|
|
47
48
|
let destroyed = false;
|
|
48
|
-
let crashed = false;
|
|
49
|
+
let crashed = false;
|
|
49
50
|
let port = null;
|
|
50
51
|
const send = (msg, transfer) => {
|
|
51
52
|
if (port)
|
|
52
|
-
port.postMessage(msg, transfer);
|
|
53
|
+
port.postMessage(msg, transfer);
|
|
53
54
|
};
|
|
54
55
|
const onMessage = (msg) => {
|
|
55
56
|
switch (msg.type) {
|
|
56
57
|
case 'ready':
|
|
57
|
-
attempt = 0;
|
|
58
|
+
attempt = 0;
|
|
58
59
|
crashed = false;
|
|
59
60
|
manifest.set({
|
|
60
61
|
hostId: msg.hostId,
|
|
@@ -83,10 +84,9 @@ function build$2(spawn, opt) {
|
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
85
86
|
case 'task:aborted':
|
|
86
|
-
taskPending.delete(msg.runId);
|
|
87
|
+
taskPending.delete(msg.runId);
|
|
87
88
|
return;
|
|
88
89
|
default:
|
|
89
|
-
// store:* traffic → replicas
|
|
90
90
|
for (const h of storeHandlers)
|
|
91
91
|
h(msg);
|
|
92
92
|
}
|
|
@@ -96,7 +96,6 @@ function build$2(spawn, opt) {
|
|
|
96
96
|
return;
|
|
97
97
|
crashed = true;
|
|
98
98
|
connected.set(false);
|
|
99
|
-
// in-flight tasks can't survive a crash; store replicas hold their value and re-hydrate on reconnect
|
|
100
99
|
for (const [, p] of taskPending)
|
|
101
100
|
p.reject(new WorkerCrashedError());
|
|
102
101
|
taskPending.clear();
|
|
@@ -111,14 +110,11 @@ function build$2(spawn, opt) {
|
|
|
111
110
|
}, delay);
|
|
112
111
|
};
|
|
113
112
|
const openPort = () => {
|
|
114
|
-
// terminate the previous worker before respawning, so a transient/manual restart never orphans
|
|
115
|
-
// a live thread (a genuine crash already killed it; terminate() is then a harmless no-op)
|
|
116
113
|
if (port)
|
|
117
114
|
closePort(port);
|
|
118
115
|
port = spawn();
|
|
119
116
|
port.onmessage = (ev) => onMessage(ev.data);
|
|
120
|
-
//
|
|
121
|
-
// MessagePort's onmessage delivery). A real `Worker` has onerror; onmessageerror where present.
|
|
117
|
+
// crash detection via property setters, not addEventListener (perturbs node MessagePort delivery)
|
|
122
118
|
const evt = port;
|
|
123
119
|
if ('onerror' in evt)
|
|
124
120
|
evt.onerror = handleCrash;
|
|
@@ -126,7 +122,6 @@ function build$2(spawn, opt) {
|
|
|
126
122
|
evt.onmessageerror = handleCrash;
|
|
127
123
|
send({ type: 'hello', proto: 1, clientId });
|
|
128
124
|
};
|
|
129
|
-
// no workers on the server — connected stays false, runTask rejects, replicas render their default
|
|
130
125
|
if (!isServer)
|
|
131
126
|
openPort();
|
|
132
127
|
inject(DestroyRef).onDestroy(() => teardown());
|
|
@@ -136,8 +131,6 @@ function build$2(spawn, opt) {
|
|
|
136
131
|
for (const [, p] of taskPending)
|
|
137
132
|
p.reject(new WorkerAbortError('worker connection destroyed'));
|
|
138
133
|
taskPending.clear();
|
|
139
|
-
// same contract as a crash: anything pending on the connection (replica writes) settles NOW
|
|
140
|
-
// rather than dangling — a destroyed port can never deliver the echo that would resolve them
|
|
141
134
|
for (const fn of disconnectHooks)
|
|
142
135
|
fn();
|
|
143
136
|
if (port)
|
|
@@ -152,9 +145,6 @@ function build$2(spawn, opt) {
|
|
|
152
145
|
return Promise.reject(new WorkerCrashedError('no worker on the server'));
|
|
153
146
|
if (destroyed)
|
|
154
147
|
return Promise.reject(new WorkerAbortError('worker connection destroyed'));
|
|
155
|
-
// between a crash and the respawned handshake the port is dead — a message posted into it
|
|
156
|
-
// vanishes and the promise would never settle. Reject honestly; the caller retries/reloads.
|
|
157
|
-
// (Before the FIRST handshake this is false: a starting worker buffers messages, so we send.)
|
|
158
148
|
if (crashed)
|
|
159
149
|
return Promise.reject(new WorkerCrashedError('worker is restarting'));
|
|
160
150
|
if (o?.signal?.aborted)
|
|
@@ -238,7 +228,7 @@ function build$1(params, options) {
|
|
|
238
228
|
if (inFlight === ac)
|
|
239
229
|
inFlight = null;
|
|
240
230
|
if (myEpoch !== epoch)
|
|
241
|
-
return;
|
|
231
|
+
return;
|
|
242
232
|
value.set(result);
|
|
243
233
|
status.set('resolved');
|
|
244
234
|
}, (err) => {
|
|
@@ -257,10 +247,9 @@ function build$1(params, options) {
|
|
|
257
247
|
const ref = effect(() => {
|
|
258
248
|
const i = input();
|
|
259
249
|
if (isServer || i === PAUSED)
|
|
260
|
-
return;
|
|
250
|
+
return;
|
|
261
251
|
if (i === undefined)
|
|
262
|
-
return;
|
|
263
|
-
// dedup: a resume to the same input (e.g. after a pause) does not re-run
|
|
252
|
+
return;
|
|
264
253
|
if (Object.is(i, lastInput) && hasRun && untracked(status) !== 'error')
|
|
265
254
|
return;
|
|
266
255
|
untracked(() => start(i));
|
|
@@ -284,11 +273,11 @@ function build$1(params, options) {
|
|
|
284
273
|
},
|
|
285
274
|
abort: () => {
|
|
286
275
|
if (!inFlight)
|
|
287
|
-
return;
|
|
276
|
+
return;
|
|
288
277
|
epoch++;
|
|
289
278
|
inFlight.abort();
|
|
290
279
|
inFlight = null;
|
|
291
|
-
status.set('local');
|
|
280
|
+
status.set('local');
|
|
292
281
|
},
|
|
293
282
|
destroy: () => {
|
|
294
283
|
epoch++;
|
|
@@ -299,100 +288,124 @@ function build$1(params, options) {
|
|
|
299
288
|
if (options.register) {
|
|
300
289
|
const scope = injectTransitionScope();
|
|
301
290
|
scope.add(self, { suspends: options.register === 'suspend' });
|
|
302
|
-
|
|
291
|
+
let removed = false;
|
|
292
|
+
const remove = () => {
|
|
293
|
+
if (removed)
|
|
294
|
+
return;
|
|
295
|
+
removed = true;
|
|
296
|
+
scope.remove(self);
|
|
297
|
+
};
|
|
298
|
+
inject(DestroyRef).onDestroy(remove);
|
|
299
|
+
const destroy = self.destroy;
|
|
300
|
+
self.destroy = () => {
|
|
301
|
+
remove();
|
|
302
|
+
destroy();
|
|
303
|
+
};
|
|
303
304
|
}
|
|
304
305
|
return self;
|
|
305
306
|
}
|
|
306
307
|
|
|
308
|
+
// An injector-free opLog driver (schedules emission off the microtask queue via `createWatch`), so
|
|
309
|
+
// the replica's `opSync` emits without depending on an application tick. Writes force a synchronous
|
|
310
|
+
// `flush()` at the call site; between writes, owner envelopes drive apply, never local emission.
|
|
311
|
+
const microtaskDriver = () => (run) => {
|
|
312
|
+
let scheduled = false;
|
|
313
|
+
const watch = createWatch(() => run(), (w) => {
|
|
314
|
+
if (scheduled)
|
|
315
|
+
return;
|
|
316
|
+
scheduled = true;
|
|
317
|
+
queueMicrotask(() => {
|
|
318
|
+
scheduled = false;
|
|
319
|
+
w.run();
|
|
320
|
+
});
|
|
321
|
+
}, false);
|
|
322
|
+
watch.notify();
|
|
323
|
+
return { destroy: () => watch.destroy() };
|
|
324
|
+
};
|
|
307
325
|
function workerStore(worker, key, opt) {
|
|
308
326
|
const injector = opt?.injector ?? inject(Injector);
|
|
309
327
|
return runInInjectionContext(injector, () => build(worker, key, opt));
|
|
310
328
|
}
|
|
311
329
|
function build(worker, key, opt) {
|
|
312
|
-
const injector = inject(Injector);
|
|
330
|
+
const injector = inject(Injector);
|
|
313
331
|
const root = signal(opt?.defaultValue, /* @ts-ignore */
|
|
314
332
|
...(ngDevMode ? [{ debugName: "root" }] : /* istanbul ignore next */ []));
|
|
315
|
-
|
|
316
|
-
const replica = toStore(root, {
|
|
333
|
+
const s = toStore(root, {
|
|
317
334
|
injector,
|
|
318
335
|
});
|
|
336
|
+
// The replica runs its own opSync over the worker transport: local writes emit stamped envelopes
|
|
337
|
+
// routed to the owner, owner envelopes fold in convergently. A driver (not the injector) so
|
|
338
|
+
// emission stays synchronous under an explicit `flush()`, matching the DI-free worker model.
|
|
339
|
+
const sync = opSync(root, {
|
|
340
|
+
writer: worker.clientId,
|
|
341
|
+
driver: microtaskDriver(),
|
|
342
|
+
onGap: () => resync(),
|
|
343
|
+
});
|
|
319
344
|
const status = signal('loading', /* @ts-ignore */
|
|
320
345
|
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
321
346
|
const error = signal(undefined, /* @ts-ignore */
|
|
322
347
|
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
323
348
|
const isLoading = computed(() => {
|
|
324
|
-
const
|
|
325
|
-
return
|
|
349
|
+
const st = status();
|
|
350
|
+
return st === 'loading' || st === 'reloading';
|
|
326
351
|
}, /* @ts-ignore */
|
|
327
352
|
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
328
353
|
let hasSnapshot = false;
|
|
329
|
-
let
|
|
330
|
-
|
|
331
|
-
let writeSeq = 0;
|
|
354
|
+
let lastEmitted = 0; // highest own-origin version emitted; the write() ack key
|
|
355
|
+
// own writes awaiting the owner's echo (resolve), plus the raw envelopes to resend after a resync
|
|
332
356
|
const writePending = new Map();
|
|
357
|
+
const unacked = new Map();
|
|
333
358
|
const hasValue = () => hasSnapshot;
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
for (const [
|
|
337
|
-
if (
|
|
338
|
-
writePending.delete(
|
|
359
|
+
const isOwned = () => worker.manifest()?.stores.includes(key) ?? false;
|
|
360
|
+
const ackUpTo = (version) => {
|
|
361
|
+
for (const [v, p] of writePending) {
|
|
362
|
+
if (v <= version) {
|
|
363
|
+
writePending.delete(v);
|
|
339
364
|
p.resolve();
|
|
340
365
|
}
|
|
341
366
|
}
|
|
367
|
+
for (const v of [...unacked.keys()])
|
|
368
|
+
if (v <= version)
|
|
369
|
+
unacked.delete(v);
|
|
342
370
|
};
|
|
371
|
+
const shipUnsub = sync.subscribe((env) => {
|
|
372
|
+
lastEmitted = env.version;
|
|
373
|
+
unacked.set(env.version, env);
|
|
374
|
+
if (isOwned() && untracked(worker.connected)) {
|
|
375
|
+
worker._send({ type: 'store:sync', store: key, env });
|
|
376
|
+
}
|
|
377
|
+
});
|
|
343
378
|
const onStoreMessage = (msg) => {
|
|
344
379
|
if (!('store' in msg) || msg.store !== key)
|
|
345
380
|
return;
|
|
346
381
|
switch (msg.type) {
|
|
347
|
-
case 'store:
|
|
348
|
-
|
|
349
|
-
|
|
382
|
+
case 'store:checkpoint': {
|
|
383
|
+
// rebase from the full unacked outbox, not opSync's bounded recent-local ring, so a burst
|
|
384
|
+
// of writes larger than that ring is never dropped from the local rebase on re-hydrate
|
|
385
|
+
sync.hydrate(msg.checkpoint, [...unacked.values()]);
|
|
350
386
|
hasSnapshot = true;
|
|
351
|
-
resyncing = false; // a fresh snapshot ends any resync
|
|
352
387
|
status.set('resolved');
|
|
353
388
|
error.set(undefined);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return; // stale/duplicate (at-least-once transport)
|
|
362
|
-
if (msg.batch.version > lastVersion + 1) {
|
|
363
|
-
// GAP: a batch was lost — re-hydrate from a fresh snapshot rather than apply out of order
|
|
364
|
-
resync();
|
|
365
|
-
return;
|
|
389
|
+
// writes the owner already applied are covered by the checkpoint watermark; resolve them,
|
|
390
|
+
// then resend any still-unacked tail so a write made before the (re)hydrate is never lost
|
|
391
|
+
ackUpTo(msg.checkpoint.wm?.[sync.origin] ?? 0);
|
|
392
|
+
if (isOwned() && untracked(worker.connected)) {
|
|
393
|
+
for (const env of [...unacked.values()].sort((a, b) => a.version - b.version)) {
|
|
394
|
+
worker._send({ type: 'store:sync', store: key, env });
|
|
395
|
+
}
|
|
366
396
|
}
|
|
367
|
-
root.set(applyOps(untracked(root), msg.batch.ops));
|
|
368
|
-
lastVersion = msg.batch.version;
|
|
369
|
-
settleWrites();
|
|
370
397
|
return;
|
|
371
398
|
}
|
|
372
|
-
case 'store:
|
|
373
|
-
const
|
|
374
|
-
if (
|
|
399
|
+
case 'store:sync': {
|
|
400
|
+
const env = msg.env;
|
|
401
|
+
if (env.origin === sync.origin) {
|
|
402
|
+
ackUpTo(env.version); // the owner echoed our own write back: acknowledgement
|
|
375
403
|
return;
|
|
376
|
-
if (lastVersion >= msg.version) {
|
|
377
|
-
writePending.delete(msg.writeId);
|
|
378
|
-
p.resolve(); // the authoritative batch already landed (FIFO: ops precede the ack)
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
p.version = msg.version; // resolve once a batch reaches this version
|
|
382
|
-
}
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
case 'store:write:error': {
|
|
386
|
-
const p = writePending.get(msg.writeId);
|
|
387
|
-
if (p) {
|
|
388
|
-
writePending.delete(msg.writeId);
|
|
389
|
-
p.reject(deserializeError(msg.error));
|
|
390
404
|
}
|
|
405
|
+
sync.receive(env); // owner or peer envelope; a version gap triggers onGap -> resync
|
|
391
406
|
return;
|
|
392
407
|
}
|
|
393
408
|
case 'store:status': {
|
|
394
|
-
// rung 3: a published derivation's remote status → this replica's status, so an in-flight
|
|
395
|
-
// worker computation shows as pending on the main thread (holding the last value)
|
|
396
409
|
switch (msg.status) {
|
|
397
410
|
case 'error':
|
|
398
411
|
error.set(msg.error ? deserializeError(msg.error) : new Error('remote computation error'));
|
|
@@ -401,7 +414,7 @@ function build(worker, key, opt) {
|
|
|
401
414
|
case 'loading':
|
|
402
415
|
case 'reloading':
|
|
403
416
|
error.set(undefined);
|
|
404
|
-
status.set(hasSnapshot ? 'reloading' : 'loading');
|
|
417
|
+
status.set(hasSnapshot ? 'reloading' : 'loading');
|
|
405
418
|
return;
|
|
406
419
|
case 'resolved':
|
|
407
420
|
error.set(undefined);
|
|
@@ -416,29 +429,25 @@ function build(worker, key, opt) {
|
|
|
416
429
|
};
|
|
417
430
|
const subscribe = () => {
|
|
418
431
|
if (hasSnapshot)
|
|
419
|
-
status.set('reloading');
|
|
432
|
+
status.set('reloading');
|
|
420
433
|
worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });
|
|
421
434
|
};
|
|
422
|
-
// a lost batch left a version gap — hold the stale value and re-subscribe for a fresh snapshot
|
|
423
435
|
const resync = () => {
|
|
424
|
-
resyncing = true;
|
|
425
436
|
status.set('reloading');
|
|
426
437
|
worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });
|
|
427
438
|
};
|
|
428
439
|
const unsub = worker._subscribe(onStoreMessage);
|
|
429
|
-
// subscribe on each `ready` — the first connection and every auto-restart re-hydration; if the
|
|
430
|
-
// connection is ALREADY up (created post-handshake), `_onReady` won't fire, so subscribe now
|
|
431
440
|
const offReady = worker._onReady(subscribe);
|
|
432
441
|
if (untracked(worker.connected))
|
|
433
|
-
subscribe();
|
|
434
|
-
// a crash can't be delivered — pending writes reject (the caller holds the value + recipe to retry)
|
|
442
|
+
subscribe(); // already up (created post-handshake): _onReady won't fire
|
|
435
443
|
const offDisconnect = worker._onDisconnect(() => {
|
|
436
444
|
for (const [, p] of writePending)
|
|
437
445
|
p.reject(new WorkerCrashedError());
|
|
438
446
|
writePending.clear();
|
|
447
|
+
unacked.clear();
|
|
439
448
|
});
|
|
440
449
|
const self = {
|
|
441
|
-
store:
|
|
450
|
+
store: s,
|
|
442
451
|
value: root.asReadonly(),
|
|
443
452
|
status,
|
|
444
453
|
error,
|
|
@@ -449,41 +458,30 @@ function build(worker, key, opt) {
|
|
|
449
458
|
const base = untracked(root);
|
|
450
459
|
if (base === undefined)
|
|
451
460
|
return Promise.reject(new Error('[@mmstack/worker] cannot write before the replica has hydrated'));
|
|
452
|
-
// hydrated but disconnected = the worker crashed (or is restarting) — a write posted now
|
|
453
|
-
// vanishes into a dead port and its echo can never arrive. Reject; the caller retries.
|
|
454
461
|
if (!untracked(worker.connected))
|
|
455
462
|
return Promise.reject(new WorkerCrashedError('worker is not connected'));
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const ops = diffOps(base, untracked(scratch));
|
|
465
|
-
if (!ops.length)
|
|
466
|
-
return Promise.resolve();
|
|
467
|
-
const writeId = ++writeSeq;
|
|
463
|
+
if (!isOwned())
|
|
464
|
+
return Promise.reject(new Error(`[@mmstack/worker] store is read-only (published): ${key}`));
|
|
465
|
+
recipe(s);
|
|
466
|
+
const before = lastEmitted;
|
|
467
|
+
sync.flush(); // emit the routed write synchronously (driver-backed opSync)
|
|
468
|
+
if (lastEmitted === before)
|
|
469
|
+
return Promise.resolve(); // no-op recipe: nothing shipped
|
|
470
|
+
const version = lastEmitted;
|
|
468
471
|
return new Promise((resolve, reject) => {
|
|
469
|
-
writePending.set(
|
|
470
|
-
worker._send({
|
|
471
|
-
type: 'store:write',
|
|
472
|
-
store: key,
|
|
473
|
-
writeId,
|
|
474
|
-
clientId: worker.clientId,
|
|
475
|
-
ops,
|
|
476
|
-
});
|
|
472
|
+
writePending.set(version, { resolve, reject });
|
|
477
473
|
});
|
|
478
474
|
},
|
|
479
475
|
destroy: () => {
|
|
476
|
+
shipUnsub();
|
|
477
|
+
sync.destroy();
|
|
480
478
|
unsub();
|
|
481
479
|
offReady();
|
|
482
480
|
offDisconnect();
|
|
483
|
-
// acks can no longer be received — settle any in-flight write instead of dangling it
|
|
484
481
|
for (const [, p] of writePending)
|
|
485
482
|
p.reject(new WorkerAbortError('worker store destroyed'));
|
|
486
483
|
writePending.clear();
|
|
484
|
+
unacked.clear();
|
|
487
485
|
worker._send({ type: 'store:unsubscribe', store: key, clientId: worker.clientId });
|
|
488
486
|
},
|
|
489
487
|
};
|
|
@@ -491,13 +489,23 @@ function build(worker, key, opt) {
|
|
|
491
489
|
if (opt?.register) {
|
|
492
490
|
const scope = injectTransitionScope();
|
|
493
491
|
scope.add(self, { suspends: opt.register === 'suspend' });
|
|
494
|
-
|
|
492
|
+
let removed = false;
|
|
493
|
+
const remove = () => {
|
|
494
|
+
if (removed)
|
|
495
|
+
return;
|
|
496
|
+
removed = true;
|
|
497
|
+
scope.remove(self);
|
|
498
|
+
};
|
|
499
|
+
inject(DestroyRef).onDestroy(remove);
|
|
500
|
+
const destroy = self.destroy;
|
|
501
|
+
self.destroy = () => {
|
|
502
|
+
remove();
|
|
503
|
+
destroy();
|
|
504
|
+
};
|
|
495
505
|
}
|
|
496
506
|
return self;
|
|
497
507
|
}
|
|
498
508
|
|
|
499
|
-
// shared wire types, re-exported so main-thread consumers import only from '@mmstack/worker'
|
|
500
|
-
|
|
501
509
|
/**
|
|
502
510
|
* Generated bundle index. Do not edit.
|
|
503
511
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mmstack-worker.mjs","sources":["../../../../packages/worker/src/lib/connect-worker.ts","../../../../packages/worker/src/lib/worker-resource.ts","../../../../packages/worker/src/lib/worker-store.ts","../../../../packages/worker/src/index.ts","../../../../packages/worker/src/mmstack-worker.ts"],"sourcesContent":["import {\n DestroyRef,\n inject,\n Injector,\n PLATFORM_ID,\n runInInjectionContext,\n signal,\n type Signal,\n} from '@angular/core';\nimport {\n closePort,\n deserializeError,\n generateId,\n takeTransferables,\n type HasSchema,\n type SchemaOf,\n type TaskInput,\n type TaskOutput,\n type WorkerEnvelope,\n type WorkerPortLike,\n type WorkerSchema,\n} from '@mmstack/worker/protocol';\n\n/** What the worker advertised in its `ready` handshake. */\nexport type WorkerManifest = {\n readonly hostId: string;\n readonly stores: readonly string[];\n readonly published: readonly string[];\n readonly tasks: readonly string[];\n};\n\n/** Thrown into a task/write promise when it is aborted. `name` is `'AbortError'` (DOM convention). */\nexport class WorkerAbortError extends Error {\n constructor(message = 'The worker task was aborted') {\n super(message);\n this.name = 'AbortError';\n }\n}\n\n/** Thrown into pending tasks/writes when the worker crashes. `name` is `'WorkerCrashedError'`. */\nexport class WorkerCrashedError extends Error {\n constructor(message = 'The worker crashed') {\n super(message);\n this.name = 'WorkerCrashedError';\n }\n}\n\nexport type ConnectWorkerOptions = {\n readonly injector?: Injector;\n /** `'auto'` (default) respawns on crash; `'manual'` surfaces disconnect and stops. */\n readonly restart?: 'auto' | 'manual';\n /** Backoff before respawn attempt `n` (0-based). Default exponential 1s→30s. */\n readonly restartDelay?: (attempt: number) => number;\n};\n\nexport type WorkerRef<M extends WorkerSchema = WorkerSchema> = HasSchema<M> & {\n /** True once the `ready` handshake has completed (and again after an auto-restart). */\n readonly connected: Signal<boolean>;\n /** The worker's advertised manifest, or `null` before the first `ready`. */\n readonly manifest: Signal<WorkerManifest | null>;\n /** Run a named task exposed by the worker host; resolves with its result (typed from the schema). */\n runTask<K extends keyof M['tasks'] & string>(\n task: K,\n input: TaskInput<M, K>,\n opt?: { signal?: AbortSignal; transfer?: Transferable[] },\n ): Promise<TaskOutput<M, K>>;\n destroy(): void;\n\n // ── internal seam for workerStore (phase 4b) — not part of the friendly surface ──\n /** @internal Post an envelope to the worker. */\n _send(msg: WorkerEnvelope, transfer?: Transferable[]): void;\n /** @internal Receive every non-task envelope (store traffic). Returns an unsubscribe. */\n _subscribe(handler: (msg: WorkerEnvelope) => void): () => void;\n /** @internal Run `fn` on every (re)connection — used to re-subscribe stores after a restart. */\n _onReady(fn: () => void): () => void;\n /** @internal Run `fn` when the connection drops (crash) — replicas reject pending writes here. */\n _onDisconnect(fn: () => void): () => void;\n /** @internal This client's identity on the transport. */\n readonly clientId: string;\n};\n\n/**\n * Connects the main thread to a worker over a {@link WorkerPortLike} the caller provides via `spawn`\n * — typically `() => new Worker(new URL('./my.worker', import.meta.url), { type: 'module' })` (the\n * URL literal must live in APP code so the bundler emits the worker chunk). Performs the hello/ready\n * handshake, exposes `connected`/`manifest`, routes named-task runs, and (via internal seams)\n * carries the store-replication traffic for {@link workerStore}. On crash it respawns with backoff\n * when `restart: 'auto'`.\n */\nexport function connectWorker<H = WorkerSchema>(\n spawn: () => WorkerPortLike,\n opt?: ConnectWorkerOptions,\n): WorkerRef<SchemaOf<H>> {\n const injector = opt?.injector ?? inject(Injector);\n return runInInjectionContext(injector, () =>\n build(spawn, opt),\n ) as unknown as WorkerRef<SchemaOf<H>>;\n}\n\nfunction build(\n spawn: () => WorkerPortLike,\n opt?: ConnectWorkerOptions,\n): WorkerRef {\n const isServer = inject(PLATFORM_ID) === 'server';\n const clientId = generateId();\n const connected = signal(false);\n const manifest = signal<WorkerManifest | null>(null);\n\n const taskPending = new Map<number, { resolve: (v: any) => void; reject: (e: unknown) => void }>();\n const storeHandlers = new Set<(msg: WorkerEnvelope) => void>();\n const readyHooks = new Set<() => void>();\n const disconnectHooks = new Set<() => void>();\n const restart = opt?.restart ?? 'auto';\n const restartDelay = opt?.restartDelay ?? ((n: number) => Math.min(30_000, 1000 * 2 ** n));\n let attempt = 0;\n let runIdSeq = 0;\n let destroyed = false;\n let crashed = false; // between a crash and the next successful handshake\n let port: WorkerPortLike = null as unknown as WorkerPortLike;\n\n const send = (msg: WorkerEnvelope, transfer?: Transferable[]): void => {\n if (port) port.postMessage(msg, transfer); // no-op on the server / between crash and respawn\n };\n\n const onMessage = (msg: WorkerEnvelope): void => {\n switch (msg.type) {\n case 'ready':\n attempt = 0; // a successful handshake resets the backoff\n crashed = false;\n manifest.set({\n hostId: msg.hostId,\n stores: msg.stores,\n published: msg.published,\n tasks: msg.tasks,\n });\n connected.set(true);\n for (const hook of readyHooks) hook();\n return;\n case 'task:ok': {\n const p = taskPending.get(msg.runId);\n if (p) {\n taskPending.delete(msg.runId);\n p.resolve(msg.value);\n }\n return;\n }\n case 'task:error': {\n const p = taskPending.get(msg.runId);\n if (p) {\n taskPending.delete(msg.runId);\n p.reject(deserializeError(msg.error));\n }\n return;\n }\n case 'task:aborted':\n taskPending.delete(msg.runId); // caller already rejected at abort\n return;\n default:\n // store:* traffic → replicas\n for (const h of storeHandlers) h(msg);\n }\n };\n\n const handleCrash = (): void => {\n if (destroyed) return;\n crashed = true;\n connected.set(false);\n // in-flight tasks can't survive a crash; store replicas hold their value and re-hydrate on reconnect\n for (const [, p] of taskPending) p.reject(new WorkerCrashedError());\n taskPending.clear();\n for (const fn of disconnectHooks) fn();\n if (restart === 'manual') return;\n const delay = restartDelay(attempt++);\n setTimeout(() => {\n if (!destroyed) openPort();\n }, delay);\n };\n\n const openPort = (): void => {\n // terminate the previous worker before respawning, so a transient/manual restart never orphans\n // a live thread (a genuine crash already killed it; terminate() is then a harmless no-op)\n if (port) closePort(port);\n port = spawn();\n port.onmessage = (ev) => onMessage(ev.data as WorkerEnvelope);\n // duck-typed crash detection via property setters (NOT addEventListener — that perturbs a node\n // MessagePort's onmessage delivery). A real `Worker` has onerror; onmessageerror where present.\n const evt = port as unknown as {\n onerror?: ((e?: unknown) => void) | null;\n onmessageerror?: ((e?: unknown) => void) | null;\n };\n if ('onerror' in evt) evt.onerror = handleCrash;\n if ('onmessageerror' in evt) evt.onmessageerror = handleCrash;\n send({ type: 'hello', proto: 1, clientId });\n };\n\n // no workers on the server — connected stays false, runTask rejects, replicas render their default\n if (!isServer) openPort();\n\n inject(DestroyRef).onDestroy(() => teardown());\n\n const teardown = (): void => {\n destroyed = true;\n connected.set(false);\n for (const [, p] of taskPending) p.reject(new WorkerAbortError('worker connection destroyed'));\n taskPending.clear();\n // same contract as a crash: anything pending on the connection (replica writes) settles NOW\n // rather than dangling — a destroyed port can never deliver the echo that would resolve them\n for (const fn of disconnectHooks) fn();\n if (port) closePort(port);\n };\n\n return {\n connected,\n manifest,\n clientId,\n runTask(\n task: string,\n input: unknown,\n o?: { signal?: AbortSignal; transfer?: Transferable[] },\n ): Promise<unknown> {\n if (isServer) return Promise.reject(new WorkerCrashedError('no worker on the server'));\n if (destroyed) return Promise.reject(new WorkerAbortError('worker connection destroyed'));\n // between a crash and the respawned handshake the port is dead — a message posted into it\n // vanishes and the promise would never settle. Reject honestly; the caller retries/reloads.\n // (Before the FIRST handshake this is false: a starting worker buffers messages, so we send.)\n if (crashed) return Promise.reject(new WorkerCrashedError('worker is restarting'));\n if (o?.signal?.aborted) return Promise.reject(new WorkerAbortError());\n const runId = ++runIdSeq;\n return new Promise<unknown>((resolve, reject) => {\n taskPending.set(runId, { resolve, reject });\n send(\n { type: 'task:run', runId, task, input },\n o?.transfer ?? takeTransferables(input),\n );\n o?.signal?.addEventListener(\n 'abort',\n () => {\n if (!taskPending.has(runId)) return;\n taskPending.delete(runId);\n send({ type: 'task:abort', runId });\n reject(new WorkerAbortError());\n },\n { once: true },\n );\n });\n },\n destroy: teardown,\n _send: send,\n _subscribe(handler) {\n storeHandlers.add(handler);\n return () => storeHandlers.delete(handler);\n },\n _onReady(fn) {\n readyHooks.add(fn);\n return () => readyHooks.delete(fn);\n },\n _onDisconnect(fn) {\n disconnectHooks.add(fn);\n return () => disconnectHooks.delete(fn);\n },\n };\n}\n","import {\n computed,\n DestroyRef,\n effect,\n inject,\n Injector,\n PLATFORM_ID,\n runInInjectionContext,\n signal,\n untracked,\n type ResourceStatus,\n type Signal,\n type ValueEqualityFn,\n} from '@angular/core';\nimport { injectTransitionScope } from '@mmstack/primitives';\nimport { WorkerAbortError, type WorkerRef } from './connect-worker';\n\n/** Returned from a paused `params` fn to HOLD (keep the current value/status, run nothing). */\nexport const PAUSED: unique symbol = Symbol('@mmstack/worker:PAUSED');\n\nexport type WorkerRequestContext = { readonly paused: typeof PAUSED };\n\n/**\n * Reactive input producer. Reads signals to derive the task input; return `undefined` to disable\n * (idle, no run), or `ctx.paused` to hold. Re-runs when the returned input changes (by `Object.is`).\n */\nexport type WorkerParamsFn<TInput> = (\n ctx: WorkerRequestContext,\n) => TInput | undefined | void | typeof PAUSED;\n\nexport type WorkerResourceOptions<TResult> = {\n readonly injector?: Injector;\n /** Equality for the result value — a run resolving equal to the held value emits no notification. */\n readonly equal?: ValueEqualityFn<TResult>;\n readonly defaultValue?: TResult;\n /**\n * Hold the previous value through a re-run (status `'reloading'`) instead of clearing it. Default\n * TRUE — a `workerResource` is an async derivation, not a fetch; flashing empty mid-recompute is\n * rarely wanted.\n */\n readonly keepPrevious?: boolean;\n /** Register into the nearest transition scope: `'indicator'` drives pending, `'suspend'` also gates first paint. */\n readonly register?: false | 'indicator' | 'suspend';\n /** The connected worker whose host exposes the task. */\n readonly worker: WorkerRef;\n /** The name of the task to run (as declared in `createWorkerHost({ tasks })`). */\n readonly task: string;\n};\n\nexport type WorkerResourceRef<T> = {\n /** The latest successfully-computed value (held through re-runs per `keepPrevious`). */\n readonly value: Signal<T | undefined>;\n readonly status: Signal<ResourceStatus>;\n readonly error: Signal<unknown>;\n readonly isLoading: Signal<boolean>;\n hasValue(): boolean;\n /** Re-run with the current input, bypassing input de-duplication. */\n reload(): void;\n /** Cancel the in-flight run; the value is KEPT and status becomes `'local'`. */\n abort(): void;\n destroy(): void;\n};\n\n/**\n * Runs a named task on a connected worker, exposed with the standard resource surface so heavy\n * compute makes the UI *pending*, not *frozen*. `params` reactively derives the input; latest-wins\n * (a changed input supersedes and aborts the in-flight run); the result surfaces as\n * `value`/`status`/`error`, and — with `register` — participates in transition scopes. No-ops on the\n * server.\n */\nexport function workerResource<TInput, TResult>(\n params: WorkerParamsFn<TInput>,\n options: WorkerResourceOptions<TResult>,\n): WorkerResourceRef<TResult> {\n const injector = options.injector ?? inject(Injector);\n return runInInjectionContext(injector, () => build<TInput, TResult>(params, options));\n}\n\nfunction build<TInput, TResult>(\n params: WorkerParamsFn<TInput>,\n options: WorkerResourceOptions<TResult>,\n): WorkerResourceRef<TResult> {\n const isServer = inject(PLATFORM_ID) === 'server';\n const keepPrevious = options.keepPrevious ?? true;\n const userEqual = options.equal;\n const { worker, task } = options;\n\n const runTask = (input: TInput, signal: AbortSignal): Promise<TResult> =>\n worker.runTask(task, input, { signal }) as Promise<TResult>;\n\n const value = signal<TResult | undefined>(options.defaultValue, {\n equal: userEqual\n ? (a, b) => (a === undefined || b === undefined ? a === b : userEqual(a, b))\n : undefined,\n });\n const status = signal<ResourceStatus>('idle');\n const error = signal<unknown>(undefined);\n const isLoading = computed(() => {\n const s = status();\n return s === 'loading' || s === 'reloading';\n });\n const hasValue = () => value() !== undefined;\n\n let epoch = 0;\n let inFlight: AbortController | null = null;\n let lastInput: TInput | undefined;\n let hasRun = false;\n\n const start = (input: TInput): void => {\n const myEpoch = ++epoch;\n inFlight?.abort();\n const ac = new AbortController();\n inFlight = ac;\n lastInput = input;\n hasRun = true;\n status.set(keepPrevious && value() !== undefined ? 'reloading' : 'loading');\n error.set(undefined);\n\n runTask(input, ac.signal).then(\n (result) => {\n if (inFlight === ac) inFlight = null;\n if (myEpoch !== epoch) return; // superseded — discard\n value.set(result);\n status.set('resolved');\n },\n (err) => {\n if (inFlight === ac) inFlight = null;\n if (myEpoch !== epoch) return;\n if (err instanceof WorkerAbortError || (err as { name?: string })?.name === 'AbortError')\n return;\n error.set(err);\n status.set('error');\n },\n );\n };\n\n const input = computed(() => params({ paused: PAUSED }));\n\n const ref = effect(() => {\n const i = input();\n if (isServer || i === PAUSED) return; // server: never run · paused: hold\n if (i === undefined) return; // disabled — keep current value/status\n // dedup: a resume to the same input (e.g. after a pause) does not re-run\n if (Object.is(i, lastInput) && hasRun && untracked(status) !== 'error') return;\n untracked(() => start(i as TInput));\n });\n\n inject(DestroyRef).onDestroy(() => {\n epoch++;\n inFlight?.abort();\n });\n\n const self: WorkerResourceRef<TResult> = {\n value,\n status,\n error,\n isLoading,\n hasValue,\n reload: () => {\n const i = untracked(input);\n if (isServer || i === PAUSED || i === undefined) return;\n start(i as TInput);\n },\n abort: () => {\n if (!inFlight) return; // nothing in flight (a scope's abortPending must not disturb a settled value)\n epoch++;\n inFlight.abort();\n inFlight = null;\n status.set('local'); // value kept\n },\n destroy: () => {\n epoch++;\n inFlight?.abort();\n ref.destroy();\n },\n };\n\n if (options.register) {\n const scope = injectTransitionScope();\n scope.add(self, { suspends: options.register === 'suspend' });\n inject(DestroyRef).onDestroy(() => scope.remove(self));\n }\n\n return self;\n}\n","import {\n computed,\n DestroyRef,\n inject,\n Injector,\n runInInjectionContext,\n signal,\n untracked,\n type ResourceStatus,\n type Signal,\n type WritableSignal,\n} from '@angular/core';\nimport {\n applyOps,\n diffOps,\n injectTransitionScope,\n toStore,\n type SignalStore,\n type WritableSignalStore,\n} from '@mmstack/primitives';\nimport {\n deserializeError,\n type IsWritableKey,\n type StoreKeys,\n type StoreValueOf,\n type WorkerEnvelope,\n type WorkerSchema,\n} from '@mmstack/worker/protocol';\nimport {\n WorkerAbortError,\n WorkerCrashedError,\n type WorkerRef,\n} from './connect-worker';\n\nexport type WorkerStoreOptions<T> = {\n readonly injector?: Injector;\n /** Value the replica holds before the first snapshot arrives. */\n readonly defaultValue?: T;\n /** Register into the nearest transition scope while hydrating/reloading. */\n readonly register?: false | 'indicator' | 'suspend';\n};\n\n/** The write path — present only on OWNED (writable) subtrees; absent on published (read-only) ones. */\nexport type WorkerStoreWrite<T> = {\n /**\n * Route a write to the OWNER: run `recipe` against a writable draft of the current replica, diff\n * it to ops, ship them. Resolves once the owner's authoritative batch carrying this write has been\n * applied to THIS replica (honest async — the value is not applied locally first; for optimistic\n * UI, fork the replica and reconcile on resolve). Rejects if the owner reports a write error.\n */\n write(recipe: (draft: WritableSignalStore<T>) => void): Promise<void>;\n};\n\nexport type WorkerStoreRef<T, W extends boolean = true> = {\n /** The live, READ-ONLY replica — deep per-leaf reads, mirrored from the worker-owned subtree. */\n readonly store: SignalStore<T>;\n /** The replica root value (undefined before hydration). */\n readonly value: Signal<T | undefined>;\n readonly status: Signal<ResourceStatus>;\n readonly error: Signal<unknown>;\n readonly isLoading: Signal<boolean>;\n /** The underlying worker connection's liveness. */\n readonly connected: Signal<boolean>;\n hasValue(): boolean;\n destroy(): void;\n} & (W extends true ? WorkerStoreWrite<T> : object);\n\n/**\n * A live READ-ONLY replica of a store subtree OWNED by the worker. Subscribes over the\n * {@link WorkerRef}, hydrates from the owner's snapshot, then applies each authoritative op batch\n * into a main-thread `store` — one `set` per batch, so a batch of N ops is a single notification\n * wave. Satisfies `ResourceLike`/`UseSource`, so it participates in transition scopes and nests in\n * `latest()`/`use()`. Writes are not local: they route to the owner (added in the next step).\n */\n// manifest-driven: key constrained to the worker's stores/published, value inferred, and `write()`\n// present only for OWNED keys\nexport function workerStore<M extends WorkerSchema, K extends StoreKeys<M>>(\n worker: WorkerRef<M>,\n key: K,\n opt?: WorkerStoreOptions<StoreValueOf<M, K> & object>,\n): WorkerStoreRef<StoreValueOf<M, K> & object, IsWritableKey<M, K>>;\n// explicit-value: for an untyped connection, or to override the inferred type\nexport function workerStore<T extends object>(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<T>,\n): WorkerStoreRef<T, true>;\nexport function workerStore(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<any>,\n): WorkerStoreRef<any, boolean> {\n const injector = opt?.injector ?? inject(Injector);\n return runInInjectionContext(injector, () => build(worker, key, opt));\n}\n\nfunction build<T extends object>(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<T>,\n): WorkerStoreRef<T, true> {\n const injector = inject(Injector); // captured for use in write() (called outside injection context)\n const root = signal<T | undefined>(opt?.defaultValue);\n // shape-adaptive: the store reflects `root` even as it goes undefined → object on first snapshot\n const replica = toStore(root as unknown as WritableSignal<T>, {\n injector,\n }) as SignalStore<T>;\n\n const status = signal<ResourceStatus>('loading');\n const error = signal<unknown>(undefined);\n const isLoading = computed(() => {\n const s = status();\n return s === 'loading' || s === 'reloading';\n });\n let hasSnapshot = false;\n let resyncing = false; // awaiting a fresh snapshot after a detected gap\n let lastVersion = 0;\n let writeSeq = 0;\n const writePending = new Map<\n number,\n { resolve: () => void; reject: (e: unknown) => void; version: number | null }\n >();\n\n const hasValue = () => hasSnapshot;\n\n // resolve any write whose acked authoritative version has now been applied to this replica\n const settleWrites = () => {\n for (const [id, p] of writePending) {\n if (p.version !== null && lastVersion >= p.version) {\n writePending.delete(id);\n p.resolve();\n }\n }\n };\n\n const onStoreMessage = (msg: WorkerEnvelope): void => {\n if (!('store' in msg) || msg.store !== key) return;\n switch (msg.type) {\n case 'store:snapshot': {\n root.set(msg.value as T);\n lastVersion = msg.version;\n hasSnapshot = true;\n resyncing = false; // a fresh snapshot ends any resync\n status.set('resolved');\n error.set(undefined);\n settleWrites();\n return;\n }\n case 'store:ops': {\n if (!hasSnapshot || resyncing) return; // pre-hydration, or dropping until a fresh snapshot\n if (msg.batch.version <= lastVersion) return; // stale/duplicate (at-least-once transport)\n if (msg.batch.version > lastVersion + 1) {\n // GAP: a batch was lost — re-hydrate from a fresh snapshot rather than apply out of order\n resync();\n return;\n }\n root.set(applyOps(untracked(root) as T, msg.batch.ops));\n lastVersion = msg.batch.version;\n settleWrites();\n return;\n }\n case 'store:write:ack': {\n const p = writePending.get(msg.writeId);\n if (!p) return;\n if (lastVersion >= msg.version) {\n writePending.delete(msg.writeId);\n p.resolve(); // the authoritative batch already landed (FIFO: ops precede the ack)\n } else {\n p.version = msg.version; // resolve once a batch reaches this version\n }\n return;\n }\n case 'store:write:error': {\n const p = writePending.get(msg.writeId);\n if (p) {\n writePending.delete(msg.writeId);\n p.reject(deserializeError(msg.error));\n }\n return;\n }\n case 'store:status': {\n // rung 3: a published derivation's remote status → this replica's status, so an in-flight\n // worker computation shows as pending on the main thread (holding the last value)\n switch (msg.status) {\n case 'error':\n error.set(msg.error ? deserializeError(msg.error) : new Error('remote computation error'));\n status.set('error');\n return;\n case 'loading':\n case 'reloading':\n error.set(undefined);\n status.set(hasSnapshot ? 'reloading' : 'loading'); // hold the value while recomputing\n return;\n case 'resolved':\n error.set(undefined);\n if (hasSnapshot) status.set('resolved');\n return;\n default:\n return;\n }\n }\n }\n };\n\n const subscribe = (): void => {\n if (hasSnapshot) status.set('reloading'); // holding stale while the fresh snapshot lands\n worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });\n };\n\n // a lost batch left a version gap — hold the stale value and re-subscribe for a fresh snapshot\n const resync = (): void => {\n resyncing = true;\n status.set('reloading');\n worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });\n };\n\n const unsub = worker._subscribe(onStoreMessage);\n // subscribe on each `ready` — the first connection and every auto-restart re-hydration; if the\n // connection is ALREADY up (created post-handshake), `_onReady` won't fire, so subscribe now\n const offReady = worker._onReady(subscribe);\n if (untracked(worker.connected)) subscribe();\n // a crash can't be delivered — pending writes reject (the caller holds the value + recipe to retry)\n const offDisconnect = worker._onDisconnect(() => {\n for (const [, p] of writePending) p.reject(new WorkerCrashedError());\n writePending.clear();\n });\n\n const self: WorkerStoreRef<T> = {\n store: replica,\n value: root.asReadonly(),\n status,\n error,\n isLoading,\n connected: worker.connected,\n hasValue,\n write: (recipe) => {\n const base = untracked(root);\n if (base === undefined)\n return Promise.reject(\n new Error('[@mmstack/worker] cannot write before the replica has hydrated'),\n );\n // hydrated but disconnected = the worker crashed (or is restarting) — a write posted now\n // vanishes into a dead port and its echo can never arrive. Reject; the caller retries.\n if (!untracked(worker.connected))\n return Promise.reject(new WorkerCrashedError('worker is not connected'));\n // fork-diff: a scratch store seeded with the CURRENT value (same ref → copy-on-write keeps\n // untouched subtrees shared), so diffOps against the base is O(changed paths)\n const scratch = signal(base);\n const scratchStore = toStore(scratch as unknown as WritableSignal<T>, {\n injector,\n }) as unknown as WritableSignalStore<T>;\n recipe(scratchStore);\n const ops = diffOps(base, untracked(scratch));\n if (!ops.length) return Promise.resolve();\n\n const writeId = ++writeSeq;\n return new Promise<void>((resolve, reject) => {\n writePending.set(writeId, { resolve, reject, version: null });\n worker._send({\n type: 'store:write',\n store: key,\n writeId,\n clientId: worker.clientId,\n ops,\n });\n });\n },\n destroy: () => {\n unsub();\n offReady();\n offDisconnect();\n // acks can no longer be received — settle any in-flight write instead of dangling it\n for (const [, p] of writePending)\n p.reject(new WorkerAbortError('worker store destroyed'));\n writePending.clear();\n worker._send({ type: 'store:unsubscribe', store: key, clientId: worker.clientId });\n },\n };\n\n inject(DestroyRef).onDestroy(() => self.destroy());\n\n if (opt?.register) {\n const scope = injectTransitionScope();\n scope.add(self, { suspends: opt.register === 'suspend' });\n inject(DestroyRef).onDestroy(() => scope.remove(self));\n }\n\n return self;\n}\n","// shared wire types, re-exported so main-thread consumers import only from '@mmstack/worker'\nexport * from '@mmstack/worker/protocol';\n\nexport {\n connectWorker,\n WorkerAbortError,\n WorkerCrashedError,\n type ConnectWorkerOptions,\n type WorkerManifest,\n type WorkerRef,\n} from './lib/connect-worker';\nexport {\n PAUSED,\n workerResource,\n type WorkerParamsFn,\n type WorkerRequestContext,\n type WorkerResourceOptions,\n type WorkerResourceRef,\n} from './lib/worker-resource';\nexport {\n workerStore,\n type WorkerStoreOptions,\n type WorkerStoreRef,\n} from './lib/worker-store';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["build"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mmstack-worker.mjs","sources":["../../../../packages/worker/src/lib/connect-worker.ts","../../../../packages/worker/src/lib/worker-resource.ts","../../../../packages/worker/src/lib/worker-store.ts","../../../../packages/worker/src/mmstack-worker.ts"],"sourcesContent":["import {\n DestroyRef,\n inject,\n Injector,\n PLATFORM_ID,\n runInInjectionContext,\n signal,\n type Signal,\n} from '@angular/core';\nimport {\n closePort,\n deserializeError,\n generateId,\n takeTransferables,\n type HasSchema,\n type SchemaOf,\n type TaskInput,\n type TaskOutput,\n type WorkerEnvelope,\n type WorkerPortLike,\n type WorkerSchema,\n} from '@mmstack/worker/protocol';\n\n/** What the worker advertised in its `ready` handshake. */\nexport type WorkerManifest = {\n readonly hostId: string;\n readonly stores: readonly string[];\n readonly published: readonly string[];\n readonly tasks: readonly string[];\n};\n\n/** Thrown into a task/write promise when it is aborted. `name` is `'AbortError'` (DOM convention). */\nexport class WorkerAbortError extends Error {\n constructor(message = 'The worker task was aborted') {\n super(message);\n this.name = 'AbortError';\n }\n}\n\n/** Thrown into pending tasks/writes when the worker crashes. `name` is `'WorkerCrashedError'`. */\nexport class WorkerCrashedError extends Error {\n constructor(message = 'The worker crashed') {\n super(message);\n this.name = 'WorkerCrashedError';\n }\n}\n\nexport type ConnectWorkerOptions = {\n readonly injector?: Injector;\n /** `'auto'` (default) respawns on crash; `'manual'` surfaces disconnect and stops. */\n readonly restart?: 'auto' | 'manual';\n /** Backoff before respawn attempt `n` (0-based). Default exponential 1s→30s. */\n readonly restartDelay?: (attempt: number) => number;\n};\n\nexport type WorkerRef<M extends WorkerSchema = WorkerSchema> = HasSchema<M> & {\n /** True once the `ready` handshake has completed (and again after an auto-restart). */\n readonly connected: Signal<boolean>;\n /** The worker's advertised manifest, or `null` before the first `ready`. */\n readonly manifest: Signal<WorkerManifest | null>;\n /** Run a named task exposed by the worker host; resolves with its result (typed from the schema). */\n runTask<K extends keyof M['tasks'] & string>(\n task: K,\n input: TaskInput<M, K>,\n opt?: { signal?: AbortSignal; transfer?: Transferable[] },\n ): Promise<TaskOutput<M, K>>;\n destroy(): void;\n\n /** @internal Post an envelope to the worker. */\n _send(msg: WorkerEnvelope, transfer?: Transferable[]): void;\n /** @internal Receive every non-task envelope (store traffic). Returns an unsubscribe. */\n _subscribe(handler: (msg: WorkerEnvelope) => void): () => void;\n /** @internal Run `fn` on every (re)connection — used to re-subscribe stores after a restart. */\n _onReady(fn: () => void): () => void;\n /** @internal Run `fn` when the connection drops (crash) — replicas reject pending writes here. */\n _onDisconnect(fn: () => void): () => void;\n /** @internal This client's identity on the transport. */\n readonly clientId: string;\n};\n\n/**\n * Connects the main thread to a worker over a {@link WorkerPortLike} the caller provides via `spawn`\n * — typically `() => new Worker(new URL('./my.worker', import.meta.url), { type: 'module' })` (the\n * URL literal must live in APP code so the bundler emits the worker chunk). Performs the hello/ready\n * handshake, exposes `connected`/`manifest`, routes named-task runs, and (via internal seams)\n * carries the store-replication traffic for {@link workerStore}. On crash it respawns with backoff\n * when `restart: 'auto'`.\n */\nexport function connectWorker<H = WorkerSchema>(\n spawn: () => WorkerPortLike,\n opt?: ConnectWorkerOptions,\n): WorkerRef<SchemaOf<H>> {\n const injector = opt?.injector ?? inject(Injector);\n return runInInjectionContext(injector, () =>\n build(spawn, opt),\n ) as unknown as WorkerRef<SchemaOf<H>>;\n}\n\nfunction build(\n spawn: () => WorkerPortLike,\n opt?: ConnectWorkerOptions,\n): WorkerRef {\n const isServer = inject(PLATFORM_ID) === 'server';\n const clientId = generateId();\n const connected = signal(false);\n const manifest = signal<WorkerManifest | null>(null);\n\n const taskPending = new Map<number, { resolve: (v: any) => void; reject: (e: unknown) => void }>();\n const storeHandlers = new Set<(msg: WorkerEnvelope) => void>();\n const readyHooks = new Set<() => void>();\n const disconnectHooks = new Set<() => void>();\n const restart = opt?.restart ?? 'auto';\n const restartDelay = opt?.restartDelay ?? ((n: number) => Math.min(30_000, 1000 * 2 ** n));\n let attempt = 0;\n let runIdSeq = 0;\n let destroyed = false;\n let crashed = false;\n let port: WorkerPortLike = null as unknown as WorkerPortLike;\n\n const send = (msg: WorkerEnvelope, transfer?: Transferable[]): void => {\n if (port) port.postMessage(msg, transfer);\n };\n\n const onMessage = (msg: WorkerEnvelope): void => {\n switch (msg.type) {\n case 'ready':\n attempt = 0;\n crashed = false;\n manifest.set({\n hostId: msg.hostId,\n stores: msg.stores,\n published: msg.published,\n tasks: msg.tasks,\n });\n connected.set(true);\n for (const hook of readyHooks) hook();\n return;\n case 'task:ok': {\n const p = taskPending.get(msg.runId);\n if (p) {\n taskPending.delete(msg.runId);\n p.resolve(msg.value);\n }\n return;\n }\n case 'task:error': {\n const p = taskPending.get(msg.runId);\n if (p) {\n taskPending.delete(msg.runId);\n p.reject(deserializeError(msg.error));\n }\n return;\n }\n case 'task:aborted':\n taskPending.delete(msg.runId);\n return;\n default:\n for (const h of storeHandlers) h(msg);\n }\n };\n\n const handleCrash = (): void => {\n if (destroyed) return;\n crashed = true;\n connected.set(false);\n for (const [, p] of taskPending) p.reject(new WorkerCrashedError());\n taskPending.clear();\n for (const fn of disconnectHooks) fn();\n if (restart === 'manual') return;\n const delay = restartDelay(attempt++);\n setTimeout(() => {\n if (!destroyed) openPort();\n }, delay);\n };\n\n const openPort = (): void => {\n if (port) closePort(port);\n port = spawn();\n port.onmessage = (ev) => onMessage(ev.data as WorkerEnvelope);\n // crash detection via property setters, not addEventListener (perturbs node MessagePort delivery)\n const evt = port as unknown as {\n onerror?: ((e?: unknown) => void) | null;\n onmessageerror?: ((e?: unknown) => void) | null;\n };\n if ('onerror' in evt) evt.onerror = handleCrash;\n if ('onmessageerror' in evt) evt.onmessageerror = handleCrash;\n send({ type: 'hello', proto: 1, clientId });\n };\n\n if (!isServer) openPort();\n\n inject(DestroyRef).onDestroy(() => teardown());\n\n const teardown = (): void => {\n destroyed = true;\n connected.set(false);\n for (const [, p] of taskPending) p.reject(new WorkerAbortError('worker connection destroyed'));\n taskPending.clear();\n for (const fn of disconnectHooks) fn();\n if (port) closePort(port);\n };\n\n return {\n connected,\n manifest,\n clientId,\n runTask(\n task: string,\n input: unknown,\n o?: { signal?: AbortSignal; transfer?: Transferable[] },\n ): Promise<unknown> {\n if (isServer) return Promise.reject(new WorkerCrashedError('no worker on the server'));\n if (destroyed) return Promise.reject(new WorkerAbortError('worker connection destroyed'));\n if (crashed) return Promise.reject(new WorkerCrashedError('worker is restarting'));\n if (o?.signal?.aborted) return Promise.reject(new WorkerAbortError());\n const runId = ++runIdSeq;\n return new Promise<unknown>((resolve, reject) => {\n taskPending.set(runId, { resolve, reject });\n send(\n { type: 'task:run', runId, task, input },\n o?.transfer ?? takeTransferables(input),\n );\n o?.signal?.addEventListener(\n 'abort',\n () => {\n if (!taskPending.has(runId)) return;\n taskPending.delete(runId);\n send({ type: 'task:abort', runId });\n reject(new WorkerAbortError());\n },\n { once: true },\n );\n });\n },\n destroy: teardown,\n _send: send,\n _subscribe(handler) {\n storeHandlers.add(handler);\n return () => storeHandlers.delete(handler);\n },\n _onReady(fn) {\n readyHooks.add(fn);\n return () => readyHooks.delete(fn);\n },\n _onDisconnect(fn) {\n disconnectHooks.add(fn);\n return () => disconnectHooks.delete(fn);\n },\n };\n}\n","import {\n computed,\n DestroyRef,\n effect,\n inject,\n Injector,\n PLATFORM_ID,\n runInInjectionContext,\n signal,\n untracked,\n type ResourceStatus,\n type Signal,\n type ValueEqualityFn,\n} from '@angular/core';\nimport { injectTransitionScope } from '@mmstack/primitives';\nimport { WorkerAbortError, type WorkerRef } from './connect-worker';\n\n/** Returned from a paused `params` fn to HOLD (keep the current value/status, run nothing). */\nexport const PAUSED: unique symbol = Symbol('@mmstack/worker:PAUSED');\n\nexport type WorkerRequestContext = { readonly paused: typeof PAUSED };\n\n/**\n * Reactive input producer. Reads signals to derive the task input; return `undefined` to disable\n * (idle, no run), or `ctx.paused` to hold. Re-runs when the returned input changes (by `Object.is`).\n */\nexport type WorkerParamsFn<TInput> = (\n ctx: WorkerRequestContext,\n) => TInput | undefined | void | typeof PAUSED;\n\nexport type WorkerResourceOptions<TResult> = {\n readonly injector?: Injector;\n /** Equality for the result value — a run resolving equal to the held value emits no notification. */\n readonly equal?: ValueEqualityFn<TResult>;\n readonly defaultValue?: TResult;\n /**\n * Hold the previous value through a re-run (status `'reloading'`) instead of clearing it. Default\n * TRUE — a `workerResource` is an async derivation, not a fetch; flashing empty mid-recompute is\n * rarely wanted.\n */\n readonly keepPrevious?: boolean;\n /** Register into the nearest transition scope: `'indicator'` drives pending, `'suspend'` also gates first paint. */\n readonly register?: false | 'indicator' | 'suspend';\n /** The connected worker whose host exposes the task. */\n readonly worker: WorkerRef;\n /** The name of the task to run (as declared in `createWorkerHost({ tasks })`). */\n readonly task: string;\n};\n\nexport type WorkerResourceRef<T> = {\n /** The latest successfully-computed value (held through re-runs per `keepPrevious`). */\n readonly value: Signal<T | undefined>;\n readonly status: Signal<ResourceStatus>;\n readonly error: Signal<unknown>;\n readonly isLoading: Signal<boolean>;\n hasValue(): boolean;\n /** Re-run with the current input, bypassing input de-duplication. */\n reload(): void;\n /** Cancel the in-flight run; the value is KEPT and status becomes `'local'`. */\n abort(): void;\n destroy(): void;\n};\n\n/**\n * Runs a named task on a connected worker, exposed with the standard resource surface so heavy\n * compute makes the UI *pending*, not *frozen*. `params` reactively derives the input; latest-wins\n * (a changed input supersedes and aborts the in-flight run); the result surfaces as\n * `value`/`status`/`error`, and — with `register` — participates in transition scopes. No-ops on the\n * server.\n */\nexport function workerResource<TInput, TResult>(\n params: WorkerParamsFn<TInput>,\n options: WorkerResourceOptions<TResult>,\n): WorkerResourceRef<TResult> {\n const injector = options.injector ?? inject(Injector);\n return runInInjectionContext(injector, () => build<TInput, TResult>(params, options));\n}\n\nfunction build<TInput, TResult>(\n params: WorkerParamsFn<TInput>,\n options: WorkerResourceOptions<TResult>,\n): WorkerResourceRef<TResult> {\n const isServer = inject(PLATFORM_ID) === 'server';\n const keepPrevious = options.keepPrevious ?? true;\n const userEqual = options.equal;\n const { worker, task } = options;\n\n const runTask = (input: TInput, signal: AbortSignal): Promise<TResult> =>\n worker.runTask(task, input, { signal }) as Promise<TResult>;\n\n const value = signal<TResult | undefined>(options.defaultValue, {\n equal: userEqual\n ? (a, b) => (a === undefined || b === undefined ? a === b : userEqual(a, b))\n : undefined,\n });\n const status = signal<ResourceStatus>('idle');\n const error = signal<unknown>(undefined);\n const isLoading = computed(() => {\n const s = status();\n return s === 'loading' || s === 'reloading';\n });\n const hasValue = () => value() !== undefined;\n\n let epoch = 0;\n let inFlight: AbortController | null = null;\n let lastInput: TInput | undefined;\n let hasRun = false;\n\n const start = (input: TInput): void => {\n const myEpoch = ++epoch;\n inFlight?.abort();\n const ac = new AbortController();\n inFlight = ac;\n lastInput = input;\n hasRun = true;\n status.set(keepPrevious && value() !== undefined ? 'reloading' : 'loading');\n error.set(undefined);\n\n runTask(input, ac.signal).then(\n (result) => {\n if (inFlight === ac) inFlight = null;\n if (myEpoch !== epoch) return;\n value.set(result);\n status.set('resolved');\n },\n (err) => {\n if (inFlight === ac) inFlight = null;\n if (myEpoch !== epoch) return;\n if (err instanceof WorkerAbortError || (err as { name?: string })?.name === 'AbortError')\n return;\n error.set(err);\n status.set('error');\n },\n );\n };\n\n const input = computed(() => params({ paused: PAUSED }));\n\n const ref = effect(() => {\n const i = input();\n if (isServer || i === PAUSED) return;\n if (i === undefined) return;\n if (Object.is(i, lastInput) && hasRun && untracked(status) !== 'error') return;\n untracked(() => start(i as TInput));\n });\n\n inject(DestroyRef).onDestroy(() => {\n epoch++;\n inFlight?.abort();\n });\n\n const self: WorkerResourceRef<TResult> = {\n value,\n status,\n error,\n isLoading,\n hasValue,\n reload: () => {\n const i = untracked(input);\n if (isServer || i === PAUSED || i === undefined) return;\n start(i as TInput);\n },\n abort: () => {\n if (!inFlight) return;\n epoch++;\n inFlight.abort();\n inFlight = null;\n status.set('local');\n },\n destroy: () => {\n epoch++;\n inFlight?.abort();\n ref.destroy();\n },\n };\n\n if (options.register) {\n const scope = injectTransitionScope();\n scope.add(self, { suspends: options.register === 'suspend' });\n let removed = false;\n const remove = () => {\n if (removed) return;\n removed = true;\n scope.remove(self);\n };\n inject(DestroyRef).onDestroy(remove);\n const destroy = self.destroy;\n self.destroy = () => {\n remove();\n destroy();\n };\n }\n\n return self;\n}\n","import {\n computed,\n DestroyRef,\n inject,\n Injector,\n runInInjectionContext,\n signal,\n untracked,\n type ResourceStatus,\n type Signal,\n type WritableSignal,\n} from '@angular/core';\nimport { createWatch } from '@angular/core/primitives/signals';\nimport {\n injectTransitionScope,\n opSync,\n toStore,\n type OpEnvelope,\n type OpLogDriver,\n type SignalStore,\n type WritableSignalStore,\n} from '@mmstack/primitives';\nimport {\n deserializeError,\n type IsWritableKey,\n type StoreKeys,\n type StoreValueOf,\n type WorkerEnvelope,\n type WorkerSchema,\n} from '@mmstack/worker/protocol';\nimport {\n WorkerAbortError,\n WorkerCrashedError,\n type WorkerRef,\n} from './connect-worker';\n\n// An injector-free opLog driver (schedules emission off the microtask queue via `createWatch`), so\n// the replica's `opSync` emits without depending on an application tick. Writes force a synchronous\n// `flush()` at the call site; between writes, owner envelopes drive apply, never local emission.\nconst microtaskDriver = (): OpLogDriver => (run) => {\n let scheduled = false;\n const watch = createWatch(\n () => run(),\n (w) => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n w.run();\n });\n },\n false,\n );\n watch.notify();\n return { destroy: () => watch.destroy() };\n};\n\nexport type WorkerStoreOptions<T> = {\n readonly injector?: Injector;\n /** Value the replica holds before the first snapshot arrives. */\n readonly defaultValue?: T;\n /** Register into the nearest transition scope while hydrating/reloading. */\n readonly register?: false | 'indicator' | 'suspend';\n};\n\n/** The write path — present only on OWNED (writable) subtrees; absent on published (read-only) ones. */\nexport type WorkerStoreWrite<T> = {\n /**\n * Route a write to the OWNER: `recipe` applies optimistically to the store, its diff ships as a\n * stamped op envelope, and the owner folds it in and echoes it back. Resolves once the owner has\n * acknowledged it (its echo reconciles this replica). The owner can override with a higher-epoch\n * correction that wins the merge. To hide the value until the owner confirms it, fork the store\n * and reveal on resolve. Rejects if the worker is disconnected or the store is read-only.\n */\n write(recipe: (draft: WritableSignalStore<T>) => void): Promise<void>;\n};\n\nexport type WorkerStoreRef<T, W extends boolean = true> = {\n /**\n * The live store. For an OWNED subtree it is a full {@link WritableSignalStore}: writes apply\n * optimistically and route to the owner, and other op-log readers (`meshSync`, `persist`) can\n * attach to it. For a PUBLISHED subtree it is a read-only {@link SignalStore} mirror.\n */\n readonly store: W extends true ? WritableSignalStore<T> : SignalStore<T>;\n /** The replica root value (undefined before hydration). */\n readonly value: Signal<T | undefined>;\n readonly status: Signal<ResourceStatus>;\n readonly error: Signal<unknown>;\n readonly isLoading: Signal<boolean>;\n /** The underlying worker connection's liveness. */\n readonly connected: Signal<boolean>;\n hasValue(): boolean;\n destroy(): void;\n} & (W extends true ? WorkerStoreWrite<T> : object);\n\n/**\n * A live replica of a store subtree OWNED by the worker. It runs its own `opSync` over the worker\n * transport: it hydrates from the owner's checkpoint, then folds each owner (or peer) envelope into\n * a main-thread `store` convergently. For an owned subtree the store is WRITABLE: a write applies\n * optimistically and its stamped envelope routes to the owner (which folds it and echoes it back),\n * and any op-log reader — `meshSync`, `persist` — can attach to the same store, so a persisted,\n * meshed, worker-owned graph is just extra readers. Satisfies `ResourceLike`/`UseSource`, so it\n * participates in transition scopes and nests in `latest()`/`use()`.\n */\nexport function workerStore<M extends WorkerSchema, K extends StoreKeys<M>>(\n worker: WorkerRef<M>,\n key: K,\n opt?: WorkerStoreOptions<StoreValueOf<M, K> & object>,\n): WorkerStoreRef<StoreValueOf<M, K> & object, IsWritableKey<M, K>>;\nexport function workerStore<T extends object>(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<T>,\n): WorkerStoreRef<T, true>;\nexport function workerStore(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<any>,\n): WorkerStoreRef<any, boolean> {\n const injector = opt?.injector ?? inject(Injector);\n return runInInjectionContext(injector, () => build(worker, key, opt));\n}\n\nfunction build<T extends object>(\n worker: WorkerRef,\n key: string,\n opt?: WorkerStoreOptions<T>,\n): WorkerStoreRef<T, true> {\n const injector = inject(Injector);\n const root = signal<T | undefined>(opt?.defaultValue);\n const s = toStore(root as unknown as WritableSignal<T>, {\n injector,\n }) as unknown as WritableSignalStore<T>;\n // The replica runs its own opSync over the worker transport: local writes emit stamped envelopes\n // routed to the owner, owner envelopes fold in convergently. A driver (not the injector) so\n // emission stays synchronous under an explicit `flush()`, matching the DI-free worker model.\n const sync = opSync(root as unknown as WritableSignal<T>, {\n writer: worker.clientId,\n driver: microtaskDriver(),\n onGap: () => resync(),\n });\n\n const status = signal<ResourceStatus>('loading');\n const error = signal<unknown>(undefined);\n const isLoading = computed(() => {\n const st = status();\n return st === 'loading' || st === 'reloading';\n });\n let hasSnapshot = false;\n let lastEmitted = 0; // highest own-origin version emitted; the write() ack key\n // own writes awaiting the owner's echo (resolve), plus the raw envelopes to resend after a resync\n const writePending = new Map<number, { resolve: () => void; reject: (e: unknown) => void }>();\n const unacked = new Map<number, OpEnvelope>();\n\n const hasValue = () => hasSnapshot;\n\n const isOwned = () => worker.manifest()?.stores.includes(key) ?? false;\n\n const ackUpTo = (version: number): void => {\n for (const [v, p] of writePending) {\n if (v <= version) {\n writePending.delete(v);\n p.resolve();\n }\n }\n for (const v of [...unacked.keys()]) if (v <= version) unacked.delete(v);\n };\n\n const shipUnsub = sync.subscribe((env) => {\n lastEmitted = env.version;\n unacked.set(env.version, env);\n if (isOwned() && untracked(worker.connected)) {\n worker._send({ type: 'store:sync', store: key, env });\n }\n });\n\n const onStoreMessage = (msg: WorkerEnvelope): void => {\n if (!('store' in msg) || msg.store !== key) return;\n switch (msg.type) {\n case 'store:checkpoint': {\n // rebase from the full unacked outbox, not opSync's bounded recent-local ring, so a burst\n // of writes larger than that ring is never dropped from the local rebase on re-hydrate\n sync.hydrate(\n msg.checkpoint as Parameters<typeof sync.hydrate>[0],\n [...unacked.values()],\n );\n hasSnapshot = true;\n status.set('resolved');\n error.set(undefined);\n // writes the owner already applied are covered by the checkpoint watermark; resolve them,\n // then resend any still-unacked tail so a write made before the (re)hydrate is never lost\n ackUpTo(msg.checkpoint.wm?.[sync.origin] ?? 0);\n if (isOwned() && untracked(worker.connected)) {\n for (const env of [...unacked.values()].sort((a, b) => a.version - b.version)) {\n worker._send({ type: 'store:sync', store: key, env });\n }\n }\n return;\n }\n case 'store:sync': {\n const env = msg.env;\n if (env.origin === sync.origin) {\n ackUpTo(env.version); // the owner echoed our own write back: acknowledgement\n return;\n }\n sync.receive(env); // owner or peer envelope; a version gap triggers onGap -> resync\n return;\n }\n case 'store:status': {\n switch (msg.status) {\n case 'error':\n error.set(msg.error ? deserializeError(msg.error) : new Error('remote computation error'));\n status.set('error');\n return;\n case 'loading':\n case 'reloading':\n error.set(undefined);\n status.set(hasSnapshot ? 'reloading' : 'loading');\n return;\n case 'resolved':\n error.set(undefined);\n if (hasSnapshot) status.set('resolved');\n return;\n default:\n return;\n }\n }\n }\n };\n\n const subscribe = (): void => {\n if (hasSnapshot) status.set('reloading');\n worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });\n };\n\n const resync = (): void => {\n status.set('reloading');\n worker._send({ type: 'store:subscribe', store: key, clientId: worker.clientId });\n };\n\n const unsub = worker._subscribe(onStoreMessage);\n const offReady = worker._onReady(subscribe);\n if (untracked(worker.connected)) subscribe(); // already up (created post-handshake): _onReady won't fire\n const offDisconnect = worker._onDisconnect(() => {\n for (const [, p] of writePending) p.reject(new WorkerCrashedError());\n writePending.clear();\n unacked.clear();\n });\n\n const self: WorkerStoreRef<T> = {\n store: s,\n value: root.asReadonly(),\n status,\n error,\n isLoading,\n connected: worker.connected,\n hasValue,\n write: (recipe) => {\n const base = untracked(root);\n if (base === undefined)\n return Promise.reject(\n new Error('[@mmstack/worker] cannot write before the replica has hydrated'),\n );\n if (!untracked(worker.connected))\n return Promise.reject(new WorkerCrashedError('worker is not connected'));\n if (!isOwned())\n return Promise.reject(\n new Error(`[@mmstack/worker] store is read-only (published): ${key}`),\n );\n recipe(s);\n const before = lastEmitted;\n sync.flush(); // emit the routed write synchronously (driver-backed opSync)\n if (lastEmitted === before) return Promise.resolve(); // no-op recipe: nothing shipped\n const version = lastEmitted;\n return new Promise<void>((resolve, reject) => {\n writePending.set(version, { resolve, reject });\n });\n },\n destroy: () => {\n shipUnsub();\n sync.destroy();\n unsub();\n offReady();\n offDisconnect();\n for (const [, p] of writePending)\n p.reject(new WorkerAbortError('worker store destroyed'));\n writePending.clear();\n unacked.clear();\n worker._send({ type: 'store:unsubscribe', store: key, clientId: worker.clientId });\n },\n };\n\n inject(DestroyRef).onDestroy(() => self.destroy());\n\n if (opt?.register) {\n const scope = injectTransitionScope();\n scope.add(self, { suspends: opt.register === 'suspend' });\n let removed = false;\n const remove = () => {\n if (removed) return;\n removed = true;\n scope.remove(self);\n };\n inject(DestroyRef).onDestroy(remove);\n const destroy = self.destroy;\n self.destroy = () => {\n remove();\n destroy();\n };\n }\n\n return self;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["build"],"mappings":";;;;;;AA+BA;AACM,MAAO,gBAAiB,SAAQ,KAAK,CAAA;IACzC,WAAA,CAAY,OAAO,GAAG,6BAA6B,EAAA;QACjD,KAAK,CAAC,OAAO,CAAC;AACd,QAAA,IAAI,CAAC,IAAI,GAAG,YAAY;IAC1B;AACD;AAED;AACM,MAAO,kBAAmB,SAAQ,KAAK,CAAA;IAC3C,WAAA,CAAY,OAAO,GAAG,oBAAoB,EAAA;QACxC,KAAK,CAAC,OAAO,CAAC;AACd,QAAA,IAAI,CAAC,IAAI,GAAG,oBAAoB;IAClC;AACD;AAmCD;;;;;;;AAOG;AACG,SAAU,aAAa,CAC3B,KAA2B,EAC3B,GAA0B,EAAA;IAE1B,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;AAClD,IAAA,OAAO,qBAAqB,CAAC,QAAQ,EAAE,MACrCA,OAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CACmB;AACxC;AAEA,SAASA,OAAK,CACZ,KAA2B,EAC3B,GAA0B,EAAA;IAE1B,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ;AACjD,IAAA,MAAM,QAAQ,GAAG,UAAU,EAAE;AAC7B,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK;kFAAC;AAC/B,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAwB,IAAI;iFAAC;AAEpD,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuE;AAClG,IAAA,MAAM,aAAa,GAAG,IAAI,GAAG,EAAiC;AAC9D,IAAA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAc;AACxC,IAAA,MAAM,eAAe,GAAG,IAAI,GAAG,EAAc;AAC7C,IAAA,MAAM,OAAO,GAAG,GAAG,EAAE,OAAO,IAAI,MAAM;IACtC,MAAM,YAAY,GAAG,GAAG,EAAE,YAAY,KAAK,CAAC,CAAS,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1F,IAAI,OAAO,GAAG,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC;IAChB,IAAI,SAAS,GAAG,KAAK;IACrB,IAAI,OAAO,GAAG,KAAK;IACnB,IAAI,IAAI,GAAmB,IAAiC;AAE5D,IAAA,MAAM,IAAI,GAAG,CAAC,GAAmB,EAAE,QAAyB,KAAU;AACpE,QAAA,IAAI,IAAI;AAAE,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC;AAC3C,IAAA,CAAC;AAED,IAAA,MAAM,SAAS,GAAG,CAAC,GAAmB,KAAU;AAC9C,QAAA,QAAQ,GAAG,CAAC,IAAI;AACd,YAAA,KAAK,OAAO;gBACV,OAAO,GAAG,CAAC;gBACX,OAAO,GAAG,KAAK;gBACf,QAAQ,CAAC,GAAG,CAAC;oBACX,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,KAAK,EAAE,GAAG,CAAC,KAAK;AACjB,iBAAA,CAAC;AACF,gBAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnB,KAAK,MAAM,IAAI,IAAI,UAAU;AAAE,oBAAA,IAAI,EAAE;gBACrC;YACF,KAAK,SAAS,EAAE;gBACd,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpC,IAAI,CAAC,EAAE;AACL,oBAAA,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7B,oBAAA,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;gBACtB;gBACA;YACF;YACA,KAAK,YAAY,EAAE;gBACjB,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpC,IAAI,CAAC,EAAE;AACL,oBAAA,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;oBAC7B,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACvC;gBACA;YACF;AACA,YAAA,KAAK,cAAc;AACjB,gBAAA,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC7B;AACF,YAAA;gBACE,KAAK,MAAM,CAAC,IAAI,aAAa;oBAAE,CAAC,CAAC,GAAG,CAAC;;AAE3C,IAAA,CAAC;IAED,MAAM,WAAW,GAAG,MAAW;AAC7B,QAAA,IAAI,SAAS;YAAE;QACf,OAAO,GAAG,IAAI;AACd,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,WAAW;AAAE,YAAA,CAAC,CAAC,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC;QACnE,WAAW,CAAC,KAAK,EAAE;QACnB,KAAK,MAAM,EAAE,IAAI,eAAe;AAAE,YAAA,EAAE,EAAE;QACtC,IAAI,OAAO,KAAK,QAAQ;YAAE;AAC1B,QAAA,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC;QACrC,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,CAAC,SAAS;AAAE,gBAAA,QAAQ,EAAE;QAC5B,CAAC,EAAE,KAAK,CAAC;AACX,IAAA,CAAC;IAED,MAAM,QAAQ,GAAG,MAAW;AAC1B,QAAA,IAAI,IAAI;YAAE,SAAS,CAAC,IAAI,CAAC;QACzB,IAAI,GAAG,KAAK,EAAE;AACd,QAAA,IAAI,CAAC,SAAS,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,IAAsB,CAAC;;QAE7D,MAAM,GAAG,GAAG,IAGX;QACD,IAAI,SAAS,IAAI,GAAG;AAAE,YAAA,GAAG,CAAC,OAAO,GAAG,WAAW;QAC/C,IAAI,gBAAgB,IAAI,GAAG;AAAE,YAAA,GAAG,CAAC,cAAc,GAAG,WAAW;AAC7D,QAAA,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;AAC7C,IAAA,CAAC;AAED,IAAA,IAAI,CAAC,QAAQ;AAAE,QAAA,QAAQ,EAAE;AAEzB,IAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,QAAQ,EAAE,CAAC;IAE9C,MAAM,QAAQ,GAAG,MAAW;QAC1B,SAAS,GAAG,IAAI;AAChB,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,WAAW;YAAE,CAAC,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,6BAA6B,CAAC,CAAC;QAC9F,WAAW,CAAC,KAAK,EAAE;QACnB,KAAK,MAAM,EAAE,IAAI,eAAe;AAAE,YAAA,EAAE,EAAE;AACtC,QAAA,IAAI,IAAI;YAAE,SAAS,CAAC,IAAI,CAAC;AAC3B,IAAA,CAAC;IAED,OAAO;QACL,SAAS;QACT,QAAQ;QACR,QAAQ;AACR,QAAA,OAAO,CACL,IAAY,EACZ,KAAc,EACd,CAAuD,EAAA;AAEvD,YAAA,IAAI,QAAQ;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;AACtF,YAAA,IAAI,SAAS;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,6BAA6B,CAAC,CAAC;AACzF,YAAA,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;AAClF,YAAA,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;AACrE,YAAA,MAAM,KAAK,GAAG,EAAE,QAAQ;YACxB,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,KAAI;gBAC9C,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC3C,IAAI,CACF,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EACxC,CAAC,EAAE,QAAQ,IAAI,iBAAiB,CAAC,KAAK,CAAC,CACxC;gBACD,CAAC,EAAE,MAAM,EAAE,gBAAgB,CACzB,OAAO,EACP,MAAK;AACH,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;wBAAE;AAC7B,oBAAA,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;oBACzB,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACnC,oBAAA,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;AAChC,gBAAA,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf;AACH,YAAA,CAAC,CAAC;QACJ,CAAC;AACD,QAAA,OAAO,EAAE,QAAQ;AACjB,QAAA,KAAK,EAAE,IAAI;AACX,QAAA,UAAU,CAAC,OAAO,EAAA;AAChB,YAAA,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC;YAC1B,OAAO,MAAM,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC;QAC5C,CAAC;AACD,QAAA,QAAQ,CAAC,EAAE,EAAA;AACT,YAAA,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,CAAC;AACD,QAAA,aAAa,CAAC,EAAE,EAAA;AACd,YAAA,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,MAAM,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,CAAC;KACF;AACH;;ACxOA;MACa,MAAM,GAAkB,MAAM,CAAC,wBAAwB;AA6CpE;;;;;;AAMG;AACG,SAAU,cAAc,CAC5B,MAA8B,EAC9B,OAAuC,EAAA;IAEvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;AACrD,IAAA,OAAO,qBAAqB,CAAC,QAAQ,EAAE,MAAMA,OAAK,CAAkB,MAAM,EAAE,OAAO,CAAC,CAAC;AACvF;AAEA,SAASA,OAAK,CACZ,MAA8B,EAC9B,OAAuC,EAAA;IAEvC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ;AACjD,IAAA,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI;AACjD,IAAA,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK;AAC/B,IAAA,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO;IAEhC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,MAAmB,KACjD,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAqB;IAE7D,MAAM,KAAK,GAAG,MAAM,CAAsB,OAAO,CAAC,YAAY,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,OAAA,EAAA,8BAAA,EAAA,CAAA,EAC5D,KAAK,EAAE;AACL,cAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;cACzE,SAAS,EAAA,CACb;AACF,IAAA,MAAM,MAAM,GAAG,MAAM,CAAiB,MAAM;+EAAC;AAC7C,IAAA,MAAM,KAAK,GAAG,MAAM,CAAU,SAAS;8EAAC;AACxC,IAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAK;AAC9B,QAAA,MAAM,CAAC,GAAG,MAAM,EAAE;AAClB,QAAA,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,WAAW;IAC7C,CAAC;kFAAC;IACF,MAAM,QAAQ,GAAG,MAAM,KAAK,EAAE,KAAK,SAAS;IAE5C,IAAI,KAAK,GAAG,CAAC;IACb,IAAI,QAAQ,GAA2B,IAAI;AAC3C,IAAA,IAAI,SAA6B;IACjC,IAAI,MAAM,GAAG,KAAK;AAElB,IAAA,MAAM,KAAK,GAAG,CAAC,KAAa,KAAU;AACpC,QAAA,MAAM,OAAO,GAAG,EAAE,KAAK;QACvB,QAAQ,EAAE,KAAK,EAAE;AACjB,QAAA,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE;QAChC,QAAQ,GAAG,EAAE;QACb,SAAS,GAAG,KAAK;QACjB,MAAM,GAAG,IAAI;AACb,QAAA,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,KAAK,EAAE,KAAK,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAC3E,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AAEpB,QAAA,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAC5B,CAAC,MAAM,KAAI;YACT,IAAI,QAAQ,KAAK,EAAE;gBAAE,QAAQ,GAAG,IAAI;YACpC,IAAI,OAAO,KAAK,KAAK;gBAAE;AACvB,YAAA,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACjB,YAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;AACxB,QAAA,CAAC,EACD,CAAC,GAAG,KAAI;YACN,IAAI,QAAQ,KAAK,EAAE;gBAAE,QAAQ,GAAG,IAAI;YACpC,IAAI,OAAO,KAAK,KAAK;gBAAE;YACvB,IAAI,GAAG,YAAY,gBAAgB,IAAK,GAAyB,EAAE,IAAI,KAAK,YAAY;gBACtF;AACF,YAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AACd,YAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AACrB,QAAA,CAAC,CACF;AACH,IAAA,CAAC;AAED,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;8EAAC;AAExD,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,MAAK;AACtB,QAAA,MAAM,CAAC,GAAG,KAAK,EAAE;AACjB,QAAA,IAAI,QAAQ,IAAI,CAAC,KAAK,MAAM;YAAE;QAC9B,IAAI,CAAC,KAAK,SAAS;YAAE;AACrB,QAAA,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,OAAO;YAAE;QACxE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAW,CAAC,CAAC;IACrC,CAAC;4EAAC;AAEF,IAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAK;AAChC,QAAA,KAAK,EAAE;QACP,QAAQ,EAAE,KAAK,EAAE;AACnB,IAAA,CAAC,CAAC;AAEF,IAAA,MAAM,IAAI,GAA+B;QACvC,KAAK;QACL,MAAM;QACN,KAAK;QACL,SAAS;QACT,QAAQ;QACR,MAAM,EAAE,MAAK;AACX,YAAA,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC;YAC1B,IAAI,QAAQ,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,SAAS;gBAAE;YACjD,KAAK,CAAC,CAAW,CAAC;QACpB,CAAC;QACD,KAAK,EAAE,MAAK;AACV,YAAA,IAAI,CAAC,QAAQ;gBAAE;AACf,YAAA,KAAK,EAAE;YACP,QAAQ,CAAC,KAAK,EAAE;YAChB,QAAQ,GAAG,IAAI;AACf,YAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;QACrB,CAAC;QACD,OAAO,EAAE,MAAK;AACZ,YAAA,KAAK,EAAE;YACP,QAAQ,EAAE,KAAK,EAAE;YACjB,GAAG,CAAC,OAAO,EAAE;QACf,CAAC;KACF;AAED,IAAA,IAAI,OAAO,CAAC,QAAQ,EAAE;AACpB,QAAA,MAAM,KAAK,GAAG,qBAAqB,EAAE;AACrC,QAAA,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC7D,IAAI,OAAO,GAAG,KAAK;QACnB,MAAM,MAAM,GAAG,MAAK;AAClB,YAAA,IAAI,OAAO;gBAAE;YACb,OAAO,GAAG,IAAI;AACd,YAAA,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;AACpB,QAAA,CAAC;QACD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AACpC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;AAC5B,QAAA,IAAI,CAAC,OAAO,GAAG,MAAK;AAClB,YAAA,MAAM,EAAE;AACR,YAAA,OAAO,EAAE;AACX,QAAA,CAAC;IACH;AAEA,IAAA,OAAO,IAAI;AACb;;AC9JA;AACA;AACA;AACA,MAAM,eAAe,GAAG,MAAmB,CAAC,GAAG,KAAI;IACjD,IAAI,SAAS,GAAG,KAAK;AACrB,IAAA,MAAM,KAAK,GAAG,WAAW,CACvB,MAAM,GAAG,EAAE,EACX,CAAC,CAAC,KAAI;AACJ,QAAA,IAAI,SAAS;YAAE;QACf,SAAS,GAAG,IAAI;QAChB,cAAc,CAAC,MAAK;YAClB,SAAS,GAAG,KAAK;YACjB,CAAC,CAAC,GAAG,EAAE;AACT,QAAA,CAAC,CAAC;IACJ,CAAC,EACD,KAAK,CACN;IACD,KAAK,CAAC,MAAM,EAAE;IACd,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE;AAC3C,CAAC;SA2De,WAAW,CACzB,MAAiB,EACjB,GAAW,EACX,GAA6B,EAAA;IAE7B,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;AAClD,IAAA,OAAO,qBAAqB,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACvE;AAEA,SAAS,KAAK,CACZ,MAAiB,EACjB,GAAW,EACX,GAA2B,EAAA;AAE3B,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AACjC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAgB,GAAG,EAAE,YAAY;6EAAC;AACrD,IAAA,MAAM,CAAC,GAAG,OAAO,CAAC,IAAoC,EAAE;QACtD,QAAQ;AACT,KAAA,CAAsC;;;;AAIvC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,IAAoC,EAAE;QACxD,MAAM,EAAE,MAAM,CAAC,QAAQ;QACvB,MAAM,EAAE,eAAe,EAAE;AACzB,QAAA,KAAK,EAAE,MAAM,MAAM,EAAE;AACtB,KAAA,CAAC;AAEF,IAAA,MAAM,MAAM,GAAG,MAAM,CAAiB,SAAS;+EAAC;AAChD,IAAA,MAAM,KAAK,GAAG,MAAM,CAAU,SAAS;8EAAC;AACxC,IAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAK;AAC9B,QAAA,MAAM,EAAE,GAAG,MAAM,EAAE;AACnB,QAAA,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,WAAW;IAC/C,CAAC;kFAAC;IACF,IAAI,WAAW,GAAG,KAAK;AACvB,IAAA,IAAI,WAAW,GAAG,CAAC,CAAC;;AAEpB,IAAA,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiE;AAC7F,IAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB;AAE7C,IAAA,MAAM,QAAQ,GAAG,MAAM,WAAW;AAElC,IAAA,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK;AAEtE,IAAA,MAAM,OAAO,GAAG,CAAC,OAAe,KAAU;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,YAAY,EAAE;AACjC,YAAA,IAAI,CAAC,IAAI,OAAO,EAAE;AAChB,gBAAA,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;gBACtB,CAAC,CAAC,OAAO,EAAE;YACb;QACF;QACA,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAAE,IAAI,CAAC,IAAI,OAAO;AAAE,gBAAA,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1E,IAAA,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,KAAI;AACvC,QAAA,WAAW,GAAG,GAAG,CAAC,OAAO;QACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;QAC7B,IAAI,OAAO,EAAE,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC5C,YAAA,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QACvD;AACF,IAAA,CAAC,CAAC;AAEF,IAAA,MAAM,cAAc,GAAG,CAAC,GAAmB,KAAU;QACnD,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG;YAAE;AAC5C,QAAA,QAAQ,GAAG,CAAC,IAAI;YACd,KAAK,kBAAkB,EAAE;;;AAGvB,gBAAA,IAAI,CAAC,OAAO,CACV,GAAG,CAAC,UAAgD,EACpD,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CACtB;gBACD,WAAW,GAAG,IAAI;AAClB,gBAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;AACtB,gBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;;;AAGpB,gBAAA,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC9C,IAAI,OAAO,EAAE,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC5C,oBAAA,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE;AAC7E,wBAAA,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;oBACvD;gBACF;gBACA;YACF;YACA,KAAK,YAAY,EAAE;AACjB,gBAAA,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG;gBACnB,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE;AAC9B,oBAAA,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;oBACrB;gBACF;AACA,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAClB;YACF;YACA,KAAK,cAAc,EAAE;AACnB,gBAAA,QAAQ,GAAG,CAAC,MAAM;AAChB,oBAAA,KAAK,OAAO;wBACV,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC1F,wBAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;wBACnB;AACF,oBAAA,KAAK,SAAS;AACd,oBAAA,KAAK,WAAW;AACd,wBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,wBAAA,MAAM,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC;wBACjD;AACF,oBAAA,KAAK,UAAU;AACb,wBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,wBAAA,IAAI,WAAW;AAAE,4BAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;wBACvC;AACF,oBAAA;wBACE;;YAEN;;AAEJ,IAAA,CAAC;IAED,MAAM,SAAS,GAAG,MAAW;AAC3B,QAAA,IAAI,WAAW;AAAE,YAAA,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AACxC,QAAA,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;AAClF,IAAA,CAAC;IAED,MAAM,MAAM,GAAG,MAAW;AACxB,QAAA,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AACvB,QAAA,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;AAClF,IAAA,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;AAC3C,IAAA,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,SAAS,EAAE,CAAC;AAC7C,IAAA,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,MAAK;AAC9C,QAAA,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,YAAY;AAAE,YAAA,CAAC,CAAC,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC;QACpE,YAAY,CAAC,KAAK,EAAE;QACpB,OAAO,CAAC,KAAK,EAAE;AACjB,IAAA,CAAC,CAAC;AAEF,IAAA,MAAM,IAAI,GAAsB;AAC9B,QAAA,KAAK,EAAE,CAAC;AACR,QAAA,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE;QACxB,MAAM;QACN,KAAK;QACL,SAAS;QACT,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,QAAQ;AACR,QAAA,KAAK,EAAE,CAAC,MAAM,KAAI;AAChB,YAAA,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;YAC5B,IAAI,IAAI,KAAK,SAAS;gBACpB,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAC5E;AACH,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC9B,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;YAC1E,IAAI,CAAC,OAAO,EAAE;AACZ,gBAAA,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,CAAA,kDAAA,EAAqD,GAAG,CAAA,CAAE,CAAC,CACtE;YACH,MAAM,CAAC,CAAC,CAAC;YACT,MAAM,MAAM,GAAG,WAAW;AAC1B,YAAA,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,IAAI,WAAW,KAAK,MAAM;AAAE,gBAAA,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YACrD,MAAM,OAAO,GAAG,WAAW;YAC3B,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,KAAI;gBAC3C,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAChD,YAAA,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,MAAK;AACZ,YAAA,SAAS,EAAE;YACX,IAAI,CAAC,OAAO,EAAE;AACd,YAAA,KAAK,EAAE;AACP,YAAA,QAAQ,EAAE;AACV,YAAA,aAAa,EAAE;AACf,YAAA,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,YAAY;gBAC9B,CAAC,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;YAC1D,YAAY,CAAC,KAAK,EAAE;YACpB,OAAO,CAAC,KAAK,EAAE;AACf,YAAA,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpF,CAAC;KACF;AAED,IAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;AAElD,IAAA,IAAI,GAAG,EAAE,QAAQ,EAAE;AACjB,QAAA,MAAM,KAAK,GAAG,qBAAqB,EAAE;AACrC,QAAA,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzD,IAAI,OAAO,GAAG,KAAK;QACnB,MAAM,MAAM,GAAG,MAAK;AAClB,YAAA,IAAI,OAAO;gBAAE;YACb,OAAO,GAAG,IAAI;AACd,YAAA,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;AACpB,QAAA,CAAC;QACD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;AACpC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;AAC5B,QAAA,IAAI,CAAC,OAAO,GAAG,MAAK;AAClB,YAAA,MAAM,EAAE;AACR,YAAA,OAAO,EAAE;AACX,QAAA,CAAC;IACH;AAEA,IAAA,OAAO,IAAI;AACb;;ACxTA;;AAEG;;;;"}
|