@solidjs/signals 2.0.0-beta.21 → 2.0.0-beta.23
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 +210 -301
- package/dist/node.cjs +1106 -1196
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +103 -103
- package/dist/prod/core/core.js +254 -297
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +60 -47
- package/dist/prod/core/heap.js +50 -50
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +64 -106
- package/dist/prod/core/owner.js +52 -52
- package/dist/prod/core/scheduler.js +210 -211
- package/dist/prod/core/verdict.js +129 -78
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +23 -5
- package/dist/prod/store/optimistic.js +11 -11
- package/dist/prod/store/projection.js +2 -2
- package/dist/prod/store/store.js +14 -14
- package/dist/types/affects.d.ts +9 -9
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/error.d.ts +7 -0
- package/dist/types/core/scheduler.d.ts +1 -6
- package/dist/types/core/types.d.ts +6 -11
- package/dist/types-cjs/affects.d.cts +9 -9
- package/dist/types-cjs/core/async.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +7 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -6
- package/dist/types-cjs/core/types.d.cts +6 -11
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -214,7 +214,7 @@ const activeLanes = new Set;
|
|
|
214
214
|
l: [ [], [] ],
|
|
215
215
|
S: null,
|
|
216
216
|
T: activeTransition,
|
|
217
|
-
|
|
217
|
+
_: r
|
|
218
218
|
};
|
|
219
219
|
signalLanes.set(e, t);
|
|
220
220
|
activeLanes.add(t);
|
|
@@ -224,7 +224,7 @@ const activeLanes = new Set;
|
|
|
224
224
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
225
225
|
// the owner's write merges the companion's subscribers into this lane and
|
|
226
226
|
// their effects wait on its async instead of flushing immediately.
|
|
227
|
-
adoptCompanionLane(e.
|
|
227
|
+
adoptCompanionLane(e.p, t);
|
|
228
228
|
adoptCompanionLane(e.O, t);
|
|
229
229
|
return t;
|
|
230
230
|
}
|
|
@@ -236,7 +236,7 @@ function adoptCompanionLane(e, t) {
|
|
|
236
236
|
const r = findLane(n);
|
|
237
237
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
238
238
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
239
|
-
if (r !== t && r.o === e && !r.
|
|
239
|
+
if (r !== t && r.o === e && !r._) r._ = t;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
/**
|
|
@@ -315,9 +315,9 @@ function resolveTransition(e) {
|
|
|
315
315
|
if (i !== n && !hasActiveOverride(e)) {
|
|
316
316
|
// Parent-child lanes stay independent so isPending resolves without
|
|
317
317
|
// waiting for the parent's async. The child keeps ownership.
|
|
318
|
-
if (n.
|
|
318
|
+
if (n._ && findLane(n._) === i) {
|
|
319
319
|
e.i = t;
|
|
320
|
-
} else if (i.
|
|
320
|
+
} else if (i._ && findLane(i._) === n) ; else mergeLanes(n, i);
|
|
321
321
|
}
|
|
322
322
|
return;
|
|
323
323
|
}
|
|
@@ -330,15 +330,15 @@ const transitions = new Set;
|
|
|
330
330
|
const dirtyQueue = {
|
|
331
331
|
h: new Array(2e3).fill(undefined),
|
|
332
332
|
N: false,
|
|
333
|
-
|
|
334
|
-
|
|
333
|
+
C: 0,
|
|
334
|
+
P: 0
|
|
335
335
|
};
|
|
336
336
|
|
|
337
337
|
const zombieQueue = {
|
|
338
338
|
h: new Array(2e3).fill(undefined),
|
|
339
339
|
N: false,
|
|
340
|
-
|
|
341
|
-
|
|
340
|
+
C: 0,
|
|
341
|
+
P: 0
|
|
342
342
|
};
|
|
343
343
|
|
|
344
344
|
let clock = 0;
|
|
@@ -572,35 +572,32 @@ class GlobalQueue extends Queue {
|
|
|
572
572
|
// _clearOptimisticStore).
|
|
573
573
|
static ne=null;
|
|
574
574
|
// affects()-side hooks (wired by affects.ts, mirroring _update): the mark
|
|
575
|
-
// engine — count/register/release
|
|
576
|
-
//
|
|
577
|
-
//
|
|
575
|
+
// engine — count/register/release — lives with the feature. Every call site
|
|
576
|
+
// is gated by state only that module creates, so `!` invocations are safe
|
|
577
|
+
// once the gate holds.
|
|
578
578
|
static re=null;
|
|
579
579
|
static ie=null;
|
|
580
580
|
static oe=null;
|
|
581
|
-
static se=null;
|
|
582
|
-
static ue=null;
|
|
583
|
-
static le=null;
|
|
584
581
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
585
582
|
// config is active — including after _resetExternalSourceConfig()).
|
|
586
|
-
static
|
|
587
|
-
static
|
|
583
|
+
static se=null;
|
|
584
|
+
static ue=null;
|
|
588
585
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
589
586
|
// imported; null in apps that never use them). Call sites either guard for
|
|
590
587
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
591
588
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
592
589
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
593
590
|
// isPending()/latest()).
|
|
591
|
+
static le=null;
|
|
592
|
+
static ce=null;
|
|
593
|
+
static ae=null;
|
|
594
594
|
static fe=null;
|
|
595
595
|
static Ee=null;
|
|
596
|
-
static de=null;
|
|
597
596
|
static Se=null;
|
|
597
|
+
static de=null;
|
|
598
598
|
static Te=null;
|
|
599
|
-
static pe=null;
|
|
600
599
|
static _e=null;
|
|
601
|
-
static
|
|
602
|
-
static Re=null;
|
|
603
|
-
static Ie=null;
|
|
600
|
+
static pe=null;
|
|
604
601
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
605
602
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
606
603
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -608,20 +605,18 @@ class GlobalQueue extends Queue {
|
|
|
608
605
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
609
606
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
610
607
|
// once the gate holds.
|
|
608
|
+
static Oe=null;
|
|
609
|
+
static Re=null;
|
|
610
|
+
static Ie=null;
|
|
611
611
|
static Ae=null;
|
|
612
612
|
static he=null;
|
|
613
613
|
static Ne=null;
|
|
614
614
|
static ye=null;
|
|
615
|
-
static Pe=null;
|
|
616
615
|
static Ce=null;
|
|
616
|
+
static Pe=null;
|
|
617
617
|
static ge=null;
|
|
618
618
|
static be=null;
|
|
619
619
|
static De=null;
|
|
620
|
-
static me=null;
|
|
621
|
-
static ve=null;
|
|
622
|
-
static we=null;
|
|
623
|
-
static Ge=null;
|
|
624
|
-
static Le=null;
|
|
625
620
|
flush() {
|
|
626
621
|
if (this.B) return;
|
|
627
622
|
this.B = true;
|
|
@@ -642,25 +637,18 @@ class GlobalQueue extends Queue {
|
|
|
642
637
|
if (this.D === e) currentBatch = this.D = createBatch();
|
|
643
638
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
644
639
|
if (activeLanes.size) {
|
|
645
|
-
GlobalQueue.
|
|
646
|
-
GlobalQueue.
|
|
640
|
+
GlobalQueue.he(EFFECT_RENDER);
|
|
641
|
+
GlobalQueue.he(EFFECT_USER);
|
|
647
642
|
}
|
|
648
643
|
this.stashQueues(e.K);
|
|
649
644
|
clock++;
|
|
650
645
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
651
646
|
// scheduled so the outer drain loop commits them via the plain
|
|
652
647
|
// flush path instead of leaving them until the next natural flush.
|
|
653
|
-
scheduled = dirtyQueue.
|
|
648
|
+
scheduled = dirtyQueue.P >= dirtyQueue.C || this.D.H.length > 0;
|
|
654
649
|
reassignPendingTransition(e.H);
|
|
655
650
|
activeTransition = null;
|
|
656
|
-
|
|
657
|
-
// wraps finalizePureQueue in the engine; a non-empty _optimisticNodes
|
|
658
|
-
// means _optimisticWrite ran, which installed the hook.
|
|
659
|
-
if (!e.$.length && !e.j.size && e.G.length) {
|
|
660
|
-
GlobalQueue.Ne(e);
|
|
661
|
-
} else {
|
|
662
|
-
finalizePureQueue(null, true);
|
|
663
|
-
}
|
|
651
|
+
finalizePureQueue(null, true);
|
|
664
652
|
return;
|
|
665
653
|
}
|
|
666
654
|
const t = activeTransition;
|
|
@@ -685,7 +673,7 @@ class GlobalQueue extends Queue {
|
|
|
685
673
|
} else {
|
|
686
674
|
if (canUseSimpleSyncFlush(this)) {
|
|
687
675
|
commitPendingNodes();
|
|
688
|
-
if (dirtyQueue.
|
|
676
|
+
if (dirtyQueue.P >= dirtyQueue.C) {
|
|
689
677
|
runHeap(dirtyQueue, GlobalQueue.X);
|
|
690
678
|
commitPendingNodes();
|
|
691
679
|
}
|
|
@@ -696,11 +684,11 @@ class GlobalQueue extends Queue {
|
|
|
696
684
|
}
|
|
697
685
|
clock++;
|
|
698
686
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
699
|
-
scheduled = dirtyQueue.
|
|
687
|
+
scheduled = dirtyQueue.P >= dirtyQueue.C;
|
|
700
688
|
// Run lane effects first (for ready lanes), then regular effects
|
|
701
|
-
activeLanes.size && GlobalQueue.
|
|
689
|
+
activeLanes.size && GlobalQueue.he(EFFECT_RENDER);
|
|
702
690
|
this.run(EFFECT_RENDER);
|
|
703
|
-
activeLanes.size && GlobalQueue.
|
|
691
|
+
activeLanes.size && GlobalQueue.he(EFFECT_USER);
|
|
704
692
|
this.run(EFFECT_USER);
|
|
705
693
|
if (false) ;
|
|
706
694
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
@@ -713,7 +701,12 @@ class GlobalQueue extends Queue {
|
|
|
713
701
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
714
702
|
if (t & STATUS_PENDING) {
|
|
715
703
|
if (n & STATUS_PENDING) {
|
|
716
|
-
const t = r !== undefined ? r : e.
|
|
704
|
+
const t = r !== undefined ? r : e.me;
|
|
705
|
+
// A visibility-only mark notification (the affects() boundary
|
|
706
|
+
// channel) updates display state on its way up but must be invisible
|
|
707
|
+
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
708
|
+
// reporter and never counts toward the loading-boundary diagnostic.
|
|
709
|
+
if (t?.ve) return true;
|
|
717
710
|
if (activeTransition && t) {
|
|
718
711
|
const n = t.source;
|
|
719
712
|
let r = activeTransition.j.get(n);
|
|
@@ -787,48 +780,48 @@ function insertSubs(e, t = false) {
|
|
|
787
780
|
// Get source lane: prefer node's own lane over current context
|
|
788
781
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
789
782
|
const n = e.i || currentOptimisticLane;
|
|
790
|
-
const r = e.
|
|
783
|
+
const r = e.we !== undefined;
|
|
791
784
|
const i = reaskArmed;
|
|
792
|
-
for (let o = e.k; o !== null; o = o.
|
|
785
|
+
for (let o = e.k; o !== null; o = o.Ge) {
|
|
793
786
|
// A value-change notification is a new question for the subscriber: any
|
|
794
787
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
795
|
-
if (i) o.
|
|
796
|
-
if (r && o.
|
|
797
|
-
o.
|
|
788
|
+
if (i) o.Ue.Le &= ~REACTIVE_REASK;
|
|
789
|
+
if (r && o.Ue.ke & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
790
|
+
o.Ue.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
798
791
|
continue;
|
|
799
792
|
}
|
|
800
793
|
if (t && n) {
|
|
801
|
-
o.
|
|
802
|
-
assignOrMergeLane(o.
|
|
794
|
+
o.Ue.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
795
|
+
assignOrMergeLane(o.Ue, n);
|
|
803
796
|
} else if (t) {
|
|
804
|
-
o.
|
|
797
|
+
o.Ue.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
805
798
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
806
|
-
o.
|
|
799
|
+
o.Ue.i = undefined;
|
|
807
800
|
}
|
|
808
|
-
enqueueSub(o.
|
|
801
|
+
enqueueSub(o.Ue);
|
|
809
802
|
}
|
|
810
803
|
}
|
|
811
804
|
|
|
812
805
|
function commitPendingNode(e) {
|
|
813
806
|
const t = e;
|
|
814
|
-
if (!t.
|
|
807
|
+
if (!t.Ve) {
|
|
815
808
|
if (e.V !== NOT_PENDING) {
|
|
816
|
-
e.
|
|
809
|
+
e.xe = e.V;
|
|
817
810
|
e.V = NOT_PENDING;
|
|
818
811
|
}
|
|
819
|
-
if (e.
|
|
812
|
+
if (e.p || e.O) GlobalQueue.fe(e);
|
|
820
813
|
return;
|
|
821
814
|
}
|
|
822
815
|
if (e.V !== NOT_PENDING) {
|
|
823
|
-
e.
|
|
816
|
+
e.xe = e.V;
|
|
824
817
|
e.V = NOT_PENDING;
|
|
825
818
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
826
|
-
if (e.
|
|
819
|
+
if (e.Qe && e.Qe !== EFFECT_TRACKED) e.Fe = true;
|
|
827
820
|
}
|
|
828
|
-
t.
|
|
829
|
-
if (!(t
|
|
830
|
-
if (t.
|
|
831
|
-
if (e.
|
|
821
|
+
t.Le &= ~REACTIVE_MANUAL_WRITE;
|
|
822
|
+
if (!(t.We & STATUS_PENDING)) t.We &= ~STATUS_UNINITIALIZED;
|
|
823
|
+
if (t.Me !== null || t.He !== null) GlobalQueue.J(t, false, true);
|
|
824
|
+
if (e.p || e.O) GlobalQueue.fe(e);
|
|
832
825
|
}
|
|
833
826
|
|
|
834
827
|
function commitPendingNodes() {
|
|
@@ -845,7 +838,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
845
838
|
const n = !t;
|
|
846
839
|
if (n) commitPendingNodes();
|
|
847
840
|
if (!t && globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
848
|
-
const r = dirtyQueue.
|
|
841
|
+
const r = dirtyQueue.P >= dirtyQueue.C;
|
|
849
842
|
if (r) runHeap(dirtyQueue, GlobalQueue.X);
|
|
850
843
|
if (n) {
|
|
851
844
|
if (r) commitPendingNodes();
|
|
@@ -853,20 +846,26 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
853
846
|
const t = e ?? globalQueue.D;
|
|
854
847
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
855
848
|
// which installed the engine's hooks.
|
|
856
|
-
if (t.G.length) GlobalQueue.
|
|
849
|
+
if (t.G.length) GlobalQueue.Re(t.G);
|
|
857
850
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
858
851
|
// so they re-run with the now-committed values visible.
|
|
859
852
|
if (e && e.q.size) {
|
|
860
853
|
for (const t of e.q) {
|
|
861
|
-
if (t.
|
|
854
|
+
if (t.Le & REACTIVE_DISPOSED) continue;
|
|
862
855
|
enqueueSub(t);
|
|
863
856
|
}
|
|
864
857
|
e.q.clear();
|
|
865
858
|
}
|
|
866
859
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
867
860
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
868
|
-
// batch means registerAffectsMark ran, which installed the hook.
|
|
869
|
-
|
|
861
|
+
// batch means registerAffectsMark ran, which installed the hook. Marks
|
|
862
|
+
// held boundary display state through the visual channel, and their
|
|
863
|
+
// release is the display-state update point — re-run the boundary sweep
|
|
864
|
+
// (the earlier sweep above ran while the marks were still live).
|
|
865
|
+
if (t.L.length) {
|
|
866
|
+
GlobalQueue.re(t.L);
|
|
867
|
+
if (globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
868
|
+
}
|
|
870
869
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
871
870
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
872
871
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
@@ -874,13 +873,13 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
874
873
|
if (t.U.size) GlobalQueue.te(t.U, e);
|
|
875
874
|
sweepTransientStoreNodes();
|
|
876
875
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
877
|
-
if (activeLanes.size) GlobalQueue.
|
|
876
|
+
if (activeLanes.size) GlobalQueue.Ae(e);
|
|
878
877
|
}
|
|
879
878
|
}
|
|
880
879
|
|
|
881
880
|
function checkBoundaryChildren(e) {
|
|
882
881
|
for (const t of e.m) {
|
|
883
|
-
t.
|
|
882
|
+
t.je?.();
|
|
884
883
|
checkBoundaryChildren(t);
|
|
885
884
|
}
|
|
886
885
|
}
|
|
@@ -947,16 +946,16 @@ function runQueue$1(e, t) {
|
|
|
947
946
|
}
|
|
948
947
|
|
|
949
948
|
function reporterBlocksSource(e, t) {
|
|
950
|
-
if (e.
|
|
951
|
-
if (e
|
|
952
|
-
for (let n = e.
|
|
953
|
-
let e = n.
|
|
949
|
+
if (e.Le & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
950
|
+
if (e.$e?.has(t)) return true;
|
|
951
|
+
for (let n = e.Ke; n; n = n.Ye) {
|
|
952
|
+
let e = n.qe;
|
|
954
953
|
while (e) {
|
|
955
|
-
if (e === t || e.
|
|
954
|
+
if (e === t || e.Be === t) return true;
|
|
956
955
|
e = e.t;
|
|
957
956
|
}
|
|
958
957
|
}
|
|
959
|
-
return !!(e
|
|
958
|
+
return !!(e.We & STATUS_PENDING && e.me instanceof NotReadyError && e.me.source === t);
|
|
960
959
|
}
|
|
961
960
|
|
|
962
961
|
function transitionComplete(e) {
|
|
@@ -972,7 +971,7 @@ function transitionComplete(e) {
|
|
|
972
971
|
}
|
|
973
972
|
r.delete(e);
|
|
974
973
|
}
|
|
975
|
-
if (!i) e.j.delete(n); else if (n
|
|
974
|
+
if (!i) e.j.delete(n); else if (n.We & STATUS_PENDING && n.me?.source === n) {
|
|
976
975
|
t = false;
|
|
977
976
|
break;
|
|
978
977
|
}
|
|
@@ -980,7 +979,7 @@ function transitionComplete(e) {
|
|
|
980
979
|
// Override blockage lives with the engine. Absent hook = "no optimistic
|
|
981
980
|
// blockage", which is exact: only _optimisticWrite (engine) pushes to
|
|
982
981
|
// _optimisticNodes, so without the engine the loop was vacuous anyway.
|
|
983
|
-
if (t && e.G.length && GlobalQueue.
|
|
982
|
+
if (t && e.G.length && GlobalQueue.Ie(e)) t = false;
|
|
984
983
|
t && (e.I = true);
|
|
985
984
|
return t;
|
|
986
985
|
}
|
|
@@ -1005,7 +1004,7 @@ function runInTransition(e, t) {
|
|
|
1005
1004
|
}
|
|
1006
1005
|
|
|
1007
1006
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1008
|
-
return e.
|
|
1007
|
+
return e.Le & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1009
1008
|
}
|
|
1010
1009
|
|
|
1011
1010
|
/**
|
|
@@ -1013,40 +1012,40 @@ function runInTransition(e, t) {
|
|
|
1013
1012
|
* the heap and go directly to their effect queue; everything else is inserted
|
|
1014
1013
|
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
1015
1014
|
*/ function enqueueSub(e) {
|
|
1016
|
-
if (e.
|
|
1015
|
+
if (e.Qe === EFFECT_TRACKED) {
|
|
1017
1016
|
const t = e;
|
|
1018
|
-
if (!t.
|
|
1019
|
-
t.
|
|
1020
|
-
t.
|
|
1017
|
+
if (!t.Fe) {
|
|
1018
|
+
t.Fe = true;
|
|
1019
|
+
t.Ze.enqueue(EFFECT_USER, t.Xe);
|
|
1021
1020
|
}
|
|
1022
1021
|
return;
|
|
1023
1022
|
}
|
|
1024
1023
|
const t = queueFor(e);
|
|
1025
|
-
if (t.
|
|
1024
|
+
if (t.C > e.ze) t.C = e.ze;
|
|
1026
1025
|
insertIntoHeap(e, t);
|
|
1027
1026
|
}
|
|
1028
1027
|
|
|
1029
1028
|
function actualInsertIntoHeap(e, t) {
|
|
1030
|
-
const n = (e.Z?.
|
|
1031
|
-
if (n >= e.
|
|
1032
|
-
const r = e.
|
|
1029
|
+
const n = (e.Z?.Je ? e.Z.et?.ze : e.Z?.ze) ?? -1;
|
|
1030
|
+
if (n >= e.ze) e.ze = n + 1;
|
|
1031
|
+
const r = e.ze;
|
|
1033
1032
|
const i = t.h[r];
|
|
1034
1033
|
if (i === undefined) t.h[r] = e; else {
|
|
1035
|
-
const t = i.
|
|
1036
|
-
t.
|
|
1037
|
-
e.
|
|
1038
|
-
i.
|
|
1034
|
+
const t = i.tt;
|
|
1035
|
+
t.nt = e;
|
|
1036
|
+
e.tt = t;
|
|
1037
|
+
i.tt = e;
|
|
1039
1038
|
}
|
|
1040
|
-
if (r > t.
|
|
1039
|
+
if (r > t.P) t.P = r;
|
|
1041
1040
|
}
|
|
1042
1041
|
|
|
1043
1042
|
function insertIntoHeap(e, t) {
|
|
1044
|
-
let n = e.
|
|
1043
|
+
let n = e.Le;
|
|
1045
1044
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1046
1045
|
if (n & REACTIVE_CHECK) {
|
|
1047
|
-
e.
|
|
1046
|
+
e.Le = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1048
1047
|
} else {
|
|
1049
|
-
e.
|
|
1048
|
+
e.Le = n | REACTIVE_IN_HEAP;
|
|
1050
1049
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1051
1050
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1052
1051
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1058,49 +1057,49 @@ function insertIntoHeap(e, t) {
|
|
|
1058
1057
|
}
|
|
1059
1058
|
|
|
1060
1059
|
function insertIntoHeapHeight(e, t) {
|
|
1061
|
-
let n = e.
|
|
1060
|
+
let n = e.Le;
|
|
1062
1061
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1063
|
-
e.
|
|
1062
|
+
e.Le = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1064
1063
|
actualInsertIntoHeap(e, t);
|
|
1065
1064
|
}
|
|
1066
1065
|
|
|
1067
1066
|
function deleteFromHeap(e, t) {
|
|
1068
|
-
const n = e.
|
|
1067
|
+
const n = e.Le;
|
|
1069
1068
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1070
|
-
e.
|
|
1071
|
-
const r = e.
|
|
1072
|
-
if (e.
|
|
1073
|
-
const n = e.
|
|
1069
|
+
e.Le = n & -25;
|
|
1070
|
+
const r = e.ze;
|
|
1071
|
+
if (e.tt === e) t.h[r] = undefined; else {
|
|
1072
|
+
const n = e.nt;
|
|
1074
1073
|
const i = t.h[r];
|
|
1075
1074
|
const o = n ?? i;
|
|
1076
|
-
if (e === i) t.h[r] = n; else e.
|
|
1077
|
-
o.
|
|
1075
|
+
if (e === i) t.h[r] = n; else e.tt.nt = n;
|
|
1076
|
+
o.tt = e.tt;
|
|
1078
1077
|
}
|
|
1079
|
-
e.
|
|
1080
|
-
e.
|
|
1078
|
+
e.tt = e;
|
|
1079
|
+
e.nt = undefined;
|
|
1081
1080
|
}
|
|
1082
1081
|
|
|
1083
1082
|
function markHeap(e) {
|
|
1084
1083
|
if (e.N) return;
|
|
1085
1084
|
e.N = true;
|
|
1086
|
-
for (let t = 0; t <= e.
|
|
1087
|
-
for (let n = e.h[t]; n !== undefined; n = n.
|
|
1088
|
-
if (n.
|
|
1085
|
+
for (let t = 0; t <= e.P; t++) {
|
|
1086
|
+
for (let n = e.h[t]; n !== undefined; n = n.nt) {
|
|
1087
|
+
if (n.Le & REACTIVE_IN_HEAP) markNode(n);
|
|
1089
1088
|
}
|
|
1090
1089
|
}
|
|
1091
1090
|
}
|
|
1092
1091
|
|
|
1093
1092
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1094
|
-
const n = e.
|
|
1093
|
+
const n = e.Le;
|
|
1095
1094
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1096
|
-
e.
|
|
1097
|
-
for (let t = e.k; t !== null; t = t.
|
|
1098
|
-
markNode(t.
|
|
1099
|
-
}
|
|
1100
|
-
if (e.
|
|
1101
|
-
for (let t = e.
|
|
1102
|
-
for (let e = t.k; e !== null; e = e.
|
|
1103
|
-
markNode(e.
|
|
1095
|
+
e.Le = n & -4 | t;
|
|
1096
|
+
for (let t = e.k; t !== null; t = t.Ge) {
|
|
1097
|
+
markNode(t.Ue, REACTIVE_CHECK);
|
|
1098
|
+
}
|
|
1099
|
+
if (e.rt !== null) {
|
|
1100
|
+
for (let t = e.rt; t !== null; t = t.it) {
|
|
1101
|
+
for (let e = t.k; e !== null; e = e.Ge) {
|
|
1102
|
+
markNode(e.Ue, REACTIVE_CHECK);
|
|
1104
1103
|
}
|
|
1105
1104
|
}
|
|
1106
1105
|
}
|
|
@@ -1108,33 +1107,33 @@ function markNode(e, t = REACTIVE_DIRTY) {
|
|
|
1108
1107
|
|
|
1109
1108
|
function runHeap(e, t) {
|
|
1110
1109
|
e.N = false;
|
|
1111
|
-
for (e.
|
|
1112
|
-
let n = e.h[e.
|
|
1110
|
+
for (e.C = 0; e.C <= e.P; e.C++) {
|
|
1111
|
+
let n = e.h[e.C];
|
|
1113
1112
|
while (n !== undefined) {
|
|
1114
|
-
if (n.
|
|
1115
|
-
n = e.h[e.
|
|
1113
|
+
if (n.Le & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1114
|
+
n = e.h[e.C];
|
|
1116
1115
|
}
|
|
1117
1116
|
}
|
|
1118
|
-
e.
|
|
1117
|
+
e.P = 0;
|
|
1119
1118
|
}
|
|
1120
1119
|
|
|
1121
1120
|
function adjustHeight(e, t) {
|
|
1122
1121
|
deleteFromHeap(e, t);
|
|
1123
|
-
let n = e.
|
|
1124
|
-
for (let t = e.
|
|
1125
|
-
const e = t.
|
|
1126
|
-
const r = e.
|
|
1127
|
-
if (r.
|
|
1128
|
-
}
|
|
1129
|
-
if (e.
|
|
1130
|
-
e.
|
|
1131
|
-
for (let t = e.k; t !== null; t = t.
|
|
1122
|
+
let n = e.ze;
|
|
1123
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
1124
|
+
const e = t.qe;
|
|
1125
|
+
const r = e.Be || e;
|
|
1126
|
+
if (r.Ve && r.ze >= n) n = r.ze + 1;
|
|
1127
|
+
}
|
|
1128
|
+
if (e.ze !== n) {
|
|
1129
|
+
e.ze = n;
|
|
1130
|
+
for (let t = e.k; t !== null; t = t.Ge) {
|
|
1132
1131
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1133
1132
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1134
1133
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
1135
1134
|
// `zombieQueue`), breaking the flag/queue invariant `deleteFromHeap`
|
|
1136
1135
|
// relies on — the same corruption class as #2759.
|
|
1137
|
-
insertIntoHeapHeight(t.
|
|
1136
|
+
insertIntoHeapHeight(t.Ue, queueFor(t.Ue));
|
|
1138
1137
|
}
|
|
1139
1138
|
}
|
|
1140
1139
|
}
|
|
@@ -1143,10 +1142,10 @@ const PENDING_OWNER = {};
|
|
|
1143
1142
|
|
|
1144
1143
|
// Dummy owner to trigger store's read() path
|
|
1145
1144
|
function markDisposal(e) {
|
|
1146
|
-
let t = e.
|
|
1145
|
+
let t = e.ot;
|
|
1147
1146
|
while (t) {
|
|
1148
|
-
const e = t.
|
|
1149
|
-
t.
|
|
1147
|
+
const e = t.Le;
|
|
1148
|
+
t.Le = e | REACTIVE_ZOMBIE;
|
|
1150
1149
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1151
1150
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1152
1151
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1157,79 +1156,79 @@ function markDisposal(e) {
|
|
|
1157
1156
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
1158
1157
|
}
|
|
1159
1158
|
markDisposal(t);
|
|
1160
|
-
t = t.
|
|
1159
|
+
t = t.st;
|
|
1161
1160
|
}
|
|
1162
1161
|
}
|
|
1163
1162
|
|
|
1164
1163
|
function dispose(e) {
|
|
1165
|
-
let t = e.
|
|
1164
|
+
let t = e.Ke;
|
|
1166
1165
|
while (t !== null) {
|
|
1167
1166
|
t = unlinkSubs(t);
|
|
1168
1167
|
}
|
|
1169
|
-
e.
|
|
1170
|
-
e.
|
|
1168
|
+
e.Ke = null;
|
|
1169
|
+
e.ut = null;
|
|
1171
1170
|
disposeChildren(e, true);
|
|
1172
1171
|
}
|
|
1173
1172
|
|
|
1174
1173
|
function disposeChildren(e, t = false, n) {
|
|
1175
|
-
const r = e.
|
|
1174
|
+
const r = e.Le;
|
|
1176
1175
|
if (r & REACTIVE_DISPOSED) return;
|
|
1177
1176
|
if (t) {
|
|
1178
|
-
e.
|
|
1177
|
+
e.Le = r | REACTIVE_DISPOSED;
|
|
1179
1178
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1180
1179
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1181
1180
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1182
1181
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1183
1182
|
// false, and notifies subscribers still watching the companion.
|
|
1184
1183
|
const t = e;
|
|
1185
|
-
if (t.
|
|
1184
|
+
if (t.p || t.O) GlobalQueue.fe(t);
|
|
1186
1185
|
}
|
|
1187
|
-
if (t && e.
|
|
1188
|
-
let i = n ? e.
|
|
1186
|
+
if (t && e.Ve) e.lt = null;
|
|
1187
|
+
let i = n ? e.Me : e.ot;
|
|
1189
1188
|
while (i) {
|
|
1190
|
-
const e = i.
|
|
1191
|
-
if (i.
|
|
1189
|
+
const e = i.st;
|
|
1190
|
+
if (i.Ke) {
|
|
1192
1191
|
const e = i;
|
|
1193
1192
|
deleteFromHeap(e, queueFor(e));
|
|
1194
|
-
let t = e.
|
|
1193
|
+
let t = e.Ke;
|
|
1195
1194
|
do {
|
|
1196
1195
|
t = unlinkSubs(t);
|
|
1197
1196
|
} while (t !== null);
|
|
1198
|
-
e.
|
|
1199
|
-
e.
|
|
1197
|
+
e.Ke = null;
|
|
1198
|
+
e.ut = null;
|
|
1200
1199
|
}
|
|
1201
1200
|
disposeChildren(i, true);
|
|
1202
1201
|
i = e;
|
|
1203
1202
|
}
|
|
1204
1203
|
if (n) {
|
|
1205
|
-
e.
|
|
1204
|
+
e.Me = null;
|
|
1206
1205
|
} else {
|
|
1207
|
-
e.
|
|
1208
|
-
e.
|
|
1206
|
+
e.ot = null;
|
|
1207
|
+
e.ct = 0;
|
|
1209
1208
|
}
|
|
1210
1209
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1211
1210
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1212
1211
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1213
1212
|
// walks that already advanced past us still reach later siblings.
|
|
1214
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.Z !== null && !(e.Z.
|
|
1215
|
-
const t = e.
|
|
1216
|
-
const n = e.
|
|
1217
|
-
if (t !== null) t.
|
|
1218
|
-
if (n !== null) n.
|
|
1219
|
-
e.
|
|
1213
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.Z !== null && !(e.Z.Le & REACTIVE_DISPOSED)) {
|
|
1214
|
+
const t = e.ft;
|
|
1215
|
+
const n = e.st;
|
|
1216
|
+
if (t !== null) t.st = n; else e.Z.ot = n;
|
|
1217
|
+
if (n !== null) n.ft = t;
|
|
1218
|
+
e.ft = null;
|
|
1220
1219
|
}
|
|
1221
1220
|
runDisposal(e, n);
|
|
1222
1221
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
1223
1222
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
1224
|
-
if (t && e.
|
|
1225
|
-
const t = e.
|
|
1226
|
-
e.
|
|
1223
|
+
if (t && e.Et) {
|
|
1224
|
+
const t = e.Et;
|
|
1225
|
+
e.Et = undefined;
|
|
1227
1226
|
t();
|
|
1228
1227
|
}
|
|
1229
1228
|
}
|
|
1230
1229
|
|
|
1231
1230
|
function runDisposal(e, t) {
|
|
1232
|
-
let n = t ? e.
|
|
1231
|
+
let n = t ? e.He : e.St;
|
|
1233
1232
|
if (!n) return;
|
|
1234
1233
|
if (Array.isArray(n)) {
|
|
1235
1234
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1239,13 +1238,13 @@ function runDisposal(e, t) {
|
|
|
1239
1238
|
} else {
|
|
1240
1239
|
n.call(n);
|
|
1241
1240
|
}
|
|
1242
|
-
t ? e.
|
|
1241
|
+
t ? e.He = null : e.St = null;
|
|
1243
1242
|
}
|
|
1244
1243
|
|
|
1245
1244
|
function childId(e, t) {
|
|
1246
1245
|
let n = e;
|
|
1247
|
-
while (n.
|
|
1248
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1246
|
+
while (n.ke & CONFIG_TRANSPARENT && n.Z) n = n.Z;
|
|
1247
|
+
if (n.id != null) return formatId(n.id, t ? n.ct++ : n.ct);
|
|
1249
1248
|
throw new Error("");
|
|
1250
1249
|
}
|
|
1251
1250
|
|
|
@@ -1326,7 +1325,7 @@ function formatId(e, t) {
|
|
|
1326
1325
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
1327
1326
|
*/ function cleanup(e) {
|
|
1328
1327
|
if (!context) return e;
|
|
1329
|
-
if (!context.
|
|
1328
|
+
if (!context.St) context.St = e; else if (Array.isArray(context.St)) context.St.push(e); else context.St = [ context.St, e ];
|
|
1330
1329
|
return e;
|
|
1331
1330
|
}
|
|
1332
1331
|
|
|
@@ -1346,7 +1345,7 @@ function formatId(e, t) {
|
|
|
1346
1345
|
* }
|
|
1347
1346
|
* ```
|
|
1348
1347
|
*/ function isDisposed(e) {
|
|
1349
|
-
return !!(e.
|
|
1348
|
+
return !!(e.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1350
1349
|
}
|
|
1351
1350
|
|
|
1352
1351
|
function disposeRootSelf(e = true) {
|
|
@@ -1365,29 +1364,29 @@ function disposeRootSelf(e = true) {
|
|
|
1365
1364
|
const n = e?.transparent ?? false;
|
|
1366
1365
|
const r = {
|
|
1367
1366
|
id: inheritId(e, n, t),
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1367
|
+
ke: n ? CONFIG_TRANSPARENT : 0,
|
|
1368
|
+
Je: true,
|
|
1369
|
+
et: t?.Je ? t.et : t,
|
|
1370
|
+
ot: null,
|
|
1371
|
+
st: null,
|
|
1372
1372
|
ft: null,
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
Ke: null,
|
|
1373
|
+
St: null,
|
|
1374
|
+
Ze: t?.Ze ?? globalQueue,
|
|
1375
|
+
dt: t?.dt || defaultContext,
|
|
1376
|
+
ct: 0,
|
|
1377
|
+
He: null,
|
|
1378
|
+
Me: null,
|
|
1380
1379
|
Z: t,
|
|
1381
1380
|
dispose: disposeRootSelf
|
|
1382
1381
|
};
|
|
1383
1382
|
if (t) {
|
|
1384
|
-
const e = t.
|
|
1383
|
+
const e = t.ot;
|
|
1385
1384
|
if (e === null) {
|
|
1386
|
-
t.
|
|
1385
|
+
t.ot = r;
|
|
1387
1386
|
} else {
|
|
1388
|
-
r.
|
|
1389
|
-
e.
|
|
1390
|
-
t.
|
|
1387
|
+
r.st = e;
|
|
1388
|
+
e.ft = r;
|
|
1389
|
+
t.ot = r;
|
|
1391
1390
|
}
|
|
1392
1391
|
}
|
|
1393
1392
|
return r;
|
|
@@ -1423,60 +1422,71 @@ function disposeRootSelf(e = true) {
|
|
|
1423
1422
|
|
|
1424
1423
|
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L100
|
|
1425
1424
|
function unlinkSubs(e) {
|
|
1426
|
-
const t = e.
|
|
1427
|
-
const n = e.
|
|
1428
|
-
const r = e.
|
|
1429
|
-
const i = e.
|
|
1430
|
-
if (r !== null) r.
|
|
1431
|
-
if (i !== null) i.
|
|
1425
|
+
const t = e.qe;
|
|
1426
|
+
const n = e.Ye;
|
|
1427
|
+
const r = e.Ge;
|
|
1428
|
+
const i = e.Tt;
|
|
1429
|
+
if (r !== null) r.Tt = i; else t._t = i;
|
|
1430
|
+
if (i !== null) i.Ge = r; else {
|
|
1432
1431
|
t.k = r;
|
|
1433
1432
|
if (r === null) {
|
|
1434
1433
|
t.W?.();
|
|
1435
1434
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1435
|
+
// A pending node is exempt: its in-flight async work (or the
|
|
1436
|
+
// transition holding it) is an observer — tearing down would orphan
|
|
1437
|
+
// the work and re-execute it on the next read. The settle path runs
|
|
1438
|
+
// this same last-one-out check when that observer releases (the
|
|
1439
|
+
// untracked-read dispose in core.ts guards on pending identically).
|
|
1436
1440
|
const e = t;
|
|
1437
|
-
e.
|
|
1441
|
+
e.Ve && e.ke & CONFIG_AUTO_DISPOSE && !(e.Le & REACTIVE_ZOMBIE) && !(e.We & STATUS_PENDING) && unobserved(e);
|
|
1438
1442
|
}
|
|
1439
1443
|
}
|
|
1440
1444
|
return n;
|
|
1441
1445
|
}
|
|
1442
1446
|
|
|
1443
1447
|
function trimStaleDeps(e) {
|
|
1444
|
-
const t = e.
|
|
1445
|
-
let n = t !== null ? t.
|
|
1448
|
+
const t = e.ut;
|
|
1449
|
+
let n = t !== null ? t.Ye : e.Ke;
|
|
1446
1450
|
if (n !== null) {
|
|
1447
1451
|
do {
|
|
1448
1452
|
n = unlinkSubs(n);
|
|
1449
1453
|
} while (n !== null);
|
|
1450
|
-
if (t !== null) t.
|
|
1454
|
+
if (t !== null) t.Ye = null; else e.Ke = null;
|
|
1451
1455
|
}
|
|
1452
1456
|
}
|
|
1453
1457
|
|
|
1454
1458
|
function unobserved(e) {
|
|
1455
1459
|
deleteFromHeap(e, queueFor(e));
|
|
1456
|
-
let t = e.
|
|
1460
|
+
let t = e.Ke;
|
|
1457
1461
|
while (t !== null) {
|
|
1458
1462
|
t = unlinkSubs(t);
|
|
1459
1463
|
}
|
|
1460
|
-
e.
|
|
1461
|
-
e.
|
|
1464
|
+
e.Ke = null;
|
|
1465
|
+
e.ut = null;
|
|
1462
1466
|
disposeChildren(e, true);
|
|
1463
1467
|
}
|
|
1464
1468
|
|
|
1465
1469
|
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L52
|
|
1466
1470
|
function link(e, t, n = false) {
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1471
|
+
// Repeat touches within one pass AND-combine `_pendingObserver`: a probe
|
|
1472
|
+
// read (`isPending(() => x())`) beside a value read of the same dep must
|
|
1473
|
+
// not relabel the value dependency as probe-only — the value read is what
|
|
1474
|
+
// real-error propagation and affects() coverage key off, regardless of
|
|
1475
|
+
// read order within the computation.
|
|
1476
|
+
const r = t.ut;
|
|
1477
|
+
if (r !== null && r.qe === e) {
|
|
1478
|
+
r.Ot &&= n;
|
|
1470
1479
|
return;
|
|
1471
1480
|
}
|
|
1472
1481
|
let i = null;
|
|
1473
|
-
const o = t.
|
|
1482
|
+
const o = t.Le & REACTIVE_RECOMPUTING_DEPS;
|
|
1474
1483
|
if (o) {
|
|
1475
|
-
i = r !== null ? r.
|
|
1476
|
-
if (i !== null && i.
|
|
1477
|
-
i.
|
|
1478
|
-
t.
|
|
1479
|
-
|
|
1484
|
+
i = r !== null ? r.Ye : t.Ke;
|
|
1485
|
+
if (i !== null && i.qe === e) {
|
|
1486
|
+
i.Rt = t.It;
|
|
1487
|
+
t.ut = i;
|
|
1488
|
+
// First touch of this pass: the previous pass's label is stale.
|
|
1489
|
+
i.Ot = n;
|
|
1480
1490
|
return;
|
|
1481
1491
|
}
|
|
1482
1492
|
}
|
|
@@ -1485,22 +1495,24 @@ function link(e, t, n = false) {
|
|
|
1485
1495
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
1486
1496
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1487
1497
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1488
|
-
const s = e.
|
|
1489
|
-
if (s !== null && s.
|
|
1490
|
-
|
|
1498
|
+
const s = e._t;
|
|
1499
|
+
if (s !== null && s.Ue === t && (!o || s.Rt === t.It)) {
|
|
1500
|
+
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1501
|
+
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1502
|
+
if (o) s.Ot &&= n; else s.Ot = n;
|
|
1491
1503
|
return;
|
|
1492
1504
|
}
|
|
1493
|
-
const u = t.
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1505
|
+
const u = t.ut = e._t = {
|
|
1506
|
+
qe: e,
|
|
1507
|
+
Ue: t,
|
|
1508
|
+
Ye: i,
|
|
1509
|
+
Tt: s,
|
|
1510
|
+
Ge: null,
|
|
1511
|
+
Rt: t.It,
|
|
1512
|
+
Ot: n
|
|
1501
1513
|
};
|
|
1502
|
-
if (r !== null) r.
|
|
1503
|
-
if (s !== null) s.
|
|
1514
|
+
if (r !== null) r.Ye = u; else t.Ke = u;
|
|
1515
|
+
if (s !== null) s.Ge = u; else e.k = u;
|
|
1504
1516
|
}
|
|
1505
1517
|
|
|
1506
1518
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1509,79 +1521,75 @@ function link(e, t, n = false) {
|
|
|
1509
1521
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
1510
1522
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
1511
1523
|
function addPendingSource(e, t) {
|
|
1512
|
-
if (e
|
|
1513
|
-
(e
|
|
1524
|
+
if (e.$e?.has(t)) return false;
|
|
1525
|
+
(e.$e ??= new Set).add(t);
|
|
1514
1526
|
return true;
|
|
1515
1527
|
}
|
|
1516
1528
|
|
|
1517
1529
|
function removePendingSource(e, t) {
|
|
1518
|
-
if (!e
|
|
1519
|
-
if (e.
|
|
1530
|
+
if (!e.$e?.delete(t)) return false;
|
|
1531
|
+
if (e.$e.size === 0) e.$e = undefined;
|
|
1520
1532
|
return true;
|
|
1521
1533
|
}
|
|
1522
1534
|
|
|
1523
1535
|
function clearPendingSources(e) {
|
|
1524
|
-
e
|
|
1525
|
-
e
|
|
1536
|
+
e.$e?.clear();
|
|
1537
|
+
e.$e = undefined;
|
|
1526
1538
|
}
|
|
1527
1539
|
|
|
1528
1540
|
function setPendingError(e, t, n) {
|
|
1529
1541
|
if (!t) {
|
|
1530
|
-
e.
|
|
1542
|
+
e.me = null;
|
|
1531
1543
|
return;
|
|
1532
1544
|
}
|
|
1533
1545
|
if (n instanceof NotReadyError && n.source === t) {
|
|
1534
|
-
e.
|
|
1546
|
+
e.me = n;
|
|
1535
1547
|
return;
|
|
1536
1548
|
}
|
|
1537
|
-
const r = e.
|
|
1549
|
+
const r = e.me;
|
|
1538
1550
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
1539
|
-
e.
|
|
1551
|
+
e.me = new NotReadyError(t);
|
|
1540
1552
|
}
|
|
1541
1553
|
}
|
|
1542
1554
|
|
|
1543
1555
|
function forEachDependent(e, t) {
|
|
1544
|
-
for (let n = e.k; n !== null; n = n.
|
|
1556
|
+
for (let n = e.k; n !== null; n = n.Ge) t(n.Ue, n);
|
|
1545
1557
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1546
|
-
for (let n = e.
|
|
1547
|
-
for (let e = n.k; e !== null; e = e.
|
|
1558
|
+
for (let n = e.rt ?? null; n !== null; n = n.it) {
|
|
1559
|
+
for (let e = n.k; e !== null; e = e.Ge) t(e.Ue, e);
|
|
1548
1560
|
}
|
|
1549
1561
|
}
|
|
1550
1562
|
|
|
1551
1563
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
1552
1564
|
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
1553
1565
|
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
1554
|
-
function settlePendingSource(e
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
//
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
if (
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
const n = e.Be?.values().next().value;
|
|
1568
|
-
if (n) {
|
|
1569
|
-
setPendingError(e, n);
|
|
1570
|
-
o !== null && o(e);
|
|
1566
|
+
function settlePendingSource(e) {
|
|
1567
|
+
let t = false;
|
|
1568
|
+
const n = new Set;
|
|
1569
|
+
// Companion updates no-op without the verdict layer (null hook).
|
|
1570
|
+
const r = GlobalQueue.ce;
|
|
1571
|
+
const settle = i => {
|
|
1572
|
+
if (n.has(i) || !removePendingSource(i, e)) return;
|
|
1573
|
+
n.add(i);
|
|
1574
|
+
i.M = clock;
|
|
1575
|
+
const o = i.$e?.values().next().value;
|
|
1576
|
+
if (o) {
|
|
1577
|
+
setPendingError(i, o);
|
|
1578
|
+
r !== null && r(i);
|
|
1571
1579
|
} else {
|
|
1572
|
-
|
|
1573
|
-
setPendingError(
|
|
1574
|
-
|
|
1575
|
-
if (
|
|
1576
|
-
enqueueSub(
|
|
1577
|
-
|
|
1580
|
+
i.We &= ~STATUS_PENDING;
|
|
1581
|
+
setPendingError(i);
|
|
1582
|
+
r !== null && r(i);
|
|
1583
|
+
if (i.At) {
|
|
1584
|
+
enqueueSub(i);
|
|
1585
|
+
t = true;
|
|
1578
1586
|
}
|
|
1579
|
-
|
|
1587
|
+
i.At = false;
|
|
1580
1588
|
}
|
|
1581
|
-
forEachDependent(
|
|
1589
|
+
forEachDependent(i, settle);
|
|
1582
1590
|
};
|
|
1583
1591
|
forEachDependent(e, settle);
|
|
1584
|
-
if (
|
|
1592
|
+
if (t) schedule();
|
|
1585
1593
|
}
|
|
1586
1594
|
|
|
1587
1595
|
// Object-thenable detection (Promises/A+ shape).
|
|
@@ -1599,26 +1607,26 @@ function handleAsync(e, t, n) {
|
|
|
1599
1607
|
});
|
|
1600
1608
|
}
|
|
1601
1609
|
if (!i && !r) {
|
|
1602
|
-
e.
|
|
1610
|
+
e.lt = null;
|
|
1603
1611
|
return t;
|
|
1604
1612
|
}
|
|
1605
|
-
e.
|
|
1613
|
+
e.lt = t;
|
|
1606
1614
|
let o;
|
|
1607
1615
|
const handleError = n => {
|
|
1608
|
-
if (e.
|
|
1616
|
+
if (e.lt !== t) return;
|
|
1609
1617
|
globalQueue.initTransition(resolveTransition(e));
|
|
1610
1618
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1611
1619
|
notifyStatus(e, n instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1612
1620
|
e.M = clock;
|
|
1613
1621
|
};
|
|
1614
1622
|
const asyncWrite = (r, i) => {
|
|
1615
|
-
if (e.
|
|
1623
|
+
if (e.lt !== t) return;
|
|
1616
1624
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1617
1625
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1618
1626
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1619
|
-
if (e.
|
|
1627
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1620
1628
|
globalQueue.initTransition(resolveTransition(e));
|
|
1621
|
-
const o = !!(e
|
|
1629
|
+
const o = !!(e.We & STATUS_UNINITIALIZED);
|
|
1622
1630
|
trimStaleDeps(e);
|
|
1623
1631
|
clearStatus(e);
|
|
1624
1632
|
const s = resolveLane(e);
|
|
@@ -1645,22 +1653,22 @@ function handleAsync(e, t, n) {
|
|
|
1645
1653
|
// only notified when the hold is visible to them: under an active
|
|
1646
1654
|
// override every reader sees the override (A17), so waking subs would
|
|
1647
1655
|
// re-show an unchanged view — the revert is the notification point.
|
|
1648
|
-
GlobalQueue.
|
|
1656
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1649
1657
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1650
1658
|
e.M = clock;
|
|
1651
1659
|
} else if (s) {
|
|
1652
1660
|
// Route through lane's effect queue for independent flushing
|
|
1653
|
-
const t = e.
|
|
1654
|
-
const n = e.
|
|
1655
|
-
const i = e.
|
|
1661
|
+
const t = e.Qe;
|
|
1662
|
+
const n = e.xe;
|
|
1663
|
+
const i = e.ht;
|
|
1656
1664
|
try {
|
|
1657
1665
|
if (!t && o || !i || !i(r, n)) {
|
|
1658
|
-
e.
|
|
1666
|
+
e.xe = r;
|
|
1659
1667
|
e.M = clock;
|
|
1660
1668
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1661
1669
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1662
1670
|
// (computePendingState doesn't read _value).
|
|
1663
|
-
GlobalQueue.
|
|
1671
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1664
1672
|
insertSubs(e, true);
|
|
1665
1673
|
}
|
|
1666
1674
|
} catch (t) {
|
|
@@ -1684,18 +1692,34 @@ function handleAsync(e, t, n) {
|
|
|
1684
1692
|
flush();
|
|
1685
1693
|
i?.();
|
|
1686
1694
|
};
|
|
1695
|
+
// A pending node's in-flight promise is an observer: `unlinkSubs` skips
|
|
1696
|
+
// autodispose while STATUS_PENDING so subscriber churn can't orphan the
|
|
1697
|
+
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
1698
|
+
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1699
|
+
// it runs the same last-one-out check the other release sites run.
|
|
1700
|
+
const settleAutodispose = () => {
|
|
1701
|
+
if (e.ke & CONFIG_AUTO_DISPOSE && !e.k && !(e.We & STATUS_PENDING)) {
|
|
1702
|
+
unobserved(e);
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1687
1705
|
if (i) {
|
|
1688
1706
|
let n = false, r = false, i, s = true;
|
|
1689
1707
|
t.then(e => {
|
|
1690
1708
|
if (s) {
|
|
1691
1709
|
o = e;
|
|
1692
1710
|
n = true;
|
|
1693
|
-
} else
|
|
1711
|
+
} else {
|
|
1712
|
+
asyncWrite(e);
|
|
1713
|
+
settleAutodispose();
|
|
1714
|
+
}
|
|
1694
1715
|
}, e => {
|
|
1695
1716
|
if (s) {
|
|
1696
1717
|
i = e;
|
|
1697
1718
|
r = true;
|
|
1698
|
-
} else
|
|
1719
|
+
} else {
|
|
1720
|
+
handleError(e);
|
|
1721
|
+
settleAutodispose();
|
|
1722
|
+
}
|
|
1699
1723
|
});
|
|
1700
1724
|
s = false;
|
|
1701
1725
|
if (r) {
|
|
@@ -1729,7 +1753,7 @@ function handleAsync(e, t, n) {
|
|
|
1729
1753
|
u = n;
|
|
1730
1754
|
c = true;
|
|
1731
1755
|
if (n.done) i = true;
|
|
1732
|
-
} else if (e.
|
|
1756
|
+
} else if (e.lt !== t) {
|
|
1733
1757
|
return;
|
|
1734
1758
|
} else if (!n.done) {
|
|
1735
1759
|
r = true;
|
|
@@ -1748,7 +1772,7 @@ function handleAsync(e, t, n) {
|
|
|
1748
1772
|
if (f) {
|
|
1749
1773
|
l = n;
|
|
1750
1774
|
a = true;
|
|
1751
|
-
} else if (e.
|
|
1775
|
+
} else if (e.lt === t) {
|
|
1752
1776
|
i = true;
|
|
1753
1777
|
handleError(n);
|
|
1754
1778
|
}
|
|
@@ -1780,86 +1804,74 @@ function handleAsync(e, t, n) {
|
|
|
1780
1804
|
}
|
|
1781
1805
|
|
|
1782
1806
|
function clearStatus(e, t = false) {
|
|
1783
|
-
if (e
|
|
1784
|
-
if (e.
|
|
1807
|
+
if (e.$e) clearPendingSources(e);
|
|
1808
|
+
if (e.At) e.At = false;
|
|
1785
1809
|
// The pending window is over; its quiet classification dies with it.
|
|
1786
1810
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1787
1811
|
// plain store to an existing slot — no shape change.)
|
|
1788
|
-
e.
|
|
1789
|
-
e
|
|
1790
|
-
if (e.
|
|
1812
|
+
e.Nt = false;
|
|
1813
|
+
e.We = t ? 0 : e.We & STATUS_UNINITIALIZED;
|
|
1814
|
+
if (e.me) setPendingError(e);
|
|
1791
1815
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1792
1816
|
// once the verdict layer created them, which installs the hooks).
|
|
1793
|
-
if (e.
|
|
1794
|
-
if (e.
|
|
1795
|
-
if (e.
|
|
1817
|
+
if (e.p || e.O) GlobalQueue.ce(e);
|
|
1818
|
+
if (e.rt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1819
|
+
if (e.yt) e.yt();
|
|
1796
1820
|
}
|
|
1797
1821
|
|
|
1798
1822
|
function notifyStatus(e, t, n, r, i) {
|
|
1799
1823
|
// Wrap regular errors to track source node
|
|
1800
1824
|
if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
|
|
1801
1825
|
const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
// freeze unrelated writes that share a downstream memo until the action
|
|
1806
|
-
// settles. Real async keeps queuing (its commits ride the transition).
|
|
1807
|
-
const s = o?.Dt !== undefined;
|
|
1808
|
-
// A real error is a settled verdict a mark must not erase (#2893): landing
|
|
1809
|
-
// STATUS_PENDING here would clobber `_error` with the sentinel's
|
|
1810
|
-
// NotReadyError, and unlike real async there is no arriving value whose
|
|
1811
|
-
// recompute would surface the error again. Descent stops too — everything
|
|
1812
|
-
// downstream holds the propagated error for the same reason.
|
|
1813
|
-
if (s && e.$e & STATUS_ERROR) return;
|
|
1814
|
-
const u = o === e;
|
|
1815
|
-
const l = t === STATUS_PENDING && e.A !== undefined && !u;
|
|
1816
|
-
const c = l && hasActiveOverride(e);
|
|
1826
|
+
const s = o === e;
|
|
1827
|
+
const u = t === STATUS_PENDING && e.A !== undefined && !s;
|
|
1828
|
+
const l = u && hasActiveOverride(e);
|
|
1817
1829
|
if (!r) {
|
|
1818
1830
|
if (t === STATUS_PENDING && o) {
|
|
1819
1831
|
addPendingSource(e, o);
|
|
1820
|
-
e
|
|
1832
|
+
e.We = STATUS_PENDING | e.We & STATUS_UNINITIALIZED;
|
|
1821
1833
|
// Preserve the current source on this propagation so render-effect notification
|
|
1822
1834
|
// can register every distinct pending source with the transition.
|
|
1823
1835
|
setPendingError(e, o, n);
|
|
1824
1836
|
} else {
|
|
1825
1837
|
clearPendingSources(e);
|
|
1826
|
-
e
|
|
1827
|
-
e.
|
|
1838
|
+
e.We = t | (t !== STATUS_ERROR ? e.We & STATUS_UNINITIALIZED : 0);
|
|
1839
|
+
e.me = n;
|
|
1828
1840
|
}
|
|
1829
|
-
GlobalQueue.
|
|
1830
|
-
if (e.
|
|
1841
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
1842
|
+
if (e.rt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1831
1843
|
}
|
|
1832
1844
|
if (i && !r) {
|
|
1833
1845
|
assignOrMergeLane(e, i);
|
|
1834
1846
|
}
|
|
1835
|
-
const
|
|
1836
|
-
const
|
|
1837
|
-
if (e.
|
|
1847
|
+
const c = r || l;
|
|
1848
|
+
const a = r || u ? undefined : i;
|
|
1849
|
+
if (e.yt) {
|
|
1838
1850
|
if (r && t === STATUS_PENDING) {
|
|
1839
1851
|
return;
|
|
1840
1852
|
}
|
|
1841
|
-
if (
|
|
1842
|
-
e.
|
|
1853
|
+
if (c) {
|
|
1854
|
+
e.yt(t, n);
|
|
1843
1855
|
} else {
|
|
1844
|
-
e.
|
|
1856
|
+
e.yt();
|
|
1845
1857
|
}
|
|
1846
1858
|
return;
|
|
1847
1859
|
}
|
|
1848
1860
|
forEachDependent(e, (e, r) => {
|
|
1849
1861
|
e.M = clock;
|
|
1850
|
-
if (t === STATUS_PENDING && o && !e
|
|
1862
|
+
if (t === STATUS_PENDING && o && !e.$e?.has(o) || t !== STATUS_PENDING && (e.me !== n || e.$e)) {
|
|
1851
1863
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1852
1864
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1853
1865
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1854
1866
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1855
1867
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1856
|
-
if (r.
|
|
1868
|
+
if (r.Ot && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1857
1869
|
enqueueSub(e);
|
|
1858
1870
|
schedule();
|
|
1859
1871
|
return;
|
|
1860
1872
|
}
|
|
1861
|
-
if (!
|
|
1862
|
-
notifyStatus(e, t, n,
|
|
1873
|
+
if (!c && !e.T) queuePendingNode(e);
|
|
1874
|
+
notifyStatus(e, t, n, c, a);
|
|
1863
1875
|
}
|
|
1864
1876
|
});
|
|
1865
1877
|
}
|
|
@@ -1892,24 +1904,13 @@ let context = null;
|
|
|
1892
1904
|
|
|
1893
1905
|
let currentOptimisticLane = null;
|
|
1894
1906
|
|
|
1895
|
-
/**
|
|
1896
|
-
* Marked sources read by the recompute currently on the stack (saved/restored
|
|
1897
|
-
* per recompute, like `context`). A computed that reads a node with a live
|
|
1898
|
-
* `affects()` mark inherits the mark's pendingness — `recompute` applies the
|
|
1899
|
-
* collected sources through `applyAffectsReads` after its commit, because the
|
|
1900
|
-
* `clearStatus` at the top of the commit path wipes whatever sentinel entries
|
|
1901
|
-
* the node held from the registration-time push. This is the pull half of
|
|
1902
|
-
* mark propagation (real async re-establishes itself by re-throwing on read;
|
|
1903
|
-
* marks are value-transparent, so they re-establish here instead).
|
|
1904
|
-
*/ let affectsReads = null;
|
|
1905
|
-
|
|
1906
1907
|
let snapshotCaptureActive = false;
|
|
1907
1908
|
|
|
1908
1909
|
let snapshotSources = null;
|
|
1909
1910
|
|
|
1910
1911
|
function ownerInSnapshotScope(e) {
|
|
1911
1912
|
while (e) {
|
|
1912
|
-
if (e.
|
|
1913
|
+
if (e.Ct) return true;
|
|
1913
1914
|
e = e.Z;
|
|
1914
1915
|
}
|
|
1915
1916
|
return false;
|
|
@@ -1921,41 +1922,41 @@ function setSnapshotCapture(e) {
|
|
|
1921
1922
|
}
|
|
1922
1923
|
|
|
1923
1924
|
function markSnapshotScope(e) {
|
|
1924
|
-
e.
|
|
1925
|
+
e.Ct = true;
|
|
1925
1926
|
}
|
|
1926
1927
|
|
|
1927
1928
|
function releaseSnapshotScope(e) {
|
|
1928
|
-
e.
|
|
1929
|
+
e.Ct = false;
|
|
1929
1930
|
releaseSubtree(e);
|
|
1930
1931
|
schedule();
|
|
1931
1932
|
}
|
|
1932
1933
|
|
|
1933
1934
|
function releaseSubtree(e) {
|
|
1934
|
-
let t = e.
|
|
1935
|
+
let t = e.ot;
|
|
1935
1936
|
while (t) {
|
|
1936
|
-
if (t.
|
|
1937
|
-
t = t.
|
|
1937
|
+
if (t.Ct) {
|
|
1938
|
+
t = t.st;
|
|
1938
1939
|
continue;
|
|
1939
1940
|
}
|
|
1940
|
-
if (t.
|
|
1941
|
+
if (t.Ve) {
|
|
1941
1942
|
const e = t;
|
|
1942
|
-
e.
|
|
1943
|
-
if (e.
|
|
1944
|
-
e.
|
|
1945
|
-
e.
|
|
1946
|
-
if (dirtyQueue.
|
|
1943
|
+
e.ke &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1944
|
+
if (e.Le & REACTIVE_SNAPSHOT_STALE) {
|
|
1945
|
+
e.Le &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1946
|
+
e.Le |= REACTIVE_DIRTY;
|
|
1947
|
+
if (dirtyQueue.C > e.ze) dirtyQueue.C = e.ze;
|
|
1947
1948
|
insertIntoHeap(e, dirtyQueue);
|
|
1948
1949
|
}
|
|
1949
1950
|
}
|
|
1950
1951
|
releaseSubtree(t);
|
|
1951
|
-
t = t.
|
|
1952
|
+
t = t.st;
|
|
1952
1953
|
}
|
|
1953
1954
|
}
|
|
1954
1955
|
|
|
1955
1956
|
function clearSnapshots() {
|
|
1956
1957
|
if (snapshotSources) {
|
|
1957
1958
|
for (const e of snapshotSources) {
|
|
1958
|
-
delete e.
|
|
1959
|
+
delete e.we;
|
|
1959
1960
|
delete e[STORE_SNAPSHOT_PROPS];
|
|
1960
1961
|
}
|
|
1961
1962
|
snapshotSources = null;
|
|
@@ -1964,105 +1965,109 @@ function clearSnapshots() {
|
|
|
1964
1965
|
}
|
|
1965
1966
|
|
|
1966
1967
|
function recompute(e, t = false) {
|
|
1967
|
-
const n = e.
|
|
1968
|
+
const n = e.Qe;
|
|
1968
1969
|
if (!t) {
|
|
1969
1970
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
1970
1971
|
deleteFromHeap(e, queueFor(e));
|
|
1971
|
-
e.
|
|
1972
|
+
e.lt = null;
|
|
1972
1973
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
1973
|
-
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.
|
|
1974
|
+
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ot !== null || e.St !== null) {
|
|
1974
1975
|
markDisposal(e);
|
|
1975
|
-
e.
|
|
1976
|
-
e.
|
|
1977
|
-
e.
|
|
1978
|
-
e.
|
|
1979
|
-
e.
|
|
1976
|
+
e.He = e.St;
|
|
1977
|
+
e.Me = e.ot;
|
|
1978
|
+
e.St = null;
|
|
1979
|
+
e.ot = null;
|
|
1980
|
+
e.ct = 0;
|
|
1980
1981
|
} else ;
|
|
1981
1982
|
}
|
|
1982
|
-
let r = !!(e.
|
|
1983
|
+
let r = !!(e.Le & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1983
1984
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1984
|
-
const o = !!(e
|
|
1985
|
+
const o = !!(e.We & STATUS_UNINITIALIZED);
|
|
1985
1986
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1986
1987
|
// the recompute wipes _flags below.
|
|
1987
|
-
const s = (e.
|
|
1988
|
+
const s = (e.Le & REACTIVE_REASK) !== 0;
|
|
1988
1989
|
const u = context;
|
|
1989
1990
|
context = e;
|
|
1990
|
-
e.
|
|
1991
|
-
e.
|
|
1992
|
-
e.
|
|
1991
|
+
e.ut = null;
|
|
1992
|
+
e.It++;
|
|
1993
|
+
e.Le = REACTIVE_RECOMPUTING_DEPS;
|
|
1993
1994
|
e.M = clock;
|
|
1994
|
-
let l = e.V === NOT_PENDING ? e.
|
|
1995
|
-
let c = e.
|
|
1995
|
+
let l = e.V === NOT_PENDING ? e.xe : e.V;
|
|
1996
|
+
let c = e.ze;
|
|
1996
1997
|
let a = tracking;
|
|
1997
|
-
|
|
1998
|
-
affectsReads = null;
|
|
1999
|
-
let E = null;
|
|
2000
|
-
let d = currentOptimisticLane;
|
|
1998
|
+
let f = currentOptimisticLane;
|
|
2001
1999
|
tracking = true;
|
|
2000
|
+
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
2001
|
+
// inside a latest() read window: read() short-circuits through the
|
|
2002
|
+
// companion path before dependency linking, so a memo created (eagerly
|
|
2003
|
+
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
2004
|
+
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
2005
|
+
// covers creation-time computes and flushes that run inside the window.
|
|
2006
|
+
const E = latestReadActive;
|
|
2007
|
+
latestReadActive = false;
|
|
2002
2008
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
2003
2009
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2004
2010
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2005
2011
|
if (r) {
|
|
2006
|
-
const t = GlobalQueue.
|
|
2012
|
+
const t = GlobalQueue.Pe(e, true);
|
|
2007
2013
|
if (t) currentOptimisticLane = t;
|
|
2008
2014
|
} else if (activeTransition && !t && activeTransition.G.length) {
|
|
2009
2015
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2010
2016
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2011
2017
|
// recomputes under the right posture and propagates correctly.
|
|
2012
|
-
const t = GlobalQueue.
|
|
2018
|
+
const t = GlobalQueue.Pe(e, false);
|
|
2013
2019
|
if (t) {
|
|
2014
2020
|
r = true;
|
|
2015
2021
|
currentOptimisticLane = t;
|
|
2016
2022
|
}
|
|
2017
2023
|
}
|
|
2018
2024
|
const S = n && n !== EFFECT_USER;
|
|
2019
|
-
const
|
|
2025
|
+
const d = stale;
|
|
2020
2026
|
if (S) stale = true;
|
|
2021
2027
|
try {
|
|
2022
|
-
if (!false && e.
|
|
2023
|
-
l = e.
|
|
2024
|
-
e.
|
|
2028
|
+
if (!false && e.ke & CONFIG_SYNC) {
|
|
2029
|
+
l = e.Ve(l);
|
|
2030
|
+
e.lt = null;
|
|
2025
2031
|
} else {
|
|
2026
2032
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2027
2033
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2028
2034
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2029
2035
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2030
2036
|
// iteration drive updates.
|
|
2031
|
-
const t = e.
|
|
2032
|
-
const n = e.
|
|
2037
|
+
const t = e.lt;
|
|
2038
|
+
const n = e.Ve(l);
|
|
2033
2039
|
const r = typeof n === "object" && n !== null;
|
|
2034
|
-
const i = e.
|
|
2040
|
+
const i = e.lt !== t;
|
|
2035
2041
|
l = i || !r ? n : handleAsync(e, n);
|
|
2036
|
-
if (!i && !r) e.
|
|
2042
|
+
if (!i && !r) e.lt = null;
|
|
2037
2043
|
}
|
|
2038
2044
|
clearStatus(e, t);
|
|
2039
2045
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2040
|
-
if (e.i) GlobalQueue.
|
|
2046
|
+
if (e.i) GlobalQueue.be(e);
|
|
2041
2047
|
} catch (t) {
|
|
2042
2048
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2043
2049
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2044
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2050
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.ge(e);
|
|
2045
2051
|
let n = false;
|
|
2046
2052
|
if (t instanceof NotReadyError) {
|
|
2047
|
-
e.
|
|
2048
|
-
if (GlobalQueue.
|
|
2053
|
+
e.At = true;
|
|
2054
|
+
if (GlobalQueue.Te !== null) n = GlobalQueue.Te(e, s);
|
|
2049
2055
|
}
|
|
2050
2056
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2051
|
-
if (n) GlobalQueue.
|
|
2057
|
+
if (n) GlobalQueue._e(e);
|
|
2052
2058
|
} finally {
|
|
2053
2059
|
tracking = a;
|
|
2054
|
-
|
|
2055
|
-
|
|
2060
|
+
latestReadActive = E;
|
|
2061
|
+
if (S) stale = d;
|
|
2062
|
+
e.Le = REACTIVE_NONE | (t ? e.Le & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2056
2063
|
context = u;
|
|
2057
|
-
E = affectsReads;
|
|
2058
|
-
affectsReads = f;
|
|
2059
2064
|
}
|
|
2060
|
-
if (!e.
|
|
2065
|
+
if (!e.me) {
|
|
2061
2066
|
trimStaleDeps(e);
|
|
2062
|
-
const s = i ? unwrapOverride(e.A) : e.V === NOT_PENDING ? e.
|
|
2067
|
+
const s = i ? unwrapOverride(e.A) : e.V === NOT_PENDING ? e.xe : e.V;
|
|
2063
2068
|
let u = false;
|
|
2064
2069
|
try {
|
|
2065
|
-
u = !n && o || !e.
|
|
2070
|
+
u = !n && o || !e.ht || !e.ht(s, l);
|
|
2066
2071
|
} catch (t) {
|
|
2067
2072
|
// A throwing user comparator is an error of this node's computation.
|
|
2068
2073
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2076,15 +2081,15 @@ function recompute(e, t = false) {
|
|
|
2076
2081
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2077
2082
|
// effect() can call its runner synchronously for the first run.
|
|
2078
2083
|
if (n && u) {
|
|
2079
|
-
e.
|
|
2084
|
+
e.Fe = !e.me;
|
|
2080
2085
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2081
2086
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2082
|
-
if (!t) e.
|
|
2087
|
+
if (!t) e.Ze.enqueue(n, e.Pt ??= GlobalQueue.ee.bind(null, e));
|
|
2083
2088
|
}
|
|
2084
|
-
if (e.
|
|
2089
|
+
if (e.me) ; else if (u) {
|
|
2085
2090
|
const o = i ? e.A : undefined;
|
|
2086
2091
|
if (t || n && activeTransition !== e.T || r) {
|
|
2087
|
-
e.
|
|
2092
|
+
e.xe = l;
|
|
2088
2093
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2089
2094
|
// override unconditionally. The direct _value commit is the lane's
|
|
2090
2095
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
@@ -2100,7 +2105,7 @@ function recompute(e, t = false) {
|
|
|
2100
2105
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2101
2106
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2102
2107
|
// pending value commits before effects run.
|
|
2103
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2108
|
+
if ((activeTransition || e.T) && GlobalQueue.le !== null) GlobalQueue.le(e, l);
|
|
2104
2109
|
}
|
|
2105
2110
|
if (!i || r || e.A !== o) insertSubs(e, r || i);
|
|
2106
2111
|
} else if (i) {
|
|
@@ -2109,90 +2114,77 @@ function recompute(e, t = false) {
|
|
|
2109
2114
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2110
2115
|
if (e.V === NOT_PENDING) queuePendingNode(e);
|
|
2111
2116
|
e.V = l;
|
|
2112
|
-
} else if (e.
|
|
2113
|
-
for (let t = e.k; t !== null; t = t.
|
|
2114
|
-
insertIntoHeapHeight(t.
|
|
2117
|
+
} else if (e.ze != c) {
|
|
2118
|
+
for (let t = e.k; t !== null; t = t.Ge) {
|
|
2119
|
+
insertIntoHeapHeight(t.Ue, queueFor(t.Ue));
|
|
2115
2120
|
}
|
|
2116
2121
|
}
|
|
2117
2122
|
}
|
|
2118
|
-
currentOptimisticLane =
|
|
2119
|
-
|
|
2120
|
-
// earlier, the sentinel's NotReadyError in `_error` would have routed the
|
|
2121
|
-
// fresh value into the error-skip branch instead of committing it. A real
|
|
2122
|
-
// (non-NotReady) error wins over marks (#2893): applying the sentinel here
|
|
2123
|
-
// would clobber the user's error with a NotReadyError from a node whose
|
|
2124
|
-
// reads value-transparency promises can never throw NotReady.
|
|
2125
|
-
// `markedReads` only collects under a live mark, so the hook is installed.
|
|
2126
|
-
if (E && !(e.$e & STATUS_ERROR)) GlobalQueue.re(e, E);
|
|
2127
|
-
// Mark-only pending doesn't queue (#2893): the node holds no value needing
|
|
2128
|
-
// a transition-scheduled commit, and queueing would stamp the marking
|
|
2129
|
-
// action's transaction onto it — freezing unrelated writes that share it.
|
|
2130
|
-
// (Single mask test up front keeps the mark-free hot path at original cost.)
|
|
2131
|
-
const p = e.$e & (STATUS_PENDING | STATUS_UNINITIALIZED);
|
|
2132
|
-
const _ = e.V !== NOT_PENDING || e.Ke !== null || e.Ye !== null || p !== 0 && (p !== STATUS_PENDING || activeAffectsMarks === 0 || !GlobalQueue.ue(e));
|
|
2123
|
+
currentOptimisticLane = f;
|
|
2124
|
+
const T = e.V !== NOT_PENDING || e.Me !== null || e.He !== null || (e.We & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2133
2125
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2134
2126
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2135
2127
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2136
2128
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2137
2129
|
// _transition.
|
|
2138
|
-
|
|
2130
|
+
T && (!t || e.We & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2139
2131
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2140
2132
|
}
|
|
2141
2133
|
|
|
2142
2134
|
function updateIfNecessary(e) {
|
|
2143
|
-
if (e.
|
|
2144
|
-
for (let t = e.
|
|
2145
|
-
const n = t.
|
|
2146
|
-
const r = n.
|
|
2147
|
-
if (r.
|
|
2135
|
+
if (e.Le & REACTIVE_CHECK) {
|
|
2136
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
2137
|
+
const n = t.qe;
|
|
2138
|
+
const r = n.Be || n;
|
|
2139
|
+
if (r.Ve) {
|
|
2148
2140
|
updateIfNecessary(r);
|
|
2149
2141
|
}
|
|
2150
|
-
if (e.
|
|
2142
|
+
if (e.Le & REACTIVE_DIRTY) {
|
|
2151
2143
|
break;
|
|
2152
2144
|
}
|
|
2153
2145
|
}
|
|
2154
2146
|
}
|
|
2155
|
-
if (e.
|
|
2147
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.me && e.M < clock && !e.lt) {
|
|
2156
2148
|
recompute(e);
|
|
2157
2149
|
}
|
|
2158
|
-
e.
|
|
2150
|
+
e.Le = e.Le & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2159
2151
|
}
|
|
2160
2152
|
|
|
2161
2153
|
function computed(e, t) {
|
|
2162
2154
|
const n = t?.transparent ?? false;
|
|
2163
2155
|
const r = {
|
|
2164
2156
|
id: inheritId(t, n, context),
|
|
2165
|
-
|
|
2166
|
-
|
|
2157
|
+
ke: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2158
|
+
ht: t?.equals != null ? t.equals : isEqual,
|
|
2167
2159
|
W: t?.unobserved,
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2160
|
+
St: null,
|
|
2161
|
+
Ze: context?.Ze ?? globalQueue,
|
|
2162
|
+
dt: context?.dt ?? defaultContext,
|
|
2163
|
+
ct: 0,
|
|
2164
|
+
Ve: e,
|
|
2165
|
+
xe: undefined,
|
|
2166
|
+
ze: 0,
|
|
2167
|
+
rt: null,
|
|
2168
|
+
nt: undefined,
|
|
2169
|
+
tt: null,
|
|
2170
|
+
Ke: null,
|
|
2175
2171
|
ut: null,
|
|
2176
|
-
|
|
2177
|
-
ot: null,
|
|
2178
|
-
Ze: null,
|
|
2179
|
-
Et: null,
|
|
2180
|
-
yt: 0,
|
|
2172
|
+
It: 0,
|
|
2181
2173
|
k: null,
|
|
2182
|
-
|
|
2174
|
+
_t: null,
|
|
2183
2175
|
Z: context,
|
|
2176
|
+
st: null,
|
|
2184
2177
|
ft: null,
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
$e: STATUS_UNINITIALIZED,
|
|
2178
|
+
ot: null,
|
|
2179
|
+
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2180
|
+
We: STATUS_UNINITIALIZED,
|
|
2189
2181
|
M: clock,
|
|
2190
2182
|
V: NOT_PENDING,
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2183
|
+
He: null,
|
|
2184
|
+
Me: null,
|
|
2185
|
+
lt: null,
|
|
2194
2186
|
T: null,
|
|
2195
|
-
|
|
2187
|
+
Nt: false
|
|
2196
2188
|
};
|
|
2197
2189
|
setupComputedNode(r, t);
|
|
2198
2190
|
return r;
|
|
@@ -2207,44 +2199,44 @@ function computed(e, t) {
|
|
|
2207
2199
|
const s = o?.transparent ?? false;
|
|
2208
2200
|
const u = {
|
|
2209
2201
|
id: inheritId(o, s, context),
|
|
2210
|
-
|
|
2211
|
-
|
|
2202
|
+
ke: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2203
|
+
ht: false,
|
|
2212
2204
|
W: o?.unobserved,
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2205
|
+
St: null,
|
|
2206
|
+
Ze: context?.Ze ?? globalQueue,
|
|
2207
|
+
dt: context?.dt ?? defaultContext,
|
|
2208
|
+
ct: 0,
|
|
2209
|
+
Ve: e,
|
|
2210
|
+
xe: undefined,
|
|
2211
|
+
ze: 0,
|
|
2212
|
+
rt: null,
|
|
2213
|
+
nt: undefined,
|
|
2214
|
+
tt: null,
|
|
2215
|
+
Ke: null,
|
|
2220
2216
|
ut: null,
|
|
2221
|
-
|
|
2222
|
-
ot: null,
|
|
2223
|
-
Ze: null,
|
|
2224
|
-
Et: null,
|
|
2225
|
-
yt: 0,
|
|
2217
|
+
It: 0,
|
|
2226
2218
|
k: null,
|
|
2227
|
-
|
|
2219
|
+
_t: null,
|
|
2228
2220
|
Z: context,
|
|
2221
|
+
st: null,
|
|
2229
2222
|
ft: null,
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
$e: STATUS_UNINITIALIZED,
|
|
2223
|
+
ot: null,
|
|
2224
|
+
Le: REACTIVE_LAZY,
|
|
2225
|
+
We: STATUS_UNINITIALIZED,
|
|
2234
2226
|
M: clock,
|
|
2235
2227
|
V: NOT_PENDING,
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2228
|
+
He: null,
|
|
2229
|
+
Me: null,
|
|
2230
|
+
lt: null,
|
|
2239
2231
|
T: null,
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2232
|
+
Nt: false,
|
|
2233
|
+
Fe: false,
|
|
2234
|
+
bt: undefined,
|
|
2235
|
+
Dt: t,
|
|
2236
|
+
vt: n,
|
|
2237
|
+
Et: undefined,
|
|
2238
|
+
Qe: r,
|
|
2239
|
+
yt: i
|
|
2248
2240
|
};
|
|
2249
2241
|
setupComputedNode(u, lazyOptions);
|
|
2250
2242
|
return u;
|
|
@@ -2255,24 +2247,24 @@ const lazyOptions = {
|
|
|
2255
2247
|
};
|
|
2256
2248
|
|
|
2257
2249
|
function setupComputedNode(e, t) {
|
|
2258
|
-
e.
|
|
2259
|
-
const n = context?.
|
|
2250
|
+
e.tt = e;
|
|
2251
|
+
const n = context?.Je ? context.et : context;
|
|
2260
2252
|
if (context) {
|
|
2261
|
-
const t = context.
|
|
2253
|
+
const t = context.ot;
|
|
2262
2254
|
if (t === null) {
|
|
2263
|
-
context.
|
|
2255
|
+
context.ot = e;
|
|
2264
2256
|
} else {
|
|
2265
|
-
e.
|
|
2266
|
-
t.
|
|
2267
|
-
context.
|
|
2257
|
+
e.st = t;
|
|
2258
|
+
t.ft = e;
|
|
2259
|
+
context.ot = e;
|
|
2268
2260
|
}
|
|
2269
2261
|
}
|
|
2270
|
-
if (n) e.
|
|
2271
|
-
if (GlobalQueue.
|
|
2262
|
+
if (n) e.ze = n.ze + 1;
|
|
2263
|
+
if (GlobalQueue.se !== null) GlobalQueue.se(e);
|
|
2272
2264
|
!t?.lazy && recompute(e, true);
|
|
2273
2265
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2274
|
-
if (!(e
|
|
2275
|
-
e.
|
|
2266
|
+
if (!(e.We & STATUS_PENDING) && !(e.ke & CONFIG_NO_SNAPSHOT)) {
|
|
2267
|
+
e.we = e.xe === undefined ? NO_SNAPSHOT : e.xe;
|
|
2276
2268
|
snapshotSources.add(e);
|
|
2277
2269
|
}
|
|
2278
2270
|
}
|
|
@@ -2280,20 +2272,20 @@ function setupComputedNode(e, t) {
|
|
|
2280
2272
|
|
|
2281
2273
|
function signal(e, t, n = null) {
|
|
2282
2274
|
const r = {
|
|
2283
|
-
|
|
2284
|
-
|
|
2275
|
+
ht: t?.equals != null ? t.equals : isEqual,
|
|
2276
|
+
ke: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2285
2277
|
W: t?.unobserved,
|
|
2286
|
-
|
|
2278
|
+
xe: e,
|
|
2287
2279
|
k: null,
|
|
2288
|
-
|
|
2280
|
+
_t: null,
|
|
2289
2281
|
M: clock,
|
|
2290
|
-
|
|
2291
|
-
|
|
2282
|
+
Be: n,
|
|
2283
|
+
it: n?.rt || null,
|
|
2292
2284
|
V: NOT_PENDING
|
|
2293
2285
|
};
|
|
2294
|
-
n && (n.
|
|
2295
|
-
if (snapshotCaptureActive && !(r.
|
|
2296
|
-
r.
|
|
2286
|
+
n && (n.rt = r);
|
|
2287
|
+
if (snapshotCaptureActive && !(r.ke & CONFIG_NO_SNAPSHOT) && !((n?.We ?? 0) & STATUS_PENDING)) {
|
|
2288
|
+
r.we = e === undefined ? NO_SNAPSHOT : e;
|
|
2297
2289
|
snapshotSources.add(r);
|
|
2298
2290
|
}
|
|
2299
2291
|
return r;
|
|
@@ -2337,11 +2329,11 @@ function isEqual(e, t) {
|
|
|
2337
2329
|
* );
|
|
2338
2330
|
* ```
|
|
2339
2331
|
*/ function untrack(e, t) {
|
|
2340
|
-
if (GlobalQueue.
|
|
2332
|
+
if (GlobalQueue.ue === null && !tracking && true) return e();
|
|
2341
2333
|
const n = tracking;
|
|
2342
2334
|
tracking = false;
|
|
2343
2335
|
try {
|
|
2344
|
-
if (GlobalQueue.
|
|
2336
|
+
if (GlobalQueue.ue !== null) return GlobalQueue.ue(e);
|
|
2345
2337
|
return e();
|
|
2346
2338
|
} finally {
|
|
2347
2339
|
tracking = n;
|
|
@@ -2353,10 +2345,10 @@ function isEqual(e, t) {
|
|
|
2353
2345
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2354
2346
|
* date so its status flags reflect the current graph.
|
|
2355
2347
|
*/ function prepareComputed(e, t) {
|
|
2356
|
-
if (e.
|
|
2357
|
-
e.
|
|
2348
|
+
if (e.Le & REACTIVE_LAZY) {
|
|
2349
|
+
e.Le &= ~REACTIVE_LAZY;
|
|
2358
2350
|
recompute(e, true);
|
|
2359
|
-
} else if (e.
|
|
2351
|
+
} else if (e.Le & REACTIVE_DISPOSED) {
|
|
2360
2352
|
recompute(e, true);
|
|
2361
2353
|
} else if (t) {
|
|
2362
2354
|
updateIfNecessary(e);
|
|
@@ -2368,78 +2360,57 @@ function read(e) {
|
|
|
2368
2360
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2369
2361
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2370
2362
|
// than the original node (which stays "pending" while held in a transition).
|
|
2371
|
-
if (latestReadActive) return GlobalQueue.
|
|
2363
|
+
if (latestReadActive) return GlobalQueue.Ee(e);
|
|
2372
2364
|
let t = context;
|
|
2373
|
-
if (t?.
|
|
2365
|
+
if (t?.Je) t = t.et;
|
|
2374
2366
|
const n = e;
|
|
2375
|
-
const r = e.
|
|
2367
|
+
const r = e.Be;
|
|
2376
2368
|
const i = r || e;
|
|
2377
2369
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2378
2370
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2379
2371
|
// recompute don't collect into the probe.
|
|
2380
2372
|
if (pendingCheckActive) {
|
|
2381
|
-
GlobalQueue.
|
|
2382
|
-
} else if (typeof n.
|
|
2373
|
+
GlobalQueue.Se(e, t, i, r);
|
|
2374
|
+
} else if (typeof n.Ve === "function") {
|
|
2383
2375
|
prepareComputed(e, false);
|
|
2384
2376
|
}
|
|
2385
|
-
if (!n.
|
|
2386
|
-
if (t && tracking)
|
|
2387
|
-
|
|
2388
|
-
// A live mark on a read source flows to the reader (probe reads are
|
|
2389
|
-
// excluded: the probe's own collection owns that verdict, and marking
|
|
2390
|
-
// the enclosing memo would make an `isPending` wrapper itself pending).
|
|
2391
|
-
if (activeAffectsMarks !== 0 && e.F && !pendingCheckActive) (affectsReads ??= []).push(e);
|
|
2392
|
-
}
|
|
2393
|
-
return !t || e.V === NOT_PENDING ? e.Me : e.V;
|
|
2377
|
+
if (!n.Ve && i === e && e.A === undefined && e.we === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2378
|
+
if (t && tracking) link(e, t);
|
|
2379
|
+
return !t || e.V === NOT_PENDING ? e.xe : e.V;
|
|
2394
2380
|
}
|
|
2395
2381
|
if (t && tracking) {
|
|
2396
2382
|
link(e, t, pendingCheckActive);
|
|
2397
|
-
|
|
2398
|
-
// transitive half (#2893): a mark-pended owner's sentinel sources flow to
|
|
2399
|
-
// the reader like a direct mark — value-transparent reads have no throw
|
|
2400
|
-
// to re-establish through, so without this a mid-window recompute sheds
|
|
2401
|
-
// pendingness permanently past one derivation level.
|
|
2402
|
-
if (activeAffectsMarks !== 0 && !pendingCheckActive) {
|
|
2403
|
-
if (e.F) (affectsReads ??= []).push(e);
|
|
2404
|
-
if (i.$e & STATUS_PENDING) GlobalQueue.le(i, affectsReads ??= []);
|
|
2405
|
-
}
|
|
2406
|
-
if (i.We) {
|
|
2383
|
+
if (i.Ve) {
|
|
2407
2384
|
const n = queueFor(e);
|
|
2408
|
-
if (i.
|
|
2385
|
+
if (i.ze >= n.C) {
|
|
2409
2386
|
markNode(t);
|
|
2410
2387
|
markHeap(n);
|
|
2411
2388
|
updateIfNecessary(i);
|
|
2412
2389
|
}
|
|
2413
|
-
const r = i.
|
|
2390
|
+
const r = i.ze;
|
|
2414
2391
|
// parent check is shallow, might need to be recursive
|
|
2415
|
-
if (r >= t.
|
|
2416
|
-
t.
|
|
2392
|
+
if (r >= t.ze && e.Z !== t) {
|
|
2393
|
+
t.ze = r + 1;
|
|
2417
2394
|
}
|
|
2418
2395
|
}
|
|
2419
2396
|
}
|
|
2420
|
-
|
|
2421
|
-
// a promise of change, not an absence of value, so a derived node whose only
|
|
2422
|
-
// pending sources are mark sentinels keeps its real value readable —
|
|
2423
|
-
// pendingness reaches readers through verdicts (isPending), not throws.
|
|
2424
|
-
// (`activeAffectsMarks` gates the source scan off the mark-free hot path;
|
|
2425
|
-
// sentinels can't survive in pending sources past their last release.)
|
|
2426
|
-
if (i.$e & STATUS_PENDING && !(activeAffectsMarks !== 0 && GlobalQueue.ue(i))) {
|
|
2397
|
+
if (i.We & STATUS_PENDING) {
|
|
2427
2398
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2428
2399
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2429
2400
|
// is installed): under a lane, only same-lane pending async without an
|
|
2430
2401
|
// active override throws.
|
|
2431
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2402
|
+
if (currentOptimisticLane === null || GlobalQueue.ye(i)) {
|
|
2432
2403
|
if (!tracking && e !== t) link(e, t);
|
|
2433
|
-
throw i.
|
|
2404
|
+
throw i.me;
|
|
2434
2405
|
}
|
|
2435
|
-
} else if (t && i !== e && i
|
|
2406
|
+
} else if (t && i !== e && i.We & STATUS_UNINITIALIZED) {
|
|
2436
2407
|
if (!tracking && e !== t) link(e, t);
|
|
2437
|
-
throw i.
|
|
2438
|
-
} else if (!t && i
|
|
2439
|
-
throw i.
|
|
2408
|
+
throw i.me;
|
|
2409
|
+
} else if (!t && i.We & STATUS_UNINITIALIZED) {
|
|
2410
|
+
throw i.me;
|
|
2440
2411
|
}
|
|
2441
2412
|
}
|
|
2442
|
-
if (e.
|
|
2413
|
+
if (e.Ve && e.We & STATUS_ERROR) {
|
|
2443
2414
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2444
2415
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2445
2416
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
@@ -2447,21 +2418,19 @@ function read(e) {
|
|
|
2447
2418
|
if (tracking && !pendingCheckActive && e.M < clock) {
|
|
2448
2419
|
recompute(e);
|
|
2449
2420
|
return read(e);
|
|
2450
|
-
} else throw e.
|
|
2421
|
+
} else throw e.me;
|
|
2451
2422
|
}
|
|
2452
|
-
if (snapshotCaptureActive && t && t.
|
|
2453
|
-
const n = e.
|
|
2423
|
+
if (snapshotCaptureActive && t && t.ke & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2424
|
+
const n = e.we;
|
|
2454
2425
|
if (n !== undefined) {
|
|
2455
2426
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2456
|
-
const i = e.V !== NOT_PENDING ? e.V : e.
|
|
2457
|
-
if (i !== r) t.
|
|
2427
|
+
const i = e.V !== NOT_PENDING ? e.V : e.xe;
|
|
2428
|
+
if (i !== r) t.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
2458
2429
|
return r;
|
|
2459
2430
|
}
|
|
2460
2431
|
}
|
|
2461
2432
|
if (e.A !== undefined && e.A !== NOT_PENDING) {
|
|
2462
|
-
//
|
|
2463
|
-
// the value for every reader — that check itself stays right here).
|
|
2464
|
-
if (t && stale && GlobalQueue.ge(e)) return e.Me;
|
|
2433
|
+
// A17: the override IS the value for every reader.
|
|
2465
2434
|
return unwrapOverride(e.A);
|
|
2466
2435
|
}
|
|
2467
2436
|
// Entanglement gate: a reader recomputing under an optimistic lane that reads
|
|
@@ -2471,18 +2440,18 @@ function read(e) {
|
|
|
2471
2440
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2472
2441
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2473
2442
|
// engine — a non-null lane implies it is installed.)
|
|
2474
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2475
|
-
return e.
|
|
2443
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ne(e, i, t)) {
|
|
2444
|
+
return e.xe;
|
|
2476
2445
|
}
|
|
2477
2446
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2478
2447
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2479
2448
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2480
2449
|
// (The lane-context clause lives with the engine.)
|
|
2481
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2450
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.Ce(e, i, t) || e.V === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.xe : e.V;
|
|
2482
2451
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2483
2452
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2484
|
-
if (pendingCheckActive) GlobalQueue.
|
|
2485
|
-
if (!t && i === e && typeof n.
|
|
2453
|
+
if (pendingCheckActive) GlobalQueue.de(e, o);
|
|
2454
|
+
if (!t && i === e && typeof n.Ve === "function" && e.ke & CONFIG_AUTO_DISPOSE && !(i.We & STATUS_PENDING) && !e.k) {
|
|
2486
2455
|
unobserved(e);
|
|
2487
2456
|
}
|
|
2488
2457
|
return o;
|
|
@@ -2494,16 +2463,16 @@ function setSignal(e, t) {
|
|
|
2494
2463
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2495
2464
|
// _overrideValue slot, and every module that creates one installs the
|
|
2496
2465
|
// engine first.
|
|
2497
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2498
|
-
const n = e.V === NOT_PENDING ? e.
|
|
2466
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.Oe(e, t);
|
|
2467
|
+
const n = e.V === NOT_PENDING ? e.xe : e.V;
|
|
2499
2468
|
if (typeof t === "function") t = t(n);
|
|
2500
2469
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2501
2470
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2502
|
-
const r = !!(e
|
|
2471
|
+
const r = !!(e.We & STATUS_UNINITIALIZED) || !e.ht || !e.ht(n, t);
|
|
2503
2472
|
if (!r) return t;
|
|
2504
2473
|
if (e.V === NOT_PENDING) queuePendingNode(e);
|
|
2505
2474
|
e.V = t;
|
|
2506
|
-
GlobalQueue.
|
|
2475
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2507
2476
|
e.M = clock;
|
|
2508
2477
|
insertSubs(e);
|
|
2509
2478
|
schedule();
|
|
@@ -2518,11 +2487,11 @@ function setSignal(e, t) {
|
|
|
2518
2487
|
* cleanup point.
|
|
2519
2488
|
*/ function suppressComputedRecompute(e) {
|
|
2520
2489
|
deleteFromHeap(e, queueFor(e));
|
|
2521
|
-
if (!(e.
|
|
2490
|
+
if (!(e.Le & REACTIVE_MANUAL_WRITE) && e.V === NOT_PENDING) {
|
|
2522
2491
|
queuePendingNode(e);
|
|
2523
2492
|
schedule();
|
|
2524
2493
|
}
|
|
2525
|
-
e.
|
|
2494
|
+
e.Le = e.Le & -4 | REACTIVE_MANUAL_WRITE;
|
|
2526
2495
|
}
|
|
2527
2496
|
|
|
2528
2497
|
/**
|
|
@@ -2601,7 +2570,7 @@ function staleValues(e, t = true) {
|
|
|
2601
2570
|
if (!t) {
|
|
2602
2571
|
return;
|
|
2603
2572
|
}
|
|
2604
|
-
if (typeof t.
|
|
2573
|
+
if (typeof t.Ve === "function" && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2605
2574
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2606
2575
|
// same question: mark it so the recompute classifies any resulting
|
|
2607
2576
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2609,11 +2578,11 @@ function staleValues(e, t = true) {
|
|
|
2609
2578
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2610
2579
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2611
2580
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2612
|
-
if (!(t.
|
|
2613
|
-
t.
|
|
2581
|
+
if (!(t.Le & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2582
|
+
t.Le |= REACTIVE_REASK;
|
|
2614
2583
|
armReaskClear();
|
|
2615
2584
|
}
|
|
2616
|
-
t.
|
|
2585
|
+
t.Le = t.Le & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2617
2586
|
insertIntoHeap(t, queueFor(t));
|
|
2618
2587
|
schedule();
|
|
2619
2588
|
}
|
|
@@ -2661,11 +2630,11 @@ function wireExternalSource(e) {
|
|
|
2661
2630
|
equals: false,
|
|
2662
2631
|
ownedWrite: true
|
|
2663
2632
|
});
|
|
2664
|
-
const n = externalSourceConfig.factory(e.
|
|
2633
|
+
const n = externalSourceConfig.factory(e.Ve, () => {
|
|
2665
2634
|
setSignal(t, undefined);
|
|
2666
2635
|
});
|
|
2667
2636
|
cleanup(() => n.dispose());
|
|
2668
|
-
e.
|
|
2637
|
+
e.Ve = e => {
|
|
2669
2638
|
read(t);
|
|
2670
2639
|
return n.track(e);
|
|
2671
2640
|
};
|
|
@@ -2679,8 +2648,8 @@ function externalUntrack(e) {
|
|
|
2679
2648
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2680
2649
|
// `externalSourceConfig` truthiness checks.
|
|
2681
2650
|
function syncExternalHooks() {
|
|
2682
|
-
GlobalQueue.
|
|
2683
|
-
GlobalQueue.
|
|
2651
|
+
GlobalQueue.se = externalSourceConfig ? wireExternalSource : null;
|
|
2652
|
+
GlobalQueue.ue = externalSourceConfig ? externalUntrack : null;
|
|
2684
2653
|
}
|
|
2685
2654
|
|
|
2686
2655
|
function enableExternalSource(e) {
|
|
@@ -2737,7 +2706,7 @@ function enableExternalSource(e) {
|
|
|
2737
2706
|
if (!t) {
|
|
2738
2707
|
throw new NoOwnerError;
|
|
2739
2708
|
}
|
|
2740
|
-
const n = hasContext(e, t) ? t.
|
|
2709
|
+
const n = hasContext(e, t) ? t.dt[e.id] : e.defaultValue;
|
|
2741
2710
|
if (isUndefined(n)) {
|
|
2742
2711
|
throw new ContextNotFoundError;
|
|
2743
2712
|
}
|
|
@@ -2758,14 +2727,14 @@ function enableExternalSource(e) {
|
|
|
2758
2727
|
}
|
|
2759
2728
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
2760
2729
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
2761
|
-
n.
|
|
2762
|
-
...n.
|
|
2730
|
+
n.dt = {
|
|
2731
|
+
...n.dt,
|
|
2763
2732
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
2764
2733
|
};
|
|
2765
2734
|
}
|
|
2766
2735
|
|
|
2767
2736
|
function hasContext(e, t) {
|
|
2768
|
-
return !isUndefined(t?.
|
|
2737
|
+
return !isUndefined(t?.dt[e.id]);
|
|
2769
2738
|
}
|
|
2770
2739
|
|
|
2771
2740
|
function isUndefined(e) {
|
|
@@ -2785,15 +2754,11 @@ function isUndefined(e) {
|
|
|
2785
2754
|
* `_optimisticNodes.length`, `activeLanes.size`), so `!` invocations are safe
|
|
2786
2755
|
* once the gate holds — the same late-binding contract as verdict.ts.
|
|
2787
2756
|
*/
|
|
2788
|
-
// When a background transition is stashed, plain optimistic signals need one
|
|
2789
|
-
// committed-view rerun. Keep that override local to the stash flush.
|
|
2790
|
-
let stashedOptimisticReads = null;
|
|
2791
|
-
|
|
2792
2757
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, t) {
|
|
2793
2758
|
const n = e.A !== NOT_PENDING;
|
|
2794
|
-
const r = n ? unwrapOverride(e.A) : e.
|
|
2759
|
+
const r = n ? unwrapOverride(e.A) : e.xe;
|
|
2795
2760
|
if (typeof t === "function") t = t(r);
|
|
2796
|
-
const i = !!(e
|
|
2761
|
+
const i = !!(e.We & STATUS_UNINITIALIZED) || !e.ht || !e.ht(r, t);
|
|
2797
2762
|
if (!i) {
|
|
2798
2763
|
// Same-value write with an active override still entangles the current
|
|
2799
2764
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2818,43 +2783,13 @@ let stashedOptimisticReads = null;
|
|
|
2818
2783
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
2819
2784
|
// writes off the optimistic path into permanent commits (#2898).
|
|
2820
2785
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2821
|
-
GlobalQueue.
|
|
2786
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2822
2787
|
e.M = clock;
|
|
2823
2788
|
insertSubs(e, true);
|
|
2824
2789
|
schedule();
|
|
2825
2790
|
return t;
|
|
2826
2791
|
}
|
|
2827
2792
|
|
|
2828
|
-
function readStashed(e) {
|
|
2829
|
-
return !!stashedOptimisticReads?.has(e);
|
|
2830
|
-
}
|
|
2831
|
-
|
|
2832
|
-
function queueStashedOptimisticEffects(e) {
|
|
2833
|
-
for (let t = e.k; t !== null; t = t.Ve) {
|
|
2834
|
-
const e = t.xe;
|
|
2835
|
-
if (!e.He) continue;
|
|
2836
|
-
enqueueSub(e);
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
/**
|
|
2841
|
-
* Incomplete-transition finalization when the stashed transition holds
|
|
2842
|
-
* optimistic nodes: give plain optimistic signals one committed-view rerun.
|
|
2843
|
-
*/ function stashOptimistic(e) {
|
|
2844
|
-
stashedOptimisticReads = new Set;
|
|
2845
|
-
for (let t = 0; t < e.G.length; t++) {
|
|
2846
|
-
const n = e.G[t];
|
|
2847
|
-
if (n.We || n.Fe & CONFIG_OWNED_WRITE) continue;
|
|
2848
|
-
stashedOptimisticReads.add(n);
|
|
2849
|
-
queueStashedOptimisticEffects(n);
|
|
2850
|
-
}
|
|
2851
|
-
try {
|
|
2852
|
-
finalizePureQueue(null, true);
|
|
2853
|
-
} finally {
|
|
2854
|
-
stashedOptimisticReads = null;
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
|
|
2858
2793
|
/**
|
|
2859
2794
|
* transitionComplete's override blockage: a settling transition stays open
|
|
2860
2795
|
* while one of its optimistic nodes holds an active override that is still
|
|
@@ -2862,11 +2797,7 @@ function queueStashedOptimisticEffects(e) {
|
|
|
2862
2797
|
*/ function transitionBlocked(e) {
|
|
2863
2798
|
for (let t = 0; t < e.G.length; t++) {
|
|
2864
2799
|
const n = e.G[t];
|
|
2865
|
-
if (hasActiveOverride(n) && "
|
|
2866
|
-
// Mark-sourced pending never blocks settlement: affects() releases AT
|
|
2867
|
-
// settle, so counting its sentinel here would deadlock the window it
|
|
2868
|
-
// is scoped to.
|
|
2869
|
-
!n.Ue.source?.Dt) {
|
|
2800
|
+
if (hasActiveOverride(n) && "We" in n && n.We & STATUS_PENDING && n.me instanceof NotReadyError) {
|
|
2870
2801
|
return true;
|
|
2871
2802
|
}
|
|
2872
2803
|
}
|
|
@@ -2884,10 +2815,10 @@ function resolveOptimisticNodes(e) {
|
|
|
2884
2815
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2885
2816
|
// override-covered authoritative values hold in _pendingValue and
|
|
2886
2817
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2887
|
-
if (!(t
|
|
2818
|
+
if (!(t.We & STATUS_PENDING)) t.We &= ~STATUS_UNINITIALIZED;
|
|
2888
2819
|
const r = t.A;
|
|
2889
2820
|
t.A = NOT_PENDING;
|
|
2890
|
-
if (r !== NOT_PENDING && t.
|
|
2821
|
+
if (r !== NOT_PENDING && t.xe !== unwrapOverride(r)) insertSubs(t, true);
|
|
2891
2822
|
t.T = null;
|
|
2892
2823
|
t.R = null;
|
|
2893
2824
|
}
|
|
@@ -2896,9 +2827,9 @@ function resolveOptimisticNodes(e) {
|
|
|
2896
2827
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2897
2828
|
for (let n = 0; n < t; n++) {
|
|
2898
2829
|
const t = e[n];
|
|
2899
|
-
if (t.
|
|
2830
|
+
if (t.p || t.O) GlobalQueue.fe(t);
|
|
2900
2831
|
const r = t.t;
|
|
2901
|
-
if (r && (r.
|
|
2832
|
+
if (r && (r.p === t || r.O === t)) GlobalQueue.fe(r);
|
|
2902
2833
|
}
|
|
2903
2834
|
e.splice(0, t);
|
|
2904
2835
|
}
|
|
@@ -2951,7 +2882,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2951
2882
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2952
2883
|
* is recorded for replay at commit.
|
|
2953
2884
|
*/ function gatedRead(e, t, n) {
|
|
2954
|
-
if (latestReadActive || e.V === NOT_PENDING || e.
|
|
2885
|
+
if (latestReadActive || e.V === NOT_PENDING || e.Ve || t !== e && !(t.Le & REACTIVE_MANUAL_WRITE)) {
|
|
2955
2886
|
return false;
|
|
2956
2887
|
}
|
|
2957
2888
|
activeTransition.q.add(n);
|
|
@@ -2962,7 +2893,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2962
2893
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2963
2894
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2964
2895
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2965
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t
|
|
2896
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.We & STATUS_PENDING);
|
|
2966
2897
|
}
|
|
2967
2898
|
|
|
2968
2899
|
/**
|
|
@@ -2971,12 +2902,12 @@ function cleanupCompletedLanes(e) {
|
|
|
2971
2902
|
* can run before its OPT-dirty child propagates).
|
|
2972
2903
|
*/ function recomputeLane(e, t) {
|
|
2973
2904
|
if (t) return resolveLane(e) ?? null;
|
|
2974
|
-
for (let t = e.
|
|
2975
|
-
const n = t.
|
|
2976
|
-
if (n.
|
|
2905
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
2906
|
+
const n = t.qe;
|
|
2907
|
+
if (n.Le & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2977
2908
|
const t = resolveLane(n);
|
|
2978
2909
|
if (t) {
|
|
2979
|
-
e.
|
|
2910
|
+
e.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
2980
2911
|
assignOrMergeLane(e, t);
|
|
2981
2912
|
return t;
|
|
2982
2913
|
}
|
|
@@ -2990,7 +2921,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2990
2921
|
if (t.o !== e) {
|
|
2991
2922
|
t.u.add(e);
|
|
2992
2923
|
e.i = t;
|
|
2993
|
-
GlobalQueue.
|
|
2924
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
2994
2925
|
}
|
|
2995
2926
|
}
|
|
2996
2927
|
|
|
@@ -2998,7 +2929,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2998
2929
|
const t = resolveLane(e);
|
|
2999
2930
|
if (t) {
|
|
3000
2931
|
t.u.delete(e);
|
|
3001
|
-
GlobalQueue.
|
|
2932
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
3002
2933
|
}
|
|
3003
2934
|
}
|
|
3004
2935
|
|
|
@@ -3013,21 +2944,19 @@ function trackOptimisticStore(e) {
|
|
|
3013
2944
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
3014
2945
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
3015
2946
|
*/ function installOptimisticEngine() {
|
|
3016
|
-
if (GlobalQueue.
|
|
3017
|
-
GlobalQueue.
|
|
3018
|
-
GlobalQueue.
|
|
3019
|
-
GlobalQueue.
|
|
3020
|
-
GlobalQueue.
|
|
3021
|
-
GlobalQueue.
|
|
3022
|
-
GlobalQueue.
|
|
3023
|
-
GlobalQueue.
|
|
3024
|
-
GlobalQueue.
|
|
3025
|
-
GlobalQueue.
|
|
3026
|
-
GlobalQueue.
|
|
3027
|
-
GlobalQueue.
|
|
3028
|
-
GlobalQueue.
|
|
3029
|
-
GlobalQueue.Ge = laneAsyncSettled;
|
|
3030
|
-
GlobalQueue.Le = trackOptimisticStore;
|
|
2947
|
+
if (GlobalQueue.Oe !== null) return;
|
|
2948
|
+
GlobalQueue.Oe = optimisticWrite;
|
|
2949
|
+
GlobalQueue.Re = resolveOptimisticNodes;
|
|
2950
|
+
GlobalQueue.Ie = transitionBlocked;
|
|
2951
|
+
GlobalQueue.Ae = cleanupCompletedLanes;
|
|
2952
|
+
GlobalQueue.he = runLaneEffects;
|
|
2953
|
+
GlobalQueue.Ne = gatedRead;
|
|
2954
|
+
GlobalQueue.ye = laneSuspends;
|
|
2955
|
+
GlobalQueue.Ce = laneReadsCommitted;
|
|
2956
|
+
GlobalQueue.Pe = recomputeLane;
|
|
2957
|
+
GlobalQueue.ge = laneAsyncPending;
|
|
2958
|
+
GlobalQueue.be = laneAsyncSettled;
|
|
2959
|
+
GlobalQueue.De = trackOptimisticStore;
|
|
3031
2960
|
}
|
|
3032
2961
|
|
|
3033
2962
|
/**
|
|
@@ -3046,21 +2975,21 @@ let pendingProbe = null;
|
|
|
3046
2975
|
* Get or create the pending signal for a node (lazy).
|
|
3047
2976
|
* Used by isPending() to track pending state reactively.
|
|
3048
2977
|
*/ function getPendingSignal(e) {
|
|
3049
|
-
if (!e.
|
|
2978
|
+
if (!e.p) {
|
|
3050
2979
|
// Start false, write true if pending - ensures reversion returns to false
|
|
3051
|
-
e.
|
|
2980
|
+
e.p = optimisticSignal(false, {
|
|
3052
2981
|
ownedWrite: true
|
|
3053
2982
|
});
|
|
3054
|
-
e.
|
|
3055
|
-
if (computePendingState(e)) setSignal(e.
|
|
2983
|
+
e.p.t = e;
|
|
2984
|
+
if (computePendingState(e)) setSignal(e.p, true);
|
|
3056
2985
|
}
|
|
3057
|
-
return e.
|
|
2986
|
+
return e.p;
|
|
3058
2987
|
}
|
|
3059
2988
|
|
|
3060
2989
|
function collectPendingSources(e) {
|
|
3061
2990
|
if (!pendingProbe) return;
|
|
3062
2991
|
pendingProbe.sources.add(e);
|
|
3063
|
-
const t = e.
|
|
2992
|
+
const t = e.Be || e;
|
|
3064
2993
|
if (t !== e) pendingProbe.sources.add(t);
|
|
3065
2994
|
}
|
|
3066
2995
|
|
|
@@ -3074,65 +3003,116 @@ function collectPendingSources(e) {
|
|
|
3074
3003
|
pendingProbe?.sources.add(e);
|
|
3075
3004
|
}
|
|
3076
3005
|
|
|
3006
|
+
/**
|
|
3007
|
+
* The affects() coverage walk — the read half of the dedicated mark channel.
|
|
3008
|
+
* A node is covered by a live mark iff it carries one (`_affectsCount`) or
|
|
3009
|
+
* derives, through its CURRENT deps (hopping store firewalls), from a node
|
|
3010
|
+
* that does. Pull-based coverage means graph rewires, mid-window recomputes,
|
|
3011
|
+
* and probe-triggered recomputes can never strand or strip a mark — there is
|
|
3012
|
+
* nothing stored downstream to corrupt. Probe-created links
|
|
3013
|
+
* (`_pendingObserver`) are skipped so an `isPending` wrapper memo never
|
|
3014
|
+
* inherits the coverage it reports on.
|
|
3015
|
+
*/ function markWalk(e, t) {
|
|
3016
|
+
if (e.F) return true;
|
|
3017
|
+
// A real error outranks an inherited mark (A16/A24c): an errored node
|
|
3018
|
+
// answers probes with its error, not a coverage verdict, and coverage does
|
|
3019
|
+
// not flow through it — matching the rails' behavior, where propagation
|
|
3020
|
+
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3021
|
+
// pending (the count check above), also matching.
|
|
3022
|
+
if (e.We & STATUS_ERROR) return false;
|
|
3023
|
+
if (t.has(e)) return false;
|
|
3024
|
+
t.add(e);
|
|
3025
|
+
const n = e.Be;
|
|
3026
|
+
if (n && markWalk(n, t)) return true;
|
|
3027
|
+
// Mid-recompute (the clearStatus companion poke runs before
|
|
3028
|
+
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3029
|
+
// pass's dependency set — walking past it would read dropped deps and
|
|
3030
|
+
// latch a stale verdict on the companion.
|
|
3031
|
+
const r = e;
|
|
3032
|
+
const i = r.Le & REACTIVE_RECOMPUTING_DEPS ? r.ut : undefined;
|
|
3033
|
+
if (i !== null) {
|
|
3034
|
+
for (let e = r.Ke ?? null; e !== null; e = e.Ye) {
|
|
3035
|
+
if (!e.Ot && markWalk(e.qe, t)) return true;
|
|
3036
|
+
if (e === i) break;
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
return false;
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
/** Gated entry: apps with no live mark pay one integer compare. */ function markCovered(e) {
|
|
3043
|
+
return activeAffectsMarks !== 0 && markWalk(e, new Set);
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3077
3046
|
function quietPending(e) {
|
|
3078
|
-
if (e
|
|
3079
|
-
for (const t of e
|
|
3047
|
+
if (e.$e) {
|
|
3048
|
+
for (const t of e.$e) if (!t.Nt) return false;
|
|
3080
3049
|
return true;
|
|
3081
3050
|
}
|
|
3082
|
-
return e.
|
|
3051
|
+
return e.Nt;
|
|
3083
3052
|
}
|
|
3084
3053
|
|
|
3085
3054
|
function newQuestionInFlight(e) {
|
|
3086
|
-
return !!(e
|
|
3055
|
+
return !!(e.We & STATUS_PENDING) && !(e.We & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3087
3056
|
}
|
|
3088
3057
|
|
|
3089
3058
|
function computePendingState(e) {
|
|
3090
3059
|
const t = e;
|
|
3091
|
-
if (t.
|
|
3092
|
-
|
|
3093
|
-
|
|
3060
|
+
if (t.Le & REACTIVE_DISPOSED) return false;
|
|
3061
|
+
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3062
|
+
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3063
|
+
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3064
|
+
if (markCovered(e)) return true;
|
|
3065
|
+
const n = e.Be;
|
|
3094
3066
|
if (e.t) {
|
|
3095
3067
|
const t = e.t;
|
|
3096
|
-
|
|
3097
|
-
const n = t.Je || t;
|
|
3068
|
+
const n = t.Be || t;
|
|
3098
3069
|
return newQuestionInFlight(n);
|
|
3099
3070
|
}
|
|
3100
3071
|
if (n && e.V !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3101
|
-
return !!(n.
|
|
3072
|
+
return !!(n.Le & REACTIVE_MANUAL_WRITE) || !n.lt && !(n.We & STATUS_PENDING) || !!(n.We & STATUS_PENDING) && quietPending(n);
|
|
3102
3073
|
}
|
|
3103
|
-
if (e.V !== NOT_PENDING && !(t
|
|
3104
|
-
if (hasActiveOverride(e)) return !e.
|
|
3074
|
+
if (e.V !== NOT_PENDING && !(t.We & STATUS_UNINITIALIZED)) {
|
|
3075
|
+
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.V, unwrapOverride(e.A));
|
|
3105
3076
|
return true;
|
|
3106
3077
|
}
|
|
3107
3078
|
return newQuestionInFlight(t);
|
|
3108
3079
|
}
|
|
3109
3080
|
|
|
3110
3081
|
function syncCompanions(e, t) {
|
|
3111
|
-
if (e.
|
|
3082
|
+
if (e.p) updatePendingSignal(e);
|
|
3112
3083
|
if (e.O) setSignal(e.O, t);
|
|
3113
3084
|
}
|
|
3114
3085
|
|
|
3115
3086
|
function updatePendingSignal(e) {
|
|
3116
|
-
if (e.
|
|
3117
|
-
setSignal(e.
|
|
3087
|
+
if (e.p) {
|
|
3088
|
+
setSignal(e.p, computePendingState(e));
|
|
3118
3089
|
}
|
|
3119
3090
|
if (e.O) updatePendingSignal(e.O);
|
|
3120
3091
|
}
|
|
3121
3092
|
|
|
3122
3093
|
function updateChildCompanions(e) {
|
|
3123
|
-
for (let t = e.
|
|
3124
|
-
if (t.
|
|
3094
|
+
for (let t = e.rt; t !== null; t = t.it) {
|
|
3095
|
+
if (t.p || t.O) updatePendingSignal(t);
|
|
3125
3096
|
}
|
|
3126
3097
|
}
|
|
3127
3098
|
|
|
3128
|
-
|
|
3129
|
-
|
|
3099
|
+
/**
|
|
3100
|
+
* Re-derive every verdict companion downstream of `el` (subs + firewall
|
|
3101
|
+
* children, dedup'd). The affects() channel's poke walk: registration and
|
|
3102
|
+
* re-ask flips use the live write path (companion setSignal — its own lane
|
|
3103
|
+
* lets the wake escape an incomplete transition's effect stash, #2887);
|
|
3104
|
+
* mark release passes `snap` because it runs inside queue finalization,
|
|
3105
|
+
* where companion writes must land committed (a setSignal there would open
|
|
3106
|
+
* a fresh override window that nothing settles).
|
|
3107
|
+
*/ function repollDownstreamVerdicts(e, t = false) {
|
|
3108
|
+
const n = t ? snapCompanionsToState : updatePendingSignal;
|
|
3109
|
+
const r = new Set;
|
|
3130
3110
|
const visit = e => {
|
|
3131
|
-
if (
|
|
3132
|
-
|
|
3133
|
-
if (e.
|
|
3134
|
-
for (let t = e.k; t !== null; t = t.
|
|
3135
|
-
for (let t = e.
|
|
3111
|
+
if (r.has(e)) return;
|
|
3112
|
+
r.add(e);
|
|
3113
|
+
if (e.p || e.O) n(e);
|
|
3114
|
+
for (let t = e.k; t !== null; t = t.Ge) visit(t.Ue);
|
|
3115
|
+
for (let t = e.rt ?? null; t !== null; t = t.it) {
|
|
3136
3116
|
visit(t);
|
|
3137
3117
|
}
|
|
3138
3118
|
};
|
|
@@ -3140,11 +3120,11 @@ function repollDownstreamVerdicts(e) {
|
|
|
3140
3120
|
}
|
|
3141
3121
|
|
|
3142
3122
|
function snapCompanionsToState(e) {
|
|
3143
|
-
const t = e.
|
|
3123
|
+
const t = e.p;
|
|
3144
3124
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3145
3125
|
const n = computePendingState(e);
|
|
3146
|
-
if (t.
|
|
3147
|
-
t.
|
|
3126
|
+
if (t.xe !== n || t.V !== NOT_PENDING) {
|
|
3127
|
+
t.xe = n;
|
|
3148
3128
|
t.V = NOT_PENDING;
|
|
3149
3129
|
t.M = clock;
|
|
3150
3130
|
insertSubs(t);
|
|
@@ -3152,9 +3132,9 @@ function snapCompanionsToState(e) {
|
|
|
3152
3132
|
}
|
|
3153
3133
|
}
|
|
3154
3134
|
const n = e.O;
|
|
3155
|
-
if (n && !(n.
|
|
3156
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.V === NOT_PENDING && !Object.is(n.
|
|
3157
|
-
n.
|
|
3135
|
+
if (n && !(n.Le & REACTIVE_DISPOSED)) {
|
|
3136
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.V === NOT_PENDING && !Object.is(n.xe, e.xe) && !(n.Le & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3137
|
+
n.Le |= REACTIVE_DIRTY;
|
|
3158
3138
|
insertIntoHeap(n, queueFor(n));
|
|
3159
3139
|
insertSubs(n);
|
|
3160
3140
|
schedule();
|
|
@@ -3186,7 +3166,7 @@ function getLatestValueComputed(e) {
|
|
|
3186
3166
|
const t = getLatestValueComputed(e);
|
|
3187
3167
|
const n = latestReadActive;
|
|
3188
3168
|
setLatestReadActive(false);
|
|
3189
|
-
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
3169
|
+
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.xe;
|
|
3190
3170
|
let i;
|
|
3191
3171
|
try {
|
|
3192
3172
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -3195,18 +3175,18 @@ function getLatestValueComputed(e) {
|
|
|
3195
3175
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3196
3176
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3197
3177
|
const e = queueFor(t);
|
|
3198
|
-
if (t.
|
|
3178
|
+
if (t.ze >= e.C && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3199
3179
|
markHeap(e);
|
|
3200
3180
|
prepareComputed(t, true);
|
|
3201
3181
|
}
|
|
3202
3182
|
i = read(t);
|
|
3203
3183
|
} catch (t) {
|
|
3204
|
-
if (t instanceof NotReadyError && (!context || !(e
|
|
3184
|
+
if (t instanceof NotReadyError && (!context || !(e.We & STATUS_UNINITIALIZED))) return r;
|
|
3205
3185
|
throw t;
|
|
3206
3186
|
} finally {
|
|
3207
3187
|
setLatestReadActive(n);
|
|
3208
3188
|
}
|
|
3209
|
-
if (t
|
|
3189
|
+
if (t.We & STATUS_PENDING) return r;
|
|
3210
3190
|
if (stale && currentOptimisticLane && t.i) {
|
|
3211
3191
|
const e = findLane(t.i);
|
|
3212
3192
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3224,12 +3204,12 @@ function getLatestValueComputed(e) {
|
|
|
3224
3204
|
|
|
3225
3205
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3226
3206
|
setPendingCheckActive(false);
|
|
3227
|
-
if (typeof e.
|
|
3228
|
-
const i = n
|
|
3207
|
+
if (typeof e.Ve === "function") prepareComputed(e, true);
|
|
3208
|
+
const i = n.We;
|
|
3229
3209
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3230
3210
|
if (tracking && e !== t) link(e, t);
|
|
3231
3211
|
setPendingCheckActive(true);
|
|
3232
|
-
throw n.
|
|
3212
|
+
throw n.me;
|
|
3233
3213
|
}
|
|
3234
3214
|
collectPendingSources(e);
|
|
3235
3215
|
if (r) collectPendingSources(r);
|
|
@@ -3241,10 +3221,10 @@ function recordFreshRead(e, t) {
|
|
|
3241
3221
|
}
|
|
3242
3222
|
|
|
3243
3223
|
function applyReask(e, t) {
|
|
3244
|
-
const n = !!(e
|
|
3245
|
-
const r = t && !(n && !e.
|
|
3246
|
-
const i = n && e.
|
|
3247
|
-
e.
|
|
3224
|
+
const n = !!(e.We & STATUS_PENDING);
|
|
3225
|
+
const r = t && !(n && !e.Nt);
|
|
3226
|
+
const i = n && e.Nt !== r;
|
|
3227
|
+
e.Nt = r;
|
|
3248
3228
|
return i;
|
|
3249
3229
|
}
|
|
3250
3230
|
|
|
@@ -3284,7 +3264,7 @@ function isPending(e) {
|
|
|
3284
3264
|
} catch (e) {
|
|
3285
3265
|
collectPending();
|
|
3286
3266
|
if (e instanceof NotReadyError) {
|
|
3287
|
-
const t = !!(e.source
|
|
3267
|
+
const t = !!(e.source?.We & STATUS_UNINITIALIZED);
|
|
3288
3268
|
if (r.found && !t) return true;
|
|
3289
3269
|
if (context && t) throw e;
|
|
3290
3270
|
}
|
|
@@ -3298,25 +3278,25 @@ function isPending(e) {
|
|
|
3298
3278
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3299
3279
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3300
3280
|
// direct calls used, so behavior is identical once this module loads.
|
|
3301
|
-
GlobalQueue.
|
|
3281
|
+
GlobalQueue.le = syncCompanions;
|
|
3302
3282
|
|
|
3303
|
-
GlobalQueue.
|
|
3283
|
+
GlobalQueue.ce = updatePendingSignal;
|
|
3304
3284
|
|
|
3305
|
-
GlobalQueue.
|
|
3285
|
+
GlobalQueue.ae = updateChildCompanions;
|
|
3306
3286
|
|
|
3307
|
-
GlobalQueue.
|
|
3287
|
+
GlobalQueue.fe = snapCompanionsToState;
|
|
3308
3288
|
|
|
3309
|
-
GlobalQueue.
|
|
3289
|
+
GlobalQueue.Ee = latestRead;
|
|
3310
3290
|
|
|
3311
|
-
GlobalQueue.
|
|
3291
|
+
GlobalQueue.Se = pendingCheckRead;
|
|
3312
3292
|
|
|
3313
|
-
GlobalQueue.
|
|
3293
|
+
GlobalQueue.de = recordFreshRead;
|
|
3314
3294
|
|
|
3315
|
-
GlobalQueue.
|
|
3295
|
+
GlobalQueue.Te = applyReask;
|
|
3316
3296
|
|
|
3317
|
-
GlobalQueue.
|
|
3297
|
+
GlobalQueue._e = repollDownstreamVerdicts;
|
|
3318
3298
|
|
|
3319
|
-
GlobalQueue.
|
|
3299
|
+
GlobalQueue.pe = witnessAffects;
|
|
3320
3300
|
|
|
3321
3301
|
/**
|
|
3322
3302
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3326,16 +3306,16 @@ GlobalQueue.Ie = witnessAffects;
|
|
|
3326
3306
|
const i = !!r?.user;
|
|
3327
3307
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3328
3308
|
recompute(o, true);
|
|
3329
|
-
!r?.defer && (o.
|
|
3309
|
+
!r?.defer && (o.Qe === EFFECT_USER || r?.schedule ? o.Ze.enqueue(o.Qe, runEffect.bind(null, o)) : runEffect(o));
|
|
3330
3310
|
}
|
|
3331
3311
|
|
|
3332
3312
|
function notifyEffectStatus(e, t) {
|
|
3333
3313
|
// Use passed values if provided, otherwise read from node
|
|
3334
|
-
const n = e !== undefined ? e : this
|
|
3335
|
-
const r = t !== undefined ? t : this.
|
|
3314
|
+
const n = e !== undefined ? e : this.We;
|
|
3315
|
+
const r = t !== undefined ? t : this.me;
|
|
3336
3316
|
if (n & STATUS_ERROR) {
|
|
3337
|
-
this.
|
|
3338
|
-
if (this.
|
|
3317
|
+
this.Ze.notify(this, STATUS_PENDING, 0);
|
|
3318
|
+
if (this.Qe === EFFECT_USER) {
|
|
3339
3319
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3340
3320
|
// queue it like the effect function. It runs in the same imperative,
|
|
3341
3321
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3345,23 +3325,23 @@ function notifyEffectStatus(e, t) {
|
|
|
3345
3325
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3346
3326
|
// `status` arg without node-state writes) don't queue: the status
|
|
3347
3327
|
// re-propagates unblocked at commit.
|
|
3348
|
-
if (this
|
|
3349
|
-
this.
|
|
3350
|
-
this.
|
|
3328
|
+
if (this.We & STATUS_ERROR) {
|
|
3329
|
+
this.Fe = true;
|
|
3330
|
+
this.Ze.enqueue(this.Qe, this.Pt ??= runEffect.bind(null, this));
|
|
3351
3331
|
}
|
|
3352
3332
|
return;
|
|
3353
3333
|
}
|
|
3354
|
-
if (!this.
|
|
3334
|
+
if (!this.Ze.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3355
3335
|
haltReactivity(unwrapStatusError(r));
|
|
3356
3336
|
throw r;
|
|
3357
3337
|
}
|
|
3358
|
-
} else if (this.
|
|
3359
|
-
this.
|
|
3338
|
+
} else if (this.Qe === EFFECT_RENDER) {
|
|
3339
|
+
this.Ze.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3360
3340
|
}
|
|
3361
3341
|
}
|
|
3362
3342
|
|
|
3363
3343
|
function runEffect(e) {
|
|
3364
|
-
if (!e.
|
|
3344
|
+
if (!e.Fe || e.Le & REACTIVE_DISPOSED) return;
|
|
3365
3345
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3366
3346
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3367
3347
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3372,42 +3352,42 @@ function runEffect(e) {
|
|
|
3372
3352
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3373
3353
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3374
3354
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3375
|
-
if (e
|
|
3376
|
-
const t = unwrapStatusError(e.
|
|
3377
|
-
e.
|
|
3378
|
-
e.
|
|
3355
|
+
if (e.We & STATUS_ERROR && e.Qe === EFFECT_USER) {
|
|
3356
|
+
const t = unwrapStatusError(e.me);
|
|
3357
|
+
e.bt = e.xe;
|
|
3358
|
+
e.Fe = false;
|
|
3379
3359
|
try {
|
|
3380
|
-
e.
|
|
3381
|
-
const t = e.
|
|
3382
|
-
e.
|
|
3360
|
+
e.vt ? e.vt(t, () => {
|
|
3361
|
+
const t = e.Et;
|
|
3362
|
+
e.Et = undefined;
|
|
3383
3363
|
t?.();
|
|
3384
3364
|
}) : console.error(t);
|
|
3385
3365
|
} catch (t) {
|
|
3386
|
-
if (!e.
|
|
3366
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3387
3367
|
haltReactivity(t);
|
|
3388
3368
|
throw t;
|
|
3389
3369
|
}
|
|
3390
3370
|
}
|
|
3391
3371
|
return;
|
|
3392
3372
|
}
|
|
3393
|
-
const t = e.
|
|
3394
|
-
e.
|
|
3373
|
+
const t = e.Et;
|
|
3374
|
+
e.Et = undefined;
|
|
3395
3375
|
try {
|
|
3396
3376
|
t?.();
|
|
3397
|
-
const n = e.
|
|
3377
|
+
const n = e.Dt(e.xe, e.bt);
|
|
3398
3378
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3399
3379
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3400
|
-
e.
|
|
3380
|
+
e.Et = n;
|
|
3401
3381
|
} catch (t) {
|
|
3402
|
-
e.
|
|
3403
|
-
e
|
|
3404
|
-
if (!e.
|
|
3382
|
+
e.me = new StatusError(e, t);
|
|
3383
|
+
e.We |= STATUS_ERROR;
|
|
3384
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3405
3385
|
haltReactivity(t);
|
|
3406
3386
|
throw t;
|
|
3407
3387
|
}
|
|
3408
3388
|
} finally {
|
|
3409
|
-
e.
|
|
3410
|
-
e.
|
|
3389
|
+
e.bt = e.xe;
|
|
3390
|
+
e.Fe = false;
|
|
3411
3391
|
}
|
|
3412
3392
|
}
|
|
3413
3393
|
|
|
@@ -3419,39 +3399,39 @@ GlobalQueue.ee = runEffect;
|
|
|
3419
3399
|
* Uses stale reads.
|
|
3420
3400
|
*/ function trackedEffect(e, t) {
|
|
3421
3401
|
const run = () => {
|
|
3422
|
-
if (!n.
|
|
3402
|
+
if (!n.Fe || n.Le & REACTIVE_DISPOSED) return;
|
|
3423
3403
|
try {
|
|
3424
|
-
n.
|
|
3404
|
+
n.Fe = false;
|
|
3425
3405
|
recompute(n);
|
|
3426
3406
|
} finally {}
|
|
3427
3407
|
};
|
|
3428
3408
|
const n = computed(() => {
|
|
3429
|
-
const t = n.
|
|
3430
|
-
n.
|
|
3409
|
+
const t = n.Et;
|
|
3410
|
+
n.Et = undefined;
|
|
3431
3411
|
t?.();
|
|
3432
3412
|
const r = staleValues(e);
|
|
3433
|
-
n.
|
|
3413
|
+
n.Et = r;
|
|
3434
3414
|
}, {
|
|
3435
3415
|
...t,
|
|
3436
3416
|
lazy: true
|
|
3437
3417
|
});
|
|
3438
|
-
n.
|
|
3439
|
-
n.
|
|
3440
|
-
n.
|
|
3441
|
-
n.
|
|
3442
|
-
n.
|
|
3443
|
-
const r = e !== undefined ? e : n
|
|
3418
|
+
n.Et = undefined;
|
|
3419
|
+
n.ke = n.ke & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3420
|
+
n.Fe = true;
|
|
3421
|
+
n.Qe = EFFECT_TRACKED;
|
|
3422
|
+
n.yt = (e, t) => {
|
|
3423
|
+
const r = e !== undefined ? e : n.We;
|
|
3444
3424
|
if (r & STATUS_ERROR) {
|
|
3445
|
-
n.
|
|
3446
|
-
const e = t !== undefined ? t : n.
|
|
3447
|
-
if (!n.
|
|
3425
|
+
n.Ze.notify(n, STATUS_PENDING, 0);
|
|
3426
|
+
const e = t !== undefined ? t : n.me;
|
|
3427
|
+
if (!n.Ze.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3448
3428
|
haltReactivity(unwrapStatusError(e));
|
|
3449
3429
|
throw e;
|
|
3450
3430
|
}
|
|
3451
3431
|
}
|
|
3452
3432
|
};
|
|
3453
|
-
n.
|
|
3454
|
-
n.
|
|
3433
|
+
n.Xe = run;
|
|
3434
|
+
n.Ze.enqueue(EFFECT_USER, run);
|
|
3455
3435
|
}
|
|
3456
3436
|
|
|
3457
3437
|
function restoreTransition(e, t) {
|
|
@@ -3632,7 +3612,7 @@ function accessor(e) {
|
|
|
3632
3612
|
function createSignal(e, t) {
|
|
3633
3613
|
if (typeof e === "function") {
|
|
3634
3614
|
const n = computed(e, t);
|
|
3635
|
-
n.
|
|
3615
|
+
n.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
3636
3616
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3637
3617
|
}
|
|
3638
3618
|
const n = signal(e, t);
|
|
@@ -3806,6 +3786,12 @@ function createEffect(e, t, n) {
|
|
|
3806
3786
|
};
|
|
3807
3787
|
}
|
|
3808
3788
|
|
|
3789
|
+
/** Delivers effect applies on a microtask instead of queueing them (#2930). */ class MicrotaskQueue extends Queue {
|
|
3790
|
+
enqueue(e, t) {
|
|
3791
|
+
queueMicrotask(() => t(e));
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3809
3795
|
/**
|
|
3810
3796
|
* Awaits a reactive expression and returns its first fully-settled value as a
|
|
3811
3797
|
* `Promise`. Pending async reads (`createMemo` returning a promise, etc.) are
|
|
@@ -3829,11 +3815,23 @@ function createEffect(e, t, n) {
|
|
|
3829
3815
|
*/ function resolve(e) {
|
|
3830
3816
|
return new Promise((t, n) => {
|
|
3831
3817
|
createRoot(r => {
|
|
3818
|
+
// Deliver effect applies on a microtask instead of the owner queue: an
|
|
3819
|
+
// incomplete transition stashes its effect queues until it settles, but
|
|
3820
|
+
// an action yielding this promise is itself what keeps the transition
|
|
3821
|
+
// open — the stashed res() deadlocked the action (#2930). The compute
|
|
3822
|
+
// still runs in place (under the transaction's view when created inside
|
|
3823
|
+
// an action step), and status/boundary notifications keep their normal
|
|
3824
|
+
// route through the inherited queue.
|
|
3825
|
+
const i = getOwner();
|
|
3826
|
+
const o = new MicrotaskQueue;
|
|
3827
|
+
o.Z = i.Ze;
|
|
3828
|
+
// notify() forwards up the normal chain
|
|
3829
|
+
i.Ze = o;
|
|
3832
3830
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
3833
3831
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
3834
3832
|
// marks them errored, so nothing would re-run and the promise would never
|
|
3835
3833
|
// settle (#2842). The effect's error channel is notified on rejection.
|
|
3836
|
-
|
|
3834
|
+
effect(e, e => {
|
|
3837
3835
|
t(e);
|
|
3838
3836
|
r();
|
|
3839
3837
|
}, e => {
|
|
@@ -3855,7 +3853,7 @@ function createOptimistic(e, t) {
|
|
|
3855
3853
|
installOptimisticEngine();
|
|
3856
3854
|
if (typeof e === "function") {
|
|
3857
3855
|
const n = optimisticComputed(e, t);
|
|
3858
|
-
n.
|
|
3856
|
+
n.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
3859
3857
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3860
3858
|
}
|
|
3861
3859
|
const n = optimisticSignal(e, t);
|
|
@@ -3944,7 +3942,7 @@ function createOptimistic(e, t) {
|
|
|
3944
3942
|
* on owner disposal
|
|
3945
3943
|
*/ function onSettled(e) {
|
|
3946
3944
|
const t = getOwner();
|
|
3947
|
-
t && !(t.
|
|
3945
|
+
t && !(t.ke & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3948
3946
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3949
3947
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3950
3948
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4098,9 +4096,9 @@ function applyArrayItem(e, t, n, r, i) {
|
|
|
4098
4096
|
if (!isWrappable(f)) continue;
|
|
4099
4097
|
const E = (u.get(f) ?? storeLookup.get(f))?.[$TARGET];
|
|
4100
4098
|
if (!E?.[STORE_DESC]) continue;
|
|
4101
|
-
const
|
|
4102
|
-
if (f ===
|
|
4103
|
-
applyState(
|
|
4099
|
+
const S = unwrap(t[a]);
|
|
4100
|
+
if (f === S || !isWrappable(S) || Array.isArray(f) !== Array.isArray(S) || i(f) != null && i(f) !== i(S)) continue;
|
|
4101
|
+
applyState(S, wrap(f, n), i);
|
|
4104
4102
|
}
|
|
4105
4103
|
}
|
|
4106
4104
|
|
|
@@ -4134,11 +4132,11 @@ function applyStateFast(e, t, n) {
|
|
|
4134
4132
|
let o = false;
|
|
4135
4133
|
const s = r.length;
|
|
4136
4134
|
if (e.length && s && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4137
|
-
let u, l, c, a, f, E,
|
|
4135
|
+
let u, l, c, a, f, E, S, d;
|
|
4138
4136
|
for (c = 0, a = Math.min(s, e.length); c < a && keyedMatch(E = r[c], e[c], n); c++) {
|
|
4139
4137
|
isWrappable(E) && isWrappable(e[c]) && applyState(e[c], wrap(E, t), n);
|
|
4140
4138
|
}
|
|
4141
|
-
const T = new Array(e.length),
|
|
4139
|
+
const T = new Array(e.length), _ = new Map;
|
|
4142
4140
|
for (a = s - 1, f = e.length - 1; a >= c && f >= c && keyedMatch(E = r[a], e[f], n); a--,
|
|
4143
4141
|
f--) {
|
|
4144
4142
|
T[f] = E;
|
|
@@ -4157,22 +4155,22 @@ function applyStateFast(e, t, n) {
|
|
|
4157
4155
|
s !== e.length && i?.length && setSignal(i.length, e.length);
|
|
4158
4156
|
return;
|
|
4159
4157
|
}
|
|
4160
|
-
|
|
4158
|
+
S = new Array(f + 1);
|
|
4161
4159
|
for (l = f; l >= c; l--) {
|
|
4162
4160
|
E = e[l];
|
|
4163
|
-
|
|
4164
|
-
u =
|
|
4165
|
-
|
|
4166
|
-
|
|
4161
|
+
d = itemKey(E, n);
|
|
4162
|
+
u = _.get(d);
|
|
4163
|
+
S[l] = u === undefined ? -1 : u;
|
|
4164
|
+
_.set(d, l);
|
|
4167
4165
|
}
|
|
4168
4166
|
for (u = c; u <= a; u++) {
|
|
4169
4167
|
E = r[u];
|
|
4170
|
-
|
|
4171
|
-
l =
|
|
4168
|
+
d = itemKey(E, n);
|
|
4169
|
+
l = _.get(d);
|
|
4172
4170
|
if (l !== undefined && l !== -1) {
|
|
4173
4171
|
T[l] = E;
|
|
4174
|
-
l =
|
|
4175
|
-
|
|
4172
|
+
l = S[l];
|
|
4173
|
+
_.set(d, l);
|
|
4176
4174
|
}
|
|
4177
4175
|
}
|
|
4178
4176
|
for (l = c; l < e.length; l++) {
|
|
@@ -4241,23 +4239,23 @@ function applyStateSlow(e, t, n) {
|
|
|
4241
4239
|
let u = false;
|
|
4242
4240
|
const l = getOverrideValue(r, i, "length", o);
|
|
4243
4241
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4244
|
-
let c, a, f, E,
|
|
4245
|
-
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(
|
|
4246
|
-
isWrappable(
|
|
4242
|
+
let c, a, f, E, S, d, T, _;
|
|
4243
|
+
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(d = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4244
|
+
isWrappable(d) && isWrappable(e[f]) && applyState(e[f], wrap(d, t), n);
|
|
4247
4245
|
}
|
|
4248
|
-
const
|
|
4249
|
-
for (E = l - 1,
|
|
4250
|
-
|
|
4251
|
-
|
|
4246
|
+
const p = new Array(e.length), O = new Map;
|
|
4247
|
+
for (E = l - 1, S = e.length - 1; E >= f && S >= f && keyedMatch(d = getOverrideValue(r, i, E, o), e[S], n); E--,
|
|
4248
|
+
S--) {
|
|
4249
|
+
p[S] = d;
|
|
4252
4250
|
}
|
|
4253
|
-
if (f >
|
|
4254
|
-
for (a = f; a <=
|
|
4251
|
+
if (f > S || f > E) {
|
|
4252
|
+
for (a = f; a <= S; a++) {
|
|
4255
4253
|
u = true;
|
|
4256
4254
|
s?.[a] && setSignal(s[a], wrapValue(e[a], t));
|
|
4257
4255
|
}
|
|
4258
4256
|
for (;a < e.length; a++) {
|
|
4259
4257
|
u = true;
|
|
4260
|
-
applyArrayItem(e[a],
|
|
4258
|
+
applyArrayItem(e[a], p[a], t, s?.[a], n);
|
|
4261
4259
|
}
|
|
4262
4260
|
const r = e.length;
|
|
4263
4261
|
syncArrayNodeMembership(t, e);
|
|
@@ -4265,27 +4263,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4265
4263
|
l !== r && s?.length && setSignal(s.length, r);
|
|
4266
4264
|
return;
|
|
4267
4265
|
}
|
|
4268
|
-
T = new Array(
|
|
4269
|
-
for (a =
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
c = O.get(
|
|
4266
|
+
T = new Array(S + 1);
|
|
4267
|
+
for (a = S; a >= f; a--) {
|
|
4268
|
+
d = e[a];
|
|
4269
|
+
_ = itemKey(d, n);
|
|
4270
|
+
c = O.get(_);
|
|
4273
4271
|
T[a] = c === undefined ? -1 : c;
|
|
4274
|
-
O.set(
|
|
4272
|
+
O.set(_, a);
|
|
4275
4273
|
}
|
|
4276
4274
|
for (c = f; c <= E; c++) {
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
a = O.get(
|
|
4275
|
+
d = getOverrideValue(r, i, c, o);
|
|
4276
|
+
_ = itemKey(d, n);
|
|
4277
|
+
a = O.get(_);
|
|
4280
4278
|
if (a !== undefined && a !== -1) {
|
|
4281
|
-
|
|
4279
|
+
p[a] = d;
|
|
4282
4280
|
a = T[a];
|
|
4283
|
-
O.set(
|
|
4281
|
+
O.set(_, a);
|
|
4284
4282
|
}
|
|
4285
4283
|
}
|
|
4286
4284
|
for (a = f; a < e.length; a++) {
|
|
4287
|
-
if (a in
|
|
4288
|
-
applyArrayItem(e[a],
|
|
4285
|
+
if (a in p) {
|
|
4286
|
+
applyArrayItem(e[a], p[a], t, s?.[a], n);
|
|
4289
4287
|
} else s?.[a] && setSignal(s[a], wrapValue(e[a], t));
|
|
4290
4288
|
}
|
|
4291
4289
|
if (f < e.length) u = true;
|
|
@@ -4316,12 +4314,12 @@ function applyStateSlow(e, t, n) {
|
|
|
4316
4314
|
const a = l[c];
|
|
4317
4315
|
const f = s[a];
|
|
4318
4316
|
const E = unwrap(getOverrideValue(r, i, a, o));
|
|
4319
|
-
let
|
|
4320
|
-
if (E ===
|
|
4321
|
-
if (!E || !isWrappable(E) || !isWrappable(
|
|
4317
|
+
let S = unwrap(e[a]);
|
|
4318
|
+
if (E === S) continue;
|
|
4319
|
+
if (!E || !isWrappable(E) || !isWrappable(S) || Array.isArray(E) !== Array.isArray(S) || n(E) != null && n(E) !== n(S)) {
|
|
4322
4320
|
u && setSignal(u, void 0);
|
|
4323
|
-
f && setSignal(f, isWrappable(
|
|
4324
|
-
} else applyState(
|
|
4321
|
+
f && setSignal(f, isWrappable(S) ? wrap(S, t) : S);
|
|
4322
|
+
} else applyState(S, wrap(E, t), n);
|
|
4325
4323
|
}
|
|
4326
4324
|
}
|
|
4327
4325
|
if (!u && t[STORE_DESC]) applyDescendants(r, e, t, s, n, i, o);
|
|
@@ -4391,7 +4389,7 @@ function createProjectionInternal(e, t, n) {
|
|
|
4391
4389
|
if (!r) r = getOwner();
|
|
4392
4390
|
runProjectionComputed(o, e, n?.key || "id");
|
|
4393
4391
|
}, undefined);
|
|
4394
|
-
r.
|
|
4392
|
+
r.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
4395
4393
|
return {
|
|
4396
4394
|
store: o,
|
|
4397
4395
|
node: r
|
|
@@ -4460,7 +4458,7 @@ function createProjectionInternal(e, t, n) {
|
|
|
4460
4458
|
const o = getOwner();
|
|
4461
4459
|
let s = false;
|
|
4462
4460
|
let u;
|
|
4463
|
-
const l = new Proxy(e, createWriteTraps(() => !s || o.
|
|
4461
|
+
const l = new Proxy(e, createWriteTraps(() => !s || o.lt === u, i));
|
|
4464
4462
|
storeSetter(l, i => {
|
|
4465
4463
|
u = t(i);
|
|
4466
4464
|
s = true;
|
|
@@ -4667,7 +4665,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
4667
4665
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
4668
4666
|
* override, else held pending value, else committed value.
|
|
4669
4667
|
*/ function visibleNodeValue(e) {
|
|
4670
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.V !== NOT_PENDING ? e.V : e.
|
|
4668
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.V !== NOT_PENDING ? e.V : e.xe;
|
|
4671
4669
|
}
|
|
4672
4670
|
|
|
4673
4671
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -4722,7 +4720,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4722
4720
|
}
|
|
4723
4721
|
if (o && n in o) {
|
|
4724
4722
|
const e = o[n];
|
|
4725
|
-
s.
|
|
4723
|
+
s.we = e === undefined ? NO_SNAPSHOT : e;
|
|
4726
4724
|
snapshotSources?.add(s);
|
|
4727
4725
|
}
|
|
4728
4726
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -4752,7 +4750,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4752
4750
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
4753
4751
|
for (const [r, i] of affectsScopes) {
|
|
4754
4752
|
if (r.F && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
4755
|
-
GlobalQueue.
|
|
4753
|
+
GlobalQueue.ie(e);
|
|
4756
4754
|
i.inherited.push(e);
|
|
4757
4755
|
}
|
|
4758
4756
|
}
|
|
@@ -4840,11 +4838,11 @@ i) {
|
|
|
4840
4838
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
4841
4839
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
4842
4840
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
4843
|
-
if (n?.F) GlobalQueue.
|
|
4841
|
+
if (n?.F) GlobalQueue.pe(n);
|
|
4844
4842
|
if (affectsScopes.size) {
|
|
4845
4843
|
const r = e[STORE_VALUE];
|
|
4846
4844
|
for (const [e, i] of affectsScopes) {
|
|
4847
|
-
if (e !== n && e.F && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.
|
|
4845
|
+
if (e !== n && e.F && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.pe(e);
|
|
4848
4846
|
}
|
|
4849
4847
|
}
|
|
4850
4848
|
}
|
|
@@ -4865,7 +4863,7 @@ i) {
|
|
|
4865
4863
|
const t = affectsScopes.get(e);
|
|
4866
4864
|
if (!t) return;
|
|
4867
4865
|
affectsScopes.delete(e);
|
|
4868
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
4866
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.oe(t.inherited[e]);
|
|
4869
4867
|
};
|
|
4870
4868
|
if (t === undefined) {
|
|
4871
4869
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -4992,7 +4990,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
4992
4990
|
}
|
|
4993
4991
|
const r = e[STORE_VALUE];
|
|
4994
4992
|
const i = r[n];
|
|
4995
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]
|
|
4993
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.We ?? 0) & STATUS_PENDING)) {
|
|
4996
4994
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
4997
4995
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
4998
4996
|
snapshotSources?.add(e);
|
|
@@ -5020,7 +5018,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5020
5018
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5021
5019
|
// optimistic engine before wrapping.
|
|
5022
5020
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5023
|
-
GlobalQueue.
|
|
5021
|
+
GlobalQueue.De(t);
|
|
5024
5022
|
}
|
|
5025
5023
|
}
|
|
5026
5024
|
|
|
@@ -5093,7 +5091,7 @@ let Writing = null;
|
|
|
5093
5091
|
* itself (the derive function works its own draft while uninitialized).
|
|
5094
5092
|
*/ function throwIfUninitialized(e) {
|
|
5095
5093
|
const t = e[STORE_FIREWALL];
|
|
5096
|
-
if (t && t
|
|
5094
|
+
if (t && t.We & STATUS_UNINITIALIZED) throw t.me ?? new NotReadyError(t);
|
|
5097
5095
|
}
|
|
5098
5096
|
|
|
5099
5097
|
const storeTraps = {
|
|
@@ -5186,9 +5184,9 @@ const storeTraps = {
|
|
|
5186
5184
|
// throws). #2769
|
|
5187
5185
|
const f = typeof t === "string" ? Number(t) : -1;
|
|
5188
5186
|
const E = Array.isArray(s) && Number.isInteger(f) && f >= 0 && f < 4294967295 && String(f) === t;
|
|
5189
|
-
const
|
|
5190
|
-
const
|
|
5191
|
-
const T = E &&
|
|
5187
|
+
const S = E ? f + 1 : 0;
|
|
5188
|
+
const d = E && (getOverlayLayer(e, "length") ?? s).length;
|
|
5189
|
+
const T = E && S > d ? S : undefined;
|
|
5192
5190
|
if (l === a && T === undefined) return true;
|
|
5193
5191
|
armOptimisticStoreWrite(e, r);
|
|
5194
5192
|
if (a !== undefined && a === i && T === undefined) {
|
|
@@ -5224,7 +5222,7 @@ const storeTraps = {
|
|
|
5224
5222
|
if (t.length) {
|
|
5225
5223
|
setSignal(t.length, T);
|
|
5226
5224
|
} else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
|
|
5227
|
-
const n = upsertStoreNode(e, t, "length",
|
|
5225
|
+
const n = upsertStoreNode(e, t, "length", d, e[STORE_SNAPSHOT_PROPS]);
|
|
5228
5226
|
setSignal(n, T);
|
|
5229
5227
|
}
|
|
5230
5228
|
}
|
|
@@ -5380,126 +5378,76 @@ function createStore(e, t, n) {
|
|
|
5380
5378
|
} : e => storeSetter(i, e) ];
|
|
5381
5379
|
}
|
|
5382
5380
|
|
|
5383
|
-
/**
|
|
5384
|
-
* The pending-source identity of a live `affects()` mark on `node` (lazy,
|
|
5385
|
-
* one per node, shared by overlapping registrations via the refcount).
|
|
5386
|
-
*
|
|
5387
|
-
* A mark rides the SAME status rails as real in-flight async — downstream
|
|
5388
|
-
* subscribers hold the sentinel in `_pendingSources` — but under its own
|
|
5389
|
-
* identity so the two channels can't clear each other:
|
|
5390
|
-
* - `_reask` is permanently `false`: a mark is by definition a declared
|
|
5391
|
-
* value change, so `quietPending` never silences a window it participates
|
|
5392
|
-
* in — even when the mark rides over an otherwise-quiet `refresh()`
|
|
5393
|
-
* re-ask of the same node (the whole point of declaring one).
|
|
5394
|
-
* - A landing on the marked node settles only the node's OWN source entry;
|
|
5395
|
-
* the sentinel entry survives until the mark's transaction releases it.
|
|
5396
|
-
* - The sentinel itself never carries `STATUS_PENDING`, so
|
|
5397
|
-
* `transitionComplete` never counts a mark as a blocker of its own
|
|
5398
|
-
* transaction (release happens AT settle — self-blocking would deadlock),
|
|
5399
|
-
* and reads of the marked node never throw (marks are value-transparent
|
|
5400
|
-
* at the source; pendingness is what propagates).
|
|
5401
|
-
*/ function getAffectsSentinel(e) {
|
|
5402
|
-
return e.Vt ??= {
|
|
5403
|
-
Qt: undefined,
|
|
5404
|
-
// Brand + backref: lets the scheduler's settlement checks recognize
|
|
5405
|
-
// mark-sourced pending (which must never block its own transaction —
|
|
5406
|
-
// release happens AT settle).
|
|
5407
|
-
Dt: e,
|
|
5408
|
-
Qe: 0,
|
|
5409
|
-
$e: 0,
|
|
5410
|
-
gt: false,
|
|
5411
|
-
Ue: undefined,
|
|
5412
|
-
k: null,
|
|
5413
|
-
Ze: null
|
|
5414
|
-
};
|
|
5415
|
-
}
|
|
5416
|
-
|
|
5417
|
-
/**
|
|
5418
|
-
* Push a live mark's pendingness downstream from the marked node through the
|
|
5419
|
-
* normal status rails. Runs on every registration (dedup in `notifyStatus`
|
|
5420
|
-
* stops re-descent at already-covered subscribers). Subscribers that
|
|
5421
|
-
* recompute mid-window shed this via `clearStatus` and re-acquire it through
|
|
5422
|
-
* the read path (`applyAffectsReads` for direct readers of the marked node,
|
|
5423
|
-
* `collectMarkSources` transitively) — the mark analogue of real async's
|
|
5424
|
-
* re-throw-on-read. Subscribers are deliberately NOT queued as pending nodes
|
|
5425
|
-
* (#2893): they hold no value needing a transition-scheduled commit, and
|
|
5426
|
-
* queueing would stamp the marking action's transaction onto them — from then
|
|
5427
|
-
* on ANY write dirtying one of them (including writes to unmarked signals
|
|
5428
|
-
* that merely share a downstream memo) would be captured and frozen until the
|
|
5429
|
-
* action settles.
|
|
5430
|
-
*/ function propagateAffectsMark(e) {
|
|
5431
|
-
if (!e.k && !e.ut) return;
|
|
5432
|
-
const t = getAffectsSentinel(e);
|
|
5433
|
-
const n = new NotReadyError(t);
|
|
5434
|
-
forEachDependent(e, e => {
|
|
5435
|
-
if (!e.Be?.has(t)) {
|
|
5436
|
-
notifyStatus(e, STATUS_PENDING, n);
|
|
5437
|
-
}
|
|
5438
|
-
});
|
|
5439
|
-
}
|
|
5440
|
-
|
|
5441
|
-
/**
|
|
5442
|
-
* Re-establish mark pendingness on a computed that read marked sources
|
|
5443
|
-
* during its recompute (`clearStatus` at the top of the commit path wiped
|
|
5444
|
-
* any sentinel entries it held). Called by `recompute` after the commit —
|
|
5445
|
-
* not before, because setting `_error` earlier would make the commit path
|
|
5446
|
-
* treat the node as errored and skip the value write.
|
|
5447
|
-
*/ function applyAffectsReads(e, t) {
|
|
5448
|
-
let n = false;
|
|
5449
|
-
for (let r = 0; r < t.length; r++) {
|
|
5450
|
-
const i = t[r];
|
|
5451
|
-
if (!i.F) continue;
|
|
5452
|
-
const o = getAffectsSentinel(i);
|
|
5453
|
-
if (addPendingSource(e, o)) {
|
|
5454
|
-
e.$e |= STATUS_PENDING;
|
|
5455
|
-
setPendingError(e, o);
|
|
5456
|
-
n = true;
|
|
5457
|
-
}
|
|
5458
|
-
}
|
|
5459
|
-
if (n && GlobalQueue.Ee !== null) GlobalQueue.Ee(e);
|
|
5460
|
-
}
|
|
5461
|
-
|
|
5462
5381
|
/**
|
|
5463
5382
|
* The counting half of a mark, shared by direct registration and store-scope
|
|
5464
|
-
* inheritance (a node created inside a live keyless mark's identity scope)
|
|
5465
|
-
*
|
|
5466
|
-
*
|
|
5383
|
+
* inheritance (a node created inside a live keyless mark's identity scope).
|
|
5384
|
+
* A mark is ONLY this count: coverage of everything derived from the node is
|
|
5385
|
+
* pull-derived by the verdict layer's `markWalk` (dep-graph reachability), so
|
|
5386
|
+
* nothing is stored downstream and nothing can be stranded or stripped by
|
|
5387
|
+
* mid-window recomputes.
|
|
5467
5388
|
*/ function markAffects(e) {
|
|
5468
5389
|
e.F = (e.F || 0) + 1;
|
|
5469
5390
|
shiftAffectsMarks(1);
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5391
|
+
}
|
|
5392
|
+
|
|
5393
|
+
/**
|
|
5394
|
+
* Boundary visual channel: within a transaction, a live mark holds Loading
|
|
5395
|
+
* fallbacks / reveal ordering the way real in-flight async would — but the
|
|
5396
|
+
* notification is tagged visibility-only at the source (`_markVisual`), so
|
|
5397
|
+
* the root queue never registers reporters from it: marks are invisible to
|
|
5398
|
+
* ALL completion and settlement accounting by construction. Boundaries hold
|
|
5399
|
+
* the marked node in `_sources` while `_affectsCount` is live; the release
|
|
5400
|
+
* sweep (finalizePureQueue re-checks boundary children after mark release)
|
|
5401
|
+
* is the display-state update point. Ambient marks release inside the same
|
|
5402
|
+
* flush that would surface them, before effects run — verdict-only, netting
|
|
5403
|
+
* no visual change.
|
|
5404
|
+
*/ function notifyMarkBoundaries(e) {
|
|
5405
|
+
if (!e.k && !e.rt) return;
|
|
5406
|
+
const t = new NotReadyError(e);
|
|
5407
|
+
t.ve = true;
|
|
5408
|
+
const n = new Set;
|
|
5409
|
+
const visit = e => {
|
|
5410
|
+
if (n.has(e)) return;
|
|
5411
|
+
n.add(e);
|
|
5412
|
+
// Display consumers (render effects, boundary computeds) act on the
|
|
5413
|
+
// notification; descent stops there, exactly like the status rails.
|
|
5414
|
+
if (e.yt) {
|
|
5415
|
+
e.yt(STATUS_PENDING, t);
|
|
5416
|
+
return;
|
|
5417
|
+
}
|
|
5418
|
+
forEachDependent(e, visit);
|
|
5419
|
+
};
|
|
5420
|
+
forEachDependent(e, visit);
|
|
5473
5421
|
}
|
|
5474
5422
|
|
|
5475
5423
|
/**
|
|
5476
5424
|
* Registers one `affects()` mark on a node: counts it, records the
|
|
5477
5425
|
* registration with the current transaction (after initTransition the queue's
|
|
5478
|
-
* batch IS the active transition, mirroring `_optimisticNodes`),
|
|
5479
|
-
*
|
|
5480
|
-
*
|
|
5481
|
-
* registration (not just the first): subscribers gained since an
|
|
5482
|
-
* overlapping registration get covered, and dedup stops re-descent
|
|
5426
|
+
* batch IS the active transition, mirroring `_optimisticNodes`), re-derives
|
|
5427
|
+
* every downstream verdict companion (the mark channel's only push — verdict
|
|
5428
|
+
* pokes, not state), and notifies boundary display state. Both walks run on
|
|
5429
|
+
* every registration (not just the first): subscribers gained since an
|
|
5430
|
+
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
5483
5431
|
*/ function registerAffectsMark(e) {
|
|
5484
5432
|
markAffects(e);
|
|
5485
5433
|
globalQueue.D.L.push(e);
|
|
5486
|
-
|
|
5434
|
+
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5435
|
+
// without them there is no materialized verdict to poke.
|
|
5436
|
+
GlobalQueue._e !== null && GlobalQueue._e(e);
|
|
5437
|
+
notifyMarkBoundaries(e);
|
|
5487
5438
|
schedule();
|
|
5488
5439
|
}
|
|
5489
5440
|
|
|
5490
5441
|
/**
|
|
5491
|
-
* Releases one registration. When the node's last mark drops,
|
|
5492
|
-
*
|
|
5493
|
-
*
|
|
5494
|
-
*
|
|
5495
|
-
* can't open a fresh override window that would itself need settlement.
|
|
5442
|
+
* Releases one registration. When the node's last mark drops, re-derives
|
|
5443
|
+
* every downstream verdict through the settlement snap (committed, not
|
|
5444
|
+
* transition-scoped — release runs inside queue finalization, where a
|
|
5445
|
+
* setSignal would open a fresh override window that nothing settles).
|
|
5496
5446
|
*/ function releaseAffectsMark(e) {
|
|
5497
5447
|
shiftAffectsMarks(-1);
|
|
5498
5448
|
e.F--;
|
|
5499
5449
|
if (!e.F) {
|
|
5500
|
-
|
|
5501
|
-
if (t) settlePendingSource(e, t, true);
|
|
5502
|
-
GlobalQueue.Se !== null && GlobalQueue.Se(e);
|
|
5450
|
+
GlobalQueue._e !== null && GlobalQueue._e(e, true);
|
|
5503
5451
|
GlobalQueue.ne?.(e);
|
|
5504
5452
|
}
|
|
5505
5453
|
}
|
|
@@ -5512,58 +5460,16 @@ function createStore(e, t, n) {
|
|
|
5512
5460
|
e.length = 0;
|
|
5513
5461
|
}
|
|
5514
5462
|
|
|
5515
|
-
/**
|
|
5516
|
-
* True when a node's pending status comes ONLY from affects() sentinels. A
|
|
5517
|
-
* mark is a promise of change, not an absence of value: reads of mark-pended
|
|
5518
|
-
* derived nodes stay value-transparent (verdicts report pending; the read
|
|
5519
|
-
* path must not suspend). Any real async source among the pending sources
|
|
5520
|
-
* keeps normal suspension semantics. Core's read path reaches this through
|
|
5521
|
-
* `GlobalQueue._onlyMarkPending`, gated on the `activeAffectsMarks` counter.
|
|
5522
|
-
*/ function onlyMarkPending(e) {
|
|
5523
|
-
const t = e.Be;
|
|
5524
|
-
if (t) {
|
|
5525
|
-
for (const e of t) if (!e.Dt) return false;
|
|
5526
|
-
return true;
|
|
5527
|
-
}
|
|
5528
|
-
return false;
|
|
5529
|
-
}
|
|
5530
|
-
|
|
5531
|
-
/**
|
|
5532
|
-
* Collect the still-live marked nodes behind a pended owner's sentinel
|
|
5533
|
-
* sources into a recompute's `affectsReads`. This is the transitive half of
|
|
5534
|
-
* read-path re-establishment (#2893): real async re-establishes at every
|
|
5535
|
-
* derivation level because its re-throw on read re-registers the source, but
|
|
5536
|
-
* mark-pended reads are value-transparent — without this, pendingness dies on
|
|
5537
|
-
* the first mid-window recompute past depth one, and the isPending() probe
|
|
5538
|
-
* itself (whose prepare step recomputes retryable NotReady holders) strips
|
|
5539
|
-
* the very status it reports on. Reached through
|
|
5540
|
-
* `GlobalQueue._collectMarkSources`, gated on `activeAffectsMarks`.
|
|
5541
|
-
*/ function collectMarkSources(e, t) {
|
|
5542
|
-
if (e.Be) {
|
|
5543
|
-
for (const n of e.Be) {
|
|
5544
|
-
const e = n.Dt;
|
|
5545
|
-
if (e && e.F) t.push(e);
|
|
5546
|
-
}
|
|
5547
|
-
}
|
|
5548
|
-
}
|
|
5549
|
-
|
|
5550
5463
|
// Late installation (same pattern as `GlobalQueue._update`): the mark engine
|
|
5551
5464
|
// lives with the feature so graphs that never declare a mark never ship it.
|
|
5552
|
-
// Each call site is gated by state only this module creates (
|
|
5553
|
-
//
|
|
5554
|
-
//
|
|
5555
|
-
|
|
5556
|
-
GlobalQueue.re = applyAffectsReads;
|
|
5557
|
-
|
|
5558
|
-
GlobalQueue.ie = releaseAffectsMarks;
|
|
5559
|
-
|
|
5560
|
-
GlobalQueue.oe = markAffects;
|
|
5465
|
+
// Each call site is gated by state only this module creates (a non-empty
|
|
5466
|
+
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
5467
|
+
// hooks are installed before the first time any of them can fire.
|
|
5468
|
+
GlobalQueue.re = releaseAffectsMarks;
|
|
5561
5469
|
|
|
5562
|
-
GlobalQueue.
|
|
5470
|
+
GlobalQueue.ie = markAffects;
|
|
5563
5471
|
|
|
5564
|
-
GlobalQueue.
|
|
5565
|
-
|
|
5566
|
-
GlobalQueue.le = collectMarkSources;
|
|
5472
|
+
GlobalQueue.oe = releaseAffectsMark;
|
|
5567
5473
|
|
|
5568
5474
|
function affects(e, t) {
|
|
5569
5475
|
const n = e?.[$TARGET];
|
|
@@ -5663,8 +5569,8 @@ function clearOptimisticStores(e, t) {
|
|
|
5663
5569
|
c.A = NOT_PENDING;
|
|
5664
5570
|
c.R = null;
|
|
5665
5571
|
c.V = NOT_PENDING;
|
|
5666
|
-
c.
|
|
5667
|
-
if (!c.
|
|
5572
|
+
c.xe = i;
|
|
5573
|
+
if (!c.ht || !c.ht(o, i)) {
|
|
5668
5574
|
insertSubs(c, true);
|
|
5669
5575
|
schedule();
|
|
5670
5576
|
}
|
|
@@ -5736,7 +5642,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5736
5642
|
setProjectionWriteActive(false);
|
|
5737
5643
|
}
|
|
5738
5644
|
}, undefined);
|
|
5739
|
-
r.
|
|
5645
|
+
r.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
5740
5646
|
}
|
|
5741
5647
|
return {
|
|
5742
5648
|
store: o,
|
|
@@ -6148,24 +6054,24 @@ function mapArray(e, t, n) {
|
|
|
6148
6054
|
const i = t.length > 1;
|
|
6149
6055
|
const o = t;
|
|
6150
6056
|
const s = {
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6057
|
+
wt: createOwner(),
|
|
6058
|
+
Gt: 0,
|
|
6059
|
+
Lt: e,
|
|
6060
|
+
Ut: [],
|
|
6061
|
+
kt: o,
|
|
6062
|
+
Vt: [],
|
|
6063
|
+
xt: [],
|
|
6064
|
+
Qt: r,
|
|
6065
|
+
Ft: r || n?.keyed === false ? [] : undefined,
|
|
6066
|
+
Wt: i && n?.keyed !== false ? [] : undefined,
|
|
6067
|
+
Mt: n?.keyed === false,
|
|
6068
|
+
Ht: n?.fallback
|
|
6163
6069
|
};
|
|
6164
6070
|
const u = computed(updateKeyedMap.bind(s));
|
|
6165
6071
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6166
6072
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6167
|
-
s.
|
|
6168
|
-
u.
|
|
6073
|
+
s.wt.et = u;
|
|
6074
|
+
u.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
6169
6075
|
return accessor(u);
|
|
6170
6076
|
}
|
|
6171
6077
|
|
|
@@ -6183,52 +6089,52 @@ const pureOptions = {
|
|
|
6183
6089
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6184
6090
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6185
6091
|
function updateKeyedMap() {
|
|
6186
|
-
const e = this.
|
|
6092
|
+
const e = this.Lt() || [], t = e.length;
|
|
6187
6093
|
e[$TRACK];
|
|
6188
6094
|
// top level tracking
|
|
6189
|
-
runWithOwner(this.
|
|
6095
|
+
runWithOwner(this.wt, () => {
|
|
6190
6096
|
let n, r, i, o,
|
|
6191
6097
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6192
6098
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6193
|
-
s = this.
|
|
6099
|
+
s = this.Ft ? this.Mt ? () => {
|
|
6194
6100
|
i[r] = signal(e[r], pureOptions);
|
|
6195
|
-
return this.
|
|
6101
|
+
return this.kt(accessor(i[r]), r);
|
|
6196
6102
|
} : () => {
|
|
6197
6103
|
i[r] = signal(e[r], pureOptions);
|
|
6198
6104
|
o && (o[r] = signal(r, pureOptions));
|
|
6199
|
-
return this.
|
|
6200
|
-
} : this.
|
|
6105
|
+
return this.kt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6106
|
+
} : this.Wt ? () => {
|
|
6201
6107
|
const t = e[r];
|
|
6202
6108
|
o[r] = signal(r, pureOptions);
|
|
6203
|
-
return this.
|
|
6109
|
+
return this.kt(t, accessor(o[r]));
|
|
6204
6110
|
} : () => {
|
|
6205
6111
|
const t = e[r];
|
|
6206
|
-
return this.
|
|
6112
|
+
return this.kt(t);
|
|
6207
6113
|
};
|
|
6208
6114
|
// fast path for empty arrays
|
|
6209
6115
|
if (t === 0) {
|
|
6210
|
-
if (this.
|
|
6211
|
-
this.
|
|
6212
|
-
this
|
|
6213
|
-
this.
|
|
6214
|
-
this.
|
|
6215
|
-
this.
|
|
6216
|
-
this.
|
|
6217
|
-
this.
|
|
6116
|
+
if (this.Gt !== 0) {
|
|
6117
|
+
this.wt.dispose(false);
|
|
6118
|
+
this.xt = [];
|
|
6119
|
+
this.Ut = [];
|
|
6120
|
+
this.Vt = [];
|
|
6121
|
+
this.Gt = 0;
|
|
6122
|
+
this.Ft && (this.Ft = []);
|
|
6123
|
+
this.Wt && (this.Wt = []);
|
|
6218
6124
|
}
|
|
6219
|
-
if (this.
|
|
6125
|
+
if (this.Ht && !this.Vt[0]) {
|
|
6220
6126
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6221
6127
|
// dispose it before re-creating
|
|
6222
|
-
this
|
|
6223
|
-
this.
|
|
6128
|
+
this.xt[0]?.dispose();
|
|
6129
|
+
this.Vt[0] = runWithOwner(this.xt[0] = createOwner(), this.Ht);
|
|
6224
6130
|
}
|
|
6225
6131
|
}
|
|
6226
6132
|
// fast path for new create
|
|
6227
|
-
else if (this.
|
|
6133
|
+
else if (this.Gt === 0) {
|
|
6228
6134
|
const u = new Array(t);
|
|
6229
6135
|
const l = new Array(t);
|
|
6230
|
-
i = this.
|
|
6231
|
-
o = this.
|
|
6136
|
+
i = this.Ft && new Array(t);
|
|
6137
|
+
o = this.Wt && new Array(t);
|
|
6232
6138
|
try {
|
|
6233
6139
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6234
6140
|
} catch (e) {
|
|
@@ -6236,60 +6142,60 @@ function updateKeyedMap() {
|
|
|
6236
6142
|
throw e;
|
|
6237
6143
|
}
|
|
6238
6144
|
// commit
|
|
6239
|
-
if (this
|
|
6145
|
+
if (this.xt[0]) this.xt[0].dispose();
|
|
6240
6146
|
// previous fallback
|
|
6241
|
-
this.
|
|
6242
|
-
this
|
|
6243
|
-
i && (this.
|
|
6244
|
-
o && (this.
|
|
6245
|
-
this.
|
|
6246
|
-
this.
|
|
6147
|
+
this.Vt = u;
|
|
6148
|
+
this.xt = l;
|
|
6149
|
+
i && (this.Ft = i);
|
|
6150
|
+
o && (this.Wt = o);
|
|
6151
|
+
this.Ut = e.slice(0);
|
|
6152
|
+
this.Gt = t;
|
|
6247
6153
|
} else {
|
|
6248
|
-
let u, l, c, a, f, E,
|
|
6249
|
-
i = this.
|
|
6250
|
-
o = this.
|
|
6154
|
+
let u, l, c, a, f, E, S, d, T, _ = new Array(t), p = new Array(t);
|
|
6155
|
+
i = this.Ft ? new Array(t) : undefined;
|
|
6156
|
+
o = this.Wt ? new Array(t) : undefined;
|
|
6251
6157
|
// skip common prefix
|
|
6252
|
-
for (u = 0, l = Math.min(this.
|
|
6253
|
-
if (this.
|
|
6158
|
+
for (u = 0, l = Math.min(this.Gt, t); u < l && (this.Ut[u] === e[u] || this.Ft && compare(this.Qt, this.Ut[u], e[u])); u++) {
|
|
6159
|
+
if (this.Ft) setSignal(this.Ft[u], e[u]);
|
|
6254
6160
|
}
|
|
6255
6161
|
// common suffix
|
|
6256
|
-
for (l = this.
|
|
6162
|
+
for (l = this.Gt - 1, c = t - 1; l >= u && c >= u && (this.Ut[l] === e[c] || this.Ft && compare(this.Qt, this.Ut[l], e[c])); l--,
|
|
6257
6163
|
c--) {
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
i && (i[c] = this.
|
|
6261
|
-
o && (o[c] = this.
|
|
6164
|
+
_[c] = this.Vt[l];
|
|
6165
|
+
p[c] = this.xt[l];
|
|
6166
|
+
i && (i[c] = this.Ft[l]);
|
|
6167
|
+
o && (o[c] = this.Wt[l]);
|
|
6262
6168
|
}
|
|
6263
6169
|
// 0) prepare a map of all indices in newItems, scanning backwards so we encounter them in natural order
|
|
6264
6170
|
E = new Map;
|
|
6265
|
-
|
|
6171
|
+
S = new Array(c + 1);
|
|
6266
6172
|
for (r = c; r >= u; r--) {
|
|
6267
6173
|
a = e[r];
|
|
6268
|
-
f = this.
|
|
6174
|
+
f = this.Qt ? this.Qt(a) : a;
|
|
6269
6175
|
n = E.get(f);
|
|
6270
|
-
|
|
6176
|
+
S[r] = n === undefined ? -1 : n;
|
|
6271
6177
|
E.set(f, r);
|
|
6272
6178
|
}
|
|
6273
6179
|
// 1) step through all old items and see if they can be found in the new set; if so, save them in a temp array and mark them moved; if not, queue them for disposal at commit
|
|
6274
6180
|
for (n = u; n <= l; n++) {
|
|
6275
|
-
a = this.
|
|
6276
|
-
f = this.
|
|
6181
|
+
a = this.Ut[n];
|
|
6182
|
+
f = this.Qt ? this.Qt(a) : a;
|
|
6277
6183
|
r = E.get(f);
|
|
6278
6184
|
if (r !== undefined && r !== -1) {
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
i && (i[r] = this.
|
|
6282
|
-
o && (o[r] = this.
|
|
6283
|
-
r =
|
|
6185
|
+
_[r] = this.Vt[n];
|
|
6186
|
+
p[r] = this.xt[n];
|
|
6187
|
+
i && (i[r] = this.Ft[n]);
|
|
6188
|
+
o && (o[r] = this.Wt[n]);
|
|
6189
|
+
r = S[r];
|
|
6284
6190
|
E.set(f, r);
|
|
6285
|
-
} else (
|
|
6191
|
+
} else (d ??= []).push(this.xt[n]);
|
|
6286
6192
|
}
|
|
6287
6193
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6288
6194
|
try {
|
|
6289
6195
|
for (r = u; r < t; r++) {
|
|
6290
|
-
if (r in
|
|
6291
|
-
(T ??= []).push(
|
|
6292
|
-
|
|
6196
|
+
if (r in _) continue;
|
|
6197
|
+
(T ??= []).push(p[r] = createOwner());
|
|
6198
|
+
_[r] = runWithOwner(p[r], s);
|
|
6293
6199
|
}
|
|
6294
6200
|
} catch (e) {
|
|
6295
6201
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
@@ -6297,25 +6203,25 @@ function updateKeyedMap() {
|
|
|
6297
6203
|
}
|
|
6298
6204
|
// 3) commit: land positions, then dispose exited rows
|
|
6299
6205
|
for (r = u; r < t; r++) {
|
|
6300
|
-
this.
|
|
6301
|
-
this
|
|
6206
|
+
this.Vt[r] = _[r];
|
|
6207
|
+
this.xt[r] = p[r];
|
|
6302
6208
|
if (i) {
|
|
6303
|
-
this.
|
|
6304
|
-
setSignal(this.
|
|
6209
|
+
this.Ft[r] = i[r];
|
|
6210
|
+
setSignal(this.Ft[r], e[r]);
|
|
6305
6211
|
}
|
|
6306
6212
|
if (o) {
|
|
6307
|
-
this.
|
|
6308
|
-
setSignal(this.
|
|
6213
|
+
this.Wt[r] = o[r];
|
|
6214
|
+
setSignal(this.Wt[r], r);
|
|
6309
6215
|
}
|
|
6310
6216
|
}
|
|
6311
|
-
if (
|
|
6217
|
+
if (d) for (n = 0; n < d.length; n++) d[n].dispose();
|
|
6312
6218
|
// 4) in case the new set is shorter than the old, set the length of the mapped array
|
|
6313
|
-
this.
|
|
6219
|
+
this.Vt = this.Vt.slice(0, this.Gt = t);
|
|
6314
6220
|
// 5) save a copy of the mapped items for the next update
|
|
6315
|
-
this.
|
|
6221
|
+
this.Ut = e.slice(0);
|
|
6316
6222
|
}
|
|
6317
6223
|
});
|
|
6318
|
-
return this.
|
|
6224
|
+
return this.Vt;
|
|
6319
6225
|
}
|
|
6320
6226
|
|
|
6321
6227
|
/**
|
|
@@ -6335,22 +6241,22 @@ function updateKeyedMap() {
|
|
|
6335
6241
|
*/ function repeat(e, t, n) {
|
|
6336
6242
|
const r = t;
|
|
6337
6243
|
const i = {
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6244
|
+
wt: createOwner(),
|
|
6245
|
+
Gt: 0,
|
|
6246
|
+
jt: 0,
|
|
6247
|
+
$t: e,
|
|
6248
|
+
kt: r,
|
|
6249
|
+
xt: [],
|
|
6250
|
+
Vt: [],
|
|
6251
|
+
Kt: n?.from,
|
|
6252
|
+
Ht: n?.fallback
|
|
6347
6253
|
};
|
|
6348
6254
|
const o = computed(updateRepeat.bind(i));
|
|
6349
6255
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6350
6256
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6351
6257
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6352
|
-
i.
|
|
6353
|
-
o.
|
|
6258
|
+
i.wt.et = o;
|
|
6259
|
+
o.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
6354
6260
|
return accessor(o);
|
|
6355
6261
|
}
|
|
6356
6262
|
|
|
@@ -6362,55 +6268,55 @@ function updateKeyedMap() {
|
|
|
6362
6268
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
6363
6269
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
6364
6270
|
function updateRepeat() {
|
|
6365
|
-
const e = this
|
|
6366
|
-
const t = this.
|
|
6367
|
-
runWithOwner(this.
|
|
6271
|
+
const e = this.$t();
|
|
6272
|
+
const t = this.Kt?.() || 0;
|
|
6273
|
+
runWithOwner(this.wt, () => {
|
|
6368
6274
|
if (e === 0) {
|
|
6369
|
-
if (this.
|
|
6370
|
-
this.
|
|
6371
|
-
this
|
|
6372
|
-
this.
|
|
6373
|
-
this.
|
|
6275
|
+
if (this.Gt !== 0) {
|
|
6276
|
+
this.wt.dispose(false);
|
|
6277
|
+
this.xt = [];
|
|
6278
|
+
this.Vt = [];
|
|
6279
|
+
this.Gt = 0;
|
|
6374
6280
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6375
|
-
this.
|
|
6281
|
+
this.jt = 0;
|
|
6376
6282
|
}
|
|
6377
|
-
if (this.
|
|
6283
|
+
if (this.Ht && !this.Vt[0]) {
|
|
6378
6284
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6379
6285
|
// dispose it before re-creating
|
|
6380
|
-
this
|
|
6381
|
-
this.
|
|
6286
|
+
this.xt[0]?.dispose();
|
|
6287
|
+
this.Vt[0] = runWithOwner(this.xt[0] = createOwner(), this.Ht);
|
|
6382
6288
|
}
|
|
6383
6289
|
return;
|
|
6384
6290
|
}
|
|
6385
6291
|
const n = t + e;
|
|
6386
|
-
const r = this.
|
|
6292
|
+
const r = this.jt + this.Gt;
|
|
6387
6293
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6388
6294
|
// windows are disjoint or when coming from empty/fallback.
|
|
6389
|
-
const i = Math.max(t, this.
|
|
6295
|
+
const i = Math.max(t, this.jt);
|
|
6390
6296
|
const o = Math.min(n, r);
|
|
6391
6297
|
const s = new Array(e);
|
|
6392
6298
|
const u = new Array(e);
|
|
6393
6299
|
for (let e = i; e < o; e++) {
|
|
6394
|
-
u[e - t] = this
|
|
6395
|
-
s[e - t] = this.
|
|
6300
|
+
u[e - t] = this.xt[e - this.jt];
|
|
6301
|
+
s[e - t] = this.Vt[e - this.jt];
|
|
6396
6302
|
}
|
|
6397
6303
|
try {
|
|
6398
6304
|
for (let e = t; e < n; e++) {
|
|
6399
6305
|
if (e >= i && e < o) continue;
|
|
6400
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
6306
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.kt(e));
|
|
6401
6307
|
}
|
|
6402
6308
|
} catch (e) {
|
|
6403
6309
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6404
6310
|
throw e;
|
|
6405
6311
|
}
|
|
6406
6312
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6407
|
-
if (this.
|
|
6408
|
-
this.
|
|
6409
|
-
this
|
|
6410
|
-
this.
|
|
6411
|
-
this.
|
|
6313
|
+
if (this.Gt === 0) this.xt[0]?.dispose(); else for (let e = this.jt; e < r; e++) if (e < t || e >= n) this.xt[e - this.jt].dispose();
|
|
6314
|
+
this.Vt = s;
|
|
6315
|
+
this.xt = u;
|
|
6316
|
+
this.jt = t;
|
|
6317
|
+
this.Gt = e;
|
|
6412
6318
|
});
|
|
6413
|
-
return this.
|
|
6319
|
+
return this.Vt;
|
|
6414
6320
|
}
|
|
6415
6321
|
|
|
6416
6322
|
function compare(e, t, n) {
|
|
@@ -6421,23 +6327,23 @@ function boundaryComputed(e, t) {
|
|
|
6421
6327
|
const n = computed(e, {
|
|
6422
6328
|
lazy: true
|
|
6423
6329
|
});
|
|
6424
|
-
n.
|
|
6330
|
+
n.yt = (e, t) => {
|
|
6425
6331
|
// Use passed values if provided, otherwise read from node
|
|
6426
|
-
const r = e !== undefined ? e : n
|
|
6427
|
-
const i = t !== undefined ? t : n.
|
|
6332
|
+
const r = e !== undefined ? e : n.We;
|
|
6333
|
+
const i = t !== undefined ? t : n.me;
|
|
6428
6334
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6429
6335
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6430
6336
|
// a boundary that handles it is found.
|
|
6431
|
-
n
|
|
6432
|
-
const o = n.
|
|
6337
|
+
n.We &= ~n.Yt;
|
|
6338
|
+
const o = n.Ze.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6433
6339
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6434
6340
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
6435
6341
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
6436
6342
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6437
|
-
const s = r & ~n.
|
|
6343
|
+
const s = r & ~n.Yt & (STATUS_PENDING | STATUS_ERROR);
|
|
6438
6344
|
if (s) {
|
|
6439
|
-
n
|
|
6440
|
-
if (n.
|
|
6345
|
+
n.We &= ~s;
|
|
6346
|
+
if (n.me === i && !(n.We & (STATUS_PENDING | STATUS_ERROR))) n.me = undefined;
|
|
6441
6347
|
}
|
|
6442
6348
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6443
6349
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6448,16 +6354,16 @@ function boundaryComputed(e, t) {
|
|
|
6448
6354
|
throw i;
|
|
6449
6355
|
}
|
|
6450
6356
|
};
|
|
6451
|
-
n.
|
|
6452
|
-
n.
|
|
6357
|
+
n.Yt = t;
|
|
6358
|
+
n.ke &= ~CONFIG_AUTO_DISPOSE;
|
|
6453
6359
|
recompute(n, true);
|
|
6454
6360
|
return n;
|
|
6455
6361
|
}
|
|
6456
6362
|
|
|
6457
6363
|
function createBoundChildren(e, t, n, r) {
|
|
6458
|
-
const i = e.
|
|
6459
|
-
i.addChild(e.
|
|
6460
|
-
cleanup(() => i.removeChild(e.
|
|
6364
|
+
const i = e.Ze;
|
|
6365
|
+
i.addChild(e.Ze = n);
|
|
6366
|
+
cleanup(() => i.removeChild(e.Ze));
|
|
6461
6367
|
return runWithOwner(e, () => {
|
|
6462
6368
|
const e = computed(t);
|
|
6463
6369
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -6479,53 +6385,53 @@ function isRevealController(e) {
|
|
|
6479
6385
|
}
|
|
6480
6386
|
|
|
6481
6387
|
function isSlotReady(e) {
|
|
6482
|
-
return isRevealController(e) ? e.
|
|
6388
|
+
return isRevealController(e) ? e.qt() : e.Bt.size === 0 && !e.Zt;
|
|
6483
6389
|
}
|
|
6484
6390
|
|
|
6485
6391
|
function isSlotMinimallyReady(e) {
|
|
6486
|
-
return isRevealController(e) ? e.
|
|
6392
|
+
return isRevealController(e) ? e.Xt() : isSlotReady(e);
|
|
6487
6393
|
}
|
|
6488
6394
|
|
|
6489
6395
|
function setSlotState(e, t, n, r) {
|
|
6490
|
-
setSignal(e.
|
|
6491
|
-
setSignal(e.
|
|
6396
|
+
setSignal(e.zt, n);
|
|
6397
|
+
setSignal(e.Jt, r);
|
|
6492
6398
|
if (isRevealController(e)) {
|
|
6493
|
-
if (!n && e.
|
|
6494
|
-
return e.
|
|
6399
|
+
if (!n && e.en === t) e.en = undefined;
|
|
6400
|
+
return e.tn(n, r);
|
|
6495
6401
|
}
|
|
6496
|
-
if (!n && e.
|
|
6402
|
+
if (!n && e.nn === t && e.rn) e.nn = undefined;
|
|
6497
6403
|
}
|
|
6498
6404
|
|
|
6499
6405
|
class RevealController {
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6406
|
+
sn;
|
|
6407
|
+
un;
|
|
6408
|
+
ln=[];
|
|
6409
|
+
en;
|
|
6410
|
+
zt=signal(false, {
|
|
6505
6411
|
ownedWrite: true,
|
|
6506
|
-
|
|
6412
|
+
gt: true
|
|
6507
6413
|
});
|
|
6508
|
-
|
|
6414
|
+
Jt=signal(false, {
|
|
6509
6415
|
ownedWrite: true,
|
|
6510
|
-
|
|
6416
|
+
gt: true
|
|
6511
6417
|
});
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6418
|
+
cn=true;
|
|
6419
|
+
an=true;
|
|
6420
|
+
fn=false;
|
|
6515
6421
|
constructor(e, t) {
|
|
6516
|
-
this.
|
|
6517
|
-
this.
|
|
6422
|
+
this.sn = e;
|
|
6423
|
+
this.un = t;
|
|
6518
6424
|
}
|
|
6519
|
-
|
|
6520
|
-
for (let t = 0; t < this.
|
|
6521
|
-
const n = this.
|
|
6522
|
-
if ((isRevealController(n) ? n.
|
|
6425
|
+
En(e) {
|
|
6426
|
+
for (let t = 0; t < this.ln.length; t++) {
|
|
6427
|
+
const n = this.ln[t];
|
|
6428
|
+
if ((isRevealController(n) ? n.en : n.nn) !== this) continue;
|
|
6523
6429
|
if (e(n) === false) return false;
|
|
6524
6430
|
}
|
|
6525
6431
|
return true;
|
|
6526
6432
|
}
|
|
6527
|
-
|
|
6528
|
-
return this.
|
|
6433
|
+
qt() {
|
|
6434
|
+
return this.En(isSlotReady);
|
|
6529
6435
|
}
|
|
6530
6436
|
/**
|
|
6531
6437
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -6533,13 +6439,13 @@ class RevealController {
|
|
|
6533
6439
|
* - `together`: every direct slot is minimally ready.
|
|
6534
6440
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
6535
6441
|
* - `natural`: any owned slot is minimally ready.
|
|
6536
|
-
*/
|
|
6537
|
-
const e = untrack(this.
|
|
6538
|
-
if (e === "together") return this.
|
|
6442
|
+
*/ Xt() {
|
|
6443
|
+
const e = untrack(this.sn);
|
|
6444
|
+
if (e === "together") return this.En(isSlotMinimallyReady);
|
|
6539
6445
|
if (e === "natural") {
|
|
6540
6446
|
let e = false;
|
|
6541
6447
|
let t = false;
|
|
6542
|
-
this.
|
|
6448
|
+
this.En(n => {
|
|
6543
6449
|
e = true;
|
|
6544
6450
|
if (isSlotMinimallyReady(n)) {
|
|
6545
6451
|
t = true;
|
|
@@ -6550,45 +6456,45 @@ class RevealController {
|
|
|
6550
6456
|
}
|
|
6551
6457
|
// sequential: only the first owned slot matters.
|
|
6552
6458
|
let t = true;
|
|
6553
|
-
this.
|
|
6459
|
+
this.En(e => {
|
|
6554
6460
|
t = isSlotMinimallyReady(e);
|
|
6555
6461
|
return false;
|
|
6556
6462
|
});
|
|
6557
6463
|
return t;
|
|
6558
6464
|
}
|
|
6559
|
-
|
|
6560
|
-
if (this.
|
|
6561
|
-
this.
|
|
6562
|
-
const t = untrack(this.
|
|
6563
|
-
setSignal(e.
|
|
6564
|
-
untrack(() => this.
|
|
6565
|
-
}
|
|
6566
|
-
|
|
6567
|
-
const t = this.
|
|
6568
|
-
if (t >= 0) this.
|
|
6569
|
-
untrack(() => this.
|
|
6570
|
-
}
|
|
6571
|
-
|
|
6572
|
-
if (this.
|
|
6573
|
-
this.
|
|
6574
|
-
const n = this.
|
|
6575
|
-
const r = this.
|
|
6465
|
+
Sn(e) {
|
|
6466
|
+
if (this.ln.includes(e)) return;
|
|
6467
|
+
this.ln.push(e);
|
|
6468
|
+
const t = untrack(this.sn);
|
|
6469
|
+
setSignal(e.zt, true), setSignal(e.Jt, t === "sequential" ? !!untrack(this.un) : false);
|
|
6470
|
+
untrack(() => this.tn());
|
|
6471
|
+
}
|
|
6472
|
+
dn(e) {
|
|
6473
|
+
const t = this.ln.indexOf(e);
|
|
6474
|
+
if (t >= 0) this.ln.splice(t, 1);
|
|
6475
|
+
untrack(() => this.tn());
|
|
6476
|
+
}
|
|
6477
|
+
tn(e, t) {
|
|
6478
|
+
if (this.fn) return;
|
|
6479
|
+
this.fn = true;
|
|
6480
|
+
const n = this.cn;
|
|
6481
|
+
const r = this.an;
|
|
6576
6482
|
try {
|
|
6577
|
-
const n = e ?? read(this.
|
|
6483
|
+
const n = e ?? read(this.zt), r = untrack(this.sn), i = r === "sequential" && !!untrack(this.un), o = t ?? i;
|
|
6578
6484
|
if (n) {
|
|
6579
6485
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
6580
6486
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
6581
6487
|
// held; it resumes once the outer releases us.
|
|
6582
|
-
this.
|
|
6488
|
+
this.En(e => setSlotState(e, this, true, o));
|
|
6583
6489
|
} else if (r === "natural") {
|
|
6584
6490
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
6585
6491
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
6586
6492
|
// so the parent backpointer survives for upward readiness notifications.
|
|
6587
|
-
this.
|
|
6493
|
+
this.En(e => {
|
|
6588
6494
|
if (isRevealController(e)) {
|
|
6589
|
-
setSignal(e.
|
|
6590
|
-
setSignal(e.
|
|
6591
|
-
e.
|
|
6495
|
+
setSignal(e.Jt, false);
|
|
6496
|
+
setSignal(e.zt, false);
|
|
6497
|
+
e.tn(false, false);
|
|
6592
6498
|
} else {
|
|
6593
6499
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
6594
6500
|
}
|
|
@@ -6599,11 +6505,11 @@ class RevealController {
|
|
|
6599
6505
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
6600
6506
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
6601
6507
|
// cohesive reveal without waiting for every grandchild.
|
|
6602
|
-
const e = this.
|
|
6603
|
-
this.
|
|
6508
|
+
const e = this.En(isSlotMinimallyReady);
|
|
6509
|
+
this.En(t => setSlotState(t, this, !e, false));
|
|
6604
6510
|
} else {
|
|
6605
6511
|
let e = false;
|
|
6606
|
-
this.
|
|
6512
|
+
this.En(t => {
|
|
6607
6513
|
if (e) return setSlotState(t, this, true, i);
|
|
6608
6514
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
6609
6515
|
e = true;
|
|
@@ -6614,63 +6520,63 @@ class RevealController {
|
|
|
6614
6520
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
6615
6521
|
// backpointer survives for upward readiness notifications.
|
|
6616
6522
|
if (isRevealController(t)) {
|
|
6617
|
-
setSignal(t.
|
|
6618
|
-
setSignal(t.
|
|
6619
|
-
t.
|
|
6523
|
+
setSignal(t.Jt, false);
|
|
6524
|
+
setSignal(t.zt, false);
|
|
6525
|
+
t.tn(false, false);
|
|
6620
6526
|
} else {
|
|
6621
6527
|
setSlotState(t, this, true, false);
|
|
6622
6528
|
}
|
|
6623
6529
|
});
|
|
6624
6530
|
}
|
|
6625
6531
|
} finally {
|
|
6626
|
-
this.
|
|
6627
|
-
this.
|
|
6628
|
-
this.
|
|
6532
|
+
this.cn = this.qt();
|
|
6533
|
+
this.an = this.Xt();
|
|
6534
|
+
this.fn = false;
|
|
6629
6535
|
}
|
|
6630
|
-
if (this.
|
|
6536
|
+
if (this.en && (n !== this.cn || r !== this.an)) this.en.tn();
|
|
6631
6537
|
}
|
|
6632
6538
|
}
|
|
6633
6539
|
|
|
6634
6540
|
class CollectionQueue extends Queue {
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6541
|
+
Tn;
|
|
6542
|
+
Bt=new Set;
|
|
6543
|
+
_n;
|
|
6544
|
+
Zt=true;
|
|
6545
|
+
zt=signal(false, {
|
|
6640
6546
|
ownedWrite: true,
|
|
6641
|
-
|
|
6547
|
+
gt: true
|
|
6642
6548
|
});
|
|
6643
|
-
|
|
6644
|
-
|
|
6549
|
+
me;
|
|
6550
|
+
Jt=signal(false, {
|
|
6645
6551
|
ownedWrite: true,
|
|
6646
|
-
|
|
6552
|
+
gt: true
|
|
6647
6553
|
});
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6554
|
+
nn;
|
|
6555
|
+
rn=false;
|
|
6556
|
+
pn;
|
|
6557
|
+
On=ON_INIT;
|
|
6652
6558
|
constructor(e) {
|
|
6653
6559
|
super();
|
|
6654
|
-
this.
|
|
6560
|
+
this.Tn = e;
|
|
6655
6561
|
}
|
|
6656
6562
|
run(e) {
|
|
6657
|
-
if (!e || read(this.
|
|
6563
|
+
if (!e || read(this.zt) && (!_revealUsed || read(this.Jt))) return;
|
|
6658
6564
|
return super.run(e);
|
|
6659
6565
|
}
|
|
6660
6566
|
notify(e, t, n, r) {
|
|
6661
|
-
if (!(t & this.
|
|
6662
|
-
if (this.
|
|
6567
|
+
if (!(t & this.Tn)) return super.notify(e, t, n, r);
|
|
6568
|
+
if (this.rn && this.pn) {
|
|
6663
6569
|
const e = untrack(() => {
|
|
6664
6570
|
try {
|
|
6665
|
-
return this.
|
|
6571
|
+
return this.pn();
|
|
6666
6572
|
} catch {
|
|
6667
6573
|
return ON_INIT;
|
|
6668
6574
|
}
|
|
6669
6575
|
});
|
|
6670
|
-
if (e !== this.
|
|
6671
|
-
this.
|
|
6672
|
-
this.
|
|
6673
|
-
this.
|
|
6576
|
+
if (e !== this.On) {
|
|
6577
|
+
this.On = e;
|
|
6578
|
+
this.rn = false;
|
|
6579
|
+
this.Bt.clear();
|
|
6674
6580
|
}
|
|
6675
6581
|
}
|
|
6676
6582
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -6683,43 +6589,47 @@ class CollectionQueue extends Queue {
|
|
|
6683
6589
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
6684
6590
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
6685
6591
|
// (the Loading > Errored > content composition escape, #2856).
|
|
6686
|
-
if (this.
|
|
6687
|
-
if (n & this.
|
|
6688
|
-
this.
|
|
6689
|
-
const t = r?.source || e.
|
|
6592
|
+
if (this.Tn & STATUS_PENDING && this.rn) return super.notify(e, t, n, r);
|
|
6593
|
+
if (n & this.Tn) {
|
|
6594
|
+
this.Zt = true;
|
|
6595
|
+
const t = r?.source || e.me?.source;
|
|
6690
6596
|
if (t) {
|
|
6691
|
-
const e = this.
|
|
6692
|
-
this.
|
|
6693
|
-
if (e) setSignal(this.
|
|
6694
|
-
if (this.
|
|
6695
|
-
setSignal(this.
|
|
6597
|
+
const e = this.Bt.size === 0;
|
|
6598
|
+
this.Bt.add(t);
|
|
6599
|
+
if (e) setSignal(this.zt, true);
|
|
6600
|
+
if (this.Tn & STATUS_ERROR) {
|
|
6601
|
+
setSignal(this.me, unwrapStatusError(t.me));
|
|
6696
6602
|
}
|
|
6697
6603
|
}
|
|
6698
6604
|
}
|
|
6699
|
-
t &= ~this.
|
|
6605
|
+
t &= ~this.Tn;
|
|
6700
6606
|
return t ? super.notify(e, t, n, r) : true;
|
|
6701
6607
|
}
|
|
6702
|
-
|
|
6703
|
-
for (const e of this.
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6608
|
+
je() {
|
|
6609
|
+
for (const e of this.Bt) {
|
|
6610
|
+
// A source with a live affects() mark holds display state for the
|
|
6611
|
+
// mark's lifetime (the visual channel): the marked node carries no
|
|
6612
|
+
// status of its own, so the count is the liveness test. The release
|
|
6613
|
+
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
6614
|
+
if (e.Le & REACTIVE_DISPOSED || !e.F && !(e.We & this.Tn) && !(this.Tn & STATUS_ERROR && e.We & STATUS_PENDING)) this.Bt.delete(e);
|
|
6615
|
+
}
|
|
6616
|
+
if (!this.Bt.size) {
|
|
6617
|
+
if (this.Tn & STATUS_PENDING && this.Zt && !this.rn && this._n) {
|
|
6618
|
+
this.Zt = !!(this._n.We & this.Tn);
|
|
6709
6619
|
} else {
|
|
6710
|
-
this.
|
|
6620
|
+
this.Zt = false;
|
|
6711
6621
|
}
|
|
6712
|
-
if (!this.
|
|
6713
|
-
setSignal(this.
|
|
6714
|
-
if (this.
|
|
6622
|
+
if (!this.Zt) {
|
|
6623
|
+
setSignal(this.zt, false);
|
|
6624
|
+
if (this.pn) {
|
|
6715
6625
|
try {
|
|
6716
|
-
this.
|
|
6626
|
+
this.On = untrack(() => this.pn());
|
|
6717
6627
|
} catch {
|
|
6718
6628
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
6719
6629
|
}
|
|
6720
6630
|
}
|
|
6721
6631
|
}
|
|
6722
|
-
if (_revealUsed) this.
|
|
6632
|
+
if (_revealUsed) this.nn?.tn();
|
|
6723
6633
|
}
|
|
6724
6634
|
}
|
|
6725
6635
|
|
|
@@ -6727,12 +6637,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6727
6637
|
const i = createOwner();
|
|
6728
6638
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
6729
6639
|
const o = new CollectionQueue(e);
|
|
6730
|
-
if (e === STATUS_ERROR) o.
|
|
6640
|
+
if (e === STATUS_ERROR) o.me = signal(undefined, {
|
|
6731
6641
|
ownedWrite: true,
|
|
6732
|
-
|
|
6642
|
+
gt: true
|
|
6733
6643
|
});
|
|
6734
|
-
if (r) o.
|
|
6735
|
-
const s = o.
|
|
6644
|
+
if (r) o.pn = r;
|
|
6645
|
+
const s = o._n = createBoundChildren(i, t, o, e);
|
|
6736
6646
|
// Prime source tracking so reveal registration sees pending sources.
|
|
6737
6647
|
untrack(() => {
|
|
6738
6648
|
let t = false;
|
|
@@ -6741,23 +6651,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6741
6651
|
} catch (e) {
|
|
6742
6652
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
6743
6653
|
}
|
|
6744
|
-
o.
|
|
6654
|
+
o.Zt = t || !!(s.We & e) || s.me instanceof NotReadyError;
|
|
6745
6655
|
});
|
|
6746
6656
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
6747
6657
|
if (u) {
|
|
6748
|
-
o.
|
|
6749
|
-
u.
|
|
6750
|
-
cleanup(() => u.
|
|
6658
|
+
o.nn = u;
|
|
6659
|
+
u.Sn(o);
|
|
6660
|
+
cleanup(() => u.dn(o));
|
|
6751
6661
|
}
|
|
6752
6662
|
return accessor(computed(() => {
|
|
6753
|
-
if (!read(o.
|
|
6663
|
+
if (!read(o.zt)) {
|
|
6754
6664
|
const e = read(s);
|
|
6755
|
-
if (!untrack(() => read(o.
|
|
6665
|
+
if (!untrack(() => read(o.zt))) return o.rn = true, e;
|
|
6756
6666
|
}
|
|
6757
6667
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
6758
6668
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
6759
6669
|
// outside a `createRevealOrder` scope.
|
|
6760
|
-
if (_revealUsed && read(o.
|
|
6670
|
+
if (_revealUsed && read(o.Jt)) return undefined;
|
|
6761
6671
|
return n(o);
|
|
6762
6672
|
},
|
|
6763
6673
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -6765,7 +6675,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6765
6675
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
6766
6676
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
6767
6677
|
{
|
|
6768
|
-
|
|
6678
|
+
gt: true
|
|
6769
6679
|
}));
|
|
6770
6680
|
}
|
|
6771
6681
|
|
|
@@ -6818,8 +6728,8 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6818
6728
|
* }
|
|
6819
6729
|
* ```
|
|
6820
6730
|
*/ function createErrorBoundary(e, t) {
|
|
6821
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
6822
|
-
for (const t of e.
|
|
6731
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.me), () => {
|
|
6732
|
+
for (const t of e.Bt) recompute(t);
|
|
6823
6733
|
schedule();
|
|
6824
6734
|
}));
|
|
6825
6735
|
}
|
|
@@ -6876,12 +6786,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6876
6786
|
computed(() => {
|
|
6877
6787
|
i();
|
|
6878
6788
|
o();
|
|
6879
|
-
s.
|
|
6789
|
+
s.tn();
|
|
6880
6790
|
});
|
|
6881
6791
|
if (r) {
|
|
6882
|
-
s.
|
|
6883
|
-
r.
|
|
6884
|
-
cleanup(() => r.
|
|
6792
|
+
s.en = r;
|
|
6793
|
+
r.Sn(s);
|
|
6794
|
+
cleanup(() => r.dn(s));
|
|
6885
6795
|
}
|
|
6886
6796
|
return t;
|
|
6887
6797
|
});
|