@graphrefly/graphrefly 0.18.0 → 0.19.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/dist/{chunk-TNKODJ6E.js → chunk-AHRKWMNI.js} +7 -3
- package/dist/{chunk-TNKODJ6E.js.map → chunk-AHRKWMNI.js.map} +1 -1
- package/dist/{chunk-76YPZQTW.js → chunk-BER7UYLM.js} +27 -26
- package/dist/chunk-BER7UYLM.js.map +1 -0
- package/dist/{chunk-F6ORUNO7.js → chunk-IRZAGZUB.js} +34 -2
- package/dist/{chunk-F6ORUNO7.js.map → chunk-IRZAGZUB.js.map} +1 -1
- package/dist/{chunk-LB3RYLSC.js → chunk-JC2SN46B.js} +197 -42
- package/dist/chunk-JC2SN46B.js.map +1 -0
- package/dist/{chunk-KJGUP35I.js → chunk-OO5QOAXI.js} +4 -4
- package/dist/{chunk-UVWEKTYC.js → chunk-UW77D7SP.js} +3 -3
- package/dist/{chunk-J7S54G7I.js → chunk-XUOY3YKN.js} +7 -2
- package/dist/chunk-XUOY3YKN.js.map +1 -0
- package/dist/chunk-YLR5JUJZ.js +111 -0
- package/dist/chunk-YLR5JUJZ.js.map +1 -0
- package/dist/{chunk-BV3TPSBK.js → chunk-YXR3WW3Q.js} +740 -755
- package/dist/chunk-YXR3WW3Q.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +931 -784
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +4 -4
- package/dist/compat/nestjs/index.d.ts +4 -4
- package/dist/compat/nestjs/index.js +7 -7
- package/dist/core/index.cjs +651 -664
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +7 -3
- package/dist/extra/index.cjs +686 -672
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +4 -4
- package/dist/extra/index.d.ts +4 -4
- package/dist/extra/index.js +5 -5
- package/dist/graph/index.cjs +836 -808
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +3 -3
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.js +8 -8
- package/dist/{graph-gISB9n3n.d.ts → graph-KsTe57nI.d.cts} +82 -8
- package/dist/{graph-BYFlyNpX.d.cts → graph-mILUUqW8.d.ts} +82 -8
- package/dist/{index-CgKPpiu8.d.ts → index-8a605sg9.d.ts} +2 -2
- package/dist/{index-DKaB2x0T.d.ts → index-B2SvPEbc.d.ts} +6 -65
- package/dist/{index-B80mMeuf.d.ts → index-BBUYZfJ1.d.cts} +122 -76
- package/dist/{index-D_tUMcpz.d.cts → index-Bjh5C1Tp.d.cts} +37 -32
- package/dist/{index-B43mC7uY.d.cts → index-BjtlNirP.d.cts} +3 -3
- package/dist/{index-7WnwgjMu.d.ts → index-BnkMgNNa.d.ts} +37 -32
- package/dist/{index-CEDaJaYE.d.ts → index-CgSiUouz.d.ts} +3 -3
- package/dist/{index-EmzYk-TG.d.cts → index-CvKzv0AW.d.ts} +122 -76
- package/dist/{index-Ci_vPaVm.d.cts → index-UudxGnzc.d.cts} +6 -65
- package/dist/{index-BqOWSFhr.d.cts → index-VHA43cGP.d.cts} +2 -2
- package/dist/index.cjs +5920 -5572
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +595 -399
- package/dist/index.d.ts +595 -399
- package/dist/index.js +4357 -4063
- package/dist/index.js.map +1 -1
- package/dist/{meta-npl5b97j.d.cts → meta-BnG7XAaE.d.cts} +394 -236
- package/dist/{meta-npl5b97j.d.ts → meta-BnG7XAaE.d.ts} +394 -236
- package/dist/{observable-DFBCBELR.d.cts → observable-C8Kx_O6k.d.cts} +1 -1
- package/dist/{observable-oAGygKvc.d.ts → observable-DcBwQY7t.d.ts} +1 -1
- package/dist/patterns/reactive-layout/index.cjs +865 -718
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +3 -3
- package/dist/patterns/reactive-layout/index.d.ts +3 -3
- package/dist/patterns/reactive-layout/index.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-76YPZQTW.js.map +0 -1
- package/dist/chunk-BV3TPSBK.js.map +0 -1
- package/dist/chunk-FCLROC4Q.js +0 -231
- package/dist/chunk-FCLROC4Q.js.map +0 -1
- package/dist/chunk-J7S54G7I.js.map +0 -1
- package/dist/chunk-LB3RYLSC.js.map +0 -1
- /package/dist/{chunk-KJGUP35I.js.map → chunk-OO5QOAXI.js.map} +0 -0
- /package/dist/{chunk-UVWEKTYC.js.map → chunk-UW77D7SP.js.map} +0 -0
package/dist/extra/index.cjs
CHANGED
|
@@ -65,6 +65,7 @@ __export(extra_exports, {
|
|
|
65
65
|
find: () => find,
|
|
66
66
|
first: () => first,
|
|
67
67
|
firstValueFrom: () => firstValueFrom,
|
|
68
|
+
firstWhere: () => firstWhere,
|
|
68
69
|
flatMap: () => flatMap,
|
|
69
70
|
forEach: () => forEach,
|
|
70
71
|
fromAny: () => fromAny,
|
|
@@ -142,7 +143,6 @@ __export(extra_exports, {
|
|
|
142
143
|
shareReplay: () => shareReplay,
|
|
143
144
|
signalToName: () => signalToName,
|
|
144
145
|
skip: () => skip,
|
|
145
|
-
startWith: () => startWith,
|
|
146
146
|
switchMap: () => switchMap,
|
|
147
147
|
take: () => take,
|
|
148
148
|
takeUntil: () => takeUntil,
|
|
@@ -189,6 +189,7 @@ __export(extra_exports, {
|
|
|
189
189
|
module.exports = __toCommonJS(extra_exports);
|
|
190
190
|
|
|
191
191
|
// src/core/messages.ts
|
|
192
|
+
var START = /* @__PURE__ */ Symbol.for("graphrefly/START");
|
|
192
193
|
var DATA = /* @__PURE__ */ Symbol.for("graphrefly/DATA");
|
|
193
194
|
var DIRTY = /* @__PURE__ */ Symbol.for("graphrefly/DIRTY");
|
|
194
195
|
var RESOLVED = /* @__PURE__ */ Symbol.for("graphrefly/RESOLVED");
|
|
@@ -199,6 +200,7 @@ var TEARDOWN = /* @__PURE__ */ Symbol.for("graphrefly/TEARDOWN");
|
|
|
199
200
|
var COMPLETE = /* @__PURE__ */ Symbol.for("graphrefly/COMPLETE");
|
|
200
201
|
var ERROR = /* @__PURE__ */ Symbol.for("graphrefly/ERROR");
|
|
201
202
|
var knownMessageTypes = [
|
|
203
|
+
START,
|
|
202
204
|
DATA,
|
|
203
205
|
DIRTY,
|
|
204
206
|
RESOLVED,
|
|
@@ -209,13 +211,15 @@ var knownMessageTypes = [
|
|
|
209
211
|
COMPLETE,
|
|
210
212
|
ERROR
|
|
211
213
|
];
|
|
214
|
+
var knownMessageSet = new Set(knownMessageTypes);
|
|
212
215
|
function messageTier(t) {
|
|
213
|
-
if (t ===
|
|
214
|
-
if (t ===
|
|
215
|
-
if (t ===
|
|
216
|
-
if (t ===
|
|
217
|
-
if (t ===
|
|
218
|
-
return
|
|
216
|
+
if (t === START) return 0;
|
|
217
|
+
if (t === DIRTY || t === INVALIDATE) return 1;
|
|
218
|
+
if (t === PAUSE || t === RESUME) return 2;
|
|
219
|
+
if (t === DATA || t === RESOLVED) return 3;
|
|
220
|
+
if (t === COMPLETE || t === ERROR) return 4;
|
|
221
|
+
if (t === TEARDOWN) return 5;
|
|
222
|
+
return 1;
|
|
219
223
|
}
|
|
220
224
|
function isPhase2Message(msg) {
|
|
221
225
|
const t = msg[0];
|
|
@@ -224,6 +228,10 @@ function isPhase2Message(msg) {
|
|
|
224
228
|
function isTerminalMessage(t) {
|
|
225
229
|
return t === COMPLETE || t === ERROR;
|
|
226
230
|
}
|
|
231
|
+
function isLocalOnly(t) {
|
|
232
|
+
if (!knownMessageSet.has(t)) return false;
|
|
233
|
+
return messageTier(t) < 3;
|
|
234
|
+
}
|
|
227
235
|
function propagatesToMeta(t) {
|
|
228
236
|
return t === TEARDOWN;
|
|
229
237
|
}
|
|
@@ -384,14 +392,14 @@ function _downSequential(sink, messages, phase = 2) {
|
|
|
384
392
|
const dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;
|
|
385
393
|
for (const msg of messages) {
|
|
386
394
|
const tier = messageTier(msg[0]);
|
|
387
|
-
if (tier ===
|
|
395
|
+
if (tier === 3) {
|
|
388
396
|
if (isBatching()) {
|
|
389
397
|
const m = msg;
|
|
390
398
|
dataQueue.push(() => sink([m]));
|
|
391
399
|
} else {
|
|
392
400
|
sink([msg]);
|
|
393
401
|
}
|
|
394
|
-
} else if (tier >=
|
|
402
|
+
} else if (tier >= 4) {
|
|
395
403
|
if (isBatching()) {
|
|
396
404
|
const m = msg;
|
|
397
405
|
pendingPhase3.push(() => sink([m]));
|
|
@@ -500,10 +508,24 @@ function advanceVersion(info, newValue, hashFn) {
|
|
|
500
508
|
}
|
|
501
509
|
}
|
|
502
510
|
|
|
503
|
-
// src/core/node.ts
|
|
511
|
+
// src/core/node-base.ts
|
|
504
512
|
var NO_VALUE = /* @__PURE__ */ Symbol.for("graphrefly/NO_VALUE");
|
|
505
513
|
var CLEANUP_RESULT = /* @__PURE__ */ Symbol.for("graphrefly/CLEANUP_RESULT");
|
|
506
|
-
|
|
514
|
+
var isCleanupResult = (value) => typeof value === "object" && value !== null && CLEANUP_RESULT in value;
|
|
515
|
+
var isCleanupFn = (value) => typeof value === "function";
|
|
516
|
+
function statusAfterMessage(status, msg) {
|
|
517
|
+
const t = msg[0];
|
|
518
|
+
if (t === DIRTY) return "dirty";
|
|
519
|
+
if (t === DATA) return "settled";
|
|
520
|
+
if (t === RESOLVED) return "resolved";
|
|
521
|
+
if (t === COMPLETE) return "completed";
|
|
522
|
+
if (t === ERROR) return "errored";
|
|
523
|
+
if (t === INVALIDATE) return "dirty";
|
|
524
|
+
if (t === TEARDOWN) return "disconnected";
|
|
525
|
+
return status;
|
|
526
|
+
}
|
|
527
|
+
function createIntBitSet(size) {
|
|
528
|
+
const fullMask = size >= 32 ? -1 : ~(-1 << size);
|
|
507
529
|
let bits = 0;
|
|
508
530
|
return {
|
|
509
531
|
set(i) {
|
|
@@ -516,7 +538,8 @@ function createIntBitSet() {
|
|
|
516
538
|
return (bits & 1 << i) !== 0;
|
|
517
539
|
},
|
|
518
540
|
covers(other) {
|
|
519
|
-
|
|
541
|
+
const otherBits = other._bits();
|
|
542
|
+
return (bits & otherBits) === otherBits;
|
|
520
543
|
},
|
|
521
544
|
any() {
|
|
522
545
|
return bits !== 0;
|
|
@@ -524,6 +547,9 @@ function createIntBitSet() {
|
|
|
524
547
|
reset() {
|
|
525
548
|
bits = 0;
|
|
526
549
|
},
|
|
550
|
+
setAll() {
|
|
551
|
+
bits = fullMask;
|
|
552
|
+
},
|
|
527
553
|
_bits() {
|
|
528
554
|
return bits;
|
|
529
555
|
}
|
|
@@ -531,6 +557,8 @@ function createIntBitSet() {
|
|
|
531
557
|
}
|
|
532
558
|
function createArrayBitSet(size) {
|
|
533
559
|
const words = new Uint32Array(Math.ceil(size / 32));
|
|
560
|
+
const lastBits = size % 32;
|
|
561
|
+
const lastWordMask = lastBits === 0 ? 4294967295 : (1 << lastBits) - 1 >>> 0;
|
|
534
562
|
return {
|
|
535
563
|
set(i) {
|
|
536
564
|
words[i >>> 5] |= 1 << (i & 31);
|
|
@@ -557,130 +585,103 @@ function createArrayBitSet(size) {
|
|
|
557
585
|
reset() {
|
|
558
586
|
words.fill(0);
|
|
559
587
|
},
|
|
588
|
+
setAll() {
|
|
589
|
+
for (let w = 0; w < words.length - 1; w++) words[w] = 4294967295;
|
|
590
|
+
if (words.length > 0) words[words.length - 1] = lastWordMask;
|
|
591
|
+
},
|
|
560
592
|
_words: words
|
|
561
593
|
};
|
|
562
594
|
}
|
|
563
595
|
function createBitSet(size) {
|
|
564
|
-
return size <= 31 ? createIntBitSet() : createArrayBitSet(size);
|
|
596
|
+
return size <= 31 ? createIntBitSet(size) : createArrayBitSet(size);
|
|
565
597
|
}
|
|
566
|
-
var
|
|
567
|
-
|
|
568
|
-
var isCleanupResult = (value) => typeof value === "object" && value !== null && CLEANUP_RESULT in value;
|
|
569
|
-
var isCleanupFn = (value) => typeof value === "function";
|
|
570
|
-
var statusAfterMessage = (status, msg) => {
|
|
571
|
-
const t = msg[0];
|
|
572
|
-
if (t === DIRTY) return "dirty";
|
|
573
|
-
if (t === DATA) return "settled";
|
|
574
|
-
if (t === RESOLVED) return "resolved";
|
|
575
|
-
if (t === COMPLETE) return "completed";
|
|
576
|
-
if (t === ERROR) return "errored";
|
|
577
|
-
if (t === INVALIDATE) return "dirty";
|
|
578
|
-
if (t === TEARDOWN) return "disconnected";
|
|
579
|
-
return status;
|
|
580
|
-
};
|
|
581
|
-
var NodeImpl = class {
|
|
582
|
-
// --- Configuration (set once, never reassigned) ---
|
|
598
|
+
var NodeBase = class {
|
|
599
|
+
// --- Identity (set once) ---
|
|
583
600
|
_optsName;
|
|
584
601
|
_registryName;
|
|
585
|
-
/** @internal
|
|
602
|
+
/** @internal Read by `describeNode` before inference. */
|
|
586
603
|
_describeKind;
|
|
587
604
|
meta;
|
|
588
|
-
|
|
589
|
-
_fn;
|
|
590
|
-
_opts;
|
|
605
|
+
// --- Options ---
|
|
591
606
|
_equals;
|
|
607
|
+
_resubscribable;
|
|
608
|
+
_resetOnTeardown;
|
|
609
|
+
_onResubscribe;
|
|
592
610
|
_onMessage;
|
|
593
|
-
/** @internal
|
|
611
|
+
/** @internal Read by `describeNode` for `accessHintForGuard`. */
|
|
594
612
|
_guard;
|
|
613
|
+
/** @internal Subclasses update this through {@link _recordMutation}. */
|
|
595
614
|
_lastMutation;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
// ---
|
|
615
|
+
// --- Versioning ---
|
|
616
|
+
_hashFn;
|
|
617
|
+
_versioning;
|
|
618
|
+
// --- Lifecycle state ---
|
|
619
|
+
/** @internal Read by `describeNode` and `graph.ts`. */
|
|
600
620
|
_cached;
|
|
621
|
+
/** @internal Read externally via `get status()`. */
|
|
601
622
|
_status;
|
|
602
623
|
_terminal = false;
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
_manualEmitUsed = false;
|
|
624
|
+
_active = false;
|
|
625
|
+
// --- Sink storage ---
|
|
626
|
+
/** @internal Read by `graph/profile.ts` for subscriber counts. */
|
|
607
627
|
_sinkCount = 0;
|
|
608
628
|
_singleDepSinkCount = 0;
|
|
609
|
-
// --- Object/collection state ---
|
|
610
|
-
_depDirtyMask;
|
|
611
|
-
_depSettledMask;
|
|
612
|
-
_depCompleteMask;
|
|
613
|
-
_allDepsCompleteMask;
|
|
614
|
-
_lastDepValues;
|
|
615
|
-
_cleanup;
|
|
616
|
-
_sinks = null;
|
|
617
629
|
_singleDepSinks = /* @__PURE__ */ new WeakSet();
|
|
618
|
-
|
|
630
|
+
_sinks = null;
|
|
631
|
+
// --- Actions + bound helpers ---
|
|
619
632
|
_actions;
|
|
620
633
|
_boundDownToSinks;
|
|
634
|
+
// --- Inspector hook (Graph observability) ---
|
|
621
635
|
_inspectorHook;
|
|
622
|
-
|
|
623
|
-
_hashFn;
|
|
624
|
-
constructor(deps, fn, opts) {
|
|
625
|
-
this._deps = deps;
|
|
626
|
-
this._fn = fn;
|
|
627
|
-
this._opts = opts;
|
|
636
|
+
constructor(opts) {
|
|
628
637
|
this._optsName = opts.name;
|
|
629
638
|
this._describeKind = opts.describeKind;
|
|
630
639
|
this._equals = opts.equals ?? Object.is;
|
|
640
|
+
this._resubscribable = opts.resubscribable ?? false;
|
|
641
|
+
this._resetOnTeardown = opts.resetOnTeardown ?? false;
|
|
642
|
+
this._onResubscribe = opts.onResubscribe;
|
|
631
643
|
this._onMessage = opts.onMessage;
|
|
632
644
|
this._guard = opts.guard;
|
|
633
|
-
this._hasDeps = deps.length > 0;
|
|
634
|
-
this._autoComplete = opts.completeWhenDepsComplete ?? true;
|
|
635
|
-
this._isSingleDep = deps.length === 1 && fn != null;
|
|
636
645
|
this._cached = "initial" in opts ? opts.initial : NO_VALUE;
|
|
637
|
-
this._status =
|
|
646
|
+
this._status = "disconnected";
|
|
638
647
|
this._hashFn = opts.versioningHash ?? defaultHash;
|
|
639
648
|
this._versioning = opts.versioning != null ? createVersioning(opts.versioning, this._cached === NO_VALUE ? void 0 : this._cached, {
|
|
640
649
|
id: opts.versioningId,
|
|
641
650
|
hash: this._hashFn
|
|
642
651
|
}) : void 0;
|
|
643
|
-
this._depDirtyMask = createBitSet(deps.length);
|
|
644
|
-
this._depSettledMask = createBitSet(deps.length);
|
|
645
|
-
this._depCompleteMask = createBitSet(deps.length);
|
|
646
|
-
this._allDepsCompleteMask = createBitSet(deps.length);
|
|
647
|
-
for (let i = 0; i < deps.length; i++) this._allDepsCompleteMask.set(i);
|
|
648
652
|
const meta = {};
|
|
649
653
|
for (const [k, v] of Object.entries(opts.meta ?? {})) {
|
|
650
|
-
meta[k] =
|
|
651
|
-
initial: v,
|
|
652
|
-
name: `${opts.name ?? "node"}:meta:${k}`,
|
|
653
|
-
describeKind: "state",
|
|
654
|
-
...opts.guard != null ? { guard: opts.guard } : {}
|
|
655
|
-
});
|
|
654
|
+
meta[k] = this._createMetaNode(k, v, opts);
|
|
656
655
|
}
|
|
657
656
|
Object.freeze(meta);
|
|
658
657
|
this.meta = meta;
|
|
659
658
|
const self = this;
|
|
660
659
|
this._actions = {
|
|
661
660
|
down(messages) {
|
|
662
|
-
self.
|
|
661
|
+
self._onManualEmit();
|
|
663
662
|
self._downInternal(messages);
|
|
664
663
|
},
|
|
665
664
|
emit(value) {
|
|
666
|
-
self.
|
|
665
|
+
self._onManualEmit();
|
|
667
666
|
self._downAutoValue(value);
|
|
668
667
|
},
|
|
669
668
|
up(messages) {
|
|
670
669
|
self._upInternal(messages);
|
|
671
670
|
}
|
|
672
671
|
};
|
|
673
|
-
this.down = this.down.bind(this);
|
|
674
|
-
this.up = this.up.bind(this);
|
|
675
672
|
this._boundDownToSinks = this._downToSinks.bind(this);
|
|
676
673
|
}
|
|
674
|
+
/**
|
|
675
|
+
* Subclass hook invoked by `actions.down` / `actions.emit`. Default no-op;
|
|
676
|
+
* {@link NodeImpl} overrides to set `_manualEmitUsed`.
|
|
677
|
+
*/
|
|
678
|
+
_onManualEmit() {
|
|
679
|
+
}
|
|
680
|
+
// --- Identity getters ---
|
|
677
681
|
get name() {
|
|
678
682
|
return this._registryName ?? this._optsName;
|
|
679
683
|
}
|
|
680
|
-
/**
|
|
681
|
-
* When a node is registered with {@link Graph.add} without an options `name`,
|
|
682
|
-
* the graph assigns the registry local name for introspection (parity with graphrefly-py).
|
|
683
|
-
*/
|
|
684
|
+
/** @internal Assigned by `Graph.add` when registered without an options `name`. */
|
|
684
685
|
_assignRegistryName(localName) {
|
|
685
686
|
if (this._optsName !== void 0 || this._registryName !== void 0) return;
|
|
686
687
|
this._registryName = localName;
|
|
@@ -698,7 +699,10 @@ var NodeImpl = class {
|
|
|
698
699
|
}
|
|
699
700
|
};
|
|
700
701
|
}
|
|
701
|
-
|
|
702
|
+
/** @internal Used by subclasses to surface inspector events. */
|
|
703
|
+
_emitInspectorHook(event) {
|
|
704
|
+
this._inspectorHook?.(event);
|
|
705
|
+
}
|
|
702
706
|
get status() {
|
|
703
707
|
return this._status;
|
|
704
708
|
}
|
|
@@ -708,15 +712,7 @@ var NodeImpl = class {
|
|
|
708
712
|
get v() {
|
|
709
713
|
return this._versioning;
|
|
710
714
|
}
|
|
711
|
-
/**
|
|
712
|
-
* Retroactively apply versioning to a node that was created without it.
|
|
713
|
-
* No-op if versioning is already enabled.
|
|
714
|
-
*
|
|
715
|
-
* Version starts at 0 regardless of prior DATA emissions — it tracks
|
|
716
|
-
* changes from the moment versioning is enabled, not historical ones.
|
|
717
|
-
*
|
|
718
|
-
* @internal — used by {@link Graph.setVersioning}.
|
|
719
|
-
*/
|
|
715
|
+
/** @internal Used by `Graph.setVersioning` to retroactively apply versioning. */
|
|
720
716
|
_applyVersioning(level, opts) {
|
|
721
717
|
if (this._versioning != null) return;
|
|
722
718
|
this._hashFn = opts?.hash ?? this._hashFn;
|
|
@@ -736,6 +732,7 @@ var NodeImpl = class {
|
|
|
736
732
|
if (this._guard == null) return true;
|
|
737
733
|
return this._guard(normalizeActor(actor), "observe");
|
|
738
734
|
}
|
|
735
|
+
// --- Public transport ---
|
|
739
736
|
get() {
|
|
740
737
|
return this._cached === NO_VALUE ? void 0 : this._cached;
|
|
741
738
|
}
|
|
@@ -748,43 +745,25 @@ var NodeImpl = class {
|
|
|
748
745
|
if (!this._guard(actor, action)) {
|
|
749
746
|
throw new GuardDenied({ actor, action, nodeName: this.name });
|
|
750
747
|
}
|
|
751
|
-
this.
|
|
748
|
+
this._recordMutation(actor);
|
|
752
749
|
}
|
|
753
750
|
this._downInternal(messages);
|
|
754
751
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
this.
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
for (let i = 0; i < sinkMessages.length; i++) {
|
|
769
|
-
const t = sinkMessages[i][0];
|
|
770
|
-
if (t === DATA || t === RESOLVED) {
|
|
771
|
-
hasPhase2 = true;
|
|
772
|
-
break;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
if (hasPhase2) {
|
|
776
|
-
const filtered = [];
|
|
777
|
-
for (let i = 0; i < sinkMessages.length; i++) {
|
|
778
|
-
if (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);
|
|
779
|
-
}
|
|
780
|
-
if (filtered.length > 0) {
|
|
781
|
-
downWithBatch(this._boundDownToSinks, filtered);
|
|
782
|
-
}
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
downWithBatch(this._boundDownToSinks, sinkMessages);
|
|
752
|
+
/** @internal Record a successful guarded mutation (called by `down` and subclass `up`). */
|
|
753
|
+
_recordMutation(actor) {
|
|
754
|
+
this._lastMutation = { actor, timestamp_ns: wallClockNs() };
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* At-most-once deactivation guard. Both TEARDOWN (eager) and
|
|
758
|
+
* unsubscribe-body (lazy) call this. The `_active` flag ensures
|
|
759
|
+
* `_doDeactivate` runs exactly once per activation cycle.
|
|
760
|
+
*/
|
|
761
|
+
_onDeactivate() {
|
|
762
|
+
if (!this._active) return;
|
|
763
|
+
this._active = false;
|
|
764
|
+
this._doDeactivate();
|
|
787
765
|
}
|
|
766
|
+
// --- Subscribe (uniform across node shapes) ---
|
|
788
767
|
subscribe(sink, hints) {
|
|
789
768
|
if (hints?.actor != null && this._guard != null) {
|
|
790
769
|
const actor = normalizeActor(hints.actor);
|
|
@@ -792,17 +771,21 @@ var NodeImpl = class {
|
|
|
792
771
|
throw new GuardDenied({ actor, action: "observe", nodeName: this.name });
|
|
793
772
|
}
|
|
794
773
|
}
|
|
795
|
-
if (this._terminal && this.
|
|
774
|
+
if (this._terminal && this._resubscribable) {
|
|
796
775
|
this._terminal = false;
|
|
797
776
|
this._cached = NO_VALUE;
|
|
798
|
-
this._status =
|
|
799
|
-
this.
|
|
777
|
+
this._status = "disconnected";
|
|
778
|
+
this._onResubscribe?.();
|
|
800
779
|
}
|
|
801
780
|
this._sinkCount += 1;
|
|
802
781
|
if (hints?.singleDep) {
|
|
803
782
|
this._singleDepSinkCount += 1;
|
|
804
783
|
this._singleDepSinks.add(sink);
|
|
805
784
|
}
|
|
785
|
+
if (!this._terminal) {
|
|
786
|
+
const startMessages = this._cached === NO_VALUE ? [[START]] : [[START], [DATA, this._cached]];
|
|
787
|
+
downWithBatch(sink, startMessages);
|
|
788
|
+
}
|
|
806
789
|
if (this._sinks == null) {
|
|
807
790
|
this._sinks = sink;
|
|
808
791
|
} else if (typeof this._sinks === "function") {
|
|
@@ -810,10 +793,12 @@ var NodeImpl = class {
|
|
|
810
793
|
} else {
|
|
811
794
|
this._sinks.add(sink);
|
|
812
795
|
}
|
|
813
|
-
if (this.
|
|
814
|
-
this.
|
|
815
|
-
|
|
816
|
-
|
|
796
|
+
if (this._sinkCount === 1 && !this._terminal) {
|
|
797
|
+
this._active = true;
|
|
798
|
+
this._onActivate();
|
|
799
|
+
}
|
|
800
|
+
if (!this._terminal && this._status === "disconnected" && this._cached === NO_VALUE) {
|
|
801
|
+
this._status = "pending";
|
|
817
802
|
}
|
|
818
803
|
let removed = false;
|
|
819
804
|
return () => {
|
|
@@ -837,39 +822,49 @@ var NodeImpl = class {
|
|
|
837
822
|
}
|
|
838
823
|
}
|
|
839
824
|
if (this._sinks == null) {
|
|
840
|
-
this.
|
|
841
|
-
this._stopProducer();
|
|
825
|
+
this._onDeactivate();
|
|
842
826
|
}
|
|
843
827
|
};
|
|
844
828
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
829
|
+
// --- Down pipeline ---
|
|
830
|
+
/**
|
|
831
|
+
* Core outgoing dispatch. Applies terminal filter + local lifecycle
|
|
832
|
+
* update, then hands messages to `downWithBatch` for tier-aware delivery.
|
|
833
|
+
*/
|
|
834
|
+
_downInternal(messages) {
|
|
835
|
+
if (messages.length === 0) return;
|
|
836
|
+
let sinkMessages = messages;
|
|
837
|
+
if (this._terminal && !this._resubscribable) {
|
|
838
|
+
const pass = messages.filter((m) => m[0] === TEARDOWN || m[0] === INVALIDATE);
|
|
839
|
+
if (pass.length === 0) return;
|
|
840
|
+
sinkMessages = pass;
|
|
853
841
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
842
|
+
this._handleLocalLifecycle(sinkMessages);
|
|
843
|
+
if (this._canSkipDirty()) {
|
|
844
|
+
let hasPhase2 = false;
|
|
845
|
+
for (let i = 0; i < sinkMessages.length; i++) {
|
|
846
|
+
const t = sinkMessages[i][0];
|
|
847
|
+
if (t === DATA || t === RESOLVED) {
|
|
848
|
+
hasPhase2 = true;
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (hasPhase2) {
|
|
853
|
+
const filtered = [];
|
|
854
|
+
for (let i = 0; i < sinkMessages.length; i++) {
|
|
855
|
+
if (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);
|
|
856
|
+
}
|
|
857
|
+
if (filtered.length > 0) {
|
|
858
|
+
downWithBatch(this._boundDownToSinks, filtered);
|
|
859
|
+
}
|
|
860
|
+
return;
|
|
859
861
|
}
|
|
860
862
|
}
|
|
863
|
+
downWithBatch(this._boundDownToSinks, sinkMessages);
|
|
861
864
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
for (const dep of this._deps) {
|
|
865
|
-
dep.up?.(messages, { internal: true });
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
unsubscribe() {
|
|
869
|
-
if (!this._hasDeps) return;
|
|
870
|
-
this._disconnectUpstream();
|
|
865
|
+
_canSkipDirty() {
|
|
866
|
+
return this._sinkCount === 1 && this._singleDepSinkCount === 1;
|
|
871
867
|
}
|
|
872
|
-
// --- Private methods (prototype, _ prefix) ---
|
|
873
868
|
_downToSinks(messages) {
|
|
874
869
|
if (this._sinks == null) return;
|
|
875
870
|
if (typeof this._sinks === "function") {
|
|
@@ -881,6 +876,11 @@ var NodeImpl = class {
|
|
|
881
876
|
sink(messages);
|
|
882
877
|
}
|
|
883
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Update `_cached`, `_status`, `_terminal` from message batch before
|
|
881
|
+
* delivery. Subclass hooks `_onInvalidate` / `_onTeardown` let
|
|
882
|
+
* {@link NodeImpl} clear `_lastDepValues` and invoke cleanup fns.
|
|
883
|
+
*/
|
|
884
884
|
_handleLocalLifecycle(messages) {
|
|
885
885
|
for (const m of messages) {
|
|
886
886
|
const t = m[0];
|
|
@@ -894,28 +894,22 @@ var NodeImpl = class {
|
|
|
894
894
|
}
|
|
895
895
|
}
|
|
896
896
|
if (t === INVALIDATE) {
|
|
897
|
-
|
|
898
|
-
this._cleanup = void 0;
|
|
899
|
-
cleanupFn?.();
|
|
897
|
+
this._onInvalidate();
|
|
900
898
|
this._cached = NO_VALUE;
|
|
901
|
-
this._lastDepValues = void 0;
|
|
902
899
|
}
|
|
903
900
|
this._status = statusAfterMessage(this._status, m);
|
|
904
901
|
if (t === COMPLETE || t === ERROR) {
|
|
905
902
|
this._terminal = true;
|
|
906
903
|
}
|
|
907
904
|
if (t === TEARDOWN) {
|
|
908
|
-
if (this.
|
|
905
|
+
if (this._resetOnTeardown) {
|
|
909
906
|
this._cached = NO_VALUE;
|
|
910
907
|
}
|
|
911
|
-
|
|
912
|
-
this._cleanup = void 0;
|
|
913
|
-
teardownCleanup?.();
|
|
908
|
+
this._onTeardown();
|
|
914
909
|
try {
|
|
915
910
|
this._propagateToMeta(t);
|
|
916
911
|
} finally {
|
|
917
|
-
this.
|
|
918
|
-
this._stopProducer();
|
|
912
|
+
this._onDeactivate();
|
|
919
913
|
}
|
|
920
914
|
}
|
|
921
915
|
if (t !== TEARDOWN && propagatesToMeta(t)) {
|
|
@@ -923,7 +917,20 @@ var NodeImpl = class {
|
|
|
923
917
|
}
|
|
924
918
|
}
|
|
925
919
|
}
|
|
926
|
-
/**
|
|
920
|
+
/**
|
|
921
|
+
* Subclass hook: invoked when INVALIDATE arrives (before `_cached` is
|
|
922
|
+
* cleared). {@link NodeImpl} uses this to run the fn cleanup fn and
|
|
923
|
+
* drop `_lastDepValues` so the next wave re-runs fn.
|
|
924
|
+
*/
|
|
925
|
+
_onInvalidate() {
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Subclass hook: invoked when TEARDOWN arrives, before `_onDeactivate`.
|
|
929
|
+
* {@link NodeImpl} uses this to run any pending cleanup fn.
|
|
930
|
+
*/
|
|
931
|
+
_onTeardown() {
|
|
932
|
+
}
|
|
933
|
+
/** Forward a signal to all companion meta nodes (best-effort). */
|
|
927
934
|
_propagateToMeta(t) {
|
|
928
935
|
for (const metaNode of Object.values(this.meta)) {
|
|
929
936
|
try {
|
|
@@ -932,9 +939,10 @@ var NodeImpl = class {
|
|
|
932
939
|
}
|
|
933
940
|
}
|
|
934
941
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
942
|
+
/**
|
|
943
|
+
* Frame a computed value into the right protocol messages and dispatch
|
|
944
|
+
* via `_downInternal`. Used by `_runFn` and `actions.emit`.
|
|
945
|
+
*/
|
|
938
946
|
_downAutoValue(value) {
|
|
939
947
|
const wasDirty = this._status === "dirty";
|
|
940
948
|
let unchanged;
|
|
@@ -942,7 +950,9 @@ var NodeImpl = class {
|
|
|
942
950
|
unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
|
|
943
951
|
} catch (eqErr) {
|
|
944
952
|
const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
|
|
945
|
-
const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, {
|
|
953
|
+
const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, {
|
|
954
|
+
cause: eqErr
|
|
955
|
+
});
|
|
946
956
|
this._downInternal([[ERROR, wrapped]]);
|
|
947
957
|
return;
|
|
948
958
|
}
|
|
@@ -952,89 +962,173 @@ var NodeImpl = class {
|
|
|
952
962
|
}
|
|
953
963
|
this._downInternal(wasDirty ? [[DATA, value]] : [[DIRTY], [DATA, value]]);
|
|
954
964
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if ("value" in out) {
|
|
990
|
-
this._downAutoValue(out.value);
|
|
991
|
-
}
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
if (isCleanupFn(out)) {
|
|
995
|
-
this._cleanup = out;
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
if (this._manualEmitUsed) return;
|
|
999
|
-
if (out === void 0) return;
|
|
1000
|
-
this._downAutoValue(out);
|
|
1001
|
-
} catch (err) {
|
|
1002
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1003
|
-
const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
|
|
1004
|
-
this._downInternal([[ERROR, wrapped]]);
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
// src/core/node.ts
|
|
968
|
+
var NodeImpl = class extends NodeBase {
|
|
969
|
+
// --- Dep configuration (set once) ---
|
|
970
|
+
_deps;
|
|
971
|
+
_fn;
|
|
972
|
+
_opts;
|
|
973
|
+
_hasDeps;
|
|
974
|
+
_isSingleDep;
|
|
975
|
+
_autoComplete;
|
|
976
|
+
// --- Wave tracking masks ---
|
|
977
|
+
_depDirtyMask;
|
|
978
|
+
_depSettledMask;
|
|
979
|
+
_depCompleteMask;
|
|
980
|
+
_allDepsCompleteMask;
|
|
981
|
+
// --- Identity-skip optimization ---
|
|
982
|
+
_lastDepValues;
|
|
983
|
+
_cleanup;
|
|
984
|
+
// --- Upstream bookkeeping ---
|
|
985
|
+
_upstreamUnsubs = [];
|
|
986
|
+
// --- Fn behavior flag ---
|
|
987
|
+
/** @internal Read by `describeNode` to infer `"operator"` label. */
|
|
988
|
+
_manualEmitUsed = false;
|
|
989
|
+
constructor(deps, fn, opts) {
|
|
990
|
+
super(opts);
|
|
991
|
+
this._deps = deps;
|
|
992
|
+
this._fn = fn;
|
|
993
|
+
this._opts = opts;
|
|
994
|
+
this._hasDeps = deps.length > 0;
|
|
995
|
+
this._isSingleDep = deps.length === 1 && fn != null;
|
|
996
|
+
this._autoComplete = opts.completeWhenDepsComplete ?? true;
|
|
997
|
+
if (!this._hasDeps && fn == null && this._cached !== NO_VALUE) {
|
|
998
|
+
this._status = "settled";
|
|
1005
999
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
this.
|
|
1010
|
-
this.
|
|
1011
|
-
|
|
1012
|
-
|
|
1000
|
+
this._depDirtyMask = createBitSet(deps.length);
|
|
1001
|
+
this._depSettledMask = createBitSet(deps.length);
|
|
1002
|
+
this._depCompleteMask = createBitSet(deps.length);
|
|
1003
|
+
this._allDepsCompleteMask = createBitSet(deps.length);
|
|
1004
|
+
for (let i = 0; i < deps.length; i++) this._allDepsCompleteMask.set(i);
|
|
1005
|
+
this.down = this.down.bind(this);
|
|
1006
|
+
this.up = this.up.bind(this);
|
|
1007
|
+
}
|
|
1008
|
+
// --- Meta node factory (called from base constructor) ---
|
|
1009
|
+
_createMetaNode(key, initialValue, opts) {
|
|
1010
|
+
return node({
|
|
1011
|
+
initial: initialValue,
|
|
1012
|
+
name: `${opts.name ?? "node"}:meta:${key}`,
|
|
1013
|
+
describeKind: "state",
|
|
1014
|
+
...opts.guard != null ? { guard: opts.guard } : {}
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
// --- Manual emit tracker (set by actions.down / actions.emit) ---
|
|
1018
|
+
_onManualEmit() {
|
|
1019
|
+
this._manualEmitUsed = true;
|
|
1020
|
+
}
|
|
1021
|
+
// --- Up / unsubscribe ---
|
|
1022
|
+
up(messages, options) {
|
|
1023
|
+
if (!this._hasDeps) return;
|
|
1024
|
+
if (!options?.internal && this._guard != null) {
|
|
1025
|
+
const actor = normalizeActor(options?.actor);
|
|
1026
|
+
if (!this._guard(actor, "write")) {
|
|
1027
|
+
throw new GuardDenied({ actor, action: "write", nodeName: this.name });
|
|
1028
|
+
}
|
|
1029
|
+
this._recordMutation(actor);
|
|
1030
|
+
}
|
|
1031
|
+
for (const dep of this._deps) {
|
|
1032
|
+
if (options === void 0) {
|
|
1033
|
+
dep.up?.(messages);
|
|
1034
|
+
} else {
|
|
1035
|
+
dep.up?.(messages, options);
|
|
1036
|
+
}
|
|
1013
1037
|
}
|
|
1014
1038
|
}
|
|
1015
|
-
|
|
1016
|
-
if (!this.
|
|
1017
|
-
|
|
1039
|
+
_upInternal(messages) {
|
|
1040
|
+
if (!this._hasDeps) return;
|
|
1041
|
+
for (const dep of this._deps) {
|
|
1042
|
+
dep.up?.(messages, { internal: true });
|
|
1018
1043
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1044
|
+
}
|
|
1045
|
+
unsubscribe() {
|
|
1046
|
+
if (!this._hasDeps) return;
|
|
1047
|
+
this._disconnectUpstream();
|
|
1048
|
+
}
|
|
1049
|
+
// --- Activation (first-subscriber / last-subscriber hooks) ---
|
|
1050
|
+
_onActivate() {
|
|
1051
|
+
if (this._hasDeps) {
|
|
1052
|
+
this._connectUpstream();
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
if (this._fn) {
|
|
1023
1056
|
this._runFn();
|
|
1057
|
+
return;
|
|
1024
1058
|
}
|
|
1025
1059
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1060
|
+
_doDeactivate() {
|
|
1061
|
+
this._disconnectUpstream();
|
|
1062
|
+
const cleanup = this._cleanup;
|
|
1063
|
+
this._cleanup = void 0;
|
|
1064
|
+
cleanup?.();
|
|
1065
|
+
if (this._fn != null) {
|
|
1066
|
+
this._cached = NO_VALUE;
|
|
1067
|
+
this._lastDepValues = void 0;
|
|
1068
|
+
}
|
|
1069
|
+
if (this._hasDeps || this._fn != null) {
|
|
1070
|
+
this._status = "disconnected";
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
// --- INVALIDATE / TEARDOWN hooks (clear fn state) ---
|
|
1074
|
+
_onInvalidate() {
|
|
1075
|
+
const cleanup = this._cleanup;
|
|
1076
|
+
this._cleanup = void 0;
|
|
1077
|
+
cleanup?.();
|
|
1078
|
+
this._lastDepValues = void 0;
|
|
1079
|
+
}
|
|
1080
|
+
_onTeardown() {
|
|
1081
|
+
const cleanup = this._cleanup;
|
|
1082
|
+
this._cleanup = void 0;
|
|
1083
|
+
cleanup?.();
|
|
1084
|
+
}
|
|
1085
|
+
// --- Upstream connect / disconnect ---
|
|
1086
|
+
_connectUpstream() {
|
|
1087
|
+
if (!this._hasDeps) return;
|
|
1088
|
+
if (this._upstreamUnsubs.length > 0) return;
|
|
1089
|
+
this._depDirtyMask.setAll();
|
|
1090
|
+
this._depSettledMask.reset();
|
|
1091
|
+
this._depCompleteMask.reset();
|
|
1092
|
+
const depValuesBefore = this._lastDepValues;
|
|
1093
|
+
const subHints = this._isSingleDep ? { singleDep: true } : void 0;
|
|
1094
|
+
for (let i = 0; i < this._deps.length; i += 1) {
|
|
1095
|
+
const dep = this._deps[i];
|
|
1096
|
+
this._upstreamUnsubs.push(
|
|
1097
|
+
dep.subscribe((msgs) => this._handleDepMessages(i, msgs), subHints)
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
if (this._fn && this._onMessage && !this._terminal && this._lastDepValues === depValuesBefore) {
|
|
1101
|
+
this._runFn();
|
|
1029
1102
|
}
|
|
1030
1103
|
}
|
|
1104
|
+
_disconnectUpstream() {
|
|
1105
|
+
if (this._upstreamUnsubs.length === 0) return;
|
|
1106
|
+
for (const unsub of this._upstreamUnsubs.splice(0)) {
|
|
1107
|
+
unsub();
|
|
1108
|
+
}
|
|
1109
|
+
this._depDirtyMask.reset();
|
|
1110
|
+
this._depSettledMask.reset();
|
|
1111
|
+
this._depCompleteMask.reset();
|
|
1112
|
+
}
|
|
1113
|
+
// --- Wave handling ---
|
|
1031
1114
|
_handleDepMessages(index, messages) {
|
|
1032
1115
|
for (const msg of messages) {
|
|
1033
|
-
this.
|
|
1116
|
+
this._emitInspectorHook({ kind: "dep_message", depIndex: index, message: msg });
|
|
1034
1117
|
const t = msg[0];
|
|
1035
1118
|
if (this._onMessage) {
|
|
1036
1119
|
try {
|
|
1037
|
-
|
|
1120
|
+
const consumed = this._onMessage(msg, index, this._actions);
|
|
1121
|
+
if (consumed) {
|
|
1122
|
+
if (t === START) {
|
|
1123
|
+
this._depDirtyMask.clear(index);
|
|
1124
|
+
if (this._depDirtyMask.any() && this._depSettledMask.covers(this._depDirtyMask)) {
|
|
1125
|
+
this._depDirtyMask.reset();
|
|
1126
|
+
this._depSettledMask.reset();
|
|
1127
|
+
this._runFn();
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1038
1132
|
} catch (err) {
|
|
1039
1133
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1040
1134
|
const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
|
|
@@ -1044,6 +1138,7 @@ var NodeImpl = class {
|
|
|
1044
1138
|
return;
|
|
1045
1139
|
}
|
|
1046
1140
|
}
|
|
1141
|
+
if (messageTier(t) < 1) continue;
|
|
1047
1142
|
if (!this._fn) {
|
|
1048
1143
|
if (t === COMPLETE && this._deps.length > 1) {
|
|
1049
1144
|
this._depCompleteMask.set(index);
|
|
@@ -1087,53 +1182,85 @@ var NodeImpl = class {
|
|
|
1087
1182
|
this._downInternal([msg]);
|
|
1088
1183
|
}
|
|
1089
1184
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
this.
|
|
1093
|
-
this.
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
this._status = "settled";
|
|
1097
|
-
const subHints = this._isSingleDep ? { singleDep: true } : void 0;
|
|
1098
|
-
this._connecting = true;
|
|
1099
|
-
try {
|
|
1100
|
-
for (let i = 0; i < this._deps.length; i += 1) {
|
|
1101
|
-
const dep = this._deps[i];
|
|
1102
|
-
this._upstreamUnsubs.push(
|
|
1103
|
-
dep.subscribe((msgs) => this._handleDepMessages(i, msgs), subHints)
|
|
1104
|
-
);
|
|
1105
|
-
}
|
|
1106
|
-
} finally {
|
|
1107
|
-
this._connecting = false;
|
|
1185
|
+
_onDepDirty(index) {
|
|
1186
|
+
const wasDirty = this._depDirtyMask.has(index);
|
|
1187
|
+
this._depDirtyMask.set(index);
|
|
1188
|
+
this._depSettledMask.clear(index);
|
|
1189
|
+
if (!wasDirty) {
|
|
1190
|
+
this._downInternal([[DIRTY]]);
|
|
1108
1191
|
}
|
|
1109
|
-
|
|
1192
|
+
}
|
|
1193
|
+
_onDepSettled(index) {
|
|
1194
|
+
if (!this._depDirtyMask.has(index)) {
|
|
1195
|
+
this._onDepDirty(index);
|
|
1196
|
+
}
|
|
1197
|
+
this._depSettledMask.set(index);
|
|
1198
|
+
if (this._depDirtyMask.any() && this._depSettledMask.covers(this._depDirtyMask)) {
|
|
1199
|
+
this._depDirtyMask.reset();
|
|
1200
|
+
this._depSettledMask.reset();
|
|
1110
1201
|
this._runFn();
|
|
1111
1202
|
}
|
|
1112
1203
|
}
|
|
1113
|
-
|
|
1114
|
-
if (
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
this._cleanup = void 0;
|
|
1118
|
-
producerCleanup?.();
|
|
1119
|
-
}
|
|
1120
|
-
_startProducer() {
|
|
1121
|
-
if (this._deps.length !== 0 || !this._fn || this._producerStarted) return;
|
|
1122
|
-
this._producerStarted = true;
|
|
1123
|
-
this._runFn();
|
|
1204
|
+
_maybeCompleteFromDeps() {
|
|
1205
|
+
if (this._autoComplete && this._deps.length > 0 && this._depCompleteMask.covers(this._allDepsCompleteMask)) {
|
|
1206
|
+
this._downInternal([[COMPLETE]]);
|
|
1207
|
+
}
|
|
1124
1208
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1209
|
+
// --- Fn execution ---
|
|
1210
|
+
_runFn() {
|
|
1211
|
+
if (!this._fn) return;
|
|
1212
|
+
if (this._terminal && !this._resubscribable) return;
|
|
1213
|
+
try {
|
|
1214
|
+
const n = this._deps.length;
|
|
1215
|
+
const depValues = new Array(n);
|
|
1216
|
+
for (let i = 0; i < n; i++) depValues[i] = this._deps[i].get();
|
|
1217
|
+
const prev = this._lastDepValues;
|
|
1218
|
+
if (n > 0 && prev != null && prev.length === n) {
|
|
1219
|
+
let allSame = true;
|
|
1220
|
+
for (let i = 0; i < n; i++) {
|
|
1221
|
+
if (!Object.is(depValues[i], prev[i])) {
|
|
1222
|
+
allSame = false;
|
|
1223
|
+
break;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
if (allSame) {
|
|
1227
|
+
if (this._status === "dirty") {
|
|
1228
|
+
this._downInternal([[RESOLVED]]);
|
|
1229
|
+
}
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
const prevCleanup = this._cleanup;
|
|
1234
|
+
this._cleanup = void 0;
|
|
1235
|
+
prevCleanup?.();
|
|
1236
|
+
this._manualEmitUsed = false;
|
|
1237
|
+
this._lastDepValues = depValues;
|
|
1238
|
+
this._emitInspectorHook({ kind: "run", depValues });
|
|
1239
|
+
const out = this._fn(depValues, this._actions);
|
|
1240
|
+
if (isCleanupResult(out)) {
|
|
1241
|
+
this._cleanup = out.cleanup;
|
|
1242
|
+
if (this._manualEmitUsed) return;
|
|
1243
|
+
if ("value" in out) {
|
|
1244
|
+
this._downAutoValue(out.value);
|
|
1245
|
+
}
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
if (isCleanupFn(out)) {
|
|
1249
|
+
this._cleanup = out;
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
if (this._manualEmitUsed) return;
|
|
1253
|
+
if (out === void 0) return;
|
|
1254
|
+
this._downAutoValue(out);
|
|
1255
|
+
} catch (err) {
|
|
1256
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1257
|
+
const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
|
|
1258
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
1129
1259
|
}
|
|
1130
|
-
this._connected = false;
|
|
1131
|
-
this._depDirtyMask.reset();
|
|
1132
|
-
this._depSettledMask.reset();
|
|
1133
|
-
this._depCompleteMask.reset();
|
|
1134
|
-
this._status = "disconnected";
|
|
1135
1260
|
}
|
|
1136
1261
|
};
|
|
1262
|
+
var isNodeArray = (value) => Array.isArray(value);
|
|
1263
|
+
var isNodeOptions = (value) => typeof value === "object" && value != null && !Array.isArray(value);
|
|
1137
1264
|
function node(depsOrFn, fnOrOpts, optsArg) {
|
|
1138
1265
|
const deps = isNodeArray(depsOrFn) ? depsOrFn : [];
|
|
1139
1266
|
const fn = typeof depsOrFn === "function" ? depsOrFn : typeof fnOrOpts === "function" ? fnOrOpts : void 0;
|
|
@@ -2277,6 +2404,37 @@ function firstValueFrom(source) {
|
|
|
2277
2404
|
});
|
|
2278
2405
|
});
|
|
2279
2406
|
}
|
|
2407
|
+
function firstWhere(source, predicate) {
|
|
2408
|
+
return new Promise((resolve, reject) => {
|
|
2409
|
+
let settled = false;
|
|
2410
|
+
const unsub = source.subscribe((msgs) => {
|
|
2411
|
+
for (const m of msgs) {
|
|
2412
|
+
if (settled) return;
|
|
2413
|
+
if (m[0] === DATA) {
|
|
2414
|
+
const v = m[1];
|
|
2415
|
+
if (predicate(v)) {
|
|
2416
|
+
settled = true;
|
|
2417
|
+
resolve(v);
|
|
2418
|
+
queueMicrotask(() => unsub());
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
if (m[0] === ERROR) {
|
|
2423
|
+
settled = true;
|
|
2424
|
+
reject(m[1]);
|
|
2425
|
+
queueMicrotask(() => unsub());
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
if (m[0] === COMPLETE) {
|
|
2429
|
+
settled = true;
|
|
2430
|
+
reject(new Error("completed without matching value"));
|
|
2431
|
+
queueMicrotask(() => unsub());
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
});
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2280
2438
|
var shareReplay = replay;
|
|
2281
2439
|
|
|
2282
2440
|
// src/extra/adapters.ts
|
|
@@ -2519,6 +2677,10 @@ function toSSE(source, opts) {
|
|
|
2519
2677
|
unsub = source.subscribe((msgs) => {
|
|
2520
2678
|
for (const msg of msgs) {
|
|
2521
2679
|
const t = msg[0];
|
|
2680
|
+
if (isLocalOnly(t)) {
|
|
2681
|
+
if (t === DIRTY && includeDirty) {
|
|
2682
|
+
} else continue;
|
|
2683
|
+
}
|
|
2522
2684
|
if (t === DATA) {
|
|
2523
2685
|
write(dataEvent, serializeSseData(msg[1], serialize));
|
|
2524
2686
|
continue;
|
|
@@ -2534,7 +2696,6 @@ function toSSE(source, opts) {
|
|
|
2534
2696
|
return;
|
|
2535
2697
|
}
|
|
2536
2698
|
if (!includeResolved && t === RESOLVED) continue;
|
|
2537
|
-
if (!includeDirty && t === DIRTY) continue;
|
|
2538
2699
|
write(
|
|
2539
2700
|
eventNameResolver(t),
|
|
2540
2701
|
msg.length > 1 ? serializeSseData(msg[1], serialize) : void 0
|
|
@@ -5121,230 +5282,47 @@ function restoreGraphCheckpointIndexedDb(graph, spec) {
|
|
|
5121
5282
|
}
|
|
5122
5283
|
|
|
5123
5284
|
// src/core/dynamic-node.ts
|
|
5285
|
+
var MAX_RERUN = 16;
|
|
5124
5286
|
function dynamicNode(fn, opts) {
|
|
5125
5287
|
return new DynamicNodeImpl(fn, opts ?? {});
|
|
5126
5288
|
}
|
|
5127
|
-
var DynamicNodeImpl = class {
|
|
5128
|
-
_optsName;
|
|
5129
|
-
_registryName;
|
|
5130
|
-
_describeKind;
|
|
5131
|
-
meta;
|
|
5289
|
+
var DynamicNodeImpl = class extends NodeBase {
|
|
5132
5290
|
_fn;
|
|
5133
|
-
_equals;
|
|
5134
|
-
_resubscribable;
|
|
5135
|
-
_resetOnTeardown;
|
|
5136
5291
|
_autoComplete;
|
|
5137
|
-
_onMessage;
|
|
5138
|
-
_onResubscribe;
|
|
5139
|
-
/** @internal — read by {@link describeNode} for `accessHintForGuard`. */
|
|
5140
|
-
_guard;
|
|
5141
|
-
_lastMutation;
|
|
5142
|
-
_inspectorHook;
|
|
5143
|
-
// Sink tracking
|
|
5144
|
-
_sinkCount = 0;
|
|
5145
|
-
_singleDepSinkCount = 0;
|
|
5146
|
-
_singleDepSinks = /* @__PURE__ */ new WeakSet();
|
|
5147
|
-
// Actions object (for onMessage handler)
|
|
5148
|
-
_actions;
|
|
5149
|
-
_boundDownToSinks;
|
|
5150
|
-
// Mutable state
|
|
5151
|
-
_cached = NO_VALUE;
|
|
5152
|
-
_status = "disconnected";
|
|
5153
|
-
_terminal = false;
|
|
5154
|
-
_connected = false;
|
|
5155
|
-
_rewiring = false;
|
|
5156
|
-
// re-entrancy guard
|
|
5157
5292
|
// Dynamic deps tracking
|
|
5293
|
+
/** @internal Read by `describeNode`. */
|
|
5158
5294
|
_deps = [];
|
|
5159
5295
|
_depUnsubs = [];
|
|
5160
5296
|
_depIndexMap = /* @__PURE__ */ new Map();
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5297
|
+
_depDirtyBits = /* @__PURE__ */ new Set();
|
|
5298
|
+
_depSettledBits = /* @__PURE__ */ new Set();
|
|
5299
|
+
_depCompleteBits = /* @__PURE__ */ new Set();
|
|
5300
|
+
// Execution state
|
|
5301
|
+
_running = false;
|
|
5302
|
+
_rewiring = false;
|
|
5303
|
+
_bufferedDepMessages = [];
|
|
5304
|
+
_trackedValues = /* @__PURE__ */ new Map();
|
|
5305
|
+
_rerunCount = 0;
|
|
5167
5306
|
constructor(fn, opts) {
|
|
5307
|
+
super(opts);
|
|
5168
5308
|
this._fn = fn;
|
|
5169
|
-
this._optsName = opts.name;
|
|
5170
|
-
this._describeKind = opts.describeKind;
|
|
5171
|
-
this._equals = opts.equals ?? Object.is;
|
|
5172
|
-
this._resubscribable = opts.resubscribable ?? false;
|
|
5173
|
-
this._resetOnTeardown = opts.resetOnTeardown ?? false;
|
|
5174
5309
|
this._autoComplete = opts.completeWhenDepsComplete ?? true;
|
|
5175
|
-
this.
|
|
5176
|
-
this.
|
|
5177
|
-
this._guard = opts.guard;
|
|
5178
|
-
this._inspectorHook = void 0;
|
|
5179
|
-
const meta = {};
|
|
5180
|
-
for (const [k, v] of Object.entries(opts.meta ?? {})) {
|
|
5181
|
-
meta[k] = node({
|
|
5182
|
-
initial: v,
|
|
5183
|
-
name: `${opts.name ?? "dynamicNode"}:meta:${k}`,
|
|
5184
|
-
describeKind: "state",
|
|
5185
|
-
...opts.guard != null ? { guard: opts.guard } : {}
|
|
5186
|
-
});
|
|
5187
|
-
}
|
|
5188
|
-
Object.freeze(meta);
|
|
5189
|
-
this.meta = meta;
|
|
5190
|
-
const self = this;
|
|
5191
|
-
this._actions = {
|
|
5192
|
-
down(messages) {
|
|
5193
|
-
self._downInternal(messages);
|
|
5194
|
-
},
|
|
5195
|
-
emit(value) {
|
|
5196
|
-
self._downAutoValue(value);
|
|
5197
|
-
},
|
|
5198
|
-
up(messages) {
|
|
5199
|
-
for (const dep of self._deps) {
|
|
5200
|
-
dep.up?.(messages, { internal: true });
|
|
5201
|
-
}
|
|
5202
|
-
}
|
|
5203
|
-
};
|
|
5204
|
-
this._boundDownToSinks = this._downToSinks.bind(this);
|
|
5205
|
-
}
|
|
5206
|
-
get name() {
|
|
5207
|
-
return this._registryName ?? this._optsName;
|
|
5310
|
+
this.down = this.down.bind(this);
|
|
5311
|
+
this.up = this.up.bind(this);
|
|
5208
5312
|
}
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5313
|
+
_createMetaNode(key, initialValue, opts) {
|
|
5314
|
+
return node({
|
|
5315
|
+
initial: initialValue,
|
|
5316
|
+
name: `${opts.name ?? "dynamicNode"}:meta:${key}`,
|
|
5317
|
+
describeKind: "state",
|
|
5318
|
+
...opts.guard != null ? { guard: opts.guard } : {}
|
|
5319
|
+
});
|
|
5213
5320
|
}
|
|
5214
|
-
/**
|
|
5215
|
-
* @internal Attach/remove inspector hook for graph-level observability.
|
|
5216
|
-
* Returns a disposer that restores the previous hook.
|
|
5217
|
-
*/
|
|
5218
|
-
_setInspectorHook(hook) {
|
|
5219
|
-
const prev = this._inspectorHook;
|
|
5220
|
-
this._inspectorHook = hook;
|
|
5221
|
-
return () => {
|
|
5222
|
-
if (this._inspectorHook === hook) {
|
|
5223
|
-
this._inspectorHook = prev;
|
|
5224
|
-
}
|
|
5225
|
-
};
|
|
5226
|
-
}
|
|
5227
|
-
get status() {
|
|
5228
|
-
return this._status;
|
|
5229
|
-
}
|
|
5230
|
-
get lastMutation() {
|
|
5231
|
-
return this._lastMutation;
|
|
5232
|
-
}
|
|
5233
|
-
/** Versioning not yet supported on DynamicNodeImpl. */
|
|
5321
|
+
/** Versioning not supported on DynamicNodeImpl (override base). */
|
|
5234
5322
|
get v() {
|
|
5235
5323
|
return void 0;
|
|
5236
5324
|
}
|
|
5237
|
-
|
|
5238
|
-
return this._guard != null;
|
|
5239
|
-
}
|
|
5240
|
-
allowsObserve(actor) {
|
|
5241
|
-
if (this._guard == null) return true;
|
|
5242
|
-
return this._guard(normalizeActor(actor), "observe");
|
|
5243
|
-
}
|
|
5244
|
-
get() {
|
|
5245
|
-
return this._cached === NO_VALUE ? void 0 : this._cached;
|
|
5246
|
-
}
|
|
5247
|
-
down(messages, options) {
|
|
5248
|
-
if (messages.length === 0) return;
|
|
5249
|
-
if (!options?.internal && this._guard != null) {
|
|
5250
|
-
const actor = normalizeActor(options?.actor);
|
|
5251
|
-
const delivery = options?.delivery ?? "write";
|
|
5252
|
-
const action = delivery === "signal" ? "signal" : "write";
|
|
5253
|
-
if (!this._guard(actor, action)) {
|
|
5254
|
-
throw new GuardDenied({ actor, action, nodeName: this.name });
|
|
5255
|
-
}
|
|
5256
|
-
this._lastMutation = { actor, timestamp_ns: wallClockNs() };
|
|
5257
|
-
}
|
|
5258
|
-
this._downInternal(messages);
|
|
5259
|
-
}
|
|
5260
|
-
_downInternal(messages) {
|
|
5261
|
-
if (messages.length === 0) return;
|
|
5262
|
-
let sinkMessages = messages;
|
|
5263
|
-
if (this._terminal && !this._resubscribable) {
|
|
5264
|
-
const pass = messages.filter((m) => m[0] === TEARDOWN || m[0] === INVALIDATE);
|
|
5265
|
-
if (pass.length === 0) return;
|
|
5266
|
-
sinkMessages = pass;
|
|
5267
|
-
}
|
|
5268
|
-
this._handleLocalLifecycle(sinkMessages);
|
|
5269
|
-
if (this._canSkipDirty()) {
|
|
5270
|
-
let hasPhase2 = false;
|
|
5271
|
-
for (let i = 0; i < sinkMessages.length; i++) {
|
|
5272
|
-
const t = sinkMessages[i][0];
|
|
5273
|
-
if (t === DATA || t === RESOLVED) {
|
|
5274
|
-
hasPhase2 = true;
|
|
5275
|
-
break;
|
|
5276
|
-
}
|
|
5277
|
-
}
|
|
5278
|
-
if (hasPhase2) {
|
|
5279
|
-
const filtered = [];
|
|
5280
|
-
for (let i = 0; i < sinkMessages.length; i++) {
|
|
5281
|
-
if (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);
|
|
5282
|
-
}
|
|
5283
|
-
if (filtered.length > 0) {
|
|
5284
|
-
downWithBatch(this._boundDownToSinks, filtered);
|
|
5285
|
-
}
|
|
5286
|
-
return;
|
|
5287
|
-
}
|
|
5288
|
-
}
|
|
5289
|
-
downWithBatch(this._boundDownToSinks, sinkMessages);
|
|
5290
|
-
}
|
|
5291
|
-
_canSkipDirty() {
|
|
5292
|
-
return this._sinkCount === 1 && this._singleDepSinkCount === 1;
|
|
5293
|
-
}
|
|
5294
|
-
subscribe(sink, hints) {
|
|
5295
|
-
if (hints?.actor != null && this._guard != null) {
|
|
5296
|
-
const actor = normalizeActor(hints.actor);
|
|
5297
|
-
if (!this._guard(actor, "observe")) {
|
|
5298
|
-
throw new GuardDenied({ actor, action: "observe", nodeName: this.name });
|
|
5299
|
-
}
|
|
5300
|
-
}
|
|
5301
|
-
if (this._terminal && this._resubscribable) {
|
|
5302
|
-
this._terminal = false;
|
|
5303
|
-
this._cached = NO_VALUE;
|
|
5304
|
-
this._status = "disconnected";
|
|
5305
|
-
this._onResubscribe?.();
|
|
5306
|
-
}
|
|
5307
|
-
this._sinkCount += 1;
|
|
5308
|
-
if (hints?.singleDep) {
|
|
5309
|
-
this._singleDepSinkCount += 1;
|
|
5310
|
-
this._singleDepSinks.add(sink);
|
|
5311
|
-
}
|
|
5312
|
-
if (this._sinks == null) {
|
|
5313
|
-
this._sinks = sink;
|
|
5314
|
-
} else if (typeof this._sinks === "function") {
|
|
5315
|
-
this._sinks = /* @__PURE__ */ new Set([this._sinks, sink]);
|
|
5316
|
-
} else {
|
|
5317
|
-
this._sinks.add(sink);
|
|
5318
|
-
}
|
|
5319
|
-
if (!this._connected) {
|
|
5320
|
-
this._connect();
|
|
5321
|
-
}
|
|
5322
|
-
let removed = false;
|
|
5323
|
-
return () => {
|
|
5324
|
-
if (removed) return;
|
|
5325
|
-
removed = true;
|
|
5326
|
-
this._sinkCount -= 1;
|
|
5327
|
-
if (this._singleDepSinks.has(sink)) {
|
|
5328
|
-
this._singleDepSinkCount -= 1;
|
|
5329
|
-
this._singleDepSinks.delete(sink);
|
|
5330
|
-
}
|
|
5331
|
-
if (this._sinks == null) return;
|
|
5332
|
-
if (typeof this._sinks === "function") {
|
|
5333
|
-
if (this._sinks === sink) this._sinks = null;
|
|
5334
|
-
} else {
|
|
5335
|
-
this._sinks.delete(sink);
|
|
5336
|
-
if (this._sinks.size === 1) {
|
|
5337
|
-
const [only] = this._sinks;
|
|
5338
|
-
this._sinks = only;
|
|
5339
|
-
} else if (this._sinks.size === 0) {
|
|
5340
|
-
this._sinks = null;
|
|
5341
|
-
}
|
|
5342
|
-
}
|
|
5343
|
-
if (this._sinks == null) {
|
|
5344
|
-
this._disconnect();
|
|
5345
|
-
}
|
|
5346
|
-
};
|
|
5347
|
-
}
|
|
5325
|
+
// --- Up / unsubscribe ---
|
|
5348
5326
|
up(messages, options) {
|
|
5349
5327
|
if (this._deps.length === 0) return;
|
|
5350
5328
|
if (!options?.internal && this._guard != null) {
|
|
@@ -5352,221 +5330,227 @@ var DynamicNodeImpl = class {
|
|
|
5352
5330
|
if (!this._guard(actor, "write")) {
|
|
5353
5331
|
throw new GuardDenied({ actor, action: "write", nodeName: this.name });
|
|
5354
5332
|
}
|
|
5355
|
-
this.
|
|
5333
|
+
this._recordMutation(actor);
|
|
5356
5334
|
}
|
|
5357
5335
|
for (const dep of this._deps) {
|
|
5358
5336
|
dep.up?.(messages, options);
|
|
5359
5337
|
}
|
|
5360
5338
|
}
|
|
5361
|
-
|
|
5362
|
-
this.
|
|
5363
|
-
|
|
5364
|
-
// --- Private methods ---
|
|
5365
|
-
_downToSinks(messages) {
|
|
5366
|
-
if (this._sinks == null) return;
|
|
5367
|
-
if (typeof this._sinks === "function") {
|
|
5368
|
-
this._sinks(messages);
|
|
5369
|
-
return;
|
|
5370
|
-
}
|
|
5371
|
-
const snapshot = [...this._sinks];
|
|
5372
|
-
for (const sink of snapshot) {
|
|
5373
|
-
sink(messages);
|
|
5374
|
-
}
|
|
5375
|
-
}
|
|
5376
|
-
_handleLocalLifecycle(messages) {
|
|
5377
|
-
for (const m of messages) {
|
|
5378
|
-
const t = m[0];
|
|
5379
|
-
if (t === DATA) this._cached = m[1];
|
|
5380
|
-
if (t === INVALIDATE) {
|
|
5381
|
-
this._cached = NO_VALUE;
|
|
5382
|
-
this._status = "dirty";
|
|
5383
|
-
}
|
|
5384
|
-
if (t === DATA) {
|
|
5385
|
-
this._status = "settled";
|
|
5386
|
-
} else if (t === RESOLVED) {
|
|
5387
|
-
this._status = "resolved";
|
|
5388
|
-
} else if (t === DIRTY) {
|
|
5389
|
-
this._status = "dirty";
|
|
5390
|
-
} else if (t === COMPLETE) {
|
|
5391
|
-
this._status = "completed";
|
|
5392
|
-
this._terminal = true;
|
|
5393
|
-
} else if (t === ERROR) {
|
|
5394
|
-
this._status = "errored";
|
|
5395
|
-
this._terminal = true;
|
|
5396
|
-
}
|
|
5397
|
-
if (t === TEARDOWN) {
|
|
5398
|
-
if (this._resetOnTeardown) this._cached = NO_VALUE;
|
|
5399
|
-
try {
|
|
5400
|
-
this._propagateToMeta(t);
|
|
5401
|
-
} finally {
|
|
5402
|
-
this._disconnect();
|
|
5403
|
-
}
|
|
5404
|
-
}
|
|
5405
|
-
if (t !== TEARDOWN && propagatesToMeta(t)) {
|
|
5406
|
-
this._propagateToMeta(t);
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
}
|
|
5410
|
-
/** Propagate a signal to all companion meta nodes (best-effort). */
|
|
5411
|
-
_propagateToMeta(t) {
|
|
5412
|
-
for (const metaNode of Object.values(this.meta)) {
|
|
5413
|
-
try {
|
|
5414
|
-
metaNode.down([[t]], { internal: true });
|
|
5415
|
-
} catch {
|
|
5416
|
-
}
|
|
5339
|
+
_upInternal(messages) {
|
|
5340
|
+
for (const dep of this._deps) {
|
|
5341
|
+
dep.up?.(messages, { internal: true });
|
|
5417
5342
|
}
|
|
5418
5343
|
}
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
let unchanged;
|
|
5422
|
-
try {
|
|
5423
|
-
unchanged = this._cached !== NO_VALUE && this._equals(this._cached, value);
|
|
5424
|
-
} catch (eqErr) {
|
|
5425
|
-
const eqMsg = eqErr instanceof Error ? eqErr.message : String(eqErr);
|
|
5426
|
-
const wrapped = new Error(`Node "${this.name}": equals threw: ${eqMsg}`, { cause: eqErr });
|
|
5427
|
-
this._downInternal([[ERROR, wrapped]]);
|
|
5428
|
-
return;
|
|
5429
|
-
}
|
|
5430
|
-
if (unchanged) {
|
|
5431
|
-
this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
|
|
5432
|
-
return;
|
|
5433
|
-
}
|
|
5434
|
-
this._cached = value;
|
|
5435
|
-
this._downInternal(wasDirty ? [[DATA, value]] : [[DIRTY], [DATA, value]]);
|
|
5344
|
+
unsubscribe() {
|
|
5345
|
+
this._disconnect();
|
|
5436
5346
|
}
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
this._connected = true;
|
|
5440
|
-
this._status = "settled";
|
|
5441
|
-
this._dirtyBits.clear();
|
|
5442
|
-
this._settledBits.clear();
|
|
5443
|
-
this._completeBits.clear();
|
|
5347
|
+
// --- Activation hooks ---
|
|
5348
|
+
_onActivate() {
|
|
5444
5349
|
this._runFn();
|
|
5445
5350
|
}
|
|
5351
|
+
_doDeactivate() {
|
|
5352
|
+
this._disconnect();
|
|
5353
|
+
}
|
|
5446
5354
|
_disconnect() {
|
|
5447
|
-
if (!this._connected) return;
|
|
5448
5355
|
for (const unsub of this._depUnsubs) unsub();
|
|
5449
5356
|
this._depUnsubs = [];
|
|
5450
5357
|
this._deps = [];
|
|
5451
5358
|
this._depIndexMap.clear();
|
|
5452
|
-
this.
|
|
5453
|
-
this.
|
|
5454
|
-
this.
|
|
5455
|
-
this.
|
|
5359
|
+
this._depDirtyBits.clear();
|
|
5360
|
+
this._depSettledBits.clear();
|
|
5361
|
+
this._depCompleteBits.clear();
|
|
5362
|
+
this._cached = NO_VALUE;
|
|
5456
5363
|
this._status = "disconnected";
|
|
5457
5364
|
}
|
|
5365
|
+
// --- Fn execution with rewire buffer ---
|
|
5458
5366
|
_runFn() {
|
|
5459
5367
|
if (this._terminal && !this._resubscribable) return;
|
|
5460
|
-
if (this.
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
if (!trackedSet.has(dep)) {
|
|
5465
|
-
trackedSet.add(dep);
|
|
5466
|
-
trackedDeps.push(dep);
|
|
5467
|
-
}
|
|
5468
|
-
return dep.get();
|
|
5469
|
-
};
|
|
5368
|
+
if (this._running) return;
|
|
5369
|
+
this._running = true;
|
|
5370
|
+
this._rerunCount = 0;
|
|
5371
|
+
let result;
|
|
5470
5372
|
try {
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5373
|
+
for (; ; ) {
|
|
5374
|
+
const trackedDeps = [];
|
|
5375
|
+
const trackedValuesMap = /* @__PURE__ */ new Map();
|
|
5376
|
+
const trackedSet = /* @__PURE__ */ new Set();
|
|
5377
|
+
const get = (dep) => {
|
|
5378
|
+
if (!trackedSet.has(dep)) {
|
|
5379
|
+
trackedSet.add(dep);
|
|
5380
|
+
trackedDeps.push(dep);
|
|
5381
|
+
trackedValuesMap.set(dep, dep.get());
|
|
5382
|
+
}
|
|
5383
|
+
return dep.get();
|
|
5384
|
+
};
|
|
5385
|
+
this._trackedValues = trackedValuesMap;
|
|
5386
|
+
const depValues = [];
|
|
5387
|
+
for (const dep of this._deps) depValues.push(dep.get());
|
|
5388
|
+
this._emitInspectorHook({ kind: "run", depValues });
|
|
5389
|
+
try {
|
|
5390
|
+
result = this._fn(get);
|
|
5391
|
+
} catch (err) {
|
|
5392
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
5393
|
+
const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, {
|
|
5394
|
+
cause: err
|
|
5395
|
+
});
|
|
5396
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
this._rewiring = true;
|
|
5400
|
+
this._bufferedDepMessages = [];
|
|
5401
|
+
try {
|
|
5402
|
+
this._rewire(trackedDeps);
|
|
5403
|
+
} finally {
|
|
5404
|
+
this._rewiring = false;
|
|
5405
|
+
}
|
|
5406
|
+
let needsRerun = false;
|
|
5407
|
+
for (const entry of this._bufferedDepMessages) {
|
|
5408
|
+
for (const msg of entry.msgs) {
|
|
5409
|
+
if (msg[0] === DATA) {
|
|
5410
|
+
const dep = this._deps[entry.index];
|
|
5411
|
+
const trackedValue = dep != null ? this._trackedValues.get(dep) : void 0;
|
|
5412
|
+
const actualValue = msg[1];
|
|
5413
|
+
if (!this._equals(trackedValue, actualValue)) {
|
|
5414
|
+
needsRerun = true;
|
|
5415
|
+
break;
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
if (needsRerun) break;
|
|
5420
|
+
}
|
|
5421
|
+
if (needsRerun) {
|
|
5422
|
+
this._rerunCount += 1;
|
|
5423
|
+
if (this._rerunCount > MAX_RERUN) {
|
|
5424
|
+
this._bufferedDepMessages = [];
|
|
5425
|
+
this._downInternal([
|
|
5426
|
+
[
|
|
5427
|
+
ERROR,
|
|
5428
|
+
new Error(
|
|
5429
|
+
`dynamicNode "${this.name ?? "anonymous"}": rewire did not stabilize within ${MAX_RERUN} iterations`
|
|
5430
|
+
)
|
|
5431
|
+
]
|
|
5432
|
+
]);
|
|
5433
|
+
return;
|
|
5434
|
+
}
|
|
5435
|
+
this._bufferedDepMessages = [];
|
|
5436
|
+
continue;
|
|
5437
|
+
}
|
|
5438
|
+
const drain = this._bufferedDepMessages;
|
|
5439
|
+
this._bufferedDepMessages = [];
|
|
5440
|
+
for (const entry of drain) {
|
|
5441
|
+
for (const msg of entry.msgs) {
|
|
5442
|
+
this._updateMasksForMessage(entry.index, msg);
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
this._depDirtyBits.clear();
|
|
5446
|
+
this._depSettledBits.clear();
|
|
5447
|
+
break;
|
|
5448
|
+
}
|
|
5449
|
+
} finally {
|
|
5450
|
+
this._running = false;
|
|
5482
5451
|
}
|
|
5452
|
+
this._downAutoValue(result);
|
|
5483
5453
|
}
|
|
5484
5454
|
_rewire(newDeps) {
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
const
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
const unsub = dep.subscribe((msgs) => this._handleDepMessages(idx, msgs));
|
|
5501
|
-
newUnsubs.push(unsub);
|
|
5502
|
-
}
|
|
5455
|
+
const oldMap = this._depIndexMap;
|
|
5456
|
+
const newMap = /* @__PURE__ */ new Map();
|
|
5457
|
+
const newUnsubs = [];
|
|
5458
|
+
for (let i = 0; i < newDeps.length; i++) {
|
|
5459
|
+
const dep = newDeps[i];
|
|
5460
|
+
newMap.set(dep, i);
|
|
5461
|
+
const oldIdx = oldMap.get(dep);
|
|
5462
|
+
if (oldIdx !== void 0) {
|
|
5463
|
+
newUnsubs.push(this._depUnsubs[oldIdx]);
|
|
5464
|
+
this._depUnsubs[oldIdx] = () => {
|
|
5465
|
+
};
|
|
5466
|
+
} else {
|
|
5467
|
+
const idx = i;
|
|
5468
|
+
const unsub = dep.subscribe((msgs) => this._handleDepMessages(idx, msgs));
|
|
5469
|
+
newUnsubs.push(unsub);
|
|
5503
5470
|
}
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5471
|
+
}
|
|
5472
|
+
for (const [dep, oldIdx] of oldMap) {
|
|
5473
|
+
if (!newMap.has(dep)) {
|
|
5474
|
+
this._depUnsubs[oldIdx]();
|
|
5508
5475
|
}
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5476
|
+
}
|
|
5477
|
+
this._deps = newDeps;
|
|
5478
|
+
this._depUnsubs = newUnsubs;
|
|
5479
|
+
this._depIndexMap = newMap;
|
|
5480
|
+
this._depDirtyBits.clear();
|
|
5481
|
+
this._depSettledBits.clear();
|
|
5482
|
+
const newCompleteBits = /* @__PURE__ */ new Set();
|
|
5483
|
+
for (const oldIdx of this._depCompleteBits) {
|
|
5484
|
+
for (const [dep, idx] of oldMap) {
|
|
5485
|
+
if (idx === oldIdx && newMap.has(dep)) {
|
|
5518
5486
|
newCompleteBits.add(newMap.get(dep));
|
|
5487
|
+
break;
|
|
5519
5488
|
}
|
|
5520
5489
|
}
|
|
5521
|
-
this._completeBits = newCompleteBits;
|
|
5522
|
-
} finally {
|
|
5523
|
-
this._rewiring = false;
|
|
5524
5490
|
}
|
|
5491
|
+
this._depCompleteBits = newCompleteBits;
|
|
5525
5492
|
}
|
|
5493
|
+
// --- Dep message handling ---
|
|
5526
5494
|
_handleDepMessages(index, messages) {
|
|
5527
|
-
if (this._rewiring)
|
|
5495
|
+
if (this._rewiring) {
|
|
5496
|
+
this._bufferedDepMessages.push({ index, msgs: messages });
|
|
5497
|
+
return;
|
|
5498
|
+
}
|
|
5528
5499
|
for (const msg of messages) {
|
|
5529
|
-
this.
|
|
5500
|
+
this._emitInspectorHook({ kind: "dep_message", depIndex: index, message: msg });
|
|
5530
5501
|
const t = msg[0];
|
|
5531
5502
|
if (this._onMessage) {
|
|
5532
5503
|
try {
|
|
5533
5504
|
if (this._onMessage(msg, index, this._actions)) continue;
|
|
5534
5505
|
} catch (err) {
|
|
5535
|
-
|
|
5506
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
5507
|
+
const wrapped = new Error(`Node "${this.name}": onMessage threw: ${errMsg}`, {
|
|
5508
|
+
cause: err
|
|
5509
|
+
});
|
|
5510
|
+
this._downInternal([[ERROR, wrapped]]);
|
|
5536
5511
|
return;
|
|
5537
5512
|
}
|
|
5538
5513
|
}
|
|
5514
|
+
if (messageTier(t) < 1) continue;
|
|
5539
5515
|
if (t === DIRTY) {
|
|
5540
|
-
this.
|
|
5541
|
-
this.
|
|
5542
|
-
|
|
5543
|
-
|
|
5516
|
+
const wasEmpty = this._depDirtyBits.size === 0;
|
|
5517
|
+
this._depDirtyBits.add(index);
|
|
5518
|
+
this._depSettledBits.delete(index);
|
|
5519
|
+
if (wasEmpty) {
|
|
5520
|
+
this._downInternal([[DIRTY]]);
|
|
5544
5521
|
}
|
|
5545
5522
|
continue;
|
|
5546
5523
|
}
|
|
5547
5524
|
if (t === DATA || t === RESOLVED) {
|
|
5548
|
-
if (!this.
|
|
5549
|
-
this.
|
|
5550
|
-
|
|
5525
|
+
if (!this._depDirtyBits.has(index)) {
|
|
5526
|
+
const wasEmpty = this._depDirtyBits.size === 0;
|
|
5527
|
+
this._depDirtyBits.add(index);
|
|
5528
|
+
if (wasEmpty) {
|
|
5529
|
+
this._downInternal([[DIRTY]]);
|
|
5530
|
+
}
|
|
5551
5531
|
}
|
|
5552
|
-
this.
|
|
5532
|
+
this._depSettledBits.add(index);
|
|
5553
5533
|
if (this._allDirtySettled()) {
|
|
5554
|
-
this.
|
|
5555
|
-
this.
|
|
5556
|
-
this.
|
|
5534
|
+
this._depDirtyBits.clear();
|
|
5535
|
+
this._depSettledBits.clear();
|
|
5536
|
+
if (!this._running) {
|
|
5537
|
+
if (this._depValuesDifferFromTracked()) {
|
|
5538
|
+
this._runFn();
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5557
5541
|
}
|
|
5558
5542
|
continue;
|
|
5559
5543
|
}
|
|
5560
5544
|
if (t === COMPLETE) {
|
|
5561
|
-
this.
|
|
5562
|
-
this.
|
|
5563
|
-
this.
|
|
5545
|
+
this._depCompleteBits.add(index);
|
|
5546
|
+
this._depDirtyBits.delete(index);
|
|
5547
|
+
this._depSettledBits.delete(index);
|
|
5564
5548
|
if (this._allDirtySettled()) {
|
|
5565
|
-
this.
|
|
5566
|
-
this.
|
|
5567
|
-
this._runFn();
|
|
5549
|
+
this._depDirtyBits.clear();
|
|
5550
|
+
this._depSettledBits.clear();
|
|
5551
|
+
if (!this._running) this._runFn();
|
|
5568
5552
|
}
|
|
5569
|
-
if (this._autoComplete && this.
|
|
5553
|
+
if (this._autoComplete && this._depCompleteBits.size >= this._deps.length && this._deps.length > 0) {
|
|
5570
5554
|
this._downInternal([[COMPLETE]]);
|
|
5571
5555
|
}
|
|
5572
5556
|
continue;
|
|
@@ -5582,13 +5566,46 @@ var DynamicNodeImpl = class {
|
|
|
5582
5566
|
this._downInternal([msg]);
|
|
5583
5567
|
}
|
|
5584
5568
|
}
|
|
5569
|
+
/**
|
|
5570
|
+
* Update dep masks for a message without triggering `_runFn` — used
|
|
5571
|
+
* during post-rewire drain so the wave state is consistent with the
|
|
5572
|
+
* buffered activation cascade without recursing.
|
|
5573
|
+
*/
|
|
5574
|
+
_updateMasksForMessage(index, msg) {
|
|
5575
|
+
const t = msg[0];
|
|
5576
|
+
if (t === DIRTY) {
|
|
5577
|
+
this._depDirtyBits.add(index);
|
|
5578
|
+
this._depSettledBits.delete(index);
|
|
5579
|
+
} else if (t === DATA || t === RESOLVED) {
|
|
5580
|
+
this._depDirtyBits.add(index);
|
|
5581
|
+
this._depSettledBits.add(index);
|
|
5582
|
+
} else if (t === COMPLETE) {
|
|
5583
|
+
this._depCompleteBits.add(index);
|
|
5584
|
+
this._depDirtyBits.delete(index);
|
|
5585
|
+
this._depSettledBits.delete(index);
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
5585
5588
|
_allDirtySettled() {
|
|
5586
|
-
if (this.
|
|
5587
|
-
for (const idx of this.
|
|
5588
|
-
if (!this.
|
|
5589
|
+
if (this._depDirtyBits.size === 0) return false;
|
|
5590
|
+
for (const idx of this._depDirtyBits) {
|
|
5591
|
+
if (!this._depSettledBits.has(idx)) return false;
|
|
5589
5592
|
}
|
|
5590
5593
|
return true;
|
|
5591
5594
|
}
|
|
5595
|
+
/**
|
|
5596
|
+
* True if any current dep value differs from what the last `_runFn`
|
|
5597
|
+
* saw via `get()`. Used to suppress redundant re-runs when deferred
|
|
5598
|
+
* handshake messages arrive after `_rewire` for a dep whose value
|
|
5599
|
+
* already matches `_trackedValues`.
|
|
5600
|
+
*/
|
|
5601
|
+
_depValuesDifferFromTracked() {
|
|
5602
|
+
for (const dep of this._deps) {
|
|
5603
|
+
const current = dep.get();
|
|
5604
|
+
const tracked = this._trackedValues.get(dep);
|
|
5605
|
+
if (!this._equals(current, tracked)) return true;
|
|
5606
|
+
}
|
|
5607
|
+
return false;
|
|
5608
|
+
}
|
|
5592
5609
|
};
|
|
5593
5610
|
|
|
5594
5611
|
// src/extra/operators.ts
|
|
@@ -5651,9 +5668,12 @@ function reduce(source, reducer, seed, opts) {
|
|
|
5651
5668
|
}
|
|
5652
5669
|
function take(source, count, opts) {
|
|
5653
5670
|
if (count <= 0) {
|
|
5671
|
+
let completed = false;
|
|
5654
5672
|
return node(
|
|
5655
5673
|
[source],
|
|
5656
5674
|
(_d, a) => {
|
|
5675
|
+
if (completed) return void 0;
|
|
5676
|
+
completed = true;
|
|
5657
5677
|
a.down([[COMPLETE]]);
|
|
5658
5678
|
return void 0;
|
|
5659
5679
|
},
|
|
@@ -5661,8 +5681,15 @@ function take(source, count, opts) {
|
|
|
5661
5681
|
...operatorOpts3(opts),
|
|
5662
5682
|
completeWhenDepsComplete: false,
|
|
5663
5683
|
onMessage(msg, _i, a) {
|
|
5664
|
-
if (msg[0] ===
|
|
5684
|
+
if (msg[0] === START && !completed) {
|
|
5685
|
+
completed = true;
|
|
5686
|
+
a.down([[COMPLETE]]);
|
|
5687
|
+
return true;
|
|
5688
|
+
}
|
|
5689
|
+
if (msg[0] === COMPLETE && !completed) {
|
|
5690
|
+
completed = true;
|
|
5665
5691
|
a.down([[COMPLETE]]);
|
|
5692
|
+
return true;
|
|
5666
5693
|
}
|
|
5667
5694
|
return true;
|
|
5668
5695
|
}
|
|
@@ -5844,21 +5871,6 @@ function find(source, predicate, opts) {
|
|
|
5844
5871
|
function elementAt(source, index, opts) {
|
|
5845
5872
|
return take(skip(source, index, opts), 1, opts);
|
|
5846
5873
|
}
|
|
5847
|
-
function startWith(source, initial, opts) {
|
|
5848
|
-
let prepended = false;
|
|
5849
|
-
return node(
|
|
5850
|
-
[source],
|
|
5851
|
-
([v], a) => {
|
|
5852
|
-
if (!prepended) {
|
|
5853
|
-
prepended = true;
|
|
5854
|
-
a.emit(initial);
|
|
5855
|
-
}
|
|
5856
|
-
a.emit(v);
|
|
5857
|
-
return void 0;
|
|
5858
|
-
},
|
|
5859
|
-
operatorOpts3(opts)
|
|
5860
|
-
);
|
|
5861
|
-
}
|
|
5862
5874
|
function tap(source, fnOrObserver, opts) {
|
|
5863
5875
|
if (typeof fnOrObserver === "function") {
|
|
5864
5876
|
return derived(
|
|
@@ -6194,6 +6206,7 @@ function forwardInner(inner, a, onInnerComplete) {
|
|
|
6194
6206
|
let sawError = false;
|
|
6195
6207
|
const out = [];
|
|
6196
6208
|
for (const m of msgs) {
|
|
6209
|
+
if (messageTier(m[0]) < 1) continue;
|
|
6197
6210
|
if (m[0] === DATA) emitted = true;
|
|
6198
6211
|
if (m[0] === COMPLETE) sawComplete = true;
|
|
6199
6212
|
else {
|
|
@@ -6678,7 +6691,7 @@ function sample(source, notifier, opts) {
|
|
|
6678
6691
|
if (terminated) return true;
|
|
6679
6692
|
const t = msg[0];
|
|
6680
6693
|
const tier = messageTier(t);
|
|
6681
|
-
if (tier >=
|
|
6694
|
+
if (tier >= 4) {
|
|
6682
6695
|
if (t === ERROR) {
|
|
6683
6696
|
terminated = true;
|
|
6684
6697
|
a.down([msg]);
|
|
@@ -6694,6 +6707,7 @@ function sample(source, notifier, opts) {
|
|
|
6694
6707
|
a.down([msg]);
|
|
6695
6708
|
return true;
|
|
6696
6709
|
}
|
|
6710
|
+
terminated = true;
|
|
6697
6711
|
a.down([msg]);
|
|
6698
6712
|
return true;
|
|
6699
6713
|
}
|
|
@@ -8007,7 +8021,7 @@ function workerBridge(target, opts) {
|
|
|
8007
8021
|
for (const m of msgs) {
|
|
8008
8022
|
const type = m[0];
|
|
8009
8023
|
if (type === DATA) continue;
|
|
8010
|
-
if (
|
|
8024
|
+
if (isLocalOnly(type)) continue;
|
|
8011
8025
|
if (type === ERROR) {
|
|
8012
8026
|
transport.post({
|
|
8013
8027
|
t: "e",
|
|
@@ -8133,7 +8147,7 @@ function workerSelf(target, opts) {
|
|
|
8133
8147
|
for (const m of msgs) {
|
|
8134
8148
|
const type = m[0];
|
|
8135
8149
|
if (type === DATA) continue;
|
|
8136
|
-
if (
|
|
8150
|
+
if (isLocalOnly(type)) continue;
|
|
8137
8151
|
if (type === ERROR) {
|
|
8138
8152
|
transport.post({
|
|
8139
8153
|
t: "e",
|
|
@@ -8277,6 +8291,7 @@ function workerSelf(target, opts) {
|
|
|
8277
8291
|
find,
|
|
8278
8292
|
first,
|
|
8279
8293
|
firstValueFrom,
|
|
8294
|
+
firstWhere,
|
|
8280
8295
|
flatMap,
|
|
8281
8296
|
forEach,
|
|
8282
8297
|
fromAny,
|
|
@@ -8354,7 +8369,6 @@ function workerSelf(target, opts) {
|
|
|
8354
8369
|
shareReplay,
|
|
8355
8370
|
signalToName,
|
|
8356
8371
|
skip,
|
|
8357
|
-
startWith,
|
|
8358
8372
|
switchMap,
|
|
8359
8373
|
take,
|
|
8360
8374
|
takeUntil,
|