@solidjs/signals 2.0.0-beta.24 → 2.0.0-beta.26
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/dev.js +577 -87
- package/dist/node.cjs +1120 -683
- package/dist/prod/core/async.js +180 -107
- package/dist/prod/core/core.js +214 -180
- package/dist/prod/core/effect.js +19 -19
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +25 -25
- package/dist/prod/core/heap.js +23 -23
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +42 -40
- package/dist/prod/core/owner.js +41 -41
- package/dist/prod/core/scheduler.js +90 -90
- package/dist/prod/core/verdict.js +54 -54
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +18 -11
- package/dist/prod/store/projection.js +25 -18
- package/dist/prod/store/reconcile.js +405 -211
- package/dist/prod/store/store.js +225 -105
- package/dist/prod/store/utils.js +22 -22
- package/dist/types/core/async.d.ts +1 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/store/optimistic.d.ts +1 -1
- package/dist/types/store/store.d.ts +20 -2
- package/dist/types-cjs/core/async.d.cts +1 -0
- package/dist/types-cjs/core/core.d.cts +15 -0
- package/dist/types-cjs/store/optimistic.d.cts +1 -1
- package/dist/types-cjs/store/store.d.cts +20 -2
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -223,7 +223,7 @@ const activeLanes = new Set;
|
|
|
223
223
|
l: [ [], [] ],
|
|
224
224
|
S: null,
|
|
225
225
|
T: activeTransition,
|
|
226
|
-
|
|
226
|
+
O: r
|
|
227
227
|
};
|
|
228
228
|
signalLanes.set(e, t);
|
|
229
229
|
activeLanes.add(t);
|
|
@@ -233,7 +233,7 @@ const activeLanes = new Set;
|
|
|
233
233
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
234
234
|
// the owner's write merges the companion's subscribers into this lane and
|
|
235
235
|
// their effects wait on its async instead of flushing immediately.
|
|
236
|
-
adoptCompanionLane(e.
|
|
236
|
+
adoptCompanionLane(e._, t);
|
|
237
237
|
adoptCompanionLane(e.p, t);
|
|
238
238
|
return t;
|
|
239
239
|
}
|
|
@@ -245,7 +245,7 @@ function adoptCompanionLane(e, t) {
|
|
|
245
245
|
const r = findLane(n);
|
|
246
246
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
247
247
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
248
|
-
if (r !== t && r.o === e && !r.
|
|
248
|
+
if (r !== t && r.o === e && !r.O) r.O = t;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
/**
|
|
@@ -324,9 +324,9 @@ function resolveTransition(e) {
|
|
|
324
324
|
if (i !== n && !hasActiveOverride(e)) {
|
|
325
325
|
// Parent-child lanes stay independent so isPending resolves without
|
|
326
326
|
// waiting for the parent's async. The child keeps ownership.
|
|
327
|
-
if (n.
|
|
327
|
+
if (n.O && findLane(n.O) === i) {
|
|
328
328
|
e.i = t;
|
|
329
|
-
} else if (i.
|
|
329
|
+
} else if (i.O && findLane(i.O) === n) ; else mergeLanes(n, i);
|
|
330
330
|
}
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
@@ -376,24 +376,24 @@ function registerTransientStoreNode(e) {
|
|
|
376
376
|
|
|
377
377
|
function canUseSimpleSyncFlush(e) {
|
|
378
378
|
const t = e.D;
|
|
379
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.
|
|
379
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.L.length === 0 && t.V.size === 0 && transientStoreNodes.size === 0;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
function sweepTransientStoreNodes() {
|
|
383
383
|
if (transientStoreNodes.size === 0) return;
|
|
384
384
|
for (const e of transientStoreNodes) {
|
|
385
|
-
if (e.
|
|
385
|
+
if (e.G !== null) {
|
|
386
386
|
transientStoreNodes.delete(e);
|
|
387
387
|
continue;
|
|
388
388
|
}
|
|
389
|
-
if (e.
|
|
389
|
+
if (e.U !== NOT_PENDING) continue;
|
|
390
390
|
if (e.A !== undefined && e.A !== NOT_PENDING) continue;
|
|
391
391
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
392
392
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
393
393
|
// unmarked node for the same property).
|
|
394
394
|
if (e.k) continue;
|
|
395
395
|
transientStoreNodes.delete(e);
|
|
396
|
-
e.
|
|
396
|
+
e.W?.();
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
@@ -420,12 +420,12 @@ function setProjectionWriteActive(e) {
|
|
|
420
420
|
* land there directly — no per-field aliasing.
|
|
421
421
|
*/ function createBatch() {
|
|
422
422
|
return {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
423
|
+
F: clock,
|
|
424
|
+
H: [],
|
|
425
|
+
M: new Map,
|
|
426
426
|
v: [],
|
|
427
|
-
|
|
428
|
-
|
|
427
|
+
L: [],
|
|
428
|
+
V: new Set,
|
|
429
429
|
$: [],
|
|
430
430
|
j: {
|
|
431
431
|
K: [ [], [] ],
|
|
@@ -447,17 +447,17 @@ function mergeTransitionState(e, t) {
|
|
|
447
447
|
e.v.push(...t.v);
|
|
448
448
|
t.v.length = 0;
|
|
449
449
|
}
|
|
450
|
-
if (t.
|
|
450
|
+
if (t.L.length) {
|
|
451
451
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
452
452
|
// transition, and the adoption pass in initTransition would re-push its
|
|
453
453
|
// contents into the target — double-releasing every mark.
|
|
454
|
-
e.
|
|
455
|
-
t.
|
|
454
|
+
e.L.push(...t.L);
|
|
455
|
+
t.L.length = 0;
|
|
456
456
|
}
|
|
457
|
-
for (const n of t.
|
|
458
|
-
for (const [n, r] of t.
|
|
459
|
-
let t = e.
|
|
460
|
-
if (!t) e.
|
|
457
|
+
for (const n of t.V) e.V.add(n);
|
|
458
|
+
for (const [n, r] of t.M) {
|
|
459
|
+
let t = e.M.get(n);
|
|
460
|
+
if (!t) e.M.set(n, t = new Set);
|
|
461
461
|
for (const e of r) t.add(e);
|
|
462
462
|
}
|
|
463
463
|
for (const n of t.Y) e.Y.add(n);
|
|
@@ -599,14 +599,14 @@ class GlobalQueue extends Queue {
|
|
|
599
599
|
// isPending()/latest()).
|
|
600
600
|
static ue=null;
|
|
601
601
|
static le=null;
|
|
602
|
-
static ce=null;
|
|
603
602
|
static ae=null;
|
|
603
|
+
static ce=null;
|
|
604
604
|
static fe=null;
|
|
605
605
|
static Ee=null;
|
|
606
606
|
static de=null;
|
|
607
607
|
static Se=null;
|
|
608
608
|
static Te=null;
|
|
609
|
-
static
|
|
609
|
+
static Oe=null;
|
|
610
610
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
611
611
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
612
612
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -614,7 +614,7 @@ class GlobalQueue extends Queue {
|
|
|
614
614
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
615
615
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
616
616
|
// once the gate holds.
|
|
617
|
-
static
|
|
617
|
+
static _e=null;
|
|
618
618
|
static pe=null;
|
|
619
619
|
static Re=null;
|
|
620
620
|
static Ie=null;
|
|
@@ -654,29 +654,29 @@ class GlobalQueue extends Queue {
|
|
|
654
654
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
655
655
|
// scheduled so the outer drain loop commits them via the plain
|
|
656
656
|
// flush path instead of leaving them until the next natural flush.
|
|
657
|
-
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.
|
|
658
|
-
reassignPendingTransition(e.
|
|
657
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.H.length > 0;
|
|
658
|
+
reassignPendingTransition(e.H);
|
|
659
659
|
activeTransition = null;
|
|
660
660
|
finalizePureQueue(null, true);
|
|
661
661
|
return;
|
|
662
662
|
}
|
|
663
663
|
const t = activeTransition;
|
|
664
664
|
const n = this.D;
|
|
665
|
-
n !== t && n.
|
|
665
|
+
n !== t && n.H.push(...t.H);
|
|
666
666
|
this.restoreQueues(t.j);
|
|
667
667
|
transitions.delete(t);
|
|
668
668
|
activeTransition = null;
|
|
669
|
-
reassignPendingTransition(n.
|
|
669
|
+
reassignPendingTransition(n.H);
|
|
670
670
|
finalizePureQueue(t);
|
|
671
671
|
if (n === t) {
|
|
672
672
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
673
673
|
// as the ambient batch — late registrations during finalization live
|
|
674
674
|
// there and must survive to the next flush.
|
|
675
675
|
const e = createBatch();
|
|
676
|
-
e.
|
|
676
|
+
e.H = n.H;
|
|
677
677
|
e.v = n.v;
|
|
678
|
-
e.G = n.G;
|
|
679
678
|
e.L = n.L;
|
|
679
|
+
e.V = n.V;
|
|
680
680
|
currentBatch = this.D = e;
|
|
681
681
|
}
|
|
682
682
|
} else {
|
|
@@ -715,11 +715,11 @@ class GlobalQueue extends Queue {
|
|
|
715
715
|
// channel) updates display state on its way up but must be invisible
|
|
716
716
|
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
717
717
|
// reporter and never counts toward the loading-boundary diagnostic.
|
|
718
|
-
if (t?.
|
|
718
|
+
if (t?.we) return true;
|
|
719
719
|
if (activeTransition && t) {
|
|
720
720
|
const n = t.source;
|
|
721
|
-
let r = activeTransition.
|
|
722
|
-
if (!r) activeTransition.
|
|
721
|
+
let r = activeTransition.M.get(n);
|
|
722
|
+
if (!r) activeTransition.M.set(n, r = new Set);
|
|
723
723
|
const i = r.size;
|
|
724
724
|
r.add(e);
|
|
725
725
|
if (r.size !== i) schedule();
|
|
@@ -732,7 +732,7 @@ class GlobalQueue extends Queue {
|
|
|
732
732
|
initTransition(e) {
|
|
733
733
|
if (e) e = currentTransition(e);
|
|
734
734
|
if (e && e === activeTransition) return;
|
|
735
|
-
if (!e && activeTransition && activeTransition.
|
|
735
|
+
if (!e && activeTransition && activeTransition.F === clock) return;
|
|
736
736
|
if (!activeTransition) {
|
|
737
737
|
activeTransition = e ?? createBatch();
|
|
738
738
|
} else if (e) {
|
|
@@ -742,7 +742,7 @@ class GlobalQueue extends Queue {
|
|
|
742
742
|
activeTransition = e;
|
|
743
743
|
}
|
|
744
744
|
transitions.add(activeTransition);
|
|
745
|
-
activeTransition.
|
|
745
|
+
activeTransition.F = clock;
|
|
746
746
|
const t = this.D;
|
|
747
747
|
if (t !== activeTransition) {
|
|
748
748
|
// Adopt the ambient batch into the transaction, then make the
|
|
@@ -752,18 +752,18 @@ class GlobalQueue extends Queue {
|
|
|
752
752
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
753
753
|
// downstream: propagation never queues pended subscribers as pending
|
|
754
754
|
// nodes, see propagateAffectsMark, #2893.
|
|
755
|
-
for (let e = 0; e < t.
|
|
756
|
-
const n = t.
|
|
755
|
+
for (let e = 0; e < t.H.length; e++) {
|
|
756
|
+
const n = t.H[e];
|
|
757
757
|
n.T = activeTransition;
|
|
758
|
-
activeTransition.
|
|
758
|
+
activeTransition.H.push(n);
|
|
759
759
|
}
|
|
760
760
|
for (let e = 0; e < t.v.length; e++) {
|
|
761
761
|
const n = t.v[e];
|
|
762
762
|
n.T = activeTransition;
|
|
763
763
|
activeTransition.v.push(n);
|
|
764
764
|
}
|
|
765
|
-
if (t.
|
|
766
|
-
for (const e of t.
|
|
765
|
+
if (t.L.length) activeTransition.L.push(...t.L);
|
|
766
|
+
for (const e of t.V) activeTransition.V.add(e);
|
|
767
767
|
currentBatch = this.D = activeTransition;
|
|
768
768
|
}
|
|
769
769
|
for (const e of activeLanes) {
|
|
@@ -773,7 +773,7 @@ class GlobalQueue extends Queue {
|
|
|
773
773
|
}
|
|
774
774
|
|
|
775
775
|
function queuePendingNode(e) {
|
|
776
|
-
currentBatch.
|
|
776
|
+
currentBatch.H.push(e);
|
|
777
777
|
}
|
|
778
778
|
|
|
779
779
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -789,52 +789,52 @@ function insertSubs(e, t = false) {
|
|
|
789
789
|
// Get source lane: prefer node's own lane over current context
|
|
790
790
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
791
791
|
const n = e.i || currentOptimisticLane;
|
|
792
|
-
const r = e.
|
|
792
|
+
const r = e.me !== undefined;
|
|
793
793
|
const i = reaskArmed;
|
|
794
|
-
for (let o = e.
|
|
794
|
+
for (let o = e.G; o !== null; o = o.ve) {
|
|
795
795
|
// A value-change notification is a new question for the subscriber: any
|
|
796
796
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
797
|
-
if (i) o.Le
|
|
798
|
-
if (r && o.
|
|
799
|
-
o.Le
|
|
797
|
+
if (i) o.Ve.Le &= ~REACTIVE_REASK;
|
|
798
|
+
if (r && o.Ve.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
799
|
+
o.Ve.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
800
800
|
continue;
|
|
801
801
|
}
|
|
802
802
|
if (t && n) {
|
|
803
|
-
o.Le
|
|
804
|
-
assignOrMergeLane(o.
|
|
803
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
804
|
+
assignOrMergeLane(o.Ve, n);
|
|
805
805
|
} else if (t) {
|
|
806
|
-
o.Le
|
|
806
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
807
807
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
808
|
-
o.
|
|
808
|
+
o.Ve.i = undefined;
|
|
809
809
|
}
|
|
810
|
-
enqueueSub(o.
|
|
810
|
+
enqueueSub(o.Ve);
|
|
811
811
|
}
|
|
812
812
|
}
|
|
813
813
|
|
|
814
814
|
function commitPendingNode(e) {
|
|
815
815
|
const t = e;
|
|
816
|
-
if (!t.
|
|
817
|
-
if (e.
|
|
818
|
-
e.ke = e.
|
|
819
|
-
e.
|
|
816
|
+
if (!t.Ue) {
|
|
817
|
+
if (e.U !== NOT_PENDING) {
|
|
818
|
+
e.ke = e.U;
|
|
819
|
+
e.U = NOT_PENDING;
|
|
820
820
|
}
|
|
821
|
-
if (e.
|
|
821
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
822
822
|
return;
|
|
823
823
|
}
|
|
824
|
-
if (e.
|
|
825
|
-
e.ke = e.
|
|
826
|
-
e.
|
|
824
|
+
if (e.U !== NOT_PENDING) {
|
|
825
|
+
e.ke = e.U;
|
|
826
|
+
e.U = NOT_PENDING;
|
|
827
827
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
828
|
-
if (e.
|
|
828
|
+
if (e.We && e.We !== EFFECT_TRACKED) e.Fe = true;
|
|
829
829
|
}
|
|
830
|
-
t.
|
|
831
|
-
if (!(t.
|
|
832
|
-
if (t.
|
|
833
|
-
if (e.
|
|
830
|
+
t.Le &= ~REACTIVE_MANUAL_WRITE;
|
|
831
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
832
|
+
if (t.Qe !== null || t.He !== null) GlobalQueue.X(t, false, true);
|
|
833
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
834
834
|
}
|
|
835
835
|
|
|
836
836
|
function commitPendingNodes() {
|
|
837
|
-
const e = currentBatch.
|
|
837
|
+
const e = currentBatch.H;
|
|
838
838
|
for (let t = 0; t < e.length; t++) {
|
|
839
839
|
commitPendingNode(e[t]);
|
|
840
840
|
}
|
|
@@ -860,7 +860,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
860
860
|
// so they re-run with the now-committed values visible.
|
|
861
861
|
if (e && e.Y.size) {
|
|
862
862
|
for (const t of e.Y) {
|
|
863
|
-
if (t.
|
|
863
|
+
if (t.Le & REACTIVE_DISPOSED) continue;
|
|
864
864
|
enqueueSub(t);
|
|
865
865
|
}
|
|
866
866
|
e.Y.clear();
|
|
@@ -871,15 +871,15 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
871
871
|
// held boundary display state through the visual channel, and their
|
|
872
872
|
// release is the display-state update point — re-run the boundary sweep
|
|
873
873
|
// (the earlier sweep above ran while the marks were still live).
|
|
874
|
-
if (t.
|
|
875
|
-
GlobalQueue.ne(t.
|
|
874
|
+
if (t.L.length) {
|
|
875
|
+
GlobalQueue.ne(t.L);
|
|
876
876
|
if (globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
877
877
|
}
|
|
878
878
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
879
879
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
880
880
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
881
881
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
882
|
-
if (t.
|
|
882
|
+
if (t.V.size) GlobalQueue.ee(t.V, e);
|
|
883
883
|
sweepTransientStoreNodes();
|
|
884
884
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
885
885
|
if (activeLanes.size) GlobalQueue.Ie(e);
|
|
@@ -888,7 +888,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
888
888
|
|
|
889
889
|
function checkBoundaryChildren(e) {
|
|
890
890
|
for (const t of e.m) {
|
|
891
|
-
t.
|
|
891
|
+
t.Me?.();
|
|
892
892
|
checkBoundaryChildren(t);
|
|
893
893
|
}
|
|
894
894
|
}
|
|
@@ -955,7 +955,7 @@ function runQueue$1(e, t) {
|
|
|
955
955
|
}
|
|
956
956
|
|
|
957
957
|
function reporterBlocksSource(e, t) {
|
|
958
|
-
if (e.
|
|
958
|
+
if (e.Le & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
959
959
|
if (e.$e?.has(t)) return true;
|
|
960
960
|
for (let n = e.je; n; n = n.Ke) {
|
|
961
961
|
let e = n.Ye;
|
|
@@ -964,14 +964,14 @@ function reporterBlocksSource(e, t) {
|
|
|
964
964
|
e = e.t;
|
|
965
965
|
}
|
|
966
966
|
}
|
|
967
|
-
return !!(e.
|
|
967
|
+
return !!(e.xe & STATUS_PENDING && e.De instanceof NotReadyError && e.De.source === t);
|
|
968
968
|
}
|
|
969
969
|
|
|
970
970
|
function transitionComplete(e) {
|
|
971
971
|
if (e.I) return true;
|
|
972
972
|
if (e.$.length) return false;
|
|
973
973
|
let t = true;
|
|
974
|
-
for (const [n, r] of e.
|
|
974
|
+
for (const [n, r] of e.M) {
|
|
975
975
|
let i = false;
|
|
976
976
|
for (const e of r) {
|
|
977
977
|
if (reporterBlocksSource(e, n)) {
|
|
@@ -980,7 +980,7 @@ function transitionComplete(e) {
|
|
|
980
980
|
}
|
|
981
981
|
r.delete(e);
|
|
982
982
|
}
|
|
983
|
-
if (!i) e.
|
|
983
|
+
if (!i) e.M.delete(n); else if (n.xe & STATUS_PENDING && n.De?.source === n) {
|
|
984
984
|
t = false;
|
|
985
985
|
break;
|
|
986
986
|
}
|
|
@@ -1013,7 +1013,7 @@ function runInTransition(e, t) {
|
|
|
1013
1013
|
}
|
|
1014
1014
|
|
|
1015
1015
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1016
|
-
return e.
|
|
1016
|
+
return e.Le & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1017
1017
|
}
|
|
1018
1018
|
|
|
1019
1019
|
/**
|
|
@@ -1021,10 +1021,10 @@ function runInTransition(e, t) {
|
|
|
1021
1021
|
* the heap and go directly to their effect queue; everything else is inserted
|
|
1022
1022
|
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
1023
1023
|
*/ function enqueueSub(e) {
|
|
1024
|
-
if (e.
|
|
1024
|
+
if (e.We === EFFECT_TRACKED) {
|
|
1025
1025
|
const t = e;
|
|
1026
|
-
if (!t.
|
|
1027
|
-
t.
|
|
1026
|
+
if (!t.Fe) {
|
|
1027
|
+
t.Fe = true;
|
|
1028
1028
|
t.Be.enqueue(EFFECT_USER, t.Ze);
|
|
1029
1029
|
}
|
|
1030
1030
|
return;
|
|
@@ -1049,12 +1049,12 @@ function actualInsertIntoHeap(e, t) {
|
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
1051
|
function insertIntoHeap(e, t) {
|
|
1052
|
-
let n = e.
|
|
1052
|
+
let n = e.Le;
|
|
1053
1053
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1054
1054
|
if (n & REACTIVE_CHECK) {
|
|
1055
|
-
e.
|
|
1055
|
+
e.Le = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1056
1056
|
} else {
|
|
1057
|
-
e.
|
|
1057
|
+
e.Le = n | REACTIVE_IN_HEAP;
|
|
1058
1058
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1059
1059
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1060
1060
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1066,16 +1066,16 @@ function insertIntoHeap(e, t) {
|
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
1068
1068
|
function insertIntoHeapHeight(e, t) {
|
|
1069
|
-
let n = e.
|
|
1069
|
+
let n = e.Le;
|
|
1070
1070
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1071
|
-
e.
|
|
1071
|
+
e.Le = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1072
1072
|
actualInsertIntoHeap(e, t);
|
|
1073
1073
|
}
|
|
1074
1074
|
|
|
1075
1075
|
function deleteFromHeap(e, t) {
|
|
1076
|
-
const n = e.
|
|
1076
|
+
const n = e.Le;
|
|
1077
1077
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1078
|
-
e.
|
|
1078
|
+
e.Le = n & -25;
|
|
1079
1079
|
const r = e.Xe;
|
|
1080
1080
|
if (e.et === e) t.h[r] = undefined; else {
|
|
1081
1081
|
const n = e.tt;
|
|
@@ -1093,22 +1093,22 @@ function markHeap(e) {
|
|
|
1093
1093
|
e.N = true;
|
|
1094
1094
|
for (let t = 0; t <= e.C; t++) {
|
|
1095
1095
|
for (let n = e.h[t]; n !== undefined; n = n.tt) {
|
|
1096
|
-
if (n.
|
|
1096
|
+
if (n.Le & REACTIVE_IN_HEAP) markNode(n);
|
|
1097
1097
|
}
|
|
1098
1098
|
}
|
|
1099
1099
|
}
|
|
1100
1100
|
|
|
1101
1101
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1102
|
-
const n = e.
|
|
1102
|
+
const n = e.Le;
|
|
1103
1103
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1104
|
-
e.
|
|
1105
|
-
for (let t = e.
|
|
1106
|
-
markNode(t.
|
|
1104
|
+
e.Le = n & -4 | t;
|
|
1105
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
1106
|
+
markNode(t.Ve, REACTIVE_CHECK);
|
|
1107
1107
|
}
|
|
1108
1108
|
if (e.nt !== null) {
|
|
1109
1109
|
for (let t = e.nt; t !== null; t = t.rt) {
|
|
1110
|
-
for (let e = t.
|
|
1111
|
-
markNode(e.
|
|
1110
|
+
for (let e = t.G; e !== null; e = e.ve) {
|
|
1111
|
+
markNode(e.Ve, REACTIVE_CHECK);
|
|
1112
1112
|
}
|
|
1113
1113
|
}
|
|
1114
1114
|
}
|
|
@@ -1119,7 +1119,7 @@ function runHeap(e, t) {
|
|
|
1119
1119
|
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1120
1120
|
let n = e.h[e.P];
|
|
1121
1121
|
while (n !== undefined) {
|
|
1122
|
-
if (n.
|
|
1122
|
+
if (n.Le & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1123
1123
|
n = e.h[e.P];
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
@@ -1132,17 +1132,17 @@ function adjustHeight(e, t) {
|
|
|
1132
1132
|
for (let t = e.je; t; t = t.Ke) {
|
|
1133
1133
|
const e = t.Ye;
|
|
1134
1134
|
const r = e.qe || e;
|
|
1135
|
-
if (r.
|
|
1135
|
+
if (r.Ue && r.Xe >= n) n = r.Xe + 1;
|
|
1136
1136
|
}
|
|
1137
1137
|
if (e.Xe !== n) {
|
|
1138
1138
|
e.Xe = n;
|
|
1139
|
-
for (let t = e.
|
|
1139
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
1140
1140
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1141
1141
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1142
1142
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
1143
1143
|
// `zombieQueue`), breaking the flag/queue invariant `deleteFromHeap`
|
|
1144
1144
|
// relies on — the same corruption class as #2759.
|
|
1145
|
-
insertIntoHeapHeight(t.
|
|
1145
|
+
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
1146
1146
|
}
|
|
1147
1147
|
}
|
|
1148
1148
|
}
|
|
@@ -1153,8 +1153,8 @@ const PENDING_OWNER = {};
|
|
|
1153
1153
|
function markDisposal(e) {
|
|
1154
1154
|
let t = e.it;
|
|
1155
1155
|
while (t) {
|
|
1156
|
-
const e = t.
|
|
1157
|
-
t.
|
|
1156
|
+
const e = t.Le;
|
|
1157
|
+
t.Le = e | REACTIVE_ZOMBIE;
|
|
1158
1158
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1159
1159
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1160
1160
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1180,20 +1180,20 @@ function dispose(e) {
|
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
1182
|
function disposeChildren(e, t = false, n) {
|
|
1183
|
-
const r = e.
|
|
1183
|
+
const r = e.Le;
|
|
1184
1184
|
if (r & REACTIVE_DISPOSED) return;
|
|
1185
1185
|
if (t) {
|
|
1186
|
-
e.
|
|
1186
|
+
e.Le = r | REACTIVE_DISPOSED;
|
|
1187
1187
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1188
1188
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1189
1189
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1190
1190
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1191
1191
|
// false, and notifies subscribers still watching the companion.
|
|
1192
1192
|
const t = e;
|
|
1193
|
-
if (t.
|
|
1193
|
+
if (t._ || t.p) GlobalQueue.ce(t);
|
|
1194
1194
|
}
|
|
1195
|
-
if (t && e.
|
|
1196
|
-
let i = n ? e.
|
|
1195
|
+
if (t && e.Ue) e.ut = null;
|
|
1196
|
+
let i = n ? e.Qe : e.it;
|
|
1197
1197
|
while (i) {
|
|
1198
1198
|
const e = i.ot;
|
|
1199
1199
|
if (i.je) {
|
|
@@ -1210,7 +1210,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1210
1210
|
i = e;
|
|
1211
1211
|
}
|
|
1212
1212
|
if (n) {
|
|
1213
|
-
e.
|
|
1213
|
+
e.Qe = null;
|
|
1214
1214
|
} else {
|
|
1215
1215
|
e.it = null;
|
|
1216
1216
|
e.lt = 0;
|
|
@@ -1219,7 +1219,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1219
1219
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1220
1220
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1221
1221
|
// walks that already advanced past us still reach later siblings.
|
|
1222
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.
|
|
1222
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.Le & REACTIVE_DISPOSED)) {
|
|
1223
1223
|
const t = e.ct;
|
|
1224
1224
|
const n = e.ot;
|
|
1225
1225
|
if (t !== null) t.ot = n; else e.B.it = n;
|
|
@@ -1237,7 +1237,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1237
1237
|
}
|
|
1238
1238
|
|
|
1239
1239
|
function runDisposal(e, t) {
|
|
1240
|
-
let n = t ? e.
|
|
1240
|
+
let n = t ? e.He : e.Et;
|
|
1241
1241
|
if (!n) return;
|
|
1242
1242
|
if (Array.isArray(n)) {
|
|
1243
1243
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1247,12 +1247,12 @@ function runDisposal(e, t) {
|
|
|
1247
1247
|
} else {
|
|
1248
1248
|
n.call(n);
|
|
1249
1249
|
}
|
|
1250
|
-
t ? e.
|
|
1250
|
+
t ? e.He = null : e.Et = null;
|
|
1251
1251
|
}
|
|
1252
1252
|
|
|
1253
1253
|
function childId(e, t) {
|
|
1254
1254
|
let n = e;
|
|
1255
|
-
while (n.
|
|
1255
|
+
while (n.Ge & CONFIG_TRANSPARENT && n.B) n = n.B;
|
|
1256
1256
|
if (n.id != null) return formatId(n.id, t ? n.lt++ : n.lt);
|
|
1257
1257
|
throw new Error("");
|
|
1258
1258
|
}
|
|
@@ -1354,7 +1354,7 @@ function formatId(e, t) {
|
|
|
1354
1354
|
* }
|
|
1355
1355
|
* ```
|
|
1356
1356
|
*/ function isDisposed(e) {
|
|
1357
|
-
return !!(e.
|
|
1357
|
+
return !!(e.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1358
1358
|
}
|
|
1359
1359
|
|
|
1360
1360
|
function disposeRootSelf(e = true) {
|
|
@@ -1373,7 +1373,7 @@ function disposeRootSelf(e = true) {
|
|
|
1373
1373
|
const n = e?.transparent ?? false;
|
|
1374
1374
|
const r = {
|
|
1375
1375
|
id: inheritId(e, n, t),
|
|
1376
|
-
|
|
1376
|
+
Ge: n ? CONFIG_TRANSPARENT : 0,
|
|
1377
1377
|
ze: true,
|
|
1378
1378
|
Je: t?.ze ? t.Je : t,
|
|
1379
1379
|
it: null,
|
|
@@ -1383,8 +1383,8 @@ function disposeRootSelf(e = true) {
|
|
|
1383
1383
|
Be: t?.Be ?? globalQueue,
|
|
1384
1384
|
dt: t?.dt || defaultContext,
|
|
1385
1385
|
lt: 0,
|
|
1386
|
-
|
|
1387
|
-
|
|
1386
|
+
He: null,
|
|
1387
|
+
Qe: null,
|
|
1388
1388
|
B: t,
|
|
1389
1389
|
dispose: disposeRootSelf
|
|
1390
1390
|
};
|
|
@@ -1433,13 +1433,13 @@ function disposeRootSelf(e = true) {
|
|
|
1433
1433
|
function unlinkSubs(e) {
|
|
1434
1434
|
const t = e.Ye;
|
|
1435
1435
|
const n = e.Ke;
|
|
1436
|
-
const r = e.
|
|
1436
|
+
const r = e.ve;
|
|
1437
1437
|
const i = e.St;
|
|
1438
1438
|
if (r !== null) r.St = i; else t.Tt = i;
|
|
1439
|
-
if (i !== null) i.
|
|
1440
|
-
t.
|
|
1439
|
+
if (i !== null) i.ve = r; else {
|
|
1440
|
+
t.G = r;
|
|
1441
1441
|
if (r === null) {
|
|
1442
|
-
t.
|
|
1442
|
+
t.W?.();
|
|
1443
1443
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1444
1444
|
// A pending node is exempt: its in-flight async work (or the
|
|
1445
1445
|
// transition holding it) is an observer — tearing down would orphan
|
|
@@ -1447,7 +1447,7 @@ function unlinkSubs(e) {
|
|
|
1447
1447
|
// this same last-one-out check when that observer releases (the
|
|
1448
1448
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1449
1449
|
const e = t;
|
|
1450
|
-
e.
|
|
1450
|
+
e.Ue && e.Ge & CONFIG_AUTO_DISPOSE && !(e.Le & REACTIVE_ZOMBIE) && !(e.xe & STATUS_PENDING) && unobserved(e);
|
|
1451
1451
|
}
|
|
1452
1452
|
}
|
|
1453
1453
|
return n;
|
|
@@ -1484,18 +1484,18 @@ function link(e, t, n = false) {
|
|
|
1484
1484
|
// read order within the computation.
|
|
1485
1485
|
const r = t.st;
|
|
1486
1486
|
if (r !== null && r.Ye === e) {
|
|
1487
|
-
r.
|
|
1487
|
+
r.Ot &&= n;
|
|
1488
1488
|
return;
|
|
1489
1489
|
}
|
|
1490
1490
|
let i = null;
|
|
1491
|
-
const o = t.
|
|
1491
|
+
const o = t.Le & REACTIVE_RECOMPUTING_DEPS;
|
|
1492
1492
|
if (o) {
|
|
1493
1493
|
i = r !== null ? r.Ke : t.je;
|
|
1494
1494
|
if (i !== null && i.Ye === e) {
|
|
1495
|
-
i.
|
|
1495
|
+
i._t = t.Rt;
|
|
1496
1496
|
t.st = i;
|
|
1497
1497
|
// First touch of this pass: the previous pass's label is stale.
|
|
1498
|
-
i.
|
|
1498
|
+
i.Ot = n;
|
|
1499
1499
|
return;
|
|
1500
1500
|
}
|
|
1501
1501
|
}
|
|
@@ -1505,23 +1505,23 @@ function link(e, t, n = false) {
|
|
|
1505
1505
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1506
1506
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1507
1507
|
const s = e.Tt;
|
|
1508
|
-
if (s !== null && s.
|
|
1508
|
+
if (s !== null && s.Ve === t && (!o || s._t === t.Rt)) {
|
|
1509
1509
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1510
1510
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1511
|
-
if (o) s.
|
|
1511
|
+
if (o) s.Ot &&= n; else s.Ot = n;
|
|
1512
1512
|
return;
|
|
1513
1513
|
}
|
|
1514
1514
|
const u = t.st = e.Tt = {
|
|
1515
1515
|
Ye: e,
|
|
1516
|
-
|
|
1516
|
+
Ve: t,
|
|
1517
1517
|
Ke: i,
|
|
1518
1518
|
St: s,
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1519
|
+
ve: null,
|
|
1520
|
+
_t: t.Rt,
|
|
1521
|
+
Ot: n
|
|
1522
1522
|
};
|
|
1523
1523
|
if (r !== null) r.Ke = u; else t.je = u;
|
|
1524
|
-
if (s !== null) s.
|
|
1524
|
+
if (s !== null) s.ve = u; else e.G = u;
|
|
1525
1525
|
}
|
|
1526
1526
|
|
|
1527
1527
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1562,42 +1562,78 @@ function setPendingError(e, t, n) {
|
|
|
1562
1562
|
}
|
|
1563
1563
|
|
|
1564
1564
|
function forEachDependent(e, t) {
|
|
1565
|
-
for (let n = e.
|
|
1565
|
+
for (let n = e.G; n !== null; n = n.ve) t(n.Ve, n);
|
|
1566
1566
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1567
1567
|
for (let n = e.nt ?? null; n !== null; n = n.rt) {
|
|
1568
|
-
for (let e = n.
|
|
1568
|
+
for (let e = n.G; e !== null; e = e.ve) t(e.Ve, e);
|
|
1569
1569
|
}
|
|
1570
1570
|
}
|
|
1571
1571
|
|
|
1572
1572
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
1573
1573
|
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
1574
1574
|
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
1575
|
+
// Settle-time counterpart of unlinkSubs' last-one-out check. A lazy node that
|
|
1576
|
+
// loses its last subscriber while STATUS_PENDING is exempt from autodispose
|
|
1577
|
+
// (the in-flight work is an observer), so whatever CLEARS that pending state
|
|
1578
|
+
// must run the release — otherwise the node stays linked and recomputes
|
|
1579
|
+
// forever with zero subscribers (#2934). The node's own promise/iterator
|
|
1580
|
+
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1581
|
+
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1582
|
+
function releaseIfSettledUnobserved(e) {
|
|
1583
|
+
e.Ue && e.Ge & CONFIG_AUTO_DISPOSE && !e.G && !(e.Le & REACTIVE_ZOMBIE) && !(e.xe & STATUS_PENDING) && unobserved(e);
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
1587
|
+
// sources through its own recursion (no per-node settle callback), so after
|
|
1588
|
+
// the propagation completes, walk the same graph for stranded lazy nodes.
|
|
1589
|
+
// Collect-then-release so unobserved() never unlinks under the walk.
|
|
1590
|
+
function releaseSettledDependents(e) {
|
|
1591
|
+
let t;
|
|
1592
|
+
const n = new Set;
|
|
1593
|
+
const visit = e => {
|
|
1594
|
+
if (n.has(e)) return;
|
|
1595
|
+
n.add(e);
|
|
1596
|
+
if (!e.G && e.Ge & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
1597
|
+
forEachDependent(e, visit);
|
|
1598
|
+
};
|
|
1599
|
+
forEachDependent(e, visit);
|
|
1600
|
+
if (t) for (const e of t) releaseIfSettledUnobserved(e);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1575
1603
|
function settlePendingSource(e) {
|
|
1576
1604
|
let t = false;
|
|
1577
|
-
|
|
1605
|
+
let n;
|
|
1606
|
+
const r = new Set;
|
|
1578
1607
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1579
|
-
const
|
|
1580
|
-
const settle =
|
|
1581
|
-
if (
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
if (
|
|
1586
|
-
setPendingError(
|
|
1587
|
-
|
|
1608
|
+
const i = GlobalQueue.le;
|
|
1609
|
+
const settle = o => {
|
|
1610
|
+
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1611
|
+
r.add(o);
|
|
1612
|
+
o.F = clock;
|
|
1613
|
+
const s = o.$e?.values().next().value;
|
|
1614
|
+
if (s) {
|
|
1615
|
+
setPendingError(o, s);
|
|
1616
|
+
i !== null && i(o);
|
|
1588
1617
|
} else {
|
|
1589
|
-
|
|
1590
|
-
setPendingError(
|
|
1591
|
-
|
|
1592
|
-
if (
|
|
1593
|
-
enqueueSub(
|
|
1618
|
+
o.xe &= ~STATUS_PENDING;
|
|
1619
|
+
setPendingError(o);
|
|
1620
|
+
i !== null && i(o);
|
|
1621
|
+
if (o.It) {
|
|
1622
|
+
enqueueSub(o);
|
|
1594
1623
|
t = true;
|
|
1595
1624
|
}
|
|
1596
|
-
|
|
1625
|
+
o.It = false;
|
|
1626
|
+
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1627
|
+
// again at release time — deferred so unobserved() can't unlink subs
|
|
1628
|
+
// lists this walk is still iterating.
|
|
1629
|
+
if (!o.G && o.Ge & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
1597
1630
|
}
|
|
1598
|
-
forEachDependent(
|
|
1631
|
+
forEachDependent(o, settle);
|
|
1599
1632
|
};
|
|
1600
1633
|
forEachDependent(e, settle);
|
|
1634
|
+
// Release before the flush schedule below: unobserved() pulls the node back
|
|
1635
|
+
// out of the heap, so the enqueueSub above never recomputes a released node.
|
|
1636
|
+
if (n) for (const e of n) releaseIfSettledUnobserved(e);
|
|
1601
1637
|
if (t) schedule();
|
|
1602
1638
|
}
|
|
1603
1639
|
|
|
@@ -1621,21 +1657,46 @@ function handleAsync(e, t, n) {
|
|
|
1621
1657
|
}
|
|
1622
1658
|
e.ut = t;
|
|
1623
1659
|
let o;
|
|
1660
|
+
// Settle-time transition re-entry. The loading rail is invisible to
|
|
1661
|
+
// transactions (#2933): a boundary-caught first load never registers as an
|
|
1662
|
+
// async reporter, so its settle — the boundary's fallback -> content
|
|
1663
|
+
// reveal — must flow ambiently. The node can still carry a `_transition`
|
|
1664
|
+
// stamp (pending-node bookkeeping rides through the stamping sites), and
|
|
1665
|
+
// blindly re-entering that stamped, still-incomplete transaction stashed
|
|
1666
|
+
// the reveal with it — a deadlock when the transaction's completion
|
|
1667
|
+
// depended on the reveal (#2937). An ESCAPED first load did register and
|
|
1668
|
+
// keeps transition scheduling; initialized (value-holding) pending settles
|
|
1669
|
+
// are the transaction's reveal machinery and always re-enter.
|
|
1670
|
+
const settleTransition = () => {
|
|
1671
|
+
const t = resolveTransition(e);
|
|
1672
|
+
if (t && e.xe & STATUS_UNINITIALIZED && !currentTransition(t).M.has(e)) {
|
|
1673
|
+
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1674
|
+
// stash-path restamp both re-enter the transaction through it.
|
|
1675
|
+
e.T = null;
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
globalQueue.initTransition(t);
|
|
1679
|
+
};
|
|
1624
1680
|
const handleError = n => {
|
|
1625
1681
|
if (e.ut !== t) return;
|
|
1626
|
-
|
|
1682
|
+
settleTransition();
|
|
1627
1683
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1628
|
-
|
|
1629
|
-
e
|
|
1684
|
+
const r = n instanceof NotReadyError;
|
|
1685
|
+
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1686
|
+
e.F = clock;
|
|
1687
|
+
// A real error settles derivatively-pending dependents (notifyStatus
|
|
1688
|
+
// cleared their pending sources), so stranded lazy ones release here —
|
|
1689
|
+
// the error twin of settlePendingSource's release (#2934).
|
|
1690
|
+
if (!r) releaseSettledDependents(e);
|
|
1630
1691
|
};
|
|
1631
1692
|
const asyncWrite = (r, i) => {
|
|
1632
1693
|
if (e.ut !== t) return;
|
|
1633
1694
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1634
1695
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1635
1696
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1636
|
-
if (e.
|
|
1637
|
-
|
|
1638
|
-
const o = !!(e.
|
|
1697
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1698
|
+
settleTransition();
|
|
1699
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1639
1700
|
trimStaleDeps(e);
|
|
1640
1701
|
clearStatus(e);
|
|
1641
1702
|
const s = resolveLane(e);
|
|
@@ -1653,8 +1714,8 @@ function handleAsync(e, t, n) {
|
|
|
1653
1714
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
1654
1715
|
// has committed by then, so corrections reveal atomically with their
|
|
1655
1716
|
// transition rather than escaping it.
|
|
1656
|
-
if (e.
|
|
1657
|
-
e.
|
|
1717
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
1718
|
+
e.U = r;
|
|
1658
1719
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
1659
1720
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
1660
1721
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -1664,16 +1725,16 @@ function handleAsync(e, t, n) {
|
|
|
1664
1725
|
// re-show an unchanged view — the revert is the notification point.
|
|
1665
1726
|
GlobalQueue.ue !== null && GlobalQueue.ue(e, r);
|
|
1666
1727
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1667
|
-
e.
|
|
1728
|
+
e.F = clock;
|
|
1668
1729
|
} else if (s) {
|
|
1669
1730
|
// Route through lane's effect queue for independent flushing
|
|
1670
|
-
const t = e.
|
|
1731
|
+
const t = e.We;
|
|
1671
1732
|
const n = e.ke;
|
|
1672
1733
|
const i = e.At;
|
|
1673
1734
|
try {
|
|
1674
1735
|
if (!t && o || !i || !i(r, n)) {
|
|
1675
1736
|
e.ke = r;
|
|
1676
|
-
e.
|
|
1737
|
+
e.F = clock;
|
|
1677
1738
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1678
1739
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1679
1740
|
// (computePendingState doesn't read _value).
|
|
@@ -1706,10 +1767,14 @@ function handleAsync(e, t, n) {
|
|
|
1706
1767
|
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
1707
1768
|
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1708
1769
|
// it runs the same last-one-out check the other release sites run.
|
|
1770
|
+
// Returns whether the node released, so the iterator branch can stop
|
|
1771
|
+
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1709
1772
|
const settleAutodispose = () => {
|
|
1710
|
-
if (e.
|
|
1773
|
+
if (e.Ge & CONFIG_AUTO_DISPOSE && !e.G && !(e.xe & STATUS_PENDING)) {
|
|
1711
1774
|
unobserved(e);
|
|
1775
|
+
return true;
|
|
1712
1776
|
}
|
|
1777
|
+
return false;
|
|
1713
1778
|
};
|
|
1714
1779
|
if (i) {
|
|
1715
1780
|
let n = false, r = false, i, s = true;
|
|
@@ -1755,18 +1820,24 @@ function handleAsync(e, t, n) {
|
|
|
1755
1820
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
1756
1821
|
} catch {}
|
|
1757
1822
|
});
|
|
1823
|
+
// Release check before each next pull: an unobserved lazy node must tear
|
|
1824
|
+
// down (its cleanup above closes the iterator) instead of pumping the
|
|
1825
|
+
// stream forever with zero subscribers (#2935).
|
|
1826
|
+
const iterateOrRelease = () => {
|
|
1827
|
+
if (!settleAutodispose()) iterate();
|
|
1828
|
+
};
|
|
1758
1829
|
const iterate = () => {
|
|
1759
|
-
let u, l,
|
|
1830
|
+
let u, l, a = false, c = false, f = true;
|
|
1760
1831
|
n.next().then(n => {
|
|
1761
1832
|
if (f) {
|
|
1762
1833
|
u = n;
|
|
1763
|
-
|
|
1834
|
+
a = true;
|
|
1764
1835
|
if (n.done) i = true;
|
|
1765
1836
|
} else if (e.ut !== t) {
|
|
1766
1837
|
return;
|
|
1767
1838
|
} else if (!n.done) {
|
|
1768
1839
|
r = true;
|
|
1769
|
-
asyncWrite(n.value,
|
|
1840
|
+
asyncWrite(n.value, iterateOrRelease);
|
|
1770
1841
|
} else {
|
|
1771
1842
|
i = true;
|
|
1772
1843
|
if (r) {
|
|
@@ -1776,30 +1847,32 @@ function handleAsync(e, t, n) {
|
|
|
1776
1847
|
// Empty completion settles like the immediately-done sync path.
|
|
1777
1848
|
asyncWrite(undefined);
|
|
1778
1849
|
}
|
|
1850
|
+
settleAutodispose();
|
|
1779
1851
|
}
|
|
1780
1852
|
}, n => {
|
|
1781
1853
|
if (f) {
|
|
1782
1854
|
l = n;
|
|
1783
|
-
|
|
1855
|
+
c = true;
|
|
1784
1856
|
} else if (e.ut === t) {
|
|
1785
1857
|
i = true;
|
|
1786
1858
|
handleError(n);
|
|
1859
|
+
settleAutodispose();
|
|
1787
1860
|
}
|
|
1788
1861
|
});
|
|
1789
1862
|
f = false;
|
|
1790
|
-
if (
|
|
1863
|
+
if (c) {
|
|
1791
1864
|
// Match the promise branch, but only rethrow during the initial read.
|
|
1792
1865
|
i = true;
|
|
1793
1866
|
handleError(l);
|
|
1794
1867
|
if (s) throw l;
|
|
1795
1868
|
return true;
|
|
1796
1869
|
}
|
|
1797
|
-
if (
|
|
1870
|
+
if (a && !u.done) {
|
|
1798
1871
|
o = u.value;
|
|
1799
1872
|
r = true;
|
|
1800
1873
|
return iterate();
|
|
1801
1874
|
}
|
|
1802
|
-
return
|
|
1875
|
+
return a && u.done;
|
|
1803
1876
|
};
|
|
1804
1877
|
const u = iterate();
|
|
1805
1878
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
@@ -1819,12 +1892,12 @@ function clearStatus(e, t = false) {
|
|
|
1819
1892
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1820
1893
|
// plain store to an existing slot — no shape change.)
|
|
1821
1894
|
e.ht = false;
|
|
1822
|
-
e.
|
|
1895
|
+
e.xe = t ? 0 : e.xe & STATUS_UNINITIALIZED;
|
|
1823
1896
|
if (e.De) setPendingError(e);
|
|
1824
1897
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1825
1898
|
// once the verdict layer created them, which installs the hooks).
|
|
1826
|
-
if (e.
|
|
1827
|
-
if (e.nt && GlobalQueue.
|
|
1899
|
+
if (e._ || e.p) GlobalQueue.le(e);
|
|
1900
|
+
if (e.nt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1828
1901
|
if (e.Nt) e.Nt();
|
|
1829
1902
|
}
|
|
1830
1903
|
|
|
@@ -1838,28 +1911,28 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1838
1911
|
if (!r) {
|
|
1839
1912
|
if (t === STATUS_PENDING && o) {
|
|
1840
1913
|
addPendingSource(e, o);
|
|
1841
|
-
e.
|
|
1914
|
+
e.xe = STATUS_PENDING | e.xe & STATUS_UNINITIALIZED;
|
|
1842
1915
|
// Preserve the current source on this propagation so render-effect notification
|
|
1843
1916
|
// can register every distinct pending source with the transition.
|
|
1844
1917
|
setPendingError(e, o, n);
|
|
1845
1918
|
} else {
|
|
1846
1919
|
clearPendingSources(e);
|
|
1847
|
-
e.
|
|
1920
|
+
e.xe = t | (t !== STATUS_ERROR ? e.xe & STATUS_UNINITIALIZED : 0);
|
|
1848
1921
|
e.De = n;
|
|
1849
1922
|
}
|
|
1850
1923
|
GlobalQueue.le !== null && GlobalQueue.le(e);
|
|
1851
|
-
if (e.nt && GlobalQueue.
|
|
1924
|
+
if (e.nt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1852
1925
|
}
|
|
1853
1926
|
if (i && !r) {
|
|
1854
1927
|
assignOrMergeLane(e, i);
|
|
1855
1928
|
}
|
|
1856
|
-
const
|
|
1857
|
-
const
|
|
1929
|
+
const a = r || l;
|
|
1930
|
+
const c = r || u ? undefined : i;
|
|
1858
1931
|
if (e.Nt) {
|
|
1859
1932
|
if (r && t === STATUS_PENDING) {
|
|
1860
1933
|
return;
|
|
1861
1934
|
}
|
|
1862
|
-
if (
|
|
1935
|
+
if (a) {
|
|
1863
1936
|
e.Nt(t, n);
|
|
1864
1937
|
} else {
|
|
1865
1938
|
e.Nt();
|
|
@@ -1867,20 +1940,20 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1867
1940
|
return;
|
|
1868
1941
|
}
|
|
1869
1942
|
forEachDependent(e, (e, r) => {
|
|
1870
|
-
e.
|
|
1943
|
+
e.F = clock;
|
|
1871
1944
|
if (t === STATUS_PENDING && o && !e.$e?.has(o) || t !== STATUS_PENDING && (e.De !== n || e.$e)) {
|
|
1872
1945
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1873
1946
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1874
1947
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1875
1948
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1876
1949
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1877
|
-
if (r.
|
|
1950
|
+
if (r.Ot && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1878
1951
|
enqueueSub(e);
|
|
1879
1952
|
schedule();
|
|
1880
1953
|
return;
|
|
1881
1954
|
}
|
|
1882
|
-
if (!
|
|
1883
|
-
notifyStatus(e, t, n,
|
|
1955
|
+
if (!a && !e.T) queuePendingNode(e);
|
|
1956
|
+
notifyStatus(e, t, n, a, c);
|
|
1884
1957
|
}
|
|
1885
1958
|
});
|
|
1886
1959
|
}
|
|
@@ -1947,12 +2020,12 @@ function releaseSubtree(e) {
|
|
|
1947
2020
|
t = t.ot;
|
|
1948
2021
|
continue;
|
|
1949
2022
|
}
|
|
1950
|
-
if (t.
|
|
2023
|
+
if (t.Ue) {
|
|
1951
2024
|
const e = t;
|
|
1952
|
-
e.
|
|
1953
|
-
if (e.
|
|
1954
|
-
e.
|
|
1955
|
-
e.
|
|
2025
|
+
e.Ge &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
2026
|
+
if (e.Le & REACTIVE_SNAPSHOT_STALE) {
|
|
2027
|
+
e.Le &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2028
|
+
e.Le |= REACTIVE_DIRTY;
|
|
1956
2029
|
if (dirtyQueue.P > e.Xe) dirtyQueue.P = e.Xe;
|
|
1957
2030
|
insertIntoHeap(e, dirtyQueue);
|
|
1958
2031
|
}
|
|
@@ -1965,7 +2038,7 @@ function releaseSubtree(e) {
|
|
|
1965
2038
|
function clearSnapshots() {
|
|
1966
2039
|
if (snapshotSources) {
|
|
1967
2040
|
for (const e of snapshotSources) {
|
|
1968
|
-
delete e.
|
|
2041
|
+
delete e.me;
|
|
1969
2042
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
1970
2043
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
1971
2044
|
// when present so signal-node sources don't grow the field.
|
|
@@ -1977,7 +2050,7 @@ function clearSnapshots() {
|
|
|
1977
2050
|
}
|
|
1978
2051
|
|
|
1979
2052
|
function recompute(e, t = false) {
|
|
1980
|
-
const n = e.
|
|
2053
|
+
const n = e.We;
|
|
1981
2054
|
if (!t) {
|
|
1982
2055
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
1983
2056
|
deleteFromHeap(e, queueFor(e));
|
|
@@ -1985,28 +2058,28 @@ function recompute(e, t = false) {
|
|
|
1985
2058
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
1986
2059
|
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.it !== null || e.Et !== null) {
|
|
1987
2060
|
markDisposal(e);
|
|
1988
|
-
e.
|
|
1989
|
-
e.
|
|
2061
|
+
e.He = e.Et;
|
|
2062
|
+
e.Qe = e.it;
|
|
1990
2063
|
e.Et = null;
|
|
1991
2064
|
e.it = null;
|
|
1992
2065
|
e.lt = 0;
|
|
1993
2066
|
} else ;
|
|
1994
2067
|
}
|
|
1995
|
-
let r = !!(e.
|
|
2068
|
+
let r = !!(e.Le & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1996
2069
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1997
|
-
const o = !!(e.
|
|
2070
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1998
2071
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1999
2072
|
// the recompute wipes _flags below.
|
|
2000
|
-
const s = (e.
|
|
2073
|
+
const s = (e.Le & REACTIVE_REASK) !== 0;
|
|
2001
2074
|
const u = context;
|
|
2002
2075
|
context = e;
|
|
2003
2076
|
e.st = null;
|
|
2004
2077
|
e.Rt++;
|
|
2005
|
-
e.
|
|
2006
|
-
e.
|
|
2007
|
-
let l = e.
|
|
2008
|
-
let
|
|
2009
|
-
let
|
|
2078
|
+
e.Le = REACTIVE_RECOMPUTING_DEPS;
|
|
2079
|
+
e.F = clock;
|
|
2080
|
+
let l = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2081
|
+
let a = e.Xe;
|
|
2082
|
+
let c = tracking;
|
|
2010
2083
|
let f = currentOptimisticLane;
|
|
2011
2084
|
tracking = true;
|
|
2012
2085
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
@@ -2037,8 +2110,8 @@ function recompute(e, t = false) {
|
|
|
2037
2110
|
const S = stale;
|
|
2038
2111
|
if (d) stale = true;
|
|
2039
2112
|
try {
|
|
2040
|
-
if (!false && e.
|
|
2041
|
-
l = e.
|
|
2113
|
+
if (!false && e.Ge & CONFIG_SYNC) {
|
|
2114
|
+
l = e.Ue(l);
|
|
2042
2115
|
e.ut = null;
|
|
2043
2116
|
} else {
|
|
2044
2117
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
@@ -2047,13 +2120,16 @@ function recompute(e, t = false) {
|
|
|
2047
2120
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2048
2121
|
// iteration drive updates.
|
|
2049
2122
|
const t = e.ut;
|
|
2050
|
-
const n = e.
|
|
2123
|
+
const n = e.Ue(l);
|
|
2051
2124
|
const r = typeof n === "object" && n !== null;
|
|
2052
2125
|
const i = e.ut !== t;
|
|
2053
2126
|
l = i || !r ? n : handleAsync(e, n);
|
|
2054
2127
|
if (!i && !r) e.ut = null;
|
|
2055
2128
|
}
|
|
2056
|
-
clearStatus
|
|
2129
|
+
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2130
|
+
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2131
|
+
// the flags write (create or not) stores the 0 already there.
|
|
2132
|
+
if (e.xe !== 0 || e.Nt !== undefined || e.De || e.ht || e.It || e.$e !== undefined || e._ !== undefined || e.p !== undefined || e.nt !== null) clearStatus(e, t);
|
|
2057
2133
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2058
2134
|
if (e.i) GlobalQueue.ge(e);
|
|
2059
2135
|
} catch (t) {
|
|
@@ -2068,15 +2144,15 @@ function recompute(e, t = false) {
|
|
|
2068
2144
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2069
2145
|
if (n) GlobalQueue.Te(e);
|
|
2070
2146
|
} finally {
|
|
2071
|
-
tracking =
|
|
2147
|
+
tracking = c;
|
|
2072
2148
|
latestReadActive = E;
|
|
2073
2149
|
if (d) stale = S;
|
|
2074
|
-
e.
|
|
2150
|
+
e.Le = REACTIVE_NONE | (t ? e.Le & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2075
2151
|
context = u;
|
|
2076
2152
|
}
|
|
2077
2153
|
if (!e.De) {
|
|
2078
2154
|
trimStaleDeps(e);
|
|
2079
|
-
const s = i ? unwrapOverride(e.A) : e.
|
|
2155
|
+
const s = i ? unwrapOverride(e.A) : e.U === NOT_PENDING ? e.ke : e.U;
|
|
2080
2156
|
let u = false;
|
|
2081
2157
|
try {
|
|
2082
2158
|
u = !n && o || !e.At || !e.At(s, l);
|
|
@@ -2093,14 +2169,19 @@ function recompute(e, t = false) {
|
|
|
2093
2169
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2094
2170
|
// effect() can call its runner synchronously for the first run.
|
|
2095
2171
|
if (n && u) {
|
|
2096
|
-
e.
|
|
2172
|
+
e.Fe = !e.De;
|
|
2097
2173
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2098
2174
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2099
2175
|
if (!t) e.Be.enqueue(n, e.Pt ??= GlobalQueue.J.bind(null, e));
|
|
2100
2176
|
}
|
|
2101
2177
|
if (e.De) ; else if (u) {
|
|
2102
2178
|
const o = i ? e.A : undefined;
|
|
2103
|
-
if (t ||
|
|
2179
|
+
if (t ||
|
|
2180
|
+
// Plain sync flush (no transition on either side) commits effect
|
|
2181
|
+
// values directly — the pending round-trip (queuePendingNode +
|
|
2182
|
+
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2183
|
+
// paying it per effect on the plain path is pure overhead.
|
|
2184
|
+
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2104
2185
|
e.ke = l;
|
|
2105
2186
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2106
2187
|
// override unconditionally. The direct _value commit is the lane's
|
|
@@ -2108,10 +2189,10 @@ function recompute(e, t = false) {
|
|
|
2108
2189
|
// commit can't clobber the fresh value.
|
|
2109
2190
|
if (i && r) {
|
|
2110
2191
|
e.A = l === undefined ? OVERRIDE_UNDEFINED : l;
|
|
2111
|
-
e.
|
|
2192
|
+
e.U = NOT_PENDING;
|
|
2112
2193
|
}
|
|
2113
2194
|
} else {
|
|
2114
|
-
e.
|
|
2195
|
+
e.U = l;
|
|
2115
2196
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2116
2197
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2117
2198
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
@@ -2119,61 +2200,63 @@ function recompute(e, t = false) {
|
|
|
2119
2200
|
// pending value commits before effects run.
|
|
2120
2201
|
if ((activeTransition || e.T) && GlobalQueue.ue !== null) GlobalQueue.ue(e, l);
|
|
2121
2202
|
}
|
|
2122
|
-
|
|
2203
|
+
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2204
|
+
// subscriber-less node has nothing to notify.
|
|
2205
|
+
if (e.G !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2123
2206
|
} else if (i) {
|
|
2124
2207
|
// Unchanged value (equals the override) recomputed while the override
|
|
2125
2208
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2126
2209
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2127
|
-
if (e.
|
|
2128
|
-
e.
|
|
2129
|
-
} else if (e.Xe !=
|
|
2130
|
-
for (let t = e.
|
|
2131
|
-
insertIntoHeapHeight(t.
|
|
2210
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2211
|
+
e.U = l;
|
|
2212
|
+
} else if (e.Xe != a) {
|
|
2213
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
2214
|
+
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2132
2215
|
}
|
|
2133
2216
|
}
|
|
2134
2217
|
}
|
|
2135
2218
|
currentOptimisticLane = f;
|
|
2136
|
-
const T = e.
|
|
2219
|
+
const T = e.U !== NOT_PENDING || e.Qe !== null || e.He !== null || (e.xe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2137
2220
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2138
2221
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2139
2222
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2140
2223
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2141
2224
|
// _transition.
|
|
2142
|
-
T && (!t || e.
|
|
2225
|
+
T && (!t || e.xe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2143
2226
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2144
2227
|
}
|
|
2145
2228
|
|
|
2146
2229
|
function updateIfNecessary(e) {
|
|
2147
|
-
if (e.
|
|
2230
|
+
if (e.Le & REACTIVE_CHECK) {
|
|
2148
2231
|
for (let t = e.je; t; t = t.Ke) {
|
|
2149
2232
|
const n = t.Ye;
|
|
2150
2233
|
const r = n.qe || n;
|
|
2151
|
-
if (r.
|
|
2234
|
+
if (r.Ue) {
|
|
2152
2235
|
updateIfNecessary(r);
|
|
2153
2236
|
}
|
|
2154
|
-
if (e.
|
|
2237
|
+
if (e.Le & REACTIVE_DIRTY) {
|
|
2155
2238
|
break;
|
|
2156
2239
|
}
|
|
2157
2240
|
}
|
|
2158
2241
|
}
|
|
2159
|
-
if (e.
|
|
2242
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.De && e.F < clock && !e.ut) {
|
|
2160
2243
|
recompute(e);
|
|
2161
2244
|
}
|
|
2162
|
-
e.
|
|
2245
|
+
e.Le = e.Le & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2163
2246
|
}
|
|
2164
2247
|
|
|
2165
2248
|
function computed(e, t) {
|
|
2166
2249
|
const n = t?.transparent ?? false;
|
|
2167
2250
|
const r = {
|
|
2168
2251
|
id: inheritId(t, n, context),
|
|
2169
|
-
|
|
2252
|
+
Ge: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2170
2253
|
At: t?.equals != null ? t.equals : isEqual,
|
|
2171
|
-
|
|
2254
|
+
W: t?.unobserved,
|
|
2172
2255
|
Et: null,
|
|
2173
2256
|
Be: context?.Be ?? globalQueue,
|
|
2174
2257
|
dt: context?.dt ?? defaultContext,
|
|
2175
2258
|
lt: 0,
|
|
2176
|
-
|
|
2259
|
+
Ue: e,
|
|
2177
2260
|
ke: undefined,
|
|
2178
2261
|
Xe: 0,
|
|
2179
2262
|
nt: null,
|
|
@@ -2182,18 +2265,18 @@ function computed(e, t) {
|
|
|
2182
2265
|
je: null,
|
|
2183
2266
|
st: null,
|
|
2184
2267
|
Rt: 0,
|
|
2185
|
-
|
|
2268
|
+
G: null,
|
|
2186
2269
|
Tt: null,
|
|
2187
2270
|
B: context,
|
|
2188
2271
|
ot: null,
|
|
2189
2272
|
ct: null,
|
|
2190
2273
|
it: null,
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2274
|
+
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2275
|
+
xe: STATUS_UNINITIALIZED,
|
|
2276
|
+
F: clock,
|
|
2277
|
+
U: NOT_PENDING,
|
|
2278
|
+
He: null,
|
|
2279
|
+
Qe: null,
|
|
2197
2280
|
ut: null,
|
|
2198
2281
|
T: null,
|
|
2199
2282
|
ht: false
|
|
@@ -2211,14 +2294,14 @@ function computed(e, t) {
|
|
|
2211
2294
|
const s = o?.transparent ?? false;
|
|
2212
2295
|
const u = {
|
|
2213
2296
|
id: inheritId(o, s, context),
|
|
2214
|
-
|
|
2297
|
+
Ge: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2215
2298
|
At: false,
|
|
2216
|
-
|
|
2299
|
+
W: o?.unobserved,
|
|
2217
2300
|
Et: null,
|
|
2218
2301
|
Be: context?.Be ?? globalQueue,
|
|
2219
2302
|
dt: context?.dt ?? defaultContext,
|
|
2220
2303
|
lt: 0,
|
|
2221
|
-
|
|
2304
|
+
Ue: e,
|
|
2222
2305
|
ke: undefined,
|
|
2223
2306
|
Xe: 0,
|
|
2224
2307
|
nt: null,
|
|
@@ -2227,27 +2310,27 @@ function computed(e, t) {
|
|
|
2227
2310
|
je: null,
|
|
2228
2311
|
st: null,
|
|
2229
2312
|
Rt: 0,
|
|
2230
|
-
|
|
2313
|
+
G: null,
|
|
2231
2314
|
Tt: null,
|
|
2232
2315
|
B: context,
|
|
2233
2316
|
ot: null,
|
|
2234
2317
|
ct: null,
|
|
2235
2318
|
it: null,
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2319
|
+
Le: REACTIVE_LAZY,
|
|
2320
|
+
xe: STATUS_UNINITIALIZED,
|
|
2321
|
+
F: clock,
|
|
2322
|
+
U: NOT_PENDING,
|
|
2323
|
+
He: null,
|
|
2324
|
+
Qe: null,
|
|
2242
2325
|
ut: null,
|
|
2243
2326
|
T: null,
|
|
2244
2327
|
ht: false,
|
|
2245
|
-
|
|
2328
|
+
Fe: false,
|
|
2246
2329
|
gt: undefined,
|
|
2247
2330
|
bt: t,
|
|
2248
2331
|
Dt: n,
|
|
2249
2332
|
ft: undefined,
|
|
2250
|
-
|
|
2333
|
+
We: r,
|
|
2251
2334
|
Nt: i
|
|
2252
2335
|
};
|
|
2253
2336
|
setupComputedNode(u, lazyOptions);
|
|
@@ -2275,8 +2358,8 @@ function setupComputedNode(e, t) {
|
|
|
2275
2358
|
if (GlobalQueue.oe !== null) GlobalQueue.oe(e);
|
|
2276
2359
|
!t?.lazy && recompute(e, true);
|
|
2277
2360
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2278
|
-
if (!(e.
|
|
2279
|
-
e.
|
|
2361
|
+
if (!(e.xe & STATUS_PENDING) && !(e.Ge & CONFIG_NO_SNAPSHOT)) {
|
|
2362
|
+
e.me = e.ke === undefined ? NO_SNAPSHOT : e.ke;
|
|
2280
2363
|
snapshotSources.add(e);
|
|
2281
2364
|
}
|
|
2282
2365
|
}
|
|
@@ -2285,19 +2368,19 @@ function setupComputedNode(e, t) {
|
|
|
2285
2368
|
function signal(e, t, n = null) {
|
|
2286
2369
|
const r = {
|
|
2287
2370
|
At: t?.equals != null ? t.equals : isEqual,
|
|
2288
|
-
|
|
2289
|
-
|
|
2371
|
+
Ge: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0),
|
|
2372
|
+
W: t?.unobserved,
|
|
2290
2373
|
ke: e,
|
|
2291
|
-
|
|
2374
|
+
G: null,
|
|
2292
2375
|
Tt: null,
|
|
2293
|
-
|
|
2376
|
+
F: clock,
|
|
2294
2377
|
qe: n,
|
|
2295
2378
|
rt: n?.nt || null,
|
|
2296
|
-
|
|
2379
|
+
U: NOT_PENDING
|
|
2297
2380
|
};
|
|
2298
2381
|
n && (n.nt = r);
|
|
2299
|
-
if (snapshotCaptureActive && !(r.
|
|
2300
|
-
r.
|
|
2382
|
+
if (snapshotCaptureActive && !(r.Ge & CONFIG_NO_SNAPSHOT) && !((n?.xe ?? 0) & STATUS_PENDING)) {
|
|
2383
|
+
r.me = e === undefined ? NO_SNAPSHOT : e;
|
|
2301
2384
|
snapshotSources.add(r);
|
|
2302
2385
|
}
|
|
2303
2386
|
return r;
|
|
@@ -2357,16 +2440,37 @@ function isEqual(e, t) {
|
|
|
2357
2440
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2358
2441
|
* date so its status flags reflect the current graph.
|
|
2359
2442
|
*/ function prepareComputed(e, t) {
|
|
2360
|
-
if (e.
|
|
2361
|
-
e.
|
|
2443
|
+
if (e.Le & REACTIVE_LAZY) {
|
|
2444
|
+
e.Le &= ~REACTIVE_LAZY;
|
|
2362
2445
|
recompute(e, true);
|
|
2363
|
-
} else if (e.
|
|
2446
|
+
} else if (e.Le & REACTIVE_DISPOSED) {
|
|
2364
2447
|
recompute(e, true);
|
|
2365
2448
|
} else if (t) {
|
|
2366
2449
|
updateIfNecessary(e);
|
|
2367
2450
|
}
|
|
2368
2451
|
}
|
|
2369
2452
|
|
|
2453
|
+
/**
|
|
2454
|
+
* Sentinel returned by readNodeFast when the plain-signal fast path does not
|
|
2455
|
+
* apply and the caller must fall back to the full read().
|
|
2456
|
+
*/ const READ_SLOW = Symbol("read-slow");
|
|
2457
|
+
|
|
2458
|
+
/**
|
|
2459
|
+
* read()'s plain-signal fast path as a standalone entry for hot callers
|
|
2460
|
+
* (store traps). Safe to substitute for read() only because the bail
|
|
2461
|
+
* conditions mirror read()'s prelude and fast-path guard exactly: the
|
|
2462
|
+
* latestRead and pendingCheck windows run side-effectful hooks before the
|
|
2463
|
+
* fast path, `_fn` nodes need prepareComputed, and firewall / override /
|
|
2464
|
+
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2465
|
+
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2466
|
+
*/ function readNodeFast(e) {
|
|
2467
|
+
if (latestReadActive || pendingCheckActive || e.Ue || e.qe || e.A !== undefined || e.me !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2468
|
+
let t = context;
|
|
2469
|
+
if (t?.ze) t = t.Je;
|
|
2470
|
+
if (t && tracking) link(e, t);
|
|
2471
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2370
2474
|
function read(e) {
|
|
2371
2475
|
// Handle latest() mode: read from _latestValueComputed
|
|
2372
2476
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
@@ -2383,16 +2487,16 @@ function read(e) {
|
|
|
2383
2487
|
// recompute don't collect into the probe.
|
|
2384
2488
|
if (pendingCheckActive) {
|
|
2385
2489
|
GlobalQueue.Ee(e, t, i, r);
|
|
2386
|
-
} else if (typeof n.
|
|
2490
|
+
} else if (typeof n.Ue === "function") {
|
|
2387
2491
|
prepareComputed(e, false);
|
|
2388
2492
|
}
|
|
2389
|
-
if (!n.
|
|
2493
|
+
if (!n.Ue && i === e && e.A === undefined && e.me === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2390
2494
|
if (t && tracking) link(e, t);
|
|
2391
|
-
return !t || e.
|
|
2495
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2392
2496
|
}
|
|
2393
2497
|
if (t && tracking) {
|
|
2394
2498
|
link(e, t, pendingCheckActive);
|
|
2395
|
-
if (i.
|
|
2499
|
+
if (i.Ue) {
|
|
2396
2500
|
const n = queueFor(e);
|
|
2397
2501
|
if (i.Xe >= n.P) {
|
|
2398
2502
|
markNode(t);
|
|
@@ -2406,7 +2510,7 @@ function read(e) {
|
|
|
2406
2510
|
}
|
|
2407
2511
|
}
|
|
2408
2512
|
}
|
|
2409
|
-
if (i.
|
|
2513
|
+
if (i.xe & STATUS_PENDING) {
|
|
2410
2514
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2411
2515
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2412
2516
|
// is installed): under a lane, only same-lane pending async without an
|
|
@@ -2415,29 +2519,29 @@ function read(e) {
|
|
|
2415
2519
|
if (!tracking && e !== t) link(e, t);
|
|
2416
2520
|
throw i.De;
|
|
2417
2521
|
}
|
|
2418
|
-
} else if (t && i !== e && i.
|
|
2522
|
+
} else if (t && i !== e && i.xe & STATUS_UNINITIALIZED) {
|
|
2419
2523
|
if (!tracking && e !== t) link(e, t);
|
|
2420
2524
|
throw i.De;
|
|
2421
|
-
} else if (!t && i.
|
|
2525
|
+
} else if (!t && i.xe & STATUS_UNINITIALIZED) {
|
|
2422
2526
|
throw i.De;
|
|
2423
2527
|
}
|
|
2424
2528
|
}
|
|
2425
|
-
if (e.
|
|
2529
|
+
if (e.Ue && e.xe & STATUS_ERROR) {
|
|
2426
2530
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2427
2531
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2428
2532
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2429
2533
|
// - el._time < clock: only on a later cycle than the one the error was found
|
|
2430
|
-
if (tracking && !pendingCheckActive && e.
|
|
2534
|
+
if (tracking && !pendingCheckActive && e.F < clock) {
|
|
2431
2535
|
recompute(e);
|
|
2432
2536
|
return read(e);
|
|
2433
2537
|
} else throw e.De;
|
|
2434
2538
|
}
|
|
2435
|
-
if (snapshotCaptureActive && t && t.
|
|
2436
|
-
const n = e.
|
|
2539
|
+
if (snapshotCaptureActive && t && t.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2540
|
+
const n = e.me;
|
|
2437
2541
|
if (n !== undefined) {
|
|
2438
2542
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2439
|
-
const i = e.
|
|
2440
|
-
if (i !== r) t.
|
|
2543
|
+
const i = e.U !== NOT_PENDING ? e.U : e.ke;
|
|
2544
|
+
if (i !== r) t.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
2441
2545
|
return r;
|
|
2442
2546
|
}
|
|
2443
2547
|
}
|
|
@@ -2459,11 +2563,11 @@ function read(e) {
|
|
|
2459
2563
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2460
2564
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2461
2565
|
// (The lane-context clause lives with the engine.)
|
|
2462
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.
|
|
2566
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.U === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.ke : e.U;
|
|
2463
2567
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2464
2568
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2465
2569
|
if (pendingCheckActive) GlobalQueue.de(e, o);
|
|
2466
|
-
if (!t && i === e && typeof n.
|
|
2570
|
+
if (!t && i === e && typeof n.Ue === "function" && e.Ge & CONFIG_AUTO_DISPOSE && !(i.xe & STATUS_PENDING) && !e.G) {
|
|
2467
2571
|
unobserved(e);
|
|
2468
2572
|
}
|
|
2469
2573
|
return o;
|
|
@@ -2475,17 +2579,20 @@ function setSignal(e, t) {
|
|
|
2475
2579
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2476
2580
|
// _overrideValue slot, and every module that creates one installs the
|
|
2477
2581
|
// engine first.
|
|
2478
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2479
|
-
const n = e.
|
|
2582
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue._e(e, t);
|
|
2583
|
+
const n = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2480
2584
|
if (typeof t === "function") t = t(n);
|
|
2481
2585
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2482
2586
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2483
|
-
const r = !!(e.
|
|
2587
|
+
const r = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(n, t);
|
|
2484
2588
|
if (!r) return t;
|
|
2485
|
-
if (e.
|
|
2486
|
-
e.
|
|
2487
|
-
|
|
2488
|
-
|
|
2589
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2590
|
+
e.U = t;
|
|
2591
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2592
|
+
// neither companion present the call is a guaranteed no-op (companions are
|
|
2593
|
+
// only ever created, never removed, and creating one installs the hook).
|
|
2594
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2595
|
+
e.F = clock;
|
|
2489
2596
|
insertSubs(e);
|
|
2490
2597
|
schedule();
|
|
2491
2598
|
return t;
|
|
@@ -2499,11 +2606,11 @@ function setSignal(e, t) {
|
|
|
2499
2606
|
* cleanup point.
|
|
2500
2607
|
*/ function suppressComputedRecompute(e) {
|
|
2501
2608
|
deleteFromHeap(e, queueFor(e));
|
|
2502
|
-
if (!(e.
|
|
2609
|
+
if (!(e.Le & REACTIVE_MANUAL_WRITE) && e.U === NOT_PENDING) {
|
|
2503
2610
|
queuePendingNode(e);
|
|
2504
2611
|
schedule();
|
|
2505
2612
|
}
|
|
2506
|
-
e.
|
|
2613
|
+
e.Le = e.Le & -4 | REACTIVE_MANUAL_WRITE;
|
|
2507
2614
|
}
|
|
2508
2615
|
|
|
2509
2616
|
/**
|
|
@@ -2582,7 +2689,7 @@ function staleValues(e, t = true) {
|
|
|
2582
2689
|
if (!t) {
|
|
2583
2690
|
return;
|
|
2584
2691
|
}
|
|
2585
|
-
if (typeof t.
|
|
2692
|
+
if (typeof t.Ue === "function" && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2586
2693
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2587
2694
|
// same question: mark it so the recompute classifies any resulting
|
|
2588
2695
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2590,11 +2697,11 @@ function staleValues(e, t = true) {
|
|
|
2590
2697
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2591
2698
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2592
2699
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2593
|
-
if (!(t.
|
|
2594
|
-
t.
|
|
2700
|
+
if (!(t.Le & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2701
|
+
t.Le |= REACTIVE_REASK;
|
|
2595
2702
|
armReaskClear();
|
|
2596
2703
|
}
|
|
2597
|
-
t.
|
|
2704
|
+
t.Le = t.Le & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2598
2705
|
insertIntoHeap(t, queueFor(t));
|
|
2599
2706
|
schedule();
|
|
2600
2707
|
}
|
|
@@ -2642,11 +2749,11 @@ function wireExternalSource(e) {
|
|
|
2642
2749
|
equals: false,
|
|
2643
2750
|
ownedWrite: true
|
|
2644
2751
|
});
|
|
2645
|
-
const n = externalSourceConfig.factory(e.
|
|
2752
|
+
const n = externalSourceConfig.factory(e.Ue, () => {
|
|
2646
2753
|
setSignal(t, undefined);
|
|
2647
2754
|
});
|
|
2648
2755
|
cleanup(() => n.dispose());
|
|
2649
|
-
e.
|
|
2756
|
+
e.Ue = e => {
|
|
2650
2757
|
read(t);
|
|
2651
2758
|
return n.track(e);
|
|
2652
2759
|
};
|
|
@@ -2770,7 +2877,7 @@ function isUndefined(e) {
|
|
|
2770
2877
|
const n = e.A !== NOT_PENDING;
|
|
2771
2878
|
const r = n ? unwrapOverride(e.A) : e.ke;
|
|
2772
2879
|
if (typeof t === "function") t = t(r);
|
|
2773
|
-
const i = !!(e.
|
|
2880
|
+
const i = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(r, t);
|
|
2774
2881
|
if (!i) {
|
|
2775
2882
|
// Same-value write with an active override still entangles the current
|
|
2776
2883
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2795,8 +2902,10 @@ function isUndefined(e) {
|
|
|
2795
2902
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
2796
2903
|
// writes off the optimistic path into permanent commits (#2898).
|
|
2797
2904
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2798
|
-
|
|
2799
|
-
|
|
2905
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2906
|
+
// neither companion present the call is a guaranteed no-op.
|
|
2907
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2908
|
+
e.F = clock;
|
|
2800
2909
|
insertSubs(e, true);
|
|
2801
2910
|
schedule();
|
|
2802
2911
|
return t;
|
|
@@ -2809,7 +2918,7 @@ function isUndefined(e) {
|
|
|
2809
2918
|
*/ function transitionBlocked(e) {
|
|
2810
2919
|
for (let t = 0; t < e.v.length; t++) {
|
|
2811
2920
|
const n = e.v[t];
|
|
2812
|
-
if (hasActiveOverride(n) && "
|
|
2921
|
+
if (hasActiveOverride(n) && "xe" in n && n.xe & STATUS_PENDING && n.De instanceof NotReadyError) {
|
|
2813
2922
|
return true;
|
|
2814
2923
|
}
|
|
2815
2924
|
}
|
|
@@ -2827,7 +2936,7 @@ function resolveOptimisticNodes(e) {
|
|
|
2827
2936
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2828
2937
|
// override-covered authoritative values hold in _pendingValue and
|
|
2829
2938
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2830
|
-
if (!(t.
|
|
2939
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
2831
2940
|
const r = t.A;
|
|
2832
2941
|
t.A = NOT_PENDING;
|
|
2833
2942
|
if (r !== NOT_PENDING && t.ke !== unwrapOverride(r)) insertSubs(t, true);
|
|
@@ -2839,9 +2948,9 @@ function resolveOptimisticNodes(e) {
|
|
|
2839
2948
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2840
2949
|
for (let n = 0; n < t; n++) {
|
|
2841
2950
|
const t = e[n];
|
|
2842
|
-
if (t.
|
|
2951
|
+
if (t._ || t.p) GlobalQueue.ce(t);
|
|
2843
2952
|
const r = t.t;
|
|
2844
|
-
if (r && (r.
|
|
2953
|
+
if (r && (r._ === t || r.p === t)) GlobalQueue.ce(r);
|
|
2845
2954
|
}
|
|
2846
2955
|
e.splice(0, t);
|
|
2847
2956
|
}
|
|
@@ -2894,7 +3003,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2894
3003
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2895
3004
|
* is recorded for replay at commit.
|
|
2896
3005
|
*/ function gatedRead(e, t, n) {
|
|
2897
|
-
if (latestReadActive || e.
|
|
3006
|
+
if (latestReadActive || e.U === NOT_PENDING || e.Ue || t !== e && !(t.Le & REACTIVE_MANUAL_WRITE)) {
|
|
2898
3007
|
return false;
|
|
2899
3008
|
}
|
|
2900
3009
|
activeTransition.Y.add(n);
|
|
@@ -2905,7 +3014,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2905
3014
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2906
3015
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2907
3016
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2908
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.
|
|
3017
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.xe & STATUS_PENDING);
|
|
2909
3018
|
}
|
|
2910
3019
|
|
|
2911
3020
|
/**
|
|
@@ -2916,10 +3025,10 @@ function cleanupCompletedLanes(e) {
|
|
|
2916
3025
|
if (t) return resolveLane(e) ?? null;
|
|
2917
3026
|
for (let t = e.je; t; t = t.Ke) {
|
|
2918
3027
|
const n = t.Ye;
|
|
2919
|
-
if (n.
|
|
3028
|
+
if (n.Le & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2920
3029
|
const t = resolveLane(n);
|
|
2921
3030
|
if (t) {
|
|
2922
|
-
e.
|
|
3031
|
+
e.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
2923
3032
|
assignOrMergeLane(e, t);
|
|
2924
3033
|
return t;
|
|
2925
3034
|
}
|
|
@@ -2947,7 +3056,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2947
3056
|
|
|
2948
3057
|
function trackOptimisticStore(e) {
|
|
2949
3058
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
2950
|
-
globalQueue.D.
|
|
3059
|
+
globalQueue.D.V.add(e);
|
|
2951
3060
|
schedule();
|
|
2952
3061
|
}
|
|
2953
3062
|
|
|
@@ -2956,8 +3065,8 @@ function trackOptimisticStore(e) {
|
|
|
2956
3065
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
2957
3066
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
2958
3067
|
*/ function installOptimisticEngine() {
|
|
2959
|
-
if (GlobalQueue.
|
|
2960
|
-
GlobalQueue.
|
|
3068
|
+
if (GlobalQueue._e !== null) return;
|
|
3069
|
+
GlobalQueue._e = optimisticWrite;
|
|
2961
3070
|
GlobalQueue.pe = resolveOptimisticNodes;
|
|
2962
3071
|
GlobalQueue.Re = transitionBlocked;
|
|
2963
3072
|
GlobalQueue.Ie = cleanupCompletedLanes;
|
|
@@ -2987,15 +3096,15 @@ let pendingProbe = null;
|
|
|
2987
3096
|
* Get or create the pending signal for a node (lazy).
|
|
2988
3097
|
* Used by isPending() to track pending state reactively.
|
|
2989
3098
|
*/ function getPendingSignal(e) {
|
|
2990
|
-
if (!e.
|
|
3099
|
+
if (!e._) {
|
|
2991
3100
|
// Start false, write true if pending - ensures reversion returns to false
|
|
2992
|
-
e.
|
|
3101
|
+
e._ = optimisticSignal(false, {
|
|
2993
3102
|
ownedWrite: true
|
|
2994
3103
|
});
|
|
2995
|
-
e.
|
|
2996
|
-
if (computePendingState(e)) setSignal(e.
|
|
3104
|
+
e._.t = e;
|
|
3105
|
+
if (computePendingState(e)) setSignal(e._, true);
|
|
2997
3106
|
}
|
|
2998
|
-
return e.
|
|
3107
|
+
return e._;
|
|
2999
3108
|
}
|
|
3000
3109
|
|
|
3001
3110
|
function collectPendingSources(e) {
|
|
@@ -3031,7 +3140,7 @@ function collectPendingSources(e) {
|
|
|
3031
3140
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3032
3141
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3033
3142
|
// pending (the count check above), also matching.
|
|
3034
|
-
if (e.
|
|
3143
|
+
if (e.xe & STATUS_ERROR) return false;
|
|
3035
3144
|
if (t.has(e)) return false;
|
|
3036
3145
|
t.add(e);
|
|
3037
3146
|
const n = e.qe;
|
|
@@ -3041,10 +3150,10 @@ function collectPendingSources(e) {
|
|
|
3041
3150
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3042
3151
|
// latch a stale verdict on the companion.
|
|
3043
3152
|
const r = e;
|
|
3044
|
-
const i = r.
|
|
3153
|
+
const i = r.Le & REACTIVE_RECOMPUTING_DEPS ? r.st : undefined;
|
|
3045
3154
|
if (i !== null) {
|
|
3046
3155
|
for (let e = r.je ?? null; e !== null; e = e.Ke) {
|
|
3047
|
-
if (!e.
|
|
3156
|
+
if (!e.Ot && markWalk(e.Ye, t)) return true;
|
|
3048
3157
|
if (e === i) break;
|
|
3049
3158
|
}
|
|
3050
3159
|
}
|
|
@@ -3064,12 +3173,12 @@ function quietPending(e) {
|
|
|
3064
3173
|
}
|
|
3065
3174
|
|
|
3066
3175
|
function newQuestionInFlight(e) {
|
|
3067
|
-
return !!(e.
|
|
3176
|
+
return !!(e.xe & STATUS_PENDING) && !(e.xe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3068
3177
|
}
|
|
3069
3178
|
|
|
3070
3179
|
function computePendingState(e) {
|
|
3071
3180
|
const t = e;
|
|
3072
|
-
if (t.
|
|
3181
|
+
if (t.Le & REACTIVE_DISPOSED) return false;
|
|
3073
3182
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3074
3183
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3075
3184
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
@@ -3080,31 +3189,31 @@ function computePendingState(e) {
|
|
|
3080
3189
|
const n = t.qe || t;
|
|
3081
3190
|
return newQuestionInFlight(n);
|
|
3082
3191
|
}
|
|
3083
|
-
if (n && e.
|
|
3084
|
-
return !!(n.
|
|
3192
|
+
if (n && e.U !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3193
|
+
return !!(n.Le & REACTIVE_MANUAL_WRITE) || !n.ut && !(n.xe & STATUS_PENDING) || !!(n.xe & STATUS_PENDING) && quietPending(n);
|
|
3085
3194
|
}
|
|
3086
|
-
if (e.
|
|
3087
|
-
if (hasActiveOverride(e)) return !e.At || !e.At(e.
|
|
3195
|
+
if (e.U !== NOT_PENDING && !(t.xe & STATUS_UNINITIALIZED)) {
|
|
3196
|
+
if (hasActiveOverride(e)) return !e.At || !e.At(e.U, unwrapOverride(e.A));
|
|
3088
3197
|
return true;
|
|
3089
3198
|
}
|
|
3090
3199
|
return newQuestionInFlight(t);
|
|
3091
3200
|
}
|
|
3092
3201
|
|
|
3093
3202
|
function syncCompanions(e, t) {
|
|
3094
|
-
if (e.
|
|
3203
|
+
if (e._) updatePendingSignal(e);
|
|
3095
3204
|
if (e.p) setSignal(e.p, t);
|
|
3096
3205
|
}
|
|
3097
3206
|
|
|
3098
3207
|
function updatePendingSignal(e) {
|
|
3099
|
-
if (e.
|
|
3100
|
-
setSignal(e.
|
|
3208
|
+
if (e._) {
|
|
3209
|
+
setSignal(e._, computePendingState(e));
|
|
3101
3210
|
}
|
|
3102
3211
|
if (e.p) updatePendingSignal(e.p);
|
|
3103
3212
|
}
|
|
3104
3213
|
|
|
3105
3214
|
function updateChildCompanions(e) {
|
|
3106
3215
|
for (let t = e.nt; t !== null; t = t.rt) {
|
|
3107
|
-
if (t.
|
|
3216
|
+
if (t._ || t.p) updatePendingSignal(t);
|
|
3108
3217
|
}
|
|
3109
3218
|
}
|
|
3110
3219
|
|
|
@@ -3122,8 +3231,8 @@ function updateChildCompanions(e) {
|
|
|
3122
3231
|
const visit = e => {
|
|
3123
3232
|
if (r.has(e)) return;
|
|
3124
3233
|
r.add(e);
|
|
3125
|
-
if (e.
|
|
3126
|
-
for (let t = e.
|
|
3234
|
+
if (e._ || e.p) n(e);
|
|
3235
|
+
for (let t = e.G; t !== null; t = t.ve) visit(t.Ve);
|
|
3127
3236
|
for (let t = e.nt ?? null; t !== null; t = t.rt) {
|
|
3128
3237
|
visit(t);
|
|
3129
3238
|
}
|
|
@@ -3132,21 +3241,21 @@ function updateChildCompanions(e) {
|
|
|
3132
3241
|
}
|
|
3133
3242
|
|
|
3134
3243
|
function snapCompanionsToState(e) {
|
|
3135
|
-
const t = e.
|
|
3244
|
+
const t = e._;
|
|
3136
3245
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3137
3246
|
const n = computePendingState(e);
|
|
3138
|
-
if (t.ke !== n || t.
|
|
3247
|
+
if (t.ke !== n || t.U !== NOT_PENDING) {
|
|
3139
3248
|
t.ke = n;
|
|
3140
|
-
t.
|
|
3141
|
-
t.
|
|
3249
|
+
t.U = NOT_PENDING;
|
|
3250
|
+
t.F = clock;
|
|
3142
3251
|
insertSubs(t);
|
|
3143
3252
|
schedule();
|
|
3144
3253
|
}
|
|
3145
3254
|
}
|
|
3146
3255
|
const n = e.p;
|
|
3147
|
-
if (n && !(n.
|
|
3148
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.
|
|
3149
|
-
n.
|
|
3256
|
+
if (n && !(n.Le & REACTIVE_DISPOSED)) {
|
|
3257
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.ke, e.ke) && !(n.Le & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3258
|
+
n.Le |= REACTIVE_DIRTY;
|
|
3150
3259
|
insertIntoHeap(n, queueFor(n));
|
|
3151
3260
|
insertSubs(n);
|
|
3152
3261
|
schedule();
|
|
@@ -3187,18 +3296,18 @@ function getLatestValueComputed(e) {
|
|
|
3187
3296
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3188
3297
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3189
3298
|
const e = queueFor(t);
|
|
3190
|
-
if (t.Xe >= e.P && !(t.
|
|
3299
|
+
if (t.Xe >= e.P && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3191
3300
|
markHeap(e);
|
|
3192
3301
|
prepareComputed(t, true);
|
|
3193
3302
|
}
|
|
3194
3303
|
i = read(t);
|
|
3195
3304
|
} catch (t) {
|
|
3196
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3305
|
+
if (t instanceof NotReadyError && (!context || !(e.xe & STATUS_UNINITIALIZED))) return r;
|
|
3197
3306
|
throw t;
|
|
3198
3307
|
} finally {
|
|
3199
3308
|
setLatestReadActive(n);
|
|
3200
3309
|
}
|
|
3201
|
-
if (t.
|
|
3310
|
+
if (t.xe & STATUS_PENDING) return r;
|
|
3202
3311
|
if (stale && currentOptimisticLane && t.i) {
|
|
3203
3312
|
const e = findLane(t.i);
|
|
3204
3313
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3210,14 +3319,14 @@ function getLatestValueComputed(e) {
|
|
|
3210
3319
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
3211
3320
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
3212
3321
|
// other transition's committed view, matching read()'s own selection.
|
|
3213
|
-
if (t.
|
|
3322
|
+
if (t.U !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.T && activeTransition !== t.T)) return t.U;
|
|
3214
3323
|
return i;
|
|
3215
3324
|
}
|
|
3216
3325
|
|
|
3217
3326
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3218
3327
|
setPendingCheckActive(false);
|
|
3219
|
-
if (typeof e.
|
|
3220
|
-
const i = n.
|
|
3328
|
+
if (typeof e.Ue === "function") prepareComputed(e, true);
|
|
3329
|
+
const i = n.xe;
|
|
3221
3330
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3222
3331
|
if (tracking && e !== t) link(e, t);
|
|
3223
3332
|
setPendingCheckActive(true);
|
|
@@ -3229,11 +3338,11 @@ function getLatestValueComputed(e) {
|
|
|
3229
3338
|
}
|
|
3230
3339
|
|
|
3231
3340
|
function recordFreshRead(e, t) {
|
|
3232
|
-
if (pendingProbe !== null && e.
|
|
3341
|
+
if (pendingProbe !== null && e.U !== NOT_PENDING && t === e.U) pendingProbe.freshReads.add(e);
|
|
3233
3342
|
}
|
|
3234
3343
|
|
|
3235
3344
|
function applyReask(e, t) {
|
|
3236
|
-
const n = !!(e.
|
|
3345
|
+
const n = !!(e.xe & STATUS_PENDING);
|
|
3237
3346
|
const r = t && !(n && !e.ht);
|
|
3238
3347
|
const i = n && e.ht !== r;
|
|
3239
3348
|
e.ht = r;
|
|
@@ -3276,7 +3385,7 @@ function isPending(e) {
|
|
|
3276
3385
|
} catch (e) {
|
|
3277
3386
|
collectPending();
|
|
3278
3387
|
if (e instanceof NotReadyError) {
|
|
3279
|
-
const t = !!(e.source?.
|
|
3388
|
+
const t = !!(e.source?.xe & STATUS_UNINITIALIZED);
|
|
3280
3389
|
if (r.found && !t) return true;
|
|
3281
3390
|
if (context && t) throw e;
|
|
3282
3391
|
}
|
|
@@ -3294,9 +3403,9 @@ GlobalQueue.ue = syncCompanions;
|
|
|
3294
3403
|
|
|
3295
3404
|
GlobalQueue.le = updatePendingSignal;
|
|
3296
3405
|
|
|
3297
|
-
GlobalQueue.
|
|
3406
|
+
GlobalQueue.ae = updateChildCompanions;
|
|
3298
3407
|
|
|
3299
|
-
GlobalQueue.
|
|
3408
|
+
GlobalQueue.ce = snapCompanionsToState;
|
|
3300
3409
|
|
|
3301
3410
|
GlobalQueue.fe = latestRead;
|
|
3302
3411
|
|
|
@@ -3308,7 +3417,7 @@ GlobalQueue.Se = applyReask;
|
|
|
3308
3417
|
|
|
3309
3418
|
GlobalQueue.Te = repollDownstreamVerdicts;
|
|
3310
3419
|
|
|
3311
|
-
GlobalQueue.
|
|
3420
|
+
GlobalQueue.Oe = witnessAffects;
|
|
3312
3421
|
|
|
3313
3422
|
/**
|
|
3314
3423
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3318,16 +3427,16 @@ GlobalQueue._e = witnessAffects;
|
|
|
3318
3427
|
const i = !!r?.user;
|
|
3319
3428
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3320
3429
|
recompute(o, true);
|
|
3321
|
-
!r?.defer && (o.
|
|
3430
|
+
!r?.defer && (o.We === EFFECT_USER || r?.schedule ? o.Be.enqueue(o.We, runEffect.bind(null, o)) : runEffect(o));
|
|
3322
3431
|
}
|
|
3323
3432
|
|
|
3324
3433
|
function notifyEffectStatus(e, t) {
|
|
3325
3434
|
// Use passed values if provided, otherwise read from node
|
|
3326
|
-
const n = e !== undefined ? e : this.
|
|
3435
|
+
const n = e !== undefined ? e : this.xe;
|
|
3327
3436
|
const r = t !== undefined ? t : this.De;
|
|
3328
3437
|
if (n & STATUS_ERROR) {
|
|
3329
3438
|
this.Be.notify(this, STATUS_PENDING, 0);
|
|
3330
|
-
if (this.
|
|
3439
|
+
if (this.We === EFFECT_USER) {
|
|
3331
3440
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3332
3441
|
// queue it like the effect function. It runs in the same imperative,
|
|
3333
3442
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3337,9 +3446,9 @@ function notifyEffectStatus(e, t) {
|
|
|
3337
3446
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3338
3447
|
// `status` arg without node-state writes) don't queue: the status
|
|
3339
3448
|
// re-propagates unblocked at commit.
|
|
3340
|
-
if (this.
|
|
3341
|
-
this.
|
|
3342
|
-
this.Be.enqueue(this.
|
|
3449
|
+
if (this.xe & STATUS_ERROR) {
|
|
3450
|
+
this.Fe = true;
|
|
3451
|
+
this.Be.enqueue(this.We, this.Pt ??= runEffect.bind(null, this));
|
|
3343
3452
|
}
|
|
3344
3453
|
return;
|
|
3345
3454
|
}
|
|
@@ -3347,13 +3456,13 @@ function notifyEffectStatus(e, t) {
|
|
|
3347
3456
|
haltReactivity(unwrapStatusError(r));
|
|
3348
3457
|
throw r;
|
|
3349
3458
|
}
|
|
3350
|
-
} else if (this.
|
|
3459
|
+
} else if (this.We === EFFECT_RENDER) {
|
|
3351
3460
|
this.Be.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3352
3461
|
}
|
|
3353
3462
|
}
|
|
3354
3463
|
|
|
3355
3464
|
function runEffect(e) {
|
|
3356
|
-
if (!e.
|
|
3465
|
+
if (!e.Fe || e.Le & REACTIVE_DISPOSED) return;
|
|
3357
3466
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3358
3467
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3359
3468
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3364,10 +3473,10 @@ function runEffect(e) {
|
|
|
3364
3473
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3365
3474
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3366
3475
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3367
|
-
if (e.
|
|
3476
|
+
if (e.xe & STATUS_ERROR && e.We === EFFECT_USER) {
|
|
3368
3477
|
const t = unwrapStatusError(e.De);
|
|
3369
3478
|
e.gt = e.ke;
|
|
3370
|
-
e.
|
|
3479
|
+
e.Fe = false;
|
|
3371
3480
|
try {
|
|
3372
3481
|
e.Dt ? e.Dt(t, () => {
|
|
3373
3482
|
const t = e.ft;
|
|
@@ -3392,14 +3501,14 @@ function runEffect(e) {
|
|
|
3392
3501
|
e.ft = n;
|
|
3393
3502
|
} catch (t) {
|
|
3394
3503
|
e.De = new StatusError(e, t);
|
|
3395
|
-
e.
|
|
3504
|
+
e.xe |= STATUS_ERROR;
|
|
3396
3505
|
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3397
3506
|
haltReactivity(t);
|
|
3398
3507
|
throw t;
|
|
3399
3508
|
}
|
|
3400
3509
|
} finally {
|
|
3401
3510
|
e.gt = e.ke;
|
|
3402
|
-
e.
|
|
3511
|
+
e.Fe = false;
|
|
3403
3512
|
}
|
|
3404
3513
|
}
|
|
3405
3514
|
|
|
@@ -3411,9 +3520,9 @@ GlobalQueue.J = runEffect;
|
|
|
3411
3520
|
* Uses stale reads.
|
|
3412
3521
|
*/ function trackedEffect(e, t) {
|
|
3413
3522
|
const run = () => {
|
|
3414
|
-
if (!n.
|
|
3523
|
+
if (!n.Fe || n.Le & REACTIVE_DISPOSED) return;
|
|
3415
3524
|
try {
|
|
3416
|
-
n.
|
|
3525
|
+
n.Fe = false;
|
|
3417
3526
|
recompute(n);
|
|
3418
3527
|
} finally {}
|
|
3419
3528
|
};
|
|
@@ -3428,11 +3537,11 @@ GlobalQueue.J = runEffect;
|
|
|
3428
3537
|
lazy: true
|
|
3429
3538
|
});
|
|
3430
3539
|
n.ft = undefined;
|
|
3431
|
-
n.
|
|
3432
|
-
n.
|
|
3433
|
-
n.
|
|
3540
|
+
n.Ge = n.Ge & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3541
|
+
n.Fe = true;
|
|
3542
|
+
n.We = EFFECT_TRACKED;
|
|
3434
3543
|
n.Nt = (e, t) => {
|
|
3435
|
-
const r = e !== undefined ? e : n.
|
|
3544
|
+
const r = e !== undefined ? e : n.xe;
|
|
3436
3545
|
if (r & STATUS_ERROR) {
|
|
3437
3546
|
n.Be.notify(n, STATUS_PENDING, 0);
|
|
3438
3547
|
const e = t !== undefined ? t : n.De;
|
|
@@ -3624,7 +3733,7 @@ function accessor(e) {
|
|
|
3624
3733
|
function createSignal(e, t) {
|
|
3625
3734
|
if (typeof e === "function") {
|
|
3626
3735
|
const n = computed(e, t);
|
|
3627
|
-
n.
|
|
3736
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3628
3737
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3629
3738
|
}
|
|
3630
3739
|
const n = signal(e, t);
|
|
@@ -3865,7 +3974,7 @@ function createOptimistic(e, t) {
|
|
|
3865
3974
|
installOptimisticEngine();
|
|
3866
3975
|
if (typeof e === "function") {
|
|
3867
3976
|
const n = optimisticComputed(e, t);
|
|
3868
|
-
n.
|
|
3977
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3869
3978
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3870
3979
|
}
|
|
3871
3980
|
const n = optimisticSignal(e, t);
|
|
@@ -3954,7 +4063,7 @@ function createOptimistic(e, t) {
|
|
|
3954
4063
|
* on owner disposal
|
|
3955
4064
|
*/ function onSettled(e) {
|
|
3956
4065
|
const t = getOwner();
|
|
3957
|
-
t && !(t.
|
|
4066
|
+
t && !(t.Ge & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3958
4067
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3959
4068
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3960
4069
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4058,28 +4167,68 @@ function keyedMatch(e, t, n) {
|
|
|
4058
4167
|
// and `in` dependencies should follow the new value's membership. Use
|
|
4059
4168
|
// membership rather than length arithmetic so sparse arrays and named array
|
|
4060
4169
|
// props behave like normal property reads.
|
|
4170
|
+
// Inline key iteration on purpose: these loops run per array target per
|
|
4171
|
+
// reconcile pass, and a shared helper means a closure + per-key call in
|
|
4172
|
+
// instruction counts. String-only records (the common case) iterate in
|
|
4173
|
+
// place; symbol-bearing records take the nodeKeys array path.
|
|
4061
4174
|
function syncArrayNodeMembership(e, t) {
|
|
4062
4175
|
let n = e[STORE_NODE];
|
|
4063
4176
|
if (n) {
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4177
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4178
|
+
const e = nodeKeys(n);
|
|
4179
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4180
|
+
e[r] in t || setSignal(n[e[r]], undefined);
|
|
4181
|
+
}
|
|
4182
|
+
} else {
|
|
4183
|
+
for (const e in n) {
|
|
4184
|
+
e in t || setSignal(n[e], undefined);
|
|
4185
|
+
}
|
|
4068
4186
|
}
|
|
4069
4187
|
}
|
|
4070
4188
|
if (n = e[STORE_HAS]) {
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4189
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4190
|
+
const e = nodeKeys(n);
|
|
4191
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4192
|
+
setSignal(n[e[r]], e[r] in t);
|
|
4193
|
+
}
|
|
4194
|
+
} else {
|
|
4195
|
+
for (const e in n) {
|
|
4196
|
+
setSignal(n[e], e in t);
|
|
4197
|
+
}
|
|
4075
4198
|
}
|
|
4076
4199
|
}
|
|
4077
4200
|
}
|
|
4078
4201
|
|
|
4202
|
+
// Recurse into a matched wrappable child pair without manufacturing a proxy:
|
|
4203
|
+
// resolve the child's target through the lookup and dispatch directly. A
|
|
4204
|
+
// lookup miss means the child was never observed — no proxy, no nodes, no
|
|
4205
|
+
// subscribers anywhere below — so the parent's swap making `next`
|
|
4206
|
+
// authoritative IS the whole update; a later read wraps next's child on
|
|
4207
|
+
// demand. This turns the diff from O(previous graph) into O(observed graph)
|
|
4208
|
+
// and drops the wrap()/$PROXY/$TARGET round-trip per visited child.
|
|
4209
|
+
// Wrap-family stores (projections/optimistic) own child proxy creation and
|
|
4210
|
+
// keep the proxy-based recursion.
|
|
4211
|
+
function applyStateChild(e, t, n, r) {
|
|
4212
|
+
if (n[STORE_WRAP] !== undefined) {
|
|
4213
|
+
applyState(e, wrap(t, n), r);
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
const i = t[$TARGET] ?? storeLookup.get(t);
|
|
4217
|
+
if (i === undefined) return;
|
|
4218
|
+
e = unwrap(e);
|
|
4219
|
+
if (i[STORE_SHALLOW]) {
|
|
4220
|
+
applyStateShallow(e, i);
|
|
4221
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4222
|
+
applyStateSlow(e, i, r);
|
|
4223
|
+
} else {
|
|
4224
|
+
applyStateFast(e, i, r);
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4079
4228
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
4080
4229
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
4081
4230
|
function applyArrayItem(e, t, n, r, i) {
|
|
4082
|
-
if (isWrappable(e) && isWrappable(t)) {
|
|
4231
|
+
if (isWrappable(e) && isWrappable(t) && !(rawValuesUsed && (isRawValue(t) || isRawValue(e)))) {
|
|
4083
4232
|
const o = wrap(t, n);
|
|
4084
4233
|
r && setSignal(r, o);
|
|
4085
4234
|
applyState(e, o, i);
|
|
@@ -4099,18 +4248,51 @@ function applyArrayItem(e, t, n, r, i) {
|
|
|
4099
4248
|
* `$TRACK` absence (an enumeration-tracked record already diffs every key).
|
|
4100
4249
|
*/ function applyDescendants(e, t, n, r, i, o, s) {
|
|
4101
4250
|
const u = n[STORE_LOOKUP] || storeLookup;
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4251
|
+
if (o) {
|
|
4252
|
+
const n = getKeys(e, o).concat(getStoreSymbols(e, o));
|
|
4253
|
+
for (let l = 0, a = n.length; l < a; l++) {
|
|
4254
|
+
const a = n[l];
|
|
4255
|
+
if (r?.[a]) continue;
|
|
4106
4256
|
// main loop already diffed this slot
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4257
|
+
const c = unwrap(getOverrideValue(e, o, a, s));
|
|
4258
|
+
if (!isWrappable(c)) continue;
|
|
4259
|
+
descendInto(c, t[a], u, i);
|
|
4260
|
+
}
|
|
4261
|
+
return;
|
|
4262
|
+
}
|
|
4263
|
+
// No-override path (every applyStateFast call): iterate in place instead of
|
|
4264
|
+
// building keys + symbols + concat arrays per object per pass. The cheap
|
|
4265
|
+
// bails (noded key, primitive value) stay inline — only genuine descent
|
|
4266
|
+
// candidates pay a call.
|
|
4267
|
+
for (const n in e) {
|
|
4268
|
+
if (r?.[n]) continue;
|
|
4269
|
+
// main loop already diffed this slot
|
|
4270
|
+
const o = unwrap(e[n]);
|
|
4271
|
+
if (!isWrappable(o)) continue;
|
|
4272
|
+
descendInto(o, t[n], u, i);
|
|
4273
|
+
}
|
|
4274
|
+
const l = Object.getOwnPropertySymbols(e);
|
|
4275
|
+
for (let n = 0, o = l.length; n < o; n++) {
|
|
4276
|
+
if (Object.prototype.propertyIsEnumerable.call(e, l[n])) {
|
|
4277
|
+
if (r?.[l[n]]) continue;
|
|
4278
|
+
const o = unwrap(e[l[n]]);
|
|
4279
|
+
if (!isWrappable(o)) continue;
|
|
4280
|
+
descendInto(o, t[l[n]], u, i);
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
|
|
4285
|
+
function descendInto(e, t, n, r) {
|
|
4286
|
+
const i = lookupTarget(e, n);
|
|
4287
|
+
if (!i?.[STORE_DESC]) return;
|
|
4288
|
+
const o = unwrap(t);
|
|
4289
|
+
if (e === o || !isWrappable(o) || Array.isArray(e) !== Array.isArray(o) || r(e) != null && r(e) !== r(o)) return;
|
|
4290
|
+
if (i[STORE_SHALLOW]) {
|
|
4291
|
+
applyStateShallow(o, i);
|
|
4292
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4293
|
+
applyStateSlow(o, i, r);
|
|
4294
|
+
} else {
|
|
4295
|
+
applyStateFast(o, i, r);
|
|
4114
4296
|
}
|
|
4115
4297
|
}
|
|
4116
4298
|
|
|
@@ -4125,36 +4307,134 @@ function applyState(e, t, n) {
|
|
|
4125
4307
|
e = unwrap(e);
|
|
4126
4308
|
const r = t?.[$TARGET];
|
|
4127
4309
|
if (!r) return;
|
|
4128
|
-
if (r[
|
|
4310
|
+
if (r[STORE_SHALLOW]) {
|
|
4311
|
+
applyStateShallow(e, r);
|
|
4312
|
+
} else if (r[STORE_OVERRIDE] || r[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4129
4313
|
applyStateSlow(e, r, n);
|
|
4130
4314
|
} else {
|
|
4131
4315
|
applyStateFast(e, r, n);
|
|
4132
4316
|
}
|
|
4133
4317
|
}
|
|
4134
4318
|
|
|
4319
|
+
// Shallow boundary diff: the target's own keys are reactive, its values are
|
|
4320
|
+
// raw records replaced by reference — no recursion, no wrapping. Arrays merge
|
|
4321
|
+
// positionally (below a shallow boundary the VALUE is the identity; keyed
|
|
4322
|
+
// row identity belongs to the consumer, e.g. <For keyed>). Incoming
|
|
4323
|
+
// wrappables are sticky-marked raw so they present raw through every store.
|
|
4324
|
+
// One pass over a shallow target's node record: replace changed slots with
|
|
4325
|
+
// raw next values, null out slots absent from next. Returns whether anything
|
|
4326
|
+
// differed.
|
|
4327
|
+
function shallowDiffNodes(e, t, n, r) {
|
|
4328
|
+
let i = false;
|
|
4329
|
+
for (const o in e) {
|
|
4330
|
+
if (r && o === "length") continue;
|
|
4331
|
+
if (o in t) {
|
|
4332
|
+
const r = t[o];
|
|
4333
|
+
if (r !== n(o)) {
|
|
4334
|
+
i = true;
|
|
4335
|
+
setSignal(e[o], r);
|
|
4336
|
+
}
|
|
4337
|
+
} else {
|
|
4338
|
+
i = true;
|
|
4339
|
+
setSignal(e[o], undefined);
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
return i;
|
|
4343
|
+
}
|
|
4344
|
+
|
|
4345
|
+
function applyStateShallow(e, t, n) {
|
|
4346
|
+
const r = t[STORE_VALUE];
|
|
4347
|
+
const i = t[STORE_OVERRIDE];
|
|
4348
|
+
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4349
|
+
if (e === r && !i && !o) return;
|
|
4350
|
+
// Setter-staged writes fold into the diff: previous values resolve through
|
|
4351
|
+
// the override layers (so a replaced slot compares against what readers
|
|
4352
|
+
// saw), and the regular override clears with the swap — reconcile makes
|
|
4353
|
+
// `next` the authoritative base, same as the deep slow path.
|
|
4354
|
+
const prevAt = e => {
|
|
4355
|
+
const t = getOverrideValue(r, i, e, o);
|
|
4356
|
+
return t === $DELETED ? undefined : t;
|
|
4357
|
+
};
|
|
4358
|
+
t[STORE_OVERRIDE] = undefined;
|
|
4359
|
+
const s = t[STORE_LOOKUP];
|
|
4360
|
+
s !== undefined ? s.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4361
|
+
t[STORE_VALUE] = e;
|
|
4362
|
+
markRawIngest(e);
|
|
4363
|
+
const u = t[STORE_NODE];
|
|
4364
|
+
const l = u && u[$TRACK];
|
|
4365
|
+
let a = false;
|
|
4366
|
+
if (Array.isArray(r)) {
|
|
4367
|
+
const n = i?.length ?? o?.length ?? r.length;
|
|
4368
|
+
if (u) {
|
|
4369
|
+
a = shallowDiffNodes(u, e, prevAt, true);
|
|
4370
|
+
if (u.length && n !== e.length) setSignal(u.length, e.length);
|
|
4371
|
+
}
|
|
4372
|
+
if (!a && (l || t[STORE_HAS])) {
|
|
4373
|
+
// Slots without nodes still feed $TRACK enumerators / `in` probes.
|
|
4374
|
+
if (n !== e.length) a = true; else {
|
|
4375
|
+
for (let t = 0, n = e.length; t < n; t++) {
|
|
4376
|
+
if (prevAt(t) !== e[t]) {
|
|
4377
|
+
a = true;
|
|
4378
|
+
break;
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
} else {
|
|
4384
|
+
if (u) {
|
|
4385
|
+
a = shallowDiffNodes(u, e, prevAt, false);
|
|
4386
|
+
}
|
|
4387
|
+
if (!a && (l || t[STORE_HAS])) a = true;
|
|
4388
|
+
}
|
|
4389
|
+
let c = t[STORE_HAS];
|
|
4390
|
+
if (c) {
|
|
4391
|
+
for (const t in c) {
|
|
4392
|
+
setSignal(c[t], t in e);
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
a && notifySelf(t);
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4135
4398
|
function applyStateFast(e, t, n) {
|
|
4136
4399
|
const r = t[STORE_VALUE];
|
|
4137
4400
|
if (e === r) return;
|
|
4138
4401
|
const i = t[STORE_NODE];
|
|
4139
4402
|
// swap
|
|
4140
|
-
|
|
4403
|
+
{
|
|
4404
|
+
const n = t[STORE_LOOKUP];
|
|
4405
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4406
|
+
}
|
|
4141
4407
|
t[STORE_VALUE] = e;
|
|
4142
4408
|
// merge
|
|
4143
4409
|
if (Array.isArray(r)) {
|
|
4144
4410
|
let o = false;
|
|
4145
4411
|
const s = r.length;
|
|
4146
4412
|
if (e.length && s && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4147
|
-
let u, l,
|
|
4148
|
-
for (
|
|
4149
|
-
|
|
4413
|
+
let u, l, a, c, f, E, d, S;
|
|
4414
|
+
for (a = 0, c = Math.min(s, e.length); a < c && keyedMatch(E = r[a], e[a], n); a++) {
|
|
4415
|
+
// keyedMatch established both sides wrappable unless they're the
|
|
4416
|
+
// SAME reference — and an identical slot is a guaranteed no-op
|
|
4417
|
+
// (the child's STORE_VALUE tracks the previous graph), so skip
|
|
4418
|
+
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
4419
|
+
// replace the slot node instead of recursing.
|
|
4420
|
+
if (E !== e[a]) {
|
|
4421
|
+
if (rawValuesUsed && (isRawValue(E) || isRawValue(e[a]))) {
|
|
4422
|
+
i?.[a] && setSignal(i[a], wrapValue(e[a], t));
|
|
4423
|
+
} else applyStateChild(e[a], E, t, n);
|
|
4424
|
+
}
|
|
4150
4425
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4426
|
+
// Every position key-matched at equal length (the steady-state shape
|
|
4427
|
+
// of a polling tick): membership, length, and order are unchanged —
|
|
4428
|
+
// nothing below could do observable work, so skip the staging
|
|
4429
|
+
// allocations and membership sync outright.
|
|
4430
|
+
if (a === e.length && a === s) return;
|
|
4431
|
+
const T = new Array(e.length), O = new Map;
|
|
4432
|
+
for (c = s - 1, f = e.length - 1; c >= a && f >= a && keyedMatch(E = r[c], e[f], n); c--,
|
|
4153
4433
|
f--) {
|
|
4154
4434
|
T[f] = E;
|
|
4155
4435
|
}
|
|
4156
|
-
if (
|
|
4157
|
-
for (l =
|
|
4436
|
+
if (a > f || a > c) {
|
|
4437
|
+
for (l = a; l <= f; l++) {
|
|
4158
4438
|
o = true;
|
|
4159
4439
|
i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4160
4440
|
}
|
|
@@ -4168,33 +4448,35 @@ function applyStateFast(e, t, n) {
|
|
|
4168
4448
|
return;
|
|
4169
4449
|
}
|
|
4170
4450
|
d = new Array(f + 1);
|
|
4171
|
-
for (l = f; l >=
|
|
4451
|
+
for (l = f; l >= a; l--) {
|
|
4172
4452
|
E = e[l];
|
|
4173
4453
|
S = itemKey(E, n);
|
|
4174
|
-
u =
|
|
4454
|
+
u = O.get(S);
|
|
4175
4455
|
d[l] = u === undefined ? -1 : u;
|
|
4176
|
-
|
|
4456
|
+
O.set(S, l);
|
|
4177
4457
|
}
|
|
4178
|
-
for (u =
|
|
4458
|
+
for (u = a; u <= c; u++) {
|
|
4179
4459
|
E = r[u];
|
|
4180
4460
|
S = itemKey(E, n);
|
|
4181
|
-
l =
|
|
4461
|
+
l = O.get(S);
|
|
4182
4462
|
if (l !== undefined && l !== -1) {
|
|
4183
4463
|
T[l] = E;
|
|
4184
4464
|
l = d[l];
|
|
4185
|
-
|
|
4465
|
+
O.set(S, l);
|
|
4186
4466
|
}
|
|
4187
4467
|
}
|
|
4188
|
-
for (l =
|
|
4468
|
+
for (l = a; l < e.length; l++) {
|
|
4189
4469
|
if (l in T) {
|
|
4190
4470
|
applyArrayItem(e[l], T[l], t, i?.[l], n);
|
|
4191
4471
|
} else i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4192
4472
|
}
|
|
4193
|
-
if (
|
|
4473
|
+
if (a < e.length) o = true;
|
|
4194
4474
|
} else if (e.length) {
|
|
4195
4475
|
for (let s = 0, u = e.length; s < u; s++) {
|
|
4196
4476
|
const u = r[s];
|
|
4197
|
-
if (isWrappable(u) && isWrappable(e[s]))
|
|
4477
|
+
if (isWrappable(u) && isWrappable(e[s]) && !(rawValuesUsed && (isRawValue(u) || isRawValue(e[s])))) {
|
|
4478
|
+
if (u !== e[s]) applyStateChild(e[s], u, t, n);
|
|
4479
|
+
} else {
|
|
4198
4480
|
if (u !== e[s]) o = true;
|
|
4199
4481
|
i?.[s] && setSignal(i[s], wrapValue(e[s], t));
|
|
4200
4482
|
}
|
|
@@ -4213,17 +4495,42 @@ function applyStateFast(e, t, n) {
|
|
|
4213
4495
|
let s;
|
|
4214
4496
|
if (o) {
|
|
4215
4497
|
s = o[$TRACK];
|
|
4216
|
-
|
|
4498
|
+
// The per-key body is duplicated across both loops on purpose: this is
|
|
4499
|
+
// the hottest object-diff site and a shared helper costs a per-key call
|
|
4500
|
+
// in instruction counts (CodSpeed regressed ~7% on deep-tree reconciles
|
|
4501
|
+
// with the extracted form).
|
|
4502
|
+
if (s || symbolKeyedRecords.has(o)) {
|
|
4217
4503
|
const i = s ? getAllKeys(r, undefined, e) : nodeKeys(o);
|
|
4218
4504
|
for (let u = 0, l = i.length; u < l; u++) {
|
|
4219
|
-
|
|
4505
|
+
const l = i[u];
|
|
4506
|
+
const a = o[l];
|
|
4507
|
+
const c = unwrap(r[l]);
|
|
4508
|
+
const f = unwrap(e[l]);
|
|
4509
|
+
if (c === f) continue;
|
|
4510
|
+
if (!c || !isWrappable(c) || !isWrappable(f) ||
|
|
4511
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4512
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4513
|
+
rawValuesUsed && (isRawValue(c) || isRawValue(f)) || Array.isArray(c) !== Array.isArray(f) || n(c) != null && n(c) !== n(f)) {
|
|
4514
|
+
s && setSignal(s, void 0);
|
|
4515
|
+
a && setSignal(a, isWrappable(f) ? wrap(f, t) : f);
|
|
4516
|
+
} else applyStateChild(f, c, t, n);
|
|
4220
4517
|
}
|
|
4221
4518
|
} else {
|
|
4222
4519
|
// Untracked, string-only node records (the overwhelmingly common case)
|
|
4223
4520
|
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
4224
4521
|
// per pass, which dominates allocation on large-graph reconciles.
|
|
4225
4522
|
for (const i in o) {
|
|
4226
|
-
|
|
4523
|
+
const u = o[i];
|
|
4524
|
+
const l = unwrap(r[i]);
|
|
4525
|
+
const a = unwrap(e[i]);
|
|
4526
|
+
if (l === a) continue;
|
|
4527
|
+
if (!l || !isWrappable(l) || !isWrappable(a) ||
|
|
4528
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4529
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4530
|
+
rawValuesUsed && (isRawValue(l) || isRawValue(a)) || Array.isArray(l) !== Array.isArray(a) || n(l) != null && n(l) !== n(a)) {
|
|
4531
|
+
s && setSignal(s, void 0);
|
|
4532
|
+
u && setSignal(u, isWrappable(a) ? wrap(a, t) : a);
|
|
4533
|
+
} else applyStateChild(a, l, t, n);
|
|
4227
4534
|
}
|
|
4228
4535
|
}
|
|
4229
4536
|
}
|
|
@@ -4238,26 +4545,16 @@ function applyStateFast(e, t, n) {
|
|
|
4238
4545
|
}
|
|
4239
4546
|
}
|
|
4240
4547
|
|
|
4241
|
-
// One node-key step of the fast object diff — shared by the array-iterating
|
|
4242
|
-
// (tracked / symbol-keyed) and for-in (plain) loops in applyStateFast.
|
|
4243
|
-
function diffNodeKey(e, t, n, r, i, o, s) {
|
|
4244
|
-
const u = t[e];
|
|
4245
|
-
const l = unwrap(n[e]);
|
|
4246
|
-
let c = unwrap(r[e]);
|
|
4247
|
-
if (l === c) return;
|
|
4248
|
-
if (!l || !isWrappable(l) || !isWrappable(c) || Array.isArray(l) !== Array.isArray(c) || s(l) != null && s(l) !== s(c)) {
|
|
4249
|
-
o && setSignal(o, void 0);
|
|
4250
|
-
u && setSignal(u, isWrappable(c) ? wrap(c, i) : c);
|
|
4251
|
-
} else applyState(c, wrap(l, i), s);
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
4548
|
function applyStateSlow(e, t, n) {
|
|
4255
4549
|
const r = t[STORE_VALUE];
|
|
4256
4550
|
const i = t[STORE_OVERRIDE];
|
|
4257
4551
|
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4258
4552
|
let s = t[STORE_NODE];
|
|
4259
4553
|
// swap
|
|
4260
|
-
|
|
4554
|
+
{
|
|
4555
|
+
const n = t[STORE_LOOKUP];
|
|
4556
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4557
|
+
}
|
|
4261
4558
|
t[STORE_VALUE] = e;
|
|
4262
4559
|
t[STORE_OVERRIDE] = undefined;
|
|
4263
4560
|
// merge
|
|
@@ -4265,23 +4562,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4265
4562
|
let u = false;
|
|
4266
4563
|
const l = getOverrideValue(r, i, "length", o);
|
|
4267
4564
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4268
|
-
let
|
|
4565
|
+
let a, c, f, E, d, S, T, O;
|
|
4269
4566
|
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4270
|
-
isWrappable(S) && isWrappable(e[f]) &&
|
|
4567
|
+
if (isWrappable(S) && isWrappable(e[f]) && S !== e[f]) {
|
|
4568
|
+
if (rawValuesUsed && (isRawValue(S) || isRawValue(e[f]))) {
|
|
4569
|
+
s?.[f] && setSignal(s[f], wrapValue(e[f], t));
|
|
4570
|
+
} else applyState(e[f], wrap(S, t), n);
|
|
4571
|
+
}
|
|
4271
4572
|
}
|
|
4272
|
-
const
|
|
4573
|
+
const _ = new Array(e.length), p = new Map;
|
|
4273
4574
|
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4274
4575
|
d--) {
|
|
4275
|
-
|
|
4576
|
+
_[d] = S;
|
|
4276
4577
|
}
|
|
4277
4578
|
if (f > d || f > E) {
|
|
4278
|
-
for (
|
|
4579
|
+
for (c = f; c <= d; c++) {
|
|
4279
4580
|
u = true;
|
|
4280
|
-
s?.[
|
|
4581
|
+
s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4281
4582
|
}
|
|
4282
|
-
for (;
|
|
4583
|
+
for (;c < e.length; c++) {
|
|
4283
4584
|
u = true;
|
|
4284
|
-
applyArrayItem(e[
|
|
4585
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4285
4586
|
}
|
|
4286
4587
|
const r = e.length;
|
|
4287
4588
|
syncArrayNodeMembership(t, e);
|
|
@@ -4290,43 +4591,45 @@ function applyStateSlow(e, t, n) {
|
|
|
4290
4591
|
return;
|
|
4291
4592
|
}
|
|
4292
4593
|
T = new Array(d + 1);
|
|
4293
|
-
for (
|
|
4294
|
-
S = e[
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
T[
|
|
4298
|
-
p.set(
|
|
4594
|
+
for (c = d; c >= f; c--) {
|
|
4595
|
+
S = e[c];
|
|
4596
|
+
O = itemKey(S, n);
|
|
4597
|
+
a = p.get(O);
|
|
4598
|
+
T[c] = a === undefined ? -1 : a;
|
|
4599
|
+
p.set(O, c);
|
|
4299
4600
|
}
|
|
4300
|
-
for (
|
|
4301
|
-
S = getOverrideValue(r, i,
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
if (
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
p.set(
|
|
4601
|
+
for (a = f; a <= E; a++) {
|
|
4602
|
+
S = getOverrideValue(r, i, a, o);
|
|
4603
|
+
O = itemKey(S, n);
|
|
4604
|
+
c = p.get(O);
|
|
4605
|
+
if (c !== undefined && c !== -1) {
|
|
4606
|
+
_[c] = S;
|
|
4607
|
+
c = T[c];
|
|
4608
|
+
p.set(O, c);
|
|
4308
4609
|
}
|
|
4309
4610
|
}
|
|
4310
|
-
for (
|
|
4311
|
-
if (
|
|
4312
|
-
applyArrayItem(e[
|
|
4313
|
-
} else s?.[
|
|
4611
|
+
for (c = f; c < e.length; c++) {
|
|
4612
|
+
if (c in _) {
|
|
4613
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4614
|
+
} else s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4314
4615
|
}
|
|
4315
4616
|
if (f < e.length) u = true;
|
|
4316
4617
|
} else if (e.length) {
|
|
4317
|
-
for (let l = 0,
|
|
4318
|
-
const
|
|
4319
|
-
if (isWrappable(
|
|
4320
|
-
if (
|
|
4618
|
+
for (let l = 0, a = e.length; l < a; l++) {
|
|
4619
|
+
const a = getOverrideValue(r, i, l, o);
|
|
4620
|
+
if (isWrappable(a) && isWrappable(e[l]) && !(rawValuesUsed && (isRawValue(a) || isRawValue(e[l])))) {
|
|
4621
|
+
if (a !== e[l]) applyState(e[l], wrap(a, t), n);
|
|
4622
|
+
} else {
|
|
4623
|
+
if (a !== e[l]) u = true;
|
|
4321
4624
|
s?.[l] && setSignal(s[l], wrapValue(e[l], t));
|
|
4322
4625
|
}
|
|
4323
4626
|
}
|
|
4324
4627
|
}
|
|
4325
|
-
const
|
|
4628
|
+
const a = e.length;
|
|
4326
4629
|
syncArrayNodeMembership(t, e);
|
|
4327
|
-
if (l !==
|
|
4630
|
+
if (l !== a) {
|
|
4328
4631
|
u = true;
|
|
4329
|
-
s?.length && setSignal(s.length,
|
|
4632
|
+
s?.length && setSignal(s.length, a);
|
|
4330
4633
|
}
|
|
4331
4634
|
u && notifySelf(t);
|
|
4332
4635
|
return;
|
|
@@ -4336,13 +4639,13 @@ function applyStateSlow(e, t, n) {
|
|
|
4336
4639
|
if (s) {
|
|
4337
4640
|
u = s[$TRACK];
|
|
4338
4641
|
const l = u ? getAllKeys(r, i, e) : nodeKeys(s);
|
|
4339
|
-
for (let
|
|
4340
|
-
const
|
|
4341
|
-
const f = s[
|
|
4342
|
-
const E = unwrap(getOverrideValue(r, i,
|
|
4343
|
-
let d = unwrap(e[
|
|
4642
|
+
for (let a = 0, c = l.length; a < c; a++) {
|
|
4643
|
+
const c = l[a];
|
|
4644
|
+
const f = s[c];
|
|
4645
|
+
const E = unwrap(getOverrideValue(r, i, c, o));
|
|
4646
|
+
let d = unwrap(e[c]);
|
|
4344
4647
|
if (E === d) continue;
|
|
4345
|
-
if (!E || !isWrappable(E) || !isWrappable(d) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4648
|
+
if (!E || !isWrappable(E) || !isWrappable(d) || rawValuesUsed && (isRawValue(E) || isRawValue(d)) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4346
4649
|
u && setSignal(u, void 0);
|
|
4347
4650
|
f && setSignal(f, isWrappable(d) ? wrap(d, t) : d);
|
|
4348
4651
|
} else applyState(d, wrap(E, t), n);
|
|
@@ -4410,9 +4713,16 @@ const NOKEY = () => null;
|
|
|
4410
4713
|
function createProjectionInternal(e, t, n) {
|
|
4411
4714
|
let r;
|
|
4412
4715
|
const i = new WeakMap;
|
|
4716
|
+
// A shallow projection's children are raw and never wrapped, so the
|
|
4717
|
+
// wrapper only ever runs for the root — flagging unconditionally is safe.
|
|
4718
|
+
const o = !!n?.shallow;
|
|
4413
4719
|
const wrapper = e => {
|
|
4414
4720
|
e[STORE_WRAP] = wrapProjection;
|
|
4415
4721
|
e[STORE_LOOKUP] = i;
|
|
4722
|
+
if (o) {
|
|
4723
|
+
e[STORE_SHALLOW] = true;
|
|
4724
|
+
markRawIngest(e[STORE_VALUE]);
|
|
4725
|
+
}
|
|
4416
4726
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
4417
4727
|
get() {
|
|
4418
4728
|
return r;
|
|
@@ -4427,14 +4737,14 @@ function createProjectionInternal(e, t, n) {
|
|
|
4427
4737
|
i.set(e, t);
|
|
4428
4738
|
return t;
|
|
4429
4739
|
};
|
|
4430
|
-
const
|
|
4740
|
+
const s = wrapProjection(t);
|
|
4431
4741
|
r = computed(() => {
|
|
4432
4742
|
if (!r) r = getOwner();
|
|
4433
|
-
runProjectionComputed(
|
|
4743
|
+
runProjectionComputed(s, e, n?.key || "id");
|
|
4434
4744
|
}, undefined);
|
|
4435
|
-
r.
|
|
4745
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
4436
4746
|
return {
|
|
4437
|
-
store:
|
|
4747
|
+
store: s,
|
|
4438
4748
|
node: r
|
|
4439
4749
|
};
|
|
4440
4750
|
}
|
|
@@ -4582,7 +4892,7 @@ function createWriteTraps(e, t) {
|
|
|
4582
4892
|
// the record witnesses it into the active isPending() probe.
|
|
4583
4893
|
$AFFECTS = Symbol(0);
|
|
4584
4894
|
|
|
4585
|
-
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d";
|
|
4895
|
+
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d", STORE_SHALLOW = "s";
|
|
4586
4896
|
|
|
4587
4897
|
const STORE_SELF_PENDING = Symbol(0);
|
|
4588
4898
|
|
|
@@ -4606,6 +4916,7 @@ function initStoreFields(e) {
|
|
|
4606
4916
|
e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
4607
4917
|
e[STORE_PARENT] = undefined;
|
|
4608
4918
|
e[STORE_DESC] = undefined;
|
|
4919
|
+
e[STORE_SHALLOW] = undefined;
|
|
4609
4920
|
e[$PROXY] = null;
|
|
4610
4921
|
}
|
|
4611
4922
|
|
|
@@ -4630,24 +4941,107 @@ function createStoreProxy(e, t = storeTraps, n) {
|
|
|
4630
4941
|
return r[$PROXY] = new Proxy(r, t);
|
|
4631
4942
|
}
|
|
4632
4943
|
|
|
4944
|
+
// The global lookup maps raw value -> StoreNode TARGET (not proxy): reconcile
|
|
4945
|
+
// and the unwrap/snapshot walks resolve targets through it constantly, and a
|
|
4946
|
+
// target hit is a plain field read away from its proxy while a proxy hit
|
|
4947
|
+
// costs a trap to get back to the target. Per-family STORE_LOOKUP maps
|
|
4948
|
+
// (projections/optimistic) still map raw -> proxy — their wrap functions own
|
|
4949
|
+
// that contract — so mixed-lookup consumers resolve through lookupTarget().
|
|
4633
4950
|
const storeLookup = new WeakMap;
|
|
4634
4951
|
|
|
4635
4952
|
// Node records that hold at least one user (non-`$TRACK`) symbol-keyed node.
|
|
4636
4953
|
// Lets reconcile enumerate symbols only for records that need it (#2851).
|
|
4637
4954
|
const symbolKeyedRecords = new WeakSet;
|
|
4638
4955
|
|
|
4956
|
+
function lookupTarget(e, t) {
|
|
4957
|
+
if (t !== undefined && t !== storeLookup) {
|
|
4958
|
+
const n = t.get(e);
|
|
4959
|
+
if (n !== undefined) return n[$TARGET];
|
|
4960
|
+
}
|
|
4961
|
+
return storeLookup.get(e);
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4964
|
+
// Values marked raw never acquire a proxy identity: wrap() serves them as-is
|
|
4965
|
+
// everywhere — deep stores hold them as leaf values replaced by reference.
|
|
4966
|
+
// Once raw, always raw (identity stays single, just unwrapped). Consulted
|
|
4967
|
+
// only on wrap-creation and ingest paths; reads never touch it.
|
|
4968
|
+
const rawValues = new WeakSet;
|
|
4969
|
+
|
|
4970
|
+
/**
|
|
4971
|
+
* Marks a value as raw: no store will ever wrap it — every store presents it
|
|
4972
|
+
* as-is, tracked by reference at whatever slot holds it and updated by
|
|
4973
|
+
* replacement. Useful for class instances and external objects (editors,
|
|
4974
|
+
* scene graphs, Maps) and for record-shaped data updated wholesale. Sticky
|
|
4975
|
+
* for the value's lifetime.
|
|
4976
|
+
*/
|
|
4977
|
+
// Flipped on the first mark and exported as a LIVE binding: reconcile
|
|
4978
|
+
// consults it on every recursable pair, and importing the boolean directly
|
|
4979
|
+
// lets those sites skip even the function call when no shallow store or raw
|
|
4980
|
+
// mark exists anywhere in the app.
|
|
4981
|
+
let rawValuesUsed = false;
|
|
4982
|
+
|
|
4983
|
+
function isRawValue(e) {
|
|
4984
|
+
return rawValuesUsed && rawValues.has(e);
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4987
|
+
function markRawOne(e) {
|
|
4988
|
+
if (isWrappable(e)) {
|
|
4989
|
+
// A store proxy is already tracked elsewhere: the shallow boundary passes
|
|
4990
|
+
// it through by reference (replaced, never edited — same slot semantics
|
|
4991
|
+
// as a raw) instead of claiming it raw. The sticky mark is global, so
|
|
4992
|
+
// marking a live proxy would make wrap() serve it verbatim through every
|
|
4993
|
+
// OTHER store too — downstream deep stores then captured it instead of
|
|
4994
|
+
// wrapping it in their own family, and their writes landed in the
|
|
4995
|
+
// upstream store's override layer (#2932).
|
|
4996
|
+
if (e[$TARGET] !== undefined) return;
|
|
4997
|
+
rawValuesUsed = true;
|
|
4998
|
+
rawValues.add(e);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
function markRawIngest(e) {
|
|
5003
|
+
if (Array.isArray(e)) {
|
|
5004
|
+
for (let t = 0, n = e.length; t < n; t++) markRawOne(e[t]);
|
|
5005
|
+
} else {
|
|
5006
|
+
for (const t in e) markRawOne(e[t]);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
|
|
4639
5010
|
function wrap(e, t) {
|
|
5011
|
+
// Raw is raw in every family: the mark must preempt family wrapping too,
|
|
5012
|
+
// or a shallow projection/optimistic store would proxy its raw records.
|
|
5013
|
+
if (rawValuesUsed && rawValues.has(e)) return e;
|
|
4640
5014
|
if (t?.[STORE_WRAP]) {
|
|
4641
5015
|
const n = t[STORE_WRAP](e, t);
|
|
4642
5016
|
const r = n[$TARGET];
|
|
4643
5017
|
if (r && !r[STORE_PARENT] && r !== t) r[STORE_PARENT] = t;
|
|
4644
5018
|
return n;
|
|
4645
5019
|
}
|
|
4646
|
-
|
|
4647
|
-
if (
|
|
4648
|
-
|
|
4649
|
-
|
|
5020
|
+
const n = storeLookup.get(e);
|
|
5021
|
+
if (n !== undefined) return n[$PROXY];
|
|
5022
|
+
let r = e[$PROXY];
|
|
5023
|
+
if (!r) {
|
|
5024
|
+
r = createStoreProxy(e);
|
|
5025
|
+
const n = r[$TARGET];
|
|
5026
|
+
storeLookup.set(e, n);
|
|
5027
|
+
if (t) n[STORE_PARENT] = t;
|
|
5028
|
+
}
|
|
5029
|
+
return r;
|
|
5030
|
+
}
|
|
5031
|
+
|
|
5032
|
+
// Shallow store root: the target itself is fully reactive (per-key nodes,
|
|
5033
|
+
// membership, $TRACK); its values are served raw. Seed values are marked at
|
|
5034
|
+
// creation; reconcile and the set trap mark on ingest.
|
|
5035
|
+
function wrapShallow(e) {
|
|
5036
|
+
const t = storeLookup.get(e);
|
|
5037
|
+
if (t !== undefined) {
|
|
5038
|
+
if (t[STORE_SHALLOW]) return t[$PROXY];
|
|
4650
5039
|
}
|
|
5040
|
+
const n = createStoreProxy(e);
|
|
5041
|
+
const r = n[$TARGET];
|
|
5042
|
+
r[STORE_SHALLOW] = true;
|
|
5043
|
+
storeLookup.set(e, r);
|
|
5044
|
+
markRawIngest(e);
|
|
4651
5045
|
return n;
|
|
4652
5046
|
}
|
|
4653
5047
|
|
|
@@ -4669,7 +5063,7 @@ function writeOnly(e) {
|
|
|
4669
5063
|
}
|
|
4670
5064
|
|
|
4671
5065
|
function unwrapStoreValue(e, t, n) {
|
|
4672
|
-
const r = e?.[$TARGET] ||
|
|
5066
|
+
const r = e?.[$TARGET] || lookupTarget(e, n);
|
|
4673
5067
|
if (!r) return e;
|
|
4674
5068
|
const i = r[STORE_OVERRIDE];
|
|
4675
5069
|
if (!i) return r[STORE_VALUE];
|
|
@@ -4733,7 +5127,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
4733
5127
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
4734
5128
|
* override, else held pending value, else committed value.
|
|
4735
5129
|
*/ function visibleNodeValue(e) {
|
|
4736
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
5130
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.U !== NOT_PENDING ? e.U : e.ke;
|
|
4737
5131
|
}
|
|
4738
5132
|
|
|
4739
5133
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -4788,7 +5182,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4788
5182
|
}
|
|
4789
5183
|
if (o && n in o) {
|
|
4790
5184
|
const e = o[n];
|
|
4791
|
-
s.
|
|
5185
|
+
s.me = e === undefined ? NO_SNAPSHOT : e;
|
|
4792
5186
|
snapshotSources?.add(s);
|
|
4793
5187
|
}
|
|
4794
5188
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -4841,7 +5235,7 @@ const affectsScopes = new Map;
|
|
|
4841
5235
|
// holds the root, and must still descend to pick up records added since.
|
|
4842
5236
|
i) {
|
|
4843
5237
|
if (!isWrappable(e)) return;
|
|
4844
|
-
const o = e[$TARGET] || (r
|
|
5238
|
+
const o = e[$TARGET] || lookupTarget(e, r);
|
|
4845
5239
|
const s = o ? o[STORE_VALUE] : e;
|
|
4846
5240
|
if (i.has(s)) return;
|
|
4847
5241
|
i.add(s);
|
|
@@ -4868,9 +5262,9 @@ i) {
|
|
|
4868
5262
|
const l = o || r ? getStoreSymbols(s, u) : [];
|
|
4869
5263
|
for (let e = 0, o = l.length; e < o; e++) {
|
|
4870
5264
|
const o = l[e];
|
|
4871
|
-
const
|
|
4872
|
-
if (!
|
|
4873
|
-
walkAffectsScope(
|
|
5265
|
+
const a = getPropertyDescriptor(s, u, o);
|
|
5266
|
+
if (!a || a.get) continue;
|
|
5267
|
+
walkAffectsScope(a.value, t, n, r, i);
|
|
4874
5268
|
}
|
|
4875
5269
|
} else {
|
|
4876
5270
|
const e = o || r ? getStoreKeys(s, u) : getKeys(s, u);
|
|
@@ -4906,11 +5300,11 @@ i) {
|
|
|
4906
5300
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
4907
5301
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
4908
5302
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
4909
|
-
if (n?.k) GlobalQueue.
|
|
5303
|
+
if (n?.k) GlobalQueue.Oe(n);
|
|
4910
5304
|
if (affectsScopes.size) {
|
|
4911
5305
|
const r = e[STORE_VALUE];
|
|
4912
5306
|
for (const [e, i] of affectsScopes) {
|
|
4913
|
-
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.
|
|
5307
|
+
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.Oe(e);
|
|
4914
5308
|
}
|
|
4915
5309
|
}
|
|
4916
5310
|
}
|
|
@@ -5058,7 +5452,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5058
5452
|
}
|
|
5059
5453
|
const r = e[STORE_VALUE];
|
|
5060
5454
|
const i = r[n];
|
|
5061
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5455
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.xe ?? 0) & STATUS_PENDING)) {
|
|
5062
5456
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5063
5457
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5064
5458
|
snapshotSources?.add(e);
|
|
@@ -5123,24 +5517,24 @@ function notifyStoreProperty(e, t, n, r, i, o) {
|
|
|
5123
5517
|
const n = upsertStoreNode(e, getNodes(e, STORE_HAS), t, o);
|
|
5124
5518
|
setSignal(n, u);
|
|
5125
5519
|
}
|
|
5126
|
-
const
|
|
5520
|
+
const a = getNodes(e, STORE_NODE);
|
|
5127
5521
|
if (n === "set") {
|
|
5128
|
-
if (
|
|
5129
|
-
setSignal(
|
|
5522
|
+
if (a[t]) {
|
|
5523
|
+
setSignal(a[t], () => isWrappable(r) ? wrap(r, e) : r);
|
|
5130
5524
|
} else if (!s) {
|
|
5131
|
-
const n = upsertStoreNode(e,
|
|
5525
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5132
5526
|
setSignal(n, () => isWrappable(r) ? wrap(r, e) : r);
|
|
5133
5527
|
}
|
|
5134
5528
|
} else if (n === "invalidate") {
|
|
5135
|
-
if (
|
|
5136
|
-
setSignal(
|
|
5137
|
-
delete
|
|
5529
|
+
if (a[t]) {
|
|
5530
|
+
setSignal(a[t], {});
|
|
5531
|
+
delete a[t];
|
|
5138
5532
|
}
|
|
5139
5533
|
} else {
|
|
5140
|
-
if (
|
|
5141
|
-
setSignal(
|
|
5534
|
+
if (a[t]) {
|
|
5535
|
+
setSignal(a[t], undefined);
|
|
5142
5536
|
} else if (!s) {
|
|
5143
|
-
const n = upsertStoreNode(e,
|
|
5537
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5144
5538
|
setSignal(n, undefined);
|
|
5145
5539
|
}
|
|
5146
5540
|
}
|
|
@@ -5159,7 +5553,7 @@ let Writing = null;
|
|
|
5159
5553
|
* itself (the derive function works its own draft while uninitialized).
|
|
5160
5554
|
*/ function throwIfUninitialized(e) {
|
|
5161
5555
|
const t = e[STORE_FIREWALL];
|
|
5162
|
-
if (t && t.
|
|
5556
|
+
if (t && t.xe & STATUS_UNINITIALIZED) throw t.De ?? new NotReadyError(t);
|
|
5163
5557
|
}
|
|
5164
5558
|
|
|
5165
5559
|
const storeTraps = {
|
|
@@ -5182,8 +5576,20 @@ const storeTraps = {
|
|
|
5182
5576
|
const n = e[STORE_NODE];
|
|
5183
5577
|
const r = n && n[t];
|
|
5184
5578
|
if (r !== undefined && e[STORE_VALUE][$TARGET] === undefined) {
|
|
5185
|
-
|
|
5579
|
+
// readNodeFast is read()'s plain-signal fast path hoisted over the
|
|
5580
|
+
// call; READ_SLOW means a global read window (latest/pending-check/
|
|
5581
|
+
// transition/lane/snapshot capture) or a node layer is active, and
|
|
5582
|
+
// only then does the full read() resolution have anything to do.
|
|
5583
|
+
let t = readNodeFast(r);
|
|
5584
|
+
if (t === READ_SLOW) t = read(r);
|
|
5186
5585
|
if (t === $DELETED) t = undefined;
|
|
5586
|
+
// Every node-writing site wraps wrappables before setSignal (see the
|
|
5587
|
+
// dev assertion below), so re-wrapping on read is redundant — except
|
|
5588
|
+
// during snapshot capture, where read() can surface a raw captured
|
|
5589
|
+
// value seeded from snapshot props.
|
|
5590
|
+
if (!snapshotCaptureActive) {
|
|
5591
|
+
return t;
|
|
5592
|
+
}
|
|
5187
5593
|
return isWrappable(t) ? wrap(t, e) : t;
|
|
5188
5594
|
}
|
|
5189
5595
|
}
|
|
@@ -5196,40 +5602,52 @@ const storeTraps = {
|
|
|
5196
5602
|
}
|
|
5197
5603
|
const u = getOverlayLayer(e, t);
|
|
5198
5604
|
const l = !!u;
|
|
5199
|
-
const
|
|
5200
|
-
const
|
|
5605
|
+
const a = !!e[STORE_VALUE][$TARGET];
|
|
5606
|
+
const c = u ?? e[STORE_VALUE];
|
|
5201
5607
|
if (!o) {
|
|
5202
|
-
const r = Object.getOwnPropertyDescriptor(
|
|
5608
|
+
const r = Object.getOwnPropertyDescriptor(c, t);
|
|
5203
5609
|
if (r && r.get) return r.get.call(n);
|
|
5204
5610
|
if (!r && !l && e[STORE_CUSTOM_PROTO]) {
|
|
5205
|
-
const e = unwrapStoreValue(
|
|
5611
|
+
const e = unwrapStoreValue(c);
|
|
5206
5612
|
if (hasInheritedAccessor(e, t)) {
|
|
5207
|
-
return Reflect.get(
|
|
5613
|
+
return Reflect.get(c, t, n);
|
|
5208
5614
|
}
|
|
5209
5615
|
}
|
|
5210
5616
|
}
|
|
5211
5617
|
if (writeOnly(n)) {
|
|
5212
5618
|
if (isPrototypePollutionKey$1(t) && !hasOwnStoreProperty(e, t)) return undefined;
|
|
5213
|
-
let n = o && (l || !
|
|
5619
|
+
let n = o && (l || !a) ? visibleNodeValue(o) : c[t];
|
|
5214
5620
|
n === $DELETED && (n = undefined);
|
|
5215
5621
|
if (!isWrappable(n)) return n;
|
|
5622
|
+
// Shallow boundary: records are replaced, never edited in place. Reads
|
|
5623
|
+
// inside a setter serve the raw so read-then-replace, filter/pop and
|
|
5624
|
+
// projection derives all work; in-place mutation of a raw is inert by
|
|
5625
|
+
// construction — the same contract as a markRaw child in a deep store.
|
|
5626
|
+
if (e[STORE_SHALLOW]) return n;
|
|
5216
5627
|
const r = wrap(n, e);
|
|
5217
5628
|
Writing?.add(r);
|
|
5218
5629
|
return r;
|
|
5219
5630
|
}
|
|
5220
|
-
let f = o ? l || !
|
|
5631
|
+
let f = o ? l || !a ? read(i[t]) : (read(i[t]), c[t]) : c[t];
|
|
5221
5632
|
f === $DELETED && (f = undefined);
|
|
5222
5633
|
if (!o) {
|
|
5223
|
-
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(
|
|
5634
|
+
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(c, t)) {
|
|
5224
5635
|
let t;
|
|
5225
|
-
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(
|
|
5636
|
+
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(c) : f;
|
|
5226
5637
|
} else if (getObserver() && !r) {
|
|
5227
5638
|
return read(getNode(e, i, t, isWrappable(f) ? wrap(f, e) : f, isEqual, e[STORE_SNAPSHOT_PROPS]));
|
|
5228
5639
|
}
|
|
5229
5640
|
}
|
|
5230
5641
|
// Untracked fall-through (tracked reads already threw via their node in
|
|
5231
5642
|
// read(); the dev strictRead error above wins first for memo parity).
|
|
5232
|
-
|
|
5643
|
+
// Observer-present reads must NOT re-consult the flag here: during the
|
|
5644
|
+
// settle flush the firewall has recomputed (first values live on the
|
|
5645
|
+
// pending rail, served by read() above) but its UNINITIALIZED clear is
|
|
5646
|
+
// deferred to batch commit — vetoing read()'s verdict with the stale flag
|
|
5647
|
+
// threw a fresh NotReadyError for an already-settled source, which no
|
|
5648
|
+
// sweep would ever release (#2938: projection over an async store wedged
|
|
5649
|
+
// its Loading boundary on `undefined`).
|
|
5650
|
+
if (!r && !getObserver()) throwIfUninitialized(e);
|
|
5233
5651
|
return isWrappable(f) ? wrap(f, e) : f;
|
|
5234
5652
|
},
|
|
5235
5653
|
has(e, t) {
|
|
@@ -5260,37 +5678,49 @@ const storeTraps = {
|
|
|
5260
5678
|
const {base: i, overrideKey: o, state: s} = prepareStoreWrite(e, r, t);
|
|
5261
5679
|
const u = getOverlayLayer(e, t);
|
|
5262
5680
|
const l = u ? u[t] : i;
|
|
5263
|
-
const
|
|
5264
|
-
|
|
5681
|
+
const a = u ? u[t] !== $DELETED : t in e[STORE_VALUE];
|
|
5682
|
+
// Shallow slots hold store proxies verbatim (pass-through reference,
|
|
5683
|
+
// never raw-marked — see markRawOne/#2932); everything else unwraps
|
|
5684
|
+
// and marks as usual.
|
|
5685
|
+
const c = !!e[STORE_SHALLOW] && n?.[$TARGET] !== undefined;
|
|
5686
|
+
const f = c ? n : unwrapStoreValue(n);
|
|
5687
|
+
if (e[STORE_SHALLOW] && !c && isWrappable(f)) {
|
|
5688
|
+
// Flip the live gate too: a bare add was inert unless something else
|
|
5689
|
+
// had already marked a raw somewhere (wrap() checks rawValuesUsed
|
|
5690
|
+
// first), so the documented set-trap ingest mark silently no-oped in
|
|
5691
|
+
// apps whose only shallow data arrived through writes.
|
|
5692
|
+
rawValuesUsed = true;
|
|
5693
|
+
rawValues.add(f);
|
|
5694
|
+
}
|
|
5265
5695
|
// Symbol-keyed writes on arrays are metadata, not index writes — never run
|
|
5266
5696
|
// them through the numeric index/length machinery (`parseInt` on a symbol
|
|
5267
5697
|
// throws). #2769
|
|
5268
|
-
const
|
|
5269
|
-
const
|
|
5270
|
-
const
|
|
5271
|
-
const
|
|
5272
|
-
const
|
|
5273
|
-
if (l ===
|
|
5698
|
+
const E = typeof t === "string" ? Number(t) : -1;
|
|
5699
|
+
const d = Array.isArray(s) && Number.isInteger(E) && E >= 0 && E < 4294967295 && String(E) === t;
|
|
5700
|
+
const S = d ? E + 1 : 0;
|
|
5701
|
+
const T = d && (getOverlayLayer(e, "length") ?? s).length;
|
|
5702
|
+
const O = d && S > T ? S : undefined;
|
|
5703
|
+
if (l === f && O === undefined) return true;
|
|
5274
5704
|
armOptimisticStoreWrite(e, r);
|
|
5275
|
-
if (
|
|
5705
|
+
if (f !== undefined && f === i && O === undefined) {
|
|
5276
5706
|
delete e[o]?.[t];
|
|
5277
5707
|
if (o === STORE_OPTIMISTIC_OVERRIDE) delete e[STORE_OPTIMISTIC_OWNERS]?.[t];
|
|
5278
5708
|
} else {
|
|
5279
5709
|
const n = e[o] || (e[o] = Object.create(null));
|
|
5280
|
-
n[t] =
|
|
5710
|
+
n[t] = f;
|
|
5281
5711
|
stampOptimisticOwner(e, o, t);
|
|
5282
|
-
if (
|
|
5283
|
-
n.length =
|
|
5712
|
+
if (O !== undefined) {
|
|
5713
|
+
n.length = O;
|
|
5284
5714
|
stampOptimisticOwner(e, o, "length");
|
|
5285
5715
|
}
|
|
5286
5716
|
}
|
|
5287
|
-
notifyStoreProperty(e, t, "set",
|
|
5717
|
+
notifyStoreProperty(e, t, "set", f, l, a);
|
|
5288
5718
|
// Shrinking an array's length must remove the truncated indices, otherwise
|
|
5289
5719
|
// they leak through `has`, `ownKeys`, and (tracked) index reads from the
|
|
5290
5720
|
// underlying value. Mark each as deleted and notify so reactive reads update. #2768
|
|
5291
|
-
if (Array.isArray(s) && t === "length" && typeof
|
|
5721
|
+
if (Array.isArray(s) && t === "length" && typeof f === "number" && typeof l === "number" && f < l) {
|
|
5292
5722
|
const t = e[o] || (e[o] = Object.create(null));
|
|
5293
|
-
for (let n =
|
|
5723
|
+
for (let n = f; n < l; n++) {
|
|
5294
5724
|
if (t[n] === $DELETED) continue;
|
|
5295
5725
|
const r = n in t ? t[n] : s[n];
|
|
5296
5726
|
if (!(n in t) && !(n in s)) continue;
|
|
@@ -5300,13 +5730,13 @@ const storeTraps = {
|
|
|
5300
5730
|
}
|
|
5301
5731
|
}
|
|
5302
5732
|
// notify length change
|
|
5303
|
-
if (Array.isArray(s) && t !== "length" &&
|
|
5733
|
+
if (Array.isArray(s) && t !== "length" && O !== undefined) {
|
|
5304
5734
|
const t = getNodes(e, STORE_NODE);
|
|
5305
5735
|
if (t.length) {
|
|
5306
|
-
setSignal(t.length,
|
|
5736
|
+
setSignal(t.length, O);
|
|
5307
5737
|
} else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
|
|
5308
|
-
const n = upsertStoreNode(e, t, "length",
|
|
5309
|
-
setSignal(n,
|
|
5738
|
+
const n = upsertStoreNode(e, t, "length", T, e[STORE_SNAPSHOT_PROPS]);
|
|
5739
|
+
setSignal(n, O);
|
|
5310
5740
|
}
|
|
5311
5741
|
}
|
|
5312
5742
|
if (false) ;
|
|
@@ -5453,7 +5883,7 @@ function storeSetter(e, t) {
|
|
|
5453
5883
|
}
|
|
5454
5884
|
|
|
5455
5885
|
function createStore(e, t, n) {
|
|
5456
|
-
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : wrap(e);
|
|
5886
|
+
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : t?.shallow ? wrapShallow(e) : wrap(e);
|
|
5457
5887
|
return [ i, r ? e => {
|
|
5458
5888
|
// Mark the projection as manually written before notifying property nodes.
|
|
5459
5889
|
suppressComputedRecompute(i[$REFRESH]);
|
|
@@ -5485,9 +5915,9 @@ function createStore(e, t, n) {
|
|
|
5485
5915
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5486
5916
|
* no visual change.
|
|
5487
5917
|
*/ function notifyMarkBoundaries(e) {
|
|
5488
|
-
if (!e.
|
|
5918
|
+
if (!e.G && !e.nt) return;
|
|
5489
5919
|
const t = new NotReadyError(e);
|
|
5490
|
-
t.
|
|
5920
|
+
t.we = true;
|
|
5491
5921
|
const n = new Set;
|
|
5492
5922
|
const visit = e => {
|
|
5493
5923
|
if (n.has(e)) return;
|
|
@@ -5513,7 +5943,7 @@ function createStore(e, t, n) {
|
|
|
5513
5943
|
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
5514
5944
|
*/ function registerAffectsMark(e) {
|
|
5515
5945
|
markAffects(e);
|
|
5516
|
-
globalQueue.D.
|
|
5946
|
+
globalQueue.D.L.push(e);
|
|
5517
5947
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5518
5948
|
// without them there is no materialized verdict to poke.
|
|
5519
5949
|
GlobalQueue.Te !== null && GlobalQueue.Te(e);
|
|
@@ -5575,6 +6005,8 @@ function createOptimisticStore(e, t, n) {
|
|
|
5575
6005
|
installOptimisticEngine();
|
|
5576
6006
|
GlobalQueue.ee ||= clearOptimisticStores;
|
|
5577
6007
|
const r = typeof e === "function";
|
|
6008
|
+
// Plain form: the second slot carries options.
|
|
6009
|
+
if (!r && n === undefined) n = t;
|
|
5578
6010
|
const i = r ? t : e;
|
|
5579
6011
|
const o = r ? e : undefined;
|
|
5580
6012
|
// Create optimistic projection store
|
|
@@ -5638,23 +6070,23 @@ function clearOptimisticStores(e, t) {
|
|
|
5638
6070
|
delete n[l];
|
|
5639
6071
|
if (i) delete i[l];
|
|
5640
6072
|
s = true;
|
|
5641
|
-
const
|
|
5642
|
-
if (
|
|
6073
|
+
const a = r?.[l];
|
|
6074
|
+
if (a) {
|
|
5643
6075
|
// Clear lane association so effects go to regular queue
|
|
5644
|
-
|
|
6076
|
+
a.i = undefined;
|
|
5645
6077
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
5646
6078
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
5647
6079
|
const t = getOverlayLayer(e, l);
|
|
5648
6080
|
const n = t ? t[l] : e[STORE_VALUE][l];
|
|
5649
6081
|
const r = n === $DELETED ? undefined : n;
|
|
5650
6082
|
const i = isWrappable(r) ? wrap(r, e) : r;
|
|
5651
|
-
const o = visibleNodeValue(
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
if (!
|
|
5657
|
-
insertSubs(
|
|
6083
|
+
const o = visibleNodeValue(a);
|
|
6084
|
+
a.A = NOT_PENDING;
|
|
6085
|
+
a.R = null;
|
|
6086
|
+
a.U = NOT_PENDING;
|
|
6087
|
+
a.ke = i;
|
|
6088
|
+
if (!a.At || !a.At(o, i)) {
|
|
6089
|
+
insertSubs(a, true);
|
|
5658
6090
|
schedule();
|
|
5659
6091
|
}
|
|
5660
6092
|
}
|
|
@@ -5678,9 +6110,14 @@ function clearOptimisticStores(e, t) {
|
|
|
5678
6110
|
function createOptimisticProjectionInternal(e, t, n) {
|
|
5679
6111
|
let r;
|
|
5680
6112
|
const i = new WeakMap;
|
|
6113
|
+
const o = !!n?.shallow;
|
|
5681
6114
|
const wrapper = e => {
|
|
5682
6115
|
e[STORE_WRAP] = wrapProjection;
|
|
5683
6116
|
e[STORE_LOOKUP] = i;
|
|
6117
|
+
if (o) {
|
|
6118
|
+
e[STORE_SHALLOW] = true;
|
|
6119
|
+
markRawIngest(e[STORE_VALUE]);
|
|
6120
|
+
}
|
|
5684
6121
|
e[STORE_OPTIMISTIC] = true;
|
|
5685
6122
|
// Mark as optimistic store
|
|
5686
6123
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
@@ -5697,7 +6134,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5697
6134
|
i.set(e, t);
|
|
5698
6135
|
return t;
|
|
5699
6136
|
};
|
|
5700
|
-
const
|
|
6137
|
+
const s = wrapProjection(t);
|
|
5701
6138
|
// If there's a projection function, create a computed to drive it
|
|
5702
6139
|
if (e) {
|
|
5703
6140
|
// All writes inside firewall recompute must go to STORE_OVERRIDE (base), not
|
|
@@ -5706,7 +6143,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5706
6143
|
// async yields because they fire outside any enclosing try/finally. It also
|
|
5707
6144
|
// consumes stale optimistic overlays once fresh projected data lands.
|
|
5708
6145
|
const clearProjectionOverride = () => {
|
|
5709
|
-
const e =
|
|
6146
|
+
const e = s[$TARGET];
|
|
5710
6147
|
if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e);
|
|
5711
6148
|
};
|
|
5712
6149
|
const wrapCommit = e => {
|
|
@@ -5722,15 +6159,15 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5722
6159
|
r = computed(() => {
|
|
5723
6160
|
setProjectionWriteActive(true);
|
|
5724
6161
|
try {
|
|
5725
|
-
runProjectionComputed(
|
|
6162
|
+
runProjectionComputed(s, e, n?.key || "id", wrapCommit, clearProjectionOverride);
|
|
5726
6163
|
} finally {
|
|
5727
6164
|
setProjectionWriteActive(false);
|
|
5728
6165
|
}
|
|
5729
6166
|
}, undefined);
|
|
5730
|
-
r.
|
|
6167
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
5731
6168
|
}
|
|
5732
6169
|
return {
|
|
5733
|
-
store:
|
|
6170
|
+
store: s,
|
|
5734
6171
|
node: r
|
|
5735
6172
|
};
|
|
5736
6173
|
}
|
|
@@ -5836,11 +6273,11 @@ function updatePath(e, t, n = 0) {
|
|
|
5836
6273
|
});
|
|
5837
6274
|
|
|
5838
6275
|
function snapshotImpl(e, t, n, r) {
|
|
5839
|
-
let i, o, s, u, l,
|
|
6276
|
+
let i, o, s, u, l, a;
|
|
5840
6277
|
if (!isWrappable(e)) return e;
|
|
5841
6278
|
if (n && n.has(e)) return n.get(e);
|
|
5842
6279
|
if (!n) n = new Map;
|
|
5843
|
-
if (i = e[$TARGET] ||
|
|
6280
|
+
if (i = e[$TARGET] || lookupTarget(e, r)) {
|
|
5844
6281
|
if (t) {
|
|
5845
6282
|
trackSelf(i, $TRACK);
|
|
5846
6283
|
// A tracked walk reads THROUGH the record without touching the proxy
|
|
@@ -5870,26 +6307,26 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5870
6307
|
}
|
|
5871
6308
|
if (o) {
|
|
5872
6309
|
const o = s?.length ?? e.length;
|
|
5873
|
-
for (let
|
|
5874
|
-
|
|
5875
|
-
if (
|
|
5876
|
-
if (t && isWrappable(
|
|
5877
|
-
if ((l = snapshotImpl(
|
|
6310
|
+
for (let c = 0; c < o; c++) {
|
|
6311
|
+
a = s && c in s ? s[c] : e[c];
|
|
6312
|
+
if (a === $DELETED) continue;
|
|
6313
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6314
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5878
6315
|
if (!u) n.set(e, u = [ ...e ]);
|
|
5879
|
-
u[
|
|
6316
|
+
u[c] = l;
|
|
5880
6317
|
}
|
|
5881
6318
|
}
|
|
5882
6319
|
// Enumerate array symbols separately to avoid scanning indices twice.
|
|
5883
6320
|
// Spread copies omit symbols, so assign them after the numeric walk.
|
|
5884
|
-
const
|
|
5885
|
-
for (let o = 0, f =
|
|
5886
|
-
const f =
|
|
6321
|
+
const c = r ? getStoreSymbols(e, s) : [];
|
|
6322
|
+
for (let o = 0, f = c.length; o < f; o++) {
|
|
6323
|
+
const f = c[o];
|
|
5887
6324
|
const E = getPropertyDescriptor(e, s, f);
|
|
5888
6325
|
if (!E || E.get) continue;
|
|
5889
|
-
|
|
5890
|
-
if (t && isWrappable(
|
|
5891
|
-
l = snapshotImpl(
|
|
5892
|
-
if (l !==
|
|
6326
|
+
a = s && f in s ? s[f] : e[f];
|
|
6327
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6328
|
+
l = snapshotImpl(a, t, n, r);
|
|
6329
|
+
if (l !== a || u) {
|
|
5893
6330
|
if (!u) n.set(e, u = Object.assign([ ...e ], e));
|
|
5894
6331
|
u[f] = l;
|
|
5895
6332
|
}
|
|
@@ -5904,31 +6341,31 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5904
6341
|
// A lookup means this object belongs to an immutable store backing tree,
|
|
5905
6342
|
// even if that nested value has not needed its own proxy yet.
|
|
5906
6343
|
const o = r ? getStoreKeys(e, undefined) : getKeys(e, undefined);
|
|
5907
|
-
for (let s = 0,
|
|
5908
|
-
const
|
|
5909
|
-
const f = Object.getOwnPropertyDescriptor(e,
|
|
6344
|
+
for (let s = 0, c = o.length; s < c; s++) {
|
|
6345
|
+
const c = o[s];
|
|
6346
|
+
const f = Object.getOwnPropertyDescriptor(e, c);
|
|
5910
6347
|
if (f.get) continue;
|
|
5911
|
-
|
|
5912
|
-
if (t && isWrappable(
|
|
5913
|
-
if ((l = snapshotImpl(
|
|
6348
|
+
a = f.value;
|
|
6349
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6350
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5914
6351
|
if (!u) {
|
|
5915
6352
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5916
6353
|
Object.assign(u, e);
|
|
5917
6354
|
}
|
|
5918
|
-
u[
|
|
6355
|
+
u[c] = l;
|
|
5919
6356
|
}
|
|
5920
6357
|
}
|
|
5921
6358
|
} else {
|
|
5922
6359
|
// An override only exists on a store record, and the target branch above
|
|
5923
6360
|
// always set `lookup` alongside it — so this branch is always store-keyed.
|
|
5924
6361
|
const o = getStoreKeys(e, s);
|
|
5925
|
-
for (let
|
|
5926
|
-
let f = o[
|
|
6362
|
+
for (let c = 0, f = o.length; c < f; c++) {
|
|
6363
|
+
let f = o[c];
|
|
5927
6364
|
const E = getPropertyDescriptor(e, s, f);
|
|
5928
6365
|
if (E.get) continue;
|
|
5929
|
-
|
|
5930
|
-
if (t && isWrappable(
|
|
5931
|
-
if ((l = snapshotImpl(
|
|
6366
|
+
a = f in s ? s[f] : e[f];
|
|
6367
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6368
|
+
if ((l = snapshotImpl(a, t, n, r)) !== e[f] || u) {
|
|
5932
6369
|
if (!u) {
|
|
5933
6370
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5934
6371
|
Object.assign(u, e);
|
|
@@ -6151,24 +6588,24 @@ function mapArray(e, t, n) {
|
|
|
6151
6588
|
const i = t.length > 1;
|
|
6152
6589
|
const o = t;
|
|
6153
6590
|
const s = {
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
Lt: [],
|
|
6158
|
-
Ut: o,
|
|
6591
|
+
wt: createOwner(),
|
|
6592
|
+
vt: 0,
|
|
6593
|
+
Lt: e,
|
|
6159
6594
|
Vt: [],
|
|
6595
|
+
Gt: o,
|
|
6596
|
+
Ut: [],
|
|
6160
6597
|
kt: [],
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6598
|
+
Wt: r,
|
|
6599
|
+
Ft: r || n?.keyed === false ? [] : undefined,
|
|
6600
|
+
xt: i && n?.keyed !== false ? [] : undefined,
|
|
6601
|
+
Qt: n?.keyed === false,
|
|
6602
|
+
Ht: n?.fallback
|
|
6166
6603
|
};
|
|
6167
6604
|
const u = computed(updateKeyedMap.bind(s));
|
|
6168
6605
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6169
6606
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6170
|
-
s.
|
|
6171
|
-
u.
|
|
6607
|
+
s.wt.Je = u;
|
|
6608
|
+
u.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6172
6609
|
return accessor(u);
|
|
6173
6610
|
}
|
|
6174
6611
|
|
|
@@ -6186,52 +6623,52 @@ const pureOptions = {
|
|
|
6186
6623
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6187
6624
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6188
6625
|
function updateKeyedMap() {
|
|
6189
|
-
const e = this.
|
|
6626
|
+
const e = this.Lt() || [], t = e.length;
|
|
6190
6627
|
e[$TRACK];
|
|
6191
6628
|
// top level tracking
|
|
6192
|
-
runWithOwner(this.
|
|
6629
|
+
runWithOwner(this.wt, () => {
|
|
6193
6630
|
let n, r, i, o,
|
|
6194
6631
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6195
6632
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6196
|
-
s = this.
|
|
6633
|
+
s = this.Ft ? this.Qt ? () => {
|
|
6197
6634
|
i[r] = signal(e[r], pureOptions);
|
|
6198
|
-
return this.
|
|
6635
|
+
return this.Gt(accessor(i[r]), r);
|
|
6199
6636
|
} : () => {
|
|
6200
6637
|
i[r] = signal(e[r], pureOptions);
|
|
6201
6638
|
o && (o[r] = signal(r, pureOptions));
|
|
6202
|
-
return this.
|
|
6203
|
-
} : this.
|
|
6639
|
+
return this.Gt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6640
|
+
} : this.xt ? () => {
|
|
6204
6641
|
const t = e[r];
|
|
6205
6642
|
o[r] = signal(r, pureOptions);
|
|
6206
|
-
return this.
|
|
6643
|
+
return this.Gt(t, accessor(o[r]));
|
|
6207
6644
|
} : () => {
|
|
6208
6645
|
const t = e[r];
|
|
6209
|
-
return this.
|
|
6646
|
+
return this.Gt(t);
|
|
6210
6647
|
};
|
|
6211
6648
|
// fast path for empty arrays
|
|
6212
6649
|
if (t === 0) {
|
|
6213
|
-
if (this.
|
|
6214
|
-
this.
|
|
6650
|
+
if (this.vt !== 0) {
|
|
6651
|
+
this.wt.dispose(false);
|
|
6215
6652
|
this.kt = [];
|
|
6216
|
-
this.Lt = [];
|
|
6217
6653
|
this.Vt = [];
|
|
6218
|
-
this.
|
|
6654
|
+
this.Ut = [];
|
|
6655
|
+
this.vt = 0;
|
|
6656
|
+
this.Ft && (this.Ft = []);
|
|
6219
6657
|
this.xt && (this.xt = []);
|
|
6220
|
-
this.Qt && (this.Qt = []);
|
|
6221
6658
|
}
|
|
6222
|
-
if (this.
|
|
6659
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6223
6660
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6224
6661
|
// dispose it before re-creating
|
|
6225
6662
|
this.kt[0]?.dispose();
|
|
6226
|
-
this.
|
|
6663
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6227
6664
|
}
|
|
6228
6665
|
}
|
|
6229
6666
|
// fast path for new create
|
|
6230
|
-
else if (this.
|
|
6667
|
+
else if (this.vt === 0) {
|
|
6231
6668
|
const u = new Array(t);
|
|
6232
6669
|
const l = new Array(t);
|
|
6233
|
-
i = this.
|
|
6234
|
-
o = this.
|
|
6670
|
+
i = this.Ft && new Array(t);
|
|
6671
|
+
o = this.xt && new Array(t);
|
|
6235
6672
|
try {
|
|
6236
6673
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6237
6674
|
} catch (e) {
|
|
@@ -6241,41 +6678,41 @@ function updateKeyedMap() {
|
|
|
6241
6678
|
// commit
|
|
6242
6679
|
if (this.kt[0]) this.kt[0].dispose();
|
|
6243
6680
|
// previous fallback
|
|
6244
|
-
this.
|
|
6681
|
+
this.Ut = u;
|
|
6245
6682
|
this.kt = l;
|
|
6246
|
-
i && (this.
|
|
6247
|
-
o && (this.
|
|
6248
|
-
this.
|
|
6249
|
-
this.
|
|
6683
|
+
i && (this.Ft = i);
|
|
6684
|
+
o && (this.xt = o);
|
|
6685
|
+
this.Vt = e.slice(0);
|
|
6686
|
+
this.vt = t;
|
|
6250
6687
|
} else {
|
|
6251
|
-
let u, l,
|
|
6688
|
+
let u, l, a, c, f, E, d, S, T;
|
|
6252
6689
|
// skip common prefix
|
|
6253
|
-
for (u = 0, l = Math.min(this.
|
|
6254
|
-
if (this.
|
|
6690
|
+
for (u = 0, l = Math.min(this.vt, t); u < l && (this.Vt[u] === e[u] || this.Ft && compare(this.Wt, this.Vt[u], e[u])); u++) {
|
|
6691
|
+
if (this.Ft) setSignal(this.Ft[u], e[u]);
|
|
6255
6692
|
}
|
|
6256
6693
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6257
6694
|
// at commit instead of being staged and copied twice
|
|
6258
|
-
for (l = this.
|
|
6259
|
-
|
|
6695
|
+
for (l = this.vt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.Ft && compare(this.Wt, this.Vt[l], e[a])); l--,
|
|
6696
|
+
a--) ;
|
|
6260
6697
|
// no structural change (every position matched in place at equal
|
|
6261
6698
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6262
6699
|
// array identity so downstream consumers don't re-run at all
|
|
6263
|
-
if (u === t && this.
|
|
6264
|
-
this.
|
|
6700
|
+
if (u === t && this.vt === t) {
|
|
6701
|
+
this.Vt = e.slice(0);
|
|
6265
6702
|
return;
|
|
6266
6703
|
}
|
|
6267
|
-
const
|
|
6268
|
-
const
|
|
6704
|
+
const O = t - this.vt;
|
|
6705
|
+
const _ = new Array(t);
|
|
6269
6706
|
const p = new Array(t);
|
|
6270
|
-
i = this.
|
|
6271
|
-
o = this.
|
|
6707
|
+
i = this.Ft ? new Array(t) : undefined;
|
|
6708
|
+
o = this.xt ? new Array(t) : undefined;
|
|
6272
6709
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6273
6710
|
// scanning backwards so we encounter them in natural order
|
|
6274
6711
|
E = new Map;
|
|
6275
|
-
d = new Array(
|
|
6276
|
-
for (r =
|
|
6277
|
-
|
|
6278
|
-
f = this.
|
|
6712
|
+
d = new Array(a + 1);
|
|
6713
|
+
for (r = a; r >= u; r--) {
|
|
6714
|
+
c = e[r];
|
|
6715
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6279
6716
|
n = E.get(f);
|
|
6280
6717
|
d[r] = n === undefined ? -1 : n;
|
|
6281
6718
|
E.set(f, r);
|
|
@@ -6284,24 +6721,24 @@ function updateKeyedMap() {
|
|
|
6284
6721
|
// in the new set; if so, stage them at their new positions; if not,
|
|
6285
6722
|
// queue them for disposal at commit
|
|
6286
6723
|
for (n = u; n <= l; n++) {
|
|
6287
|
-
|
|
6288
|
-
f = this.
|
|
6724
|
+
c = this.Vt[n];
|
|
6725
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6289
6726
|
r = E.get(f);
|
|
6290
6727
|
if (r !== undefined && r !== -1) {
|
|
6291
|
-
|
|
6728
|
+
_[r] = this.Ut[n];
|
|
6292
6729
|
p[r] = this.kt[n];
|
|
6293
|
-
i && (i[r] = this.
|
|
6294
|
-
o && (o[r] = this.
|
|
6730
|
+
i && (i[r] = this.Ft[n]);
|
|
6731
|
+
o && (o[r] = this.xt[n]);
|
|
6295
6732
|
r = d[r];
|
|
6296
6733
|
E.set(f, r);
|
|
6297
6734
|
} else (S ??= []).push(this.kt[n]);
|
|
6298
6735
|
}
|
|
6299
6736
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6300
6737
|
try {
|
|
6301
|
-
for (r = u; r <=
|
|
6738
|
+
for (r = u; r <= a; r++) {
|
|
6302
6739
|
if (p[r] !== undefined) continue;
|
|
6303
6740
|
(T ??= []).push(p[r] = createOwner());
|
|
6304
|
-
|
|
6741
|
+
_[r] = runWithOwner(p[r], s);
|
|
6305
6742
|
}
|
|
6306
6743
|
} catch (e) {
|
|
6307
6744
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
@@ -6311,38 +6748,38 @@ function updateKeyedMap() {
|
|
|
6311
6748
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
6312
6749
|
// change propagation), then dispose exited rows
|
|
6313
6750
|
for (n = 0; n < u; n++) {
|
|
6314
|
-
|
|
6751
|
+
_[n] = this.Ut[n];
|
|
6315
6752
|
p[n] = this.kt[n];
|
|
6316
|
-
i && (i[n] = this.
|
|
6317
|
-
o && (o[n] = this.
|
|
6753
|
+
i && (i[n] = this.Ft[n]);
|
|
6754
|
+
o && (o[n] = this.xt[n]);
|
|
6318
6755
|
}
|
|
6319
|
-
for (r = u; r <=
|
|
6756
|
+
for (r = u; r <= a; r++) {
|
|
6320
6757
|
if (i) setSignal(i[r], e[r]);
|
|
6321
6758
|
if (o) setSignal(o[r], r);
|
|
6322
6759
|
}
|
|
6323
|
-
for (r =
|
|
6324
|
-
|
|
6325
|
-
p[r] = this.kt[r -
|
|
6760
|
+
for (r = a + 1; r < t; r++) {
|
|
6761
|
+
_[r] = this.Ut[r - O];
|
|
6762
|
+
p[r] = this.kt[r - O];
|
|
6326
6763
|
if (i) {
|
|
6327
|
-
i[r] = this.
|
|
6764
|
+
i[r] = this.Ft[r - O];
|
|
6328
6765
|
setSignal(i[r], e[r]);
|
|
6329
6766
|
}
|
|
6330
6767
|
if (o) {
|
|
6331
|
-
o[r] = this.
|
|
6332
|
-
if (
|
|
6768
|
+
o[r] = this.xt[r - O];
|
|
6769
|
+
if (O !== 0) setSignal(o[r], r);
|
|
6333
6770
|
}
|
|
6334
6771
|
}
|
|
6335
|
-
this.
|
|
6772
|
+
this.Ut = _;
|
|
6336
6773
|
this.kt = p;
|
|
6337
|
-
i && (this.
|
|
6338
|
-
o && (this.
|
|
6339
|
-
this.
|
|
6774
|
+
i && (this.Ft = i);
|
|
6775
|
+
o && (this.xt = o);
|
|
6776
|
+
this.vt = t;
|
|
6340
6777
|
// save a copy of the mapped items for the next update
|
|
6341
|
-
this.
|
|
6778
|
+
this.Vt = e.slice(0);
|
|
6342
6779
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6343
6780
|
}
|
|
6344
6781
|
});
|
|
6345
|
-
return this.
|
|
6782
|
+
return this.Ut;
|
|
6346
6783
|
}
|
|
6347
6784
|
|
|
6348
6785
|
/**
|
|
@@ -6362,22 +6799,22 @@ function updateKeyedMap() {
|
|
|
6362
6799
|
*/ function repeat(e, t, n) {
|
|
6363
6800
|
const r = t;
|
|
6364
6801
|
const i = {
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6802
|
+
wt: createOwner(),
|
|
6803
|
+
vt: 0,
|
|
6804
|
+
Mt: 0,
|
|
6368
6805
|
$t: e,
|
|
6369
|
-
|
|
6806
|
+
Gt: r,
|
|
6370
6807
|
kt: [],
|
|
6371
|
-
|
|
6808
|
+
Ut: [],
|
|
6372
6809
|
jt: n?.from,
|
|
6373
|
-
|
|
6810
|
+
Ht: n?.fallback
|
|
6374
6811
|
};
|
|
6375
6812
|
const o = computed(updateRepeat.bind(i));
|
|
6376
6813
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6377
6814
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6378
6815
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6379
|
-
i.
|
|
6380
|
-
o.
|
|
6816
|
+
i.wt.Je = o;
|
|
6817
|
+
o.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6381
6818
|
return accessor(o);
|
|
6382
6819
|
}
|
|
6383
6820
|
|
|
@@ -6391,53 +6828,53 @@ function updateKeyedMap() {
|
|
|
6391
6828
|
function updateRepeat() {
|
|
6392
6829
|
const e = this.$t();
|
|
6393
6830
|
const t = this.jt?.() || 0;
|
|
6394
|
-
runWithOwner(this.
|
|
6831
|
+
runWithOwner(this.wt, () => {
|
|
6395
6832
|
if (e === 0) {
|
|
6396
|
-
if (this.
|
|
6397
|
-
this.
|
|
6833
|
+
if (this.vt !== 0) {
|
|
6834
|
+
this.wt.dispose(false);
|
|
6398
6835
|
this.kt = [];
|
|
6399
|
-
this.
|
|
6400
|
-
this.
|
|
6836
|
+
this.Ut = [];
|
|
6837
|
+
this.vt = 0;
|
|
6401
6838
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6402
|
-
this.
|
|
6839
|
+
this.Mt = 0;
|
|
6403
6840
|
}
|
|
6404
|
-
if (this.
|
|
6841
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6405
6842
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6406
6843
|
// dispose it before re-creating
|
|
6407
6844
|
this.kt[0]?.dispose();
|
|
6408
|
-
this.
|
|
6845
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6409
6846
|
}
|
|
6410
6847
|
return;
|
|
6411
6848
|
}
|
|
6412
6849
|
const n = t + e;
|
|
6413
|
-
const r = this.
|
|
6850
|
+
const r = this.Mt + this.vt;
|
|
6414
6851
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6415
6852
|
// windows are disjoint or when coming from empty/fallback.
|
|
6416
|
-
const i = Math.max(t, this.
|
|
6853
|
+
const i = Math.max(t, this.Mt);
|
|
6417
6854
|
const o = Math.min(n, r);
|
|
6418
6855
|
const s = new Array(e);
|
|
6419
6856
|
const u = new Array(e);
|
|
6420
6857
|
for (let e = i; e < o; e++) {
|
|
6421
|
-
u[e - t] = this.kt[e - this.
|
|
6422
|
-
s[e - t] = this.
|
|
6858
|
+
u[e - t] = this.kt[e - this.Mt];
|
|
6859
|
+
s[e - t] = this.Ut[e - this.Mt];
|
|
6423
6860
|
}
|
|
6424
6861
|
try {
|
|
6425
6862
|
for (let e = t; e < n; e++) {
|
|
6426
6863
|
if (e >= i && e < o) continue;
|
|
6427
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
6864
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Gt(e));
|
|
6428
6865
|
}
|
|
6429
6866
|
} catch (e) {
|
|
6430
6867
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6431
6868
|
throw e;
|
|
6432
6869
|
}
|
|
6433
6870
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6434
|
-
if (this.
|
|
6435
|
-
this.
|
|
6871
|
+
if (this.vt === 0) this.kt[0]?.dispose(); else for (let e = this.Mt; e < r; e++) if (e < t || e >= n) this.kt[e - this.Mt].dispose();
|
|
6872
|
+
this.Ut = s;
|
|
6436
6873
|
this.kt = u;
|
|
6437
|
-
this.
|
|
6438
|
-
this.
|
|
6874
|
+
this.Mt = t;
|
|
6875
|
+
this.vt = e;
|
|
6439
6876
|
});
|
|
6440
|
-
return this.
|
|
6877
|
+
return this.Ut;
|
|
6441
6878
|
}
|
|
6442
6879
|
|
|
6443
6880
|
function compare(e, t, n) {
|
|
@@ -6450,12 +6887,12 @@ function boundaryComputed(e, t) {
|
|
|
6450
6887
|
});
|
|
6451
6888
|
n.Nt = (e, t) => {
|
|
6452
6889
|
// Use passed values if provided, otherwise read from node
|
|
6453
|
-
const r = e !== undefined ? e : n.
|
|
6890
|
+
const r = e !== undefined ? e : n.xe;
|
|
6454
6891
|
const i = t !== undefined ? t : n.De;
|
|
6455
6892
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6456
6893
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6457
6894
|
// a boundary that handles it is found.
|
|
6458
|
-
n.
|
|
6895
|
+
n.xe &= ~n.Kt;
|
|
6459
6896
|
const o = n.Be.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6460
6897
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6461
6898
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
@@ -6463,8 +6900,8 @@ function boundaryComputed(e, t) {
|
|
|
6463
6900
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6464
6901
|
const s = r & ~n.Kt & (STATUS_PENDING | STATUS_ERROR);
|
|
6465
6902
|
if (s) {
|
|
6466
|
-
n.
|
|
6467
|
-
if (n.De === i && !(n.
|
|
6903
|
+
n.xe &= ~s;
|
|
6904
|
+
if (n.De === i && !(n.xe & (STATUS_PENDING | STATUS_ERROR))) n.De = undefined;
|
|
6468
6905
|
}
|
|
6469
6906
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6470
6907
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6476,7 +6913,7 @@ function boundaryComputed(e, t) {
|
|
|
6476
6913
|
}
|
|
6477
6914
|
};
|
|
6478
6915
|
n.Kt = t;
|
|
6479
|
-
n.
|
|
6916
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6480
6917
|
recompute(n, true);
|
|
6481
6918
|
return n;
|
|
6482
6919
|
}
|
|
@@ -6537,8 +6974,8 @@ class RevealController {
|
|
|
6537
6974
|
Ct: true
|
|
6538
6975
|
});
|
|
6539
6976
|
ln=true;
|
|
6540
|
-
|
|
6541
|
-
|
|
6977
|
+
an=true;
|
|
6978
|
+
cn=false;
|
|
6542
6979
|
constructor(e, t) {
|
|
6543
6980
|
this.rn = e;
|
|
6544
6981
|
this.sn = t;
|
|
@@ -6596,10 +7033,10 @@ class RevealController {
|
|
|
6596
7033
|
untrack(() => this.en());
|
|
6597
7034
|
}
|
|
6598
7035
|
en(e, t) {
|
|
6599
|
-
if (this.
|
|
6600
|
-
this.
|
|
7036
|
+
if (this.cn) return;
|
|
7037
|
+
this.cn = true;
|
|
6601
7038
|
const n = this.ln;
|
|
6602
|
-
const r = this.
|
|
7039
|
+
const r = this.an;
|
|
6603
7040
|
try {
|
|
6604
7041
|
const n = e ?? read(this.Xt), r = untrack(this.rn), i = r === "sequential" && !!untrack(this.sn), o = t ?? i;
|
|
6605
7042
|
if (n) {
|
|
@@ -6651,10 +7088,10 @@ class RevealController {
|
|
|
6651
7088
|
}
|
|
6652
7089
|
} finally {
|
|
6653
7090
|
this.ln = this.Yt();
|
|
6654
|
-
this.
|
|
6655
|
-
this.
|
|
7091
|
+
this.an = this.Zt();
|
|
7092
|
+
this.cn = false;
|
|
6656
7093
|
}
|
|
6657
|
-
if (this.Jt && (n !== this.ln || r !== this.
|
|
7094
|
+
if (this.Jt && (n !== this.ln || r !== this.an)) this.Jt.en();
|
|
6658
7095
|
}
|
|
6659
7096
|
}
|
|
6660
7097
|
|
|
@@ -6674,8 +7111,8 @@ class CollectionQueue extends Queue {
|
|
|
6674
7111
|
});
|
|
6675
7112
|
tn;
|
|
6676
7113
|
nn=false;
|
|
6677
|
-
|
|
6678
|
-
|
|
7114
|
+
On;
|
|
7115
|
+
_n=ON_INIT;
|
|
6679
7116
|
constructor(e) {
|
|
6680
7117
|
super();
|
|
6681
7118
|
this.Sn = e;
|
|
@@ -6686,16 +7123,16 @@ class CollectionQueue extends Queue {
|
|
|
6686
7123
|
}
|
|
6687
7124
|
notify(e, t, n, r) {
|
|
6688
7125
|
if (!(t & this.Sn)) return super.notify(e, t, n, r);
|
|
6689
|
-
if (this.nn && this.
|
|
7126
|
+
if (this.nn && this.On) {
|
|
6690
7127
|
const e = untrack(() => {
|
|
6691
7128
|
try {
|
|
6692
|
-
return this.
|
|
7129
|
+
return this.On();
|
|
6693
7130
|
} catch {
|
|
6694
7131
|
return ON_INIT;
|
|
6695
7132
|
}
|
|
6696
7133
|
});
|
|
6697
|
-
if (e !== this.
|
|
6698
|
-
this.
|
|
7134
|
+
if (e !== this._n) {
|
|
7135
|
+
this._n = e;
|
|
6699
7136
|
this.nn = false;
|
|
6700
7137
|
this.qt.clear();
|
|
6701
7138
|
}
|
|
@@ -6726,25 +7163,25 @@ class CollectionQueue extends Queue {
|
|
|
6726
7163
|
t &= ~this.Sn;
|
|
6727
7164
|
return t ? super.notify(e, t, n, r) : true;
|
|
6728
7165
|
}
|
|
6729
|
-
|
|
7166
|
+
Me() {
|
|
6730
7167
|
for (const e of this.qt) {
|
|
6731
7168
|
// A source with a live affects() mark holds display state for the
|
|
6732
7169
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
6733
7170
|
// status of its own, so the count is the liveness test. The release
|
|
6734
7171
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
6735
|
-
if (e.
|
|
7172
|
+
if (e.Le & REACTIVE_DISPOSED || !e.k && !(e.xe & this.Sn) && !(this.Sn & STATUS_ERROR && e.xe & STATUS_PENDING)) this.qt.delete(e);
|
|
6736
7173
|
}
|
|
6737
7174
|
if (!this.qt.size) {
|
|
6738
7175
|
if (this.Sn & STATUS_PENDING && this.Bt && !this.nn && this.Tn) {
|
|
6739
|
-
this.Bt = !!(this.Tn.
|
|
7176
|
+
this.Bt = !!(this.Tn.xe & this.Sn);
|
|
6740
7177
|
} else {
|
|
6741
7178
|
this.Bt = false;
|
|
6742
7179
|
}
|
|
6743
7180
|
if (!this.Bt) {
|
|
6744
7181
|
setSignal(this.Xt, false);
|
|
6745
|
-
if (this.
|
|
7182
|
+
if (this.On) {
|
|
6746
7183
|
try {
|
|
6747
|
-
this.
|
|
7184
|
+
this._n = untrack(() => this.On());
|
|
6748
7185
|
} catch {
|
|
6749
7186
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
6750
7187
|
}
|
|
@@ -6762,7 +7199,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6762
7199
|
ownedWrite: true,
|
|
6763
7200
|
Ct: true
|
|
6764
7201
|
});
|
|
6765
|
-
if (r) o.
|
|
7202
|
+
if (r) o.On = r;
|
|
6766
7203
|
const s = o.Tn = createBoundChildren(i, t, o, e);
|
|
6767
7204
|
// Prime source tracking so reveal registration sees pending sources.
|
|
6768
7205
|
untrack(() => {
|
|
@@ -6772,7 +7209,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6772
7209
|
} catch (e) {
|
|
6773
7210
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
6774
7211
|
}
|
|
6775
|
-
o.Bt = t || !!(s.
|
|
7212
|
+
o.Bt = t || !!(s.xe & e) || s.De instanceof NotReadyError;
|
|
6776
7213
|
});
|
|
6777
7214
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
6778
7215
|
if (u) {
|