@solidjs/signals 2.0.0-beta.26 → 2.0.0-beta.28
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 +258 -67
- package/dist/node.cjs +1117 -915
- package/dist/prod/core/action.js +11 -6
- package/dist/prod/core/async.js +42 -11
- package/dist/prod/core/core.js +83 -69
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +4 -4
- package/dist/prod/core/lanes.js +1 -1
- package/dist/prod/core/optimistic.js +5 -5
- package/dist/prod/core/owner.js +1 -1
- package/dist/prod/core/scheduler.js +53 -32
- package/dist/prod/core/verdict.js +26 -26
- package/dist/prod/map.js +2 -2
- package/dist/prod/store/optimistic.js +52 -33
- package/dist/prod/store/projection.js +38 -33
- package/dist/prod/store/reconcile.js +299 -243
- package/dist/prod/store/store.js +98 -47
- package/dist/types/core/async.d.ts +1 -0
- package/dist/types/core/scheduler.d.ts +1 -0
- package/dist/types/store/optimistic.d.ts +2 -2
- package/dist/types/store/projection.d.ts +7 -2
- package/dist/types/store/reconcile.d.ts +14 -0
- package/dist/types/store/store.d.ts +2 -2
- package/dist/types-cjs/core/async.d.cts +1 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -0
- package/dist/types-cjs/store/optimistic.d.cts +2 -2
- package/dist/types-cjs/store/projection.d.cts +7 -2
- package/dist/types-cjs/store/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/store.d.cts +2 -2
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -234,7 +234,7 @@ const activeLanes = new Set;
|
|
|
234
234
|
// the owner's write merges the companion's subscribers into this lane and
|
|
235
235
|
// their effects wait on its async instead of flushing immediately.
|
|
236
236
|
adoptCompanionLane(e._, t);
|
|
237
|
-
adoptCompanionLane(e.
|
|
237
|
+
adoptCompanionLane(e.R, t);
|
|
238
238
|
return t;
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -291,10 +291,10 @@ function resolveTransition(e) {
|
|
|
291
291
|
// transactions (#2912) — the merged root's _transition would hand this
|
|
292
292
|
// node's override to whichever action wrote last through the shared
|
|
293
293
|
// reader. Chase merge chains; a dead owner settled through another path.
|
|
294
|
-
if (hasActiveOverride(e) && e.
|
|
295
|
-
const t = e.
|
|
294
|
+
if (hasActiveOverride(e) && e.p) {
|
|
295
|
+
const t = e.p = currentTransition(e.p);
|
|
296
296
|
if (t.I !== true) return t;
|
|
297
|
-
e.
|
|
297
|
+
e.p = null;
|
|
298
298
|
}
|
|
299
299
|
return resolveLane(e)?.T ?? e.T;
|
|
300
300
|
}
|
|
@@ -376,13 +376,13 @@ function registerTransientStoreNode(e) {
|
|
|
376
376
|
|
|
377
377
|
function canUseSimpleSyncFlush(e) {
|
|
378
378
|
const t = e.D;
|
|
379
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.L.length === 0 && t.
|
|
379
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.L.length === 0 && t.G.size === 0 && transientStoreNodes.size === 0;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
function sweepTransientStoreNodes() {
|
|
383
383
|
if (transientStoreNodes.size === 0) return;
|
|
384
384
|
for (const e of transientStoreNodes) {
|
|
385
|
-
if (e.
|
|
385
|
+
if (e.V !== null) {
|
|
386
386
|
transientStoreNodes.delete(e);
|
|
387
387
|
continue;
|
|
388
388
|
}
|
|
@@ -425,7 +425,7 @@ function setProjectionWriteActive(e) {
|
|
|
425
425
|
M: new Map,
|
|
426
426
|
v: [],
|
|
427
427
|
L: [],
|
|
428
|
-
|
|
428
|
+
G: new Set,
|
|
429
429
|
$: [],
|
|
430
430
|
j: {
|
|
431
431
|
K: [ [], [] ],
|
|
@@ -454,7 +454,7 @@ function mergeTransitionState(e, t) {
|
|
|
454
454
|
e.L.push(...t.L);
|
|
455
455
|
t.L.length = 0;
|
|
456
456
|
}
|
|
457
|
-
for (const n of t.
|
|
457
|
+
for (const n of t.G) e.G.add(n);
|
|
458
458
|
for (const [n, r] of t.M) {
|
|
459
459
|
let t = e.M.get(n);
|
|
460
460
|
if (!t) e.M.set(n, t = new Set);
|
|
@@ -499,10 +499,15 @@ function notifyHalted() {
|
|
|
499
499
|
haltNotified = false;
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
+
// Identifies one child-traversal pass in `Queue.run` so a rescan after the
|
|
503
|
+
// child list shifts can tell "already run this pass" from "still pending".
|
|
504
|
+
let queueRunToken = 0;
|
|
505
|
+
|
|
502
506
|
class Queue {
|
|
503
507
|
B=null;
|
|
504
508
|
K=[ [], [] ];
|
|
505
509
|
m=[];
|
|
510
|
+
Z=0;
|
|
506
511
|
created=clock;
|
|
507
512
|
addChild(e) {
|
|
508
513
|
this.m.push(e);
|
|
@@ -525,7 +530,27 @@ class Queue {
|
|
|
525
530
|
this.K[e - 1] = [];
|
|
526
531
|
runQueue$1(t, e);
|
|
527
532
|
}
|
|
528
|
-
|
|
533
|
+
// Effects run here can dispose owners, and disposal removes queues from
|
|
534
|
+
// this list — the running child itself, an earlier sibling, or several at
|
|
535
|
+
// once. A plain index walk then skips whatever shifted into the cursor.
|
|
536
|
+
// Stamping each child before it runs makes the pass idempotent, so a shift
|
|
537
|
+
// can be recovered by rescanning from the front and every child still runs
|
|
538
|
+
// exactly once. Children appended mid-pass carry a stale stamp and run,
|
|
539
|
+
// matching the previous live-array behaviour.
|
|
540
|
+
const t = this.m;
|
|
541
|
+
const n = ++queueRunToken;
|
|
542
|
+
for (let r = 0; r < t.length; ) {
|
|
543
|
+
const i = t[r];
|
|
544
|
+
if (i.Z !== n) {
|
|
545
|
+
i.Z = n;
|
|
546
|
+
i.run?.(e);
|
|
547
|
+
if (t[r] !== i) {
|
|
548
|
+
r = 0;
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
r++;
|
|
553
|
+
}
|
|
529
554
|
}
|
|
530
555
|
enqueue(e, t) {
|
|
531
556
|
if (e) {
|
|
@@ -572,32 +597,31 @@ class GlobalQueue extends Queue {
|
|
|
572
597
|
// The current transaction-shaped batch: a plain ambient batch while no
|
|
573
598
|
// transition is active, the active transition itself after initTransition.
|
|
574
599
|
D=createBatch();
|
|
575
|
-
static Z;
|
|
576
600
|
static X;
|
|
577
601
|
static J;
|
|
578
|
-
static ee
|
|
602
|
+
static ee;
|
|
603
|
+
static te=null;
|
|
579
604
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
580
605
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
581
606
|
// _clearOptimisticStore).
|
|
582
|
-
static
|
|
607
|
+
static ne=null;
|
|
583
608
|
// affects()-side hooks (wired by affects.ts, mirroring _update): the mark
|
|
584
609
|
// engine — count/register/release — lives with the feature. Every call site
|
|
585
610
|
// is gated by state only that module creates, so `!` invocations are safe
|
|
586
611
|
// once the gate holds.
|
|
587
|
-
static ne=null;
|
|
588
612
|
static re=null;
|
|
589
613
|
static ie=null;
|
|
614
|
+
static oe=null;
|
|
590
615
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
591
616
|
// config is active — including after _resetExternalSourceConfig()).
|
|
592
|
-
static oe=null;
|
|
593
617
|
static se=null;
|
|
618
|
+
static ue=null;
|
|
594
619
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
595
620
|
// imported; null in apps that never use them). Call sites either guard for
|
|
596
621
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
597
622
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
598
623
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
599
624
|
// isPending()/latest()).
|
|
600
|
-
static ue=null;
|
|
601
625
|
static le=null;
|
|
602
626
|
static ae=null;
|
|
603
627
|
static ce=null;
|
|
@@ -607,6 +631,7 @@ class GlobalQueue extends Queue {
|
|
|
607
631
|
static Se=null;
|
|
608
632
|
static Te=null;
|
|
609
633
|
static Oe=null;
|
|
634
|
+
static _e=null;
|
|
610
635
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
611
636
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
612
637
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -614,9 +639,8 @@ class GlobalQueue extends Queue {
|
|
|
614
639
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
615
640
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
616
641
|
// once the gate holds.
|
|
617
|
-
static _e=null;
|
|
618
|
-
static pe=null;
|
|
619
642
|
static Re=null;
|
|
643
|
+
static pe=null;
|
|
620
644
|
static Ie=null;
|
|
621
645
|
static Ae=null;
|
|
622
646
|
static he=null;
|
|
@@ -626,17 +650,18 @@ class GlobalQueue extends Queue {
|
|
|
626
650
|
static Ce=null;
|
|
627
651
|
static ge=null;
|
|
628
652
|
static be=null;
|
|
653
|
+
static De=null;
|
|
629
654
|
flush() {
|
|
630
655
|
if (this.q) return;
|
|
631
656
|
this.q = true;
|
|
632
657
|
try {
|
|
633
658
|
if (false) ;
|
|
634
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
659
|
+
runHeap(dirtyQueue, GlobalQueue.X);
|
|
635
660
|
if (activeTransition) {
|
|
636
661
|
const e = transitionComplete(activeTransition);
|
|
637
662
|
if (!e) {
|
|
638
663
|
const e = activeTransition;
|
|
639
|
-
runHeap(zombieQueue, GlobalQueue.
|
|
664
|
+
runHeap(zombieQueue, GlobalQueue.X);
|
|
640
665
|
// Detach: the stashed transition keeps its batch; ambient work that
|
|
641
666
|
// follows lands in a fresh one. If the batch is already a separate
|
|
642
667
|
// ambient one — action done() restored activeTransition without
|
|
@@ -646,8 +671,8 @@ class GlobalQueue extends Queue {
|
|
|
646
671
|
if (this.D === e) currentBatch = this.D = createBatch();
|
|
647
672
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
648
673
|
if (activeLanes.size) {
|
|
649
|
-
GlobalQueue.
|
|
650
|
-
GlobalQueue.
|
|
674
|
+
GlobalQueue.he(EFFECT_RENDER);
|
|
675
|
+
GlobalQueue.he(EFFECT_USER);
|
|
651
676
|
}
|
|
652
677
|
this.stashQueues(e.j);
|
|
653
678
|
clock++;
|
|
@@ -676,18 +701,18 @@ class GlobalQueue extends Queue {
|
|
|
676
701
|
e.H = n.H;
|
|
677
702
|
e.v = n.v;
|
|
678
703
|
e.L = n.L;
|
|
679
|
-
e.
|
|
704
|
+
e.G = n.G;
|
|
680
705
|
currentBatch = this.D = e;
|
|
681
706
|
}
|
|
682
707
|
} else {
|
|
683
708
|
if (canUseSimpleSyncFlush(this)) {
|
|
684
709
|
commitPendingNodes();
|
|
685
710
|
if (dirtyQueue.C >= dirtyQueue.P) {
|
|
686
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
711
|
+
runHeap(dirtyQueue, GlobalQueue.X);
|
|
687
712
|
commitPendingNodes();
|
|
688
713
|
}
|
|
689
714
|
} else {
|
|
690
|
-
if (transitions.size) runHeap(zombieQueue, GlobalQueue.
|
|
715
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue.X);
|
|
691
716
|
finalizePureQueue();
|
|
692
717
|
}
|
|
693
718
|
}
|
|
@@ -695,9 +720,9 @@ class GlobalQueue extends Queue {
|
|
|
695
720
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
696
721
|
scheduled = dirtyQueue.C >= dirtyQueue.P;
|
|
697
722
|
// Run lane effects first (for ready lanes), then regular effects
|
|
698
|
-
activeLanes.size && GlobalQueue.
|
|
723
|
+
activeLanes.size && GlobalQueue.he(EFFECT_RENDER);
|
|
699
724
|
this.run(EFFECT_RENDER);
|
|
700
|
-
activeLanes.size && GlobalQueue.
|
|
725
|
+
activeLanes.size && GlobalQueue.he(EFFECT_USER);
|
|
701
726
|
this.run(EFFECT_USER);
|
|
702
727
|
if (false) ;
|
|
703
728
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
@@ -710,12 +735,12 @@ class GlobalQueue extends Queue {
|
|
|
710
735
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
711
736
|
if (t & STATUS_PENDING) {
|
|
712
737
|
if (n & STATUS_PENDING) {
|
|
713
|
-
const t = r !== undefined ? r : e.
|
|
738
|
+
const t = r !== undefined ? r : e.we;
|
|
714
739
|
// A visibility-only mark notification (the affects() boundary
|
|
715
740
|
// channel) updates display state on its way up but must be invisible
|
|
716
741
|
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
717
742
|
// reporter and never counts toward the loading-boundary diagnostic.
|
|
718
|
-
if (t?.
|
|
743
|
+
if (t?.me) return true;
|
|
719
744
|
if (activeTransition && t) {
|
|
720
745
|
const n = t.source;
|
|
721
746
|
let r = activeTransition.M.get(n);
|
|
@@ -763,7 +788,7 @@ class GlobalQueue extends Queue {
|
|
|
763
788
|
activeTransition.v.push(n);
|
|
764
789
|
}
|
|
765
790
|
if (t.L.length) activeTransition.L.push(...t.L);
|
|
766
|
-
for (const e of t.
|
|
791
|
+
for (const e of t.G) activeTransition.G.add(e);
|
|
767
792
|
currentBatch = this.D = activeTransition;
|
|
768
793
|
}
|
|
769
794
|
for (const e of activeLanes) {
|
|
@@ -789,21 +814,21 @@ function insertSubs(e, t = false) {
|
|
|
789
814
|
// Get source lane: prefer node's own lane over current context
|
|
790
815
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
791
816
|
const n = e.i || currentOptimisticLane;
|
|
792
|
-
const r = e.
|
|
817
|
+
const r = e.ve !== undefined;
|
|
793
818
|
const i = reaskArmed;
|
|
794
|
-
for (let o = e.
|
|
819
|
+
for (let o = e.V; o !== null; o = o.Le) {
|
|
795
820
|
// A value-change notification is a new question for the subscriber: any
|
|
796
821
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
797
|
-
if (i) o.Ve.
|
|
798
|
-
if (r && o.Ve.
|
|
799
|
-
o.Ve.
|
|
822
|
+
if (i) o.Ve.Ge &= ~REACTIVE_REASK;
|
|
823
|
+
if (r && o.Ve.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
824
|
+
o.Ve.Ge |= REACTIVE_SNAPSHOT_STALE;
|
|
800
825
|
continue;
|
|
801
826
|
}
|
|
802
827
|
if (t && n) {
|
|
803
|
-
o.Ve.
|
|
828
|
+
o.Ve.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
804
829
|
assignOrMergeLane(o.Ve, n);
|
|
805
830
|
} else if (t) {
|
|
806
|
-
o.Ve.
|
|
831
|
+
o.Ve.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
807
832
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
808
833
|
o.Ve.i = undefined;
|
|
809
834
|
}
|
|
@@ -813,24 +838,24 @@ function insertSubs(e, t = false) {
|
|
|
813
838
|
|
|
814
839
|
function commitPendingNode(e) {
|
|
815
840
|
const t = e;
|
|
816
|
-
if (!t.
|
|
841
|
+
if (!t.ke) {
|
|
817
842
|
if (e.U !== NOT_PENDING) {
|
|
818
|
-
e.
|
|
843
|
+
e.We = e.U;
|
|
819
844
|
e.U = NOT_PENDING;
|
|
820
845
|
}
|
|
821
|
-
if (e._ || e.
|
|
846
|
+
if (e._ || e.R) GlobalQueue.fe(e);
|
|
822
847
|
return;
|
|
823
848
|
}
|
|
824
849
|
if (e.U !== NOT_PENDING) {
|
|
825
|
-
e.
|
|
850
|
+
e.We = e.U;
|
|
826
851
|
e.U = NOT_PENDING;
|
|
827
852
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
828
|
-
if (e.
|
|
853
|
+
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.xe = true;
|
|
829
854
|
}
|
|
830
|
-
t.
|
|
831
|
-
if (!(t.
|
|
832
|
-
if (t.
|
|
833
|
-
if (e._ || e.
|
|
855
|
+
t.Ge &= ~REACTIVE_MANUAL_WRITE;
|
|
856
|
+
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
857
|
+
if (t.He !== null || t.Me !== null) GlobalQueue.J(t, false, true);
|
|
858
|
+
if (e._ || e.R) GlobalQueue.fe(e);
|
|
834
859
|
}
|
|
835
860
|
|
|
836
861
|
function commitPendingNodes() {
|
|
@@ -848,7 +873,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
848
873
|
if (n) commitPendingNodes();
|
|
849
874
|
if (!t && globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
850
875
|
const r = dirtyQueue.C >= dirtyQueue.P;
|
|
851
|
-
if (r) runHeap(dirtyQueue, GlobalQueue.
|
|
876
|
+
if (r) runHeap(dirtyQueue, GlobalQueue.X);
|
|
852
877
|
if (n) {
|
|
853
878
|
if (r) commitPendingNodes();
|
|
854
879
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
@@ -860,7 +885,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
860
885
|
// so they re-run with the now-committed values visible.
|
|
861
886
|
if (e && e.Y.size) {
|
|
862
887
|
for (const t of e.Y) {
|
|
863
|
-
if (t.
|
|
888
|
+
if (t.Ge & REACTIVE_DISPOSED) continue;
|
|
864
889
|
enqueueSub(t);
|
|
865
890
|
}
|
|
866
891
|
e.Y.clear();
|
|
@@ -872,23 +897,23 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
872
897
|
// release is the display-state update point — re-run the boundary sweep
|
|
873
898
|
// (the earlier sweep above ran while the marks were still live).
|
|
874
899
|
if (t.L.length) {
|
|
875
|
-
GlobalQueue.
|
|
900
|
+
GlobalQueue.re(t.L);
|
|
876
901
|
if (globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
877
902
|
}
|
|
878
903
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
879
904
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
880
905
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
881
906
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
882
|
-
if (t.
|
|
907
|
+
if (t.G.size) GlobalQueue.te(t.G, e);
|
|
883
908
|
sweepTransientStoreNodes();
|
|
884
909
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
885
|
-
if (activeLanes.size) GlobalQueue.
|
|
910
|
+
if (activeLanes.size) GlobalQueue.Ae(e);
|
|
886
911
|
}
|
|
887
912
|
}
|
|
888
913
|
|
|
889
914
|
function checkBoundaryChildren(e) {
|
|
890
915
|
for (const t of e.m) {
|
|
891
|
-
t
|
|
916
|
+
t.$e?.();
|
|
892
917
|
checkBoundaryChildren(t);
|
|
893
918
|
}
|
|
894
919
|
}
|
|
@@ -955,16 +980,16 @@ function runQueue$1(e, t) {
|
|
|
955
980
|
}
|
|
956
981
|
|
|
957
982
|
function reporterBlocksSource(e, t) {
|
|
958
|
-
if (e.
|
|
959
|
-
if (e
|
|
960
|
-
for (let n = e.
|
|
961
|
-
let e = n.
|
|
983
|
+
if (e.Ge & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
984
|
+
if (e.je?.has(t)) return true;
|
|
985
|
+
for (let n = e.Ke; n; n = n.Ye) {
|
|
986
|
+
let e = n.qe;
|
|
962
987
|
while (e) {
|
|
963
|
-
if (e === t || e.
|
|
988
|
+
if (e === t || e.Be === t) return true;
|
|
964
989
|
e = e.t;
|
|
965
990
|
}
|
|
966
991
|
}
|
|
967
|
-
return !!(e.
|
|
992
|
+
return !!(e.Qe & STATUS_PENDING && e.we instanceof NotReadyError && e.we.source === t);
|
|
968
993
|
}
|
|
969
994
|
|
|
970
995
|
function transitionComplete(e) {
|
|
@@ -980,15 +1005,15 @@ function transitionComplete(e) {
|
|
|
980
1005
|
}
|
|
981
1006
|
r.delete(e);
|
|
982
1007
|
}
|
|
983
|
-
if (!i) e.M.delete(n); else if (n.
|
|
1008
|
+
if (!i) e.M.delete(n); else if (n.Qe & STATUS_PENDING && n.we?.source === n) {
|
|
984
1009
|
t = false;
|
|
985
1010
|
break;
|
|
986
1011
|
}
|
|
987
1012
|
}
|
|
988
|
-
// Override blockage lives with the engine
|
|
989
|
-
// blockage"
|
|
990
|
-
//
|
|
991
|
-
if (t &&
|
|
1013
|
+
// Override blockage lives with the engine (absent hook = "no optimistic
|
|
1014
|
+
// blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
|
|
1015
|
+
// no-ops when the transition holds neither, so no pre-check is needed.
|
|
1016
|
+
if (t && GlobalQueue.Ie?.(e)) t = false;
|
|
992
1017
|
t && (e.I = true);
|
|
993
1018
|
return t;
|
|
994
1019
|
}
|
|
@@ -998,10 +1023,6 @@ function currentTransition(e) {
|
|
|
998
1023
|
return e;
|
|
999
1024
|
}
|
|
1000
1025
|
|
|
1001
|
-
function setActiveTransition(e) {
|
|
1002
|
-
activeTransition = e;
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
1026
|
function runInTransition(e, t) {
|
|
1006
1027
|
const n = activeTransition;
|
|
1007
1028
|
try {
|
|
@@ -1013,7 +1034,7 @@ function runInTransition(e, t) {
|
|
|
1013
1034
|
}
|
|
1014
1035
|
|
|
1015
1036
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1016
|
-
return e.
|
|
1037
|
+
return e.Ge & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1017
1038
|
}
|
|
1018
1039
|
|
|
1019
1040
|
/**
|
|
@@ -1021,40 +1042,40 @@ function runInTransition(e, t) {
|
|
|
1021
1042
|
* the heap and go directly to their effect queue; everything else is inserted
|
|
1022
1043
|
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
1023
1044
|
*/ function enqueueSub(e) {
|
|
1024
|
-
if (e.
|
|
1045
|
+
if (e.Fe === EFFECT_TRACKED) {
|
|
1025
1046
|
const t = e;
|
|
1026
|
-
if (!t.
|
|
1027
|
-
t.
|
|
1028
|
-
t.
|
|
1047
|
+
if (!t.xe) {
|
|
1048
|
+
t.xe = true;
|
|
1049
|
+
t.Ze.enqueue(EFFECT_USER, t.Xe);
|
|
1029
1050
|
}
|
|
1030
1051
|
return;
|
|
1031
1052
|
}
|
|
1032
1053
|
const t = queueFor(e);
|
|
1033
|
-
if (t.P > e.
|
|
1054
|
+
if (t.P > e.ze) t.P = e.ze;
|
|
1034
1055
|
insertIntoHeap(e, t);
|
|
1035
1056
|
}
|
|
1036
1057
|
|
|
1037
1058
|
function actualInsertIntoHeap(e, t) {
|
|
1038
|
-
const n = (e.B?.
|
|
1039
|
-
if (n >= e.
|
|
1040
|
-
const r = e.
|
|
1059
|
+
const n = (e.B?.Je ? e.B.et?.ze : e.B?.ze) ?? -1;
|
|
1060
|
+
if (n >= e.ze) e.ze = n + 1;
|
|
1061
|
+
const r = e.ze;
|
|
1041
1062
|
const i = t.h[r];
|
|
1042
1063
|
if (i === undefined) t.h[r] = e; else {
|
|
1043
|
-
const t = i.
|
|
1044
|
-
t.
|
|
1045
|
-
e.
|
|
1046
|
-
i.
|
|
1064
|
+
const t = i.tt;
|
|
1065
|
+
t.nt = e;
|
|
1066
|
+
e.tt = t;
|
|
1067
|
+
i.tt = e;
|
|
1047
1068
|
}
|
|
1048
1069
|
if (r > t.C) t.C = r;
|
|
1049
1070
|
}
|
|
1050
1071
|
|
|
1051
1072
|
function insertIntoHeap(e, t) {
|
|
1052
|
-
let n = e.
|
|
1073
|
+
let n = e.Ge;
|
|
1053
1074
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1054
1075
|
if (n & REACTIVE_CHECK) {
|
|
1055
|
-
e.
|
|
1076
|
+
e.Ge = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1056
1077
|
} else {
|
|
1057
|
-
e.
|
|
1078
|
+
e.Ge = n | REACTIVE_IN_HEAP;
|
|
1058
1079
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1059
1080
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1060
1081
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1066,48 +1087,48 @@ function insertIntoHeap(e, t) {
|
|
|
1066
1087
|
}
|
|
1067
1088
|
|
|
1068
1089
|
function insertIntoHeapHeight(e, t) {
|
|
1069
|
-
let n = e.
|
|
1090
|
+
let n = e.Ge;
|
|
1070
1091
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1071
|
-
e.
|
|
1092
|
+
e.Ge = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1072
1093
|
actualInsertIntoHeap(e, t);
|
|
1073
1094
|
}
|
|
1074
1095
|
|
|
1075
1096
|
function deleteFromHeap(e, t) {
|
|
1076
|
-
const n = e.
|
|
1097
|
+
const n = e.Ge;
|
|
1077
1098
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1078
|
-
e.
|
|
1079
|
-
const r = e.
|
|
1080
|
-
if (e.
|
|
1081
|
-
const n = e.
|
|
1099
|
+
e.Ge = n & -25;
|
|
1100
|
+
const r = e.ze;
|
|
1101
|
+
if (e.tt === e) t.h[r] = undefined; else {
|
|
1102
|
+
const n = e.nt;
|
|
1082
1103
|
const i = t.h[r];
|
|
1083
1104
|
const o = n ?? i;
|
|
1084
|
-
if (e === i) t.h[r] = n; else e.
|
|
1085
|
-
o.
|
|
1105
|
+
if (e === i) t.h[r] = n; else e.tt.nt = n;
|
|
1106
|
+
o.tt = e.tt;
|
|
1086
1107
|
}
|
|
1087
|
-
e.
|
|
1088
|
-
e.
|
|
1108
|
+
e.tt = e;
|
|
1109
|
+
e.nt = undefined;
|
|
1089
1110
|
}
|
|
1090
1111
|
|
|
1091
1112
|
function markHeap(e) {
|
|
1092
1113
|
if (e.N) return;
|
|
1093
1114
|
e.N = true;
|
|
1094
1115
|
for (let t = 0; t <= e.C; t++) {
|
|
1095
|
-
for (let n = e.h[t]; n !== undefined; n = n.
|
|
1096
|
-
if (n.
|
|
1116
|
+
for (let n = e.h[t]; n !== undefined; n = n.nt) {
|
|
1117
|
+
if (n.Ge & REACTIVE_IN_HEAP) markNode(n);
|
|
1097
1118
|
}
|
|
1098
1119
|
}
|
|
1099
1120
|
}
|
|
1100
1121
|
|
|
1101
1122
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1102
|
-
const n = e.
|
|
1123
|
+
const n = e.Ge;
|
|
1103
1124
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1104
|
-
e.
|
|
1105
|
-
for (let t = e.
|
|
1125
|
+
e.Ge = n & -4 | t;
|
|
1126
|
+
for (let t = e.V; t !== null; t = t.Le) {
|
|
1106
1127
|
markNode(t.Ve, REACTIVE_CHECK);
|
|
1107
1128
|
}
|
|
1108
|
-
if (e.
|
|
1109
|
-
for (let t = e.
|
|
1110
|
-
for (let e = t.
|
|
1129
|
+
if (e.rt !== null) {
|
|
1130
|
+
for (let t = e.rt; t !== null; t = t.it) {
|
|
1131
|
+
for (let e = t.V; e !== null; e = e.Le) {
|
|
1111
1132
|
markNode(e.Ve, REACTIVE_CHECK);
|
|
1112
1133
|
}
|
|
1113
1134
|
}
|
|
@@ -1119,7 +1140,7 @@ function runHeap(e, t) {
|
|
|
1119
1140
|
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1120
1141
|
let n = e.h[e.P];
|
|
1121
1142
|
while (n !== undefined) {
|
|
1122
|
-
if (n.
|
|
1143
|
+
if (n.Ge & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1123
1144
|
n = e.h[e.P];
|
|
1124
1145
|
}
|
|
1125
1146
|
}
|
|
@@ -1128,15 +1149,15 @@ function runHeap(e, t) {
|
|
|
1128
1149
|
|
|
1129
1150
|
function adjustHeight(e, t) {
|
|
1130
1151
|
deleteFromHeap(e, t);
|
|
1131
|
-
let n = e.
|
|
1132
|
-
for (let t = e.
|
|
1133
|
-
const e = t.
|
|
1134
|
-
const r = e.
|
|
1135
|
-
if (r.
|
|
1136
|
-
}
|
|
1137
|
-
if (e.
|
|
1138
|
-
e.
|
|
1139
|
-
for (let t = e.
|
|
1152
|
+
let n = e.ze;
|
|
1153
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
1154
|
+
const e = t.qe;
|
|
1155
|
+
const r = e.Be || e;
|
|
1156
|
+
if (r.ke && r.ze >= n) n = r.ze + 1;
|
|
1157
|
+
}
|
|
1158
|
+
if (e.ze !== n) {
|
|
1159
|
+
e.ze = n;
|
|
1160
|
+
for (let t = e.V; t !== null; t = t.Le) {
|
|
1140
1161
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1141
1162
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1142
1163
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
@@ -1151,10 +1172,10 @@ const PENDING_OWNER = {};
|
|
|
1151
1172
|
|
|
1152
1173
|
// Dummy owner to trigger store's read() path
|
|
1153
1174
|
function markDisposal(e) {
|
|
1154
|
-
let t = e.
|
|
1175
|
+
let t = e.ot;
|
|
1155
1176
|
while (t) {
|
|
1156
|
-
const e = t.
|
|
1157
|
-
t.
|
|
1177
|
+
const e = t.Ge;
|
|
1178
|
+
t.Ge = e | REACTIVE_ZOMBIE;
|
|
1158
1179
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1159
1180
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1160
1181
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1165,79 +1186,79 @@ function markDisposal(e) {
|
|
|
1165
1186
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
1166
1187
|
}
|
|
1167
1188
|
markDisposal(t);
|
|
1168
|
-
t = t.
|
|
1189
|
+
t = t.st;
|
|
1169
1190
|
}
|
|
1170
1191
|
}
|
|
1171
1192
|
|
|
1172
1193
|
function dispose(e) {
|
|
1173
|
-
let t = e.
|
|
1194
|
+
let t = e.Ke;
|
|
1174
1195
|
while (t !== null) {
|
|
1175
1196
|
t = unlinkSubs(t);
|
|
1176
1197
|
}
|
|
1177
|
-
e.
|
|
1178
|
-
e.
|
|
1198
|
+
e.Ke = null;
|
|
1199
|
+
e.ut = null;
|
|
1179
1200
|
disposeChildren(e, true);
|
|
1180
1201
|
}
|
|
1181
1202
|
|
|
1182
1203
|
function disposeChildren(e, t = false, n) {
|
|
1183
|
-
const r = e.
|
|
1204
|
+
const r = e.Ge;
|
|
1184
1205
|
if (r & REACTIVE_DISPOSED) return;
|
|
1185
1206
|
if (t) {
|
|
1186
|
-
e.
|
|
1207
|
+
e.Ge = r | REACTIVE_DISPOSED;
|
|
1187
1208
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1188
1209
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1189
1210
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1190
1211
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1191
1212
|
// false, and notifies subscribers still watching the companion.
|
|
1192
1213
|
const t = e;
|
|
1193
|
-
if (t._ || t.
|
|
1214
|
+
if (t._ || t.R) GlobalQueue.fe(t);
|
|
1194
1215
|
}
|
|
1195
|
-
if (t && e.
|
|
1196
|
-
let i = n ? e.
|
|
1216
|
+
if (t && e.ke) e.lt = null;
|
|
1217
|
+
let i = n ? e.He : e.ot;
|
|
1197
1218
|
while (i) {
|
|
1198
|
-
const e = i.
|
|
1199
|
-
if (i.
|
|
1219
|
+
const e = i.st;
|
|
1220
|
+
if (i.Ke) {
|
|
1200
1221
|
const e = i;
|
|
1201
1222
|
deleteFromHeap(e, queueFor(e));
|
|
1202
|
-
let t = e.
|
|
1223
|
+
let t = e.Ke;
|
|
1203
1224
|
do {
|
|
1204
1225
|
t = unlinkSubs(t);
|
|
1205
1226
|
} while (t !== null);
|
|
1206
|
-
e.
|
|
1207
|
-
e.
|
|
1227
|
+
e.Ke = null;
|
|
1228
|
+
e.ut = null;
|
|
1208
1229
|
}
|
|
1209
1230
|
disposeChildren(i, true);
|
|
1210
1231
|
i = e;
|
|
1211
1232
|
}
|
|
1212
1233
|
if (n) {
|
|
1213
|
-
e.
|
|
1234
|
+
e.He = null;
|
|
1214
1235
|
} else {
|
|
1215
|
-
e.
|
|
1216
|
-
e.
|
|
1236
|
+
e.ot = null;
|
|
1237
|
+
e.ct = 0;
|
|
1217
1238
|
}
|
|
1218
1239
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1219
1240
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1220
1241
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1221
1242
|
// walks that already advanced past us still reach later siblings.
|
|
1222
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.
|
|
1223
|
-
const t = e.
|
|
1224
|
-
const n = e.
|
|
1225
|
-
if (t !== null) t.
|
|
1226
|
-
if (n !== null) n.
|
|
1227
|
-
e.
|
|
1243
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.Ge & REACTIVE_DISPOSED)) {
|
|
1244
|
+
const t = e.ft;
|
|
1245
|
+
const n = e.st;
|
|
1246
|
+
if (t !== null) t.st = n; else e.B.ot = n;
|
|
1247
|
+
if (n !== null) n.ft = t;
|
|
1248
|
+
e.ft = null;
|
|
1228
1249
|
}
|
|
1229
1250
|
runDisposal(e, n);
|
|
1230
1251
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
1231
1252
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
1232
|
-
if (t && e.
|
|
1233
|
-
const t = e.
|
|
1234
|
-
e.
|
|
1253
|
+
if (t && e.Et) {
|
|
1254
|
+
const t = e.Et;
|
|
1255
|
+
e.Et = undefined;
|
|
1235
1256
|
t();
|
|
1236
1257
|
}
|
|
1237
1258
|
}
|
|
1238
1259
|
|
|
1239
1260
|
function runDisposal(e, t) {
|
|
1240
|
-
let n = t ? e.
|
|
1261
|
+
let n = t ? e.Me : e.dt;
|
|
1241
1262
|
if (!n) return;
|
|
1242
1263
|
if (Array.isArray(n)) {
|
|
1243
1264
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1247,13 +1268,13 @@ function runDisposal(e, t) {
|
|
|
1247
1268
|
} else {
|
|
1248
1269
|
n.call(n);
|
|
1249
1270
|
}
|
|
1250
|
-
t ? e.
|
|
1271
|
+
t ? e.Me = null : e.dt = null;
|
|
1251
1272
|
}
|
|
1252
1273
|
|
|
1253
1274
|
function childId(e, t) {
|
|
1254
1275
|
let n = e;
|
|
1255
|
-
while (n.
|
|
1256
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1276
|
+
while (n.Ue & CONFIG_TRANSPARENT && n.B) n = n.B;
|
|
1277
|
+
if (n.id != null) return formatId(n.id, t ? n.ct++ : n.ct);
|
|
1257
1278
|
throw new Error("");
|
|
1258
1279
|
}
|
|
1259
1280
|
|
|
@@ -1334,7 +1355,7 @@ function formatId(e, t) {
|
|
|
1334
1355
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
1335
1356
|
*/ function cleanup(e) {
|
|
1336
1357
|
if (!context) return e;
|
|
1337
|
-
if (!context.
|
|
1358
|
+
if (!context.dt) context.dt = e; else if (Array.isArray(context.dt)) context.dt.push(e); else context.dt = [ context.dt, e ];
|
|
1338
1359
|
return e;
|
|
1339
1360
|
}
|
|
1340
1361
|
|
|
@@ -1354,7 +1375,7 @@ function formatId(e, t) {
|
|
|
1354
1375
|
* }
|
|
1355
1376
|
* ```
|
|
1356
1377
|
*/ function isDisposed(e) {
|
|
1357
|
-
return !!(e.
|
|
1378
|
+
return !!(e.Ge & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1358
1379
|
}
|
|
1359
1380
|
|
|
1360
1381
|
function disposeRootSelf(e = true) {
|
|
@@ -1373,29 +1394,29 @@ function disposeRootSelf(e = true) {
|
|
|
1373
1394
|
const n = e?.transparent ?? false;
|
|
1374
1395
|
const r = {
|
|
1375
1396
|
id: inheritId(e, n, t),
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
it: null,
|
|
1397
|
+
Ue: n ? CONFIG_TRANSPARENT : 0,
|
|
1398
|
+
Je: true,
|
|
1399
|
+
et: t?.Je ? t.et : t,
|
|
1380
1400
|
ot: null,
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1401
|
+
st: null,
|
|
1402
|
+
ft: null,
|
|
1403
|
+
dt: null,
|
|
1404
|
+
Ze: t?.Ze ?? globalQueue,
|
|
1405
|
+
St: t?.St || defaultContext,
|
|
1406
|
+
ct: 0,
|
|
1407
|
+
Me: null,
|
|
1386
1408
|
He: null,
|
|
1387
|
-
Qe: null,
|
|
1388
1409
|
B: t,
|
|
1389
1410
|
dispose: disposeRootSelf
|
|
1390
1411
|
};
|
|
1391
1412
|
if (t) {
|
|
1392
|
-
const e = t.
|
|
1413
|
+
const e = t.ot;
|
|
1393
1414
|
if (e === null) {
|
|
1394
|
-
t.
|
|
1415
|
+
t.ot = r;
|
|
1395
1416
|
} else {
|
|
1396
|
-
r.
|
|
1397
|
-
e.
|
|
1398
|
-
t.
|
|
1417
|
+
r.st = e;
|
|
1418
|
+
e.ft = r;
|
|
1419
|
+
t.ot = r;
|
|
1399
1420
|
}
|
|
1400
1421
|
}
|
|
1401
1422
|
return r;
|
|
@@ -1431,13 +1452,13 @@ function disposeRootSelf(e = true) {
|
|
|
1431
1452
|
|
|
1432
1453
|
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L100
|
|
1433
1454
|
function unlinkSubs(e) {
|
|
1434
|
-
const t = e.
|
|
1435
|
-
const n = e.
|
|
1436
|
-
const r = e.
|
|
1437
|
-
const i = e.
|
|
1438
|
-
if (r !== null) r.
|
|
1439
|
-
if (i !== null) i.
|
|
1440
|
-
t.
|
|
1455
|
+
const t = e.qe;
|
|
1456
|
+
const n = e.Ye;
|
|
1457
|
+
const r = e.Le;
|
|
1458
|
+
const i = e.Tt;
|
|
1459
|
+
if (r !== null) r.Tt = i; else t.Ot = i;
|
|
1460
|
+
if (i !== null) i.Le = r; else {
|
|
1461
|
+
t.V = r;
|
|
1441
1462
|
if (r === null) {
|
|
1442
1463
|
t.W?.();
|
|
1443
1464
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
@@ -1447,31 +1468,31 @@ function unlinkSubs(e) {
|
|
|
1447
1468
|
// this same last-one-out check when that observer releases (the
|
|
1448
1469
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1449
1470
|
const e = t;
|
|
1450
|
-
e.
|
|
1471
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.Ge & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1451
1472
|
}
|
|
1452
1473
|
}
|
|
1453
1474
|
return n;
|
|
1454
1475
|
}
|
|
1455
1476
|
|
|
1456
1477
|
function trimStaleDeps(e) {
|
|
1457
|
-
const t = e.
|
|
1458
|
-
let n = t !== null ? t.
|
|
1478
|
+
const t = e.ut;
|
|
1479
|
+
let n = t !== null ? t.Ye : e.Ke;
|
|
1459
1480
|
if (n !== null) {
|
|
1460
1481
|
do {
|
|
1461
1482
|
n = unlinkSubs(n);
|
|
1462
1483
|
} while (n !== null);
|
|
1463
|
-
if (t !== null) t.
|
|
1484
|
+
if (t !== null) t.Ye = null; else e.Ke = null;
|
|
1464
1485
|
}
|
|
1465
1486
|
}
|
|
1466
1487
|
|
|
1467
1488
|
function unobserved(e) {
|
|
1468
1489
|
deleteFromHeap(e, queueFor(e));
|
|
1469
|
-
let t = e.
|
|
1490
|
+
let t = e.Ke;
|
|
1470
1491
|
while (t !== null) {
|
|
1471
1492
|
t = unlinkSubs(t);
|
|
1472
1493
|
}
|
|
1473
|
-
e.
|
|
1474
|
-
e.
|
|
1494
|
+
e.Ke = null;
|
|
1495
|
+
e.ut = null;
|
|
1475
1496
|
disposeChildren(e, true);
|
|
1476
1497
|
}
|
|
1477
1498
|
|
|
@@ -1482,20 +1503,20 @@ function link(e, t, n = false) {
|
|
|
1482
1503
|
// not relabel the value dependency as probe-only — the value read is what
|
|
1483
1504
|
// real-error propagation and affects() coverage key off, regardless of
|
|
1484
1505
|
// read order within the computation.
|
|
1485
|
-
const r = t.
|
|
1486
|
-
if (r !== null && r.
|
|
1487
|
-
r.
|
|
1506
|
+
const r = t.ut;
|
|
1507
|
+
if (r !== null && r.qe === e) {
|
|
1508
|
+
r._t &&= n;
|
|
1488
1509
|
return;
|
|
1489
1510
|
}
|
|
1490
1511
|
let i = null;
|
|
1491
|
-
const o = t.
|
|
1512
|
+
const o = t.Ge & REACTIVE_RECOMPUTING_DEPS;
|
|
1492
1513
|
if (o) {
|
|
1493
|
-
i = r !== null ? r.
|
|
1494
|
-
if (i !== null && i.
|
|
1495
|
-
i.
|
|
1496
|
-
t.
|
|
1514
|
+
i = r !== null ? r.Ye : t.Ke;
|
|
1515
|
+
if (i !== null && i.qe === e) {
|
|
1516
|
+
i.Rt = t.It;
|
|
1517
|
+
t.ut = i;
|
|
1497
1518
|
// First touch of this pass: the previous pass's label is stale.
|
|
1498
|
-
i.
|
|
1519
|
+
i._t = n;
|
|
1499
1520
|
return;
|
|
1500
1521
|
}
|
|
1501
1522
|
}
|
|
@@ -1504,24 +1525,24 @@ function link(e, t, n = false) {
|
|
|
1504
1525
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
1505
1526
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1506
1527
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1507
|
-
const s = e.
|
|
1508
|
-
if (s !== null && s.Ve === t && (!o || s.
|
|
1528
|
+
const s = e.Ot;
|
|
1529
|
+
if (s !== null && s.Ve === t && (!o || s.Rt === t.It)) {
|
|
1509
1530
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1510
1531
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1511
|
-
if (o) s.
|
|
1532
|
+
if (o) s._t &&= n; else s._t = n;
|
|
1512
1533
|
return;
|
|
1513
1534
|
}
|
|
1514
|
-
const u = t.
|
|
1515
|
-
|
|
1535
|
+
const u = t.ut = e.Ot = {
|
|
1536
|
+
qe: e,
|
|
1516
1537
|
Ve: t,
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1538
|
+
Ye: i,
|
|
1539
|
+
Tt: s,
|
|
1540
|
+
Le: null,
|
|
1541
|
+
Rt: t.It,
|
|
1542
|
+
_t: n
|
|
1522
1543
|
};
|
|
1523
|
-
if (r !== null) r.
|
|
1524
|
-
if (s !== null) s.
|
|
1544
|
+
if (r !== null) r.Ye = u; else t.Ke = u;
|
|
1545
|
+
if (s !== null) s.Le = u; else e.V = u;
|
|
1525
1546
|
}
|
|
1526
1547
|
|
|
1527
1548
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1530,42 +1551,42 @@ function link(e, t, n = false) {
|
|
|
1530
1551
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
1531
1552
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
1532
1553
|
function addPendingSource(e, t) {
|
|
1533
|
-
if (e
|
|
1534
|
-
(e
|
|
1554
|
+
if (e.je?.has(t)) return false;
|
|
1555
|
+
(e.je ??= new Set).add(t);
|
|
1535
1556
|
return true;
|
|
1536
1557
|
}
|
|
1537
1558
|
|
|
1538
1559
|
function removePendingSource(e, t) {
|
|
1539
|
-
if (!e
|
|
1540
|
-
if (e
|
|
1560
|
+
if (!e.je?.delete(t)) return false;
|
|
1561
|
+
if (e.je.size === 0) e.je = undefined;
|
|
1541
1562
|
return true;
|
|
1542
1563
|
}
|
|
1543
1564
|
|
|
1544
1565
|
function clearPendingSources(e) {
|
|
1545
|
-
e
|
|
1546
|
-
e
|
|
1566
|
+
e.je?.clear();
|
|
1567
|
+
e.je = undefined;
|
|
1547
1568
|
}
|
|
1548
1569
|
|
|
1549
1570
|
function setPendingError(e, t, n) {
|
|
1550
1571
|
if (!t) {
|
|
1551
|
-
e.
|
|
1572
|
+
e.we = null;
|
|
1552
1573
|
return;
|
|
1553
1574
|
}
|
|
1554
1575
|
if (n instanceof NotReadyError && n.source === t) {
|
|
1555
|
-
e.
|
|
1576
|
+
e.we = n;
|
|
1556
1577
|
return;
|
|
1557
1578
|
}
|
|
1558
|
-
const r = e.
|
|
1579
|
+
const r = e.we;
|
|
1559
1580
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
1560
|
-
e.
|
|
1581
|
+
e.we = new NotReadyError(t);
|
|
1561
1582
|
}
|
|
1562
1583
|
}
|
|
1563
1584
|
|
|
1564
1585
|
function forEachDependent(e, t) {
|
|
1565
|
-
for (let n = e.
|
|
1586
|
+
for (let n = e.V; n !== null; n = n.Le) t(n.Ve, n);
|
|
1566
1587
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1567
|
-
for (let n = e.
|
|
1568
|
-
for (let e = n.
|
|
1588
|
+
for (let n = e.rt ?? null; n !== null; n = n.it) {
|
|
1589
|
+
for (let e = n.V; e !== null; e = e.Le) t(e.Ve, e);
|
|
1569
1590
|
}
|
|
1570
1591
|
}
|
|
1571
1592
|
|
|
@@ -1580,7 +1601,7 @@ function forEachDependent(e, t) {
|
|
|
1580
1601
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1581
1602
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1582
1603
|
function releaseIfSettledUnobserved(e) {
|
|
1583
|
-
e.
|
|
1604
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.V && !(e.Ge & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1584
1605
|
}
|
|
1585
1606
|
|
|
1586
1607
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -1593,40 +1614,71 @@ function releaseSettledDependents(e) {
|
|
|
1593
1614
|
const visit = e => {
|
|
1594
1615
|
if (n.has(e)) return;
|
|
1595
1616
|
n.add(e);
|
|
1596
|
-
if (!e.
|
|
1617
|
+
if (!e.V && e.Ue & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
1597
1618
|
forEachDependent(e, visit);
|
|
1598
1619
|
};
|
|
1599
1620
|
forEachDependent(e, visit);
|
|
1600
1621
|
if (t) for (const e of t) releaseIfSettledUnobserved(e);
|
|
1601
1622
|
}
|
|
1602
1623
|
|
|
1624
|
+
// Error-dimension twin of settlePendingSource's blocked re-enqueue (#2949):
|
|
1625
|
+
// a node in STATUS_ERROR that recovers by recomputing to an UNCHANGED value
|
|
1626
|
+
// fires no value notification — the recovery is completely silent. But a
|
|
1627
|
+
// dependent that re-ran during the error window consumed its dirty flag and
|
|
1628
|
+
// committed nothing (the fresh sibling values it read were absorbed into an
|
|
1629
|
+
// errored run), so its committed value is stale. The propagated error is one
|
|
1630
|
+
// object identity down the whole dependent tree, and holding it is exactly
|
|
1631
|
+
// the "blocked on this error" marker — re-enqueue those holders so they
|
|
1632
|
+
// re-run: fresh values commit and flow, and a dependent with another
|
|
1633
|
+
// still-broken source simply re-errors. The async dimension needs no twin of
|
|
1634
|
+
// its own: recovery there passes through a pending window whose re-runners
|
|
1635
|
+
// set _blocked and ride settlePendingSource. Walks the full dependent graph
|
|
1636
|
+
// (releaseSettledDependents shape): identity holders can sit below an
|
|
1637
|
+
// intermediate whose own error state has since been scrubbed or replaced
|
|
1638
|
+
// (e.g. an error boundary's tree node).
|
|
1639
|
+
function settleErroredDependents(e, t) {
|
|
1640
|
+
let n = false;
|
|
1641
|
+
const r = new Set;
|
|
1642
|
+
const visit = e => {
|
|
1643
|
+
if (r.has(e)) return;
|
|
1644
|
+
r.add(e);
|
|
1645
|
+
if (e.we === t) {
|
|
1646
|
+
enqueueSub(e);
|
|
1647
|
+
n = true;
|
|
1648
|
+
}
|
|
1649
|
+
forEachDependent(e, visit);
|
|
1650
|
+
};
|
|
1651
|
+
forEachDependent(e, visit);
|
|
1652
|
+
if (n) schedule();
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1603
1655
|
function settlePendingSource(e) {
|
|
1604
1656
|
let t = false;
|
|
1605
1657
|
let n;
|
|
1606
1658
|
const r = new Set;
|
|
1607
1659
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1608
|
-
const i = GlobalQueue.
|
|
1660
|
+
const i = GlobalQueue.ae;
|
|
1609
1661
|
const settle = o => {
|
|
1610
1662
|
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1611
1663
|
r.add(o);
|
|
1612
1664
|
o.F = clock;
|
|
1613
|
-
const s = o
|
|
1665
|
+
const s = o.je?.values().next().value;
|
|
1614
1666
|
if (s) {
|
|
1615
1667
|
setPendingError(o, s);
|
|
1616
1668
|
i !== null && i(o);
|
|
1617
1669
|
} else {
|
|
1618
|
-
o.
|
|
1670
|
+
o.Qe &= ~STATUS_PENDING;
|
|
1619
1671
|
setPendingError(o);
|
|
1620
1672
|
i !== null && i(o);
|
|
1621
|
-
if (o.
|
|
1673
|
+
if (o.At) {
|
|
1622
1674
|
enqueueSub(o);
|
|
1623
1675
|
t = true;
|
|
1624
1676
|
}
|
|
1625
|
-
o.
|
|
1677
|
+
o.At = false;
|
|
1626
1678
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1627
1679
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
1628
1680
|
// lists this walk is still iterating.
|
|
1629
|
-
if (!o.
|
|
1681
|
+
if (!o.V && o.Ue & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
1630
1682
|
}
|
|
1631
1683
|
forEachDependent(o, settle);
|
|
1632
1684
|
};
|
|
@@ -1652,10 +1704,10 @@ function handleAsync(e, t, n) {
|
|
|
1652
1704
|
});
|
|
1653
1705
|
}
|
|
1654
1706
|
if (!i && !r) {
|
|
1655
|
-
e.
|
|
1707
|
+
e.lt = null;
|
|
1656
1708
|
return t;
|
|
1657
1709
|
}
|
|
1658
|
-
e.
|
|
1710
|
+
e.lt = t;
|
|
1659
1711
|
let o;
|
|
1660
1712
|
// Settle-time transition re-entry. The loading rail is invisible to
|
|
1661
1713
|
// transactions (#2933): a boundary-caught first load never registers as an
|
|
@@ -1669,7 +1721,7 @@ function handleAsync(e, t, n) {
|
|
|
1669
1721
|
// are the transaction's reveal machinery and always re-enter.
|
|
1670
1722
|
const settleTransition = () => {
|
|
1671
1723
|
const t = resolveTransition(e);
|
|
1672
|
-
if (t && e.
|
|
1724
|
+
if (t && e.Qe & STATUS_UNINITIALIZED && !currentTransition(t).M.has(e)) {
|
|
1673
1725
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1674
1726
|
// stash-path restamp both re-enter the transaction through it.
|
|
1675
1727
|
e.T = null;
|
|
@@ -1678,7 +1730,7 @@ function handleAsync(e, t, n) {
|
|
|
1678
1730
|
globalQueue.initTransition(t);
|
|
1679
1731
|
};
|
|
1680
1732
|
const handleError = n => {
|
|
1681
|
-
if (e.
|
|
1733
|
+
if (e.lt !== t) return;
|
|
1682
1734
|
settleTransition();
|
|
1683
1735
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1684
1736
|
const r = n instanceof NotReadyError;
|
|
@@ -1690,13 +1742,13 @@ function handleAsync(e, t, n) {
|
|
|
1690
1742
|
if (!r) releaseSettledDependents(e);
|
|
1691
1743
|
};
|
|
1692
1744
|
const asyncWrite = (r, i) => {
|
|
1693
|
-
if (e.
|
|
1745
|
+
if (e.lt !== t) return;
|
|
1694
1746
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1695
1747
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1696
1748
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1697
|
-
if (e.
|
|
1749
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1698
1750
|
settleTransition();
|
|
1699
|
-
const o = !!(e.
|
|
1751
|
+
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
1700
1752
|
trimStaleDeps(e);
|
|
1701
1753
|
clearStatus(e);
|
|
1702
1754
|
const s = resolveLane(e);
|
|
@@ -1723,22 +1775,22 @@ function handleAsync(e, t, n) {
|
|
|
1723
1775
|
// only notified when the hold is visible to them: under an active
|
|
1724
1776
|
// override every reader sees the override (A17), so waking subs would
|
|
1725
1777
|
// re-show an unchanged view — the revert is the notification point.
|
|
1726
|
-
GlobalQueue.
|
|
1778
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1727
1779
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1728
1780
|
e.F = clock;
|
|
1729
1781
|
} else if (s) {
|
|
1730
1782
|
// Route through lane's effect queue for independent flushing
|
|
1731
|
-
const t = e.
|
|
1732
|
-
const n = e.
|
|
1733
|
-
const i = e.
|
|
1783
|
+
const t = e.Fe;
|
|
1784
|
+
const n = e.We;
|
|
1785
|
+
const i = e.ht;
|
|
1734
1786
|
try {
|
|
1735
1787
|
if (!t && o || !i || !i(r, n)) {
|
|
1736
|
-
e.
|
|
1788
|
+
e.We = r;
|
|
1737
1789
|
e.F = clock;
|
|
1738
1790
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1739
1791
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1740
1792
|
// (computePendingState doesn't read _value).
|
|
1741
|
-
GlobalQueue.
|
|
1793
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1742
1794
|
insertSubs(e, true);
|
|
1743
1795
|
}
|
|
1744
1796
|
} catch (t) {
|
|
@@ -1770,7 +1822,7 @@ function handleAsync(e, t, n) {
|
|
|
1770
1822
|
// Returns whether the node released, so the iterator branch can stop
|
|
1771
1823
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1772
1824
|
const settleAutodispose = () => {
|
|
1773
|
-
if (e.
|
|
1825
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.V && !(e.Qe & STATUS_PENDING)) {
|
|
1774
1826
|
unobserved(e);
|
|
1775
1827
|
return true;
|
|
1776
1828
|
}
|
|
@@ -1833,7 +1885,7 @@ function handleAsync(e, t, n) {
|
|
|
1833
1885
|
u = n;
|
|
1834
1886
|
a = true;
|
|
1835
1887
|
if (n.done) i = true;
|
|
1836
|
-
} else if (e.
|
|
1888
|
+
} else if (e.lt !== t) {
|
|
1837
1889
|
return;
|
|
1838
1890
|
} else if (!n.done) {
|
|
1839
1891
|
r = true;
|
|
@@ -1853,7 +1905,7 @@ function handleAsync(e, t, n) {
|
|
|
1853
1905
|
if (f) {
|
|
1854
1906
|
l = n;
|
|
1855
1907
|
c = true;
|
|
1856
|
-
} else if (e.
|
|
1908
|
+
} else if (e.lt === t) {
|
|
1857
1909
|
i = true;
|
|
1858
1910
|
handleError(n);
|
|
1859
1911
|
settleAutodispose();
|
|
@@ -1886,19 +1938,19 @@ function handleAsync(e, t, n) {
|
|
|
1886
1938
|
}
|
|
1887
1939
|
|
|
1888
1940
|
function clearStatus(e, t = false) {
|
|
1889
|
-
if (e
|
|
1890
|
-
if (e.
|
|
1941
|
+
if (e.je) clearPendingSources(e);
|
|
1942
|
+
if (e.At) e.At = false;
|
|
1891
1943
|
// The pending window is over; its quiet classification dies with it.
|
|
1892
1944
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1893
1945
|
// plain store to an existing slot — no shape change.)
|
|
1894
|
-
e.
|
|
1895
|
-
e.
|
|
1896
|
-
if (e.
|
|
1946
|
+
e.Nt = false;
|
|
1947
|
+
e.Qe = t ? 0 : e.Qe & STATUS_UNINITIALIZED;
|
|
1948
|
+
if (e.we) setPendingError(e);
|
|
1897
1949
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1898
1950
|
// once the verdict layer created them, which installs the hooks).
|
|
1899
|
-
if (e._ || e.
|
|
1900
|
-
if (e.
|
|
1901
|
-
if (e.
|
|
1951
|
+
if (e._ || e.R) GlobalQueue.ae(e);
|
|
1952
|
+
if (e.rt && GlobalQueue.ce !== null) GlobalQueue.ce(e);
|
|
1953
|
+
if (e.yt) e.yt();
|
|
1902
1954
|
}
|
|
1903
1955
|
|
|
1904
1956
|
function notifyStatus(e, t, n, r, i) {
|
|
@@ -1911,43 +1963,43 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1911
1963
|
if (!r) {
|
|
1912
1964
|
if (t === STATUS_PENDING && o) {
|
|
1913
1965
|
addPendingSource(e, o);
|
|
1914
|
-
e.
|
|
1966
|
+
e.Qe = STATUS_PENDING | e.Qe & STATUS_UNINITIALIZED;
|
|
1915
1967
|
// Preserve the current source on this propagation so render-effect notification
|
|
1916
1968
|
// can register every distinct pending source with the transition.
|
|
1917
1969
|
setPendingError(e, o, n);
|
|
1918
1970
|
} else {
|
|
1919
1971
|
clearPendingSources(e);
|
|
1920
|
-
e.
|
|
1921
|
-
e.
|
|
1972
|
+
e.Qe = t | (t !== STATUS_ERROR ? e.Qe & STATUS_UNINITIALIZED : 0);
|
|
1973
|
+
e.we = n;
|
|
1922
1974
|
}
|
|
1923
|
-
GlobalQueue.
|
|
1924
|
-
if (e.
|
|
1975
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e);
|
|
1976
|
+
if (e.rt && GlobalQueue.ce !== null) GlobalQueue.ce(e);
|
|
1925
1977
|
}
|
|
1926
1978
|
if (i && !r) {
|
|
1927
1979
|
assignOrMergeLane(e, i);
|
|
1928
1980
|
}
|
|
1929
1981
|
const a = r || l;
|
|
1930
1982
|
const c = r || u ? undefined : i;
|
|
1931
|
-
if (e.
|
|
1983
|
+
if (e.yt) {
|
|
1932
1984
|
if (r && t === STATUS_PENDING) {
|
|
1933
1985
|
return;
|
|
1934
1986
|
}
|
|
1935
1987
|
if (a) {
|
|
1936
|
-
e.
|
|
1988
|
+
e.yt(t, n);
|
|
1937
1989
|
} else {
|
|
1938
|
-
e.
|
|
1990
|
+
e.yt();
|
|
1939
1991
|
}
|
|
1940
1992
|
return;
|
|
1941
1993
|
}
|
|
1942
1994
|
forEachDependent(e, (e, r) => {
|
|
1943
1995
|
e.F = clock;
|
|
1944
|
-
if (t === STATUS_PENDING && o && !e
|
|
1996
|
+
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.we !== n || e.je)) {
|
|
1945
1997
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1946
1998
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1947
1999
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1948
2000
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1949
2001
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1950
|
-
if (r.
|
|
2002
|
+
if (r._t && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1951
2003
|
enqueueSub(e);
|
|
1952
2004
|
schedule();
|
|
1953
2005
|
return;
|
|
@@ -1958,9 +2010,9 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1958
2010
|
});
|
|
1959
2011
|
}
|
|
1960
2012
|
|
|
1961
|
-
GlobalQueue.
|
|
2013
|
+
GlobalQueue.X = recompute;
|
|
1962
2014
|
|
|
1963
|
-
GlobalQueue.
|
|
2015
|
+
GlobalQueue.J = disposeChildren;
|
|
1964
2016
|
|
|
1965
2017
|
let tracking = false;
|
|
1966
2018
|
|
|
@@ -1992,7 +2044,7 @@ let snapshotSources = null;
|
|
|
1992
2044
|
|
|
1993
2045
|
function ownerInSnapshotScope(e) {
|
|
1994
2046
|
while (e) {
|
|
1995
|
-
if (e.
|
|
2047
|
+
if (e.Pt) return true;
|
|
1996
2048
|
e = e.B;
|
|
1997
2049
|
}
|
|
1998
2050
|
return false;
|
|
@@ -2004,41 +2056,41 @@ function setSnapshotCapture(e) {
|
|
|
2004
2056
|
}
|
|
2005
2057
|
|
|
2006
2058
|
function markSnapshotScope(e) {
|
|
2007
|
-
e.
|
|
2059
|
+
e.Pt = true;
|
|
2008
2060
|
}
|
|
2009
2061
|
|
|
2010
2062
|
function releaseSnapshotScope(e) {
|
|
2011
|
-
e.
|
|
2063
|
+
e.Pt = false;
|
|
2012
2064
|
releaseSubtree(e);
|
|
2013
2065
|
schedule();
|
|
2014
2066
|
}
|
|
2015
2067
|
|
|
2016
2068
|
function releaseSubtree(e) {
|
|
2017
|
-
let t = e.
|
|
2069
|
+
let t = e.ot;
|
|
2018
2070
|
while (t) {
|
|
2019
|
-
if (t.
|
|
2020
|
-
t = t.
|
|
2071
|
+
if (t.Pt) {
|
|
2072
|
+
t = t.st;
|
|
2021
2073
|
continue;
|
|
2022
2074
|
}
|
|
2023
|
-
if (t.
|
|
2075
|
+
if (t.ke) {
|
|
2024
2076
|
const e = t;
|
|
2025
|
-
e.
|
|
2026
|
-
if (e.
|
|
2027
|
-
e.
|
|
2028
|
-
e.
|
|
2029
|
-
if (dirtyQueue.P > e.
|
|
2077
|
+
e.Ue &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
2078
|
+
if (e.Ge & REACTIVE_SNAPSHOT_STALE) {
|
|
2079
|
+
e.Ge &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2080
|
+
e.Ge |= REACTIVE_DIRTY;
|
|
2081
|
+
if (dirtyQueue.P > e.ze) dirtyQueue.P = e.ze;
|
|
2030
2082
|
insertIntoHeap(e, dirtyQueue);
|
|
2031
2083
|
}
|
|
2032
2084
|
}
|
|
2033
2085
|
releaseSubtree(t);
|
|
2034
|
-
t = t.
|
|
2086
|
+
t = t.st;
|
|
2035
2087
|
}
|
|
2036
2088
|
}
|
|
2037
2089
|
|
|
2038
2090
|
function clearSnapshots() {
|
|
2039
2091
|
if (snapshotSources) {
|
|
2040
2092
|
for (const e of snapshotSources) {
|
|
2041
|
-
delete e.
|
|
2093
|
+
delete e.ve;
|
|
2042
2094
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
2043
2095
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
2044
2096
|
// when present so signal-node sources don't grow the field.
|
|
@@ -2050,37 +2102,41 @@ function clearSnapshots() {
|
|
|
2050
2102
|
}
|
|
2051
2103
|
|
|
2052
2104
|
function recompute(e, t = false) {
|
|
2053
|
-
const n = e.
|
|
2105
|
+
const n = e.Fe;
|
|
2054
2106
|
if (!t) {
|
|
2055
2107
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
2056
2108
|
deleteFromHeap(e, queueFor(e));
|
|
2057
|
-
e.
|
|
2109
|
+
e.lt = null;
|
|
2058
2110
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
2059
|
-
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.
|
|
2111
|
+
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ot !== null || e.dt !== null) {
|
|
2060
2112
|
markDisposal(e);
|
|
2061
|
-
e.
|
|
2062
|
-
e.
|
|
2063
|
-
e.
|
|
2064
|
-
e.
|
|
2065
|
-
e.
|
|
2113
|
+
e.Me = e.dt;
|
|
2114
|
+
e.He = e.ot;
|
|
2115
|
+
e.dt = null;
|
|
2116
|
+
e.ot = null;
|
|
2117
|
+
e.ct = 0;
|
|
2066
2118
|
} else ;
|
|
2067
2119
|
}
|
|
2068
|
-
let r = !!(e.
|
|
2120
|
+
let r = !!(e.Ge & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2069
2121
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
2070
|
-
const o = !!(e.
|
|
2122
|
+
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
2123
|
+
// Outgoing error, captured before the compute clears status: if this run
|
|
2124
|
+
// recovers to an unchanged value, dependents still holding this object must
|
|
2125
|
+
// be swept (settleErroredDependents, #2949).
|
|
2126
|
+
const s = e.Qe & STATUS_ERROR ? e.we : undefined;
|
|
2071
2127
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2072
2128
|
// the recompute wipes _flags below.
|
|
2073
|
-
const
|
|
2074
|
-
const
|
|
2129
|
+
const u = (e.Ge & REACTIVE_REASK) !== 0;
|
|
2130
|
+
const l = context;
|
|
2075
2131
|
context = e;
|
|
2076
|
-
e.
|
|
2077
|
-
e.
|
|
2078
|
-
e.
|
|
2132
|
+
e.ut = null;
|
|
2133
|
+
e.It++;
|
|
2134
|
+
e.Ge = REACTIVE_RECOMPUTING_DEPS;
|
|
2079
2135
|
e.F = clock;
|
|
2080
|
-
let
|
|
2081
|
-
let
|
|
2082
|
-
let
|
|
2083
|
-
let
|
|
2136
|
+
let a = e.U === NOT_PENDING ? e.We : e.U;
|
|
2137
|
+
let c = e.ze;
|
|
2138
|
+
let f = tracking;
|
|
2139
|
+
let E = currentOptimisticLane;
|
|
2084
2140
|
tracking = true;
|
|
2085
2141
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
2086
2142
|
// inside a latest() read window: read() short-circuits through the
|
|
@@ -2088,74 +2144,74 @@ function recompute(e, t = false) {
|
|
|
2088
2144
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
2089
2145
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
2090
2146
|
// covers creation-time computes and flushes that run inside the window.
|
|
2091
|
-
const
|
|
2147
|
+
const d = latestReadActive;
|
|
2092
2148
|
latestReadActive = false;
|
|
2093
2149
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
2094
2150
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2095
2151
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2096
2152
|
if (r) {
|
|
2097
|
-
const t = GlobalQueue.
|
|
2153
|
+
const t = GlobalQueue.Ce(e, true);
|
|
2098
2154
|
if (t) currentOptimisticLane = t;
|
|
2099
2155
|
} else if (activeTransition && !t && activeTransition.v.length) {
|
|
2100
2156
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2101
2157
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2102
2158
|
// recomputes under the right posture and propagates correctly.
|
|
2103
|
-
const t = GlobalQueue.
|
|
2159
|
+
const t = GlobalQueue.Ce(e, false);
|
|
2104
2160
|
if (t) {
|
|
2105
2161
|
r = true;
|
|
2106
2162
|
currentOptimisticLane = t;
|
|
2107
2163
|
}
|
|
2108
2164
|
}
|
|
2109
|
-
const
|
|
2110
|
-
const
|
|
2111
|
-
if (
|
|
2165
|
+
const S = n && n !== EFFECT_USER;
|
|
2166
|
+
const T = stale;
|
|
2167
|
+
if (S) stale = true;
|
|
2112
2168
|
try {
|
|
2113
|
-
if (!false && e.
|
|
2114
|
-
|
|
2115
|
-
e.
|
|
2169
|
+
if (!false && e.Ue & CONFIG_SYNC) {
|
|
2170
|
+
a = e.ke(a);
|
|
2171
|
+
e.lt = null;
|
|
2116
2172
|
} else {
|
|
2117
2173
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2118
2174
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2119
2175
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2120
2176
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2121
2177
|
// iteration drive updates.
|
|
2122
|
-
const t = e.
|
|
2123
|
-
const n = e.
|
|
2178
|
+
const t = e.lt;
|
|
2179
|
+
const n = e.ke(a);
|
|
2124
2180
|
const r = typeof n === "object" && n !== null;
|
|
2125
|
-
const i = e.
|
|
2126
|
-
|
|
2127
|
-
if (!i && !r) e.
|
|
2181
|
+
const i = e.lt !== t;
|
|
2182
|
+
a = i || !r ? n : handleAsync(e, n);
|
|
2183
|
+
if (!i && !r) e.lt = null;
|
|
2128
2184
|
}
|
|
2129
2185
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2130
2186
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2131
2187
|
// the flags write (create or not) stores the 0 already there.
|
|
2132
|
-
if (e.
|
|
2188
|
+
if (e.Qe !== 0 || e.yt !== undefined || e.we || e.Nt || e.At || e.je !== undefined || e._ !== undefined || e.R !== undefined || e.rt !== null) clearStatus(e, t);
|
|
2133
2189
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2134
|
-
if (e.i) GlobalQueue.
|
|
2190
|
+
if (e.i) GlobalQueue.be(e);
|
|
2135
2191
|
} catch (t) {
|
|
2136
2192
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2137
2193
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2138
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2194
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.ge(e);
|
|
2139
2195
|
let n = false;
|
|
2140
2196
|
if (t instanceof NotReadyError) {
|
|
2141
|
-
e.
|
|
2142
|
-
if (GlobalQueue.
|
|
2197
|
+
e.At = true;
|
|
2198
|
+
if (GlobalQueue.Te !== null) n = GlobalQueue.Te(e, u);
|
|
2143
2199
|
}
|
|
2144
2200
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2145
|
-
if (n) GlobalQueue.
|
|
2201
|
+
if (n) GlobalQueue.Oe(e);
|
|
2146
2202
|
} finally {
|
|
2147
|
-
tracking =
|
|
2148
|
-
latestReadActive =
|
|
2149
|
-
if (
|
|
2150
|
-
e.
|
|
2151
|
-
context =
|
|
2203
|
+
tracking = f;
|
|
2204
|
+
latestReadActive = d;
|
|
2205
|
+
if (S) stale = T;
|
|
2206
|
+
e.Ge = REACTIVE_NONE | (t ? e.Ge & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2207
|
+
context = l;
|
|
2152
2208
|
}
|
|
2153
|
-
if (!e.
|
|
2209
|
+
if (!e.we) {
|
|
2154
2210
|
trimStaleDeps(e);
|
|
2155
|
-
const
|
|
2156
|
-
let
|
|
2211
|
+
const u = i ? unwrapOverride(e.A) : e.U === NOT_PENDING ? e.We : e.U;
|
|
2212
|
+
let l = false;
|
|
2157
2213
|
try {
|
|
2158
|
-
|
|
2214
|
+
l = !n && o || !e.ht || !e.ht(u, a);
|
|
2159
2215
|
} catch (t) {
|
|
2160
2216
|
// A throwing user comparator is an error of this node's computation.
|
|
2161
2217
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2168,13 +2224,13 @@ function recompute(e, t = false) {
|
|
|
2168
2224
|
// its runner — happen here instead. `!create` matches the previous `initialized`
|
|
2169
2225
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2170
2226
|
// effect() can call its runner synchronously for the first run.
|
|
2171
|
-
if (n &&
|
|
2172
|
-
e.
|
|
2227
|
+
if (n && l) {
|
|
2228
|
+
e.xe = !e.we;
|
|
2173
2229
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2174
2230
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2175
|
-
if (!t) e.
|
|
2231
|
+
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.ee.bind(null, e));
|
|
2176
2232
|
}
|
|
2177
|
-
if (e.
|
|
2233
|
+
if (e.we) ; else if (l) {
|
|
2178
2234
|
const o = i ? e.A : undefined;
|
|
2179
2235
|
if (t ||
|
|
2180
2236
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2182,104 +2238,110 @@ function recompute(e, t = false) {
|
|
|
2182
2238
|
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2183
2239
|
// paying it per effect on the plain path is pure overhead.
|
|
2184
2240
|
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2185
|
-
e.
|
|
2241
|
+
e.We = a;
|
|
2186
2242
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2187
2243
|
// override unconditionally. The direct _value commit is the lane's
|
|
2188
2244
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
2189
2245
|
// commit can't clobber the fresh value.
|
|
2190
2246
|
if (i && r) {
|
|
2191
|
-
e.A =
|
|
2247
|
+
e.A = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
2192
2248
|
e.U = NOT_PENDING;
|
|
2193
2249
|
}
|
|
2194
2250
|
} else {
|
|
2195
|
-
e.U =
|
|
2251
|
+
e.U = a;
|
|
2196
2252
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2197
2253
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2198
2254
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2199
2255
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2200
2256
|
// pending value commits before effects run.
|
|
2201
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2257
|
+
if ((activeTransition || e.T) && GlobalQueue.le !== null) GlobalQueue.le(e, a);
|
|
2202
2258
|
}
|
|
2203
2259
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2204
2260
|
// subscriber-less node has nothing to notify.
|
|
2205
|
-
if (e.
|
|
2261
|
+
if (e.V !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2206
2262
|
} else if (i) {
|
|
2207
2263
|
// Unchanged value (equals the override) recomputed while the override
|
|
2208
2264
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2209
2265
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2210
2266
|
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2211
|
-
e.U =
|
|
2212
|
-
} else if (e.
|
|
2213
|
-
for (let t = e.
|
|
2267
|
+
e.U = a;
|
|
2268
|
+
} else if (e.ze != c) {
|
|
2269
|
+
for (let t = e.V; t !== null; t = t.Le) {
|
|
2214
2270
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2215
2271
|
}
|
|
2216
2272
|
}
|
|
2273
|
+
// Silent recovery: errored → unchanged value fires no notification, but
|
|
2274
|
+
// dependents still holding the propagated error consumed their dirty flag
|
|
2275
|
+
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
2276
|
+
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2277
|
+
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
2278
|
+
if (s !== undefined && !l && !e.we) settleErroredDependents(e, s);
|
|
2217
2279
|
}
|
|
2218
|
-
currentOptimisticLane =
|
|
2219
|
-
const
|
|
2280
|
+
currentOptimisticLane = E;
|
|
2281
|
+
const O = e.U !== NOT_PENDING || e.He !== null || e.Me !== null || (e.Qe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2220
2282
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2221
2283
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2222
2284
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2223
2285
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2224
2286
|
// _transition.
|
|
2225
|
-
|
|
2287
|
+
O && (!t || e.Qe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2226
2288
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2227
2289
|
}
|
|
2228
2290
|
|
|
2229
2291
|
function updateIfNecessary(e) {
|
|
2230
|
-
if (e.
|
|
2231
|
-
for (let t = e.
|
|
2232
|
-
const n = t.
|
|
2233
|
-
const r = n.
|
|
2234
|
-
if (r.
|
|
2292
|
+
if (e.Ge & REACTIVE_CHECK) {
|
|
2293
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
2294
|
+
const n = t.qe;
|
|
2295
|
+
const r = n.Be || n;
|
|
2296
|
+
if (r.ke) {
|
|
2235
2297
|
updateIfNecessary(r);
|
|
2236
2298
|
}
|
|
2237
|
-
if (e.
|
|
2299
|
+
if (e.Ge & REACTIVE_DIRTY) {
|
|
2238
2300
|
break;
|
|
2239
2301
|
}
|
|
2240
2302
|
}
|
|
2241
2303
|
}
|
|
2242
|
-
if (e.
|
|
2304
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.we && e.F < clock && !e.lt) {
|
|
2243
2305
|
recompute(e);
|
|
2244
2306
|
}
|
|
2245
|
-
e.
|
|
2307
|
+
e.Ge = e.Ge & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2246
2308
|
}
|
|
2247
2309
|
|
|
2248
2310
|
function computed(e, t) {
|
|
2249
2311
|
const n = t?.transparent ?? false;
|
|
2250
2312
|
const r = {
|
|
2251
2313
|
id: inheritId(t, n, context),
|
|
2252
|
-
|
|
2253
|
-
|
|
2314
|
+
Ue: (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),
|
|
2315
|
+
ht: t?.equals != null ? t.equals : isEqual,
|
|
2254
2316
|
W: t?.unobserved,
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2317
|
+
dt: null,
|
|
2318
|
+
Ze: context?.Ze ?? globalQueue,
|
|
2319
|
+
St: context?.St ?? defaultContext,
|
|
2320
|
+
ct: 0,
|
|
2321
|
+
ke: e,
|
|
2322
|
+
We: undefined,
|
|
2323
|
+
ze: 0,
|
|
2324
|
+
rt: null,
|
|
2325
|
+
nt: undefined,
|
|
2326
|
+
tt: null,
|
|
2327
|
+
Ke: null,
|
|
2328
|
+
ut: null,
|
|
2329
|
+
It: 0,
|
|
2330
|
+
V: null,
|
|
2331
|
+
Ot: null,
|
|
2270
2332
|
B: context,
|
|
2333
|
+
st: null,
|
|
2334
|
+
ft: null,
|
|
2271
2335
|
ot: null,
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2275
|
-
xe: STATUS_UNINITIALIZED,
|
|
2336
|
+
Ge: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2337
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2276
2338
|
F: clock,
|
|
2277
2339
|
U: NOT_PENDING,
|
|
2340
|
+
Me: null,
|
|
2278
2341
|
He: null,
|
|
2279
|
-
|
|
2280
|
-
ut: null,
|
|
2342
|
+
lt: null,
|
|
2281
2343
|
T: null,
|
|
2282
|
-
|
|
2344
|
+
Nt: false
|
|
2283
2345
|
};
|
|
2284
2346
|
setupComputedNode(r, t);
|
|
2285
2347
|
return r;
|
|
@@ -2294,44 +2356,44 @@ function computed(e, t) {
|
|
|
2294
2356
|
const s = o?.transparent ?? false;
|
|
2295
2357
|
const u = {
|
|
2296
2358
|
id: inheritId(o, s, context),
|
|
2297
|
-
|
|
2298
|
-
|
|
2359
|
+
Ue: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2360
|
+
ht: false,
|
|
2299
2361
|
W: o?.unobserved,
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2362
|
+
dt: null,
|
|
2363
|
+
Ze: context?.Ze ?? globalQueue,
|
|
2364
|
+
St: context?.St ?? defaultContext,
|
|
2365
|
+
ct: 0,
|
|
2366
|
+
ke: e,
|
|
2367
|
+
We: undefined,
|
|
2368
|
+
ze: 0,
|
|
2369
|
+
rt: null,
|
|
2370
|
+
nt: undefined,
|
|
2371
|
+
tt: null,
|
|
2372
|
+
Ke: null,
|
|
2373
|
+
ut: null,
|
|
2374
|
+
It: 0,
|
|
2375
|
+
V: null,
|
|
2376
|
+
Ot: null,
|
|
2315
2377
|
B: context,
|
|
2378
|
+
st: null,
|
|
2379
|
+
ft: null,
|
|
2316
2380
|
ot: null,
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
Le: REACTIVE_LAZY,
|
|
2320
|
-
xe: STATUS_UNINITIALIZED,
|
|
2381
|
+
Ge: REACTIVE_LAZY,
|
|
2382
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2321
2383
|
F: clock,
|
|
2322
2384
|
U: NOT_PENDING,
|
|
2385
|
+
Me: null,
|
|
2323
2386
|
He: null,
|
|
2324
|
-
|
|
2325
|
-
ut: null,
|
|
2387
|
+
lt: null,
|
|
2326
2388
|
T: null,
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2389
|
+
Nt: false,
|
|
2390
|
+
xe: false,
|
|
2391
|
+
bt: undefined,
|
|
2392
|
+
Dt: t,
|
|
2393
|
+
wt: n,
|
|
2394
|
+
Et: undefined,
|
|
2395
|
+
Fe: r,
|
|
2396
|
+
yt: i
|
|
2335
2397
|
};
|
|
2336
2398
|
setupComputedNode(u, lazyOptions);
|
|
2337
2399
|
return u;
|
|
@@ -2342,24 +2404,24 @@ const lazyOptions = {
|
|
|
2342
2404
|
};
|
|
2343
2405
|
|
|
2344
2406
|
function setupComputedNode(e, t) {
|
|
2345
|
-
e.
|
|
2346
|
-
const n = context?.
|
|
2407
|
+
e.tt = e;
|
|
2408
|
+
const n = context?.Je ? context.et : context;
|
|
2347
2409
|
if (context) {
|
|
2348
|
-
const t = context.
|
|
2410
|
+
const t = context.ot;
|
|
2349
2411
|
if (t === null) {
|
|
2350
|
-
context.
|
|
2412
|
+
context.ot = e;
|
|
2351
2413
|
} else {
|
|
2352
|
-
e.
|
|
2353
|
-
t.
|
|
2354
|
-
context.
|
|
2414
|
+
e.st = t;
|
|
2415
|
+
t.ft = e;
|
|
2416
|
+
context.ot = e;
|
|
2355
2417
|
}
|
|
2356
2418
|
}
|
|
2357
|
-
if (n) e.
|
|
2358
|
-
if (GlobalQueue.
|
|
2419
|
+
if (n) e.ze = n.ze + 1;
|
|
2420
|
+
if (GlobalQueue.se !== null) GlobalQueue.se(e);
|
|
2359
2421
|
!t?.lazy && recompute(e, true);
|
|
2360
2422
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2361
|
-
if (!(e.
|
|
2362
|
-
e.
|
|
2423
|
+
if (!(e.Qe & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2424
|
+
e.ve = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2363
2425
|
snapshotSources.add(e);
|
|
2364
2426
|
}
|
|
2365
2427
|
}
|
|
@@ -2367,20 +2429,20 @@ function setupComputedNode(e, t) {
|
|
|
2367
2429
|
|
|
2368
2430
|
function signal(e, t, n = null) {
|
|
2369
2431
|
const r = {
|
|
2370
|
-
|
|
2371
|
-
|
|
2432
|
+
ht: t?.equals != null ? t.equals : isEqual,
|
|
2433
|
+
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2372
2434
|
W: t?.unobserved,
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2435
|
+
We: e,
|
|
2436
|
+
V: null,
|
|
2437
|
+
Ot: null,
|
|
2376
2438
|
F: clock,
|
|
2377
|
-
|
|
2378
|
-
|
|
2439
|
+
Be: n,
|
|
2440
|
+
it: n?.rt || null,
|
|
2379
2441
|
U: NOT_PENDING
|
|
2380
2442
|
};
|
|
2381
|
-
n && (n.
|
|
2382
|
-
if (snapshotCaptureActive && !(r.
|
|
2383
|
-
r.
|
|
2443
|
+
n && (n.rt = r);
|
|
2444
|
+
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.Qe ?? 0) & STATUS_PENDING)) {
|
|
2445
|
+
r.ve = e === undefined ? NO_SNAPSHOT : e;
|
|
2384
2446
|
snapshotSources.add(r);
|
|
2385
2447
|
}
|
|
2386
2448
|
return r;
|
|
@@ -2424,11 +2486,11 @@ function isEqual(e, t) {
|
|
|
2424
2486
|
* );
|
|
2425
2487
|
* ```
|
|
2426
2488
|
*/ function untrack(e, t) {
|
|
2427
|
-
if (GlobalQueue.
|
|
2489
|
+
if (GlobalQueue.ue === null && !tracking && true) return e();
|
|
2428
2490
|
const n = tracking;
|
|
2429
2491
|
tracking = false;
|
|
2430
2492
|
try {
|
|
2431
|
-
if (GlobalQueue.
|
|
2493
|
+
if (GlobalQueue.ue !== null) return GlobalQueue.ue(e);
|
|
2432
2494
|
return e();
|
|
2433
2495
|
} finally {
|
|
2434
2496
|
tracking = n;
|
|
@@ -2440,10 +2502,10 @@ function isEqual(e, t) {
|
|
|
2440
2502
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2441
2503
|
* date so its status flags reflect the current graph.
|
|
2442
2504
|
*/ function prepareComputed(e, t) {
|
|
2443
|
-
if (e.
|
|
2444
|
-
e.
|
|
2505
|
+
if (e.Ge & REACTIVE_LAZY) {
|
|
2506
|
+
e.Ge &= ~REACTIVE_LAZY;
|
|
2445
2507
|
recompute(e, true);
|
|
2446
|
-
} else if (e.
|
|
2508
|
+
} else if (e.Ge & REACTIVE_DISPOSED) {
|
|
2447
2509
|
recompute(e, true);
|
|
2448
2510
|
} else if (t) {
|
|
2449
2511
|
updateIfNecessary(e);
|
|
@@ -2464,11 +2526,11 @@ function isEqual(e, t) {
|
|
|
2464
2526
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2465
2527
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2466
2528
|
*/ function readNodeFast(e) {
|
|
2467
|
-
if (latestReadActive || pendingCheckActive || e.
|
|
2529
|
+
if (latestReadActive || pendingCheckActive || e.ke || e.Be || e.A !== undefined || e.ve !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2468
2530
|
let t = context;
|
|
2469
|
-
if (t?.
|
|
2531
|
+
if (t?.Je) t = t.et;
|
|
2470
2532
|
if (t && tracking) link(e, t);
|
|
2471
|
-
return !t || e.U === NOT_PENDING ? e.
|
|
2533
|
+
return !t || e.U === NOT_PENDING ? e.We : e.U;
|
|
2472
2534
|
}
|
|
2473
2535
|
|
|
2474
2536
|
function read(e) {
|
|
@@ -2476,72 +2538,76 @@ function read(e) {
|
|
|
2476
2538
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2477
2539
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2478
2540
|
// than the original node (which stays "pending" while held in a transition).
|
|
2479
|
-
if (latestReadActive) return GlobalQueue.
|
|
2541
|
+
if (latestReadActive) return GlobalQueue.Ee(e);
|
|
2480
2542
|
let t = context;
|
|
2481
|
-
if (t?.
|
|
2543
|
+
if (t?.Je) t = t.et;
|
|
2482
2544
|
const n = e;
|
|
2483
|
-
const r = e.
|
|
2545
|
+
const r = e.Be;
|
|
2484
2546
|
const i = r || e;
|
|
2485
2547
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2486
2548
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2487
2549
|
// recompute don't collect into the probe.
|
|
2488
2550
|
if (pendingCheckActive) {
|
|
2489
|
-
GlobalQueue.
|
|
2490
|
-
} else if (typeof n.
|
|
2551
|
+
GlobalQueue.de(e, t, i, r);
|
|
2552
|
+
} else if (typeof n.ke === "function") {
|
|
2491
2553
|
prepareComputed(e, false);
|
|
2492
2554
|
}
|
|
2493
|
-
if (!n.
|
|
2555
|
+
if (!n.ke && i === e && e.A === undefined && e.ve === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2494
2556
|
if (t && tracking) link(e, t);
|
|
2495
|
-
return !t || e.U === NOT_PENDING ? e.
|
|
2557
|
+
return !t || e.U === NOT_PENDING ? e.We : e.U;
|
|
2496
2558
|
}
|
|
2497
2559
|
if (t && tracking) {
|
|
2498
2560
|
link(e, t, pendingCheckActive);
|
|
2499
|
-
if (i.
|
|
2561
|
+
if (i.ke) {
|
|
2500
2562
|
const n = queueFor(e);
|
|
2501
|
-
if (i.
|
|
2563
|
+
if (i.ze >= n.P) {
|
|
2502
2564
|
markNode(t);
|
|
2503
2565
|
markHeap(n);
|
|
2504
2566
|
updateIfNecessary(i);
|
|
2505
2567
|
}
|
|
2506
|
-
const r = i.
|
|
2568
|
+
const r = i.ze;
|
|
2507
2569
|
// parent check is shallow, might need to be recursive
|
|
2508
|
-
if (r >= t.
|
|
2509
|
-
t.
|
|
2570
|
+
if (r >= t.ze && e.B !== t) {
|
|
2571
|
+
t.ze = r + 1;
|
|
2510
2572
|
}
|
|
2511
2573
|
}
|
|
2512
2574
|
}
|
|
2513
|
-
if (i.
|
|
2575
|
+
if (i.Qe & STATUS_PENDING) {
|
|
2514
2576
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2515
2577
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2516
2578
|
// is installed): under a lane, only same-lane pending async without an
|
|
2517
2579
|
// active override throws.
|
|
2518
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2580
|
+
if (currentOptimisticLane === null || GlobalQueue.ye(i)) {
|
|
2519
2581
|
if (!tracking && e !== t) link(e, t);
|
|
2520
|
-
throw i.
|
|
2582
|
+
throw i.we;
|
|
2521
2583
|
}
|
|
2522
|
-
} else if (t && i !== e && i.
|
|
2584
|
+
} else if (t && i !== e && i.Qe & STATUS_UNINITIALIZED) {
|
|
2523
2585
|
if (!tracking && e !== t) link(e, t);
|
|
2524
|
-
throw i.
|
|
2525
|
-
} else if (!t && i.
|
|
2526
|
-
throw i.
|
|
2586
|
+
throw i.we;
|
|
2587
|
+
} else if (!t && i.Qe & STATUS_UNINITIALIZED) {
|
|
2588
|
+
throw i.we;
|
|
2527
2589
|
}
|
|
2528
2590
|
}
|
|
2529
|
-
|
|
2591
|
+
// `owner` is the computed itself, or the firewall behind a store node —
|
|
2592
|
+
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
2593
|
+
// an errored derive throws for every late reader instead of silently
|
|
2594
|
+
// serving node values (the seed, or last-good data after a failed refetch).
|
|
2595
|
+
if (i.ke && i.Qe & STATUS_ERROR) {
|
|
2530
2596
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2531
2597
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2532
2598
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2533
|
-
// -
|
|
2534
|
-
if (tracking && !pendingCheckActive &&
|
|
2535
|
-
recompute(
|
|
2599
|
+
// - owner._time < clock: only on a later cycle than the one the error was found
|
|
2600
|
+
if (tracking && !pendingCheckActive && i.F < clock) {
|
|
2601
|
+
recompute(i);
|
|
2536
2602
|
return read(e);
|
|
2537
|
-
} else throw
|
|
2603
|
+
} else throw i.we;
|
|
2538
2604
|
}
|
|
2539
|
-
if (snapshotCaptureActive && t && t.
|
|
2540
|
-
const n = e.
|
|
2605
|
+
if (snapshotCaptureActive && t && t.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2606
|
+
const n = e.ve;
|
|
2541
2607
|
if (n !== undefined) {
|
|
2542
2608
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2543
|
-
const i = e.U !== NOT_PENDING ? e.U : e.
|
|
2544
|
-
if (i !== r) t.
|
|
2609
|
+
const i = e.U !== NOT_PENDING ? e.U : e.We;
|
|
2610
|
+
if (i !== r) t.Ge |= REACTIVE_SNAPSHOT_STALE;
|
|
2545
2611
|
return r;
|
|
2546
2612
|
}
|
|
2547
2613
|
}
|
|
@@ -2556,18 +2622,18 @@ function read(e) {
|
|
|
2556
2622
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2557
2623
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2558
2624
|
// engine — a non-null lane implies it is installed.)
|
|
2559
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2560
|
-
return e.
|
|
2625
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ne(e, i, t)) {
|
|
2626
|
+
return e.We;
|
|
2561
2627
|
}
|
|
2562
2628
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2563
2629
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2564
2630
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2565
2631
|
// (The lane-context clause lives with the engine.)
|
|
2566
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2632
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.Pe(e, i, t) || e.U === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.We : e.U;
|
|
2567
2633
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2568
2634
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2569
|
-
if (pendingCheckActive) GlobalQueue.
|
|
2570
|
-
if (!t && i === e && typeof n.
|
|
2635
|
+
if (pendingCheckActive) GlobalQueue.Se(e, o);
|
|
2636
|
+
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.Qe & STATUS_PENDING) && !e.V) {
|
|
2571
2637
|
unobserved(e);
|
|
2572
2638
|
}
|
|
2573
2639
|
return o;
|
|
@@ -2579,19 +2645,19 @@ function setSignal(e, t) {
|
|
|
2579
2645
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2580
2646
|
// _overrideValue slot, and every module that creates one installs the
|
|
2581
2647
|
// engine first.
|
|
2582
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2583
|
-
const n = e.U === NOT_PENDING ? e.
|
|
2648
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.Re(e, t);
|
|
2649
|
+
const n = e.U === NOT_PENDING ? e.We : e.U;
|
|
2584
2650
|
if (typeof t === "function") t = t(n);
|
|
2585
2651
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2586
2652
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2587
|
-
const r = !!(e.
|
|
2653
|
+
const r = !!(e.Qe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(n, t);
|
|
2588
2654
|
if (!r) return t;
|
|
2589
2655
|
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2590
2656
|
e.U = t;
|
|
2591
2657
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2592
2658
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
2593
2659
|
// only ever created, never removed, and creating one installs the hook).
|
|
2594
|
-
(e._ !== undefined || e.
|
|
2660
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2595
2661
|
e.F = clock;
|
|
2596
2662
|
insertSubs(e);
|
|
2597
2663
|
schedule();
|
|
@@ -2606,11 +2672,11 @@ function setSignal(e, t) {
|
|
|
2606
2672
|
* cleanup point.
|
|
2607
2673
|
*/ function suppressComputedRecompute(e) {
|
|
2608
2674
|
deleteFromHeap(e, queueFor(e));
|
|
2609
|
-
if (!(e.
|
|
2675
|
+
if (!(e.Ge & REACTIVE_MANUAL_WRITE) && e.U === NOT_PENDING) {
|
|
2610
2676
|
queuePendingNode(e);
|
|
2611
2677
|
schedule();
|
|
2612
2678
|
}
|
|
2613
|
-
e.
|
|
2679
|
+
e.Ge = e.Ge & -4 | REACTIVE_MANUAL_WRITE;
|
|
2614
2680
|
}
|
|
2615
2681
|
|
|
2616
2682
|
/**
|
|
@@ -2689,7 +2755,7 @@ function staleValues(e, t = true) {
|
|
|
2689
2755
|
if (!t) {
|
|
2690
2756
|
return;
|
|
2691
2757
|
}
|
|
2692
|
-
if (typeof t.
|
|
2758
|
+
if (typeof t.ke === "function" && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2693
2759
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2694
2760
|
// same question: mark it so the recompute classifies any resulting
|
|
2695
2761
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2697,11 +2763,11 @@ function staleValues(e, t = true) {
|
|
|
2697
2763
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2698
2764
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2699
2765
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2700
|
-
if (!(t.
|
|
2701
|
-
t.
|
|
2766
|
+
if (!(t.Ge & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2767
|
+
t.Ge |= REACTIVE_REASK;
|
|
2702
2768
|
armReaskClear();
|
|
2703
2769
|
}
|
|
2704
|
-
t.
|
|
2770
|
+
t.Ge = t.Ge & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2705
2771
|
insertIntoHeap(t, queueFor(t));
|
|
2706
2772
|
schedule();
|
|
2707
2773
|
}
|
|
@@ -2749,11 +2815,11 @@ function wireExternalSource(e) {
|
|
|
2749
2815
|
equals: false,
|
|
2750
2816
|
ownedWrite: true
|
|
2751
2817
|
});
|
|
2752
|
-
const n = externalSourceConfig.factory(e.
|
|
2818
|
+
const n = externalSourceConfig.factory(e.ke, () => {
|
|
2753
2819
|
setSignal(t, undefined);
|
|
2754
2820
|
});
|
|
2755
2821
|
cleanup(() => n.dispose());
|
|
2756
|
-
e.
|
|
2822
|
+
e.ke = e => {
|
|
2757
2823
|
read(t);
|
|
2758
2824
|
return n.track(e);
|
|
2759
2825
|
};
|
|
@@ -2767,8 +2833,8 @@ function externalUntrack(e) {
|
|
|
2767
2833
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2768
2834
|
// `externalSourceConfig` truthiness checks.
|
|
2769
2835
|
function syncExternalHooks() {
|
|
2770
|
-
GlobalQueue.
|
|
2771
|
-
GlobalQueue.
|
|
2836
|
+
GlobalQueue.se = externalSourceConfig ? wireExternalSource : null;
|
|
2837
|
+
GlobalQueue.ue = externalSourceConfig ? externalUntrack : null;
|
|
2772
2838
|
}
|
|
2773
2839
|
|
|
2774
2840
|
function enableExternalSource(e) {
|
|
@@ -2825,7 +2891,7 @@ function enableExternalSource(e) {
|
|
|
2825
2891
|
if (!t) {
|
|
2826
2892
|
throw new NoOwnerError;
|
|
2827
2893
|
}
|
|
2828
|
-
const n = hasContext(e, t) ? t.
|
|
2894
|
+
const n = hasContext(e, t) ? t.St[e.id] : e.defaultValue;
|
|
2829
2895
|
if (isUndefined(n)) {
|
|
2830
2896
|
throw new ContextNotFoundError;
|
|
2831
2897
|
}
|
|
@@ -2846,14 +2912,14 @@ function enableExternalSource(e) {
|
|
|
2846
2912
|
}
|
|
2847
2913
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
2848
2914
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
2849
|
-
n.
|
|
2850
|
-
...n.
|
|
2915
|
+
n.St = {
|
|
2916
|
+
...n.St,
|
|
2851
2917
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
2852
2918
|
};
|
|
2853
2919
|
}
|
|
2854
2920
|
|
|
2855
2921
|
function hasContext(e, t) {
|
|
2856
|
-
return !isUndefined(t?.
|
|
2922
|
+
return !isUndefined(t?.St[e.id]);
|
|
2857
2923
|
}
|
|
2858
2924
|
|
|
2859
2925
|
function isUndefined(e) {
|
|
@@ -2875,9 +2941,9 @@ function isUndefined(e) {
|
|
|
2875
2941
|
*/
|
|
2876
2942
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, t) {
|
|
2877
2943
|
const n = e.A !== NOT_PENDING;
|
|
2878
|
-
const r = n ? unwrapOverride(e.A) : e.
|
|
2944
|
+
const r = n ? unwrapOverride(e.A) : e.We;
|
|
2879
2945
|
if (typeof t === "function") t = t(r);
|
|
2880
|
-
const i = !!(e.
|
|
2946
|
+
const i = !!(e.Qe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(r, t);
|
|
2881
2947
|
if (!i) {
|
|
2882
2948
|
// Same-value write with an active override still entangles the current
|
|
2883
2949
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2895,7 +2961,7 @@ function isUndefined(e) {
|
|
|
2895
2961
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2896
2962
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2897
2963
|
// which a shared subscriber can merge across transactions (#2912).
|
|
2898
|
-
e.
|
|
2964
|
+
e.p = activeTransition;
|
|
2899
2965
|
const o = getOrCreateLane(e);
|
|
2900
2966
|
e.i = o;
|
|
2901
2967
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
@@ -2904,7 +2970,7 @@ function isUndefined(e) {
|
|
|
2904
2970
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2905
2971
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2906
2972
|
// neither companion present the call is a guaranteed no-op.
|
|
2907
|
-
(e._ !== undefined || e.
|
|
2973
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2908
2974
|
e.F = clock;
|
|
2909
2975
|
insertSubs(e, true);
|
|
2910
2976
|
schedule();
|
|
@@ -2918,7 +2984,7 @@ function isUndefined(e) {
|
|
|
2918
2984
|
*/ function transitionBlocked(e) {
|
|
2919
2985
|
for (let t = 0; t < e.v.length; t++) {
|
|
2920
2986
|
const n = e.v[t];
|
|
2921
|
-
if (hasActiveOverride(n) && "
|
|
2987
|
+
if (hasActiveOverride(n) && "Qe" in n && n.Qe & STATUS_PENDING && n.we instanceof NotReadyError) {
|
|
2922
2988
|
return true;
|
|
2923
2989
|
}
|
|
2924
2990
|
}
|
|
@@ -2936,21 +3002,21 @@ function resolveOptimisticNodes(e) {
|
|
|
2936
3002
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2937
3003
|
// override-covered authoritative values hold in _pendingValue and
|
|
2938
3004
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2939
|
-
if (!(t.
|
|
3005
|
+
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
2940
3006
|
const r = t.A;
|
|
2941
3007
|
t.A = NOT_PENDING;
|
|
2942
|
-
if (r !== NOT_PENDING && t.
|
|
3008
|
+
if (r !== NOT_PENDING && t.We !== unwrapOverride(r)) insertSubs(t, true);
|
|
2943
3009
|
t.T = null;
|
|
2944
|
-
t.
|
|
3010
|
+
t.p = null;
|
|
2945
3011
|
}
|
|
2946
3012
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
2947
3013
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
2948
3014
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2949
3015
|
for (let n = 0; n < t; n++) {
|
|
2950
3016
|
const t = e[n];
|
|
2951
|
-
if (t._ || t.
|
|
3017
|
+
if (t._ || t.R) GlobalQueue.fe(t);
|
|
2952
3018
|
const r = t.t;
|
|
2953
|
-
if (r && (r._ === t || r.
|
|
3019
|
+
if (r && (r._ === t || r.R === t)) GlobalQueue.fe(r);
|
|
2954
3020
|
}
|
|
2955
3021
|
e.splice(0, t);
|
|
2956
3022
|
}
|
|
@@ -3003,7 +3069,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3003
3069
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
3004
3070
|
* is recorded for replay at commit.
|
|
3005
3071
|
*/ function gatedRead(e, t, n) {
|
|
3006
|
-
if (latestReadActive || e.U === NOT_PENDING || e.
|
|
3072
|
+
if (latestReadActive || e.U === NOT_PENDING || e.ke || t !== e && !(t.Ge & REACTIVE_MANUAL_WRITE)) {
|
|
3007
3073
|
return false;
|
|
3008
3074
|
}
|
|
3009
3075
|
activeTransition.Y.add(n);
|
|
@@ -3014,7 +3080,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3014
3080
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3015
3081
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
3016
3082
|
*/ function laneReadsCommitted(e, t, n) {
|
|
3017
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.
|
|
3083
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.Qe & STATUS_PENDING);
|
|
3018
3084
|
}
|
|
3019
3085
|
|
|
3020
3086
|
/**
|
|
@@ -3023,12 +3089,12 @@ function cleanupCompletedLanes(e) {
|
|
|
3023
3089
|
* can run before its OPT-dirty child propagates).
|
|
3024
3090
|
*/ function recomputeLane(e, t) {
|
|
3025
3091
|
if (t) return resolveLane(e) ?? null;
|
|
3026
|
-
for (let t = e.
|
|
3027
|
-
const n = t.
|
|
3028
|
-
if (n.
|
|
3092
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
3093
|
+
const n = t.qe;
|
|
3094
|
+
if (n.Ge & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
3029
3095
|
const t = resolveLane(n);
|
|
3030
3096
|
if (t) {
|
|
3031
|
-
e.
|
|
3097
|
+
e.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
3032
3098
|
assignOrMergeLane(e, t);
|
|
3033
3099
|
return t;
|
|
3034
3100
|
}
|
|
@@ -3042,7 +3108,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3042
3108
|
if (t.o !== e) {
|
|
3043
3109
|
t.u.add(e);
|
|
3044
3110
|
e.i = t;
|
|
3045
|
-
GlobalQueue.
|
|
3111
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(t.o);
|
|
3046
3112
|
}
|
|
3047
3113
|
}
|
|
3048
3114
|
|
|
@@ -3050,13 +3116,13 @@ function cleanupCompletedLanes(e) {
|
|
|
3050
3116
|
const t = resolveLane(e);
|
|
3051
3117
|
if (t) {
|
|
3052
3118
|
t.u.delete(e);
|
|
3053
|
-
GlobalQueue.
|
|
3119
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(t.o);
|
|
3054
3120
|
}
|
|
3055
3121
|
}
|
|
3056
3122
|
|
|
3057
3123
|
function trackOptimisticStore(e) {
|
|
3058
3124
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
3059
|
-
globalQueue.D.
|
|
3125
|
+
globalQueue.D.G.add(e);
|
|
3060
3126
|
schedule();
|
|
3061
3127
|
}
|
|
3062
3128
|
|
|
@@ -3065,19 +3131,19 @@ function trackOptimisticStore(e) {
|
|
|
3065
3131
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
3066
3132
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
3067
3133
|
*/ function installOptimisticEngine() {
|
|
3068
|
-
if (GlobalQueue.
|
|
3069
|
-
GlobalQueue.
|
|
3134
|
+
if (GlobalQueue.Re !== null) return;
|
|
3135
|
+
GlobalQueue.Re = optimisticWrite;
|
|
3070
3136
|
GlobalQueue.pe = resolveOptimisticNodes;
|
|
3071
|
-
GlobalQueue.
|
|
3072
|
-
GlobalQueue.
|
|
3073
|
-
GlobalQueue.
|
|
3074
|
-
GlobalQueue.
|
|
3075
|
-
GlobalQueue.
|
|
3076
|
-
GlobalQueue.
|
|
3077
|
-
GlobalQueue.
|
|
3078
|
-
GlobalQueue.
|
|
3079
|
-
GlobalQueue.
|
|
3080
|
-
GlobalQueue.
|
|
3137
|
+
GlobalQueue.Ie = transitionBlocked;
|
|
3138
|
+
GlobalQueue.Ae = cleanupCompletedLanes;
|
|
3139
|
+
GlobalQueue.he = runLaneEffects;
|
|
3140
|
+
GlobalQueue.Ne = gatedRead;
|
|
3141
|
+
GlobalQueue.ye = laneSuspends;
|
|
3142
|
+
GlobalQueue.Pe = laneReadsCommitted;
|
|
3143
|
+
GlobalQueue.Ce = recomputeLane;
|
|
3144
|
+
GlobalQueue.ge = laneAsyncPending;
|
|
3145
|
+
GlobalQueue.be = laneAsyncSettled;
|
|
3146
|
+
GlobalQueue.De = trackOptimisticStore;
|
|
3081
3147
|
}
|
|
3082
3148
|
|
|
3083
3149
|
/**
|
|
@@ -3110,7 +3176,7 @@ let pendingProbe = null;
|
|
|
3110
3176
|
function collectPendingSources(e) {
|
|
3111
3177
|
if (!pendingProbe) return;
|
|
3112
3178
|
pendingProbe.sources.add(e);
|
|
3113
|
-
const t = e.
|
|
3179
|
+
const t = e.Be || e;
|
|
3114
3180
|
if (t !== e) pendingProbe.sources.add(t);
|
|
3115
3181
|
}
|
|
3116
3182
|
|
|
@@ -3140,20 +3206,20 @@ function collectPendingSources(e) {
|
|
|
3140
3206
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3141
3207
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3142
3208
|
// pending (the count check above), also matching.
|
|
3143
|
-
if (e.
|
|
3209
|
+
if (e.Qe & STATUS_ERROR) return false;
|
|
3144
3210
|
if (t.has(e)) return false;
|
|
3145
3211
|
t.add(e);
|
|
3146
|
-
const n = e.
|
|
3212
|
+
const n = e.Be;
|
|
3147
3213
|
if (n && markWalk(n, t)) return true;
|
|
3148
3214
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3149
3215
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3150
3216
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3151
3217
|
// latch a stale verdict on the companion.
|
|
3152
3218
|
const r = e;
|
|
3153
|
-
const i = r.
|
|
3219
|
+
const i = r.Ge & REACTIVE_RECOMPUTING_DEPS ? r.ut : undefined;
|
|
3154
3220
|
if (i !== null) {
|
|
3155
|
-
for (let e = r.
|
|
3156
|
-
if (!e.
|
|
3221
|
+
for (let e = r.Ke ?? null; e !== null; e = e.Ye) {
|
|
3222
|
+
if (!e._t && markWalk(e.qe, t)) return true;
|
|
3157
3223
|
if (e === i) break;
|
|
3158
3224
|
}
|
|
3159
3225
|
}
|
|
@@ -3165,35 +3231,35 @@ function collectPendingSources(e) {
|
|
|
3165
3231
|
}
|
|
3166
3232
|
|
|
3167
3233
|
function quietPending(e) {
|
|
3168
|
-
if (e
|
|
3169
|
-
for (const t of e
|
|
3234
|
+
if (e.je) {
|
|
3235
|
+
for (const t of e.je) if (!t.Nt) return false;
|
|
3170
3236
|
return true;
|
|
3171
3237
|
}
|
|
3172
|
-
return e.
|
|
3238
|
+
return e.Nt;
|
|
3173
3239
|
}
|
|
3174
3240
|
|
|
3175
3241
|
function newQuestionInFlight(e) {
|
|
3176
|
-
return !!(e.
|
|
3242
|
+
return !!(e.Qe & STATUS_PENDING) && !(e.Qe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3177
3243
|
}
|
|
3178
3244
|
|
|
3179
3245
|
function computePendingState(e) {
|
|
3180
3246
|
const t = e;
|
|
3181
|
-
if (t.
|
|
3247
|
+
if (t.Ge & REACTIVE_DISPOSED) return false;
|
|
3182
3248
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3183
3249
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3184
3250
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3185
3251
|
if (markCovered(e)) return true;
|
|
3186
|
-
const n = e.
|
|
3252
|
+
const n = e.Be;
|
|
3187
3253
|
if (e.t) {
|
|
3188
3254
|
const t = e.t;
|
|
3189
|
-
const n = t.
|
|
3255
|
+
const n = t.Be || t;
|
|
3190
3256
|
return newQuestionInFlight(n);
|
|
3191
3257
|
}
|
|
3192
3258
|
if (n && e.U !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3193
|
-
return !!(n.
|
|
3259
|
+
return !!(n.Ge & REACTIVE_MANUAL_WRITE) || !n.lt && !(n.Qe & STATUS_PENDING) || !!(n.Qe & STATUS_PENDING) && quietPending(n);
|
|
3194
3260
|
}
|
|
3195
|
-
if (e.U !== NOT_PENDING && !(t.
|
|
3196
|
-
if (hasActiveOverride(e)) return !e.
|
|
3261
|
+
if (e.U !== NOT_PENDING && !(t.Qe & STATUS_UNINITIALIZED)) {
|
|
3262
|
+
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.U, unwrapOverride(e.A));
|
|
3197
3263
|
return true;
|
|
3198
3264
|
}
|
|
3199
3265
|
return newQuestionInFlight(t);
|
|
@@ -3201,19 +3267,19 @@ function computePendingState(e) {
|
|
|
3201
3267
|
|
|
3202
3268
|
function syncCompanions(e, t) {
|
|
3203
3269
|
if (e._) updatePendingSignal(e);
|
|
3204
|
-
if (e.
|
|
3270
|
+
if (e.R) setSignal(e.R, t);
|
|
3205
3271
|
}
|
|
3206
3272
|
|
|
3207
3273
|
function updatePendingSignal(e) {
|
|
3208
3274
|
if (e._) {
|
|
3209
3275
|
setSignal(e._, computePendingState(e));
|
|
3210
3276
|
}
|
|
3211
|
-
if (e.
|
|
3277
|
+
if (e.R) updatePendingSignal(e.R);
|
|
3212
3278
|
}
|
|
3213
3279
|
|
|
3214
3280
|
function updateChildCompanions(e) {
|
|
3215
|
-
for (let t = e.
|
|
3216
|
-
if (t._ || t.
|
|
3281
|
+
for (let t = e.rt; t !== null; t = t.it) {
|
|
3282
|
+
if (t._ || t.R) updatePendingSignal(t);
|
|
3217
3283
|
}
|
|
3218
3284
|
}
|
|
3219
3285
|
|
|
@@ -3231,9 +3297,9 @@ function updateChildCompanions(e) {
|
|
|
3231
3297
|
const visit = e => {
|
|
3232
3298
|
if (r.has(e)) return;
|
|
3233
3299
|
r.add(e);
|
|
3234
|
-
if (e._ || e.
|
|
3235
|
-
for (let t = e.
|
|
3236
|
-
for (let t = e.
|
|
3300
|
+
if (e._ || e.R) n(e);
|
|
3301
|
+
for (let t = e.V; t !== null; t = t.Le) visit(t.Ve);
|
|
3302
|
+
for (let t = e.rt ?? null; t !== null; t = t.it) {
|
|
3237
3303
|
visit(t);
|
|
3238
3304
|
}
|
|
3239
3305
|
};
|
|
@@ -3244,18 +3310,18 @@ function snapCompanionsToState(e) {
|
|
|
3244
3310
|
const t = e._;
|
|
3245
3311
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3246
3312
|
const n = computePendingState(e);
|
|
3247
|
-
if (t.
|
|
3248
|
-
t.
|
|
3313
|
+
if (t.We !== n || t.U !== NOT_PENDING) {
|
|
3314
|
+
t.We = n;
|
|
3249
3315
|
t.U = NOT_PENDING;
|
|
3250
3316
|
t.F = clock;
|
|
3251
3317
|
insertSubs(t);
|
|
3252
3318
|
schedule();
|
|
3253
3319
|
}
|
|
3254
3320
|
}
|
|
3255
|
-
const n = e.
|
|
3256
|
-
if (n && !(n.
|
|
3257
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.
|
|
3258
|
-
n.
|
|
3321
|
+
const n = e.R;
|
|
3322
|
+
if (n && !(n.Ge & REACTIVE_DISPOSED)) {
|
|
3323
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.We, e.We) && !(n.Ge & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3324
|
+
n.Ge |= REACTIVE_DIRTY;
|
|
3259
3325
|
insertIntoHeap(n, queueFor(n));
|
|
3260
3326
|
insertSubs(n);
|
|
3261
3327
|
schedule();
|
|
@@ -3265,7 +3331,7 @@ function snapCompanionsToState(e) {
|
|
|
3265
3331
|
}
|
|
3266
3332
|
|
|
3267
3333
|
function getLatestValueComputed(e) {
|
|
3268
|
-
if (!e.
|
|
3334
|
+
if (!e.R) {
|
|
3269
3335
|
const t = latestReadActive;
|
|
3270
3336
|
setLatestReadActive(false);
|
|
3271
3337
|
const n = pendingCheckActive;
|
|
@@ -3273,21 +3339,21 @@ function getLatestValueComputed(e) {
|
|
|
3273
3339
|
const r = context;
|
|
3274
3340
|
setContextInternal(null);
|
|
3275
3341
|
// Detach from owner so it isn't disposed with effects
|
|
3276
|
-
e.
|
|
3277
|
-
e.
|
|
3342
|
+
e.R = optimisticComputed(() => read(e));
|
|
3343
|
+
e.R.t = e;
|
|
3278
3344
|
// Parent-child lane relationship
|
|
3279
3345
|
setContextInternal(r);
|
|
3280
3346
|
setPendingCheckActive(n);
|
|
3281
3347
|
setLatestReadActive(t);
|
|
3282
3348
|
}
|
|
3283
|
-
return e.
|
|
3349
|
+
return e.R;
|
|
3284
3350
|
}
|
|
3285
3351
|
|
|
3286
3352
|
/** The latest()-mode read path, installed as GlobalQueue._latestRead. */ function latestRead(e) {
|
|
3287
3353
|
const t = getLatestValueComputed(e);
|
|
3288
3354
|
const n = latestReadActive;
|
|
3289
3355
|
setLatestReadActive(false);
|
|
3290
|
-
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
3356
|
+
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.We;
|
|
3291
3357
|
let i;
|
|
3292
3358
|
try {
|
|
3293
3359
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -3296,18 +3362,18 @@ function getLatestValueComputed(e) {
|
|
|
3296
3362
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3297
3363
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3298
3364
|
const e = queueFor(t);
|
|
3299
|
-
if (t.
|
|
3365
|
+
if (t.ze >= e.P && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3300
3366
|
markHeap(e);
|
|
3301
3367
|
prepareComputed(t, true);
|
|
3302
3368
|
}
|
|
3303
3369
|
i = read(t);
|
|
3304
3370
|
} catch (t) {
|
|
3305
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3371
|
+
if (t instanceof NotReadyError && (!context || !(e.Qe & STATUS_UNINITIALIZED))) return r;
|
|
3306
3372
|
throw t;
|
|
3307
3373
|
} finally {
|
|
3308
3374
|
setLatestReadActive(n);
|
|
3309
3375
|
}
|
|
3310
|
-
if (t.
|
|
3376
|
+
if (t.Qe & STATUS_PENDING) return r;
|
|
3311
3377
|
if (stale && currentOptimisticLane && t.i) {
|
|
3312
3378
|
const e = findLane(t.i);
|
|
3313
3379
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3325,12 +3391,12 @@ function getLatestValueComputed(e) {
|
|
|
3325
3391
|
|
|
3326
3392
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3327
3393
|
setPendingCheckActive(false);
|
|
3328
|
-
if (typeof e.
|
|
3329
|
-
const i = n.
|
|
3394
|
+
if (typeof e.ke === "function") prepareComputed(e, true);
|
|
3395
|
+
const i = n.Qe;
|
|
3330
3396
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3331
3397
|
if (tracking && e !== t) link(e, t);
|
|
3332
3398
|
setPendingCheckActive(true);
|
|
3333
|
-
throw n.
|
|
3399
|
+
throw n.we;
|
|
3334
3400
|
}
|
|
3335
3401
|
collectPendingSources(e);
|
|
3336
3402
|
if (r) collectPendingSources(r);
|
|
@@ -3342,10 +3408,10 @@ function recordFreshRead(e, t) {
|
|
|
3342
3408
|
}
|
|
3343
3409
|
|
|
3344
3410
|
function applyReask(e, t) {
|
|
3345
|
-
const n = !!(e.
|
|
3346
|
-
const r = t && !(n && !e.
|
|
3347
|
-
const i = n && e.
|
|
3348
|
-
e.
|
|
3411
|
+
const n = !!(e.Qe & STATUS_PENDING);
|
|
3412
|
+
const r = t && !(n && !e.Nt);
|
|
3413
|
+
const i = n && e.Nt !== r;
|
|
3414
|
+
e.Nt = r;
|
|
3349
3415
|
return i;
|
|
3350
3416
|
}
|
|
3351
3417
|
|
|
@@ -3385,7 +3451,7 @@ function isPending(e) {
|
|
|
3385
3451
|
} catch (e) {
|
|
3386
3452
|
collectPending();
|
|
3387
3453
|
if (e instanceof NotReadyError) {
|
|
3388
|
-
const t = !!(e.source?.
|
|
3454
|
+
const t = !!(e.source?.Qe & STATUS_UNINITIALIZED);
|
|
3389
3455
|
if (r.found && !t) return true;
|
|
3390
3456
|
if (context && t) throw e;
|
|
3391
3457
|
}
|
|
@@ -3399,25 +3465,25 @@ function isPending(e) {
|
|
|
3399
3465
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3400
3466
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3401
3467
|
// direct calls used, so behavior is identical once this module loads.
|
|
3402
|
-
GlobalQueue.
|
|
3468
|
+
GlobalQueue.le = syncCompanions;
|
|
3403
3469
|
|
|
3404
|
-
GlobalQueue.
|
|
3470
|
+
GlobalQueue.ae = updatePendingSignal;
|
|
3405
3471
|
|
|
3406
|
-
GlobalQueue.
|
|
3472
|
+
GlobalQueue.ce = updateChildCompanions;
|
|
3407
3473
|
|
|
3408
|
-
GlobalQueue.
|
|
3474
|
+
GlobalQueue.fe = snapCompanionsToState;
|
|
3409
3475
|
|
|
3410
|
-
GlobalQueue.
|
|
3476
|
+
GlobalQueue.Ee = latestRead;
|
|
3411
3477
|
|
|
3412
|
-
GlobalQueue.
|
|
3478
|
+
GlobalQueue.de = pendingCheckRead;
|
|
3413
3479
|
|
|
3414
|
-
GlobalQueue.
|
|
3480
|
+
GlobalQueue.Se = recordFreshRead;
|
|
3415
3481
|
|
|
3416
|
-
GlobalQueue.
|
|
3482
|
+
GlobalQueue.Te = applyReask;
|
|
3417
3483
|
|
|
3418
|
-
GlobalQueue.
|
|
3484
|
+
GlobalQueue.Oe = repollDownstreamVerdicts;
|
|
3419
3485
|
|
|
3420
|
-
GlobalQueue.
|
|
3486
|
+
GlobalQueue._e = witnessAffects;
|
|
3421
3487
|
|
|
3422
3488
|
/**
|
|
3423
3489
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3427,16 +3493,16 @@ GlobalQueue.Oe = witnessAffects;
|
|
|
3427
3493
|
const i = !!r?.user;
|
|
3428
3494
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3429
3495
|
recompute(o, true);
|
|
3430
|
-
!r?.defer && (o.
|
|
3496
|
+
!r?.defer && (o.Fe === EFFECT_USER || r?.schedule ? o.Ze.enqueue(o.Fe, runEffect.bind(null, o)) : runEffect(o));
|
|
3431
3497
|
}
|
|
3432
3498
|
|
|
3433
3499
|
function notifyEffectStatus(e, t) {
|
|
3434
3500
|
// Use passed values if provided, otherwise read from node
|
|
3435
|
-
const n = e !== undefined ? e : this.
|
|
3436
|
-
const r = t !== undefined ? t : this.
|
|
3501
|
+
const n = e !== undefined ? e : this.Qe;
|
|
3502
|
+
const r = t !== undefined ? t : this.we;
|
|
3437
3503
|
if (n & STATUS_ERROR) {
|
|
3438
|
-
this.
|
|
3439
|
-
if (this.
|
|
3504
|
+
this.Ze.notify(this, STATUS_PENDING, 0);
|
|
3505
|
+
if (this.Fe === EFFECT_USER) {
|
|
3440
3506
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3441
3507
|
// queue it like the effect function. It runs in the same imperative,
|
|
3442
3508
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3446,23 +3512,23 @@ function notifyEffectStatus(e, t) {
|
|
|
3446
3512
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3447
3513
|
// `status` arg without node-state writes) don't queue: the status
|
|
3448
3514
|
// re-propagates unblocked at commit.
|
|
3449
|
-
if (this.
|
|
3450
|
-
this.
|
|
3451
|
-
this.
|
|
3515
|
+
if (this.Qe & STATUS_ERROR) {
|
|
3516
|
+
this.xe = true;
|
|
3517
|
+
this.Ze.enqueue(this.Fe, this.Ct ??= runEffect.bind(null, this));
|
|
3452
3518
|
}
|
|
3453
3519
|
return;
|
|
3454
3520
|
}
|
|
3455
|
-
if (!this.
|
|
3521
|
+
if (!this.Ze.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3456
3522
|
haltReactivity(unwrapStatusError(r));
|
|
3457
3523
|
throw r;
|
|
3458
3524
|
}
|
|
3459
|
-
} else if (this.
|
|
3460
|
-
this.
|
|
3525
|
+
} else if (this.Fe === EFFECT_RENDER) {
|
|
3526
|
+
this.Ze.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3461
3527
|
}
|
|
3462
3528
|
}
|
|
3463
3529
|
|
|
3464
3530
|
function runEffect(e) {
|
|
3465
|
-
if (!e.
|
|
3531
|
+
if (!e.xe || e.Ge & REACTIVE_DISPOSED) return;
|
|
3466
3532
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3467
3533
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3468
3534
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3473,46 +3539,46 @@ function runEffect(e) {
|
|
|
3473
3539
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3474
3540
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3475
3541
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3476
|
-
if (e.
|
|
3477
|
-
const t = unwrapStatusError(e.
|
|
3478
|
-
e.
|
|
3479
|
-
e.
|
|
3542
|
+
if (e.Qe & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3543
|
+
const t = unwrapStatusError(e.we);
|
|
3544
|
+
e.bt = e.We;
|
|
3545
|
+
e.xe = false;
|
|
3480
3546
|
try {
|
|
3481
|
-
e.
|
|
3482
|
-
const t = e.
|
|
3483
|
-
e.
|
|
3547
|
+
e.wt ? e.wt(t, () => {
|
|
3548
|
+
const t = e.Et;
|
|
3549
|
+
e.Et = undefined;
|
|
3484
3550
|
t?.();
|
|
3485
3551
|
}) : console.error(t);
|
|
3486
3552
|
} catch (t) {
|
|
3487
|
-
if (!e.
|
|
3553
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3488
3554
|
haltReactivity(t);
|
|
3489
3555
|
throw t;
|
|
3490
3556
|
}
|
|
3491
3557
|
}
|
|
3492
3558
|
return;
|
|
3493
3559
|
}
|
|
3494
|
-
const t = e.
|
|
3495
|
-
e.
|
|
3560
|
+
const t = e.Et;
|
|
3561
|
+
e.Et = undefined;
|
|
3496
3562
|
try {
|
|
3497
3563
|
t?.();
|
|
3498
|
-
const n = e.
|
|
3564
|
+
const n = e.Dt(e.We, e.bt);
|
|
3499
3565
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3500
3566
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3501
|
-
e.
|
|
3567
|
+
e.Et = n;
|
|
3502
3568
|
} catch (t) {
|
|
3503
|
-
e.
|
|
3504
|
-
e.
|
|
3505
|
-
if (!e.
|
|
3569
|
+
e.we = new StatusError(e, t);
|
|
3570
|
+
e.Qe |= STATUS_ERROR;
|
|
3571
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3506
3572
|
haltReactivity(t);
|
|
3507
3573
|
throw t;
|
|
3508
3574
|
}
|
|
3509
3575
|
} finally {
|
|
3510
|
-
e.
|
|
3511
|
-
e.
|
|
3576
|
+
e.bt = e.We;
|
|
3577
|
+
e.xe = false;
|
|
3512
3578
|
}
|
|
3513
3579
|
}
|
|
3514
3580
|
|
|
3515
|
-
GlobalQueue.
|
|
3581
|
+
GlobalQueue.ee = runEffect;
|
|
3516
3582
|
|
|
3517
3583
|
/**
|
|
3518
3584
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3520,39 +3586,39 @@ GlobalQueue.J = runEffect;
|
|
|
3520
3586
|
* Uses stale reads.
|
|
3521
3587
|
*/ function trackedEffect(e, t) {
|
|
3522
3588
|
const run = () => {
|
|
3523
|
-
if (!n.
|
|
3589
|
+
if (!n.xe || n.Ge & REACTIVE_DISPOSED) return;
|
|
3524
3590
|
try {
|
|
3525
|
-
n.
|
|
3591
|
+
n.xe = false;
|
|
3526
3592
|
recompute(n);
|
|
3527
3593
|
} finally {}
|
|
3528
3594
|
};
|
|
3529
3595
|
const n = computed(() => {
|
|
3530
|
-
const t = n.
|
|
3531
|
-
n.
|
|
3596
|
+
const t = n.Et;
|
|
3597
|
+
n.Et = undefined;
|
|
3532
3598
|
t?.();
|
|
3533
3599
|
const r = staleValues(e);
|
|
3534
|
-
n.
|
|
3600
|
+
n.Et = r;
|
|
3535
3601
|
}, {
|
|
3536
3602
|
...t,
|
|
3537
3603
|
lazy: true
|
|
3538
3604
|
});
|
|
3539
|
-
n.
|
|
3540
|
-
n.
|
|
3541
|
-
n.
|
|
3542
|
-
n.
|
|
3543
|
-
n.
|
|
3544
|
-
const r = e !== undefined ? e : n.
|
|
3605
|
+
n.Et = undefined;
|
|
3606
|
+
n.Ue = n.Ue & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3607
|
+
n.xe = true;
|
|
3608
|
+
n.Fe = EFFECT_TRACKED;
|
|
3609
|
+
n.yt = (e, t) => {
|
|
3610
|
+
const r = e !== undefined ? e : n.Qe;
|
|
3545
3611
|
if (r & STATUS_ERROR) {
|
|
3546
|
-
n.
|
|
3547
|
-
const e = t !== undefined ? t : n.
|
|
3548
|
-
if (!n.
|
|
3612
|
+
n.Ze.notify(n, STATUS_PENDING, 0);
|
|
3613
|
+
const e = t !== undefined ? t : n.we;
|
|
3614
|
+
if (!n.Ze.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3549
3615
|
haltReactivity(unwrapStatusError(e));
|
|
3550
3616
|
throw e;
|
|
3551
3617
|
}
|
|
3552
3618
|
}
|
|
3553
3619
|
};
|
|
3554
|
-
n.
|
|
3555
|
-
n.
|
|
3620
|
+
n.Xe = run;
|
|
3621
|
+
n.Ze.enqueue(EFFECT_USER, run);
|
|
3556
3622
|
}
|
|
3557
3623
|
|
|
3558
3624
|
function restoreTransition(e, t) {
|
|
@@ -3634,7 +3700,12 @@ function restoreTransition(e, t) {
|
|
|
3634
3700
|
o = currentTransition(o);
|
|
3635
3701
|
const u = o.$.indexOf(i);
|
|
3636
3702
|
if (u >= 0) o.$.splice(u, 1);
|
|
3637
|
-
|
|
3703
|
+
// Re-adopt through initTransition like every other resumption site:
|
|
3704
|
+
// a bare setActiveTransition leaves globalQueue._batch as a detached
|
|
3705
|
+
// ambient batch, and anything registered before the scheduled flush
|
|
3706
|
+
// (held writes on a merging transition, optimistic overrides,
|
|
3707
|
+
// affects() marks) lands there with nothing to ever finalize it.
|
|
3708
|
+
globalQueue.initTransition(o);
|
|
3638
3709
|
schedule();
|
|
3639
3710
|
s ? r(t) : n(e);
|
|
3640
3711
|
};
|
|
@@ -3733,7 +3804,7 @@ function accessor(e) {
|
|
|
3733
3804
|
function createSignal(e, t) {
|
|
3734
3805
|
if (typeof e === "function") {
|
|
3735
3806
|
const n = computed(e, t);
|
|
3736
|
-
n.
|
|
3807
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3737
3808
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3738
3809
|
}
|
|
3739
3810
|
const n = signal(e, t);
|
|
@@ -3945,9 +4016,9 @@ function createEffect(e, t, n) {
|
|
|
3945
4016
|
// route through the inherited queue.
|
|
3946
4017
|
const i = getOwner();
|
|
3947
4018
|
const o = new MicrotaskQueue;
|
|
3948
|
-
o.B = i.
|
|
4019
|
+
o.B = i.Ze;
|
|
3949
4020
|
// notify() forwards up the normal chain
|
|
3950
|
-
i.
|
|
4021
|
+
i.Ze = o;
|
|
3951
4022
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
3952
4023
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
3953
4024
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -3974,7 +4045,7 @@ function createOptimistic(e, t) {
|
|
|
3974
4045
|
installOptimisticEngine();
|
|
3975
4046
|
if (typeof e === "function") {
|
|
3976
4047
|
const n = optimisticComputed(e, t);
|
|
3977
|
-
n.
|
|
4048
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3978
4049
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3979
4050
|
}
|
|
3980
4051
|
const n = optimisticSignal(e, t);
|
|
@@ -4063,7 +4134,7 @@ function createOptimistic(e, t) {
|
|
|
4063
4134
|
* on owner disposal
|
|
4064
4135
|
*/ function onSettled(e) {
|
|
4065
4136
|
const t = getOwner();
|
|
4066
|
-
t && !(t.
|
|
4137
|
+
t && !(t.Ue & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
4067
4138
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
4068
4139
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
4069
4140
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4162,6 +4233,17 @@ function keyedMatch(e, t, n) {
|
|
|
4162
4233
|
return e === t || isWrappable(e) && isWrappable(t) && n(e) === n(t);
|
|
4163
4234
|
}
|
|
4164
4235
|
|
|
4236
|
+
// A pair of array slots may only be merged into when both sides are real store
|
|
4237
|
+
// children of the SAME container kind. An array and an object are different
|
|
4238
|
+
// shapes, and merging one into the other leaves the slot's proxy permanently
|
|
4239
|
+
// mismatched with its value (an array target holding an object, so
|
|
4240
|
+
// `Array.isArray`/spread/`map` lie). The object diff has always applied this
|
|
4241
|
+
// rule; the array paths reach the same recursion through `keyedMatch` /
|
|
4242
|
+
// positional pairing, where two keyless wrappables "match" regardless of kind.
|
|
4243
|
+
function recursablePair(e, t) {
|
|
4244
|
+
return isWrappable(e) && isWrappable(t) && !(rawValuesUsed && (isRawValue(e) || isRawValue(t))) && Array.isArray(e) === Array.isArray(t);
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4165
4247
|
// Array reconciliation updates the slots it visits, then swaps STORE_VALUE.
|
|
4166
4248
|
// Previously tracked keys that are absent from `next` still need invalidating,
|
|
4167
4249
|
// and `in` dependencies should follow the new value's membership. Use
|
|
@@ -4228,7 +4310,7 @@ function applyStateChild(e, t, n, r) {
|
|
|
4228
4310
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
4229
4311
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
4230
4312
|
function applyArrayItem(e, t, n, r, i) {
|
|
4231
|
-
if (
|
|
4313
|
+
if (recursablePair(t, e)) {
|
|
4232
4314
|
const o = wrap(t, n);
|
|
4233
4315
|
r && setSignal(r, o);
|
|
4234
4316
|
applyState(e, o, i);
|
|
@@ -4418,7 +4500,7 @@ function applyStateFast(e, t, n) {
|
|
|
4418
4500
|
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
4419
4501
|
// replace the slot node instead of recursing.
|
|
4420
4502
|
if (E !== e[a]) {
|
|
4421
|
-
if (
|
|
4503
|
+
if (!recursablePair(E, e[a])) {
|
|
4422
4504
|
i?.[a] && setSignal(i[a], wrapValue(e[a], t));
|
|
4423
4505
|
} else applyStateChild(e[a], E, t, n);
|
|
4424
4506
|
}
|
|
@@ -4474,7 +4556,7 @@ function applyStateFast(e, t, n) {
|
|
|
4474
4556
|
} else if (e.length) {
|
|
4475
4557
|
for (let s = 0, u = e.length; s < u; s++) {
|
|
4476
4558
|
const u = r[s];
|
|
4477
|
-
if (
|
|
4559
|
+
if (recursablePair(u, e[s])) {
|
|
4478
4560
|
if (u !== e[s]) applyStateChild(e[s], u, t, n);
|
|
4479
4561
|
} else {
|
|
4480
4562
|
if (u !== e[s]) o = true;
|
|
@@ -4564,13 +4646,13 @@ function applyStateSlow(e, t, n) {
|
|
|
4564
4646
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4565
4647
|
let a, c, f, E, d, S, T, O;
|
|
4566
4648
|
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4567
|
-
if (
|
|
4568
|
-
if (
|
|
4649
|
+
if (S !== e[f] && isWrappable(S) && isWrappable(e[f])) {
|
|
4650
|
+
if (!recursablePair(S, e[f])) {
|
|
4569
4651
|
s?.[f] && setSignal(s[f], wrapValue(e[f], t));
|
|
4570
4652
|
} else applyState(e[f], wrap(S, t), n);
|
|
4571
4653
|
}
|
|
4572
4654
|
}
|
|
4573
|
-
const _ = new Array(e.length),
|
|
4655
|
+
const _ = new Array(e.length), R = new Map;
|
|
4574
4656
|
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4575
4657
|
d--) {
|
|
4576
4658
|
_[d] = S;
|
|
@@ -4594,18 +4676,18 @@ function applyStateSlow(e, t, n) {
|
|
|
4594
4676
|
for (c = d; c >= f; c--) {
|
|
4595
4677
|
S = e[c];
|
|
4596
4678
|
O = itemKey(S, n);
|
|
4597
|
-
a =
|
|
4679
|
+
a = R.get(O);
|
|
4598
4680
|
T[c] = a === undefined ? -1 : a;
|
|
4599
|
-
|
|
4681
|
+
R.set(O, c);
|
|
4600
4682
|
}
|
|
4601
4683
|
for (a = f; a <= E; a++) {
|
|
4602
4684
|
S = getOverrideValue(r, i, a, o);
|
|
4603
4685
|
O = itemKey(S, n);
|
|
4604
|
-
c =
|
|
4686
|
+
c = R.get(O);
|
|
4605
4687
|
if (c !== undefined && c !== -1) {
|
|
4606
4688
|
_[c] = S;
|
|
4607
4689
|
c = T[c];
|
|
4608
|
-
|
|
4690
|
+
R.set(O, c);
|
|
4609
4691
|
}
|
|
4610
4692
|
}
|
|
4611
4693
|
for (c = f; c < e.length; c++) {
|
|
@@ -4617,7 +4699,7 @@ function applyStateSlow(e, t, n) {
|
|
|
4617
4699
|
} else if (e.length) {
|
|
4618
4700
|
for (let l = 0, a = e.length; l < a; l++) {
|
|
4619
4701
|
const a = getOverrideValue(r, i, l, o);
|
|
4620
|
-
if (
|
|
4702
|
+
if (recursablePair(a, e[l])) {
|
|
4621
4703
|
if (a !== e[l]) applyState(e[l], wrap(a, t), n);
|
|
4622
4704
|
} else {
|
|
4623
4705
|
if (a !== e[l]) u = true;
|
|
@@ -4666,6 +4748,58 @@ function applyStateSlow(e, t, n) {
|
|
|
4666
4748
|
// the positional branch and object descent to plain per-property merging.
|
|
4667
4749
|
const NOKEY = () => null;
|
|
4668
4750
|
|
|
4751
|
+
// Identity-as-key: distinct objects never match, so every slot takes the diff's
|
|
4752
|
+
// "not the same entity" branch and is replaced by reference rather than merged
|
|
4753
|
+
// into. Slots holding the same raw on both sides still keep their proxy.
|
|
4754
|
+
const IDENTITY = e => e;
|
|
4755
|
+
|
|
4756
|
+
/**
|
|
4757
|
+
* Shared body of `reconcile()` and the projection commit. `replace` is the
|
|
4758
|
+
* only difference: a projection commit is a value swap, not a merge — its root
|
|
4759
|
+
* proxy is a cell handed out by `createProjection` that can never change
|
|
4760
|
+
* reference, so a derive returning a different entity is not the slot mistake
|
|
4761
|
+
* `reconcile()` throws on. Nothing below the root survives that swap, which is
|
|
4762
|
+
* the rule the keyed diff already applies at a nested slot on a key mismatch.
|
|
4763
|
+
*
|
|
4764
|
+
* @internal
|
|
4765
|
+
*/ function reconcileState(e, t, n, r) {
|
|
4766
|
+
if (t == null) throw new Error("");
|
|
4767
|
+
// A projection commit whose derive returns a foreign store adopts it as the
|
|
4768
|
+
// live backing (store-in-store chain — the same shape as a store-proxy
|
|
4769
|
+
// seed): reads route through the inner store's own graph, so its updates
|
|
4770
|
+
// flow with no re-derive, and a derive with no dependencies never recomputes
|
|
4771
|
+
// (#2941). The diff below still runs against raw values so THIS store's
|
|
4772
|
+
// existing subscribers see the swap; the live proxy is installed after.
|
|
4773
|
+
// Shallow projections keep their raw-ingest contract and never chain.
|
|
4774
|
+
let i;
|
|
4775
|
+
const o = r ? t[$TARGET] : undefined;
|
|
4776
|
+
if (o !== undefined) {
|
|
4777
|
+
if (e?.[$TARGET] !== undefined && e[$TARGET] !== o && !o[STORE_SHALLOW]) {
|
|
4778
|
+
if (o[STORE_VALUE] === e) return;
|
|
4779
|
+
// already chained to this store
|
|
4780
|
+
i = e;
|
|
4781
|
+
}
|
|
4782
|
+
// Re-diffing a previously chained backing goes through its raw — reads
|
|
4783
|
+
// off the outgoing proxy would subscribe this computed to a store it is
|
|
4784
|
+
// about to drop.
|
|
4785
|
+
while (o[STORE_VALUE]?.[$TARGET] !== undefined) o[STORE_VALUE] = unwrap(o[STORE_VALUE]);
|
|
4786
|
+
}
|
|
4787
|
+
if (n === null) applyState(e, t, NOKEY); else {
|
|
4788
|
+
let i = typeof n === "string" ? e => e[n] : n;
|
|
4789
|
+
const o = i(t);
|
|
4790
|
+
if (o !== undefined && i(e) !== o) {
|
|
4791
|
+
if (!r) throw new Error("");
|
|
4792
|
+
// Or the outgoing raw keeps resolving to this proxy and surfaces the
|
|
4793
|
+
// incoming entity wherever it reappears in this family.
|
|
4794
|
+
const n = t[$TARGET];
|
|
4795
|
+
if (n && n[STORE_VALUE] !== unwrap(e)) n[STORE_LOOKUP]?.delete(n[STORE_VALUE]);
|
|
4796
|
+
i = IDENTITY;
|
|
4797
|
+
}
|
|
4798
|
+
applyState(e, t, i);
|
|
4799
|
+
}
|
|
4800
|
+
if (i !== undefined) o[STORE_VALUE] = i;
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4669
4803
|
/**
|
|
4670
4804
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
4671
4805
|
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
@@ -4680,6 +4814,9 @@ const NOKEY = () => null;
|
|
|
4680
4814
|
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
4681
4815
|
* monitors), where no keyed diff pass is needed or wanted.
|
|
4682
4816
|
*
|
|
4817
|
+
* Merging into a slot that holds a *different* entity throws — the caller
|
|
4818
|
+
* picked the slot, so a key mismatch there is a bug.
|
|
4819
|
+
*
|
|
4683
4820
|
* @param value the next state to merge in
|
|
4684
4821
|
* @param key property name (string) or extractor function for stable
|
|
4685
4822
|
* identity (default `"id"`); pass `null` for positional merging
|
|
@@ -4697,17 +4834,7 @@ const NOKEY = () => null;
|
|
|
4697
4834
|
* setStats(reconcile(nextStats, null));
|
|
4698
4835
|
* ```
|
|
4699
4836
|
*/ function reconcile(e, t = "id") {
|
|
4700
|
-
return n =>
|
|
4701
|
-
if (n == null) throw new Error("");
|
|
4702
|
-
if (t === null) {
|
|
4703
|
-
applyState(e, n, NOKEY);
|
|
4704
|
-
return;
|
|
4705
|
-
}
|
|
4706
|
-
const r = typeof t === "string" ? e => e[t] : t;
|
|
4707
|
-
const i = r(n);
|
|
4708
|
-
if (i !== undefined && r(e) !== i) throw new Error("");
|
|
4709
|
-
applyState(e, n, r);
|
|
4710
|
-
};
|
|
4837
|
+
return n => reconcileState(e, n, t, false);
|
|
4711
4838
|
}
|
|
4712
4839
|
|
|
4713
4840
|
function createProjectionInternal(e, t, n) {
|
|
@@ -4740,9 +4867,9 @@ function createProjectionInternal(e, t, n) {
|
|
|
4740
4867
|
const s = wrapProjection(t);
|
|
4741
4868
|
r = computed(() => {
|
|
4742
4869
|
if (!r) r = getOwner();
|
|
4743
|
-
runProjectionComputed(s, e, n?.key
|
|
4870
|
+
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key);
|
|
4744
4871
|
}, undefined);
|
|
4745
|
-
r.
|
|
4872
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
4746
4873
|
return {
|
|
4747
4874
|
store: s,
|
|
4748
4875
|
node: r
|
|
@@ -4757,6 +4884,10 @@ function createProjectionInternal(e, t, n) {
|
|
|
4757
4884
|
* items keep their proxy identity — only added/removed items are
|
|
4758
4885
|
* created/disposed.
|
|
4759
4886
|
*
|
|
4887
|
+
* If the derive returns a different entity than the one currently held (the
|
|
4888
|
+
* `/users/1` → `/users/2` shape), the store swaps to it rather than merging,
|
|
4889
|
+
* and nothing below it is treated as surviving.
|
|
4890
|
+
*
|
|
4760
4891
|
* Returns the projected store directly (no setter — reads only).
|
|
4761
4892
|
*
|
|
4762
4893
|
* Use this when you want the structural-sharing / per-property tracking
|
|
@@ -4769,7 +4900,8 @@ function createProjectionInternal(e, t, n) {
|
|
|
4769
4900
|
* @param seed the backing store value to wrap and reconcile into
|
|
4770
4901
|
* @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
|
|
4771
4902
|
* `"id"`; specify it only when your data uses a different identity field
|
|
4772
|
-
* (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`)
|
|
4903
|
+
* (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`), or `null` to merge
|
|
4904
|
+
* positionally with no keyed pass.
|
|
4773
4905
|
*
|
|
4774
4906
|
* @example
|
|
4775
4907
|
* ```ts
|
|
@@ -4811,13 +4943,13 @@ function createProjectionInternal(e, t, n) {
|
|
|
4811
4943
|
const o = getOwner();
|
|
4812
4944
|
let s = false;
|
|
4813
4945
|
let u;
|
|
4814
|
-
const l = new Proxy(e, createWriteTraps(() => !s || o.
|
|
4946
|
+
const l = new Proxy(e, createWriteTraps(() => !s || o.lt === u, i));
|
|
4815
4947
|
storeSetter(l, i => {
|
|
4816
4948
|
u = t(i);
|
|
4817
4949
|
s = true;
|
|
4818
4950
|
const commit = t => {
|
|
4819
4951
|
if (t === i || t === undefined) return;
|
|
4820
|
-
const write = () => storeSetter(e,
|
|
4952
|
+
const write = () => storeSetter(e, e => reconcileState(t, e, n, true));
|
|
4821
4953
|
r ? r(write) : write();
|
|
4822
4954
|
};
|
|
4823
4955
|
commit(handleAsync(o, u, commit));
|
|
@@ -5045,11 +5177,39 @@ function wrapShallow(e) {
|
|
|
5045
5177
|
return n;
|
|
5046
5178
|
}
|
|
5047
5179
|
|
|
5180
|
+
const OBJECT_PROTO = Object.prototype;
|
|
5181
|
+
|
|
5182
|
+
// Per-prototype memo for the custom-proto branch of isWrappable: the verdict
|
|
5183
|
+
// is fully determined by the prototype (tag and Node lineage both live on
|
|
5184
|
+
// the chain), so each class pays the tag call once — not per read.
|
|
5185
|
+
const wrappableProtos = new WeakMap;
|
|
5186
|
+
|
|
5048
5187
|
function isWrappable(e) {
|
|
5049
5188
|
if (e == null || typeof e !== "object" || Object.isFrozen(e)) return false;
|
|
5050
|
-
//
|
|
5051
|
-
//
|
|
5052
|
-
|
|
5189
|
+
// Plain data and user class instances wrap; platform objects never do
|
|
5190
|
+
// (#2952). Native code brand-checks internal slots and throws through a
|
|
5191
|
+
// proxy (`Map.prototype.size`, `Date.prototype.getTime`, ...), so
|
|
5192
|
+
// collections and other built-ins can't honestly be stores — they get the
|
|
5193
|
+
// markRaw-children contract automatically: served raw, mutations land raw,
|
|
5194
|
+
// the property holding them still tracks (reassignment notifies). The tag
|
|
5195
|
+
// check separates them structurally: user classes stringify as
|
|
5196
|
+
// `[object Object]` while every native/host object carries its own brand
|
|
5197
|
+
// (`[object Map]`, `[object Date]`, `[object Headers]`, ...), including
|
|
5198
|
+
// subclasses, which inherit the tag. getPrototypeOf keeps the hot path
|
|
5199
|
+
// (plain and null-proto objects) intrinsic-only — no property lookup.
|
|
5200
|
+
const t = Object.getPrototypeOf(e);
|
|
5201
|
+
if (t === OBJECT_PROTO || t === null) return true;
|
|
5202
|
+
if (Array.isArray(e)) return true;
|
|
5203
|
+
let n = wrappableProtos.get(t);
|
|
5204
|
+
if (n === undefined) {
|
|
5205
|
+
n = Object.prototype.toString.call(e) === "[object Object]" && (
|
|
5206
|
+
// Dynamic Node check (kept dynamic so test/SSR overrides of
|
|
5207
|
+
// `globalThis.Node` are observed at call time): shimmed DOMs implement
|
|
5208
|
+
// nodes as plain user classes, which pass the tag check.
|
|
5209
|
+
typeof Node === "undefined" || !(e instanceof Node));
|
|
5210
|
+
wrappableProtos.set(t, n);
|
|
5211
|
+
}
|
|
5212
|
+
return n;
|
|
5053
5213
|
}
|
|
5054
5214
|
|
|
5055
5215
|
let writeOverride = false;
|
|
@@ -5127,7 +5287,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
5127
5287
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
5128
5288
|
* override, else held pending value, else committed value.
|
|
5129
5289
|
*/ function visibleNodeValue(e) {
|
|
5130
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.U !== NOT_PENDING ? e.U : e.
|
|
5290
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.U !== NOT_PENDING ? e.U : e.We;
|
|
5131
5291
|
}
|
|
5132
5292
|
|
|
5133
5293
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -5182,7 +5342,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5182
5342
|
}
|
|
5183
5343
|
if (o && n in o) {
|
|
5184
5344
|
const e = o[n];
|
|
5185
|
-
s.
|
|
5345
|
+
s.ve = e === undefined ? NO_SNAPSHOT : e;
|
|
5186
5346
|
snapshotSources?.add(s);
|
|
5187
5347
|
}
|
|
5188
5348
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -5212,7 +5372,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5212
5372
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
5213
5373
|
for (const [r, i] of affectsScopes) {
|
|
5214
5374
|
if (r.k && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
5215
|
-
GlobalQueue.
|
|
5375
|
+
GlobalQueue.ie(e);
|
|
5216
5376
|
i.inherited.push(e);
|
|
5217
5377
|
}
|
|
5218
5378
|
}
|
|
@@ -5300,11 +5460,11 @@ i) {
|
|
|
5300
5460
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
5301
5461
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
5302
5462
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
5303
|
-
if (n?.k) GlobalQueue.
|
|
5463
|
+
if (n?.k) GlobalQueue._e(n);
|
|
5304
5464
|
if (affectsScopes.size) {
|
|
5305
5465
|
const r = e[STORE_VALUE];
|
|
5306
5466
|
for (const [e, i] of affectsScopes) {
|
|
5307
|
-
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.
|
|
5467
|
+
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue._e(e);
|
|
5308
5468
|
}
|
|
5309
5469
|
}
|
|
5310
5470
|
}
|
|
@@ -5321,11 +5481,11 @@ i) {
|
|
|
5321
5481
|
* @internal
|
|
5322
5482
|
*/ function getStoreAffectsNodes(e, t) {
|
|
5323
5483
|
const n = getNodes(e, STORE_NODE);
|
|
5324
|
-
GlobalQueue.
|
|
5484
|
+
GlobalQueue.ne ||= e => {
|
|
5325
5485
|
const t = affectsScopes.get(e);
|
|
5326
5486
|
if (!t) return;
|
|
5327
5487
|
affectsScopes.delete(e);
|
|
5328
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
5488
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.oe(t.inherited[e]);
|
|
5329
5489
|
};
|
|
5330
5490
|
if (t === undefined) {
|
|
5331
5491
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -5452,7 +5612,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5452
5612
|
}
|
|
5453
5613
|
const r = e[STORE_VALUE];
|
|
5454
5614
|
const i = r[n];
|
|
5455
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5615
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.Qe ?? 0) & STATUS_PENDING)) {
|
|
5456
5616
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5457
5617
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5458
5618
|
snapshotSources?.add(e);
|
|
@@ -5480,7 +5640,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5480
5640
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5481
5641
|
// optimistic engine before wrapping.
|
|
5482
5642
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5483
|
-
GlobalQueue.
|
|
5643
|
+
GlobalQueue.De(t);
|
|
5484
5644
|
}
|
|
5485
5645
|
}
|
|
5486
5646
|
|
|
@@ -5490,8 +5650,11 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5490
5650
|
* concurrent actions writing disjoint keys must revert independently, exactly
|
|
5491
5651
|
* like optimistic signal nodes do via the transition's _optimisticNodes.
|
|
5492
5652
|
* `activeTransition` is the write's transaction (action() opens it before the
|
|
5493
|
-
* body runs); null marks an ambient write
|
|
5494
|
-
*
|
|
5653
|
+
* body runs); null marks an ambient write, which clears at plain flush end —
|
|
5654
|
+
* unless its flush's transition is blocked on the store's own in-flight truth
|
|
5655
|
+
* (pending firewall, #2951), in which case it rides that transaction to
|
|
5656
|
+
* settle. Same-key writes across actions keep last-write-wins layer
|
|
5657
|
+
* semantics.
|
|
5495
5658
|
*/ function stampOptimisticOwner(e, t, n) {
|
|
5496
5659
|
if (t === STORE_OPTIMISTIC_OVERRIDE) (e[STORE_OPTIMISTIC_OWNERS] ??= Object.create(null))[n] = activeTransition;
|
|
5497
5660
|
}
|
|
@@ -5544,16 +5707,36 @@ function notifyStoreProperty(e, t, n, r, i, o) {
|
|
|
5544
5707
|
let Writing = null;
|
|
5545
5708
|
|
|
5546
5709
|
/**
|
|
5547
|
-
* A derived store
|
|
5548
|
-
*
|
|
5549
|
-
*
|
|
5550
|
-
*
|
|
5551
|
-
*
|
|
5552
|
-
*
|
|
5553
|
-
*
|
|
5554
|
-
|
|
5710
|
+
* A derived store follows async memo rules (#2897 ruling): its seed is a
|
|
5711
|
+
* draft for the derive function, never an observable value, and an errored
|
|
5712
|
+
* derive is an error state, never a silent stale/seed serve. Until the
|
|
5713
|
+
* firewall first resolves there is nothing to read, so every consumer path
|
|
5714
|
+
* throws NotReady — tracked reads through their node (core read()), and the
|
|
5715
|
+
* untracked fall-throughs in the traps through this guard. Returning the
|
|
5716
|
+
* seed leaked it; returning `undefined` would break non-nullable types.
|
|
5717
|
+
* Callers exempt the firewall itself (the derive function works its own
|
|
5718
|
+
* draft while uninitialized).
|
|
5719
|
+
*
|
|
5720
|
+
* Error rail: a firewall carrying STATUS_ERROR throws its error for every
|
|
5721
|
+
* late reader — memo parity, where read()'s error branch does the same for
|
|
5722
|
+
* plain computeds. Rejection clears STATUS_UNINITIALIZED at commit, so
|
|
5723
|
+
* without this check late readers silently got the seed while settle-time
|
|
5724
|
+
* subscribers saw the error.
|
|
5725
|
+
*
|
|
5726
|
+
* Loading rail: the veto requires the firewall to still be in flight, not
|
|
5727
|
+
* just flagged: STATUS_UNINITIALIZED's clear is deferred to batch commit,
|
|
5728
|
+
* so during the settle flush a firewall that has already recomputed — and
|
|
5729
|
+
* reconciled real values into STORE_VALUE — still carries the stale flag.
|
|
5730
|
+
* STATUS_PENDING is the live bit (it clears eagerly at settle, mirroring
|
|
5731
|
+
* core read()'s verdict), so gating on it stops the guard from throwing a
|
|
5732
|
+
* fresh NotReadyError that nothing would ever sweep. #2944: mapArray's
|
|
5733
|
+
* keyed diff reads items inside its internal owner (untracked by design)
|
|
5734
|
+
* in exactly this window, and the stale throw wedged <For> permanently.
|
|
5735
|
+
*/ function throwIfUnreadable(e) {
|
|
5555
5736
|
const t = e[STORE_FIREWALL];
|
|
5556
|
-
if (t
|
|
5737
|
+
if (!t) return;
|
|
5738
|
+
const n = t.Qe;
|
|
5739
|
+
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.we ?? new NotReadyError(t);
|
|
5557
5740
|
}
|
|
5558
5741
|
|
|
5559
5742
|
const storeTraps = {
|
|
@@ -5647,7 +5830,7 @@ const storeTraps = {
|
|
|
5647
5830
|
// threw a fresh NotReadyError for an already-settled source, which no
|
|
5648
5831
|
// sweep would ever release (#2938: projection over an async store wedged
|
|
5649
5832
|
// its Loading boundary on `undefined`).
|
|
5650
|
-
if (!r && !getObserver())
|
|
5833
|
+
if (!r && !getObserver()) throwIfUnreadable(e);
|
|
5651
5834
|
return isWrappable(f) ? wrap(f, e) : f;
|
|
5652
5835
|
},
|
|
5653
5836
|
has(e, t) {
|
|
@@ -5667,7 +5850,7 @@ const storeTraps = {
|
|
|
5667
5850
|
if (getObserver()) {
|
|
5668
5851
|
return read(getNode(e, i, t, r));
|
|
5669
5852
|
}
|
|
5670
|
-
|
|
5853
|
+
throwIfUnreadable(e);
|
|
5671
5854
|
return r;
|
|
5672
5855
|
},
|
|
5673
5856
|
set(e, t, n) {
|
|
@@ -5797,7 +5980,7 @@ const storeTraps = {
|
|
|
5797
5980
|
// path is exempt (like the get/has traps' writeOnly early returns):
|
|
5798
5981
|
// the first landing's reconcile enumerates the store while
|
|
5799
5982
|
// STATUS_UNINITIALIZED is still set — it IS the initialization.
|
|
5800
|
-
if (!getObserver() && !writeOnly(e[$PROXY]))
|
|
5983
|
+
if (!getObserver() && !writeOnly(e[$PROXY])) throwIfUnreadable(e);
|
|
5801
5984
|
}
|
|
5802
5985
|
// Merge optimistic override with regular override for key enumeration
|
|
5803
5986
|
let t = getKeys(e[STORE_VALUE], e[STORE_OVERRIDE], false);
|
|
@@ -5915,17 +6098,17 @@ function createStore(e, t, n) {
|
|
|
5915
6098
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5916
6099
|
* no visual change.
|
|
5917
6100
|
*/ function notifyMarkBoundaries(e) {
|
|
5918
|
-
if (!e.
|
|
6101
|
+
if (!e.V && !e.rt) return;
|
|
5919
6102
|
const t = new NotReadyError(e);
|
|
5920
|
-
t.
|
|
6103
|
+
t.me = true;
|
|
5921
6104
|
const n = new Set;
|
|
5922
6105
|
const visit = e => {
|
|
5923
6106
|
if (n.has(e)) return;
|
|
5924
6107
|
n.add(e);
|
|
5925
6108
|
// Display consumers (render effects, boundary computeds) act on the
|
|
5926
6109
|
// notification; descent stops there, exactly like the status rails.
|
|
5927
|
-
if (e.
|
|
5928
|
-
e.
|
|
6110
|
+
if (e.yt) {
|
|
6111
|
+
e.yt(STATUS_PENDING, t);
|
|
5929
6112
|
return;
|
|
5930
6113
|
}
|
|
5931
6114
|
forEachDependent(e, visit);
|
|
@@ -5946,7 +6129,7 @@ function createStore(e, t, n) {
|
|
|
5946
6129
|
globalQueue.D.L.push(e);
|
|
5947
6130
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5948
6131
|
// without them there is no materialized verdict to poke.
|
|
5949
|
-
GlobalQueue.
|
|
6132
|
+
GlobalQueue.Oe !== null && GlobalQueue.Oe(e);
|
|
5950
6133
|
notifyMarkBoundaries(e);
|
|
5951
6134
|
schedule();
|
|
5952
6135
|
}
|
|
@@ -5960,8 +6143,8 @@ function createStore(e, t, n) {
|
|
|
5960
6143
|
shiftAffectsMarks(-1);
|
|
5961
6144
|
e.k--;
|
|
5962
6145
|
if (!e.k) {
|
|
5963
|
-
GlobalQueue.
|
|
5964
|
-
GlobalQueue.
|
|
6146
|
+
GlobalQueue.Oe !== null && GlobalQueue.Oe(e, true);
|
|
6147
|
+
GlobalQueue.ne?.(e);
|
|
5965
6148
|
}
|
|
5966
6149
|
}
|
|
5967
6150
|
|
|
@@ -5978,11 +6161,11 @@ function createStore(e, t, n) {
|
|
|
5978
6161
|
// Each call site is gated by state only this module creates (a non-empty
|
|
5979
6162
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
5980
6163
|
// hooks are installed before the first time any of them can fire.
|
|
5981
|
-
GlobalQueue.
|
|
6164
|
+
GlobalQueue.re = releaseAffectsMarks;
|
|
5982
6165
|
|
|
5983
|
-
GlobalQueue.
|
|
6166
|
+
GlobalQueue.ie = markAffects;
|
|
5984
6167
|
|
|
5985
|
-
GlobalQueue.
|
|
6168
|
+
GlobalQueue.oe = releaseAffectsMark;
|
|
5986
6169
|
|
|
5987
6170
|
function affects(e, t) {
|
|
5988
6171
|
const n = e?.[$TARGET];
|
|
@@ -6003,7 +6186,26 @@ function createOptimisticStore(e, t, n) {
|
|
|
6003
6186
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
6004
6187
|
// node can be created.
|
|
6005
6188
|
installOptimisticEngine();
|
|
6006
|
-
GlobalQueue.
|
|
6189
|
+
if (!GlobalQueue.te) {
|
|
6190
|
+
GlobalQueue.te = clearOptimisticStores;
|
|
6191
|
+
// Store half of the engine's override blockage (#2951): signal-form
|
|
6192
|
+
// createOptimistic carries the pending async and the override on ONE node,
|
|
6193
|
+
// so transitionBlocked sees both; a derived optimistic STORE splits them —
|
|
6194
|
+
// the layer sits on store targets while the in-flight truth lives on the
|
|
6195
|
+
// firewall computed. Without this, the transition adopting a bare store
|
|
6196
|
+
// write settled in the same flush that started the refetch and its settle
|
|
6197
|
+
// consumed the layer mid-flight (follow-up writes then drafted from base,
|
|
6198
|
+
// clobbering instead of composing). Optimistic state clears when truth
|
|
6199
|
+
// lands or its transaction ends — never mid-refetch. Wrapped here (engine
|
|
6200
|
+
// is already installed above) so store-free apps never carry the check.
|
|
6201
|
+
const e = GlobalQueue.Ie;
|
|
6202
|
+
GlobalQueue.Ie = t => {
|
|
6203
|
+
for (const e of t.G) {
|
|
6204
|
+
if ((e[$TARGET]?.[STORE_FIREWALL]?.Qe ?? 0) & STATUS_PENDING) return true;
|
|
6205
|
+
}
|
|
6206
|
+
return e(t);
|
|
6207
|
+
};
|
|
6208
|
+
}
|
|
6007
6209
|
const r = typeof e === "function";
|
|
6008
6210
|
// Plain form: the second slot carries options.
|
|
6009
6211
|
if (!r && n === undefined) n = t;
|
|
@@ -6082,10 +6284,10 @@ function clearOptimisticStores(e, t) {
|
|
|
6082
6284
|
const i = isWrappable(r) ? wrap(r, e) : r;
|
|
6083
6285
|
const o = visibleNodeValue(a);
|
|
6084
6286
|
a.A = NOT_PENDING;
|
|
6085
|
-
a.
|
|
6287
|
+
a.p = null;
|
|
6086
6288
|
a.U = NOT_PENDING;
|
|
6087
|
-
a.
|
|
6088
|
-
if (!a.
|
|
6289
|
+
a.We = i;
|
|
6290
|
+
if (!a.ht || !a.ht(o, i)) {
|
|
6089
6291
|
insertSubs(a, true);
|
|
6090
6292
|
schedule();
|
|
6091
6293
|
}
|
|
@@ -6159,12 +6361,12 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6159
6361
|
r = computed(() => {
|
|
6160
6362
|
setProjectionWriteActive(true);
|
|
6161
6363
|
try {
|
|
6162
|
-
runProjectionComputed(s, e, n?.key
|
|
6364
|
+
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key, wrapCommit, clearProjectionOverride);
|
|
6163
6365
|
} finally {
|
|
6164
6366
|
setProjectionWriteActive(false);
|
|
6165
6367
|
}
|
|
6166
6368
|
}, undefined);
|
|
6167
|
-
r.
|
|
6369
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6168
6370
|
}
|
|
6169
6371
|
return {
|
|
6170
6372
|
store: s,
|
|
@@ -6588,24 +6790,24 @@ function mapArray(e, t, n) {
|
|
|
6588
6790
|
const i = t.length > 1;
|
|
6589
6791
|
const o = t;
|
|
6590
6792
|
const s = {
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6793
|
+
vt: createOwner(),
|
|
6794
|
+
Lt: 0,
|
|
6795
|
+
Gt: e,
|
|
6594
6796
|
Vt: [],
|
|
6595
|
-
|
|
6596
|
-
Ut: [],
|
|
6797
|
+
Ut: o,
|
|
6597
6798
|
kt: [],
|
|
6598
|
-
Wt:
|
|
6599
|
-
Ft: r
|
|
6600
|
-
xt:
|
|
6601
|
-
Qt: n?.keyed
|
|
6602
|
-
Ht: n?.
|
|
6799
|
+
Wt: [],
|
|
6800
|
+
Ft: r,
|
|
6801
|
+
xt: r || n?.keyed === false ? [] : undefined,
|
|
6802
|
+
Qt: i && n?.keyed !== false ? [] : undefined,
|
|
6803
|
+
Ht: n?.keyed === false,
|
|
6804
|
+
Mt: n?.fallback
|
|
6603
6805
|
};
|
|
6604
6806
|
const u = computed(updateKeyedMap.bind(s));
|
|
6605
6807
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6606
6808
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6607
|
-
s.
|
|
6608
|
-
u.
|
|
6809
|
+
s.vt.et = u;
|
|
6810
|
+
u.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6609
6811
|
return accessor(u);
|
|
6610
6812
|
}
|
|
6611
6813
|
|
|
@@ -6623,52 +6825,52 @@ const pureOptions = {
|
|
|
6623
6825
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6624
6826
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6625
6827
|
function updateKeyedMap() {
|
|
6626
|
-
const e = this.
|
|
6828
|
+
const e = this.Gt() || [], t = e.length;
|
|
6627
6829
|
e[$TRACK];
|
|
6628
6830
|
// top level tracking
|
|
6629
|
-
runWithOwner(this.
|
|
6831
|
+
runWithOwner(this.vt, () => {
|
|
6630
6832
|
let n, r, i, o,
|
|
6631
6833
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6632
6834
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6633
|
-
s = this.
|
|
6835
|
+
s = this.xt ? this.Ht ? () => {
|
|
6634
6836
|
i[r] = signal(e[r], pureOptions);
|
|
6635
|
-
return this.
|
|
6837
|
+
return this.Ut(accessor(i[r]), r);
|
|
6636
6838
|
} : () => {
|
|
6637
6839
|
i[r] = signal(e[r], pureOptions);
|
|
6638
6840
|
o && (o[r] = signal(r, pureOptions));
|
|
6639
|
-
return this.
|
|
6640
|
-
} : this.
|
|
6841
|
+
return this.Ut(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6842
|
+
} : this.Qt ? () => {
|
|
6641
6843
|
const t = e[r];
|
|
6642
6844
|
o[r] = signal(r, pureOptions);
|
|
6643
|
-
return this.
|
|
6845
|
+
return this.Ut(t, accessor(o[r]));
|
|
6644
6846
|
} : () => {
|
|
6645
6847
|
const t = e[r];
|
|
6646
|
-
return this.
|
|
6848
|
+
return this.Ut(t);
|
|
6647
6849
|
};
|
|
6648
6850
|
// fast path for empty arrays
|
|
6649
6851
|
if (t === 0) {
|
|
6650
|
-
if (this.
|
|
6651
|
-
this.
|
|
6652
|
-
this.
|
|
6852
|
+
if (this.Lt !== 0) {
|
|
6853
|
+
this.vt.dispose(false);
|
|
6854
|
+
this.Wt = [];
|
|
6653
6855
|
this.Vt = [];
|
|
6654
|
-
this.
|
|
6655
|
-
this.
|
|
6656
|
-
this.Ft && (this.Ft = []);
|
|
6856
|
+
this.kt = [];
|
|
6857
|
+
this.Lt = 0;
|
|
6657
6858
|
this.xt && (this.xt = []);
|
|
6859
|
+
this.Qt && (this.Qt = []);
|
|
6658
6860
|
}
|
|
6659
|
-
if (this.
|
|
6861
|
+
if (this.Mt && !this.kt[0]) {
|
|
6660
6862
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6661
6863
|
// dispose it before re-creating
|
|
6662
|
-
this.
|
|
6663
|
-
this.
|
|
6864
|
+
this.Wt[0]?.dispose();
|
|
6865
|
+
this.kt[0] = runWithOwner(this.Wt[0] = createOwner(), this.Mt);
|
|
6664
6866
|
}
|
|
6665
6867
|
}
|
|
6666
6868
|
// fast path for new create
|
|
6667
|
-
else if (this.
|
|
6869
|
+
else if (this.Lt === 0) {
|
|
6668
6870
|
const u = new Array(t);
|
|
6669
6871
|
const l = new Array(t);
|
|
6670
|
-
i = this.
|
|
6671
|
-
o = this.
|
|
6872
|
+
i = this.xt && new Array(t);
|
|
6873
|
+
o = this.Qt && new Array(t);
|
|
6672
6874
|
try {
|
|
6673
6875
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6674
6876
|
} catch (e) {
|
|
@@ -6676,43 +6878,43 @@ function updateKeyedMap() {
|
|
|
6676
6878
|
throw e;
|
|
6677
6879
|
}
|
|
6678
6880
|
// commit
|
|
6679
|
-
if (this.
|
|
6881
|
+
if (this.Wt[0]) this.Wt[0].dispose();
|
|
6680
6882
|
// previous fallback
|
|
6681
|
-
this.
|
|
6682
|
-
this.
|
|
6683
|
-
i && (this.
|
|
6684
|
-
o && (this.
|
|
6883
|
+
this.kt = u;
|
|
6884
|
+
this.Wt = l;
|
|
6885
|
+
i && (this.xt = i);
|
|
6886
|
+
o && (this.Qt = o);
|
|
6685
6887
|
this.Vt = e.slice(0);
|
|
6686
|
-
this.
|
|
6888
|
+
this.Lt = t;
|
|
6687
6889
|
} else {
|
|
6688
6890
|
let u, l, a, c, f, E, d, S, T;
|
|
6689
6891
|
// skip common prefix
|
|
6690
|
-
for (u = 0, l = Math.min(this.
|
|
6691
|
-
if (this.
|
|
6892
|
+
for (u = 0, l = Math.min(this.Lt, t); u < l && (this.Vt[u] === e[u] || this.xt && compare(this.Ft, this.Vt[u], e[u])); u++) {
|
|
6893
|
+
if (this.xt) setSignal(this.xt[u], e[u]);
|
|
6692
6894
|
}
|
|
6693
6895
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6694
6896
|
// at commit instead of being staged and copied twice
|
|
6695
|
-
for (l = this.
|
|
6897
|
+
for (l = this.Lt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.xt && compare(this.Ft, this.Vt[l], e[a])); l--,
|
|
6696
6898
|
a--) ;
|
|
6697
6899
|
// no structural change (every position matched in place at equal
|
|
6698
6900
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6699
6901
|
// array identity so downstream consumers don't re-run at all
|
|
6700
|
-
if (u === t && this.
|
|
6902
|
+
if (u === t && this.Lt === t) {
|
|
6701
6903
|
this.Vt = e.slice(0);
|
|
6702
6904
|
return;
|
|
6703
6905
|
}
|
|
6704
|
-
const O = t - this.
|
|
6906
|
+
const O = t - this.Lt;
|
|
6705
6907
|
const _ = new Array(t);
|
|
6706
|
-
const
|
|
6707
|
-
i = this.
|
|
6708
|
-
o = this.
|
|
6908
|
+
const R = new Array(t);
|
|
6909
|
+
i = this.xt ? new Array(t) : undefined;
|
|
6910
|
+
o = this.Qt ? new Array(t) : undefined;
|
|
6709
6911
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6710
6912
|
// scanning backwards so we encounter them in natural order
|
|
6711
6913
|
E = new Map;
|
|
6712
6914
|
d = new Array(a + 1);
|
|
6713
6915
|
for (r = a; r >= u; r--) {
|
|
6714
6916
|
c = e[r];
|
|
6715
|
-
f = this.
|
|
6917
|
+
f = this.Ft ? this.Ft(c) : c;
|
|
6716
6918
|
n = E.get(f);
|
|
6717
6919
|
d[r] = n === undefined ? -1 : n;
|
|
6718
6920
|
E.set(f, r);
|
|
@@ -6722,23 +6924,23 @@ function updateKeyedMap() {
|
|
|
6722
6924
|
// queue them for disposal at commit
|
|
6723
6925
|
for (n = u; n <= l; n++) {
|
|
6724
6926
|
c = this.Vt[n];
|
|
6725
|
-
f = this.
|
|
6927
|
+
f = this.Ft ? this.Ft(c) : c;
|
|
6726
6928
|
r = E.get(f);
|
|
6727
6929
|
if (r !== undefined && r !== -1) {
|
|
6728
|
-
_[r] = this.
|
|
6729
|
-
|
|
6730
|
-
i && (i[r] = this.
|
|
6731
|
-
o && (o[r] = this.
|
|
6930
|
+
_[r] = this.kt[n];
|
|
6931
|
+
R[r] = this.Wt[n];
|
|
6932
|
+
i && (i[r] = this.xt[n]);
|
|
6933
|
+
o && (o[r] = this.Qt[n]);
|
|
6732
6934
|
r = d[r];
|
|
6733
6935
|
E.set(f, r);
|
|
6734
|
-
} else (S ??= []).push(this.
|
|
6936
|
+
} else (S ??= []).push(this.Wt[n]);
|
|
6735
6937
|
}
|
|
6736
6938
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6737
6939
|
try {
|
|
6738
6940
|
for (r = u; r <= a; r++) {
|
|
6739
|
-
if (
|
|
6740
|
-
(T ??= []).push(
|
|
6741
|
-
_[r] = runWithOwner(
|
|
6941
|
+
if (R[r] !== undefined) continue;
|
|
6942
|
+
(T ??= []).push(R[r] = createOwner());
|
|
6943
|
+
_[r] = runWithOwner(R[r], s);
|
|
6742
6944
|
}
|
|
6743
6945
|
} catch (e) {
|
|
6744
6946
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
@@ -6748,38 +6950,38 @@ function updateKeyedMap() {
|
|
|
6748
6950
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
6749
6951
|
// change propagation), then dispose exited rows
|
|
6750
6952
|
for (n = 0; n < u; n++) {
|
|
6751
|
-
_[n] = this.
|
|
6752
|
-
|
|
6753
|
-
i && (i[n] = this.
|
|
6754
|
-
o && (o[n] = this.
|
|
6953
|
+
_[n] = this.kt[n];
|
|
6954
|
+
R[n] = this.Wt[n];
|
|
6955
|
+
i && (i[n] = this.xt[n]);
|
|
6956
|
+
o && (o[n] = this.Qt[n]);
|
|
6755
6957
|
}
|
|
6756
6958
|
for (r = u; r <= a; r++) {
|
|
6757
6959
|
if (i) setSignal(i[r], e[r]);
|
|
6758
6960
|
if (o) setSignal(o[r], r);
|
|
6759
6961
|
}
|
|
6760
6962
|
for (r = a + 1; r < t; r++) {
|
|
6761
|
-
_[r] = this.
|
|
6762
|
-
|
|
6963
|
+
_[r] = this.kt[r - O];
|
|
6964
|
+
R[r] = this.Wt[r - O];
|
|
6763
6965
|
if (i) {
|
|
6764
|
-
i[r] = this.
|
|
6966
|
+
i[r] = this.xt[r - O];
|
|
6765
6967
|
setSignal(i[r], e[r]);
|
|
6766
6968
|
}
|
|
6767
6969
|
if (o) {
|
|
6768
|
-
o[r] = this.
|
|
6970
|
+
o[r] = this.Qt[r - O];
|
|
6769
6971
|
if (O !== 0) setSignal(o[r], r);
|
|
6770
6972
|
}
|
|
6771
6973
|
}
|
|
6772
|
-
this.
|
|
6773
|
-
this.
|
|
6774
|
-
i && (this.
|
|
6775
|
-
o && (this.
|
|
6776
|
-
this.
|
|
6974
|
+
this.kt = _;
|
|
6975
|
+
this.Wt = R;
|
|
6976
|
+
i && (this.xt = i);
|
|
6977
|
+
o && (this.Qt = o);
|
|
6978
|
+
this.Lt = t;
|
|
6777
6979
|
// save a copy of the mapped items for the next update
|
|
6778
6980
|
this.Vt = e.slice(0);
|
|
6779
6981
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6780
6982
|
}
|
|
6781
6983
|
});
|
|
6782
|
-
return this.
|
|
6984
|
+
return this.kt;
|
|
6783
6985
|
}
|
|
6784
6986
|
|
|
6785
6987
|
/**
|
|
@@ -6799,22 +7001,22 @@ function updateKeyedMap() {
|
|
|
6799
7001
|
*/ function repeat(e, t, n) {
|
|
6800
7002
|
const r = t;
|
|
6801
7003
|
const i = {
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
7004
|
+
vt: createOwner(),
|
|
7005
|
+
Lt: 0,
|
|
7006
|
+
$t: 0,
|
|
7007
|
+
jt: e,
|
|
7008
|
+
Ut: r,
|
|
7009
|
+
Wt: [],
|
|
6807
7010
|
kt: [],
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
Ht: n?.fallback
|
|
7011
|
+
Kt: n?.from,
|
|
7012
|
+
Mt: n?.fallback
|
|
6811
7013
|
};
|
|
6812
7014
|
const o = computed(updateRepeat.bind(i));
|
|
6813
7015
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6814
7016
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6815
7017
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6816
|
-
i.
|
|
6817
|
-
o.
|
|
7018
|
+
i.vt.et = o;
|
|
7019
|
+
o.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6818
7020
|
return accessor(o);
|
|
6819
7021
|
}
|
|
6820
7022
|
|
|
@@ -6826,55 +7028,55 @@ function updateKeyedMap() {
|
|
|
6826
7028
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
6827
7029
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
6828
7030
|
function updateRepeat() {
|
|
6829
|
-
const e = this
|
|
6830
|
-
const t = this.
|
|
6831
|
-
runWithOwner(this.
|
|
7031
|
+
const e = this.jt();
|
|
7032
|
+
const t = this.Kt?.() || 0;
|
|
7033
|
+
runWithOwner(this.vt, () => {
|
|
6832
7034
|
if (e === 0) {
|
|
6833
|
-
if (this.
|
|
6834
|
-
this.
|
|
7035
|
+
if (this.Lt !== 0) {
|
|
7036
|
+
this.vt.dispose(false);
|
|
7037
|
+
this.Wt = [];
|
|
6835
7038
|
this.kt = [];
|
|
6836
|
-
this.
|
|
6837
|
-
this.vt = 0;
|
|
7039
|
+
this.Lt = 0;
|
|
6838
7040
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6839
|
-
this
|
|
7041
|
+
this.$t = 0;
|
|
6840
7042
|
}
|
|
6841
|
-
if (this.
|
|
7043
|
+
if (this.Mt && !this.kt[0]) {
|
|
6842
7044
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6843
7045
|
// dispose it before re-creating
|
|
6844
|
-
this.
|
|
6845
|
-
this.
|
|
7046
|
+
this.Wt[0]?.dispose();
|
|
7047
|
+
this.kt[0] = runWithOwner(this.Wt[0] = createOwner(), this.Mt);
|
|
6846
7048
|
}
|
|
6847
7049
|
return;
|
|
6848
7050
|
}
|
|
6849
7051
|
const n = t + e;
|
|
6850
|
-
const r = this
|
|
7052
|
+
const r = this.$t + this.Lt;
|
|
6851
7053
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6852
7054
|
// windows are disjoint or when coming from empty/fallback.
|
|
6853
|
-
const i = Math.max(t, this
|
|
7055
|
+
const i = Math.max(t, this.$t);
|
|
6854
7056
|
const o = Math.min(n, r);
|
|
6855
7057
|
const s = new Array(e);
|
|
6856
7058
|
const u = new Array(e);
|
|
6857
7059
|
for (let e = i; e < o; e++) {
|
|
6858
|
-
u[e - t] = this.
|
|
6859
|
-
s[e - t] = this.
|
|
7060
|
+
u[e - t] = this.Wt[e - this.$t];
|
|
7061
|
+
s[e - t] = this.kt[e - this.$t];
|
|
6860
7062
|
}
|
|
6861
7063
|
try {
|
|
6862
7064
|
for (let e = t; e < n; e++) {
|
|
6863
7065
|
if (e >= i && e < o) continue;
|
|
6864
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
7066
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Ut(e));
|
|
6865
7067
|
}
|
|
6866
7068
|
} catch (e) {
|
|
6867
7069
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6868
7070
|
throw e;
|
|
6869
7071
|
}
|
|
6870
7072
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6871
|
-
if (this.
|
|
6872
|
-
this.
|
|
6873
|
-
this.
|
|
6874
|
-
this
|
|
6875
|
-
this.
|
|
7073
|
+
if (this.Lt === 0) this.Wt[0]?.dispose(); else for (let e = this.$t; e < r; e++) if (e < t || e >= n) this.Wt[e - this.$t].dispose();
|
|
7074
|
+
this.kt = s;
|
|
7075
|
+
this.Wt = u;
|
|
7076
|
+
this.$t = t;
|
|
7077
|
+
this.Lt = e;
|
|
6876
7078
|
});
|
|
6877
|
-
return this.
|
|
7079
|
+
return this.kt;
|
|
6878
7080
|
}
|
|
6879
7081
|
|
|
6880
7082
|
function compare(e, t, n) {
|
|
@@ -6885,23 +7087,23 @@ function boundaryComputed(e, t) {
|
|
|
6885
7087
|
const n = computed(e, {
|
|
6886
7088
|
lazy: true
|
|
6887
7089
|
});
|
|
6888
|
-
n.
|
|
7090
|
+
n.yt = (e, t) => {
|
|
6889
7091
|
// Use passed values if provided, otherwise read from node
|
|
6890
|
-
const r = e !== undefined ? e : n.
|
|
6891
|
-
const i = t !== undefined ? t : n.
|
|
7092
|
+
const r = e !== undefined ? e : n.Qe;
|
|
7093
|
+
const i = t !== undefined ? t : n.we;
|
|
6892
7094
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6893
7095
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6894
7096
|
// a boundary that handles it is found.
|
|
6895
|
-
n.
|
|
6896
|
-
const o = n.
|
|
7097
|
+
n.Qe &= ~n.Yt;
|
|
7098
|
+
const o = n.Ze.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6897
7099
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6898
7100
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
6899
7101
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
6900
7102
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6901
|
-
const s = r & ~n.
|
|
7103
|
+
const s = r & ~n.Yt & (STATUS_PENDING | STATUS_ERROR);
|
|
6902
7104
|
if (s) {
|
|
6903
|
-
n.
|
|
6904
|
-
if (n.
|
|
7105
|
+
n.Qe &= ~s;
|
|
7106
|
+
if (n.we === i && !(n.Qe & (STATUS_PENDING | STATUS_ERROR))) n.we = undefined;
|
|
6905
7107
|
}
|
|
6906
7108
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6907
7109
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6912,16 +7114,16 @@ function boundaryComputed(e, t) {
|
|
|
6912
7114
|
throw i;
|
|
6913
7115
|
}
|
|
6914
7116
|
};
|
|
6915
|
-
n.
|
|
6916
|
-
n.
|
|
7117
|
+
n.Yt = t;
|
|
7118
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6917
7119
|
recompute(n, true);
|
|
6918
7120
|
return n;
|
|
6919
7121
|
}
|
|
6920
7122
|
|
|
6921
7123
|
function createBoundChildren(e, t, n, r) {
|
|
6922
|
-
const i = e.
|
|
6923
|
-
i.addChild(e.
|
|
6924
|
-
cleanup(() => i.removeChild(e.
|
|
7124
|
+
const i = e.Ze;
|
|
7125
|
+
i.addChild(e.Ze = n);
|
|
7126
|
+
cleanup(() => i.removeChild(e.Ze));
|
|
6925
7127
|
return runWithOwner(e, () => {
|
|
6926
7128
|
const e = computed(t);
|
|
6927
7129
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -6943,53 +7145,53 @@ function isRevealController(e) {
|
|
|
6943
7145
|
}
|
|
6944
7146
|
|
|
6945
7147
|
function isSlotReady(e) {
|
|
6946
|
-
return isRevealController(e) ? e.
|
|
7148
|
+
return isRevealController(e) ? e.qt() : e.Bt.size === 0 && !e.Zt;
|
|
6947
7149
|
}
|
|
6948
7150
|
|
|
6949
7151
|
function isSlotMinimallyReady(e) {
|
|
6950
|
-
return isRevealController(e) ? e.
|
|
7152
|
+
return isRevealController(e) ? e.Xt() : isSlotReady(e);
|
|
6951
7153
|
}
|
|
6952
7154
|
|
|
6953
7155
|
function setSlotState(e, t, n, r) {
|
|
6954
|
-
setSignal(e.
|
|
6955
|
-
setSignal(e.
|
|
7156
|
+
setSignal(e.zt, n);
|
|
7157
|
+
setSignal(e.Jt, r);
|
|
6956
7158
|
if (isRevealController(e)) {
|
|
6957
|
-
if (!n && e.
|
|
6958
|
-
return e.
|
|
7159
|
+
if (!n && e.en === t) e.en = undefined;
|
|
7160
|
+
return e.tn(n, r);
|
|
6959
7161
|
}
|
|
6960
|
-
if (!n && e.
|
|
7162
|
+
if (!n && e.nn === t && e.rn) e.nn = undefined;
|
|
6961
7163
|
}
|
|
6962
7164
|
|
|
6963
7165
|
class RevealController {
|
|
6964
|
-
rn;
|
|
6965
7166
|
sn;
|
|
6966
|
-
un
|
|
6967
|
-
|
|
6968
|
-
|
|
7167
|
+
un;
|
|
7168
|
+
ln=[];
|
|
7169
|
+
en;
|
|
7170
|
+
zt=signal(false, {
|
|
6969
7171
|
ownedWrite: true,
|
|
6970
|
-
|
|
7172
|
+
gt: true
|
|
6971
7173
|
});
|
|
6972
|
-
|
|
7174
|
+
Jt=signal(false, {
|
|
6973
7175
|
ownedWrite: true,
|
|
6974
|
-
|
|
7176
|
+
gt: true
|
|
6975
7177
|
});
|
|
6976
|
-
ln=true;
|
|
6977
7178
|
an=true;
|
|
6978
|
-
cn=
|
|
7179
|
+
cn=true;
|
|
7180
|
+
fn=false;
|
|
6979
7181
|
constructor(e, t) {
|
|
6980
|
-
this.
|
|
6981
|
-
this.
|
|
7182
|
+
this.sn = e;
|
|
7183
|
+
this.un = t;
|
|
6982
7184
|
}
|
|
6983
|
-
|
|
6984
|
-
for (let t = 0; t < this.
|
|
6985
|
-
const n = this.
|
|
6986
|
-
if ((isRevealController(n) ? n.
|
|
7185
|
+
En(e) {
|
|
7186
|
+
for (let t = 0; t < this.ln.length; t++) {
|
|
7187
|
+
const n = this.ln[t];
|
|
7188
|
+
if ((isRevealController(n) ? n.en : n.nn) !== this) continue;
|
|
6987
7189
|
if (e(n) === false) return false;
|
|
6988
7190
|
}
|
|
6989
7191
|
return true;
|
|
6990
7192
|
}
|
|
6991
|
-
|
|
6992
|
-
return this.
|
|
7193
|
+
qt() {
|
|
7194
|
+
return this.En(isSlotReady);
|
|
6993
7195
|
}
|
|
6994
7196
|
/**
|
|
6995
7197
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -6997,13 +7199,13 @@ class RevealController {
|
|
|
6997
7199
|
* - `together`: every direct slot is minimally ready.
|
|
6998
7200
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
6999
7201
|
* - `natural`: any owned slot is minimally ready.
|
|
7000
|
-
*/
|
|
7001
|
-
const e = untrack(this.
|
|
7002
|
-
if (e === "together") return this.
|
|
7202
|
+
*/ Xt() {
|
|
7203
|
+
const e = untrack(this.sn);
|
|
7204
|
+
if (e === "together") return this.En(isSlotMinimallyReady);
|
|
7003
7205
|
if (e === "natural") {
|
|
7004
7206
|
let e = false;
|
|
7005
7207
|
let t = false;
|
|
7006
|
-
this.
|
|
7208
|
+
this.En(n => {
|
|
7007
7209
|
e = true;
|
|
7008
7210
|
if (isSlotMinimallyReady(n)) {
|
|
7009
7211
|
t = true;
|
|
@@ -7014,45 +7216,45 @@ class RevealController {
|
|
|
7014
7216
|
}
|
|
7015
7217
|
// sequential: only the first owned slot matters.
|
|
7016
7218
|
let t = true;
|
|
7017
|
-
this.
|
|
7219
|
+
this.En(e => {
|
|
7018
7220
|
t = isSlotMinimallyReady(e);
|
|
7019
7221
|
return false;
|
|
7020
7222
|
});
|
|
7021
7223
|
return t;
|
|
7022
7224
|
}
|
|
7023
|
-
En(e) {
|
|
7024
|
-
if (this.un.includes(e)) return;
|
|
7025
|
-
this.un.push(e);
|
|
7026
|
-
const t = untrack(this.rn);
|
|
7027
|
-
setSignal(e.Xt, true), setSignal(e.zt, t === "sequential" ? !!untrack(this.sn) : false);
|
|
7028
|
-
untrack(() => this.en());
|
|
7029
|
-
}
|
|
7030
7225
|
dn(e) {
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
untrack(
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
const
|
|
7039
|
-
|
|
7226
|
+
if (this.ln.includes(e)) return;
|
|
7227
|
+
this.ln.push(e);
|
|
7228
|
+
const t = untrack(this.sn);
|
|
7229
|
+
setSignal(e.zt, true), setSignal(e.Jt, t === "sequential" ? !!untrack(this.un) : false);
|
|
7230
|
+
untrack(() => this.tn());
|
|
7231
|
+
}
|
|
7232
|
+
Sn(e) {
|
|
7233
|
+
const t = this.ln.indexOf(e);
|
|
7234
|
+
if (t >= 0) this.ln.splice(t, 1);
|
|
7235
|
+
untrack(() => this.tn());
|
|
7236
|
+
}
|
|
7237
|
+
tn(e, t) {
|
|
7238
|
+
if (this.fn) return;
|
|
7239
|
+
this.fn = true;
|
|
7240
|
+
const n = this.an;
|
|
7241
|
+
const r = this.cn;
|
|
7040
7242
|
try {
|
|
7041
|
-
const n = e ?? read(this.
|
|
7243
|
+
const n = e ?? read(this.zt), r = untrack(this.sn), i = r === "sequential" && !!untrack(this.un), o = t ?? i;
|
|
7042
7244
|
if (n) {
|
|
7043
7245
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
7044
7246
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
7045
7247
|
// held; it resumes once the outer releases us.
|
|
7046
|
-
this.
|
|
7248
|
+
this.En(e => setSlotState(e, this, true, o));
|
|
7047
7249
|
} else if (r === "natural") {
|
|
7048
7250
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
7049
7251
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
7050
7252
|
// so the parent backpointer survives for upward readiness notifications.
|
|
7051
|
-
this.
|
|
7253
|
+
this.En(e => {
|
|
7052
7254
|
if (isRevealController(e)) {
|
|
7255
|
+
setSignal(e.Jt, false);
|
|
7053
7256
|
setSignal(e.zt, false);
|
|
7054
|
-
|
|
7055
|
-
e.en(false, false);
|
|
7257
|
+
e.tn(false, false);
|
|
7056
7258
|
} else {
|
|
7057
7259
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
7058
7260
|
}
|
|
@@ -7063,11 +7265,11 @@ class RevealController {
|
|
|
7063
7265
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
7064
7266
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
7065
7267
|
// cohesive reveal without waiting for every grandchild.
|
|
7066
|
-
const e = this.
|
|
7067
|
-
this.
|
|
7268
|
+
const e = this.En(isSlotMinimallyReady);
|
|
7269
|
+
this.En(t => setSlotState(t, this, !e, false));
|
|
7068
7270
|
} else {
|
|
7069
7271
|
let e = false;
|
|
7070
|
-
this.
|
|
7272
|
+
this.En(t => {
|
|
7071
7273
|
if (e) return setSlotState(t, this, true, i);
|
|
7072
7274
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
7073
7275
|
e = true;
|
|
@@ -7078,63 +7280,63 @@ class RevealController {
|
|
|
7078
7280
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
7079
7281
|
// backpointer survives for upward readiness notifications.
|
|
7080
7282
|
if (isRevealController(t)) {
|
|
7283
|
+
setSignal(t.Jt, false);
|
|
7081
7284
|
setSignal(t.zt, false);
|
|
7082
|
-
|
|
7083
|
-
t.en(false, false);
|
|
7285
|
+
t.tn(false, false);
|
|
7084
7286
|
} else {
|
|
7085
7287
|
setSlotState(t, this, true, false);
|
|
7086
7288
|
}
|
|
7087
7289
|
});
|
|
7088
7290
|
}
|
|
7089
7291
|
} finally {
|
|
7090
|
-
this.
|
|
7091
|
-
this.
|
|
7092
|
-
this.
|
|
7292
|
+
this.an = this.qt();
|
|
7293
|
+
this.cn = this.Xt();
|
|
7294
|
+
this.fn = false;
|
|
7093
7295
|
}
|
|
7094
|
-
if (this.
|
|
7296
|
+
if (this.en && (n !== this.an || r !== this.cn)) this.en.tn();
|
|
7095
7297
|
}
|
|
7096
7298
|
}
|
|
7097
7299
|
|
|
7098
7300
|
class CollectionQueue extends Queue {
|
|
7099
|
-
Sn;
|
|
7100
|
-
qt=new Set;
|
|
7101
7301
|
Tn;
|
|
7102
|
-
Bt=
|
|
7103
|
-
|
|
7302
|
+
Bt=new Set;
|
|
7303
|
+
On;
|
|
7304
|
+
Zt=true;
|
|
7305
|
+
zt=signal(false, {
|
|
7104
7306
|
ownedWrite: true,
|
|
7105
|
-
|
|
7307
|
+
gt: true
|
|
7106
7308
|
});
|
|
7107
|
-
|
|
7108
|
-
|
|
7309
|
+
we;
|
|
7310
|
+
Jt=signal(false, {
|
|
7109
7311
|
ownedWrite: true,
|
|
7110
|
-
|
|
7312
|
+
gt: true
|
|
7111
7313
|
});
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7314
|
+
nn;
|
|
7315
|
+
rn=false;
|
|
7316
|
+
_n;
|
|
7317
|
+
Rn=ON_INIT;
|
|
7116
7318
|
constructor(e) {
|
|
7117
7319
|
super();
|
|
7118
|
-
this.
|
|
7320
|
+
this.Tn = e;
|
|
7119
7321
|
}
|
|
7120
7322
|
run(e) {
|
|
7121
|
-
if (!e || read(this.
|
|
7323
|
+
if (!e || read(this.zt) && (!_revealUsed || read(this.Jt))) return;
|
|
7122
7324
|
return super.run(e);
|
|
7123
7325
|
}
|
|
7124
7326
|
notify(e, t, n, r) {
|
|
7125
|
-
if (!(t & this.
|
|
7126
|
-
if (this.
|
|
7327
|
+
if (!(t & this.Tn)) return super.notify(e, t, n, r);
|
|
7328
|
+
if (this.rn && this._n) {
|
|
7127
7329
|
const e = untrack(() => {
|
|
7128
7330
|
try {
|
|
7129
|
-
return this.
|
|
7331
|
+
return this._n();
|
|
7130
7332
|
} catch {
|
|
7131
7333
|
return ON_INIT;
|
|
7132
7334
|
}
|
|
7133
7335
|
});
|
|
7134
|
-
if (e !== this.
|
|
7135
|
-
this.
|
|
7136
|
-
this.
|
|
7137
|
-
this.
|
|
7336
|
+
if (e !== this.Rn) {
|
|
7337
|
+
this.Rn = e;
|
|
7338
|
+
this.rn = false;
|
|
7339
|
+
this.Bt.clear();
|
|
7138
7340
|
}
|
|
7139
7341
|
}
|
|
7140
7342
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -7147,47 +7349,47 @@ class CollectionQueue extends Queue {
|
|
|
7147
7349
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
7148
7350
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
7149
7351
|
// (the Loading > Errored > content composition escape, #2856).
|
|
7150
|
-
if (this.
|
|
7151
|
-
if (n & this.
|
|
7152
|
-
this.
|
|
7153
|
-
const t = r?.source || e.
|
|
7352
|
+
if (this.Tn & STATUS_PENDING && this.rn) return super.notify(e, t, n, r);
|
|
7353
|
+
if (n & this.Tn) {
|
|
7354
|
+
this.Zt = true;
|
|
7355
|
+
const t = r?.source || e.we?.source;
|
|
7154
7356
|
if (t) {
|
|
7155
|
-
const e = this.
|
|
7156
|
-
this.
|
|
7157
|
-
if (e) setSignal(this.
|
|
7158
|
-
if (this.
|
|
7159
|
-
setSignal(this.
|
|
7357
|
+
const e = this.Bt.size === 0;
|
|
7358
|
+
this.Bt.add(t);
|
|
7359
|
+
if (e) setSignal(this.zt, true);
|
|
7360
|
+
if (this.Tn & STATUS_ERROR) {
|
|
7361
|
+
setSignal(this.we, unwrapStatusError(t.we));
|
|
7160
7362
|
}
|
|
7161
7363
|
}
|
|
7162
7364
|
}
|
|
7163
|
-
t &= ~this.
|
|
7365
|
+
t &= ~this.Tn;
|
|
7164
7366
|
return t ? super.notify(e, t, n, r) : true;
|
|
7165
7367
|
}
|
|
7166
|
-
|
|
7167
|
-
for (const e of this.
|
|
7368
|
+
$e() {
|
|
7369
|
+
for (const e of this.Bt) {
|
|
7168
7370
|
// A source with a live affects() mark holds display state for the
|
|
7169
7371
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7170
7372
|
// status of its own, so the count is the liveness test. The release
|
|
7171
7373
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7172
|
-
if (e.
|
|
7374
|
+
if (e.Ge & REACTIVE_DISPOSED || !e.k && !(e.Qe & this.Tn) && !(this.Tn & STATUS_ERROR && e.Qe & STATUS_PENDING)) this.Bt.delete(e);
|
|
7173
7375
|
}
|
|
7174
|
-
if (!this.
|
|
7175
|
-
if (this.
|
|
7176
|
-
this.
|
|
7376
|
+
if (!this.Bt.size) {
|
|
7377
|
+
if (this.Tn & STATUS_PENDING && this.Zt && !this.rn && this.On) {
|
|
7378
|
+
this.Zt = !!(this.On.Qe & this.Tn);
|
|
7177
7379
|
} else {
|
|
7178
|
-
this.
|
|
7380
|
+
this.Zt = false;
|
|
7179
7381
|
}
|
|
7180
|
-
if (!this.
|
|
7181
|
-
setSignal(this.
|
|
7182
|
-
if (this.
|
|
7382
|
+
if (!this.Zt) {
|
|
7383
|
+
setSignal(this.zt, false);
|
|
7384
|
+
if (this._n) {
|
|
7183
7385
|
try {
|
|
7184
|
-
this.
|
|
7386
|
+
this.Rn = untrack(() => this._n());
|
|
7185
7387
|
} catch {
|
|
7186
7388
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
7187
7389
|
}
|
|
7188
7390
|
}
|
|
7189
7391
|
}
|
|
7190
|
-
if (_revealUsed) this.tn
|
|
7392
|
+
if (_revealUsed) this.nn?.tn();
|
|
7191
7393
|
}
|
|
7192
7394
|
}
|
|
7193
7395
|
|
|
@@ -7195,12 +7397,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7195
7397
|
const i = createOwner();
|
|
7196
7398
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
7197
7399
|
const o = new CollectionQueue(e);
|
|
7198
|
-
if (e === STATUS_ERROR) o.
|
|
7400
|
+
if (e === STATUS_ERROR) o.we = signal(undefined, {
|
|
7199
7401
|
ownedWrite: true,
|
|
7200
|
-
|
|
7402
|
+
gt: true
|
|
7201
7403
|
});
|
|
7202
|
-
if (r) o.
|
|
7203
|
-
const s = o.
|
|
7404
|
+
if (r) o._n = r;
|
|
7405
|
+
const s = o.On = createBoundChildren(i, t, o, e);
|
|
7204
7406
|
// Prime source tracking so reveal registration sees pending sources.
|
|
7205
7407
|
untrack(() => {
|
|
7206
7408
|
let t = false;
|
|
@@ -7209,23 +7411,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7209
7411
|
} catch (e) {
|
|
7210
7412
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7211
7413
|
}
|
|
7212
|
-
o.
|
|
7414
|
+
o.Zt = t || !!(s.Qe & e) || s.we instanceof NotReadyError;
|
|
7213
7415
|
});
|
|
7214
7416
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7215
7417
|
if (u) {
|
|
7216
|
-
o.
|
|
7217
|
-
u.
|
|
7218
|
-
cleanup(() => u.
|
|
7418
|
+
o.nn = u;
|
|
7419
|
+
u.dn(o);
|
|
7420
|
+
cleanup(() => u.Sn(o));
|
|
7219
7421
|
}
|
|
7220
7422
|
return accessor(computed(() => {
|
|
7221
|
-
if (!read(o.
|
|
7423
|
+
if (!read(o.zt)) {
|
|
7222
7424
|
const e = read(s);
|
|
7223
|
-
if (!untrack(() => read(o.
|
|
7425
|
+
if (!untrack(() => read(o.zt))) return o.rn = true, e;
|
|
7224
7426
|
}
|
|
7225
7427
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
7226
7428
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
7227
7429
|
// outside a `createRevealOrder` scope.
|
|
7228
|
-
if (_revealUsed && read(o.
|
|
7430
|
+
if (_revealUsed && read(o.Jt)) return undefined;
|
|
7229
7431
|
return n(o);
|
|
7230
7432
|
},
|
|
7231
7433
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -7233,7 +7435,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7233
7435
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
7234
7436
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
7235
7437
|
{
|
|
7236
|
-
|
|
7438
|
+
gt: true
|
|
7237
7439
|
}));
|
|
7238
7440
|
}
|
|
7239
7441
|
|
|
@@ -7286,8 +7488,8 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7286
7488
|
* }
|
|
7287
7489
|
* ```
|
|
7288
7490
|
*/ function createErrorBoundary(e, t) {
|
|
7289
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
7290
|
-
for (const t of e.
|
|
7491
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.we), () => {
|
|
7492
|
+
for (const t of e.Bt) recompute(t);
|
|
7291
7493
|
schedule();
|
|
7292
7494
|
}));
|
|
7293
7495
|
}
|
|
@@ -7344,12 +7546,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7344
7546
|
computed(() => {
|
|
7345
7547
|
i();
|
|
7346
7548
|
o();
|
|
7347
|
-
s.
|
|
7549
|
+
s.tn();
|
|
7348
7550
|
});
|
|
7349
7551
|
if (r) {
|
|
7350
|
-
s.
|
|
7351
|
-
r.
|
|
7352
|
-
cleanup(() => r.
|
|
7552
|
+
s.en = r;
|
|
7553
|
+
r.dn(s);
|
|
7554
|
+
cleanup(() => r.Sn(s));
|
|
7353
7555
|
}
|
|
7354
7556
|
return t;
|
|
7355
7557
|
});
|