@solidjs/signals 2.0.0-beta.25 → 2.0.0-beta.27
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 +370 -73
- package/dist/node.cjs +1247 -946
- package/dist/prod/core/action.js +11 -6
- package/dist/prod/core/async.js +212 -108
- package/dist/prod/core/core.js +203 -189
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/external.js +3 -3
- package/dist/prod/core/graph.js +28 -28
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +44 -44
- package/dist/prod/core/scheduler.js +127 -106
- package/dist/prod/core/verdict.js +54 -54
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +55 -36
- package/dist/prod/store/projection.js +38 -33
- package/dist/prod/store/reconcile.js +299 -243
- package/dist/prod/store/store.js +127 -50
- package/dist/types/core/async.d.ts +2 -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 +2 -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,74 +1551,141 @@ 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
|
|
|
1572
1593
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
1573
1594
|
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
1574
1595
|
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
1596
|
+
// Settle-time counterpart of unlinkSubs' last-one-out check. A lazy node that
|
|
1597
|
+
// loses its last subscriber while STATUS_PENDING is exempt from autodispose
|
|
1598
|
+
// (the in-flight work is an observer), so whatever CLEARS that pending state
|
|
1599
|
+
// must run the release — otherwise the node stays linked and recomputes
|
|
1600
|
+
// forever with zero subscribers (#2934). The node's own promise/iterator
|
|
1601
|
+
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1602
|
+
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1603
|
+
function releaseIfSettledUnobserved(e) {
|
|
1604
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.V && !(e.Ge & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
1608
|
+
// sources through its own recursion (no per-node settle callback), so after
|
|
1609
|
+
// the propagation completes, walk the same graph for stranded lazy nodes.
|
|
1610
|
+
// Collect-then-release so unobserved() never unlinks under the walk.
|
|
1611
|
+
function releaseSettledDependents(e) {
|
|
1612
|
+
let t;
|
|
1613
|
+
const n = new Set;
|
|
1614
|
+
const visit = e => {
|
|
1615
|
+
if (n.has(e)) return;
|
|
1616
|
+
n.add(e);
|
|
1617
|
+
if (!e.V && e.Ue & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
1618
|
+
forEachDependent(e, visit);
|
|
1619
|
+
};
|
|
1620
|
+
forEachDependent(e, visit);
|
|
1621
|
+
if (t) for (const e of t) releaseIfSettledUnobserved(e);
|
|
1622
|
+
}
|
|
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
|
+
|
|
1575
1655
|
function settlePendingSource(e) {
|
|
1576
1656
|
let t = false;
|
|
1577
|
-
|
|
1657
|
+
let n;
|
|
1658
|
+
const r = new Set;
|
|
1578
1659
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1579
|
-
const
|
|
1580
|
-
const settle =
|
|
1581
|
-
if (
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
if (
|
|
1586
|
-
setPendingError(
|
|
1587
|
-
|
|
1660
|
+
const i = GlobalQueue.ae;
|
|
1661
|
+
const settle = o => {
|
|
1662
|
+
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1663
|
+
r.add(o);
|
|
1664
|
+
o.F = clock;
|
|
1665
|
+
const s = o.je?.values().next().value;
|
|
1666
|
+
if (s) {
|
|
1667
|
+
setPendingError(o, s);
|
|
1668
|
+
i !== null && i(o);
|
|
1588
1669
|
} else {
|
|
1589
|
-
|
|
1590
|
-
setPendingError(
|
|
1591
|
-
|
|
1592
|
-
if (
|
|
1593
|
-
enqueueSub(
|
|
1670
|
+
o.Qe &= ~STATUS_PENDING;
|
|
1671
|
+
setPendingError(o);
|
|
1672
|
+
i !== null && i(o);
|
|
1673
|
+
if (o.At) {
|
|
1674
|
+
enqueueSub(o);
|
|
1594
1675
|
t = true;
|
|
1595
1676
|
}
|
|
1596
|
-
|
|
1677
|
+
o.At = false;
|
|
1678
|
+
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1679
|
+
// again at release time — deferred so unobserved() can't unlink subs
|
|
1680
|
+
// lists this walk is still iterating.
|
|
1681
|
+
if (!o.V && o.Ue & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
1597
1682
|
}
|
|
1598
|
-
forEachDependent(
|
|
1683
|
+
forEachDependent(o, settle);
|
|
1599
1684
|
};
|
|
1600
1685
|
forEachDependent(e, settle);
|
|
1686
|
+
// Release before the flush schedule below: unobserved() pulls the node back
|
|
1687
|
+
// out of the heap, so the enqueueSub above never recomputes a released node.
|
|
1688
|
+
if (n) for (const e of n) releaseIfSettledUnobserved(e);
|
|
1601
1689
|
if (t) schedule();
|
|
1602
1690
|
}
|
|
1603
1691
|
|
|
@@ -1616,26 +1704,51 @@ function handleAsync(e, t, n) {
|
|
|
1616
1704
|
});
|
|
1617
1705
|
}
|
|
1618
1706
|
if (!i && !r) {
|
|
1619
|
-
e.
|
|
1707
|
+
e.lt = null;
|
|
1620
1708
|
return t;
|
|
1621
1709
|
}
|
|
1622
|
-
e.
|
|
1710
|
+
e.lt = t;
|
|
1623
1711
|
let o;
|
|
1712
|
+
// Settle-time transition re-entry. The loading rail is invisible to
|
|
1713
|
+
// transactions (#2933): a boundary-caught first load never registers as an
|
|
1714
|
+
// async reporter, so its settle — the boundary's fallback -> content
|
|
1715
|
+
// reveal — must flow ambiently. The node can still carry a `_transition`
|
|
1716
|
+
// stamp (pending-node bookkeeping rides through the stamping sites), and
|
|
1717
|
+
// blindly re-entering that stamped, still-incomplete transaction stashed
|
|
1718
|
+
// the reveal with it — a deadlock when the transaction's completion
|
|
1719
|
+
// depended on the reveal (#2937). An ESCAPED first load did register and
|
|
1720
|
+
// keeps transition scheduling; initialized (value-holding) pending settles
|
|
1721
|
+
// are the transaction's reveal machinery and always re-enter.
|
|
1722
|
+
const settleTransition = () => {
|
|
1723
|
+
const t = resolveTransition(e);
|
|
1724
|
+
if (t && e.Qe & STATUS_UNINITIALIZED && !currentTransition(t).M.has(e)) {
|
|
1725
|
+
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1726
|
+
// stash-path restamp both re-enter the transaction through it.
|
|
1727
|
+
e.T = null;
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
globalQueue.initTransition(t);
|
|
1731
|
+
};
|
|
1624
1732
|
const handleError = n => {
|
|
1625
|
-
if (e.
|
|
1626
|
-
|
|
1733
|
+
if (e.lt !== t) return;
|
|
1734
|
+
settleTransition();
|
|
1627
1735
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1628
|
-
|
|
1736
|
+
const r = n instanceof NotReadyError;
|
|
1737
|
+
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1629
1738
|
e.F = clock;
|
|
1739
|
+
// A real error settles derivatively-pending dependents (notifyStatus
|
|
1740
|
+
// cleared their pending sources), so stranded lazy ones release here —
|
|
1741
|
+
// the error twin of settlePendingSource's release (#2934).
|
|
1742
|
+
if (!r) releaseSettledDependents(e);
|
|
1630
1743
|
};
|
|
1631
1744
|
const asyncWrite = (r, i) => {
|
|
1632
|
-
if (e.
|
|
1745
|
+
if (e.lt !== t) return;
|
|
1633
1746
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1634
1747
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1635
1748
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1636
|
-
if (e.
|
|
1637
|
-
|
|
1638
|
-
const o = !!(e.
|
|
1749
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1750
|
+
settleTransition();
|
|
1751
|
+
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
1639
1752
|
trimStaleDeps(e);
|
|
1640
1753
|
clearStatus(e);
|
|
1641
1754
|
const s = resolveLane(e);
|
|
@@ -1662,22 +1775,22 @@ function handleAsync(e, t, n) {
|
|
|
1662
1775
|
// only notified when the hold is visible to them: under an active
|
|
1663
1776
|
// override every reader sees the override (A17), so waking subs would
|
|
1664
1777
|
// re-show an unchanged view — the revert is the notification point.
|
|
1665
|
-
GlobalQueue.
|
|
1778
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1666
1779
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1667
1780
|
e.F = clock;
|
|
1668
1781
|
} else if (s) {
|
|
1669
1782
|
// Route through lane's effect queue for independent flushing
|
|
1670
|
-
const t = e.
|
|
1671
|
-
const n = e.
|
|
1672
|
-
const i = e.
|
|
1783
|
+
const t = e.Fe;
|
|
1784
|
+
const n = e.We;
|
|
1785
|
+
const i = e.ht;
|
|
1673
1786
|
try {
|
|
1674
1787
|
if (!t && o || !i || !i(r, n)) {
|
|
1675
|
-
e.
|
|
1788
|
+
e.We = r;
|
|
1676
1789
|
e.F = clock;
|
|
1677
1790
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1678
1791
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1679
1792
|
// (computePendingState doesn't read _value).
|
|
1680
|
-
GlobalQueue.
|
|
1793
|
+
GlobalQueue.le !== null && GlobalQueue.le(e, r);
|
|
1681
1794
|
insertSubs(e, true);
|
|
1682
1795
|
}
|
|
1683
1796
|
} catch (t) {
|
|
@@ -1706,10 +1819,14 @@ function handleAsync(e, t, n) {
|
|
|
1706
1819
|
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
1707
1820
|
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1708
1821
|
// it runs the same last-one-out check the other release sites run.
|
|
1822
|
+
// Returns whether the node released, so the iterator branch can stop
|
|
1823
|
+
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1709
1824
|
const settleAutodispose = () => {
|
|
1710
|
-
if (e.
|
|
1825
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.V && !(e.Qe & STATUS_PENDING)) {
|
|
1711
1826
|
unobserved(e);
|
|
1827
|
+
return true;
|
|
1712
1828
|
}
|
|
1829
|
+
return false;
|
|
1713
1830
|
};
|
|
1714
1831
|
if (i) {
|
|
1715
1832
|
let n = false, r = false, i, s = true;
|
|
@@ -1755,6 +1872,12 @@ function handleAsync(e, t, n) {
|
|
|
1755
1872
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
1756
1873
|
} catch {}
|
|
1757
1874
|
});
|
|
1875
|
+
// Release check before each next pull: an unobserved lazy node must tear
|
|
1876
|
+
// down (its cleanup above closes the iterator) instead of pumping the
|
|
1877
|
+
// stream forever with zero subscribers (#2935).
|
|
1878
|
+
const iterateOrRelease = () => {
|
|
1879
|
+
if (!settleAutodispose()) iterate();
|
|
1880
|
+
};
|
|
1758
1881
|
const iterate = () => {
|
|
1759
1882
|
let u, l, a = false, c = false, f = true;
|
|
1760
1883
|
n.next().then(n => {
|
|
@@ -1762,11 +1885,11 @@ function handleAsync(e, t, n) {
|
|
|
1762
1885
|
u = n;
|
|
1763
1886
|
a = true;
|
|
1764
1887
|
if (n.done) i = true;
|
|
1765
|
-
} else if (e.
|
|
1888
|
+
} else if (e.lt !== t) {
|
|
1766
1889
|
return;
|
|
1767
1890
|
} else if (!n.done) {
|
|
1768
1891
|
r = true;
|
|
1769
|
-
asyncWrite(n.value,
|
|
1892
|
+
asyncWrite(n.value, iterateOrRelease);
|
|
1770
1893
|
} else {
|
|
1771
1894
|
i = true;
|
|
1772
1895
|
if (r) {
|
|
@@ -1776,14 +1899,16 @@ function handleAsync(e, t, n) {
|
|
|
1776
1899
|
// Empty completion settles like the immediately-done sync path.
|
|
1777
1900
|
asyncWrite(undefined);
|
|
1778
1901
|
}
|
|
1902
|
+
settleAutodispose();
|
|
1779
1903
|
}
|
|
1780
1904
|
}, n => {
|
|
1781
1905
|
if (f) {
|
|
1782
1906
|
l = n;
|
|
1783
1907
|
c = true;
|
|
1784
|
-
} else if (e.
|
|
1908
|
+
} else if (e.lt === t) {
|
|
1785
1909
|
i = true;
|
|
1786
1910
|
handleError(n);
|
|
1911
|
+
settleAutodispose();
|
|
1787
1912
|
}
|
|
1788
1913
|
});
|
|
1789
1914
|
f = false;
|
|
@@ -1813,19 +1938,19 @@ function handleAsync(e, t, n) {
|
|
|
1813
1938
|
}
|
|
1814
1939
|
|
|
1815
1940
|
function clearStatus(e, t = false) {
|
|
1816
|
-
if (e
|
|
1817
|
-
if (e.
|
|
1941
|
+
if (e.je) clearPendingSources(e);
|
|
1942
|
+
if (e.At) e.At = false;
|
|
1818
1943
|
// The pending window is over; its quiet classification dies with it.
|
|
1819
1944
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1820
1945
|
// plain store to an existing slot — no shape change.)
|
|
1821
|
-
e.
|
|
1822
|
-
e.
|
|
1823
|
-
if (e.
|
|
1946
|
+
e.Nt = false;
|
|
1947
|
+
e.Qe = t ? 0 : e.Qe & STATUS_UNINITIALIZED;
|
|
1948
|
+
if (e.we) setPendingError(e);
|
|
1824
1949
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1825
1950
|
// once the verdict layer created them, which installs the hooks).
|
|
1826
|
-
if (e._ || e.
|
|
1827
|
-
if (e.
|
|
1828
|
-
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();
|
|
1829
1954
|
}
|
|
1830
1955
|
|
|
1831
1956
|
function notifyStatus(e, t, n, r, i) {
|
|
@@ -1838,43 +1963,43 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1838
1963
|
if (!r) {
|
|
1839
1964
|
if (t === STATUS_PENDING && o) {
|
|
1840
1965
|
addPendingSource(e, o);
|
|
1841
|
-
e.
|
|
1966
|
+
e.Qe = STATUS_PENDING | e.Qe & STATUS_UNINITIALIZED;
|
|
1842
1967
|
// Preserve the current source on this propagation so render-effect notification
|
|
1843
1968
|
// can register every distinct pending source with the transition.
|
|
1844
1969
|
setPendingError(e, o, n);
|
|
1845
1970
|
} else {
|
|
1846
1971
|
clearPendingSources(e);
|
|
1847
|
-
e.
|
|
1848
|
-
e.
|
|
1972
|
+
e.Qe = t | (t !== STATUS_ERROR ? e.Qe & STATUS_UNINITIALIZED : 0);
|
|
1973
|
+
e.we = n;
|
|
1849
1974
|
}
|
|
1850
|
-
GlobalQueue.
|
|
1851
|
-
if (e.
|
|
1975
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e);
|
|
1976
|
+
if (e.rt && GlobalQueue.ce !== null) GlobalQueue.ce(e);
|
|
1852
1977
|
}
|
|
1853
1978
|
if (i && !r) {
|
|
1854
1979
|
assignOrMergeLane(e, i);
|
|
1855
1980
|
}
|
|
1856
1981
|
const a = r || l;
|
|
1857
1982
|
const c = r || u ? undefined : i;
|
|
1858
|
-
if (e.
|
|
1983
|
+
if (e.yt) {
|
|
1859
1984
|
if (r && t === STATUS_PENDING) {
|
|
1860
1985
|
return;
|
|
1861
1986
|
}
|
|
1862
1987
|
if (a) {
|
|
1863
|
-
e.
|
|
1988
|
+
e.yt(t, n);
|
|
1864
1989
|
} else {
|
|
1865
|
-
e.
|
|
1990
|
+
e.yt();
|
|
1866
1991
|
}
|
|
1867
1992
|
return;
|
|
1868
1993
|
}
|
|
1869
1994
|
forEachDependent(e, (e, r) => {
|
|
1870
1995
|
e.F = clock;
|
|
1871
|
-
if (t === STATUS_PENDING && o && !e
|
|
1996
|
+
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.we !== n || e.je)) {
|
|
1872
1997
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1873
1998
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1874
1999
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1875
2000
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1876
2001
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1877
|
-
if (r.
|
|
2002
|
+
if (r._t && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1878
2003
|
enqueueSub(e);
|
|
1879
2004
|
schedule();
|
|
1880
2005
|
return;
|
|
@@ -1885,9 +2010,9 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1885
2010
|
});
|
|
1886
2011
|
}
|
|
1887
2012
|
|
|
1888
|
-
GlobalQueue.
|
|
2013
|
+
GlobalQueue.X = recompute;
|
|
1889
2014
|
|
|
1890
|
-
GlobalQueue.
|
|
2015
|
+
GlobalQueue.J = disposeChildren;
|
|
1891
2016
|
|
|
1892
2017
|
let tracking = false;
|
|
1893
2018
|
|
|
@@ -1919,7 +2044,7 @@ let snapshotSources = null;
|
|
|
1919
2044
|
|
|
1920
2045
|
function ownerInSnapshotScope(e) {
|
|
1921
2046
|
while (e) {
|
|
1922
|
-
if (e.
|
|
2047
|
+
if (e.Pt) return true;
|
|
1923
2048
|
e = e.B;
|
|
1924
2049
|
}
|
|
1925
2050
|
return false;
|
|
@@ -1931,41 +2056,41 @@ function setSnapshotCapture(e) {
|
|
|
1931
2056
|
}
|
|
1932
2057
|
|
|
1933
2058
|
function markSnapshotScope(e) {
|
|
1934
|
-
e.
|
|
2059
|
+
e.Pt = true;
|
|
1935
2060
|
}
|
|
1936
2061
|
|
|
1937
2062
|
function releaseSnapshotScope(e) {
|
|
1938
|
-
e.
|
|
2063
|
+
e.Pt = false;
|
|
1939
2064
|
releaseSubtree(e);
|
|
1940
2065
|
schedule();
|
|
1941
2066
|
}
|
|
1942
2067
|
|
|
1943
2068
|
function releaseSubtree(e) {
|
|
1944
|
-
let t = e.
|
|
2069
|
+
let t = e.ot;
|
|
1945
2070
|
while (t) {
|
|
1946
|
-
if (t.
|
|
1947
|
-
t = t.
|
|
2071
|
+
if (t.Pt) {
|
|
2072
|
+
t = t.st;
|
|
1948
2073
|
continue;
|
|
1949
2074
|
}
|
|
1950
|
-
if (t.
|
|
2075
|
+
if (t.ke) {
|
|
1951
2076
|
const e = t;
|
|
1952
|
-
e.
|
|
1953
|
-
if (e.
|
|
1954
|
-
e.
|
|
1955
|
-
e.
|
|
1956
|
-
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;
|
|
1957
2082
|
insertIntoHeap(e, dirtyQueue);
|
|
1958
2083
|
}
|
|
1959
2084
|
}
|
|
1960
2085
|
releaseSubtree(t);
|
|
1961
|
-
t = t.
|
|
2086
|
+
t = t.st;
|
|
1962
2087
|
}
|
|
1963
2088
|
}
|
|
1964
2089
|
|
|
1965
2090
|
function clearSnapshots() {
|
|
1966
2091
|
if (snapshotSources) {
|
|
1967
2092
|
for (const e of snapshotSources) {
|
|
1968
|
-
delete e.
|
|
2093
|
+
delete e.ve;
|
|
1969
2094
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
1970
2095
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
1971
2096
|
// when present so signal-node sources don't grow the field.
|
|
@@ -1977,37 +2102,41 @@ function clearSnapshots() {
|
|
|
1977
2102
|
}
|
|
1978
2103
|
|
|
1979
2104
|
function recompute(e, t = false) {
|
|
1980
|
-
const n = e.
|
|
2105
|
+
const n = e.Fe;
|
|
1981
2106
|
if (!t) {
|
|
1982
2107
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
1983
2108
|
deleteFromHeap(e, queueFor(e));
|
|
1984
|
-
e.
|
|
2109
|
+
e.lt = null;
|
|
1985
2110
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
1986
|
-
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) {
|
|
1987
2112
|
markDisposal(e);
|
|
1988
|
-
e.
|
|
1989
|
-
e.
|
|
1990
|
-
e.
|
|
1991
|
-
e.
|
|
1992
|
-
e.
|
|
2113
|
+
e.Me = e.dt;
|
|
2114
|
+
e.He = e.ot;
|
|
2115
|
+
e.dt = null;
|
|
2116
|
+
e.ot = null;
|
|
2117
|
+
e.ct = 0;
|
|
1993
2118
|
} else ;
|
|
1994
2119
|
}
|
|
1995
|
-
let r = !!(e.
|
|
2120
|
+
let r = !!(e.Ge & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1996
2121
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1997
|
-
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;
|
|
1998
2127
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1999
2128
|
// the recompute wipes _flags below.
|
|
2000
|
-
const
|
|
2001
|
-
const
|
|
2129
|
+
const u = (e.Ge & REACTIVE_REASK) !== 0;
|
|
2130
|
+
const l = context;
|
|
2002
2131
|
context = e;
|
|
2003
|
-
e.
|
|
2004
|
-
e.
|
|
2005
|
-
e.
|
|
2132
|
+
e.ut = null;
|
|
2133
|
+
e.It++;
|
|
2134
|
+
e.Ge = REACTIVE_RECOMPUTING_DEPS;
|
|
2006
2135
|
e.F = clock;
|
|
2007
|
-
let
|
|
2008
|
-
let
|
|
2009
|
-
let
|
|
2010
|
-
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;
|
|
2011
2140
|
tracking = true;
|
|
2012
2141
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
2013
2142
|
// inside a latest() read window: read() short-circuits through the
|
|
@@ -2015,74 +2144,74 @@ function recompute(e, t = false) {
|
|
|
2015
2144
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
2016
2145
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
2017
2146
|
// covers creation-time computes and flushes that run inside the window.
|
|
2018
|
-
const
|
|
2147
|
+
const d = latestReadActive;
|
|
2019
2148
|
latestReadActive = false;
|
|
2020
2149
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
2021
2150
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2022
2151
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2023
2152
|
if (r) {
|
|
2024
|
-
const t = GlobalQueue.
|
|
2153
|
+
const t = GlobalQueue.Ce(e, true);
|
|
2025
2154
|
if (t) currentOptimisticLane = t;
|
|
2026
2155
|
} else if (activeTransition && !t && activeTransition.v.length) {
|
|
2027
2156
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2028
2157
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2029
2158
|
// recomputes under the right posture and propagates correctly.
|
|
2030
|
-
const t = GlobalQueue.
|
|
2159
|
+
const t = GlobalQueue.Ce(e, false);
|
|
2031
2160
|
if (t) {
|
|
2032
2161
|
r = true;
|
|
2033
2162
|
currentOptimisticLane = t;
|
|
2034
2163
|
}
|
|
2035
2164
|
}
|
|
2036
|
-
const
|
|
2037
|
-
const
|
|
2038
|
-
if (
|
|
2165
|
+
const S = n && n !== EFFECT_USER;
|
|
2166
|
+
const T = stale;
|
|
2167
|
+
if (S) stale = true;
|
|
2039
2168
|
try {
|
|
2040
|
-
if (!false && e.
|
|
2041
|
-
|
|
2042
|
-
e.
|
|
2169
|
+
if (!false && e.Ue & CONFIG_SYNC) {
|
|
2170
|
+
a = e.ke(a);
|
|
2171
|
+
e.lt = null;
|
|
2043
2172
|
} else {
|
|
2044
2173
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2045
2174
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2046
2175
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2047
2176
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2048
2177
|
// iteration drive updates.
|
|
2049
|
-
const t = e.
|
|
2050
|
-
const n = e.
|
|
2178
|
+
const t = e.lt;
|
|
2179
|
+
const n = e.ke(a);
|
|
2051
2180
|
const r = typeof n === "object" && n !== null;
|
|
2052
|
-
const i = e.
|
|
2053
|
-
|
|
2054
|
-
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;
|
|
2055
2184
|
}
|
|
2056
2185
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2057
2186
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2058
2187
|
// the flags write (create or not) stores the 0 already there.
|
|
2059
|
-
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);
|
|
2060
2189
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2061
|
-
if (e.i) GlobalQueue.
|
|
2190
|
+
if (e.i) GlobalQueue.be(e);
|
|
2062
2191
|
} catch (t) {
|
|
2063
2192
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2064
2193
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2065
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2194
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.ge(e);
|
|
2066
2195
|
let n = false;
|
|
2067
2196
|
if (t instanceof NotReadyError) {
|
|
2068
|
-
e.
|
|
2069
|
-
if (GlobalQueue.
|
|
2197
|
+
e.At = true;
|
|
2198
|
+
if (GlobalQueue.Te !== null) n = GlobalQueue.Te(e, u);
|
|
2070
2199
|
}
|
|
2071
2200
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2072
|
-
if (n) GlobalQueue.
|
|
2201
|
+
if (n) GlobalQueue.Oe(e);
|
|
2073
2202
|
} finally {
|
|
2074
|
-
tracking =
|
|
2075
|
-
latestReadActive =
|
|
2076
|
-
if (
|
|
2077
|
-
e.
|
|
2078
|
-
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;
|
|
2079
2208
|
}
|
|
2080
|
-
if (!e.
|
|
2209
|
+
if (!e.we) {
|
|
2081
2210
|
trimStaleDeps(e);
|
|
2082
|
-
const
|
|
2083
|
-
let
|
|
2211
|
+
const u = i ? unwrapOverride(e.A) : e.U === NOT_PENDING ? e.We : e.U;
|
|
2212
|
+
let l = false;
|
|
2084
2213
|
try {
|
|
2085
|
-
|
|
2214
|
+
l = !n && o || !e.ht || !e.ht(u, a);
|
|
2086
2215
|
} catch (t) {
|
|
2087
2216
|
// A throwing user comparator is an error of this node's computation.
|
|
2088
2217
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2095,13 +2224,13 @@ function recompute(e, t = false) {
|
|
|
2095
2224
|
// its runner — happen here instead. `!create` matches the previous `initialized`
|
|
2096
2225
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2097
2226
|
// effect() can call its runner synchronously for the first run.
|
|
2098
|
-
if (n &&
|
|
2099
|
-
e.
|
|
2227
|
+
if (n && l) {
|
|
2228
|
+
e.xe = !e.we;
|
|
2100
2229
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2101
2230
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2102
|
-
if (!t) e.
|
|
2231
|
+
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.ee.bind(null, e));
|
|
2103
2232
|
}
|
|
2104
|
-
if (e.
|
|
2233
|
+
if (e.we) ; else if (l) {
|
|
2105
2234
|
const o = i ? e.A : undefined;
|
|
2106
2235
|
if (t ||
|
|
2107
2236
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2109,104 +2238,110 @@ function recompute(e, t = false) {
|
|
|
2109
2238
|
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2110
2239
|
// paying it per effect on the plain path is pure overhead.
|
|
2111
2240
|
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2112
|
-
e.
|
|
2241
|
+
e.We = a;
|
|
2113
2242
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2114
2243
|
// override unconditionally. The direct _value commit is the lane's
|
|
2115
2244
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
2116
2245
|
// commit can't clobber the fresh value.
|
|
2117
2246
|
if (i && r) {
|
|
2118
|
-
e.A =
|
|
2247
|
+
e.A = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
2119
2248
|
e.U = NOT_PENDING;
|
|
2120
2249
|
}
|
|
2121
2250
|
} else {
|
|
2122
|
-
e.U =
|
|
2251
|
+
e.U = a;
|
|
2123
2252
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2124
2253
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2125
2254
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2126
2255
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2127
2256
|
// pending value commits before effects run.
|
|
2128
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2257
|
+
if ((activeTransition || e.T) && GlobalQueue.le !== null) GlobalQueue.le(e, a);
|
|
2129
2258
|
}
|
|
2130
2259
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2131
2260
|
// subscriber-less node has nothing to notify.
|
|
2132
|
-
if (e.
|
|
2261
|
+
if (e.V !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2133
2262
|
} else if (i) {
|
|
2134
2263
|
// Unchanged value (equals the override) recomputed while the override
|
|
2135
2264
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2136
2265
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2137
2266
|
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2138
|
-
e.U =
|
|
2139
|
-
} else if (e.
|
|
2140
|
-
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) {
|
|
2141
2270
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2142
2271
|
}
|
|
2143
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);
|
|
2144
2279
|
}
|
|
2145
|
-
currentOptimisticLane =
|
|
2146
|
-
const
|
|
2280
|
+
currentOptimisticLane = E;
|
|
2281
|
+
const O = e.U !== NOT_PENDING || e.He !== null || e.Me !== null || (e.Qe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2147
2282
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2148
2283
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2149
2284
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2150
2285
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2151
2286
|
// _transition.
|
|
2152
|
-
|
|
2287
|
+
O && (!t || e.Qe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2153
2288
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2154
2289
|
}
|
|
2155
2290
|
|
|
2156
2291
|
function updateIfNecessary(e) {
|
|
2157
|
-
if (e.
|
|
2158
|
-
for (let t = e.
|
|
2159
|
-
const n = t.
|
|
2160
|
-
const r = n.
|
|
2161
|
-
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) {
|
|
2162
2297
|
updateIfNecessary(r);
|
|
2163
2298
|
}
|
|
2164
|
-
if (e.
|
|
2299
|
+
if (e.Ge & REACTIVE_DIRTY) {
|
|
2165
2300
|
break;
|
|
2166
2301
|
}
|
|
2167
2302
|
}
|
|
2168
2303
|
}
|
|
2169
|
-
if (e.
|
|
2304
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.we && e.F < clock && !e.lt) {
|
|
2170
2305
|
recompute(e);
|
|
2171
2306
|
}
|
|
2172
|
-
e.
|
|
2307
|
+
e.Ge = e.Ge & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2173
2308
|
}
|
|
2174
2309
|
|
|
2175
2310
|
function computed(e, t) {
|
|
2176
2311
|
const n = t?.transparent ?? false;
|
|
2177
2312
|
const r = {
|
|
2178
2313
|
id: inheritId(t, n, context),
|
|
2179
|
-
|
|
2180
|
-
|
|
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,
|
|
2181
2316
|
W: t?.unobserved,
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
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,
|
|
2197
2332
|
B: context,
|
|
2333
|
+
st: null,
|
|
2334
|
+
ft: null,
|
|
2198
2335
|
ot: null,
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2202
|
-
xe: STATUS_UNINITIALIZED,
|
|
2336
|
+
Ge: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2337
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2203
2338
|
F: clock,
|
|
2204
2339
|
U: NOT_PENDING,
|
|
2340
|
+
Me: null,
|
|
2205
2341
|
He: null,
|
|
2206
|
-
|
|
2207
|
-
ut: null,
|
|
2342
|
+
lt: null,
|
|
2208
2343
|
T: null,
|
|
2209
|
-
|
|
2344
|
+
Nt: false
|
|
2210
2345
|
};
|
|
2211
2346
|
setupComputedNode(r, t);
|
|
2212
2347
|
return r;
|
|
@@ -2221,44 +2356,44 @@ function computed(e, t) {
|
|
|
2221
2356
|
const s = o?.transparent ?? false;
|
|
2222
2357
|
const u = {
|
|
2223
2358
|
id: inheritId(o, s, context),
|
|
2224
|
-
|
|
2225
|
-
|
|
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,
|
|
2226
2361
|
W: o?.unobserved,
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
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,
|
|
2242
2377
|
B: context,
|
|
2378
|
+
st: null,
|
|
2379
|
+
ft: null,
|
|
2243
2380
|
ot: null,
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
Le: REACTIVE_LAZY,
|
|
2247
|
-
xe: STATUS_UNINITIALIZED,
|
|
2381
|
+
Ge: REACTIVE_LAZY,
|
|
2382
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2248
2383
|
F: clock,
|
|
2249
2384
|
U: NOT_PENDING,
|
|
2385
|
+
Me: null,
|
|
2250
2386
|
He: null,
|
|
2251
|
-
|
|
2252
|
-
ut: null,
|
|
2387
|
+
lt: null,
|
|
2253
2388
|
T: null,
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2389
|
+
Nt: false,
|
|
2390
|
+
xe: false,
|
|
2391
|
+
bt: undefined,
|
|
2392
|
+
Dt: t,
|
|
2393
|
+
wt: n,
|
|
2394
|
+
Et: undefined,
|
|
2395
|
+
Fe: r,
|
|
2396
|
+
yt: i
|
|
2262
2397
|
};
|
|
2263
2398
|
setupComputedNode(u, lazyOptions);
|
|
2264
2399
|
return u;
|
|
@@ -2269,24 +2404,24 @@ const lazyOptions = {
|
|
|
2269
2404
|
};
|
|
2270
2405
|
|
|
2271
2406
|
function setupComputedNode(e, t) {
|
|
2272
|
-
e.
|
|
2273
|
-
const n = context?.
|
|
2407
|
+
e.tt = e;
|
|
2408
|
+
const n = context?.Je ? context.et : context;
|
|
2274
2409
|
if (context) {
|
|
2275
|
-
const t = context.
|
|
2410
|
+
const t = context.ot;
|
|
2276
2411
|
if (t === null) {
|
|
2277
|
-
context.
|
|
2412
|
+
context.ot = e;
|
|
2278
2413
|
} else {
|
|
2279
|
-
e.
|
|
2280
|
-
t.
|
|
2281
|
-
context.
|
|
2414
|
+
e.st = t;
|
|
2415
|
+
t.ft = e;
|
|
2416
|
+
context.ot = e;
|
|
2282
2417
|
}
|
|
2283
2418
|
}
|
|
2284
|
-
if (n) e.
|
|
2285
|
-
if (GlobalQueue.
|
|
2419
|
+
if (n) e.ze = n.ze + 1;
|
|
2420
|
+
if (GlobalQueue.se !== null) GlobalQueue.se(e);
|
|
2286
2421
|
!t?.lazy && recompute(e, true);
|
|
2287
2422
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2288
|
-
if (!(e.
|
|
2289
|
-
e.
|
|
2423
|
+
if (!(e.Qe & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2424
|
+
e.ve = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2290
2425
|
snapshotSources.add(e);
|
|
2291
2426
|
}
|
|
2292
2427
|
}
|
|
@@ -2294,20 +2429,20 @@ function setupComputedNode(e, t) {
|
|
|
2294
2429
|
|
|
2295
2430
|
function signal(e, t, n = null) {
|
|
2296
2431
|
const r = {
|
|
2297
|
-
|
|
2298
|
-
|
|
2432
|
+
ht: t?.equals != null ? t.equals : isEqual,
|
|
2433
|
+
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2299
2434
|
W: t?.unobserved,
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2435
|
+
We: e,
|
|
2436
|
+
V: null,
|
|
2437
|
+
Ot: null,
|
|
2303
2438
|
F: clock,
|
|
2304
|
-
|
|
2305
|
-
|
|
2439
|
+
Be: n,
|
|
2440
|
+
it: n?.rt || null,
|
|
2306
2441
|
U: NOT_PENDING
|
|
2307
2442
|
};
|
|
2308
|
-
n && (n.
|
|
2309
|
-
if (snapshotCaptureActive && !(r.
|
|
2310
|
-
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;
|
|
2311
2446
|
snapshotSources.add(r);
|
|
2312
2447
|
}
|
|
2313
2448
|
return r;
|
|
@@ -2351,11 +2486,11 @@ function isEqual(e, t) {
|
|
|
2351
2486
|
* );
|
|
2352
2487
|
* ```
|
|
2353
2488
|
*/ function untrack(e, t) {
|
|
2354
|
-
if (GlobalQueue.
|
|
2489
|
+
if (GlobalQueue.ue === null && !tracking && true) return e();
|
|
2355
2490
|
const n = tracking;
|
|
2356
2491
|
tracking = false;
|
|
2357
2492
|
try {
|
|
2358
|
-
if (GlobalQueue.
|
|
2493
|
+
if (GlobalQueue.ue !== null) return GlobalQueue.ue(e);
|
|
2359
2494
|
return e();
|
|
2360
2495
|
} finally {
|
|
2361
2496
|
tracking = n;
|
|
@@ -2367,10 +2502,10 @@ function isEqual(e, t) {
|
|
|
2367
2502
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2368
2503
|
* date so its status flags reflect the current graph.
|
|
2369
2504
|
*/ function prepareComputed(e, t) {
|
|
2370
|
-
if (e.
|
|
2371
|
-
e.
|
|
2505
|
+
if (e.Ge & REACTIVE_LAZY) {
|
|
2506
|
+
e.Ge &= ~REACTIVE_LAZY;
|
|
2372
2507
|
recompute(e, true);
|
|
2373
|
-
} else if (e.
|
|
2508
|
+
} else if (e.Ge & REACTIVE_DISPOSED) {
|
|
2374
2509
|
recompute(e, true);
|
|
2375
2510
|
} else if (t) {
|
|
2376
2511
|
updateIfNecessary(e);
|
|
@@ -2391,11 +2526,11 @@ function isEqual(e, t) {
|
|
|
2391
2526
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2392
2527
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2393
2528
|
*/ function readNodeFast(e) {
|
|
2394
|
-
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;
|
|
2395
2530
|
let t = context;
|
|
2396
|
-
if (t?.
|
|
2531
|
+
if (t?.Je) t = t.et;
|
|
2397
2532
|
if (t && tracking) link(e, t);
|
|
2398
|
-
return !t || e.U === NOT_PENDING ? e.
|
|
2533
|
+
return !t || e.U === NOT_PENDING ? e.We : e.U;
|
|
2399
2534
|
}
|
|
2400
2535
|
|
|
2401
2536
|
function read(e) {
|
|
@@ -2403,72 +2538,76 @@ function read(e) {
|
|
|
2403
2538
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2404
2539
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2405
2540
|
// than the original node (which stays "pending" while held in a transition).
|
|
2406
|
-
if (latestReadActive) return GlobalQueue.
|
|
2541
|
+
if (latestReadActive) return GlobalQueue.Ee(e);
|
|
2407
2542
|
let t = context;
|
|
2408
|
-
if (t?.
|
|
2543
|
+
if (t?.Je) t = t.et;
|
|
2409
2544
|
const n = e;
|
|
2410
|
-
const r = e.
|
|
2545
|
+
const r = e.Be;
|
|
2411
2546
|
const i = r || e;
|
|
2412
2547
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2413
2548
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2414
2549
|
// recompute don't collect into the probe.
|
|
2415
2550
|
if (pendingCheckActive) {
|
|
2416
|
-
GlobalQueue.
|
|
2417
|
-
} else if (typeof n.
|
|
2551
|
+
GlobalQueue.de(e, t, i, r);
|
|
2552
|
+
} else if (typeof n.ke === "function") {
|
|
2418
2553
|
prepareComputed(e, false);
|
|
2419
2554
|
}
|
|
2420
|
-
if (!n.
|
|
2555
|
+
if (!n.ke && i === e && e.A === undefined && e.ve === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2421
2556
|
if (t && tracking) link(e, t);
|
|
2422
|
-
return !t || e.U === NOT_PENDING ? e.
|
|
2557
|
+
return !t || e.U === NOT_PENDING ? e.We : e.U;
|
|
2423
2558
|
}
|
|
2424
2559
|
if (t && tracking) {
|
|
2425
2560
|
link(e, t, pendingCheckActive);
|
|
2426
|
-
if (i.
|
|
2561
|
+
if (i.ke) {
|
|
2427
2562
|
const n = queueFor(e);
|
|
2428
|
-
if (i.
|
|
2563
|
+
if (i.ze >= n.P) {
|
|
2429
2564
|
markNode(t);
|
|
2430
2565
|
markHeap(n);
|
|
2431
2566
|
updateIfNecessary(i);
|
|
2432
2567
|
}
|
|
2433
|
-
const r = i.
|
|
2568
|
+
const r = i.ze;
|
|
2434
2569
|
// parent check is shallow, might need to be recursive
|
|
2435
|
-
if (r >= t.
|
|
2436
|
-
t.
|
|
2570
|
+
if (r >= t.ze && e.B !== t) {
|
|
2571
|
+
t.ze = r + 1;
|
|
2437
2572
|
}
|
|
2438
2573
|
}
|
|
2439
2574
|
}
|
|
2440
|
-
if (i.
|
|
2575
|
+
if (i.Qe & STATUS_PENDING) {
|
|
2441
2576
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2442
2577
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2443
2578
|
// is installed): under a lane, only same-lane pending async without an
|
|
2444
2579
|
// active override throws.
|
|
2445
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2580
|
+
if (currentOptimisticLane === null || GlobalQueue.ye(i)) {
|
|
2446
2581
|
if (!tracking && e !== t) link(e, t);
|
|
2447
|
-
throw i.
|
|
2582
|
+
throw i.we;
|
|
2448
2583
|
}
|
|
2449
|
-
} else if (t && i !== e && i.
|
|
2584
|
+
} else if (t && i !== e && i.Qe & STATUS_UNINITIALIZED) {
|
|
2450
2585
|
if (!tracking && e !== t) link(e, t);
|
|
2451
|
-
throw i.
|
|
2452
|
-
} else if (!t && i.
|
|
2453
|
-
throw i.
|
|
2586
|
+
throw i.we;
|
|
2587
|
+
} else if (!t && i.Qe & STATUS_UNINITIALIZED) {
|
|
2588
|
+
throw i.we;
|
|
2454
2589
|
}
|
|
2455
2590
|
}
|
|
2456
|
-
|
|
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) {
|
|
2457
2596
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2458
2597
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2459
2598
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2460
|
-
// -
|
|
2461
|
-
if (tracking && !pendingCheckActive &&
|
|
2462
|
-
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);
|
|
2463
2602
|
return read(e);
|
|
2464
|
-
} else throw
|
|
2603
|
+
} else throw i.we;
|
|
2465
2604
|
}
|
|
2466
|
-
if (snapshotCaptureActive && t && t.
|
|
2467
|
-
const n = e.
|
|
2605
|
+
if (snapshotCaptureActive && t && t.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2606
|
+
const n = e.ve;
|
|
2468
2607
|
if (n !== undefined) {
|
|
2469
2608
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2470
|
-
const i = e.U !== NOT_PENDING ? e.U : e.
|
|
2471
|
-
if (i !== r) t.
|
|
2609
|
+
const i = e.U !== NOT_PENDING ? e.U : e.We;
|
|
2610
|
+
if (i !== r) t.Ge |= REACTIVE_SNAPSHOT_STALE;
|
|
2472
2611
|
return r;
|
|
2473
2612
|
}
|
|
2474
2613
|
}
|
|
@@ -2483,18 +2622,18 @@ function read(e) {
|
|
|
2483
2622
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2484
2623
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2485
2624
|
// engine — a non-null lane implies it is installed.)
|
|
2486
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2487
|
-
return e.
|
|
2625
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ne(e, i, t)) {
|
|
2626
|
+
return e.We;
|
|
2488
2627
|
}
|
|
2489
2628
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2490
2629
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2491
2630
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2492
2631
|
// (The lane-context clause lives with the engine.)
|
|
2493
|
-
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;
|
|
2494
2633
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2495
2634
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2496
|
-
if (pendingCheckActive) GlobalQueue.
|
|
2497
|
-
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) {
|
|
2498
2637
|
unobserved(e);
|
|
2499
2638
|
}
|
|
2500
2639
|
return o;
|
|
@@ -2506,19 +2645,19 @@ function setSignal(e, t) {
|
|
|
2506
2645
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2507
2646
|
// _overrideValue slot, and every module that creates one installs the
|
|
2508
2647
|
// engine first.
|
|
2509
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2510
|
-
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;
|
|
2511
2650
|
if (typeof t === "function") t = t(n);
|
|
2512
2651
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2513
2652
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2514
|
-
const r = !!(e.
|
|
2653
|
+
const r = !!(e.Qe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(n, t);
|
|
2515
2654
|
if (!r) return t;
|
|
2516
2655
|
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2517
2656
|
e.U = t;
|
|
2518
2657
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2519
2658
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
2520
2659
|
// only ever created, never removed, and creating one installs the hook).
|
|
2521
|
-
(e._ !== undefined || e.
|
|
2660
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2522
2661
|
e.F = clock;
|
|
2523
2662
|
insertSubs(e);
|
|
2524
2663
|
schedule();
|
|
@@ -2533,11 +2672,11 @@ function setSignal(e, t) {
|
|
|
2533
2672
|
* cleanup point.
|
|
2534
2673
|
*/ function suppressComputedRecompute(e) {
|
|
2535
2674
|
deleteFromHeap(e, queueFor(e));
|
|
2536
|
-
if (!(e.
|
|
2675
|
+
if (!(e.Ge & REACTIVE_MANUAL_WRITE) && e.U === NOT_PENDING) {
|
|
2537
2676
|
queuePendingNode(e);
|
|
2538
2677
|
schedule();
|
|
2539
2678
|
}
|
|
2540
|
-
e.
|
|
2679
|
+
e.Ge = e.Ge & -4 | REACTIVE_MANUAL_WRITE;
|
|
2541
2680
|
}
|
|
2542
2681
|
|
|
2543
2682
|
/**
|
|
@@ -2616,7 +2755,7 @@ function staleValues(e, t = true) {
|
|
|
2616
2755
|
if (!t) {
|
|
2617
2756
|
return;
|
|
2618
2757
|
}
|
|
2619
|
-
if (typeof t.
|
|
2758
|
+
if (typeof t.ke === "function" && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2620
2759
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2621
2760
|
// same question: mark it so the recompute classifies any resulting
|
|
2622
2761
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2624,11 +2763,11 @@ function staleValues(e, t = true) {
|
|
|
2624
2763
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2625
2764
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2626
2765
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2627
|
-
if (!(t.
|
|
2628
|
-
t.
|
|
2766
|
+
if (!(t.Ge & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2767
|
+
t.Ge |= REACTIVE_REASK;
|
|
2629
2768
|
armReaskClear();
|
|
2630
2769
|
}
|
|
2631
|
-
t.
|
|
2770
|
+
t.Ge = t.Ge & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2632
2771
|
insertIntoHeap(t, queueFor(t));
|
|
2633
2772
|
schedule();
|
|
2634
2773
|
}
|
|
@@ -2676,11 +2815,11 @@ function wireExternalSource(e) {
|
|
|
2676
2815
|
equals: false,
|
|
2677
2816
|
ownedWrite: true
|
|
2678
2817
|
});
|
|
2679
|
-
const n = externalSourceConfig.factory(e.
|
|
2818
|
+
const n = externalSourceConfig.factory(e.ke, () => {
|
|
2680
2819
|
setSignal(t, undefined);
|
|
2681
2820
|
});
|
|
2682
2821
|
cleanup(() => n.dispose());
|
|
2683
|
-
e.
|
|
2822
|
+
e.ke = e => {
|
|
2684
2823
|
read(t);
|
|
2685
2824
|
return n.track(e);
|
|
2686
2825
|
};
|
|
@@ -2694,8 +2833,8 @@ function externalUntrack(e) {
|
|
|
2694
2833
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2695
2834
|
// `externalSourceConfig` truthiness checks.
|
|
2696
2835
|
function syncExternalHooks() {
|
|
2697
|
-
GlobalQueue.
|
|
2698
|
-
GlobalQueue.
|
|
2836
|
+
GlobalQueue.se = externalSourceConfig ? wireExternalSource : null;
|
|
2837
|
+
GlobalQueue.ue = externalSourceConfig ? externalUntrack : null;
|
|
2699
2838
|
}
|
|
2700
2839
|
|
|
2701
2840
|
function enableExternalSource(e) {
|
|
@@ -2752,7 +2891,7 @@ function enableExternalSource(e) {
|
|
|
2752
2891
|
if (!t) {
|
|
2753
2892
|
throw new NoOwnerError;
|
|
2754
2893
|
}
|
|
2755
|
-
const n = hasContext(e, t) ? t.
|
|
2894
|
+
const n = hasContext(e, t) ? t.St[e.id] : e.defaultValue;
|
|
2756
2895
|
if (isUndefined(n)) {
|
|
2757
2896
|
throw new ContextNotFoundError;
|
|
2758
2897
|
}
|
|
@@ -2773,14 +2912,14 @@ function enableExternalSource(e) {
|
|
|
2773
2912
|
}
|
|
2774
2913
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
2775
2914
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
2776
|
-
n.
|
|
2777
|
-
...n.
|
|
2915
|
+
n.St = {
|
|
2916
|
+
...n.St,
|
|
2778
2917
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
2779
2918
|
};
|
|
2780
2919
|
}
|
|
2781
2920
|
|
|
2782
2921
|
function hasContext(e, t) {
|
|
2783
|
-
return !isUndefined(t?.
|
|
2922
|
+
return !isUndefined(t?.St[e.id]);
|
|
2784
2923
|
}
|
|
2785
2924
|
|
|
2786
2925
|
function isUndefined(e) {
|
|
@@ -2802,9 +2941,9 @@ function isUndefined(e) {
|
|
|
2802
2941
|
*/
|
|
2803
2942
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, t) {
|
|
2804
2943
|
const n = e.A !== NOT_PENDING;
|
|
2805
|
-
const r = n ? unwrapOverride(e.A) : e.
|
|
2944
|
+
const r = n ? unwrapOverride(e.A) : e.We;
|
|
2806
2945
|
if (typeof t === "function") t = t(r);
|
|
2807
|
-
const i = !!(e.
|
|
2946
|
+
const i = !!(e.Qe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(r, t);
|
|
2808
2947
|
if (!i) {
|
|
2809
2948
|
// Same-value write with an active override still entangles the current
|
|
2810
2949
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2822,7 +2961,7 @@ function isUndefined(e) {
|
|
|
2822
2961
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2823
2962
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2824
2963
|
// which a shared subscriber can merge across transactions (#2912).
|
|
2825
|
-
e.
|
|
2964
|
+
e.p = activeTransition;
|
|
2826
2965
|
const o = getOrCreateLane(e);
|
|
2827
2966
|
e.i = o;
|
|
2828
2967
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
@@ -2831,7 +2970,7 @@ function isUndefined(e) {
|
|
|
2831
2970
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2832
2971
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2833
2972
|
// neither companion present the call is a guaranteed no-op.
|
|
2834
|
-
(e._ !== undefined || e.
|
|
2973
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.le !== null && GlobalQueue.le(e, t);
|
|
2835
2974
|
e.F = clock;
|
|
2836
2975
|
insertSubs(e, true);
|
|
2837
2976
|
schedule();
|
|
@@ -2845,7 +2984,7 @@ function isUndefined(e) {
|
|
|
2845
2984
|
*/ function transitionBlocked(e) {
|
|
2846
2985
|
for (let t = 0; t < e.v.length; t++) {
|
|
2847
2986
|
const n = e.v[t];
|
|
2848
|
-
if (hasActiveOverride(n) && "
|
|
2987
|
+
if (hasActiveOverride(n) && "Qe" in n && n.Qe & STATUS_PENDING && n.we instanceof NotReadyError) {
|
|
2849
2988
|
return true;
|
|
2850
2989
|
}
|
|
2851
2990
|
}
|
|
@@ -2863,21 +3002,21 @@ function resolveOptimisticNodes(e) {
|
|
|
2863
3002
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2864
3003
|
// override-covered authoritative values hold in _pendingValue and
|
|
2865
3004
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2866
|
-
if (!(t.
|
|
3005
|
+
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
2867
3006
|
const r = t.A;
|
|
2868
3007
|
t.A = NOT_PENDING;
|
|
2869
|
-
if (r !== NOT_PENDING && t.
|
|
3008
|
+
if (r !== NOT_PENDING && t.We !== unwrapOverride(r)) insertSubs(t, true);
|
|
2870
3009
|
t.T = null;
|
|
2871
|
-
t.
|
|
3010
|
+
t.p = null;
|
|
2872
3011
|
}
|
|
2873
3012
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
2874
3013
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
2875
3014
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2876
3015
|
for (let n = 0; n < t; n++) {
|
|
2877
3016
|
const t = e[n];
|
|
2878
|
-
if (t._ || t.
|
|
3017
|
+
if (t._ || t.R) GlobalQueue.fe(t);
|
|
2879
3018
|
const r = t.t;
|
|
2880
|
-
if (r && (r._ === t || r.
|
|
3019
|
+
if (r && (r._ === t || r.R === t)) GlobalQueue.fe(r);
|
|
2881
3020
|
}
|
|
2882
3021
|
e.splice(0, t);
|
|
2883
3022
|
}
|
|
@@ -2930,7 +3069,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2930
3069
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2931
3070
|
* is recorded for replay at commit.
|
|
2932
3071
|
*/ function gatedRead(e, t, n) {
|
|
2933
|
-
if (latestReadActive || e.U === NOT_PENDING || e.
|
|
3072
|
+
if (latestReadActive || e.U === NOT_PENDING || e.ke || t !== e && !(t.Ge & REACTIVE_MANUAL_WRITE)) {
|
|
2934
3073
|
return false;
|
|
2935
3074
|
}
|
|
2936
3075
|
activeTransition.Y.add(n);
|
|
@@ -2941,7 +3080,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2941
3080
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2942
3081
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2943
3082
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2944
|
-
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);
|
|
2945
3084
|
}
|
|
2946
3085
|
|
|
2947
3086
|
/**
|
|
@@ -2950,12 +3089,12 @@ function cleanupCompletedLanes(e) {
|
|
|
2950
3089
|
* can run before its OPT-dirty child propagates).
|
|
2951
3090
|
*/ function recomputeLane(e, t) {
|
|
2952
3091
|
if (t) return resolveLane(e) ?? null;
|
|
2953
|
-
for (let t = e.
|
|
2954
|
-
const n = t.
|
|
2955
|
-
if (n.
|
|
3092
|
+
for (let t = e.Ke; t; t = t.Ye) {
|
|
3093
|
+
const n = t.qe;
|
|
3094
|
+
if (n.Ge & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2956
3095
|
const t = resolveLane(n);
|
|
2957
3096
|
if (t) {
|
|
2958
|
-
e.
|
|
3097
|
+
e.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
2959
3098
|
assignOrMergeLane(e, t);
|
|
2960
3099
|
return t;
|
|
2961
3100
|
}
|
|
@@ -2969,7 +3108,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2969
3108
|
if (t.o !== e) {
|
|
2970
3109
|
t.u.add(e);
|
|
2971
3110
|
e.i = t;
|
|
2972
|
-
GlobalQueue.
|
|
3111
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(t.o);
|
|
2973
3112
|
}
|
|
2974
3113
|
}
|
|
2975
3114
|
|
|
@@ -2977,13 +3116,13 @@ function cleanupCompletedLanes(e) {
|
|
|
2977
3116
|
const t = resolveLane(e);
|
|
2978
3117
|
if (t) {
|
|
2979
3118
|
t.u.delete(e);
|
|
2980
|
-
GlobalQueue.
|
|
3119
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(t.o);
|
|
2981
3120
|
}
|
|
2982
3121
|
}
|
|
2983
3122
|
|
|
2984
3123
|
function trackOptimisticStore(e) {
|
|
2985
3124
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
2986
|
-
globalQueue.D.
|
|
3125
|
+
globalQueue.D.G.add(e);
|
|
2987
3126
|
schedule();
|
|
2988
3127
|
}
|
|
2989
3128
|
|
|
@@ -2992,19 +3131,19 @@ function trackOptimisticStore(e) {
|
|
|
2992
3131
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
2993
3132
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
2994
3133
|
*/ function installOptimisticEngine() {
|
|
2995
|
-
if (GlobalQueue.
|
|
2996
|
-
GlobalQueue.
|
|
3134
|
+
if (GlobalQueue.Re !== null) return;
|
|
3135
|
+
GlobalQueue.Re = optimisticWrite;
|
|
2997
3136
|
GlobalQueue.pe = resolveOptimisticNodes;
|
|
2998
|
-
GlobalQueue.
|
|
2999
|
-
GlobalQueue.
|
|
3000
|
-
GlobalQueue.
|
|
3001
|
-
GlobalQueue.
|
|
3002
|
-
GlobalQueue.
|
|
3003
|
-
GlobalQueue.
|
|
3004
|
-
GlobalQueue.
|
|
3005
|
-
GlobalQueue.
|
|
3006
|
-
GlobalQueue.
|
|
3007
|
-
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;
|
|
3008
3147
|
}
|
|
3009
3148
|
|
|
3010
3149
|
/**
|
|
@@ -3037,7 +3176,7 @@ let pendingProbe = null;
|
|
|
3037
3176
|
function collectPendingSources(e) {
|
|
3038
3177
|
if (!pendingProbe) return;
|
|
3039
3178
|
pendingProbe.sources.add(e);
|
|
3040
|
-
const t = e.
|
|
3179
|
+
const t = e.Be || e;
|
|
3041
3180
|
if (t !== e) pendingProbe.sources.add(t);
|
|
3042
3181
|
}
|
|
3043
3182
|
|
|
@@ -3067,20 +3206,20 @@ function collectPendingSources(e) {
|
|
|
3067
3206
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3068
3207
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3069
3208
|
// pending (the count check above), also matching.
|
|
3070
|
-
if (e.
|
|
3209
|
+
if (e.Qe & STATUS_ERROR) return false;
|
|
3071
3210
|
if (t.has(e)) return false;
|
|
3072
3211
|
t.add(e);
|
|
3073
|
-
const n = e.
|
|
3212
|
+
const n = e.Be;
|
|
3074
3213
|
if (n && markWalk(n, t)) return true;
|
|
3075
3214
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3076
3215
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3077
3216
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3078
3217
|
// latch a stale verdict on the companion.
|
|
3079
3218
|
const r = e;
|
|
3080
|
-
const i = r.
|
|
3219
|
+
const i = r.Ge & REACTIVE_RECOMPUTING_DEPS ? r.ut : undefined;
|
|
3081
3220
|
if (i !== null) {
|
|
3082
|
-
for (let e = r.
|
|
3083
|
-
if (!e.
|
|
3221
|
+
for (let e = r.Ke ?? null; e !== null; e = e.Ye) {
|
|
3222
|
+
if (!e._t && markWalk(e.qe, t)) return true;
|
|
3084
3223
|
if (e === i) break;
|
|
3085
3224
|
}
|
|
3086
3225
|
}
|
|
@@ -3092,35 +3231,35 @@ function collectPendingSources(e) {
|
|
|
3092
3231
|
}
|
|
3093
3232
|
|
|
3094
3233
|
function quietPending(e) {
|
|
3095
|
-
if (e
|
|
3096
|
-
for (const t of e
|
|
3234
|
+
if (e.je) {
|
|
3235
|
+
for (const t of e.je) if (!t.Nt) return false;
|
|
3097
3236
|
return true;
|
|
3098
3237
|
}
|
|
3099
|
-
return e.
|
|
3238
|
+
return e.Nt;
|
|
3100
3239
|
}
|
|
3101
3240
|
|
|
3102
3241
|
function newQuestionInFlight(e) {
|
|
3103
|
-
return !!(e.
|
|
3242
|
+
return !!(e.Qe & STATUS_PENDING) && !(e.Qe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3104
3243
|
}
|
|
3105
3244
|
|
|
3106
3245
|
function computePendingState(e) {
|
|
3107
3246
|
const t = e;
|
|
3108
|
-
if (t.
|
|
3247
|
+
if (t.Ge & REACTIVE_DISPOSED) return false;
|
|
3109
3248
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3110
3249
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3111
3250
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3112
3251
|
if (markCovered(e)) return true;
|
|
3113
|
-
const n = e.
|
|
3252
|
+
const n = e.Be;
|
|
3114
3253
|
if (e.t) {
|
|
3115
3254
|
const t = e.t;
|
|
3116
|
-
const n = t.
|
|
3255
|
+
const n = t.Be || t;
|
|
3117
3256
|
return newQuestionInFlight(n);
|
|
3118
3257
|
}
|
|
3119
3258
|
if (n && e.U !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3120
|
-
return !!(n.
|
|
3259
|
+
return !!(n.Ge & REACTIVE_MANUAL_WRITE) || !n.lt && !(n.Qe & STATUS_PENDING) || !!(n.Qe & STATUS_PENDING) && quietPending(n);
|
|
3121
3260
|
}
|
|
3122
|
-
if (e.U !== NOT_PENDING && !(t.
|
|
3123
|
-
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));
|
|
3124
3263
|
return true;
|
|
3125
3264
|
}
|
|
3126
3265
|
return newQuestionInFlight(t);
|
|
@@ -3128,19 +3267,19 @@ function computePendingState(e) {
|
|
|
3128
3267
|
|
|
3129
3268
|
function syncCompanions(e, t) {
|
|
3130
3269
|
if (e._) updatePendingSignal(e);
|
|
3131
|
-
if (e.
|
|
3270
|
+
if (e.R) setSignal(e.R, t);
|
|
3132
3271
|
}
|
|
3133
3272
|
|
|
3134
3273
|
function updatePendingSignal(e) {
|
|
3135
3274
|
if (e._) {
|
|
3136
3275
|
setSignal(e._, computePendingState(e));
|
|
3137
3276
|
}
|
|
3138
|
-
if (e.
|
|
3277
|
+
if (e.R) updatePendingSignal(e.R);
|
|
3139
3278
|
}
|
|
3140
3279
|
|
|
3141
3280
|
function updateChildCompanions(e) {
|
|
3142
|
-
for (let t = e.
|
|
3143
|
-
if (t._ || t.
|
|
3281
|
+
for (let t = e.rt; t !== null; t = t.it) {
|
|
3282
|
+
if (t._ || t.R) updatePendingSignal(t);
|
|
3144
3283
|
}
|
|
3145
3284
|
}
|
|
3146
3285
|
|
|
@@ -3158,9 +3297,9 @@ function updateChildCompanions(e) {
|
|
|
3158
3297
|
const visit = e => {
|
|
3159
3298
|
if (r.has(e)) return;
|
|
3160
3299
|
r.add(e);
|
|
3161
|
-
if (e._ || e.
|
|
3162
|
-
for (let t = e.
|
|
3163
|
-
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) {
|
|
3164
3303
|
visit(t);
|
|
3165
3304
|
}
|
|
3166
3305
|
};
|
|
@@ -3171,18 +3310,18 @@ function snapCompanionsToState(e) {
|
|
|
3171
3310
|
const t = e._;
|
|
3172
3311
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3173
3312
|
const n = computePendingState(e);
|
|
3174
|
-
if (t.
|
|
3175
|
-
t.
|
|
3313
|
+
if (t.We !== n || t.U !== NOT_PENDING) {
|
|
3314
|
+
t.We = n;
|
|
3176
3315
|
t.U = NOT_PENDING;
|
|
3177
3316
|
t.F = clock;
|
|
3178
3317
|
insertSubs(t);
|
|
3179
3318
|
schedule();
|
|
3180
3319
|
}
|
|
3181
3320
|
}
|
|
3182
|
-
const n = e.
|
|
3183
|
-
if (n && !(n.
|
|
3184
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.
|
|
3185
|
-
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;
|
|
3186
3325
|
insertIntoHeap(n, queueFor(n));
|
|
3187
3326
|
insertSubs(n);
|
|
3188
3327
|
schedule();
|
|
@@ -3192,7 +3331,7 @@ function snapCompanionsToState(e) {
|
|
|
3192
3331
|
}
|
|
3193
3332
|
|
|
3194
3333
|
function getLatestValueComputed(e) {
|
|
3195
|
-
if (!e.
|
|
3334
|
+
if (!e.R) {
|
|
3196
3335
|
const t = latestReadActive;
|
|
3197
3336
|
setLatestReadActive(false);
|
|
3198
3337
|
const n = pendingCheckActive;
|
|
@@ -3200,21 +3339,21 @@ function getLatestValueComputed(e) {
|
|
|
3200
3339
|
const r = context;
|
|
3201
3340
|
setContextInternal(null);
|
|
3202
3341
|
// Detach from owner so it isn't disposed with effects
|
|
3203
|
-
e.
|
|
3204
|
-
e.
|
|
3342
|
+
e.R = optimisticComputed(() => read(e));
|
|
3343
|
+
e.R.t = e;
|
|
3205
3344
|
// Parent-child lane relationship
|
|
3206
3345
|
setContextInternal(r);
|
|
3207
3346
|
setPendingCheckActive(n);
|
|
3208
3347
|
setLatestReadActive(t);
|
|
3209
3348
|
}
|
|
3210
|
-
return e.
|
|
3349
|
+
return e.R;
|
|
3211
3350
|
}
|
|
3212
3351
|
|
|
3213
3352
|
/** The latest()-mode read path, installed as GlobalQueue._latestRead. */ function latestRead(e) {
|
|
3214
3353
|
const t = getLatestValueComputed(e);
|
|
3215
3354
|
const n = latestReadActive;
|
|
3216
3355
|
setLatestReadActive(false);
|
|
3217
|
-
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;
|
|
3218
3357
|
let i;
|
|
3219
3358
|
try {
|
|
3220
3359
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -3223,18 +3362,18 @@ function getLatestValueComputed(e) {
|
|
|
3223
3362
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3224
3363
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3225
3364
|
const e = queueFor(t);
|
|
3226
|
-
if (t.
|
|
3365
|
+
if (t.ze >= e.P && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3227
3366
|
markHeap(e);
|
|
3228
3367
|
prepareComputed(t, true);
|
|
3229
3368
|
}
|
|
3230
3369
|
i = read(t);
|
|
3231
3370
|
} catch (t) {
|
|
3232
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3371
|
+
if (t instanceof NotReadyError && (!context || !(e.Qe & STATUS_UNINITIALIZED))) return r;
|
|
3233
3372
|
throw t;
|
|
3234
3373
|
} finally {
|
|
3235
3374
|
setLatestReadActive(n);
|
|
3236
3375
|
}
|
|
3237
|
-
if (t.
|
|
3376
|
+
if (t.Qe & STATUS_PENDING) return r;
|
|
3238
3377
|
if (stale && currentOptimisticLane && t.i) {
|
|
3239
3378
|
const e = findLane(t.i);
|
|
3240
3379
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3252,12 +3391,12 @@ function getLatestValueComputed(e) {
|
|
|
3252
3391
|
|
|
3253
3392
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3254
3393
|
setPendingCheckActive(false);
|
|
3255
|
-
if (typeof e.
|
|
3256
|
-
const i = n.
|
|
3394
|
+
if (typeof e.ke === "function") prepareComputed(e, true);
|
|
3395
|
+
const i = n.Qe;
|
|
3257
3396
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3258
3397
|
if (tracking && e !== t) link(e, t);
|
|
3259
3398
|
setPendingCheckActive(true);
|
|
3260
|
-
throw n.
|
|
3399
|
+
throw n.we;
|
|
3261
3400
|
}
|
|
3262
3401
|
collectPendingSources(e);
|
|
3263
3402
|
if (r) collectPendingSources(r);
|
|
@@ -3269,10 +3408,10 @@ function recordFreshRead(e, t) {
|
|
|
3269
3408
|
}
|
|
3270
3409
|
|
|
3271
3410
|
function applyReask(e, t) {
|
|
3272
|
-
const n = !!(e.
|
|
3273
|
-
const r = t && !(n && !e.
|
|
3274
|
-
const i = n && e.
|
|
3275
|
-
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;
|
|
3276
3415
|
return i;
|
|
3277
3416
|
}
|
|
3278
3417
|
|
|
@@ -3312,7 +3451,7 @@ function isPending(e) {
|
|
|
3312
3451
|
} catch (e) {
|
|
3313
3452
|
collectPending();
|
|
3314
3453
|
if (e instanceof NotReadyError) {
|
|
3315
|
-
const t = !!(e.source?.
|
|
3454
|
+
const t = !!(e.source?.Qe & STATUS_UNINITIALIZED);
|
|
3316
3455
|
if (r.found && !t) return true;
|
|
3317
3456
|
if (context && t) throw e;
|
|
3318
3457
|
}
|
|
@@ -3326,25 +3465,25 @@ function isPending(e) {
|
|
|
3326
3465
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3327
3466
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3328
3467
|
// direct calls used, so behavior is identical once this module loads.
|
|
3329
|
-
GlobalQueue.
|
|
3468
|
+
GlobalQueue.le = syncCompanions;
|
|
3330
3469
|
|
|
3331
|
-
GlobalQueue.
|
|
3470
|
+
GlobalQueue.ae = updatePendingSignal;
|
|
3332
3471
|
|
|
3333
|
-
GlobalQueue.
|
|
3472
|
+
GlobalQueue.ce = updateChildCompanions;
|
|
3334
3473
|
|
|
3335
|
-
GlobalQueue.
|
|
3474
|
+
GlobalQueue.fe = snapCompanionsToState;
|
|
3336
3475
|
|
|
3337
|
-
GlobalQueue.
|
|
3476
|
+
GlobalQueue.Ee = latestRead;
|
|
3338
3477
|
|
|
3339
|
-
GlobalQueue.
|
|
3478
|
+
GlobalQueue.de = pendingCheckRead;
|
|
3340
3479
|
|
|
3341
|
-
GlobalQueue.
|
|
3480
|
+
GlobalQueue.Se = recordFreshRead;
|
|
3342
3481
|
|
|
3343
|
-
GlobalQueue.
|
|
3482
|
+
GlobalQueue.Te = applyReask;
|
|
3344
3483
|
|
|
3345
|
-
GlobalQueue.
|
|
3484
|
+
GlobalQueue.Oe = repollDownstreamVerdicts;
|
|
3346
3485
|
|
|
3347
|
-
GlobalQueue.
|
|
3486
|
+
GlobalQueue._e = witnessAffects;
|
|
3348
3487
|
|
|
3349
3488
|
/**
|
|
3350
3489
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3354,16 +3493,16 @@ GlobalQueue.Oe = witnessAffects;
|
|
|
3354
3493
|
const i = !!r?.user;
|
|
3355
3494
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3356
3495
|
recompute(o, true);
|
|
3357
|
-
!r?.defer && (o.
|
|
3496
|
+
!r?.defer && (o.Fe === EFFECT_USER || r?.schedule ? o.Ze.enqueue(o.Fe, runEffect.bind(null, o)) : runEffect(o));
|
|
3358
3497
|
}
|
|
3359
3498
|
|
|
3360
3499
|
function notifyEffectStatus(e, t) {
|
|
3361
3500
|
// Use passed values if provided, otherwise read from node
|
|
3362
|
-
const n = e !== undefined ? e : this.
|
|
3363
|
-
const r = t !== undefined ? t : this.
|
|
3501
|
+
const n = e !== undefined ? e : this.Qe;
|
|
3502
|
+
const r = t !== undefined ? t : this.we;
|
|
3364
3503
|
if (n & STATUS_ERROR) {
|
|
3365
|
-
this.
|
|
3366
|
-
if (this.
|
|
3504
|
+
this.Ze.notify(this, STATUS_PENDING, 0);
|
|
3505
|
+
if (this.Fe === EFFECT_USER) {
|
|
3367
3506
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3368
3507
|
// queue it like the effect function. It runs in the same imperative,
|
|
3369
3508
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3373,23 +3512,23 @@ function notifyEffectStatus(e, t) {
|
|
|
3373
3512
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3374
3513
|
// `status` arg without node-state writes) don't queue: the status
|
|
3375
3514
|
// re-propagates unblocked at commit.
|
|
3376
|
-
if (this.
|
|
3377
|
-
this.
|
|
3378
|
-
this.
|
|
3515
|
+
if (this.Qe & STATUS_ERROR) {
|
|
3516
|
+
this.xe = true;
|
|
3517
|
+
this.Ze.enqueue(this.Fe, this.Ct ??= runEffect.bind(null, this));
|
|
3379
3518
|
}
|
|
3380
3519
|
return;
|
|
3381
3520
|
}
|
|
3382
|
-
if (!this.
|
|
3521
|
+
if (!this.Ze.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3383
3522
|
haltReactivity(unwrapStatusError(r));
|
|
3384
3523
|
throw r;
|
|
3385
3524
|
}
|
|
3386
|
-
} else if (this.
|
|
3387
|
-
this.
|
|
3525
|
+
} else if (this.Fe === EFFECT_RENDER) {
|
|
3526
|
+
this.Ze.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3388
3527
|
}
|
|
3389
3528
|
}
|
|
3390
3529
|
|
|
3391
3530
|
function runEffect(e) {
|
|
3392
|
-
if (!e.
|
|
3531
|
+
if (!e.xe || e.Ge & REACTIVE_DISPOSED) return;
|
|
3393
3532
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3394
3533
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3395
3534
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3400,46 +3539,46 @@ function runEffect(e) {
|
|
|
3400
3539
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3401
3540
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3402
3541
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3403
|
-
if (e.
|
|
3404
|
-
const t = unwrapStatusError(e.
|
|
3405
|
-
e.
|
|
3406
|
-
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;
|
|
3407
3546
|
try {
|
|
3408
|
-
e.
|
|
3409
|
-
const t = e.
|
|
3410
|
-
e.
|
|
3547
|
+
e.wt ? e.wt(t, () => {
|
|
3548
|
+
const t = e.Et;
|
|
3549
|
+
e.Et = undefined;
|
|
3411
3550
|
t?.();
|
|
3412
3551
|
}) : console.error(t);
|
|
3413
3552
|
} catch (t) {
|
|
3414
|
-
if (!e.
|
|
3553
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3415
3554
|
haltReactivity(t);
|
|
3416
3555
|
throw t;
|
|
3417
3556
|
}
|
|
3418
3557
|
}
|
|
3419
3558
|
return;
|
|
3420
3559
|
}
|
|
3421
|
-
const t = e.
|
|
3422
|
-
e.
|
|
3560
|
+
const t = e.Et;
|
|
3561
|
+
e.Et = undefined;
|
|
3423
3562
|
try {
|
|
3424
3563
|
t?.();
|
|
3425
|
-
const n = e.
|
|
3564
|
+
const n = e.Dt(e.We, e.bt);
|
|
3426
3565
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3427
3566
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3428
|
-
e.
|
|
3567
|
+
e.Et = n;
|
|
3429
3568
|
} catch (t) {
|
|
3430
|
-
e.
|
|
3431
|
-
e.
|
|
3432
|
-
if (!e.
|
|
3569
|
+
e.we = new StatusError(e, t);
|
|
3570
|
+
e.Qe |= STATUS_ERROR;
|
|
3571
|
+
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3433
3572
|
haltReactivity(t);
|
|
3434
3573
|
throw t;
|
|
3435
3574
|
}
|
|
3436
3575
|
} finally {
|
|
3437
|
-
e.
|
|
3438
|
-
e.
|
|
3576
|
+
e.bt = e.We;
|
|
3577
|
+
e.xe = false;
|
|
3439
3578
|
}
|
|
3440
3579
|
}
|
|
3441
3580
|
|
|
3442
|
-
GlobalQueue.
|
|
3581
|
+
GlobalQueue.ee = runEffect;
|
|
3443
3582
|
|
|
3444
3583
|
/**
|
|
3445
3584
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3447,39 +3586,39 @@ GlobalQueue.J = runEffect;
|
|
|
3447
3586
|
* Uses stale reads.
|
|
3448
3587
|
*/ function trackedEffect(e, t) {
|
|
3449
3588
|
const run = () => {
|
|
3450
|
-
if (!n.
|
|
3589
|
+
if (!n.xe || n.Ge & REACTIVE_DISPOSED) return;
|
|
3451
3590
|
try {
|
|
3452
|
-
n.
|
|
3591
|
+
n.xe = false;
|
|
3453
3592
|
recompute(n);
|
|
3454
3593
|
} finally {}
|
|
3455
3594
|
};
|
|
3456
3595
|
const n = computed(() => {
|
|
3457
|
-
const t = n.
|
|
3458
|
-
n.
|
|
3596
|
+
const t = n.Et;
|
|
3597
|
+
n.Et = undefined;
|
|
3459
3598
|
t?.();
|
|
3460
3599
|
const r = staleValues(e);
|
|
3461
|
-
n.
|
|
3600
|
+
n.Et = r;
|
|
3462
3601
|
}, {
|
|
3463
3602
|
...t,
|
|
3464
3603
|
lazy: true
|
|
3465
3604
|
});
|
|
3466
|
-
n.
|
|
3467
|
-
n.
|
|
3468
|
-
n.
|
|
3469
|
-
n.
|
|
3470
|
-
n.
|
|
3471
|
-
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;
|
|
3472
3611
|
if (r & STATUS_ERROR) {
|
|
3473
|
-
n.
|
|
3474
|
-
const e = t !== undefined ? t : n.
|
|
3475
|
-
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)) {
|
|
3476
3615
|
haltReactivity(unwrapStatusError(e));
|
|
3477
3616
|
throw e;
|
|
3478
3617
|
}
|
|
3479
3618
|
}
|
|
3480
3619
|
};
|
|
3481
|
-
n.
|
|
3482
|
-
n.
|
|
3620
|
+
n.Xe = run;
|
|
3621
|
+
n.Ze.enqueue(EFFECT_USER, run);
|
|
3483
3622
|
}
|
|
3484
3623
|
|
|
3485
3624
|
function restoreTransition(e, t) {
|
|
@@ -3561,7 +3700,12 @@ function restoreTransition(e, t) {
|
|
|
3561
3700
|
o = currentTransition(o);
|
|
3562
3701
|
const u = o.$.indexOf(i);
|
|
3563
3702
|
if (u >= 0) o.$.splice(u, 1);
|
|
3564
|
-
|
|
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);
|
|
3565
3709
|
schedule();
|
|
3566
3710
|
s ? r(t) : n(e);
|
|
3567
3711
|
};
|
|
@@ -3660,7 +3804,7 @@ function accessor(e) {
|
|
|
3660
3804
|
function createSignal(e, t) {
|
|
3661
3805
|
if (typeof e === "function") {
|
|
3662
3806
|
const n = computed(e, t);
|
|
3663
|
-
n.
|
|
3807
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3664
3808
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3665
3809
|
}
|
|
3666
3810
|
const n = signal(e, t);
|
|
@@ -3872,9 +4016,9 @@ function createEffect(e, t, n) {
|
|
|
3872
4016
|
// route through the inherited queue.
|
|
3873
4017
|
const i = getOwner();
|
|
3874
4018
|
const o = new MicrotaskQueue;
|
|
3875
|
-
o.B = i.
|
|
4019
|
+
o.B = i.Ze;
|
|
3876
4020
|
// notify() forwards up the normal chain
|
|
3877
|
-
i.
|
|
4021
|
+
i.Ze = o;
|
|
3878
4022
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
3879
4023
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
3880
4024
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -3901,7 +4045,7 @@ function createOptimistic(e, t) {
|
|
|
3901
4045
|
installOptimisticEngine();
|
|
3902
4046
|
if (typeof e === "function") {
|
|
3903
4047
|
const n = optimisticComputed(e, t);
|
|
3904
|
-
n.
|
|
4048
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3905
4049
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3906
4050
|
}
|
|
3907
4051
|
const n = optimisticSignal(e, t);
|
|
@@ -3990,7 +4134,7 @@ function createOptimistic(e, t) {
|
|
|
3990
4134
|
* on owner disposal
|
|
3991
4135
|
*/ function onSettled(e) {
|
|
3992
4136
|
const t = getOwner();
|
|
3993
|
-
t && !(t.
|
|
4137
|
+
t && !(t.Ue & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3994
4138
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3995
4139
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3996
4140
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4089,6 +4233,17 @@ function keyedMatch(e, t, n) {
|
|
|
4089
4233
|
return e === t || isWrappable(e) && isWrappable(t) && n(e) === n(t);
|
|
4090
4234
|
}
|
|
4091
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
|
+
|
|
4092
4247
|
// Array reconciliation updates the slots it visits, then swaps STORE_VALUE.
|
|
4093
4248
|
// Previously tracked keys that are absent from `next` still need invalidating,
|
|
4094
4249
|
// and `in` dependencies should follow the new value's membership. Use
|
|
@@ -4155,7 +4310,7 @@ function applyStateChild(e, t, n, r) {
|
|
|
4155
4310
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
4156
4311
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
4157
4312
|
function applyArrayItem(e, t, n, r, i) {
|
|
4158
|
-
if (
|
|
4313
|
+
if (recursablePair(t, e)) {
|
|
4159
4314
|
const o = wrap(t, n);
|
|
4160
4315
|
r && setSignal(r, o);
|
|
4161
4316
|
applyState(e, o, i);
|
|
@@ -4345,7 +4500,7 @@ function applyStateFast(e, t, n) {
|
|
|
4345
4500
|
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
4346
4501
|
// replace the slot node instead of recursing.
|
|
4347
4502
|
if (E !== e[a]) {
|
|
4348
|
-
if (
|
|
4503
|
+
if (!recursablePair(E, e[a])) {
|
|
4349
4504
|
i?.[a] && setSignal(i[a], wrapValue(e[a], t));
|
|
4350
4505
|
} else applyStateChild(e[a], E, t, n);
|
|
4351
4506
|
}
|
|
@@ -4401,7 +4556,7 @@ function applyStateFast(e, t, n) {
|
|
|
4401
4556
|
} else if (e.length) {
|
|
4402
4557
|
for (let s = 0, u = e.length; s < u; s++) {
|
|
4403
4558
|
const u = r[s];
|
|
4404
|
-
if (
|
|
4559
|
+
if (recursablePair(u, e[s])) {
|
|
4405
4560
|
if (u !== e[s]) applyStateChild(e[s], u, t, n);
|
|
4406
4561
|
} else {
|
|
4407
4562
|
if (u !== e[s]) o = true;
|
|
@@ -4491,13 +4646,13 @@ function applyStateSlow(e, t, n) {
|
|
|
4491
4646
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4492
4647
|
let a, c, f, E, d, S, T, O;
|
|
4493
4648
|
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4494
|
-
if (
|
|
4495
|
-
if (
|
|
4649
|
+
if (S !== e[f] && isWrappable(S) && isWrappable(e[f])) {
|
|
4650
|
+
if (!recursablePair(S, e[f])) {
|
|
4496
4651
|
s?.[f] && setSignal(s[f], wrapValue(e[f], t));
|
|
4497
4652
|
} else applyState(e[f], wrap(S, t), n);
|
|
4498
4653
|
}
|
|
4499
4654
|
}
|
|
4500
|
-
const _ = new Array(e.length),
|
|
4655
|
+
const _ = new Array(e.length), R = new Map;
|
|
4501
4656
|
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4502
4657
|
d--) {
|
|
4503
4658
|
_[d] = S;
|
|
@@ -4521,18 +4676,18 @@ function applyStateSlow(e, t, n) {
|
|
|
4521
4676
|
for (c = d; c >= f; c--) {
|
|
4522
4677
|
S = e[c];
|
|
4523
4678
|
O = itemKey(S, n);
|
|
4524
|
-
a =
|
|
4679
|
+
a = R.get(O);
|
|
4525
4680
|
T[c] = a === undefined ? -1 : a;
|
|
4526
|
-
|
|
4681
|
+
R.set(O, c);
|
|
4527
4682
|
}
|
|
4528
4683
|
for (a = f; a <= E; a++) {
|
|
4529
4684
|
S = getOverrideValue(r, i, a, o);
|
|
4530
4685
|
O = itemKey(S, n);
|
|
4531
|
-
c =
|
|
4686
|
+
c = R.get(O);
|
|
4532
4687
|
if (c !== undefined && c !== -1) {
|
|
4533
4688
|
_[c] = S;
|
|
4534
4689
|
c = T[c];
|
|
4535
|
-
|
|
4690
|
+
R.set(O, c);
|
|
4536
4691
|
}
|
|
4537
4692
|
}
|
|
4538
4693
|
for (c = f; c < e.length; c++) {
|
|
@@ -4544,7 +4699,7 @@ function applyStateSlow(e, t, n) {
|
|
|
4544
4699
|
} else if (e.length) {
|
|
4545
4700
|
for (let l = 0, a = e.length; l < a; l++) {
|
|
4546
4701
|
const a = getOverrideValue(r, i, l, o);
|
|
4547
|
-
if (
|
|
4702
|
+
if (recursablePair(a, e[l])) {
|
|
4548
4703
|
if (a !== e[l]) applyState(e[l], wrap(a, t), n);
|
|
4549
4704
|
} else {
|
|
4550
4705
|
if (a !== e[l]) u = true;
|
|
@@ -4593,6 +4748,58 @@ function applyStateSlow(e, t, n) {
|
|
|
4593
4748
|
// the positional branch and object descent to plain per-property merging.
|
|
4594
4749
|
const NOKEY = () => null;
|
|
4595
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
|
+
|
|
4596
4803
|
/**
|
|
4597
4804
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
4598
4805
|
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
@@ -4607,6 +4814,9 @@ const NOKEY = () => null;
|
|
|
4607
4814
|
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
4608
4815
|
* monitors), where no keyed diff pass is needed or wanted.
|
|
4609
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
|
+
*
|
|
4610
4820
|
* @param value the next state to merge in
|
|
4611
4821
|
* @param key property name (string) or extractor function for stable
|
|
4612
4822
|
* identity (default `"id"`); pass `null` for positional merging
|
|
@@ -4624,17 +4834,7 @@ const NOKEY = () => null;
|
|
|
4624
4834
|
* setStats(reconcile(nextStats, null));
|
|
4625
4835
|
* ```
|
|
4626
4836
|
*/ function reconcile(e, t = "id") {
|
|
4627
|
-
return n =>
|
|
4628
|
-
if (n == null) throw new Error("");
|
|
4629
|
-
if (t === null) {
|
|
4630
|
-
applyState(e, n, NOKEY);
|
|
4631
|
-
return;
|
|
4632
|
-
}
|
|
4633
|
-
const r = typeof t === "string" ? e => e[t] : t;
|
|
4634
|
-
const i = r(n);
|
|
4635
|
-
if (i !== undefined && r(e) !== i) throw new Error("");
|
|
4636
|
-
applyState(e, n, r);
|
|
4637
|
-
};
|
|
4837
|
+
return n => reconcileState(e, n, t, false);
|
|
4638
4838
|
}
|
|
4639
4839
|
|
|
4640
4840
|
function createProjectionInternal(e, t, n) {
|
|
@@ -4667,9 +4867,9 @@ function createProjectionInternal(e, t, n) {
|
|
|
4667
4867
|
const s = wrapProjection(t);
|
|
4668
4868
|
r = computed(() => {
|
|
4669
4869
|
if (!r) r = getOwner();
|
|
4670
|
-
runProjectionComputed(s, e, n?.key
|
|
4870
|
+
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key);
|
|
4671
4871
|
}, undefined);
|
|
4672
|
-
r.
|
|
4872
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
4673
4873
|
return {
|
|
4674
4874
|
store: s,
|
|
4675
4875
|
node: r
|
|
@@ -4684,6 +4884,10 @@ function createProjectionInternal(e, t, n) {
|
|
|
4684
4884
|
* items keep their proxy identity — only added/removed items are
|
|
4685
4885
|
* created/disposed.
|
|
4686
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
|
+
*
|
|
4687
4891
|
* Returns the projected store directly (no setter — reads only).
|
|
4688
4892
|
*
|
|
4689
4893
|
* Use this when you want the structural-sharing / per-property tracking
|
|
@@ -4696,7 +4900,8 @@ function createProjectionInternal(e, t, n) {
|
|
|
4696
4900
|
* @param seed the backing store value to wrap and reconcile into
|
|
4697
4901
|
* @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
|
|
4698
4902
|
* `"id"`; specify it only when your data uses a different identity field
|
|
4699
|
-
* (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.
|
|
4700
4905
|
*
|
|
4701
4906
|
* @example
|
|
4702
4907
|
* ```ts
|
|
@@ -4738,13 +4943,13 @@ function createProjectionInternal(e, t, n) {
|
|
|
4738
4943
|
const o = getOwner();
|
|
4739
4944
|
let s = false;
|
|
4740
4945
|
let u;
|
|
4741
|
-
const l = new Proxy(e, createWriteTraps(() => !s || o.
|
|
4946
|
+
const l = new Proxy(e, createWriteTraps(() => !s || o.lt === u, i));
|
|
4742
4947
|
storeSetter(l, i => {
|
|
4743
4948
|
u = t(i);
|
|
4744
4949
|
s = true;
|
|
4745
4950
|
const commit = t => {
|
|
4746
4951
|
if (t === i || t === undefined) return;
|
|
4747
|
-
const write = () => storeSetter(e,
|
|
4952
|
+
const write = () => storeSetter(e, e => reconcileState(t, e, n, true));
|
|
4748
4953
|
r ? r(write) : write();
|
|
4749
4954
|
};
|
|
4750
4955
|
commit(handleAsync(o, u, commit));
|
|
@@ -4913,6 +5118,14 @@ function isRawValue(e) {
|
|
|
4913
5118
|
|
|
4914
5119
|
function markRawOne(e) {
|
|
4915
5120
|
if (isWrappable(e)) {
|
|
5121
|
+
// A store proxy is already tracked elsewhere: the shallow boundary passes
|
|
5122
|
+
// it through by reference (replaced, never edited — same slot semantics
|
|
5123
|
+
// as a raw) instead of claiming it raw. The sticky mark is global, so
|
|
5124
|
+
// marking a live proxy would make wrap() serve it verbatim through every
|
|
5125
|
+
// OTHER store too — downstream deep stores then captured it instead of
|
|
5126
|
+
// wrapping it in their own family, and their writes landed in the
|
|
5127
|
+
// upstream store's override layer (#2932).
|
|
5128
|
+
if (e[$TARGET] !== undefined) return;
|
|
4916
5129
|
rawValuesUsed = true;
|
|
4917
5130
|
rawValues.add(e);
|
|
4918
5131
|
}
|
|
@@ -4964,11 +5177,39 @@ function wrapShallow(e) {
|
|
|
4964
5177
|
return n;
|
|
4965
5178
|
}
|
|
4966
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
|
+
|
|
4967
5187
|
function isWrappable(e) {
|
|
4968
5188
|
if (e == null || typeof e !== "object" || Object.isFrozen(e)) return false;
|
|
4969
|
-
//
|
|
4970
|
-
//
|
|
4971
|
-
|
|
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;
|
|
4972
5213
|
}
|
|
4973
5214
|
|
|
4974
5215
|
let writeOverride = false;
|
|
@@ -5046,7 +5287,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
5046
5287
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
5047
5288
|
* override, else held pending value, else committed value.
|
|
5048
5289
|
*/ function visibleNodeValue(e) {
|
|
5049
|
-
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;
|
|
5050
5291
|
}
|
|
5051
5292
|
|
|
5052
5293
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -5101,7 +5342,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5101
5342
|
}
|
|
5102
5343
|
if (o && n in o) {
|
|
5103
5344
|
const e = o[n];
|
|
5104
|
-
s.
|
|
5345
|
+
s.ve = e === undefined ? NO_SNAPSHOT : e;
|
|
5105
5346
|
snapshotSources?.add(s);
|
|
5106
5347
|
}
|
|
5107
5348
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -5131,7 +5372,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5131
5372
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
5132
5373
|
for (const [r, i] of affectsScopes) {
|
|
5133
5374
|
if (r.k && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
5134
|
-
GlobalQueue.
|
|
5375
|
+
GlobalQueue.ie(e);
|
|
5135
5376
|
i.inherited.push(e);
|
|
5136
5377
|
}
|
|
5137
5378
|
}
|
|
@@ -5219,11 +5460,11 @@ i) {
|
|
|
5219
5460
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
5220
5461
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
5221
5462
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
5222
|
-
if (n?.k) GlobalQueue.
|
|
5463
|
+
if (n?.k) GlobalQueue._e(n);
|
|
5223
5464
|
if (affectsScopes.size) {
|
|
5224
5465
|
const r = e[STORE_VALUE];
|
|
5225
5466
|
for (const [e, i] of affectsScopes) {
|
|
5226
|
-
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);
|
|
5227
5468
|
}
|
|
5228
5469
|
}
|
|
5229
5470
|
}
|
|
@@ -5240,11 +5481,11 @@ i) {
|
|
|
5240
5481
|
* @internal
|
|
5241
5482
|
*/ function getStoreAffectsNodes(e, t) {
|
|
5242
5483
|
const n = getNodes(e, STORE_NODE);
|
|
5243
|
-
GlobalQueue.
|
|
5484
|
+
GlobalQueue.ne ||= e => {
|
|
5244
5485
|
const t = affectsScopes.get(e);
|
|
5245
5486
|
if (!t) return;
|
|
5246
5487
|
affectsScopes.delete(e);
|
|
5247
|
-
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]);
|
|
5248
5489
|
};
|
|
5249
5490
|
if (t === undefined) {
|
|
5250
5491
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -5371,7 +5612,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5371
5612
|
}
|
|
5372
5613
|
const r = e[STORE_VALUE];
|
|
5373
5614
|
const i = r[n];
|
|
5374
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5615
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.Qe ?? 0) & STATUS_PENDING)) {
|
|
5375
5616
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5376
5617
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5377
5618
|
snapshotSources?.add(e);
|
|
@@ -5399,7 +5640,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5399
5640
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5400
5641
|
// optimistic engine before wrapping.
|
|
5401
5642
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5402
|
-
GlobalQueue.
|
|
5643
|
+
GlobalQueue.De(t);
|
|
5403
5644
|
}
|
|
5404
5645
|
}
|
|
5405
5646
|
|
|
@@ -5409,8 +5650,11 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5409
5650
|
* concurrent actions writing disjoint keys must revert independently, exactly
|
|
5410
5651
|
* like optimistic signal nodes do via the transition's _optimisticNodes.
|
|
5411
5652
|
* `activeTransition` is the write's transaction (action() opens it before the
|
|
5412
|
-
* body runs); null marks an ambient write
|
|
5413
|
-
*
|
|
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.
|
|
5414
5658
|
*/ function stampOptimisticOwner(e, t, n) {
|
|
5415
5659
|
if (t === STORE_OPTIMISTIC_OVERRIDE) (e[STORE_OPTIMISTIC_OWNERS] ??= Object.create(null))[n] = activeTransition;
|
|
5416
5660
|
}
|
|
@@ -5463,16 +5707,36 @@ function notifyStoreProperty(e, t, n, r, i, o) {
|
|
|
5463
5707
|
let Writing = null;
|
|
5464
5708
|
|
|
5465
5709
|
/**
|
|
5466
|
-
* A derived store
|
|
5467
|
-
*
|
|
5468
|
-
*
|
|
5469
|
-
*
|
|
5470
|
-
*
|
|
5471
|
-
*
|
|
5472
|
-
*
|
|
5473
|
-
|
|
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) {
|
|
5474
5736
|
const t = e[STORE_FIREWALL];
|
|
5475
|
-
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);
|
|
5476
5740
|
}
|
|
5477
5741
|
|
|
5478
5742
|
const storeTraps = {
|
|
@@ -5559,7 +5823,14 @@ const storeTraps = {
|
|
|
5559
5823
|
}
|
|
5560
5824
|
// Untracked fall-through (tracked reads already threw via their node in
|
|
5561
5825
|
// read(); the dev strictRead error above wins first for memo parity).
|
|
5562
|
-
|
|
5826
|
+
// Observer-present reads must NOT re-consult the flag here: during the
|
|
5827
|
+
// settle flush the firewall has recomputed (first values live on the
|
|
5828
|
+
// pending rail, served by read() above) but its UNINITIALIZED clear is
|
|
5829
|
+
// deferred to batch commit — vetoing read()'s verdict with the stale flag
|
|
5830
|
+
// threw a fresh NotReadyError for an already-settled source, which no
|
|
5831
|
+
// sweep would ever release (#2938: projection over an async store wedged
|
|
5832
|
+
// its Loading boundary on `undefined`).
|
|
5833
|
+
if (!r && !getObserver()) throwIfUnreadable(e);
|
|
5563
5834
|
return isWrappable(f) ? wrap(f, e) : f;
|
|
5564
5835
|
},
|
|
5565
5836
|
has(e, t) {
|
|
@@ -5579,7 +5850,7 @@ const storeTraps = {
|
|
|
5579
5850
|
if (getObserver()) {
|
|
5580
5851
|
return read(getNode(e, i, t, r));
|
|
5581
5852
|
}
|
|
5582
|
-
|
|
5853
|
+
throwIfUnreadable(e);
|
|
5583
5854
|
return r;
|
|
5584
5855
|
},
|
|
5585
5856
|
set(e, t, n) {
|
|
@@ -5591,37 +5862,48 @@ const storeTraps = {
|
|
|
5591
5862
|
const u = getOverlayLayer(e, t);
|
|
5592
5863
|
const l = u ? u[t] : i;
|
|
5593
5864
|
const a = u ? u[t] !== $DELETED : t in e[STORE_VALUE];
|
|
5594
|
-
|
|
5595
|
-
|
|
5865
|
+
// Shallow slots hold store proxies verbatim (pass-through reference,
|
|
5866
|
+
// never raw-marked — see markRawOne/#2932); everything else unwraps
|
|
5867
|
+
// and marks as usual.
|
|
5868
|
+
const c = !!e[STORE_SHALLOW] && n?.[$TARGET] !== undefined;
|
|
5869
|
+
const f = c ? n : unwrapStoreValue(n);
|
|
5870
|
+
if (e[STORE_SHALLOW] && !c && isWrappable(f)) {
|
|
5871
|
+
// Flip the live gate too: a bare add was inert unless something else
|
|
5872
|
+
// had already marked a raw somewhere (wrap() checks rawValuesUsed
|
|
5873
|
+
// first), so the documented set-trap ingest mark silently no-oped in
|
|
5874
|
+
// apps whose only shallow data arrived through writes.
|
|
5875
|
+
rawValuesUsed = true;
|
|
5876
|
+
rawValues.add(f);
|
|
5877
|
+
}
|
|
5596
5878
|
// Symbol-keyed writes on arrays are metadata, not index writes — never run
|
|
5597
5879
|
// them through the numeric index/length machinery (`parseInt` on a symbol
|
|
5598
5880
|
// throws). #2769
|
|
5599
|
-
const
|
|
5600
|
-
const
|
|
5601
|
-
const
|
|
5602
|
-
const
|
|
5603
|
-
const
|
|
5604
|
-
if (l ===
|
|
5881
|
+
const E = typeof t === "string" ? Number(t) : -1;
|
|
5882
|
+
const d = Array.isArray(s) && Number.isInteger(E) && E >= 0 && E < 4294967295 && String(E) === t;
|
|
5883
|
+
const S = d ? E + 1 : 0;
|
|
5884
|
+
const T = d && (getOverlayLayer(e, "length") ?? s).length;
|
|
5885
|
+
const O = d && S > T ? S : undefined;
|
|
5886
|
+
if (l === f && O === undefined) return true;
|
|
5605
5887
|
armOptimisticStoreWrite(e, r);
|
|
5606
|
-
if (
|
|
5888
|
+
if (f !== undefined && f === i && O === undefined) {
|
|
5607
5889
|
delete e[o]?.[t];
|
|
5608
5890
|
if (o === STORE_OPTIMISTIC_OVERRIDE) delete e[STORE_OPTIMISTIC_OWNERS]?.[t];
|
|
5609
5891
|
} else {
|
|
5610
5892
|
const n = e[o] || (e[o] = Object.create(null));
|
|
5611
|
-
n[t] =
|
|
5893
|
+
n[t] = f;
|
|
5612
5894
|
stampOptimisticOwner(e, o, t);
|
|
5613
|
-
if (
|
|
5614
|
-
n.length =
|
|
5895
|
+
if (O !== undefined) {
|
|
5896
|
+
n.length = O;
|
|
5615
5897
|
stampOptimisticOwner(e, o, "length");
|
|
5616
5898
|
}
|
|
5617
5899
|
}
|
|
5618
|
-
notifyStoreProperty(e, t, "set",
|
|
5900
|
+
notifyStoreProperty(e, t, "set", f, l, a);
|
|
5619
5901
|
// Shrinking an array's length must remove the truncated indices, otherwise
|
|
5620
5902
|
// they leak through `has`, `ownKeys`, and (tracked) index reads from the
|
|
5621
5903
|
// underlying value. Mark each as deleted and notify so reactive reads update. #2768
|
|
5622
|
-
if (Array.isArray(s) && t === "length" && typeof
|
|
5904
|
+
if (Array.isArray(s) && t === "length" && typeof f === "number" && typeof l === "number" && f < l) {
|
|
5623
5905
|
const t = e[o] || (e[o] = Object.create(null));
|
|
5624
|
-
for (let n =
|
|
5906
|
+
for (let n = f; n < l; n++) {
|
|
5625
5907
|
if (t[n] === $DELETED) continue;
|
|
5626
5908
|
const r = n in t ? t[n] : s[n];
|
|
5627
5909
|
if (!(n in t) && !(n in s)) continue;
|
|
@@ -5631,13 +5913,13 @@ const storeTraps = {
|
|
|
5631
5913
|
}
|
|
5632
5914
|
}
|
|
5633
5915
|
// notify length change
|
|
5634
|
-
if (Array.isArray(s) && t !== "length" &&
|
|
5916
|
+
if (Array.isArray(s) && t !== "length" && O !== undefined) {
|
|
5635
5917
|
const t = getNodes(e, STORE_NODE);
|
|
5636
5918
|
if (t.length) {
|
|
5637
|
-
setSignal(t.length,
|
|
5919
|
+
setSignal(t.length, O);
|
|
5638
5920
|
} else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
|
|
5639
|
-
const n = upsertStoreNode(e, t, "length",
|
|
5640
|
-
setSignal(n,
|
|
5921
|
+
const n = upsertStoreNode(e, t, "length", T, e[STORE_SNAPSHOT_PROPS]);
|
|
5922
|
+
setSignal(n, O);
|
|
5641
5923
|
}
|
|
5642
5924
|
}
|
|
5643
5925
|
if (false) ;
|
|
@@ -5698,7 +5980,7 @@ const storeTraps = {
|
|
|
5698
5980
|
// path is exempt (like the get/has traps' writeOnly early returns):
|
|
5699
5981
|
// the first landing's reconcile enumerates the store while
|
|
5700
5982
|
// STATUS_UNINITIALIZED is still set — it IS the initialization.
|
|
5701
|
-
if (!getObserver() && !writeOnly(e[$PROXY]))
|
|
5983
|
+
if (!getObserver() && !writeOnly(e[$PROXY])) throwIfUnreadable(e);
|
|
5702
5984
|
}
|
|
5703
5985
|
// Merge optimistic override with regular override for key enumeration
|
|
5704
5986
|
let t = getKeys(e[STORE_VALUE], e[STORE_OVERRIDE], false);
|
|
@@ -5816,17 +6098,17 @@ function createStore(e, t, n) {
|
|
|
5816
6098
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5817
6099
|
* no visual change.
|
|
5818
6100
|
*/ function notifyMarkBoundaries(e) {
|
|
5819
|
-
if (!e.
|
|
6101
|
+
if (!e.V && !e.rt) return;
|
|
5820
6102
|
const t = new NotReadyError(e);
|
|
5821
|
-
t.
|
|
6103
|
+
t.me = true;
|
|
5822
6104
|
const n = new Set;
|
|
5823
6105
|
const visit = e => {
|
|
5824
6106
|
if (n.has(e)) return;
|
|
5825
6107
|
n.add(e);
|
|
5826
6108
|
// Display consumers (render effects, boundary computeds) act on the
|
|
5827
6109
|
// notification; descent stops there, exactly like the status rails.
|
|
5828
|
-
if (e.
|
|
5829
|
-
e.
|
|
6110
|
+
if (e.yt) {
|
|
6111
|
+
e.yt(STATUS_PENDING, t);
|
|
5830
6112
|
return;
|
|
5831
6113
|
}
|
|
5832
6114
|
forEachDependent(e, visit);
|
|
@@ -5847,7 +6129,7 @@ function createStore(e, t, n) {
|
|
|
5847
6129
|
globalQueue.D.L.push(e);
|
|
5848
6130
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5849
6131
|
// without them there is no materialized verdict to poke.
|
|
5850
|
-
GlobalQueue.
|
|
6132
|
+
GlobalQueue.Oe !== null && GlobalQueue.Oe(e);
|
|
5851
6133
|
notifyMarkBoundaries(e);
|
|
5852
6134
|
schedule();
|
|
5853
6135
|
}
|
|
@@ -5861,8 +6143,8 @@ function createStore(e, t, n) {
|
|
|
5861
6143
|
shiftAffectsMarks(-1);
|
|
5862
6144
|
e.k--;
|
|
5863
6145
|
if (!e.k) {
|
|
5864
|
-
GlobalQueue.
|
|
5865
|
-
GlobalQueue.
|
|
6146
|
+
GlobalQueue.Oe !== null && GlobalQueue.Oe(e, true);
|
|
6147
|
+
GlobalQueue.ne?.(e);
|
|
5866
6148
|
}
|
|
5867
6149
|
}
|
|
5868
6150
|
|
|
@@ -5879,11 +6161,11 @@ function createStore(e, t, n) {
|
|
|
5879
6161
|
// Each call site is gated by state only this module creates (a non-empty
|
|
5880
6162
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
5881
6163
|
// hooks are installed before the first time any of them can fire.
|
|
5882
|
-
GlobalQueue.
|
|
6164
|
+
GlobalQueue.re = releaseAffectsMarks;
|
|
5883
6165
|
|
|
5884
|
-
GlobalQueue.
|
|
6166
|
+
GlobalQueue.ie = markAffects;
|
|
5885
6167
|
|
|
5886
|
-
GlobalQueue.
|
|
6168
|
+
GlobalQueue.oe = releaseAffectsMark;
|
|
5887
6169
|
|
|
5888
6170
|
function affects(e, t) {
|
|
5889
6171
|
const n = e?.[$TARGET];
|
|
@@ -5904,7 +6186,26 @@ function createOptimisticStore(e, t, n) {
|
|
|
5904
6186
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
5905
6187
|
// node can be created.
|
|
5906
6188
|
installOptimisticEngine();
|
|
5907
|
-
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
|
+
}
|
|
5908
6209
|
const r = typeof e === "function";
|
|
5909
6210
|
// Plain form: the second slot carries options.
|
|
5910
6211
|
if (!r && n === undefined) n = t;
|
|
@@ -5983,10 +6284,10 @@ function clearOptimisticStores(e, t) {
|
|
|
5983
6284
|
const i = isWrappable(r) ? wrap(r, e) : r;
|
|
5984
6285
|
const o = visibleNodeValue(a);
|
|
5985
6286
|
a.A = NOT_PENDING;
|
|
5986
|
-
a.
|
|
6287
|
+
a.p = null;
|
|
5987
6288
|
a.U = NOT_PENDING;
|
|
5988
|
-
a.
|
|
5989
|
-
if (!a.
|
|
6289
|
+
a.We = i;
|
|
6290
|
+
if (!a.ht || !a.ht(o, i)) {
|
|
5990
6291
|
insertSubs(a, true);
|
|
5991
6292
|
schedule();
|
|
5992
6293
|
}
|
|
@@ -6060,12 +6361,12 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6060
6361
|
r = computed(() => {
|
|
6061
6362
|
setProjectionWriteActive(true);
|
|
6062
6363
|
try {
|
|
6063
|
-
runProjectionComputed(s, e, n?.key
|
|
6364
|
+
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key, wrapCommit, clearProjectionOverride);
|
|
6064
6365
|
} finally {
|
|
6065
6366
|
setProjectionWriteActive(false);
|
|
6066
6367
|
}
|
|
6067
6368
|
}, undefined);
|
|
6068
|
-
r.
|
|
6369
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6069
6370
|
}
|
|
6070
6371
|
return {
|
|
6071
6372
|
store: s,
|
|
@@ -6489,24 +6790,24 @@ function mapArray(e, t, n) {
|
|
|
6489
6790
|
const i = t.length > 1;
|
|
6490
6791
|
const o = t;
|
|
6491
6792
|
const s = {
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6793
|
+
vt: createOwner(),
|
|
6794
|
+
Lt: 0,
|
|
6795
|
+
Gt: e,
|
|
6495
6796
|
Vt: [],
|
|
6496
|
-
|
|
6497
|
-
Ut: [],
|
|
6797
|
+
Ut: o,
|
|
6498
6798
|
kt: [],
|
|
6499
|
-
Wt:
|
|
6500
|
-
Ft: r
|
|
6501
|
-
xt:
|
|
6502
|
-
Qt: n?.keyed
|
|
6503
|
-
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
|
|
6504
6805
|
};
|
|
6505
6806
|
const u = computed(updateKeyedMap.bind(s));
|
|
6506
6807
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6507
6808
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6508
|
-
s.
|
|
6509
|
-
u.
|
|
6809
|
+
s.vt.et = u;
|
|
6810
|
+
u.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6510
6811
|
return accessor(u);
|
|
6511
6812
|
}
|
|
6512
6813
|
|
|
@@ -6524,52 +6825,52 @@ const pureOptions = {
|
|
|
6524
6825
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6525
6826
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6526
6827
|
function updateKeyedMap() {
|
|
6527
|
-
const e = this.
|
|
6828
|
+
const e = this.Gt() || [], t = e.length;
|
|
6528
6829
|
e[$TRACK];
|
|
6529
6830
|
// top level tracking
|
|
6530
|
-
runWithOwner(this.
|
|
6831
|
+
runWithOwner(this.vt, () => {
|
|
6531
6832
|
let n, r, i, o,
|
|
6532
6833
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6533
6834
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6534
|
-
s = this.
|
|
6835
|
+
s = this.xt ? this.Ht ? () => {
|
|
6535
6836
|
i[r] = signal(e[r], pureOptions);
|
|
6536
|
-
return this.
|
|
6837
|
+
return this.Ut(accessor(i[r]), r);
|
|
6537
6838
|
} : () => {
|
|
6538
6839
|
i[r] = signal(e[r], pureOptions);
|
|
6539
6840
|
o && (o[r] = signal(r, pureOptions));
|
|
6540
|
-
return this.
|
|
6541
|
-
} : this.
|
|
6841
|
+
return this.Ut(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6842
|
+
} : this.Qt ? () => {
|
|
6542
6843
|
const t = e[r];
|
|
6543
6844
|
o[r] = signal(r, pureOptions);
|
|
6544
|
-
return this.
|
|
6845
|
+
return this.Ut(t, accessor(o[r]));
|
|
6545
6846
|
} : () => {
|
|
6546
6847
|
const t = e[r];
|
|
6547
|
-
return this.
|
|
6848
|
+
return this.Ut(t);
|
|
6548
6849
|
};
|
|
6549
6850
|
// fast path for empty arrays
|
|
6550
6851
|
if (t === 0) {
|
|
6551
|
-
if (this.
|
|
6552
|
-
this.
|
|
6553
|
-
this.
|
|
6852
|
+
if (this.Lt !== 0) {
|
|
6853
|
+
this.vt.dispose(false);
|
|
6854
|
+
this.Wt = [];
|
|
6554
6855
|
this.Vt = [];
|
|
6555
|
-
this.
|
|
6556
|
-
this.
|
|
6557
|
-
this.Ft && (this.Ft = []);
|
|
6856
|
+
this.kt = [];
|
|
6857
|
+
this.Lt = 0;
|
|
6558
6858
|
this.xt && (this.xt = []);
|
|
6859
|
+
this.Qt && (this.Qt = []);
|
|
6559
6860
|
}
|
|
6560
|
-
if (this.
|
|
6861
|
+
if (this.Mt && !this.kt[0]) {
|
|
6561
6862
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6562
6863
|
// dispose it before re-creating
|
|
6563
|
-
this.
|
|
6564
|
-
this.
|
|
6864
|
+
this.Wt[0]?.dispose();
|
|
6865
|
+
this.kt[0] = runWithOwner(this.Wt[0] = createOwner(), this.Mt);
|
|
6565
6866
|
}
|
|
6566
6867
|
}
|
|
6567
6868
|
// fast path for new create
|
|
6568
|
-
else if (this.
|
|
6869
|
+
else if (this.Lt === 0) {
|
|
6569
6870
|
const u = new Array(t);
|
|
6570
6871
|
const l = new Array(t);
|
|
6571
|
-
i = this.
|
|
6572
|
-
o = this.
|
|
6872
|
+
i = this.xt && new Array(t);
|
|
6873
|
+
o = this.Qt && new Array(t);
|
|
6573
6874
|
try {
|
|
6574
6875
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6575
6876
|
} catch (e) {
|
|
@@ -6577,43 +6878,43 @@ function updateKeyedMap() {
|
|
|
6577
6878
|
throw e;
|
|
6578
6879
|
}
|
|
6579
6880
|
// commit
|
|
6580
|
-
if (this.
|
|
6881
|
+
if (this.Wt[0]) this.Wt[0].dispose();
|
|
6581
6882
|
// previous fallback
|
|
6582
|
-
this.
|
|
6583
|
-
this.
|
|
6584
|
-
i && (this.
|
|
6585
|
-
o && (this.
|
|
6883
|
+
this.kt = u;
|
|
6884
|
+
this.Wt = l;
|
|
6885
|
+
i && (this.xt = i);
|
|
6886
|
+
o && (this.Qt = o);
|
|
6586
6887
|
this.Vt = e.slice(0);
|
|
6587
|
-
this.
|
|
6888
|
+
this.Lt = t;
|
|
6588
6889
|
} else {
|
|
6589
6890
|
let u, l, a, c, f, E, d, S, T;
|
|
6590
6891
|
// skip common prefix
|
|
6591
|
-
for (u = 0, l = Math.min(this.
|
|
6592
|
-
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]);
|
|
6593
6894
|
}
|
|
6594
6895
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6595
6896
|
// at commit instead of being staged and copied twice
|
|
6596
|
-
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--,
|
|
6597
6898
|
a--) ;
|
|
6598
6899
|
// no structural change (every position matched in place at equal
|
|
6599
6900
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6600
6901
|
// array identity so downstream consumers don't re-run at all
|
|
6601
|
-
if (u === t && this.
|
|
6902
|
+
if (u === t && this.Lt === t) {
|
|
6602
6903
|
this.Vt = e.slice(0);
|
|
6603
6904
|
return;
|
|
6604
6905
|
}
|
|
6605
|
-
const O = t - this.
|
|
6906
|
+
const O = t - this.Lt;
|
|
6606
6907
|
const _ = new Array(t);
|
|
6607
|
-
const
|
|
6608
|
-
i = this.
|
|
6609
|
-
o = this.
|
|
6908
|
+
const R = new Array(t);
|
|
6909
|
+
i = this.xt ? new Array(t) : undefined;
|
|
6910
|
+
o = this.Qt ? new Array(t) : undefined;
|
|
6610
6911
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6611
6912
|
// scanning backwards so we encounter them in natural order
|
|
6612
6913
|
E = new Map;
|
|
6613
6914
|
d = new Array(a + 1);
|
|
6614
6915
|
for (r = a; r >= u; r--) {
|
|
6615
6916
|
c = e[r];
|
|
6616
|
-
f = this.
|
|
6917
|
+
f = this.Ft ? this.Ft(c) : c;
|
|
6617
6918
|
n = E.get(f);
|
|
6618
6919
|
d[r] = n === undefined ? -1 : n;
|
|
6619
6920
|
E.set(f, r);
|
|
@@ -6623,23 +6924,23 @@ function updateKeyedMap() {
|
|
|
6623
6924
|
// queue them for disposal at commit
|
|
6624
6925
|
for (n = u; n <= l; n++) {
|
|
6625
6926
|
c = this.Vt[n];
|
|
6626
|
-
f = this.
|
|
6927
|
+
f = this.Ft ? this.Ft(c) : c;
|
|
6627
6928
|
r = E.get(f);
|
|
6628
6929
|
if (r !== undefined && r !== -1) {
|
|
6629
|
-
_[r] = this.
|
|
6630
|
-
|
|
6631
|
-
i && (i[r] = this.
|
|
6632
|
-
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]);
|
|
6633
6934
|
r = d[r];
|
|
6634
6935
|
E.set(f, r);
|
|
6635
|
-
} else (S ??= []).push(this.
|
|
6936
|
+
} else (S ??= []).push(this.Wt[n]);
|
|
6636
6937
|
}
|
|
6637
6938
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6638
6939
|
try {
|
|
6639
6940
|
for (r = u; r <= a; r++) {
|
|
6640
|
-
if (
|
|
6641
|
-
(T ??= []).push(
|
|
6642
|
-
_[r] = runWithOwner(
|
|
6941
|
+
if (R[r] !== undefined) continue;
|
|
6942
|
+
(T ??= []).push(R[r] = createOwner());
|
|
6943
|
+
_[r] = runWithOwner(R[r], s);
|
|
6643
6944
|
}
|
|
6644
6945
|
} catch (e) {
|
|
6645
6946
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
@@ -6649,38 +6950,38 @@ function updateKeyedMap() {
|
|
|
6649
6950
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
6650
6951
|
// change propagation), then dispose exited rows
|
|
6651
6952
|
for (n = 0; n < u; n++) {
|
|
6652
|
-
_[n] = this.
|
|
6653
|
-
|
|
6654
|
-
i && (i[n] = this.
|
|
6655
|
-
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]);
|
|
6656
6957
|
}
|
|
6657
6958
|
for (r = u; r <= a; r++) {
|
|
6658
6959
|
if (i) setSignal(i[r], e[r]);
|
|
6659
6960
|
if (o) setSignal(o[r], r);
|
|
6660
6961
|
}
|
|
6661
6962
|
for (r = a + 1; r < t; r++) {
|
|
6662
|
-
_[r] = this.
|
|
6663
|
-
|
|
6963
|
+
_[r] = this.kt[r - O];
|
|
6964
|
+
R[r] = this.Wt[r - O];
|
|
6664
6965
|
if (i) {
|
|
6665
|
-
i[r] = this.
|
|
6966
|
+
i[r] = this.xt[r - O];
|
|
6666
6967
|
setSignal(i[r], e[r]);
|
|
6667
6968
|
}
|
|
6668
6969
|
if (o) {
|
|
6669
|
-
o[r] = this.
|
|
6970
|
+
o[r] = this.Qt[r - O];
|
|
6670
6971
|
if (O !== 0) setSignal(o[r], r);
|
|
6671
6972
|
}
|
|
6672
6973
|
}
|
|
6673
|
-
this.
|
|
6674
|
-
this.
|
|
6675
|
-
i && (this.
|
|
6676
|
-
o && (this.
|
|
6677
|
-
this.
|
|
6974
|
+
this.kt = _;
|
|
6975
|
+
this.Wt = R;
|
|
6976
|
+
i && (this.xt = i);
|
|
6977
|
+
o && (this.Qt = o);
|
|
6978
|
+
this.Lt = t;
|
|
6678
6979
|
// save a copy of the mapped items for the next update
|
|
6679
6980
|
this.Vt = e.slice(0);
|
|
6680
6981
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6681
6982
|
}
|
|
6682
6983
|
});
|
|
6683
|
-
return this.
|
|
6984
|
+
return this.kt;
|
|
6684
6985
|
}
|
|
6685
6986
|
|
|
6686
6987
|
/**
|
|
@@ -6700,22 +7001,22 @@ function updateKeyedMap() {
|
|
|
6700
7001
|
*/ function repeat(e, t, n) {
|
|
6701
7002
|
const r = t;
|
|
6702
7003
|
const i = {
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
7004
|
+
vt: createOwner(),
|
|
7005
|
+
Lt: 0,
|
|
7006
|
+
$t: 0,
|
|
7007
|
+
jt: e,
|
|
7008
|
+
Ut: r,
|
|
7009
|
+
Wt: [],
|
|
6708
7010
|
kt: [],
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
Ht: n?.fallback
|
|
7011
|
+
Kt: n?.from,
|
|
7012
|
+
Mt: n?.fallback
|
|
6712
7013
|
};
|
|
6713
7014
|
const o = computed(updateRepeat.bind(i));
|
|
6714
7015
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6715
7016
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6716
7017
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6717
|
-
i.
|
|
6718
|
-
o.
|
|
7018
|
+
i.vt.et = o;
|
|
7019
|
+
o.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6719
7020
|
return accessor(o);
|
|
6720
7021
|
}
|
|
6721
7022
|
|
|
@@ -6727,55 +7028,55 @@ function updateKeyedMap() {
|
|
|
6727
7028
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
6728
7029
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
6729
7030
|
function updateRepeat() {
|
|
6730
|
-
const e = this
|
|
6731
|
-
const t = this.
|
|
6732
|
-
runWithOwner(this.
|
|
7031
|
+
const e = this.jt();
|
|
7032
|
+
const t = this.Kt?.() || 0;
|
|
7033
|
+
runWithOwner(this.vt, () => {
|
|
6733
7034
|
if (e === 0) {
|
|
6734
|
-
if (this.
|
|
6735
|
-
this.
|
|
7035
|
+
if (this.Lt !== 0) {
|
|
7036
|
+
this.vt.dispose(false);
|
|
7037
|
+
this.Wt = [];
|
|
6736
7038
|
this.kt = [];
|
|
6737
|
-
this.
|
|
6738
|
-
this.vt = 0;
|
|
7039
|
+
this.Lt = 0;
|
|
6739
7040
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6740
|
-
this
|
|
7041
|
+
this.$t = 0;
|
|
6741
7042
|
}
|
|
6742
|
-
if (this.
|
|
7043
|
+
if (this.Mt && !this.kt[0]) {
|
|
6743
7044
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6744
7045
|
// dispose it before re-creating
|
|
6745
|
-
this.
|
|
6746
|
-
this.
|
|
7046
|
+
this.Wt[0]?.dispose();
|
|
7047
|
+
this.kt[0] = runWithOwner(this.Wt[0] = createOwner(), this.Mt);
|
|
6747
7048
|
}
|
|
6748
7049
|
return;
|
|
6749
7050
|
}
|
|
6750
7051
|
const n = t + e;
|
|
6751
|
-
const r = this
|
|
7052
|
+
const r = this.$t + this.Lt;
|
|
6752
7053
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6753
7054
|
// windows are disjoint or when coming from empty/fallback.
|
|
6754
|
-
const i = Math.max(t, this
|
|
7055
|
+
const i = Math.max(t, this.$t);
|
|
6755
7056
|
const o = Math.min(n, r);
|
|
6756
7057
|
const s = new Array(e);
|
|
6757
7058
|
const u = new Array(e);
|
|
6758
7059
|
for (let e = i; e < o; e++) {
|
|
6759
|
-
u[e - t] = this.
|
|
6760
|
-
s[e - t] = this.
|
|
7060
|
+
u[e - t] = this.Wt[e - this.$t];
|
|
7061
|
+
s[e - t] = this.kt[e - this.$t];
|
|
6761
7062
|
}
|
|
6762
7063
|
try {
|
|
6763
7064
|
for (let e = t; e < n; e++) {
|
|
6764
7065
|
if (e >= i && e < o) continue;
|
|
6765
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
7066
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Ut(e));
|
|
6766
7067
|
}
|
|
6767
7068
|
} catch (e) {
|
|
6768
7069
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6769
7070
|
throw e;
|
|
6770
7071
|
}
|
|
6771
7072
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6772
|
-
if (this.
|
|
6773
|
-
this.
|
|
6774
|
-
this.
|
|
6775
|
-
this
|
|
6776
|
-
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;
|
|
6777
7078
|
});
|
|
6778
|
-
return this.
|
|
7079
|
+
return this.kt;
|
|
6779
7080
|
}
|
|
6780
7081
|
|
|
6781
7082
|
function compare(e, t, n) {
|
|
@@ -6786,23 +7087,23 @@ function boundaryComputed(e, t) {
|
|
|
6786
7087
|
const n = computed(e, {
|
|
6787
7088
|
lazy: true
|
|
6788
7089
|
});
|
|
6789
|
-
n.
|
|
7090
|
+
n.yt = (e, t) => {
|
|
6790
7091
|
// Use passed values if provided, otherwise read from node
|
|
6791
|
-
const r = e !== undefined ? e : n.
|
|
6792
|
-
const i = t !== undefined ? t : n.
|
|
7092
|
+
const r = e !== undefined ? e : n.Qe;
|
|
7093
|
+
const i = t !== undefined ? t : n.we;
|
|
6793
7094
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6794
7095
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6795
7096
|
// a boundary that handles it is found.
|
|
6796
|
-
n.
|
|
6797
|
-
const o = n.
|
|
7097
|
+
n.Qe &= ~n.Yt;
|
|
7098
|
+
const o = n.Ze.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6798
7099
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6799
7100
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
6800
7101
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
6801
7102
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6802
|
-
const s = r & ~n.
|
|
7103
|
+
const s = r & ~n.Yt & (STATUS_PENDING | STATUS_ERROR);
|
|
6803
7104
|
if (s) {
|
|
6804
|
-
n.
|
|
6805
|
-
if (n.
|
|
7105
|
+
n.Qe &= ~s;
|
|
7106
|
+
if (n.we === i && !(n.Qe & (STATUS_PENDING | STATUS_ERROR))) n.we = undefined;
|
|
6806
7107
|
}
|
|
6807
7108
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6808
7109
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6813,16 +7114,16 @@ function boundaryComputed(e, t) {
|
|
|
6813
7114
|
throw i;
|
|
6814
7115
|
}
|
|
6815
7116
|
};
|
|
6816
|
-
n.
|
|
6817
|
-
n.
|
|
7117
|
+
n.Yt = t;
|
|
7118
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6818
7119
|
recompute(n, true);
|
|
6819
7120
|
return n;
|
|
6820
7121
|
}
|
|
6821
7122
|
|
|
6822
7123
|
function createBoundChildren(e, t, n, r) {
|
|
6823
|
-
const i = e.
|
|
6824
|
-
i.addChild(e.
|
|
6825
|
-
cleanup(() => i.removeChild(e.
|
|
7124
|
+
const i = e.Ze;
|
|
7125
|
+
i.addChild(e.Ze = n);
|
|
7126
|
+
cleanup(() => i.removeChild(e.Ze));
|
|
6826
7127
|
return runWithOwner(e, () => {
|
|
6827
7128
|
const e = computed(t);
|
|
6828
7129
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -6844,53 +7145,53 @@ function isRevealController(e) {
|
|
|
6844
7145
|
}
|
|
6845
7146
|
|
|
6846
7147
|
function isSlotReady(e) {
|
|
6847
|
-
return isRevealController(e) ? e.
|
|
7148
|
+
return isRevealController(e) ? e.qt() : e.Bt.size === 0 && !e.Zt;
|
|
6848
7149
|
}
|
|
6849
7150
|
|
|
6850
7151
|
function isSlotMinimallyReady(e) {
|
|
6851
|
-
return isRevealController(e) ? e.
|
|
7152
|
+
return isRevealController(e) ? e.Xt() : isSlotReady(e);
|
|
6852
7153
|
}
|
|
6853
7154
|
|
|
6854
7155
|
function setSlotState(e, t, n, r) {
|
|
6855
|
-
setSignal(e.
|
|
6856
|
-
setSignal(e.
|
|
7156
|
+
setSignal(e.zt, n);
|
|
7157
|
+
setSignal(e.Jt, r);
|
|
6857
7158
|
if (isRevealController(e)) {
|
|
6858
|
-
if (!n && e.
|
|
6859
|
-
return e.
|
|
7159
|
+
if (!n && e.en === t) e.en = undefined;
|
|
7160
|
+
return e.tn(n, r);
|
|
6860
7161
|
}
|
|
6861
|
-
if (!n && e.
|
|
7162
|
+
if (!n && e.nn === t && e.rn) e.nn = undefined;
|
|
6862
7163
|
}
|
|
6863
7164
|
|
|
6864
7165
|
class RevealController {
|
|
6865
|
-
rn;
|
|
6866
7166
|
sn;
|
|
6867
|
-
un
|
|
6868
|
-
|
|
6869
|
-
|
|
7167
|
+
un;
|
|
7168
|
+
ln=[];
|
|
7169
|
+
en;
|
|
7170
|
+
zt=signal(false, {
|
|
6870
7171
|
ownedWrite: true,
|
|
6871
|
-
|
|
7172
|
+
gt: true
|
|
6872
7173
|
});
|
|
6873
|
-
|
|
7174
|
+
Jt=signal(false, {
|
|
6874
7175
|
ownedWrite: true,
|
|
6875
|
-
|
|
7176
|
+
gt: true
|
|
6876
7177
|
});
|
|
6877
|
-
ln=true;
|
|
6878
7178
|
an=true;
|
|
6879
|
-
cn=
|
|
7179
|
+
cn=true;
|
|
7180
|
+
fn=false;
|
|
6880
7181
|
constructor(e, t) {
|
|
6881
|
-
this.
|
|
6882
|
-
this.
|
|
7182
|
+
this.sn = e;
|
|
7183
|
+
this.un = t;
|
|
6883
7184
|
}
|
|
6884
|
-
|
|
6885
|
-
for (let t = 0; t < this.
|
|
6886
|
-
const n = this.
|
|
6887
|
-
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;
|
|
6888
7189
|
if (e(n) === false) return false;
|
|
6889
7190
|
}
|
|
6890
7191
|
return true;
|
|
6891
7192
|
}
|
|
6892
|
-
|
|
6893
|
-
return this.
|
|
7193
|
+
qt() {
|
|
7194
|
+
return this.En(isSlotReady);
|
|
6894
7195
|
}
|
|
6895
7196
|
/**
|
|
6896
7197
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -6898,13 +7199,13 @@ class RevealController {
|
|
|
6898
7199
|
* - `together`: every direct slot is minimally ready.
|
|
6899
7200
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
6900
7201
|
* - `natural`: any owned slot is minimally ready.
|
|
6901
|
-
*/
|
|
6902
|
-
const e = untrack(this.
|
|
6903
|
-
if (e === "together") return this.
|
|
7202
|
+
*/ Xt() {
|
|
7203
|
+
const e = untrack(this.sn);
|
|
7204
|
+
if (e === "together") return this.En(isSlotMinimallyReady);
|
|
6904
7205
|
if (e === "natural") {
|
|
6905
7206
|
let e = false;
|
|
6906
7207
|
let t = false;
|
|
6907
|
-
this.
|
|
7208
|
+
this.En(n => {
|
|
6908
7209
|
e = true;
|
|
6909
7210
|
if (isSlotMinimallyReady(n)) {
|
|
6910
7211
|
t = true;
|
|
@@ -6915,45 +7216,45 @@ class RevealController {
|
|
|
6915
7216
|
}
|
|
6916
7217
|
// sequential: only the first owned slot matters.
|
|
6917
7218
|
let t = true;
|
|
6918
|
-
this.
|
|
7219
|
+
this.En(e => {
|
|
6919
7220
|
t = isSlotMinimallyReady(e);
|
|
6920
7221
|
return false;
|
|
6921
7222
|
});
|
|
6922
7223
|
return t;
|
|
6923
7224
|
}
|
|
6924
|
-
En(e) {
|
|
6925
|
-
if (this.un.includes(e)) return;
|
|
6926
|
-
this.un.push(e);
|
|
6927
|
-
const t = untrack(this.rn);
|
|
6928
|
-
setSignal(e.Xt, true), setSignal(e.zt, t === "sequential" ? !!untrack(this.sn) : false);
|
|
6929
|
-
untrack(() => this.en());
|
|
6930
|
-
}
|
|
6931
7225
|
dn(e) {
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
untrack(
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
const
|
|
6940
|
-
|
|
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;
|
|
6941
7242
|
try {
|
|
6942
|
-
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;
|
|
6943
7244
|
if (n) {
|
|
6944
7245
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
6945
7246
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
6946
7247
|
// held; it resumes once the outer releases us.
|
|
6947
|
-
this.
|
|
7248
|
+
this.En(e => setSlotState(e, this, true, o));
|
|
6948
7249
|
} else if (r === "natural") {
|
|
6949
7250
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
6950
7251
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
6951
7252
|
// so the parent backpointer survives for upward readiness notifications.
|
|
6952
|
-
this.
|
|
7253
|
+
this.En(e => {
|
|
6953
7254
|
if (isRevealController(e)) {
|
|
7255
|
+
setSignal(e.Jt, false);
|
|
6954
7256
|
setSignal(e.zt, false);
|
|
6955
|
-
|
|
6956
|
-
e.en(false, false);
|
|
7257
|
+
e.tn(false, false);
|
|
6957
7258
|
} else {
|
|
6958
7259
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
6959
7260
|
}
|
|
@@ -6964,11 +7265,11 @@ class RevealController {
|
|
|
6964
7265
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
6965
7266
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
6966
7267
|
// cohesive reveal without waiting for every grandchild.
|
|
6967
|
-
const e = this.
|
|
6968
|
-
this.
|
|
7268
|
+
const e = this.En(isSlotMinimallyReady);
|
|
7269
|
+
this.En(t => setSlotState(t, this, !e, false));
|
|
6969
7270
|
} else {
|
|
6970
7271
|
let e = false;
|
|
6971
|
-
this.
|
|
7272
|
+
this.En(t => {
|
|
6972
7273
|
if (e) return setSlotState(t, this, true, i);
|
|
6973
7274
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
6974
7275
|
e = true;
|
|
@@ -6979,63 +7280,63 @@ class RevealController {
|
|
|
6979
7280
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
6980
7281
|
// backpointer survives for upward readiness notifications.
|
|
6981
7282
|
if (isRevealController(t)) {
|
|
7283
|
+
setSignal(t.Jt, false);
|
|
6982
7284
|
setSignal(t.zt, false);
|
|
6983
|
-
|
|
6984
|
-
t.en(false, false);
|
|
7285
|
+
t.tn(false, false);
|
|
6985
7286
|
} else {
|
|
6986
7287
|
setSlotState(t, this, true, false);
|
|
6987
7288
|
}
|
|
6988
7289
|
});
|
|
6989
7290
|
}
|
|
6990
7291
|
} finally {
|
|
6991
|
-
this.
|
|
6992
|
-
this.
|
|
6993
|
-
this.
|
|
7292
|
+
this.an = this.qt();
|
|
7293
|
+
this.cn = this.Xt();
|
|
7294
|
+
this.fn = false;
|
|
6994
7295
|
}
|
|
6995
|
-
if (this.
|
|
7296
|
+
if (this.en && (n !== this.an || r !== this.cn)) this.en.tn();
|
|
6996
7297
|
}
|
|
6997
7298
|
}
|
|
6998
7299
|
|
|
6999
7300
|
class CollectionQueue extends Queue {
|
|
7000
|
-
Sn;
|
|
7001
|
-
qt=new Set;
|
|
7002
7301
|
Tn;
|
|
7003
|
-
Bt=
|
|
7004
|
-
|
|
7302
|
+
Bt=new Set;
|
|
7303
|
+
On;
|
|
7304
|
+
Zt=true;
|
|
7305
|
+
zt=signal(false, {
|
|
7005
7306
|
ownedWrite: true,
|
|
7006
|
-
|
|
7307
|
+
gt: true
|
|
7007
7308
|
});
|
|
7008
|
-
|
|
7009
|
-
|
|
7309
|
+
we;
|
|
7310
|
+
Jt=signal(false, {
|
|
7010
7311
|
ownedWrite: true,
|
|
7011
|
-
|
|
7312
|
+
gt: true
|
|
7012
7313
|
});
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7314
|
+
nn;
|
|
7315
|
+
rn=false;
|
|
7316
|
+
_n;
|
|
7317
|
+
Rn=ON_INIT;
|
|
7017
7318
|
constructor(e) {
|
|
7018
7319
|
super();
|
|
7019
|
-
this.
|
|
7320
|
+
this.Tn = e;
|
|
7020
7321
|
}
|
|
7021
7322
|
run(e) {
|
|
7022
|
-
if (!e || read(this.
|
|
7323
|
+
if (!e || read(this.zt) && (!_revealUsed || read(this.Jt))) return;
|
|
7023
7324
|
return super.run(e);
|
|
7024
7325
|
}
|
|
7025
7326
|
notify(e, t, n, r) {
|
|
7026
|
-
if (!(t & this.
|
|
7027
|
-
if (this.
|
|
7327
|
+
if (!(t & this.Tn)) return super.notify(e, t, n, r);
|
|
7328
|
+
if (this.rn && this._n) {
|
|
7028
7329
|
const e = untrack(() => {
|
|
7029
7330
|
try {
|
|
7030
|
-
return this.
|
|
7331
|
+
return this._n();
|
|
7031
7332
|
} catch {
|
|
7032
7333
|
return ON_INIT;
|
|
7033
7334
|
}
|
|
7034
7335
|
});
|
|
7035
|
-
if (e !== this.
|
|
7036
|
-
this.
|
|
7037
|
-
this.
|
|
7038
|
-
this.
|
|
7336
|
+
if (e !== this.Rn) {
|
|
7337
|
+
this.Rn = e;
|
|
7338
|
+
this.rn = false;
|
|
7339
|
+
this.Bt.clear();
|
|
7039
7340
|
}
|
|
7040
7341
|
}
|
|
7041
7342
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -7048,47 +7349,47 @@ class CollectionQueue extends Queue {
|
|
|
7048
7349
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
7049
7350
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
7050
7351
|
// (the Loading > Errored > content composition escape, #2856).
|
|
7051
|
-
if (this.
|
|
7052
|
-
if (n & this.
|
|
7053
|
-
this.
|
|
7054
|
-
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;
|
|
7055
7356
|
if (t) {
|
|
7056
|
-
const e = this.
|
|
7057
|
-
this.
|
|
7058
|
-
if (e) setSignal(this.
|
|
7059
|
-
if (this.
|
|
7060
|
-
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));
|
|
7061
7362
|
}
|
|
7062
7363
|
}
|
|
7063
7364
|
}
|
|
7064
|
-
t &= ~this.
|
|
7365
|
+
t &= ~this.Tn;
|
|
7065
7366
|
return t ? super.notify(e, t, n, r) : true;
|
|
7066
7367
|
}
|
|
7067
|
-
|
|
7068
|
-
for (const e of this.
|
|
7368
|
+
$e() {
|
|
7369
|
+
for (const e of this.Bt) {
|
|
7069
7370
|
// A source with a live affects() mark holds display state for the
|
|
7070
7371
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7071
7372
|
// status of its own, so the count is the liveness test. The release
|
|
7072
7373
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7073
|
-
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);
|
|
7074
7375
|
}
|
|
7075
|
-
if (!this.
|
|
7076
|
-
if (this.
|
|
7077
|
-
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);
|
|
7078
7379
|
} else {
|
|
7079
|
-
this.
|
|
7380
|
+
this.Zt = false;
|
|
7080
7381
|
}
|
|
7081
|
-
if (!this.
|
|
7082
|
-
setSignal(this.
|
|
7083
|
-
if (this.
|
|
7382
|
+
if (!this.Zt) {
|
|
7383
|
+
setSignal(this.zt, false);
|
|
7384
|
+
if (this._n) {
|
|
7084
7385
|
try {
|
|
7085
|
-
this.
|
|
7386
|
+
this.Rn = untrack(() => this._n());
|
|
7086
7387
|
} catch {
|
|
7087
7388
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
7088
7389
|
}
|
|
7089
7390
|
}
|
|
7090
7391
|
}
|
|
7091
|
-
if (_revealUsed) this.tn
|
|
7392
|
+
if (_revealUsed) this.nn?.tn();
|
|
7092
7393
|
}
|
|
7093
7394
|
}
|
|
7094
7395
|
|
|
@@ -7096,12 +7397,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7096
7397
|
const i = createOwner();
|
|
7097
7398
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
7098
7399
|
const o = new CollectionQueue(e);
|
|
7099
|
-
if (e === STATUS_ERROR) o.
|
|
7400
|
+
if (e === STATUS_ERROR) o.we = signal(undefined, {
|
|
7100
7401
|
ownedWrite: true,
|
|
7101
|
-
|
|
7402
|
+
gt: true
|
|
7102
7403
|
});
|
|
7103
|
-
if (r) o.
|
|
7104
|
-
const s = o.
|
|
7404
|
+
if (r) o._n = r;
|
|
7405
|
+
const s = o.On = createBoundChildren(i, t, o, e);
|
|
7105
7406
|
// Prime source tracking so reveal registration sees pending sources.
|
|
7106
7407
|
untrack(() => {
|
|
7107
7408
|
let t = false;
|
|
@@ -7110,23 +7411,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7110
7411
|
} catch (e) {
|
|
7111
7412
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7112
7413
|
}
|
|
7113
|
-
o.
|
|
7414
|
+
o.Zt = t || !!(s.Qe & e) || s.we instanceof NotReadyError;
|
|
7114
7415
|
});
|
|
7115
7416
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7116
7417
|
if (u) {
|
|
7117
|
-
o.
|
|
7118
|
-
u.
|
|
7119
|
-
cleanup(() => u.
|
|
7418
|
+
o.nn = u;
|
|
7419
|
+
u.dn(o);
|
|
7420
|
+
cleanup(() => u.Sn(o));
|
|
7120
7421
|
}
|
|
7121
7422
|
return accessor(computed(() => {
|
|
7122
|
-
if (!read(o.
|
|
7423
|
+
if (!read(o.zt)) {
|
|
7123
7424
|
const e = read(s);
|
|
7124
|
-
if (!untrack(() => read(o.
|
|
7425
|
+
if (!untrack(() => read(o.zt))) return o.rn = true, e;
|
|
7125
7426
|
}
|
|
7126
7427
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
7127
7428
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
7128
7429
|
// outside a `createRevealOrder` scope.
|
|
7129
|
-
if (_revealUsed && read(o.
|
|
7430
|
+
if (_revealUsed && read(o.Jt)) return undefined;
|
|
7130
7431
|
return n(o);
|
|
7131
7432
|
},
|
|
7132
7433
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -7134,7 +7435,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7134
7435
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
7135
7436
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
7136
7437
|
{
|
|
7137
|
-
|
|
7438
|
+
gt: true
|
|
7138
7439
|
}));
|
|
7139
7440
|
}
|
|
7140
7441
|
|
|
@@ -7187,8 +7488,8 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7187
7488
|
* }
|
|
7188
7489
|
* ```
|
|
7189
7490
|
*/ function createErrorBoundary(e, t) {
|
|
7190
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
7191
|
-
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);
|
|
7192
7493
|
schedule();
|
|
7193
7494
|
}));
|
|
7194
7495
|
}
|
|
@@ -7245,12 +7546,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7245
7546
|
computed(() => {
|
|
7246
7547
|
i();
|
|
7247
7548
|
o();
|
|
7248
|
-
s.
|
|
7549
|
+
s.tn();
|
|
7249
7550
|
});
|
|
7250
7551
|
if (r) {
|
|
7251
|
-
s.
|
|
7252
|
-
r.
|
|
7253
|
-
cleanup(() => r.
|
|
7552
|
+
s.en = r;
|
|
7553
|
+
r.dn(s);
|
|
7554
|
+
cleanup(() => r.Sn(s));
|
|
7254
7555
|
}
|
|
7255
7556
|
return t;
|
|
7256
7557
|
});
|