@solidjs/signals 2.0.0-beta.29 → 2.0.0-beta.31
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 +54 -8
- package/dist/node.cjs +526 -485
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/optimistic.js +17 -5
- package/dist/prod/core/scheduler.js +60 -31
- package/dist/prod/core/verdict.js +1 -1
- package/dist/prod/map.js +56 -56
- package/dist/prod/store/optimistic.js +2 -2
- package/dist/prod/store/store.js +2 -2
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -350,6 +350,15 @@ const zombieQueue = {
|
|
|
350
350
|
C: 0
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
+
/** runHeap callback that discards a queued zombie recompute instead of running
|
|
354
|
+
* it: unlink pure recompute entries; strip just the recompute bit from dirtied
|
|
355
|
+
* height-adjust entries so their height work still happens. */ function cancelZombieRecompute(e) {
|
|
356
|
+
if (e.D & REACTIVE_IN_HEAP_HEIGHT) e.D &= -12; else {
|
|
357
|
+
deleteFromHeap(e, zombieQueue);
|
|
358
|
+
e.D &= -4;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
353
362
|
let clock = 0;
|
|
354
363
|
|
|
355
364
|
let activeTransition = null;
|
|
@@ -375,25 +384,25 @@ function registerTransientStoreNode(e) {
|
|
|
375
384
|
}
|
|
376
385
|
|
|
377
386
|
function canUseSimpleSyncFlush(e) {
|
|
378
|
-
const t = e.
|
|
379
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.
|
|
387
|
+
const t = e.m;
|
|
388
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.v.length === 0 && t.L.length === 0 && t.G.length === 0 && t.V.size === 0 && transientStoreNodes.size === 0;
|
|
380
389
|
}
|
|
381
390
|
|
|
382
391
|
function sweepTransientStoreNodes() {
|
|
383
392
|
if (transientStoreNodes.size === 0) return;
|
|
384
393
|
for (const e of transientStoreNodes) {
|
|
385
|
-
if (e.
|
|
394
|
+
if (e.U !== null) {
|
|
386
395
|
transientStoreNodes.delete(e);
|
|
387
396
|
continue;
|
|
388
397
|
}
|
|
389
|
-
if (e.
|
|
398
|
+
if (e.k !== NOT_PENDING) continue;
|
|
390
399
|
if (e.A !== undefined && e.A !== NOT_PENDING) continue;
|
|
391
400
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
392
401
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
393
402
|
// unmarked node for the same property).
|
|
394
|
-
if (e.
|
|
403
|
+
if (e.W) continue;
|
|
395
404
|
transientStoreNodes.delete(e);
|
|
396
|
-
e.
|
|
405
|
+
e.F?.();
|
|
397
406
|
}
|
|
398
407
|
}
|
|
399
408
|
|
|
@@ -420,47 +429,47 @@ function setProjectionWriteActive(e) {
|
|
|
420
429
|
* land there directly — no per-field aliasing.
|
|
421
430
|
*/ function createBatch() {
|
|
422
431
|
return {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
v: [],
|
|
432
|
+
H: clock,
|
|
433
|
+
M: [],
|
|
434
|
+
$: new Map,
|
|
427
435
|
L: [],
|
|
428
|
-
G:
|
|
429
|
-
|
|
430
|
-
j:
|
|
431
|
-
|
|
432
|
-
|
|
436
|
+
G: [],
|
|
437
|
+
V: new Set,
|
|
438
|
+
j: [],
|
|
439
|
+
K: {
|
|
440
|
+
Y: [ [], [] ],
|
|
441
|
+
v: []
|
|
433
442
|
},
|
|
434
443
|
I: false,
|
|
435
|
-
|
|
444
|
+
q: new Set
|
|
436
445
|
};
|
|
437
446
|
}
|
|
438
447
|
|
|
439
448
|
function mergeTransitionState(e, t) {
|
|
440
449
|
t.I = e;
|
|
441
|
-
e
|
|
450
|
+
e.j.push(...t.j);
|
|
442
451
|
for (const n of activeLanes) if (n.T === t) n.T = e;
|
|
443
|
-
if (t.
|
|
452
|
+
if (t.L.length) {
|
|
444
453
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
445
454
|
// transition, and the adoption pass in initTransition would re-push its
|
|
446
455
|
// contents into the target — duplicating every entry.
|
|
447
|
-
e.
|
|
448
|
-
t.
|
|
456
|
+
e.L.push(...t.L);
|
|
457
|
+
t.L.length = 0;
|
|
449
458
|
}
|
|
450
|
-
if (t.
|
|
459
|
+
if (t.G.length) {
|
|
451
460
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
452
461
|
// transition, and the adoption pass in initTransition would re-push its
|
|
453
462
|
// contents into the target — double-releasing every mark.
|
|
454
|
-
e.
|
|
455
|
-
t.
|
|
463
|
+
e.G.push(...t.G);
|
|
464
|
+
t.G.length = 0;
|
|
456
465
|
}
|
|
457
|
-
for (const n of t.
|
|
458
|
-
for (const [n, r] of t
|
|
459
|
-
let t = e
|
|
460
|
-
if (!t) e
|
|
466
|
+
for (const n of t.V) e.V.add(n);
|
|
467
|
+
for (const [n, r] of t.$) {
|
|
468
|
+
let t = e.$.get(n);
|
|
469
|
+
if (!t) e.$.set(n, t = new Set);
|
|
461
470
|
for (const e of r) t.add(e);
|
|
462
471
|
}
|
|
463
|
-
for (const n of t.
|
|
472
|
+
for (const n of t.q) e.q.add(n);
|
|
464
473
|
}
|
|
465
474
|
|
|
466
475
|
function schedule() {
|
|
@@ -470,7 +479,7 @@ function schedule() {
|
|
|
470
479
|
}
|
|
471
480
|
if (scheduled) return;
|
|
472
481
|
scheduled = true;
|
|
473
|
-
if (!syncDepth && !globalQueue.
|
|
482
|
+
if (!syncDepth && !globalQueue.B && !projectionWriteActive) queueMicrotask(flush);
|
|
474
483
|
}
|
|
475
484
|
|
|
476
485
|
/**
|
|
@@ -504,30 +513,30 @@ function notifyHalted() {
|
|
|
504
513
|
let queueRunToken = 0;
|
|
505
514
|
|
|
506
515
|
class Queue {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
516
|
+
Z=null;
|
|
517
|
+
Y=[ [], [] ];
|
|
518
|
+
v=[];
|
|
519
|
+
X=0;
|
|
511
520
|
created=clock;
|
|
512
521
|
addChild(e) {
|
|
513
|
-
this.
|
|
514
|
-
e.
|
|
522
|
+
this.v.push(e);
|
|
523
|
+
e.Z = this;
|
|
515
524
|
}
|
|
516
525
|
removeChild(e) {
|
|
517
|
-
const t = this.
|
|
526
|
+
const t = this.v.indexOf(e);
|
|
518
527
|
if (t >= 0) {
|
|
519
|
-
this.
|
|
520
|
-
e.
|
|
528
|
+
this.v.splice(t, 1);
|
|
529
|
+
e.Z = null;
|
|
521
530
|
}
|
|
522
531
|
}
|
|
523
532
|
notify(e, t, n, r) {
|
|
524
|
-
if (this.
|
|
533
|
+
if (this.Z) return this.Z.notify(e, t, n, r);
|
|
525
534
|
return false;
|
|
526
535
|
}
|
|
527
536
|
run(e) {
|
|
528
|
-
if (this.
|
|
529
|
-
const t = this.
|
|
530
|
-
this.
|
|
537
|
+
if (this.Y[e - 1].length) {
|
|
538
|
+
const t = this.Y[e - 1];
|
|
539
|
+
this.Y[e - 1] = [];
|
|
531
540
|
runQueue$1(t, e);
|
|
532
541
|
}
|
|
533
542
|
// Effects run here can dispose owners, and disposal removes queues from
|
|
@@ -537,12 +546,12 @@ class Queue {
|
|
|
537
546
|
// can be recovered by rescanning from the front and every child still runs
|
|
538
547
|
// exactly once. Children appended mid-pass carry a stale stamp and run,
|
|
539
548
|
// matching the previous live-array behaviour.
|
|
540
|
-
const t = this.
|
|
549
|
+
const t = this.v;
|
|
541
550
|
const n = ++queueRunToken;
|
|
542
551
|
for (let r = 0; r < t.length; ) {
|
|
543
552
|
const i = t[r];
|
|
544
|
-
if (i.
|
|
545
|
-
i.
|
|
553
|
+
if (i.X !== n) {
|
|
554
|
+
i.X = n;
|
|
546
555
|
i.run?.(e);
|
|
547
556
|
if (t[r] !== i) {
|
|
548
557
|
r = 0;
|
|
@@ -559,70 +568,69 @@ class Queue {
|
|
|
559
568
|
const n = findLane(currentOptimisticLane);
|
|
560
569
|
n.l[e - 1].push(t);
|
|
561
570
|
} else {
|
|
562
|
-
this.
|
|
571
|
+
this.Y[e - 1].push(t);
|
|
563
572
|
}
|
|
564
573
|
}
|
|
565
574
|
schedule();
|
|
566
575
|
}
|
|
567
576
|
stashQueues(e) {
|
|
568
|
-
e.
|
|
569
|
-
e.
|
|
570
|
-
this.
|
|
571
|
-
for (let t = 0; t < this.
|
|
572
|
-
let n = this.
|
|
573
|
-
let r = e.
|
|
577
|
+
e.Y[0].push(...this.Y[0]);
|
|
578
|
+
e.Y[1].push(...this.Y[1]);
|
|
579
|
+
this.Y = [ [], [] ];
|
|
580
|
+
for (let t = 0; t < this.v.length; t++) {
|
|
581
|
+
let n = this.v[t];
|
|
582
|
+
let r = e.v[t];
|
|
574
583
|
if (!r) {
|
|
575
584
|
r = {
|
|
576
|
-
|
|
577
|
-
|
|
585
|
+
Y: [ [], [] ],
|
|
586
|
+
v: []
|
|
578
587
|
};
|
|
579
|
-
e.
|
|
588
|
+
e.v[t] = r;
|
|
580
589
|
}
|
|
581
590
|
n.stashQueues(r);
|
|
582
591
|
}
|
|
583
592
|
}
|
|
584
593
|
restoreQueues(e) {
|
|
585
|
-
this.
|
|
586
|
-
this.
|
|
587
|
-
for (let t = 0; t < e.
|
|
588
|
-
const n = e.
|
|
589
|
-
let r = this.
|
|
594
|
+
this.Y[0].push(...e.Y[0]);
|
|
595
|
+
this.Y[1].push(...e.Y[1]);
|
|
596
|
+
for (let t = 0; t < e.v.length; t++) {
|
|
597
|
+
const n = e.v[t];
|
|
598
|
+
let r = this.v[t];
|
|
590
599
|
if (r) r.restoreQueues(n);
|
|
591
600
|
}
|
|
592
601
|
}
|
|
593
602
|
}
|
|
594
603
|
|
|
595
604
|
class GlobalQueue extends Queue {
|
|
596
|
-
|
|
605
|
+
B=false;
|
|
597
606
|
// The current transaction-shaped batch: a plain ambient batch while no
|
|
598
607
|
// transition is active, the active transition itself after initTransition.
|
|
599
|
-
|
|
600
|
-
static X;
|
|
608
|
+
m=createBatch();
|
|
601
609
|
static J;
|
|
602
610
|
static ee;
|
|
603
|
-
static te
|
|
611
|
+
static te;
|
|
612
|
+
static ne=null;
|
|
604
613
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
605
614
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
606
615
|
// _clearOptimisticStore).
|
|
607
|
-
static
|
|
616
|
+
static re=null;
|
|
608
617
|
// affects()-side hooks (wired by affects.ts, mirroring _update): the mark
|
|
609
618
|
// engine — count/register/release — lives with the feature. Every call site
|
|
610
619
|
// is gated by state only that module creates, so `!` invocations are safe
|
|
611
620
|
// once the gate holds.
|
|
612
|
-
static re=null;
|
|
613
621
|
static ie=null;
|
|
614
622
|
static oe=null;
|
|
623
|
+
static se=null;
|
|
615
624
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
616
625
|
// config is active — including after _resetExternalSourceConfig()).
|
|
617
|
-
static se=null;
|
|
618
626
|
static ue=null;
|
|
627
|
+
static le=null;
|
|
619
628
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
620
629
|
// imported; null in apps that never use them). Call sites either guard for
|
|
621
630
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
622
631
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
623
632
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
624
633
|
// isPending()/latest()).
|
|
625
|
-
static le=null;
|
|
626
634
|
static ae=null;
|
|
627
635
|
static ce=null;
|
|
628
636
|
static fe=null;
|
|
@@ -632,6 +640,7 @@ class GlobalQueue extends Queue {
|
|
|
632
640
|
static Te=null;
|
|
633
641
|
static Oe=null;
|
|
634
642
|
static _e=null;
|
|
643
|
+
static Re=null;
|
|
635
644
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
636
645
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
637
646
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -639,7 +648,6 @@ class GlobalQueue extends Queue {
|
|
|
639
648
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
640
649
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
641
650
|
// once the gate holds.
|
|
642
|
-
static Re=null;
|
|
643
651
|
static pe=null;
|
|
644
652
|
static Ie=null;
|
|
645
653
|
static Ae=null;
|
|
@@ -651,68 +659,77 @@ class GlobalQueue extends Queue {
|
|
|
651
659
|
static ge=null;
|
|
652
660
|
static be=null;
|
|
653
661
|
static De=null;
|
|
662
|
+
static we=null;
|
|
654
663
|
flush() {
|
|
655
|
-
if (this.
|
|
656
|
-
this.
|
|
664
|
+
if (this.B) return;
|
|
665
|
+
this.B = true;
|
|
657
666
|
try {
|
|
658
667
|
if (false) ;
|
|
659
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
668
|
+
runHeap(dirtyQueue, GlobalQueue.J);
|
|
660
669
|
if (activeTransition) {
|
|
661
670
|
const e = transitionComplete(activeTransition);
|
|
662
671
|
if (!e) {
|
|
663
672
|
const e = activeTransition;
|
|
664
|
-
|
|
673
|
+
// When the parking batch IS the transition, all of its writes commit
|
|
674
|
+
// only with it — every zombie recompute they queued would run against
|
|
675
|
+
// a world the zombie never displays (zombies render mainline until
|
|
676
|
+
// commit), so cancel them instead of running them. Only an ambient
|
|
677
|
+
// batch's mainline writes (the #2916 shape below) legitimately reach
|
|
678
|
+
// zombies here. Height-adjust entries still process normally: a
|
|
679
|
+
// dirtied one keeps its height flag and falls through to runHeap's
|
|
680
|
+
// adjustHeight path on the next pass of the bucket.
|
|
681
|
+
runHeap(zombieQueue, this.m === e ? cancelZombieRecompute : GlobalQueue.J);
|
|
665
682
|
// Detach: the stashed transition keeps its batch; ambient work that
|
|
666
683
|
// follows lands in a fresh one. If the batch is already a separate
|
|
667
684
|
// ambient one — action done() restored activeTransition without
|
|
668
685
|
// adopting the batch, and an ordinary write landed there before
|
|
669
686
|
// the scheduled flush (#2916) — keep it: replacing it would strand
|
|
670
687
|
// its queued pending nodes with held _pendingValues forever.
|
|
671
|
-
if (this.
|
|
688
|
+
if (this.m === e) currentBatch = this.m = createBatch();
|
|
672
689
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
673
690
|
if (activeLanes.size) {
|
|
674
|
-
GlobalQueue.
|
|
675
|
-
GlobalQueue.
|
|
691
|
+
GlobalQueue.Ne(EFFECT_RENDER);
|
|
692
|
+
GlobalQueue.Ne(EFFECT_USER);
|
|
676
693
|
}
|
|
677
|
-
this.stashQueues(e.
|
|
694
|
+
this.stashQueues(e.K);
|
|
678
695
|
clock++;
|
|
679
696
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
680
697
|
// scheduled so the outer drain loop commits them via the plain
|
|
681
698
|
// flush path instead of leaving them until the next natural flush.
|
|
682
|
-
scheduled = dirtyQueue.C >= dirtyQueue.P || this.
|
|
683
|
-
reassignPendingTransition(e.
|
|
699
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P || this.m.M.length > 0;
|
|
700
|
+
reassignPendingTransition(e.M);
|
|
684
701
|
activeTransition = null;
|
|
685
702
|
finalizePureQueue(null, true);
|
|
686
703
|
return;
|
|
687
704
|
}
|
|
688
705
|
const t = activeTransition;
|
|
689
|
-
const n = this.
|
|
690
|
-
n !== t && n.
|
|
691
|
-
this.restoreQueues(t.
|
|
706
|
+
const n = this.m;
|
|
707
|
+
n !== t && n.M.push(...t.M);
|
|
708
|
+
this.restoreQueues(t.K);
|
|
692
709
|
transitions.delete(t);
|
|
693
710
|
activeTransition = null;
|
|
694
|
-
reassignPendingTransition(n.
|
|
711
|
+
reassignPendingTransition(n.M);
|
|
695
712
|
finalizePureQueue(t);
|
|
696
713
|
if (n === t) {
|
|
697
714
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
698
715
|
// as the ambient batch — late registrations during finalization live
|
|
699
716
|
// there and must survive to the next flush.
|
|
700
717
|
const e = createBatch();
|
|
701
|
-
e.
|
|
702
|
-
e.v = n.v;
|
|
718
|
+
e.M = n.M;
|
|
703
719
|
e.L = n.L;
|
|
704
720
|
e.G = n.G;
|
|
705
|
-
|
|
721
|
+
e.V = n.V;
|
|
722
|
+
currentBatch = this.m = e;
|
|
706
723
|
}
|
|
707
724
|
} else {
|
|
708
725
|
if (canUseSimpleSyncFlush(this)) {
|
|
709
726
|
commitPendingNodes();
|
|
710
727
|
if (dirtyQueue.C >= dirtyQueue.P) {
|
|
711
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
728
|
+
runHeap(dirtyQueue, GlobalQueue.J);
|
|
712
729
|
commitPendingNodes();
|
|
713
730
|
}
|
|
714
731
|
} else {
|
|
715
|
-
if (transitions.size) runHeap(zombieQueue, GlobalQueue.
|
|
732
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue.J);
|
|
716
733
|
finalizePureQueue();
|
|
717
734
|
}
|
|
718
735
|
}
|
|
@@ -720,31 +737,31 @@ class GlobalQueue extends Queue {
|
|
|
720
737
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
721
738
|
scheduled = dirtyQueue.C >= dirtyQueue.P;
|
|
722
739
|
// Run lane effects first (for ready lanes), then regular effects
|
|
723
|
-
activeLanes.size && GlobalQueue.
|
|
740
|
+
activeLanes.size && GlobalQueue.Ne(EFFECT_RENDER);
|
|
724
741
|
this.run(EFFECT_RENDER);
|
|
725
|
-
activeLanes.size && GlobalQueue.
|
|
742
|
+
activeLanes.size && GlobalQueue.Ne(EFFECT_USER);
|
|
726
743
|
this.run(EFFECT_USER);
|
|
727
744
|
if (false) ;
|
|
728
745
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
729
746
|
if (false) ;
|
|
730
747
|
} finally {
|
|
731
|
-
this.
|
|
748
|
+
this.B = false;
|
|
732
749
|
}
|
|
733
750
|
}
|
|
734
751
|
notify(e, t, n, r) {
|
|
735
752
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
736
753
|
if (t & STATUS_PENDING) {
|
|
737
754
|
if (n & STATUS_PENDING) {
|
|
738
|
-
const t = r !== undefined ? r : e.
|
|
755
|
+
const t = r !== undefined ? r : e.me;
|
|
739
756
|
// A visibility-only mark notification (the affects() boundary
|
|
740
757
|
// channel) updates display state on its way up but must be invisible
|
|
741
758
|
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
742
759
|
// reporter and never counts toward the loading-boundary diagnostic.
|
|
743
|
-
if (t?.
|
|
760
|
+
if (t?.ve) return true;
|
|
744
761
|
if (activeTransition && t) {
|
|
745
762
|
const n = t.source;
|
|
746
|
-
let r = activeTransition
|
|
747
|
-
if (!r) activeTransition
|
|
763
|
+
let r = activeTransition.$.get(n);
|
|
764
|
+
if (!r) activeTransition.$.set(n, r = new Set);
|
|
748
765
|
const i = r.size;
|
|
749
766
|
r.add(e);
|
|
750
767
|
if (r.size !== i) schedule();
|
|
@@ -757,7 +774,7 @@ class GlobalQueue extends Queue {
|
|
|
757
774
|
initTransition(e) {
|
|
758
775
|
if (e) e = currentTransition(e);
|
|
759
776
|
if (e && e === activeTransition) return;
|
|
760
|
-
if (!e && activeTransition && activeTransition.
|
|
777
|
+
if (!e && activeTransition && activeTransition.H === clock) return;
|
|
761
778
|
if (!activeTransition) {
|
|
762
779
|
activeTransition = e ?? createBatch();
|
|
763
780
|
} else if (e) {
|
|
@@ -767,8 +784,8 @@ class GlobalQueue extends Queue {
|
|
|
767
784
|
activeTransition = e;
|
|
768
785
|
}
|
|
769
786
|
transitions.add(activeTransition);
|
|
770
|
-
activeTransition.
|
|
771
|
-
const t = this.
|
|
787
|
+
activeTransition.H = clock;
|
|
788
|
+
const t = this.m;
|
|
772
789
|
if (t !== activeTransition) {
|
|
773
790
|
// Adopt the ambient batch into the transaction, then make the
|
|
774
791
|
// transaction the batch so later registrations land there directly.
|
|
@@ -777,19 +794,25 @@ class GlobalQueue extends Queue {
|
|
|
777
794
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
778
795
|
// downstream: propagation never queues pended subscribers as pending
|
|
779
796
|
// nodes, see propagateAffectsMark, #2893.
|
|
780
|
-
for (let e = 0; e < t.
|
|
781
|
-
const n = t.
|
|
797
|
+
for (let e = 0; e < t.M.length; e++) {
|
|
798
|
+
const n = t.M[e];
|
|
782
799
|
n.T = activeTransition;
|
|
783
|
-
activeTransition.
|
|
800
|
+
activeTransition.M.push(n);
|
|
784
801
|
}
|
|
785
|
-
for (let e = 0; e < t.
|
|
786
|
-
const n = t.
|
|
802
|
+
for (let e = 0; e < t.L.length; e++) {
|
|
803
|
+
const n = t.L[e];
|
|
787
804
|
n.T = activeTransition;
|
|
788
|
-
activeTransition.
|
|
805
|
+
activeTransition.L.push(n);
|
|
789
806
|
}
|
|
790
|
-
if (t.
|
|
791
|
-
for (const e of t.
|
|
792
|
-
|
|
807
|
+
if (t.G.length) activeTransition.G.push(...t.G);
|
|
808
|
+
for (const e of t.V) activeTransition.V.add(e);
|
|
809
|
+
// Gated readers recorded against the ambient batch move with it: their
|
|
810
|
+
// replay-at-commit now happens at the transaction's completion.
|
|
811
|
+
if (t.q.size) {
|
|
812
|
+
for (const e of t.q) activeTransition.q.add(e);
|
|
813
|
+
t.q.clear();
|
|
814
|
+
}
|
|
815
|
+
currentBatch = this.m = activeTransition;
|
|
793
816
|
}
|
|
794
817
|
for (const e of activeLanes) {
|
|
795
818
|
if (!e.T) e.T = activeTransition;
|
|
@@ -798,7 +821,7 @@ class GlobalQueue extends Queue {
|
|
|
798
821
|
}
|
|
799
822
|
|
|
800
823
|
function queuePendingNode(e) {
|
|
801
|
-
currentBatch.
|
|
824
|
+
currentBatch.M.push(e);
|
|
802
825
|
}
|
|
803
826
|
|
|
804
827
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -814,21 +837,21 @@ function insertSubs(e, t = false) {
|
|
|
814
837
|
// Get source lane: prefer node's own lane over current context
|
|
815
838
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
816
839
|
const n = e.i || currentOptimisticLane;
|
|
817
|
-
const r = e.
|
|
840
|
+
const r = e.Le !== undefined;
|
|
818
841
|
const i = reaskArmed;
|
|
819
|
-
for (let o = e.
|
|
842
|
+
for (let o = e.U; o !== null; o = o.Ge) {
|
|
820
843
|
// A value-change notification is a new question for the subscriber: any
|
|
821
844
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
822
|
-
if (i) o.Ve.
|
|
845
|
+
if (i) o.Ve.D &= ~REACTIVE_REASK;
|
|
823
846
|
if (r && o.Ve.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
824
|
-
o.Ve.
|
|
847
|
+
o.Ve.D |= REACTIVE_SNAPSHOT_STALE;
|
|
825
848
|
continue;
|
|
826
849
|
}
|
|
827
850
|
if (t && n) {
|
|
828
|
-
o.Ve.
|
|
851
|
+
o.Ve.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
829
852
|
assignOrMergeLane(o.Ve, n);
|
|
830
853
|
} else if (t) {
|
|
831
|
-
o.Ve.
|
|
854
|
+
o.Ve.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
832
855
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
833
856
|
o.Ve.i = undefined;
|
|
834
857
|
}
|
|
@@ -839,27 +862,27 @@ function insertSubs(e, t = false) {
|
|
|
839
862
|
function commitPendingNode(e) {
|
|
840
863
|
const t = e;
|
|
841
864
|
if (!t.ke) {
|
|
842
|
-
if (e.
|
|
843
|
-
e.We = e.
|
|
844
|
-
e.
|
|
865
|
+
if (e.k !== NOT_PENDING) {
|
|
866
|
+
e.We = e.k;
|
|
867
|
+
e.k = NOT_PENDING;
|
|
845
868
|
}
|
|
846
|
-
if (e._ || e.R) GlobalQueue.
|
|
869
|
+
if (e._ || e.R) GlobalQueue.Ee(e);
|
|
847
870
|
return;
|
|
848
871
|
}
|
|
849
|
-
if (e.
|
|
850
|
-
e.We = e.
|
|
851
|
-
e.
|
|
872
|
+
if (e.k !== NOT_PENDING) {
|
|
873
|
+
e.We = e.k;
|
|
874
|
+
e.k = NOT_PENDING;
|
|
852
875
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
853
|
-
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.
|
|
876
|
+
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.Qe = true;
|
|
854
877
|
}
|
|
855
|
-
t.
|
|
856
|
-
if (!(t.
|
|
857
|
-
if (t.He !== null || t.Me !== null) GlobalQueue.
|
|
858
|
-
if (e._ || e.R) GlobalQueue.
|
|
878
|
+
t.D &= ~REACTIVE_MANUAL_WRITE;
|
|
879
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
880
|
+
if (t.He !== null || t.Me !== null) GlobalQueue.ee(t, false, true);
|
|
881
|
+
if (e._ || e.R) GlobalQueue.Ee(e);
|
|
859
882
|
}
|
|
860
883
|
|
|
861
884
|
function commitPendingNodes() {
|
|
862
|
-
const e = currentBatch.
|
|
885
|
+
const e = currentBatch.M;
|
|
863
886
|
for (let t = 0; t < e.length; t++) {
|
|
864
887
|
commitPendingNode(e[t]);
|
|
865
888
|
}
|
|
@@ -871,24 +894,30 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
871
894
|
// For completing transitions or no-transition, resolve pending and revert optimistic
|
|
872
895
|
const n = !t;
|
|
873
896
|
if (n) commitPendingNodes();
|
|
874
|
-
if (!t && globalQueue.
|
|
897
|
+
if (!t && globalQueue.v.length) checkBoundaryChildren(globalQueue);
|
|
875
898
|
const r = dirtyQueue.C >= dirtyQueue.P;
|
|
876
|
-
if (r) runHeap(dirtyQueue, GlobalQueue.
|
|
899
|
+
if (r) runHeap(dirtyQueue, GlobalQueue.J);
|
|
877
900
|
if (n) {
|
|
878
901
|
if (r) commitPendingNodes();
|
|
879
902
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
880
|
-
const t = e ?? globalQueue.
|
|
903
|
+
const t = e ?? globalQueue.m;
|
|
881
904
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
882
905
|
// which installed the engine's hooks.
|
|
883
|
-
if (t.
|
|
906
|
+
if (t.L.length) GlobalQueue.Ie(t.L);
|
|
884
907
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
885
|
-
// so they re-run with the now-committed values visible.
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
if (t.
|
|
889
|
-
|
|
908
|
+
// so they re-run with the now-committed values visible. The ambient batch
|
|
909
|
+
// replays too — laneReadsCommitted records readers whose committed-view
|
|
910
|
+
// read hid a same-tick plain write that just committed above (#2963).
|
|
911
|
+
if (t.q.size) {
|
|
912
|
+
for (const e of t.q) {
|
|
913
|
+
if (e.D & REACTIVE_DISPOSED) continue;
|
|
914
|
+
enqueueSub(e);
|
|
890
915
|
}
|
|
891
|
-
|
|
916
|
+
t.q.clear();
|
|
917
|
+
// A completing transition keeps the outer flush loop alive by itself;
|
|
918
|
+
// the ambient batch needs the re-arm or the replay sits in the heap
|
|
919
|
+
// until the next unrelated write.
|
|
920
|
+
schedule();
|
|
892
921
|
}
|
|
893
922
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
894
923
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
@@ -896,23 +925,23 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
896
925
|
// held boundary display state through the visual channel, and their
|
|
897
926
|
// release is the display-state update point — re-run the boundary sweep
|
|
898
927
|
// (the earlier sweep above ran while the marks were still live).
|
|
899
|
-
if (t.
|
|
900
|
-
GlobalQueue.
|
|
901
|
-
if (globalQueue.
|
|
928
|
+
if (t.G.length) {
|
|
929
|
+
GlobalQueue.ie(t.G);
|
|
930
|
+
if (globalQueue.v.length) checkBoundaryChildren(globalQueue);
|
|
902
931
|
}
|
|
903
932
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
904
933
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
905
934
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
906
935
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
907
|
-
if (t.
|
|
936
|
+
if (t.V.size) GlobalQueue.ne(t.V, e);
|
|
908
937
|
sweepTransientStoreNodes();
|
|
909
938
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
910
|
-
if (activeLanes.size) GlobalQueue.
|
|
939
|
+
if (activeLanes.size) GlobalQueue.he(e);
|
|
911
940
|
}
|
|
912
941
|
}
|
|
913
942
|
|
|
914
943
|
function checkBoundaryChildren(e) {
|
|
915
|
-
for (const t of e.
|
|
944
|
+
for (const t of e.v) {
|
|
916
945
|
t.$e?.();
|
|
917
946
|
checkBoundaryChildren(t);
|
|
918
947
|
}
|
|
@@ -947,7 +976,7 @@ const globalQueue = new GlobalQueue;
|
|
|
947
976
|
// property hop through `_batch` was a measured instruction-count regression
|
|
948
977
|
// (CodSpeed update1to1, PR #2905). The field stays authoritative for
|
|
949
978
|
// cross-module readers; every `_batch` assignment updates both.
|
|
950
|
-
let currentBatch = globalQueue.
|
|
979
|
+
let currentBatch = globalQueue.m;
|
|
951
980
|
|
|
952
981
|
function flush(e) {
|
|
953
982
|
if (e) {
|
|
@@ -964,7 +993,7 @@ function flush(e) {
|
|
|
964
993
|
}
|
|
965
994
|
}
|
|
966
995
|
}
|
|
967
|
-
if (globalQueue.
|
|
996
|
+
if (globalQueue.B) {
|
|
968
997
|
return;
|
|
969
998
|
}
|
|
970
999
|
if (halted) return;
|
|
@@ -980,7 +1009,7 @@ function runQueue$1(e, t) {
|
|
|
980
1009
|
}
|
|
981
1010
|
|
|
982
1011
|
function reporterBlocksSource(e, t) {
|
|
983
|
-
if (e.
|
|
1012
|
+
if (e.D & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
984
1013
|
if (e.je?.has(t)) return true;
|
|
985
1014
|
for (let n = e.Ke; n; n = n.Ye) {
|
|
986
1015
|
let e = n.qe;
|
|
@@ -989,14 +1018,14 @@ function reporterBlocksSource(e, t) {
|
|
|
989
1018
|
e = e.t;
|
|
990
1019
|
}
|
|
991
1020
|
}
|
|
992
|
-
return !!(e.
|
|
1021
|
+
return !!(e.xe & STATUS_PENDING && e.me instanceof NotReadyError && e.me.source === t);
|
|
993
1022
|
}
|
|
994
1023
|
|
|
995
1024
|
function transitionComplete(e) {
|
|
996
1025
|
if (e.I) return true;
|
|
997
|
-
if (e
|
|
1026
|
+
if (e.j.length) return false;
|
|
998
1027
|
let t = true;
|
|
999
|
-
for (const [n, r] of e
|
|
1028
|
+
for (const [n, r] of e.$) {
|
|
1000
1029
|
let i = false;
|
|
1001
1030
|
for (const e of r) {
|
|
1002
1031
|
if (reporterBlocksSource(e, n)) {
|
|
@@ -1005,7 +1034,7 @@ function transitionComplete(e) {
|
|
|
1005
1034
|
}
|
|
1006
1035
|
r.delete(e);
|
|
1007
1036
|
}
|
|
1008
|
-
if (!i) e
|
|
1037
|
+
if (!i) e.$.delete(n); else if (n.xe & STATUS_PENDING && n.me?.source === n) {
|
|
1009
1038
|
t = false;
|
|
1010
1039
|
break;
|
|
1011
1040
|
}
|
|
@@ -1013,7 +1042,7 @@ function transitionComplete(e) {
|
|
|
1013
1042
|
// Override blockage lives with the engine (absent hook = "no optimistic
|
|
1014
1043
|
// blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
|
|
1015
1044
|
// no-ops when the transition holds neither, so no pre-check is needed.
|
|
1016
|
-
if (t && GlobalQueue.
|
|
1045
|
+
if (t && GlobalQueue.Ae?.(e)) t = false;
|
|
1017
1046
|
t && (e.I = true);
|
|
1018
1047
|
return t;
|
|
1019
1048
|
}
|
|
@@ -1034,7 +1063,7 @@ function runInTransition(e, t) {
|
|
|
1034
1063
|
}
|
|
1035
1064
|
|
|
1036
1065
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1037
|
-
return e.
|
|
1066
|
+
return e.D & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1038
1067
|
}
|
|
1039
1068
|
|
|
1040
1069
|
/**
|
|
@@ -1044,8 +1073,8 @@ function runInTransition(e, t) {
|
|
|
1044
1073
|
*/ function enqueueSub(e) {
|
|
1045
1074
|
if (e.Fe === EFFECT_TRACKED) {
|
|
1046
1075
|
const t = e;
|
|
1047
|
-
if (!t.
|
|
1048
|
-
t.
|
|
1076
|
+
if (!t.Qe) {
|
|
1077
|
+
t.Qe = true;
|
|
1049
1078
|
t.Ze.enqueue(EFFECT_USER, t.Xe);
|
|
1050
1079
|
}
|
|
1051
1080
|
return;
|
|
@@ -1056,7 +1085,7 @@ function runInTransition(e, t) {
|
|
|
1056
1085
|
}
|
|
1057
1086
|
|
|
1058
1087
|
function actualInsertIntoHeap(e, t) {
|
|
1059
|
-
const n = (e.
|
|
1088
|
+
const n = (e.Z?.Je ? e.Z.et?.ze : e.Z?.ze) ?? -1;
|
|
1060
1089
|
if (n >= e.ze) e.ze = n + 1;
|
|
1061
1090
|
const r = e.ze;
|
|
1062
1091
|
const i = t.h[r];
|
|
@@ -1070,12 +1099,12 @@ function actualInsertIntoHeap(e, t) {
|
|
|
1070
1099
|
}
|
|
1071
1100
|
|
|
1072
1101
|
function insertIntoHeap(e, t) {
|
|
1073
|
-
let n = e.
|
|
1102
|
+
let n = e.D;
|
|
1074
1103
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1075
1104
|
if (n & REACTIVE_CHECK) {
|
|
1076
|
-
e.
|
|
1105
|
+
e.D = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1077
1106
|
} else {
|
|
1078
|
-
e.
|
|
1107
|
+
e.D = n | REACTIVE_IN_HEAP;
|
|
1079
1108
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1080
1109
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1081
1110
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1087,16 +1116,16 @@ function insertIntoHeap(e, t) {
|
|
|
1087
1116
|
}
|
|
1088
1117
|
|
|
1089
1118
|
function insertIntoHeapHeight(e, t) {
|
|
1090
|
-
let n = e.
|
|
1119
|
+
let n = e.D;
|
|
1091
1120
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1092
|
-
e.
|
|
1121
|
+
e.D = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1093
1122
|
actualInsertIntoHeap(e, t);
|
|
1094
1123
|
}
|
|
1095
1124
|
|
|
1096
1125
|
function deleteFromHeap(e, t) {
|
|
1097
|
-
const n = e.
|
|
1126
|
+
const n = e.D;
|
|
1098
1127
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1099
|
-
e.
|
|
1128
|
+
e.D = n & -25;
|
|
1100
1129
|
const r = e.ze;
|
|
1101
1130
|
if (e.tt === e) t.h[r] = undefined; else {
|
|
1102
1131
|
const n = e.nt;
|
|
@@ -1114,21 +1143,21 @@ function markHeap(e) {
|
|
|
1114
1143
|
e.N = true;
|
|
1115
1144
|
for (let t = 0; t <= e.C; t++) {
|
|
1116
1145
|
for (let n = e.h[t]; n !== undefined; n = n.nt) {
|
|
1117
|
-
if (n.
|
|
1146
|
+
if (n.D & REACTIVE_IN_HEAP) markNode(n);
|
|
1118
1147
|
}
|
|
1119
1148
|
}
|
|
1120
1149
|
}
|
|
1121
1150
|
|
|
1122
1151
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1123
|
-
const n = e.
|
|
1152
|
+
const n = e.D;
|
|
1124
1153
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1125
|
-
e.
|
|
1126
|
-
for (let t = e.
|
|
1154
|
+
e.D = n & -4 | t;
|
|
1155
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1127
1156
|
markNode(t.Ve, REACTIVE_CHECK);
|
|
1128
1157
|
}
|
|
1129
1158
|
if (e.rt !== null) {
|
|
1130
1159
|
for (let t = e.rt; t !== null; t = t.it) {
|
|
1131
|
-
for (let e = t.
|
|
1160
|
+
for (let e = t.U; e !== null; e = e.Ge) {
|
|
1132
1161
|
markNode(e.Ve, REACTIVE_CHECK);
|
|
1133
1162
|
}
|
|
1134
1163
|
}
|
|
@@ -1140,7 +1169,7 @@ function runHeap(e, t) {
|
|
|
1140
1169
|
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1141
1170
|
let n = e.h[e.P];
|
|
1142
1171
|
while (n !== undefined) {
|
|
1143
|
-
if (n.
|
|
1172
|
+
if (n.D & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1144
1173
|
n = e.h[e.P];
|
|
1145
1174
|
}
|
|
1146
1175
|
}
|
|
@@ -1157,7 +1186,7 @@ function adjustHeight(e, t) {
|
|
|
1157
1186
|
}
|
|
1158
1187
|
if (e.ze !== n) {
|
|
1159
1188
|
e.ze = n;
|
|
1160
|
-
for (let t = e.
|
|
1189
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1161
1190
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1162
1191
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1163
1192
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
@@ -1174,8 +1203,8 @@ const PENDING_OWNER = {};
|
|
|
1174
1203
|
function markDisposal(e) {
|
|
1175
1204
|
let t = e.ot;
|
|
1176
1205
|
while (t) {
|
|
1177
|
-
const e = t.
|
|
1178
|
-
t.
|
|
1206
|
+
const e = t.D;
|
|
1207
|
+
t.D = e | REACTIVE_ZOMBIE;
|
|
1179
1208
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1180
1209
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1181
1210
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1201,17 +1230,17 @@ function dispose(e) {
|
|
|
1201
1230
|
}
|
|
1202
1231
|
|
|
1203
1232
|
function disposeChildren(e, t = false, n) {
|
|
1204
|
-
const r = e.
|
|
1233
|
+
const r = e.D;
|
|
1205
1234
|
if (r & REACTIVE_DISPOSED) return;
|
|
1206
1235
|
if (t) {
|
|
1207
|
-
e.
|
|
1236
|
+
e.D = r | REACTIVE_DISPOSED;
|
|
1208
1237
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1209
1238
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1210
1239
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1211
1240
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1212
1241
|
// false, and notifies subscribers still watching the companion.
|
|
1213
1242
|
const t = e;
|
|
1214
|
-
if (t._ || t.R) GlobalQueue.
|
|
1243
|
+
if (t._ || t.R) GlobalQueue.Ee(t);
|
|
1215
1244
|
}
|
|
1216
1245
|
if (t && e.ke) e.lt = null;
|
|
1217
1246
|
let i = n ? e.He : e.ot;
|
|
@@ -1240,10 +1269,10 @@ function disposeChildren(e, t = false, n) {
|
|
|
1240
1269
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1241
1270
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1242
1271
|
// walks that already advanced past us still reach later siblings.
|
|
1243
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.
|
|
1272
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.Z !== null && !(e.Z.D & REACTIVE_DISPOSED)) {
|
|
1244
1273
|
const t = e.ft;
|
|
1245
1274
|
const n = e.st;
|
|
1246
|
-
if (t !== null) t.st = n; else e.
|
|
1275
|
+
if (t !== null) t.st = n; else e.Z.ot = n;
|
|
1247
1276
|
if (n !== null) n.ft = t;
|
|
1248
1277
|
e.ft = null;
|
|
1249
1278
|
}
|
|
@@ -1273,7 +1302,7 @@ function runDisposal(e, t) {
|
|
|
1273
1302
|
|
|
1274
1303
|
function childId(e, t) {
|
|
1275
1304
|
let n = e;
|
|
1276
|
-
while (n.Ue & CONFIG_TRANSPARENT && n.
|
|
1305
|
+
while (n.Ue & CONFIG_TRANSPARENT && n.Z) n = n.Z;
|
|
1277
1306
|
if (n.id != null) return formatId(n.id, t ? n.ct++ : n.ct);
|
|
1278
1307
|
throw new Error("");
|
|
1279
1308
|
}
|
|
@@ -1375,7 +1404,7 @@ function formatId(e, t) {
|
|
|
1375
1404
|
* }
|
|
1376
1405
|
* ```
|
|
1377
1406
|
*/ function isDisposed(e) {
|
|
1378
|
-
return !!(e.
|
|
1407
|
+
return !!(e.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1379
1408
|
}
|
|
1380
1409
|
|
|
1381
1410
|
function disposeRootSelf(e = true) {
|
|
@@ -1406,7 +1435,7 @@ function disposeRootSelf(e = true) {
|
|
|
1406
1435
|
ct: 0,
|
|
1407
1436
|
Me: null,
|
|
1408
1437
|
He: null,
|
|
1409
|
-
|
|
1438
|
+
Z: t,
|
|
1410
1439
|
dispose: disposeRootSelf
|
|
1411
1440
|
};
|
|
1412
1441
|
if (t) {
|
|
@@ -1454,13 +1483,13 @@ function disposeRootSelf(e = true) {
|
|
|
1454
1483
|
function unlinkSubs(e) {
|
|
1455
1484
|
const t = e.qe;
|
|
1456
1485
|
const n = e.Ye;
|
|
1457
|
-
const r = e.
|
|
1486
|
+
const r = e.Ge;
|
|
1458
1487
|
const i = e.Tt;
|
|
1459
1488
|
if (r !== null) r.Tt = i; else t.Ot = i;
|
|
1460
|
-
if (i !== null) i.
|
|
1461
|
-
t.
|
|
1489
|
+
if (i !== null) i.Ge = r; else {
|
|
1490
|
+
t.U = r;
|
|
1462
1491
|
if (r === null) {
|
|
1463
|
-
t.
|
|
1492
|
+
t.F?.();
|
|
1464
1493
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1465
1494
|
// A pending node is exempt: its in-flight async work (or the
|
|
1466
1495
|
// transition holding it) is an observer — tearing down would orphan
|
|
@@ -1468,7 +1497,7 @@ function unlinkSubs(e) {
|
|
|
1468
1497
|
// this same last-one-out check when that observer releases (the
|
|
1469
1498
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1470
1499
|
const e = t;
|
|
1471
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.
|
|
1500
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.D & REACTIVE_ZOMBIE) && !(e.xe & STATUS_PENDING) && unobserved(e);
|
|
1472
1501
|
}
|
|
1473
1502
|
}
|
|
1474
1503
|
return n;
|
|
@@ -1509,7 +1538,7 @@ function link(e, t, n = false) {
|
|
|
1509
1538
|
return;
|
|
1510
1539
|
}
|
|
1511
1540
|
let i = null;
|
|
1512
|
-
const o = t.
|
|
1541
|
+
const o = t.D & REACTIVE_RECOMPUTING_DEPS;
|
|
1513
1542
|
if (o) {
|
|
1514
1543
|
i = r !== null ? r.Ye : t.Ke;
|
|
1515
1544
|
if (i !== null && i.qe === e) {
|
|
@@ -1537,12 +1566,12 @@ function link(e, t, n = false) {
|
|
|
1537
1566
|
Ve: t,
|
|
1538
1567
|
Ye: i,
|
|
1539
1568
|
Tt: s,
|
|
1540
|
-
|
|
1569
|
+
Ge: null,
|
|
1541
1570
|
Rt: t.It,
|
|
1542
1571
|
_t: n
|
|
1543
1572
|
};
|
|
1544
1573
|
if (r !== null) r.Ye = u; else t.Ke = u;
|
|
1545
|
-
if (s !== null) s.
|
|
1574
|
+
if (s !== null) s.Ge = u; else e.U = u;
|
|
1546
1575
|
}
|
|
1547
1576
|
|
|
1548
1577
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1569,24 +1598,24 @@ function clearPendingSources(e) {
|
|
|
1569
1598
|
|
|
1570
1599
|
function setPendingError(e, t, n) {
|
|
1571
1600
|
if (!t) {
|
|
1572
|
-
e.
|
|
1601
|
+
e.me = null;
|
|
1573
1602
|
return;
|
|
1574
1603
|
}
|
|
1575
1604
|
if (n instanceof NotReadyError && n.source === t) {
|
|
1576
|
-
e.
|
|
1605
|
+
e.me = n;
|
|
1577
1606
|
return;
|
|
1578
1607
|
}
|
|
1579
|
-
const r = e.
|
|
1608
|
+
const r = e.me;
|
|
1580
1609
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
1581
|
-
e.
|
|
1610
|
+
e.me = new NotReadyError(t);
|
|
1582
1611
|
}
|
|
1583
1612
|
}
|
|
1584
1613
|
|
|
1585
1614
|
function forEachDependent(e, t) {
|
|
1586
|
-
for (let n = e.
|
|
1615
|
+
for (let n = e.U; n !== null; n = n.Ge) t(n.Ve, n);
|
|
1587
1616
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1588
1617
|
for (let n = e.rt ?? null; n !== null; n = n.it) {
|
|
1589
|
-
for (let e = n.
|
|
1618
|
+
for (let e = n.U; e !== null; e = e.Ge) t(e.Ve, e);
|
|
1590
1619
|
}
|
|
1591
1620
|
}
|
|
1592
1621
|
|
|
@@ -1601,7 +1630,7 @@ function forEachDependent(e, t) {
|
|
|
1601
1630
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1602
1631
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1603
1632
|
function releaseIfSettledUnobserved(e) {
|
|
1604
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.
|
|
1633
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.D & REACTIVE_ZOMBIE) && !(e.xe & STATUS_PENDING) && unobserved(e);
|
|
1605
1634
|
}
|
|
1606
1635
|
|
|
1607
1636
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -1614,7 +1643,7 @@ function releaseSettledDependents(e) {
|
|
|
1614
1643
|
const visit = e => {
|
|
1615
1644
|
if (n.has(e)) return;
|
|
1616
1645
|
n.add(e);
|
|
1617
|
-
if (!e.
|
|
1646
|
+
if (!e.U && e.Ue & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
1618
1647
|
forEachDependent(e, visit);
|
|
1619
1648
|
};
|
|
1620
1649
|
forEachDependent(e, visit);
|
|
@@ -1642,7 +1671,7 @@ function settleErroredDependents(e, t) {
|
|
|
1642
1671
|
const visit = e => {
|
|
1643
1672
|
if (r.has(e)) return;
|
|
1644
1673
|
r.add(e);
|
|
1645
|
-
if (e.
|
|
1674
|
+
if (e.me === t) {
|
|
1646
1675
|
enqueueSub(e);
|
|
1647
1676
|
n = true;
|
|
1648
1677
|
}
|
|
@@ -1657,17 +1686,17 @@ function settlePendingSource(e) {
|
|
|
1657
1686
|
let n;
|
|
1658
1687
|
const r = new Set;
|
|
1659
1688
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1660
|
-
const i = GlobalQueue.
|
|
1689
|
+
const i = GlobalQueue.ce;
|
|
1661
1690
|
const settle = o => {
|
|
1662
1691
|
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1663
1692
|
r.add(o);
|
|
1664
|
-
o.
|
|
1693
|
+
o.H = clock;
|
|
1665
1694
|
const s = o.je?.values().next().value;
|
|
1666
1695
|
if (s) {
|
|
1667
1696
|
setPendingError(o, s);
|
|
1668
1697
|
i !== null && i(o);
|
|
1669
1698
|
} else {
|
|
1670
|
-
o.
|
|
1699
|
+
o.xe &= ~STATUS_PENDING;
|
|
1671
1700
|
setPendingError(o);
|
|
1672
1701
|
i !== null && i(o);
|
|
1673
1702
|
if (o.At) {
|
|
@@ -1678,7 +1707,7 @@ function settlePendingSource(e) {
|
|
|
1678
1707
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1679
1708
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
1680
1709
|
// lists this walk is still iterating.
|
|
1681
|
-
if (!o.
|
|
1710
|
+
if (!o.U && o.Ue & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
1682
1711
|
}
|
|
1683
1712
|
forEachDependent(o, settle);
|
|
1684
1713
|
};
|
|
@@ -1721,7 +1750,7 @@ function handleAsync(e, t, n) {
|
|
|
1721
1750
|
// are the transaction's reveal machinery and always re-enter.
|
|
1722
1751
|
const settleTransition = () => {
|
|
1723
1752
|
const t = resolveTransition(e);
|
|
1724
|
-
if (t && e.
|
|
1753
|
+
if (t && e.xe & STATUS_UNINITIALIZED && !currentTransition(t).$.has(e)) {
|
|
1725
1754
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1726
1755
|
// stash-path restamp both re-enter the transaction through it.
|
|
1727
1756
|
e.T = null;
|
|
@@ -1735,7 +1764,7 @@ function handleAsync(e, t, n) {
|
|
|
1735
1764
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1736
1765
|
const r = n instanceof NotReadyError;
|
|
1737
1766
|
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1738
|
-
e.
|
|
1767
|
+
e.H = clock;
|
|
1739
1768
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
1740
1769
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
1741
1770
|
// the error twin of settlePendingSource's release (#2934).
|
|
@@ -1746,9 +1775,9 @@ function handleAsync(e, t, n) {
|
|
|
1746
1775
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1747
1776
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1748
1777
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1749
|
-
if (e.
|
|
1778
|
+
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1750
1779
|
settleTransition();
|
|
1751
|
-
const o = !!(e.
|
|
1780
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1752
1781
|
trimStaleDeps(e);
|
|
1753
1782
|
clearStatus(e);
|
|
1754
1783
|
const s = resolveLane(e);
|
|
@@ -1766,8 +1795,8 @@ function handleAsync(e, t, n) {
|
|
|
1766
1795
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
1767
1796
|
// has committed by then, so corrections reveal atomically with their
|
|
1768
1797
|
// transition rather than escaping it.
|
|
1769
|
-
if (e.
|
|
1770
|
-
e.
|
|
1798
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
1799
|
+
e.k = r;
|
|
1771
1800
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
1772
1801
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
1773
1802
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -1775,9 +1804,9 @@ function handleAsync(e, t, n) {
|
|
|
1775
1804
|
// only notified when the hold is visible to them: under an active
|
|
1776
1805
|
// override every reader sees the override (A17), so waking subs would
|
|
1777
1806
|
// re-show an unchanged view — the revert is the notification point.
|
|
1778
|
-
GlobalQueue.
|
|
1807
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e, r);
|
|
1779
1808
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1780
|
-
e.
|
|
1809
|
+
e.H = clock;
|
|
1781
1810
|
} else if (s) {
|
|
1782
1811
|
// Route through lane's effect queue for independent flushing
|
|
1783
1812
|
const t = e.Fe;
|
|
@@ -1786,11 +1815,11 @@ function handleAsync(e, t, n) {
|
|
|
1786
1815
|
try {
|
|
1787
1816
|
if (!t && o || !i || !i(r, n)) {
|
|
1788
1817
|
e.We = r;
|
|
1789
|
-
e.
|
|
1818
|
+
e.H = clock;
|
|
1790
1819
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1791
1820
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1792
1821
|
// (computePendingState doesn't read _value).
|
|
1793
|
-
GlobalQueue.
|
|
1822
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e, r);
|
|
1794
1823
|
insertSubs(e, true);
|
|
1795
1824
|
}
|
|
1796
1825
|
} catch (t) {
|
|
@@ -1822,7 +1851,7 @@ function handleAsync(e, t, n) {
|
|
|
1822
1851
|
// Returns whether the node released, so the iterator branch can stop
|
|
1823
1852
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1824
1853
|
const settleAutodispose = () => {
|
|
1825
|
-
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.
|
|
1854
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.xe & STATUS_PENDING)) {
|
|
1826
1855
|
unobserved(e);
|
|
1827
1856
|
return true;
|
|
1828
1857
|
}
|
|
@@ -1944,12 +1973,12 @@ function clearStatus(e, t = false) {
|
|
|
1944
1973
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1945
1974
|
// plain store to an existing slot — no shape change.)
|
|
1946
1975
|
e.Nt = false;
|
|
1947
|
-
e.
|
|
1948
|
-
if (e.
|
|
1976
|
+
e.xe = t ? 0 : e.xe & STATUS_UNINITIALIZED;
|
|
1977
|
+
if (e.me) setPendingError(e);
|
|
1949
1978
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1950
1979
|
// once the verdict layer created them, which installs the hooks).
|
|
1951
|
-
if (e._ || e.R) GlobalQueue.
|
|
1952
|
-
if (e.rt && GlobalQueue.
|
|
1980
|
+
if (e._ || e.R) GlobalQueue.ce(e);
|
|
1981
|
+
if (e.rt && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1953
1982
|
if (e.yt) e.yt();
|
|
1954
1983
|
}
|
|
1955
1984
|
|
|
@@ -1963,17 +1992,17 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1963
1992
|
if (!r) {
|
|
1964
1993
|
if (t === STATUS_PENDING && o) {
|
|
1965
1994
|
addPendingSource(e, o);
|
|
1966
|
-
e.
|
|
1995
|
+
e.xe = STATUS_PENDING | e.xe & STATUS_UNINITIALIZED;
|
|
1967
1996
|
// Preserve the current source on this propagation so render-effect notification
|
|
1968
1997
|
// can register every distinct pending source with the transition.
|
|
1969
1998
|
setPendingError(e, o, n);
|
|
1970
1999
|
} else {
|
|
1971
2000
|
clearPendingSources(e);
|
|
1972
|
-
e.
|
|
1973
|
-
e.
|
|
2001
|
+
e.xe = t | (t !== STATUS_ERROR ? e.xe & STATUS_UNINITIALIZED : 0);
|
|
2002
|
+
e.me = n;
|
|
1974
2003
|
}
|
|
1975
|
-
GlobalQueue.
|
|
1976
|
-
if (e.rt && GlobalQueue.
|
|
2004
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
2005
|
+
if (e.rt && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1977
2006
|
}
|
|
1978
2007
|
if (i && !r) {
|
|
1979
2008
|
assignOrMergeLane(e, i);
|
|
@@ -1992,8 +2021,8 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1992
2021
|
return;
|
|
1993
2022
|
}
|
|
1994
2023
|
forEachDependent(e, (e, r) => {
|
|
1995
|
-
e.
|
|
1996
|
-
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.
|
|
2024
|
+
e.H = clock;
|
|
2025
|
+
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.me !== n || e.je)) {
|
|
1997
2026
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1998
2027
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1999
2028
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
@@ -2010,9 +2039,9 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
2010
2039
|
});
|
|
2011
2040
|
}
|
|
2012
2041
|
|
|
2013
|
-
GlobalQueue.
|
|
2042
|
+
GlobalQueue.J = recompute;
|
|
2014
2043
|
|
|
2015
|
-
GlobalQueue.
|
|
2044
|
+
GlobalQueue.ee = disposeChildren;
|
|
2016
2045
|
|
|
2017
2046
|
let tracking = false;
|
|
2018
2047
|
|
|
@@ -2045,7 +2074,7 @@ let snapshotSources = null;
|
|
|
2045
2074
|
function ownerInSnapshotScope(e) {
|
|
2046
2075
|
while (e) {
|
|
2047
2076
|
if (e.Pt) return true;
|
|
2048
|
-
e = e.
|
|
2077
|
+
e = e.Z;
|
|
2049
2078
|
}
|
|
2050
2079
|
return false;
|
|
2051
2080
|
}
|
|
@@ -2075,9 +2104,9 @@ function releaseSubtree(e) {
|
|
|
2075
2104
|
if (t.ke) {
|
|
2076
2105
|
const e = t;
|
|
2077
2106
|
e.Ue &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
2078
|
-
if (e.
|
|
2079
|
-
e.
|
|
2080
|
-
e.
|
|
2107
|
+
if (e.D & REACTIVE_SNAPSHOT_STALE) {
|
|
2108
|
+
e.D &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2109
|
+
e.D |= REACTIVE_DIRTY;
|
|
2081
2110
|
if (dirtyQueue.P > e.ze) dirtyQueue.P = e.ze;
|
|
2082
2111
|
insertIntoHeap(e, dirtyQueue);
|
|
2083
2112
|
}
|
|
@@ -2090,7 +2119,7 @@ function releaseSubtree(e) {
|
|
|
2090
2119
|
function clearSnapshots() {
|
|
2091
2120
|
if (snapshotSources) {
|
|
2092
2121
|
for (const e of snapshotSources) {
|
|
2093
|
-
delete e.
|
|
2122
|
+
delete e.Le;
|
|
2094
2123
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
2095
2124
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
2096
2125
|
// when present so signal-node sources don't grow the field.
|
|
@@ -2117,23 +2146,23 @@ function recompute(e, t = false) {
|
|
|
2117
2146
|
e.ct = 0;
|
|
2118
2147
|
} else ;
|
|
2119
2148
|
}
|
|
2120
|
-
let r = !!(e.
|
|
2149
|
+
let r = !!(e.D & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2121
2150
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
2122
|
-
const o = !!(e.
|
|
2151
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
2123
2152
|
// Outgoing error, captured before the compute clears status: if this run
|
|
2124
2153
|
// recovers to an unchanged value, dependents still holding this object must
|
|
2125
2154
|
// be swept (settleErroredDependents, #2949).
|
|
2126
|
-
const s = e.
|
|
2155
|
+
const s = e.xe & STATUS_ERROR ? e.me : undefined;
|
|
2127
2156
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2128
2157
|
// the recompute wipes _flags below.
|
|
2129
|
-
const u = (e.
|
|
2158
|
+
const u = (e.D & REACTIVE_REASK) !== 0;
|
|
2130
2159
|
const l = context;
|
|
2131
2160
|
context = e;
|
|
2132
2161
|
e.ut = null;
|
|
2133
2162
|
e.It++;
|
|
2134
|
-
e.
|
|
2135
|
-
e.
|
|
2136
|
-
let a = e.
|
|
2163
|
+
e.D = REACTIVE_RECOMPUTING_DEPS;
|
|
2164
|
+
e.H = clock;
|
|
2165
|
+
let a = e.k === NOT_PENDING ? e.We : e.k;
|
|
2137
2166
|
let c = e.ze;
|
|
2138
2167
|
let f = tracking;
|
|
2139
2168
|
let E = currentOptimisticLane;
|
|
@@ -2150,13 +2179,13 @@ function recompute(e, t = false) {
|
|
|
2150
2179
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2151
2180
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2152
2181
|
if (r) {
|
|
2153
|
-
const t = GlobalQueue.
|
|
2182
|
+
const t = GlobalQueue.ge(e, true);
|
|
2154
2183
|
if (t) currentOptimisticLane = t;
|
|
2155
|
-
} else if (activeTransition && !t && activeTransition.
|
|
2184
|
+
} else if (activeTransition && !t && activeTransition.L.length) {
|
|
2156
2185
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2157
2186
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2158
2187
|
// recomputes under the right posture and propagates correctly.
|
|
2159
|
-
const t = GlobalQueue.
|
|
2188
|
+
const t = GlobalQueue.ge(e, false);
|
|
2160
2189
|
if (t) {
|
|
2161
2190
|
r = true;
|
|
2162
2191
|
currentOptimisticLane = t;
|
|
@@ -2185,30 +2214,30 @@ function recompute(e, t = false) {
|
|
|
2185
2214
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2186
2215
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2187
2216
|
// the flags write (create or not) stores the 0 already there.
|
|
2188
|
-
if (e.
|
|
2217
|
+
if (e.xe !== 0 || e.yt !== undefined || e.me || e.Nt || e.At || e.je !== undefined || e._ !== undefined || e.R !== undefined || e.rt !== null) clearStatus(e, t);
|
|
2189
2218
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2190
|
-
if (e.i) GlobalQueue.
|
|
2219
|
+
if (e.i) GlobalQueue.De(e);
|
|
2191
2220
|
} catch (t) {
|
|
2192
2221
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2193
2222
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2194
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2223
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.be(e);
|
|
2195
2224
|
let n = false;
|
|
2196
2225
|
if (t instanceof NotReadyError) {
|
|
2197
2226
|
e.At = true;
|
|
2198
|
-
if (GlobalQueue.
|
|
2227
|
+
if (GlobalQueue.Oe !== null) n = GlobalQueue.Oe(e, u);
|
|
2199
2228
|
}
|
|
2200
2229
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2201
|
-
if (n) GlobalQueue.
|
|
2230
|
+
if (n) GlobalQueue._e(e);
|
|
2202
2231
|
} finally {
|
|
2203
2232
|
tracking = f;
|
|
2204
2233
|
latestReadActive = d;
|
|
2205
2234
|
if (S) stale = T;
|
|
2206
|
-
e.
|
|
2235
|
+
e.D = REACTIVE_NONE | (t ? e.D & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2207
2236
|
context = l;
|
|
2208
2237
|
}
|
|
2209
|
-
if (!e.
|
|
2238
|
+
if (!e.me) {
|
|
2210
2239
|
trimStaleDeps(e);
|
|
2211
|
-
const u = i ? unwrapOverride(e.A) : e.
|
|
2240
|
+
const u = i ? unwrapOverride(e.A) : e.k === NOT_PENDING ? e.We : e.k;
|
|
2212
2241
|
let l = false;
|
|
2213
2242
|
try {
|
|
2214
2243
|
l = !n && o || !e.ht || !e.ht(u, a);
|
|
@@ -2225,12 +2254,12 @@ function recompute(e, t = false) {
|
|
|
2225
2254
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2226
2255
|
// effect() can call its runner synchronously for the first run.
|
|
2227
2256
|
if (n && l) {
|
|
2228
|
-
e.
|
|
2257
|
+
e.Qe = !e.me;
|
|
2229
2258
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2230
2259
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2231
|
-
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.
|
|
2260
|
+
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.te.bind(null, e));
|
|
2232
2261
|
}
|
|
2233
|
-
if (e.
|
|
2262
|
+
if (e.me) ; else if (l) {
|
|
2234
2263
|
const o = i ? e.A : undefined;
|
|
2235
2264
|
if (t ||
|
|
2236
2265
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2245,28 +2274,28 @@ function recompute(e, t = false) {
|
|
|
2245
2274
|
// commit can't clobber the fresh value.
|
|
2246
2275
|
if (i && r) {
|
|
2247
2276
|
e.A = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
2248
|
-
e.
|
|
2277
|
+
e.k = NOT_PENDING;
|
|
2249
2278
|
}
|
|
2250
2279
|
} else {
|
|
2251
|
-
e.
|
|
2280
|
+
e.k = a;
|
|
2252
2281
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2253
2282
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2254
2283
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2255
2284
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2256
2285
|
// pending value commits before effects run.
|
|
2257
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2286
|
+
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e, a);
|
|
2258
2287
|
}
|
|
2259
2288
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2260
2289
|
// subscriber-less node has nothing to notify.
|
|
2261
|
-
if (e.
|
|
2290
|
+
if (e.U !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2262
2291
|
} else if (i) {
|
|
2263
2292
|
// Unchanged value (equals the override) recomputed while the override
|
|
2264
2293
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2265
2294
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2266
|
-
if (e.
|
|
2267
|
-
e.
|
|
2295
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2296
|
+
e.k = a;
|
|
2268
2297
|
} else if (e.ze != c) {
|
|
2269
|
-
for (let t = e.
|
|
2298
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
2270
2299
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2271
2300
|
}
|
|
2272
2301
|
}
|
|
@@ -2275,36 +2304,36 @@ function recompute(e, t = false) {
|
|
|
2275
2304
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
2276
2305
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2277
2306
|
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
2278
|
-
if (s !== undefined && !l && !e.
|
|
2307
|
+
if (s !== undefined && !l && !e.me) settleErroredDependents(e, s);
|
|
2279
2308
|
}
|
|
2280
2309
|
currentOptimisticLane = E;
|
|
2281
|
-
const O = e.
|
|
2310
|
+
const O = e.k !== NOT_PENDING || e.He !== null || e.Me !== null || (e.xe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2282
2311
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2283
2312
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2284
2313
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2285
2314
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2286
2315
|
// _transition.
|
|
2287
|
-
O && (!t || e.
|
|
2316
|
+
O && (!t || e.xe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2288
2317
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2289
2318
|
}
|
|
2290
2319
|
|
|
2291
2320
|
function updateIfNecessary(e) {
|
|
2292
|
-
if (e.
|
|
2321
|
+
if (e.D & REACTIVE_CHECK) {
|
|
2293
2322
|
for (let t = e.Ke; t; t = t.Ye) {
|
|
2294
2323
|
const n = t.qe;
|
|
2295
2324
|
const r = n.Be || n;
|
|
2296
2325
|
if (r.ke) {
|
|
2297
2326
|
updateIfNecessary(r);
|
|
2298
2327
|
}
|
|
2299
|
-
if (e.
|
|
2328
|
+
if (e.D & REACTIVE_DIRTY) {
|
|
2300
2329
|
break;
|
|
2301
2330
|
}
|
|
2302
2331
|
}
|
|
2303
2332
|
}
|
|
2304
|
-
if (e.
|
|
2333
|
+
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.me && e.H < clock && !e.lt) {
|
|
2305
2334
|
recompute(e);
|
|
2306
2335
|
}
|
|
2307
|
-
e.
|
|
2336
|
+
e.D = e.D & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2308
2337
|
}
|
|
2309
2338
|
|
|
2310
2339
|
function computed(e, t) {
|
|
@@ -2313,7 +2342,7 @@ function computed(e, t) {
|
|
|
2313
2342
|
id: inheritId(t, n, context),
|
|
2314
2343
|
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
2344
|
ht: t?.equals != null ? t.equals : isEqual,
|
|
2316
|
-
|
|
2345
|
+
F: t?.unobserved,
|
|
2317
2346
|
dt: null,
|
|
2318
2347
|
Ze: context?.Ze ?? globalQueue,
|
|
2319
2348
|
St: context?.St ?? defaultContext,
|
|
@@ -2327,16 +2356,16 @@ function computed(e, t) {
|
|
|
2327
2356
|
Ke: null,
|
|
2328
2357
|
ut: null,
|
|
2329
2358
|
It: 0,
|
|
2330
|
-
|
|
2359
|
+
U: null,
|
|
2331
2360
|
Ot: null,
|
|
2332
|
-
|
|
2361
|
+
Z: context,
|
|
2333
2362
|
st: null,
|
|
2334
2363
|
ft: null,
|
|
2335
2364
|
ot: null,
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2365
|
+
D: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2366
|
+
xe: STATUS_UNINITIALIZED,
|
|
2367
|
+
H: clock,
|
|
2368
|
+
k: NOT_PENDING,
|
|
2340
2369
|
Me: null,
|
|
2341
2370
|
He: null,
|
|
2342
2371
|
lt: null,
|
|
@@ -2358,7 +2387,7 @@ function computed(e, t) {
|
|
|
2358
2387
|
id: inheritId(o, s, context),
|
|
2359
2388
|
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
2389
|
ht: false,
|
|
2361
|
-
|
|
2390
|
+
F: o?.unobserved,
|
|
2362
2391
|
dt: null,
|
|
2363
2392
|
Ze: context?.Ze ?? globalQueue,
|
|
2364
2393
|
St: context?.St ?? defaultContext,
|
|
@@ -2372,22 +2401,22 @@ function computed(e, t) {
|
|
|
2372
2401
|
Ke: null,
|
|
2373
2402
|
ut: null,
|
|
2374
2403
|
It: 0,
|
|
2375
|
-
|
|
2404
|
+
U: null,
|
|
2376
2405
|
Ot: null,
|
|
2377
|
-
|
|
2406
|
+
Z: context,
|
|
2378
2407
|
st: null,
|
|
2379
2408
|
ft: null,
|
|
2380
2409
|
ot: null,
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2410
|
+
D: REACTIVE_LAZY,
|
|
2411
|
+
xe: STATUS_UNINITIALIZED,
|
|
2412
|
+
H: clock,
|
|
2413
|
+
k: NOT_PENDING,
|
|
2385
2414
|
Me: null,
|
|
2386
2415
|
He: null,
|
|
2387
2416
|
lt: null,
|
|
2388
2417
|
T: null,
|
|
2389
2418
|
Nt: false,
|
|
2390
|
-
|
|
2419
|
+
Qe: false,
|
|
2391
2420
|
bt: undefined,
|
|
2392
2421
|
Dt: t,
|
|
2393
2422
|
wt: n,
|
|
@@ -2417,11 +2446,11 @@ function setupComputedNode(e, t) {
|
|
|
2417
2446
|
}
|
|
2418
2447
|
}
|
|
2419
2448
|
if (n) e.ze = n.ze + 1;
|
|
2420
|
-
if (GlobalQueue.
|
|
2449
|
+
if (GlobalQueue.ue !== null) GlobalQueue.ue(e);
|
|
2421
2450
|
!t?.lazy && recompute(e, true);
|
|
2422
2451
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2423
|
-
if (!(e.
|
|
2424
|
-
e.
|
|
2452
|
+
if (!(e.xe & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2453
|
+
e.Le = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2425
2454
|
snapshotSources.add(e);
|
|
2426
2455
|
}
|
|
2427
2456
|
}
|
|
@@ -2431,18 +2460,18 @@ function signal(e, t, n = null) {
|
|
|
2431
2460
|
const r = {
|
|
2432
2461
|
ht: t?.equals != null ? t.equals : isEqual,
|
|
2433
2462
|
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2434
|
-
|
|
2463
|
+
F: t?.unobserved,
|
|
2435
2464
|
We: e,
|
|
2436
|
-
|
|
2465
|
+
U: null,
|
|
2437
2466
|
Ot: null,
|
|
2438
|
-
|
|
2467
|
+
H: clock,
|
|
2439
2468
|
Be: n,
|
|
2440
2469
|
it: n?.rt || null,
|
|
2441
|
-
|
|
2470
|
+
k: NOT_PENDING
|
|
2442
2471
|
};
|
|
2443
2472
|
n && (n.rt = r);
|
|
2444
|
-
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.
|
|
2445
|
-
r.
|
|
2473
|
+
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.xe ?? 0) & STATUS_PENDING)) {
|
|
2474
|
+
r.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
2446
2475
|
snapshotSources.add(r);
|
|
2447
2476
|
}
|
|
2448
2477
|
return r;
|
|
@@ -2486,11 +2515,11 @@ function isEqual(e, t) {
|
|
|
2486
2515
|
* );
|
|
2487
2516
|
* ```
|
|
2488
2517
|
*/ function untrack(e, t) {
|
|
2489
|
-
if (GlobalQueue.
|
|
2518
|
+
if (GlobalQueue.le === null && !tracking && true) return e();
|
|
2490
2519
|
const n = tracking;
|
|
2491
2520
|
tracking = false;
|
|
2492
2521
|
try {
|
|
2493
|
-
if (GlobalQueue.
|
|
2522
|
+
if (GlobalQueue.le !== null) return GlobalQueue.le(e);
|
|
2494
2523
|
return e();
|
|
2495
2524
|
} finally {
|
|
2496
2525
|
tracking = n;
|
|
@@ -2502,10 +2531,10 @@ function isEqual(e, t) {
|
|
|
2502
2531
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2503
2532
|
* date so its status flags reflect the current graph.
|
|
2504
2533
|
*/ function prepareComputed(e, t) {
|
|
2505
|
-
if (e.
|
|
2506
|
-
e.
|
|
2534
|
+
if (e.D & REACTIVE_LAZY) {
|
|
2535
|
+
e.D &= ~REACTIVE_LAZY;
|
|
2507
2536
|
recompute(e, true);
|
|
2508
|
-
} else if (e.
|
|
2537
|
+
} else if (e.D & REACTIVE_DISPOSED) {
|
|
2509
2538
|
recompute(e, true);
|
|
2510
2539
|
} else if (t) {
|
|
2511
2540
|
updateIfNecessary(e);
|
|
@@ -2526,11 +2555,11 @@ function isEqual(e, t) {
|
|
|
2526
2555
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2527
2556
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2528
2557
|
*/ function readNodeFast(e) {
|
|
2529
|
-
if (latestReadActive || pendingCheckActive || e.ke || e.Be || e.A !== undefined || e.
|
|
2558
|
+
if (latestReadActive || pendingCheckActive || e.ke || e.Be || e.A !== undefined || e.Le !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2530
2559
|
let t = context;
|
|
2531
2560
|
if (t?.Je) t = t.et;
|
|
2532
2561
|
if (t && tracking) link(e, t);
|
|
2533
|
-
return !t || e.
|
|
2562
|
+
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2534
2563
|
}
|
|
2535
2564
|
|
|
2536
2565
|
function read(e) {
|
|
@@ -2538,7 +2567,7 @@ function read(e) {
|
|
|
2538
2567
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2539
2568
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2540
2569
|
// than the original node (which stays "pending" while held in a transition).
|
|
2541
|
-
if (latestReadActive) return GlobalQueue.
|
|
2570
|
+
if (latestReadActive) return GlobalQueue.de(e);
|
|
2542
2571
|
let t = context;
|
|
2543
2572
|
if (t?.Je) t = t.et;
|
|
2544
2573
|
const n = e;
|
|
@@ -2548,13 +2577,13 @@ function read(e) {
|
|
|
2548
2577
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2549
2578
|
// recompute don't collect into the probe.
|
|
2550
2579
|
if (pendingCheckActive) {
|
|
2551
|
-
GlobalQueue.
|
|
2580
|
+
GlobalQueue.Se(e, t, i, r);
|
|
2552
2581
|
} else if (typeof n.ke === "function") {
|
|
2553
2582
|
prepareComputed(e, false);
|
|
2554
2583
|
}
|
|
2555
|
-
if (!n.ke && i === e && e.A === undefined && e.
|
|
2584
|
+
if (!n.ke && i === e && e.A === undefined && e.Le === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2556
2585
|
if (t && tracking) link(e, t);
|
|
2557
|
-
return !t || e.
|
|
2586
|
+
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2558
2587
|
}
|
|
2559
2588
|
if (t && tracking) {
|
|
2560
2589
|
link(e, t, pendingCheckActive);
|
|
@@ -2567,47 +2596,47 @@ function read(e) {
|
|
|
2567
2596
|
}
|
|
2568
2597
|
const r = i.ze;
|
|
2569
2598
|
// parent check is shallow, might need to be recursive
|
|
2570
|
-
if (r >= t.ze && e.
|
|
2599
|
+
if (r >= t.ze && e.Z !== t) {
|
|
2571
2600
|
t.ze = r + 1;
|
|
2572
2601
|
}
|
|
2573
2602
|
}
|
|
2574
2603
|
}
|
|
2575
|
-
if (i.
|
|
2604
|
+
if (i.xe & STATUS_PENDING) {
|
|
2576
2605
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2577
2606
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2578
2607
|
// is installed): under a lane, only same-lane pending async without an
|
|
2579
2608
|
// active override throws.
|
|
2580
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2609
|
+
if (currentOptimisticLane === null || GlobalQueue.Pe(i)) {
|
|
2581
2610
|
if (!tracking && e !== t) link(e, t);
|
|
2582
|
-
throw i.
|
|
2611
|
+
throw i.me;
|
|
2583
2612
|
}
|
|
2584
|
-
} else if (t && i !== e && i.
|
|
2613
|
+
} else if (t && i !== e && i.xe & STATUS_UNINITIALIZED) {
|
|
2585
2614
|
if (!tracking && e !== t) link(e, t);
|
|
2586
|
-
throw i.
|
|
2587
|
-
} else if (!t && i.
|
|
2588
|
-
throw i.
|
|
2615
|
+
throw i.me;
|
|
2616
|
+
} else if (!t && i.xe & STATUS_UNINITIALIZED) {
|
|
2617
|
+
throw i.me;
|
|
2589
2618
|
}
|
|
2590
2619
|
}
|
|
2591
2620
|
// `owner` is the computed itself, or the firewall behind a store node —
|
|
2592
2621
|
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
2593
2622
|
// an errored derive throws for every late reader instead of silently
|
|
2594
2623
|
// serving node values (the seed, or last-good data after a failed refetch).
|
|
2595
|
-
if (i.ke && i.
|
|
2624
|
+
if (i.ke && i.xe & STATUS_ERROR) {
|
|
2596
2625
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2597
2626
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2598
2627
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2599
2628
|
// - owner._time < clock: only on a later cycle than the one the error was found
|
|
2600
|
-
if (tracking && !pendingCheckActive && i.
|
|
2629
|
+
if (tracking && !pendingCheckActive && i.H < clock) {
|
|
2601
2630
|
recompute(i);
|
|
2602
2631
|
return read(e);
|
|
2603
|
-
} else throw i.
|
|
2632
|
+
} else throw i.me;
|
|
2604
2633
|
}
|
|
2605
2634
|
if (snapshotCaptureActive && t && t.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2606
|
-
const n = e.
|
|
2635
|
+
const n = e.Le;
|
|
2607
2636
|
if (n !== undefined) {
|
|
2608
2637
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2609
|
-
const i = e.
|
|
2610
|
-
if (i !== r) t.
|
|
2638
|
+
const i = e.k !== NOT_PENDING ? e.k : e.We;
|
|
2639
|
+
if (i !== r) t.D |= REACTIVE_SNAPSHOT_STALE;
|
|
2611
2640
|
return r;
|
|
2612
2641
|
}
|
|
2613
2642
|
}
|
|
@@ -2622,18 +2651,18 @@ function read(e) {
|
|
|
2622
2651
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2623
2652
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2624
2653
|
// engine — a non-null lane implies it is installed.)
|
|
2625
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2654
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.ye(e, i, t)) {
|
|
2626
2655
|
return e.We;
|
|
2627
2656
|
}
|
|
2628
2657
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2629
2658
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2630
2659
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2631
2660
|
// (The lane-context clause lives with the engine.)
|
|
2632
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2661
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.Ce(e, i, t) || e.k === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.We : e.k;
|
|
2633
2662
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2634
2663
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2635
|
-
if (pendingCheckActive) GlobalQueue.
|
|
2636
|
-
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.
|
|
2664
|
+
if (pendingCheckActive) GlobalQueue.Te(e, o);
|
|
2665
|
+
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.xe & STATUS_PENDING) && !e.U) {
|
|
2637
2666
|
unobserved(e);
|
|
2638
2667
|
}
|
|
2639
2668
|
return o;
|
|
@@ -2645,20 +2674,20 @@ function setSignal(e, t) {
|
|
|
2645
2674
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2646
2675
|
// _overrideValue slot, and every module that creates one installs the
|
|
2647
2676
|
// engine first.
|
|
2648
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2649
|
-
const n = e.
|
|
2677
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.pe(e, t);
|
|
2678
|
+
const n = e.k === NOT_PENDING ? e.We : e.k;
|
|
2650
2679
|
if (typeof t === "function") t = t(n);
|
|
2651
2680
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2652
2681
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2653
|
-
const r = !!(e.
|
|
2682
|
+
const r = !!(e.xe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(n, t);
|
|
2654
2683
|
if (!r) return t;
|
|
2655
|
-
if (e.
|
|
2656
|
-
e.
|
|
2684
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2685
|
+
e.k = t;
|
|
2657
2686
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2658
2687
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
2659
2688
|
// only ever created, never removed, and creating one installs the hook).
|
|
2660
|
-
(e._ !== undefined || e.R !== undefined) && GlobalQueue.
|
|
2661
|
-
e.
|
|
2689
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.ae !== null && GlobalQueue.ae(e, t);
|
|
2690
|
+
e.H = clock;
|
|
2662
2691
|
insertSubs(e);
|
|
2663
2692
|
schedule();
|
|
2664
2693
|
return t;
|
|
@@ -2672,11 +2701,11 @@ function setSignal(e, t) {
|
|
|
2672
2701
|
* cleanup point.
|
|
2673
2702
|
*/ function suppressComputedRecompute(e) {
|
|
2674
2703
|
deleteFromHeap(e, queueFor(e));
|
|
2675
|
-
if (!(e.
|
|
2704
|
+
if (!(e.D & REACTIVE_MANUAL_WRITE) && e.k === NOT_PENDING) {
|
|
2676
2705
|
queuePendingNode(e);
|
|
2677
2706
|
schedule();
|
|
2678
2707
|
}
|
|
2679
|
-
e.
|
|
2708
|
+
e.D = e.D & -4 | REACTIVE_MANUAL_WRITE;
|
|
2680
2709
|
}
|
|
2681
2710
|
|
|
2682
2711
|
/**
|
|
@@ -2755,7 +2784,7 @@ function staleValues(e, t = true) {
|
|
|
2755
2784
|
if (!t) {
|
|
2756
2785
|
return;
|
|
2757
2786
|
}
|
|
2758
|
-
if (typeof t.ke === "function" && !(t.
|
|
2787
|
+
if (typeof t.ke === "function" && !(t.D & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2759
2788
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2760
2789
|
// same question: mark it so the recompute classifies any resulting
|
|
2761
2790
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2763,11 +2792,11 @@ function staleValues(e, t = true) {
|
|
|
2763
2792
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2764
2793
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2765
2794
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2766
|
-
if (!(t.
|
|
2767
|
-
t.
|
|
2795
|
+
if (!(t.D & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2796
|
+
t.D |= REACTIVE_REASK;
|
|
2768
2797
|
armReaskClear();
|
|
2769
2798
|
}
|
|
2770
|
-
t.
|
|
2799
|
+
t.D = t.D & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2771
2800
|
insertIntoHeap(t, queueFor(t));
|
|
2772
2801
|
schedule();
|
|
2773
2802
|
}
|
|
@@ -2833,8 +2862,8 @@ function externalUntrack(e) {
|
|
|
2833
2862
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2834
2863
|
// `externalSourceConfig` truthiness checks.
|
|
2835
2864
|
function syncExternalHooks() {
|
|
2836
|
-
GlobalQueue.
|
|
2837
|
-
GlobalQueue.
|
|
2865
|
+
GlobalQueue.ue = externalSourceConfig ? wireExternalSource : null;
|
|
2866
|
+
GlobalQueue.le = externalSourceConfig ? externalUntrack : null;
|
|
2838
2867
|
}
|
|
2839
2868
|
|
|
2840
2869
|
function enableExternalSource(e) {
|
|
@@ -2943,7 +2972,7 @@ function isUndefined(e) {
|
|
|
2943
2972
|
const n = e.A !== NOT_PENDING;
|
|
2944
2973
|
const r = n ? unwrapOverride(e.A) : e.We;
|
|
2945
2974
|
if (typeof t === "function") t = t(r);
|
|
2946
|
-
const i = !!(e.
|
|
2975
|
+
const i = !!(e.xe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(r, t);
|
|
2947
2976
|
if (!i) {
|
|
2948
2977
|
// Same-value write with an active override still entangles the current
|
|
2949
2978
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2957,7 +2986,7 @@ function isUndefined(e) {
|
|
|
2957
2986
|
// No revert target is stashed: while the override is active every reader
|
|
2958
2987
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
2959
2988
|
// reverting is just dropping the override — _value is already correct.
|
|
2960
|
-
else globalQueue.
|
|
2989
|
+
else globalQueue.m.L.push(e);
|
|
2961
2990
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2962
2991
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2963
2992
|
// which a shared subscriber can merge across transactions (#2912).
|
|
@@ -2970,8 +2999,8 @@ function isUndefined(e) {
|
|
|
2970
2999
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2971
3000
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2972
3001
|
// neither companion present the call is a guaranteed no-op.
|
|
2973
|
-
(e._ !== undefined || e.R !== undefined) && GlobalQueue.
|
|
2974
|
-
e.
|
|
3002
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.ae !== null && GlobalQueue.ae(e, t);
|
|
3003
|
+
e.H = clock;
|
|
2975
3004
|
insertSubs(e, true);
|
|
2976
3005
|
schedule();
|
|
2977
3006
|
return t;
|
|
@@ -2982,9 +3011,9 @@ function isUndefined(e) {
|
|
|
2982
3011
|
* while one of its optimistic nodes holds an active override that is still
|
|
2983
3012
|
* pending on real (non-affects-sentinel) async.
|
|
2984
3013
|
*/ function transitionBlocked(e) {
|
|
2985
|
-
for (let t = 0; t < e.
|
|
2986
|
-
const n = e.
|
|
2987
|
-
if (hasActiveOverride(n) && "
|
|
3014
|
+
for (let t = 0; t < e.L.length; t++) {
|
|
3015
|
+
const n = e.L[t];
|
|
3016
|
+
if (hasActiveOverride(n) && "xe" in n && n.xe & STATUS_PENDING && n.me instanceof NotReadyError) {
|
|
2988
3017
|
return true;
|
|
2989
3018
|
}
|
|
2990
3019
|
}
|
|
@@ -3002,7 +3031,7 @@ function resolveOptimisticNodes(e) {
|
|
|
3002
3031
|
// Revert is a pure drop: there is no revert target to commit —
|
|
3003
3032
|
// override-covered authoritative values hold in _pendingValue and
|
|
3004
3033
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
3005
|
-
if (!(t.
|
|
3034
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
3006
3035
|
const r = t.A;
|
|
3007
3036
|
t.A = NOT_PENDING;
|
|
3008
3037
|
if (r !== NOT_PENDING && t.We !== unwrapOverride(r)) insertSubs(t, true);
|
|
@@ -3014,9 +3043,9 @@ function resolveOptimisticNodes(e) {
|
|
|
3014
3043
|
// transition that produced them (A19 — pending is a property of the data).
|
|
3015
3044
|
for (let n = 0; n < t; n++) {
|
|
3016
3045
|
const t = e[n];
|
|
3017
|
-
if (t._ || t.R) GlobalQueue.
|
|
3046
|
+
if (t._ || t.R) GlobalQueue.Ee(t);
|
|
3018
3047
|
const r = t.t;
|
|
3019
|
-
if (r && (r._ === t || r.R === t)) GlobalQueue.
|
|
3048
|
+
if (r && (r._ === t || r.R === t)) GlobalQueue.Ee(r);
|
|
3020
3049
|
}
|
|
3021
3050
|
e.splice(0, t);
|
|
3022
3051
|
}
|
|
@@ -3069,10 +3098,10 @@ function cleanupCompletedLanes(e) {
|
|
|
3069
3098
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
3070
3099
|
* is recorded for replay at commit.
|
|
3071
3100
|
*/ function gatedRead(e, t, n) {
|
|
3072
|
-
if (latestReadActive || e.
|
|
3101
|
+
if (latestReadActive || e.k === NOT_PENDING || e.ke || t !== e && !(t.D & REACTIVE_MANUAL_WRITE)) {
|
|
3073
3102
|
return false;
|
|
3074
3103
|
}
|
|
3075
|
-
activeTransition.
|
|
3104
|
+
activeTransition.q.add(n);
|
|
3076
3105
|
return true;
|
|
3077
3106
|
}
|
|
3078
3107
|
|
|
@@ -3080,7 +3109,19 @@ function cleanupCompletedLanes(e) {
|
|
|
3080
3109
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3081
3110
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
3082
3111
|
*/ function laneReadsCommitted(e, t, n) {
|
|
3083
|
-
|
|
3112
|
+
if (e.A !== undefined || !!e.i || !!(t.xe & STATUS_PENDING)) return true;
|
|
3113
|
+
if (t === e && stale && n.t !== e) {
|
|
3114
|
+
// The committed view can hide a same-tick ambient write (a lane member —
|
|
3115
|
+
// even just an isPending companion flip — puts the reader "under a lane"
|
|
3116
|
+
// against unrelated plain writes). With no transaction the write commits
|
|
3117
|
+
// at THIS flush's end with no re-delivery, so record the reader for
|
|
3118
|
+
// replay at commit — the same contract gatedRead provides when a
|
|
3119
|
+
// transaction is active (#2963). If a transaction forms mid-flush,
|
|
3120
|
+
// initTransition carries the recording over to it.
|
|
3121
|
+
if (e.k !== NOT_PENDING && activeTransition === null) globalQueue.m.q.add(n);
|
|
3122
|
+
return true;
|
|
3123
|
+
}
|
|
3124
|
+
return false;
|
|
3084
3125
|
}
|
|
3085
3126
|
|
|
3086
3127
|
/**
|
|
@@ -3091,10 +3132,10 @@ function cleanupCompletedLanes(e) {
|
|
|
3091
3132
|
if (t) return resolveLane(e) ?? null;
|
|
3092
3133
|
for (let t = e.Ke; t; t = t.Ye) {
|
|
3093
3134
|
const n = t.qe;
|
|
3094
|
-
if (n.
|
|
3135
|
+
if (n.D & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
3095
3136
|
const t = resolveLane(n);
|
|
3096
3137
|
if (t) {
|
|
3097
|
-
e.
|
|
3138
|
+
e.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
3098
3139
|
assignOrMergeLane(e, t);
|
|
3099
3140
|
return t;
|
|
3100
3141
|
}
|
|
@@ -3108,7 +3149,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3108
3149
|
if (t.o !== e) {
|
|
3109
3150
|
t.u.add(e);
|
|
3110
3151
|
e.i = t;
|
|
3111
|
-
GlobalQueue.
|
|
3152
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
3112
3153
|
}
|
|
3113
3154
|
}
|
|
3114
3155
|
|
|
@@ -3116,13 +3157,13 @@ function cleanupCompletedLanes(e) {
|
|
|
3116
3157
|
const t = resolveLane(e);
|
|
3117
3158
|
if (t) {
|
|
3118
3159
|
t.u.delete(e);
|
|
3119
|
-
GlobalQueue.
|
|
3160
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
3120
3161
|
}
|
|
3121
3162
|
}
|
|
3122
3163
|
|
|
3123
3164
|
function trackOptimisticStore(e) {
|
|
3124
3165
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
3125
|
-
globalQueue.
|
|
3166
|
+
globalQueue.m.V.add(e);
|
|
3126
3167
|
schedule();
|
|
3127
3168
|
}
|
|
3128
3169
|
|
|
@@ -3131,19 +3172,19 @@ function trackOptimisticStore(e) {
|
|
|
3131
3172
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
3132
3173
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
3133
3174
|
*/ function installOptimisticEngine() {
|
|
3134
|
-
if (GlobalQueue.
|
|
3135
|
-
GlobalQueue.
|
|
3136
|
-
GlobalQueue.
|
|
3137
|
-
GlobalQueue.
|
|
3138
|
-
GlobalQueue.
|
|
3139
|
-
GlobalQueue.
|
|
3140
|
-
GlobalQueue.
|
|
3141
|
-
GlobalQueue.
|
|
3142
|
-
GlobalQueue.
|
|
3143
|
-
GlobalQueue.
|
|
3144
|
-
GlobalQueue.
|
|
3145
|
-
GlobalQueue.
|
|
3146
|
-
GlobalQueue.
|
|
3175
|
+
if (GlobalQueue.pe !== null) return;
|
|
3176
|
+
GlobalQueue.pe = optimisticWrite;
|
|
3177
|
+
GlobalQueue.Ie = resolveOptimisticNodes;
|
|
3178
|
+
GlobalQueue.Ae = transitionBlocked;
|
|
3179
|
+
GlobalQueue.he = cleanupCompletedLanes;
|
|
3180
|
+
GlobalQueue.Ne = runLaneEffects;
|
|
3181
|
+
GlobalQueue.ye = gatedRead;
|
|
3182
|
+
GlobalQueue.Pe = laneSuspends;
|
|
3183
|
+
GlobalQueue.Ce = laneReadsCommitted;
|
|
3184
|
+
GlobalQueue.ge = recomputeLane;
|
|
3185
|
+
GlobalQueue.be = laneAsyncPending;
|
|
3186
|
+
GlobalQueue.De = laneAsyncSettled;
|
|
3187
|
+
GlobalQueue.we = trackOptimisticStore;
|
|
3147
3188
|
}
|
|
3148
3189
|
|
|
3149
3190
|
/**
|
|
@@ -3200,13 +3241,13 @@ function collectPendingSources(e) {
|
|
|
3200
3241
|
* (`_pendingObserver`) are skipped so an `isPending` wrapper memo never
|
|
3201
3242
|
* inherits the coverage it reports on.
|
|
3202
3243
|
*/ function markWalk(e, t) {
|
|
3203
|
-
if (e.
|
|
3244
|
+
if (e.W) return true;
|
|
3204
3245
|
// A real error outranks an inherited mark (A16/A24c): an errored node
|
|
3205
3246
|
// answers probes with its error, not a coverage verdict, and coverage does
|
|
3206
3247
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3207
3248
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3208
3249
|
// pending (the count check above), also matching.
|
|
3209
|
-
if (e.
|
|
3250
|
+
if (e.xe & STATUS_ERROR) return false;
|
|
3210
3251
|
if (t.has(e)) return false;
|
|
3211
3252
|
t.add(e);
|
|
3212
3253
|
const n = e.Be;
|
|
@@ -3216,7 +3257,7 @@ function collectPendingSources(e) {
|
|
|
3216
3257
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3217
3258
|
// latch a stale verdict on the companion.
|
|
3218
3259
|
const r = e;
|
|
3219
|
-
const i = r.
|
|
3260
|
+
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.ut : undefined;
|
|
3220
3261
|
if (i !== null) {
|
|
3221
3262
|
for (let e = r.Ke ?? null; e !== null; e = e.Ye) {
|
|
3222
3263
|
if (!e._t && markWalk(e.qe, t)) return true;
|
|
@@ -3239,12 +3280,12 @@ function quietPending(e) {
|
|
|
3239
3280
|
}
|
|
3240
3281
|
|
|
3241
3282
|
function newQuestionInFlight(e) {
|
|
3242
|
-
return !!(e.
|
|
3283
|
+
return !!(e.xe & STATUS_PENDING) && !(e.xe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3243
3284
|
}
|
|
3244
3285
|
|
|
3245
3286
|
function computePendingState(e) {
|
|
3246
3287
|
const t = e;
|
|
3247
|
-
if (t.
|
|
3288
|
+
if (t.D & REACTIVE_DISPOSED) return false;
|
|
3248
3289
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3249
3290
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3250
3291
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
@@ -3255,11 +3296,11 @@ function computePendingState(e) {
|
|
|
3255
3296
|
const n = t.Be || t;
|
|
3256
3297
|
return newQuestionInFlight(n);
|
|
3257
3298
|
}
|
|
3258
|
-
if (n && e.
|
|
3259
|
-
return !!(n.
|
|
3299
|
+
if (n && e.k !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3300
|
+
return !!(n.D & REACTIVE_MANUAL_WRITE) || !n.lt && !(n.xe & STATUS_PENDING) || !!(n.xe & STATUS_PENDING) && quietPending(n);
|
|
3260
3301
|
}
|
|
3261
|
-
if (e.
|
|
3262
|
-
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.
|
|
3302
|
+
if (e.k !== NOT_PENDING && !(t.xe & STATUS_UNINITIALIZED)) {
|
|
3303
|
+
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.k, unwrapOverride(e.A));
|
|
3263
3304
|
return true;
|
|
3264
3305
|
}
|
|
3265
3306
|
return newQuestionInFlight(t);
|
|
@@ -3298,7 +3339,7 @@ function updateChildCompanions(e) {
|
|
|
3298
3339
|
if (r.has(e)) return;
|
|
3299
3340
|
r.add(e);
|
|
3300
3341
|
if (e._ || e.R) n(e);
|
|
3301
|
-
for (let t = e.
|
|
3342
|
+
for (let t = e.U; t !== null; t = t.Ge) visit(t.Ve);
|
|
3302
3343
|
for (let t = e.rt ?? null; t !== null; t = t.it) {
|
|
3303
3344
|
visit(t);
|
|
3304
3345
|
}
|
|
@@ -3310,18 +3351,18 @@ function snapCompanionsToState(e) {
|
|
|
3310
3351
|
const t = e._;
|
|
3311
3352
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3312
3353
|
const n = computePendingState(e);
|
|
3313
|
-
if (t.We !== n || t.
|
|
3354
|
+
if (t.We !== n || t.k !== NOT_PENDING) {
|
|
3314
3355
|
t.We = n;
|
|
3315
|
-
t.
|
|
3316
|
-
t.
|
|
3356
|
+
t.k = NOT_PENDING;
|
|
3357
|
+
t.H = clock;
|
|
3317
3358
|
insertSubs(t);
|
|
3318
3359
|
schedule();
|
|
3319
3360
|
}
|
|
3320
3361
|
}
|
|
3321
3362
|
const n = e.R;
|
|
3322
|
-
if (n && !(n.
|
|
3323
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.
|
|
3324
|
-
n.
|
|
3363
|
+
if (n && !(n.D & REACTIVE_DISPOSED)) {
|
|
3364
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.k === NOT_PENDING && !Object.is(n.We, e.We) && !(n.D & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3365
|
+
n.D |= REACTIVE_DIRTY;
|
|
3325
3366
|
insertIntoHeap(n, queueFor(n));
|
|
3326
3367
|
insertSubs(n);
|
|
3327
3368
|
schedule();
|
|
@@ -3362,18 +3403,18 @@ function getLatestValueComputed(e) {
|
|
|
3362
3403
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3363
3404
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3364
3405
|
const e = queueFor(t);
|
|
3365
|
-
if (t.ze >= e.P && !(t.
|
|
3406
|
+
if (t.ze >= e.P && !(t.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3366
3407
|
markHeap(e);
|
|
3367
3408
|
prepareComputed(t, true);
|
|
3368
3409
|
}
|
|
3369
3410
|
i = read(t);
|
|
3370
3411
|
} catch (t) {
|
|
3371
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3412
|
+
if (t instanceof NotReadyError && (!context || !(e.xe & STATUS_UNINITIALIZED))) return r;
|
|
3372
3413
|
throw t;
|
|
3373
3414
|
} finally {
|
|
3374
3415
|
setLatestReadActive(n);
|
|
3375
3416
|
}
|
|
3376
|
-
if (t.
|
|
3417
|
+
if (t.xe & STATUS_PENDING) return r;
|
|
3377
3418
|
if (stale && currentOptimisticLane && t.i) {
|
|
3378
3419
|
const e = findLane(t.i);
|
|
3379
3420
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3385,18 +3426,18 @@ function getLatestValueComputed(e) {
|
|
|
3385
3426
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
3386
3427
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
3387
3428
|
// other transition's committed view, matching read()'s own selection.
|
|
3388
|
-
if (t.
|
|
3429
|
+
if (t.k !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.T && activeTransition !== t.T)) return t.k;
|
|
3389
3430
|
return i;
|
|
3390
3431
|
}
|
|
3391
3432
|
|
|
3392
3433
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3393
3434
|
setPendingCheckActive(false);
|
|
3394
3435
|
if (typeof e.ke === "function") prepareComputed(e, true);
|
|
3395
|
-
const i = n.
|
|
3436
|
+
const i = n.xe;
|
|
3396
3437
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3397
3438
|
if (tracking && e !== t) link(e, t);
|
|
3398
3439
|
setPendingCheckActive(true);
|
|
3399
|
-
throw n.
|
|
3440
|
+
throw n.me;
|
|
3400
3441
|
}
|
|
3401
3442
|
collectPendingSources(e);
|
|
3402
3443
|
if (r) collectPendingSources(r);
|
|
@@ -3404,11 +3445,11 @@ function getLatestValueComputed(e) {
|
|
|
3404
3445
|
}
|
|
3405
3446
|
|
|
3406
3447
|
function recordFreshRead(e, t) {
|
|
3407
|
-
if (pendingProbe !== null && e.
|
|
3448
|
+
if (pendingProbe !== null && e.k !== NOT_PENDING && t === e.k) pendingProbe.freshReads.add(e);
|
|
3408
3449
|
}
|
|
3409
3450
|
|
|
3410
3451
|
function applyReask(e, t) {
|
|
3411
|
-
const n = !!(e.
|
|
3452
|
+
const n = !!(e.xe & STATUS_PENDING);
|
|
3412
3453
|
const r = t && !(n && !e.Nt);
|
|
3413
3454
|
const i = n && e.Nt !== r;
|
|
3414
3455
|
e.Nt = r;
|
|
@@ -3451,7 +3492,7 @@ function isPending(e) {
|
|
|
3451
3492
|
} catch (e) {
|
|
3452
3493
|
collectPending();
|
|
3453
3494
|
if (e instanceof NotReadyError) {
|
|
3454
|
-
const t = !!(e.source?.
|
|
3495
|
+
const t = !!(e.source?.xe & STATUS_UNINITIALIZED);
|
|
3455
3496
|
if (r.found && !t) return true;
|
|
3456
3497
|
if (context && t) throw e;
|
|
3457
3498
|
}
|
|
@@ -3465,25 +3506,25 @@ function isPending(e) {
|
|
|
3465
3506
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3466
3507
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3467
3508
|
// direct calls used, so behavior is identical once this module loads.
|
|
3468
|
-
GlobalQueue.
|
|
3509
|
+
GlobalQueue.ae = syncCompanions;
|
|
3469
3510
|
|
|
3470
|
-
GlobalQueue.
|
|
3511
|
+
GlobalQueue.ce = updatePendingSignal;
|
|
3471
3512
|
|
|
3472
|
-
GlobalQueue.
|
|
3513
|
+
GlobalQueue.fe = updateChildCompanions;
|
|
3473
3514
|
|
|
3474
|
-
GlobalQueue.
|
|
3515
|
+
GlobalQueue.Ee = snapCompanionsToState;
|
|
3475
3516
|
|
|
3476
|
-
GlobalQueue.
|
|
3517
|
+
GlobalQueue.de = latestRead;
|
|
3477
3518
|
|
|
3478
|
-
GlobalQueue.
|
|
3519
|
+
GlobalQueue.Se = pendingCheckRead;
|
|
3479
3520
|
|
|
3480
|
-
GlobalQueue.
|
|
3521
|
+
GlobalQueue.Te = recordFreshRead;
|
|
3481
3522
|
|
|
3482
|
-
GlobalQueue.
|
|
3523
|
+
GlobalQueue.Oe = applyReask;
|
|
3483
3524
|
|
|
3484
|
-
GlobalQueue.
|
|
3525
|
+
GlobalQueue._e = repollDownstreamVerdicts;
|
|
3485
3526
|
|
|
3486
|
-
GlobalQueue.
|
|
3527
|
+
GlobalQueue.Re = witnessAffects;
|
|
3487
3528
|
|
|
3488
3529
|
/**
|
|
3489
3530
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3498,8 +3539,8 @@ GlobalQueue._e = witnessAffects;
|
|
|
3498
3539
|
|
|
3499
3540
|
function notifyEffectStatus(e, t) {
|
|
3500
3541
|
// Use passed values if provided, otherwise read from node
|
|
3501
|
-
const n = e !== undefined ? e : this.
|
|
3502
|
-
const r = t !== undefined ? t : this.
|
|
3542
|
+
const n = e !== undefined ? e : this.xe;
|
|
3543
|
+
const r = t !== undefined ? t : this.me;
|
|
3503
3544
|
if (n & STATUS_ERROR) {
|
|
3504
3545
|
this.Ze.notify(this, STATUS_PENDING, 0);
|
|
3505
3546
|
if (this.Fe === EFFECT_USER) {
|
|
@@ -3512,8 +3553,8 @@ function notifyEffectStatus(e, t) {
|
|
|
3512
3553
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3513
3554
|
// `status` arg without node-state writes) don't queue: the status
|
|
3514
3555
|
// re-propagates unblocked at commit.
|
|
3515
|
-
if (this.
|
|
3516
|
-
this.
|
|
3556
|
+
if (this.xe & STATUS_ERROR) {
|
|
3557
|
+
this.Qe = true;
|
|
3517
3558
|
this.Ze.enqueue(this.Fe, this.Ct ??= runEffect.bind(null, this));
|
|
3518
3559
|
}
|
|
3519
3560
|
return;
|
|
@@ -3528,7 +3569,7 @@ function notifyEffectStatus(e, t) {
|
|
|
3528
3569
|
}
|
|
3529
3570
|
|
|
3530
3571
|
function runEffect(e) {
|
|
3531
|
-
if (!e.
|
|
3572
|
+
if (!e.Qe || e.D & REACTIVE_DISPOSED) return;
|
|
3532
3573
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3533
3574
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3534
3575
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3539,10 +3580,10 @@ function runEffect(e) {
|
|
|
3539
3580
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3540
3581
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3541
3582
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3542
|
-
if (e.
|
|
3543
|
-
const t = unwrapStatusError(e.
|
|
3583
|
+
if (e.xe & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3584
|
+
const t = unwrapStatusError(e.me);
|
|
3544
3585
|
e.bt = e.We;
|
|
3545
|
-
e.
|
|
3586
|
+
e.Qe = false;
|
|
3546
3587
|
try {
|
|
3547
3588
|
e.wt ? e.wt(t, () => {
|
|
3548
3589
|
const t = e.Et;
|
|
@@ -3566,19 +3607,19 @@ function runEffect(e) {
|
|
|
3566
3607
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3567
3608
|
e.Et = n;
|
|
3568
3609
|
} catch (t) {
|
|
3569
|
-
e.
|
|
3570
|
-
e.
|
|
3610
|
+
e.me = new StatusError(e, t);
|
|
3611
|
+
e.xe |= STATUS_ERROR;
|
|
3571
3612
|
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3572
3613
|
haltReactivity(t);
|
|
3573
3614
|
throw t;
|
|
3574
3615
|
}
|
|
3575
3616
|
} finally {
|
|
3576
3617
|
e.bt = e.We;
|
|
3577
|
-
e.
|
|
3618
|
+
e.Qe = false;
|
|
3578
3619
|
}
|
|
3579
3620
|
}
|
|
3580
3621
|
|
|
3581
|
-
GlobalQueue.
|
|
3622
|
+
GlobalQueue.te = runEffect;
|
|
3582
3623
|
|
|
3583
3624
|
/**
|
|
3584
3625
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3586,9 +3627,9 @@ GlobalQueue.ee = runEffect;
|
|
|
3586
3627
|
* Uses stale reads.
|
|
3587
3628
|
*/ function trackedEffect(e, t) {
|
|
3588
3629
|
const run = () => {
|
|
3589
|
-
if (!n.
|
|
3630
|
+
if (!n.Qe || n.D & REACTIVE_DISPOSED) return;
|
|
3590
3631
|
try {
|
|
3591
|
-
n.
|
|
3632
|
+
n.Qe = false;
|
|
3592
3633
|
recompute(n);
|
|
3593
3634
|
} finally {}
|
|
3594
3635
|
};
|
|
@@ -3604,13 +3645,13 @@ GlobalQueue.ee = runEffect;
|
|
|
3604
3645
|
});
|
|
3605
3646
|
n.Et = undefined;
|
|
3606
3647
|
n.Ue = n.Ue & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3607
|
-
n.
|
|
3648
|
+
n.Qe = true;
|
|
3608
3649
|
n.Fe = EFFECT_TRACKED;
|
|
3609
3650
|
n.yt = (e, t) => {
|
|
3610
|
-
const r = e !== undefined ? e : n.
|
|
3651
|
+
const r = e !== undefined ? e : n.xe;
|
|
3611
3652
|
if (r & STATUS_ERROR) {
|
|
3612
3653
|
n.Ze.notify(n, STATUS_PENDING, 0);
|
|
3613
|
-
const e = t !== undefined ? t : n.
|
|
3654
|
+
const e = t !== undefined ? t : n.me;
|
|
3614
3655
|
if (!n.Ze.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3615
3656
|
haltReactivity(unwrapStatusError(e));
|
|
3616
3657
|
throw e;
|
|
@@ -3695,11 +3736,11 @@ function restoreTransition(e, t) {
|
|
|
3695
3736
|
const i = e(...t);
|
|
3696
3737
|
globalQueue.initTransition();
|
|
3697
3738
|
let o = activeTransition;
|
|
3698
|
-
o
|
|
3739
|
+
o.j.push(i);
|
|
3699
3740
|
const done = (e, t, s = false) => {
|
|
3700
3741
|
o = currentTransition(o);
|
|
3701
|
-
const u = o
|
|
3702
|
-
if (u >= 0) o
|
|
3742
|
+
const u = o.j.indexOf(i);
|
|
3743
|
+
if (u >= 0) o.j.splice(u, 1);
|
|
3703
3744
|
// Re-adopt through initTransition like every other resumption site:
|
|
3704
3745
|
// a bare setActiveTransition leaves globalQueue._batch as a detached
|
|
3705
3746
|
// ambient batch, and anything registered before the scheduled flush
|
|
@@ -4016,7 +4057,7 @@ function createEffect(e, t, n) {
|
|
|
4016
4057
|
// route through the inherited queue.
|
|
4017
4058
|
const i = getOwner();
|
|
4018
4059
|
const o = new MicrotaskQueue;
|
|
4019
|
-
o.
|
|
4060
|
+
o.Z = i.Ze;
|
|
4020
4061
|
// notify() forwards up the normal chain
|
|
4021
4062
|
i.Ze = o;
|
|
4022
4063
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
@@ -5287,7 +5328,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
5287
5328
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
5288
5329
|
* override, else held pending value, else committed value.
|
|
5289
5330
|
*/ function visibleNodeValue(e) {
|
|
5290
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
5331
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.k !== NOT_PENDING ? e.k : e.We;
|
|
5291
5332
|
}
|
|
5292
5333
|
|
|
5293
5334
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -5342,7 +5383,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5342
5383
|
}
|
|
5343
5384
|
if (o && n in o) {
|
|
5344
5385
|
const e = o[n];
|
|
5345
|
-
s.
|
|
5386
|
+
s.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
5346
5387
|
snapshotSources?.add(s);
|
|
5347
5388
|
}
|
|
5348
5389
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -5371,8 +5412,8 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5371
5412
|
*/ function inheritAffectsMarks(e, t, n) {
|
|
5372
5413
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
5373
5414
|
for (const [r, i] of affectsScopes) {
|
|
5374
|
-
if (r.
|
|
5375
|
-
GlobalQueue.
|
|
5415
|
+
if (r.W && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
5416
|
+
GlobalQueue.oe(e);
|
|
5376
5417
|
i.inherited.push(e);
|
|
5377
5418
|
}
|
|
5378
5419
|
}
|
|
@@ -5460,11 +5501,11 @@ i) {
|
|
|
5460
5501
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
5461
5502
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
5462
5503
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
5463
|
-
if (n?.
|
|
5504
|
+
if (n?.W) GlobalQueue.Re(n);
|
|
5464
5505
|
if (affectsScopes.size) {
|
|
5465
5506
|
const r = e[STORE_VALUE];
|
|
5466
5507
|
for (const [e, i] of affectsScopes) {
|
|
5467
|
-
if (e !== n && e.
|
|
5508
|
+
if (e !== n && e.W && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.Re(e);
|
|
5468
5509
|
}
|
|
5469
5510
|
}
|
|
5470
5511
|
}
|
|
@@ -5481,11 +5522,11 @@ i) {
|
|
|
5481
5522
|
* @internal
|
|
5482
5523
|
*/ function getStoreAffectsNodes(e, t) {
|
|
5483
5524
|
const n = getNodes(e, STORE_NODE);
|
|
5484
|
-
GlobalQueue.
|
|
5525
|
+
GlobalQueue.re ||= e => {
|
|
5485
5526
|
const t = affectsScopes.get(e);
|
|
5486
5527
|
if (!t) return;
|
|
5487
5528
|
affectsScopes.delete(e);
|
|
5488
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
5529
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.se(t.inherited[e]);
|
|
5489
5530
|
};
|
|
5490
5531
|
if (t === undefined) {
|
|
5491
5532
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -5612,7 +5653,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5612
5653
|
}
|
|
5613
5654
|
const r = e[STORE_VALUE];
|
|
5614
5655
|
const i = r[n];
|
|
5615
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5656
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.xe ?? 0) & STATUS_PENDING)) {
|
|
5616
5657
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5617
5658
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5618
5659
|
snapshotSources?.add(e);
|
|
@@ -5640,7 +5681,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5640
5681
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5641
5682
|
// optimistic engine before wrapping.
|
|
5642
5683
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5643
|
-
GlobalQueue.
|
|
5684
|
+
GlobalQueue.we(t);
|
|
5644
5685
|
}
|
|
5645
5686
|
}
|
|
5646
5687
|
|
|
@@ -5735,8 +5776,8 @@ let Writing = null;
|
|
|
5735
5776
|
*/ function throwIfUnreadable(e) {
|
|
5736
5777
|
const t = e[STORE_FIREWALL];
|
|
5737
5778
|
if (!t) return;
|
|
5738
|
-
const n = t.
|
|
5739
|
-
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.
|
|
5779
|
+
const n = t.xe;
|
|
5780
|
+
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.me ?? new NotReadyError(t);
|
|
5740
5781
|
}
|
|
5741
5782
|
|
|
5742
5783
|
const storeTraps = {
|
|
@@ -6082,7 +6123,7 @@ function createStore(e, t, n) {
|
|
|
6082
6123
|
* nothing is stored downstream and nothing can be stranded or stripped by
|
|
6083
6124
|
* mid-window recomputes.
|
|
6084
6125
|
*/ function markAffects(e) {
|
|
6085
|
-
e.
|
|
6126
|
+
e.W = (e.W || 0) + 1;
|
|
6086
6127
|
shiftAffectsMarks(1);
|
|
6087
6128
|
}
|
|
6088
6129
|
|
|
@@ -6098,9 +6139,9 @@ function createStore(e, t, n) {
|
|
|
6098
6139
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
6099
6140
|
* no visual change.
|
|
6100
6141
|
*/ function notifyMarkBoundaries(e) {
|
|
6101
|
-
if (!e.
|
|
6142
|
+
if (!e.U && !e.rt) return;
|
|
6102
6143
|
const t = new NotReadyError(e);
|
|
6103
|
-
t.
|
|
6144
|
+
t.ve = true;
|
|
6104
6145
|
const n = new Set;
|
|
6105
6146
|
const visit = e => {
|
|
6106
6147
|
if (n.has(e)) return;
|
|
@@ -6126,10 +6167,10 @@ function createStore(e, t, n) {
|
|
|
6126
6167
|
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
6127
6168
|
*/ function registerAffectsMark(e) {
|
|
6128
6169
|
markAffects(e);
|
|
6129
|
-
globalQueue.
|
|
6170
|
+
globalQueue.m.G.push(e);
|
|
6130
6171
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
6131
6172
|
// without them there is no materialized verdict to poke.
|
|
6132
|
-
GlobalQueue.
|
|
6173
|
+
GlobalQueue._e !== null && GlobalQueue._e(e);
|
|
6133
6174
|
notifyMarkBoundaries(e);
|
|
6134
6175
|
schedule();
|
|
6135
6176
|
}
|
|
@@ -6141,10 +6182,10 @@ function createStore(e, t, n) {
|
|
|
6141
6182
|
* setSignal would open a fresh override window that nothing settles).
|
|
6142
6183
|
*/ function releaseAffectsMark(e) {
|
|
6143
6184
|
shiftAffectsMarks(-1);
|
|
6144
|
-
e.
|
|
6145
|
-
if (!e.
|
|
6146
|
-
GlobalQueue.
|
|
6147
|
-
GlobalQueue.
|
|
6185
|
+
e.W--;
|
|
6186
|
+
if (!e.W) {
|
|
6187
|
+
GlobalQueue._e !== null && GlobalQueue._e(e, true);
|
|
6188
|
+
GlobalQueue.re?.(e);
|
|
6148
6189
|
}
|
|
6149
6190
|
}
|
|
6150
6191
|
|
|
@@ -6161,11 +6202,11 @@ function createStore(e, t, n) {
|
|
|
6161
6202
|
// Each call site is gated by state only this module creates (a non-empty
|
|
6162
6203
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
6163
6204
|
// hooks are installed before the first time any of them can fire.
|
|
6164
|
-
GlobalQueue.
|
|
6205
|
+
GlobalQueue.ie = releaseAffectsMarks;
|
|
6165
6206
|
|
|
6166
|
-
GlobalQueue.
|
|
6207
|
+
GlobalQueue.oe = markAffects;
|
|
6167
6208
|
|
|
6168
|
-
GlobalQueue.
|
|
6209
|
+
GlobalQueue.se = releaseAffectsMark;
|
|
6169
6210
|
|
|
6170
6211
|
function affects(e, t) {
|
|
6171
6212
|
const n = e?.[$TARGET];
|
|
@@ -6186,8 +6227,8 @@ function createOptimisticStore(e, t, n) {
|
|
|
6186
6227
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
6187
6228
|
// node can be created.
|
|
6188
6229
|
installOptimisticEngine();
|
|
6189
|
-
if (!GlobalQueue.
|
|
6190
|
-
GlobalQueue.
|
|
6230
|
+
if (!GlobalQueue.ne) {
|
|
6231
|
+
GlobalQueue.ne = clearOptimisticStores;
|
|
6191
6232
|
// Store half of the engine's override blockage (#2951): signal-form
|
|
6192
6233
|
// createOptimistic carries the pending async and the override on ONE node,
|
|
6193
6234
|
// so transitionBlocked sees both; a derived optimistic STORE splits them —
|
|
@@ -6198,10 +6239,10 @@ function createOptimisticStore(e, t, n) {
|
|
|
6198
6239
|
// clobbering instead of composing). Optimistic state clears when truth
|
|
6199
6240
|
// lands or its transaction ends — never mid-refetch. Wrapped here (engine
|
|
6200
6241
|
// is already installed above) so store-free apps never carry the check.
|
|
6201
|
-
const e = GlobalQueue.
|
|
6202
|
-
GlobalQueue.
|
|
6203
|
-
for (const e of t.
|
|
6204
|
-
if ((e[$TARGET]?.[STORE_FIREWALL]?.
|
|
6242
|
+
const e = GlobalQueue.Ae;
|
|
6243
|
+
GlobalQueue.Ae = t => {
|
|
6244
|
+
for (const e of t.V) {
|
|
6245
|
+
if ((e[$TARGET]?.[STORE_FIREWALL]?.xe ?? 0) & STATUS_PENDING) return true;
|
|
6205
6246
|
}
|
|
6206
6247
|
return e(t);
|
|
6207
6248
|
};
|
|
@@ -6285,7 +6326,7 @@ function clearOptimisticStores(e, t) {
|
|
|
6285
6326
|
const o = visibleNodeValue(a);
|
|
6286
6327
|
a.A = NOT_PENDING;
|
|
6287
6328
|
a.p = null;
|
|
6288
|
-
a.
|
|
6329
|
+
a.k = NOT_PENDING;
|
|
6289
6330
|
a.We = i;
|
|
6290
6331
|
if (!a.ht || !a.ht(o, i)) {
|
|
6291
6332
|
insertSubs(a, true);
|
|
@@ -6798,8 +6839,8 @@ function mapArray(e, t, n) {
|
|
|
6798
6839
|
kt: [],
|
|
6799
6840
|
Wt: [],
|
|
6800
6841
|
Ft: r,
|
|
6801
|
-
|
|
6802
|
-
|
|
6842
|
+
Qt: r || n?.keyed === false ? [] : undefined,
|
|
6843
|
+
xt: i && n?.keyed !== false ? [] : undefined,
|
|
6803
6844
|
Ht: n?.keyed === false,
|
|
6804
6845
|
Mt: n?.fallback
|
|
6805
6846
|
};
|
|
@@ -6832,14 +6873,14 @@ function updateKeyedMap() {
|
|
|
6832
6873
|
let n, r, i, o,
|
|
6833
6874
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6834
6875
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6835
|
-
s = this.
|
|
6876
|
+
s = this.Qt ? this.Ht ? () => {
|
|
6836
6877
|
i[r] = signal(e[r], pureOptions);
|
|
6837
6878
|
return this.Ut(accessor(i[r]), r);
|
|
6838
6879
|
} : () => {
|
|
6839
6880
|
i[r] = signal(e[r], pureOptions);
|
|
6840
6881
|
o && (o[r] = signal(r, pureOptions));
|
|
6841
6882
|
return this.Ut(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6842
|
-
} : this.
|
|
6883
|
+
} : this.xt ? () => {
|
|
6843
6884
|
const t = e[r];
|
|
6844
6885
|
o[r] = signal(r, pureOptions);
|
|
6845
6886
|
return this.Ut(t, accessor(o[r]));
|
|
@@ -6855,8 +6896,8 @@ function updateKeyedMap() {
|
|
|
6855
6896
|
this.Vt = [];
|
|
6856
6897
|
this.kt = [];
|
|
6857
6898
|
this.Lt = 0;
|
|
6858
|
-
this.xt && (this.xt = []);
|
|
6859
6899
|
this.Qt && (this.Qt = []);
|
|
6900
|
+
this.xt && (this.xt = []);
|
|
6860
6901
|
}
|
|
6861
6902
|
if (this.Mt && !this.kt[0]) {
|
|
6862
6903
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
@@ -6869,8 +6910,8 @@ function updateKeyedMap() {
|
|
|
6869
6910
|
else if (this.Lt === 0) {
|
|
6870
6911
|
const u = new Array(t);
|
|
6871
6912
|
const l = new Array(t);
|
|
6872
|
-
i = this.
|
|
6873
|
-
o = this.
|
|
6913
|
+
i = this.Qt && new Array(t);
|
|
6914
|
+
o = this.xt && new Array(t);
|
|
6874
6915
|
try {
|
|
6875
6916
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6876
6917
|
} catch (e) {
|
|
@@ -6882,19 +6923,19 @@ function updateKeyedMap() {
|
|
|
6882
6923
|
// previous fallback
|
|
6883
6924
|
this.kt = u;
|
|
6884
6925
|
this.Wt = l;
|
|
6885
|
-
i && (this.
|
|
6886
|
-
o && (this.
|
|
6926
|
+
i && (this.Qt = i);
|
|
6927
|
+
o && (this.xt = o);
|
|
6887
6928
|
this.Vt = e.slice(0);
|
|
6888
6929
|
this.Lt = t;
|
|
6889
6930
|
} else {
|
|
6890
6931
|
let u, l, a, c, f, E, d, S, T;
|
|
6891
6932
|
// skip common prefix
|
|
6892
|
-
for (u = 0, l = Math.min(this.Lt, t); u < l && (this.Vt[u] === e[u] || this.
|
|
6893
|
-
if (this.
|
|
6933
|
+
for (u = 0, l = Math.min(this.Lt, t); u < l && (this.Vt[u] === e[u] || this.Qt && compare(this.Ft, this.Vt[u], e[u])); u++) {
|
|
6934
|
+
if (this.Qt) setSignal(this.Qt[u], e[u]);
|
|
6894
6935
|
}
|
|
6895
6936
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6896
6937
|
// at commit instead of being staged and copied twice
|
|
6897
|
-
for (l = this.Lt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.
|
|
6938
|
+
for (l = this.Lt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.Qt && compare(this.Ft, this.Vt[l], e[a])); l--,
|
|
6898
6939
|
a--) ;
|
|
6899
6940
|
// no structural change (every position matched in place at equal
|
|
6900
6941
|
// length — the common post-reconcile shape): keep the same mapped
|
|
@@ -6906,8 +6947,8 @@ function updateKeyedMap() {
|
|
|
6906
6947
|
const O = t - this.Lt;
|
|
6907
6948
|
const _ = new Array(t);
|
|
6908
6949
|
const R = new Array(t);
|
|
6909
|
-
i = this.
|
|
6910
|
-
o = this.
|
|
6950
|
+
i = this.Qt ? new Array(t) : undefined;
|
|
6951
|
+
o = this.xt ? new Array(t) : undefined;
|
|
6911
6952
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6912
6953
|
// scanning backwards so we encounter them in natural order
|
|
6913
6954
|
E = new Map;
|
|
@@ -6929,8 +6970,8 @@ function updateKeyedMap() {
|
|
|
6929
6970
|
if (r !== undefined && r !== -1) {
|
|
6930
6971
|
_[r] = this.kt[n];
|
|
6931
6972
|
R[r] = this.Wt[n];
|
|
6932
|
-
i && (i[r] = this.
|
|
6933
|
-
o && (o[r] = this.
|
|
6973
|
+
i && (i[r] = this.Qt[n]);
|
|
6974
|
+
o && (o[r] = this.xt[n]);
|
|
6934
6975
|
r = d[r];
|
|
6935
6976
|
E.set(f, r);
|
|
6936
6977
|
} else (S ??= []).push(this.Wt[n]);
|
|
@@ -6952,8 +6993,8 @@ function updateKeyedMap() {
|
|
|
6952
6993
|
for (n = 0; n < u; n++) {
|
|
6953
6994
|
_[n] = this.kt[n];
|
|
6954
6995
|
R[n] = this.Wt[n];
|
|
6955
|
-
i && (i[n] = this.
|
|
6956
|
-
o && (o[n] = this.
|
|
6996
|
+
i && (i[n] = this.Qt[n]);
|
|
6997
|
+
o && (o[n] = this.xt[n]);
|
|
6957
6998
|
}
|
|
6958
6999
|
for (r = u; r <= a; r++) {
|
|
6959
7000
|
if (i) setSignal(i[r], e[r]);
|
|
@@ -6963,18 +7004,18 @@ function updateKeyedMap() {
|
|
|
6963
7004
|
_[r] = this.kt[r - O];
|
|
6964
7005
|
R[r] = this.Wt[r - O];
|
|
6965
7006
|
if (i) {
|
|
6966
|
-
i[r] = this.
|
|
7007
|
+
i[r] = this.Qt[r - O];
|
|
6967
7008
|
setSignal(i[r], e[r]);
|
|
6968
7009
|
}
|
|
6969
7010
|
if (o) {
|
|
6970
|
-
o[r] = this.
|
|
7011
|
+
o[r] = this.xt[r - O];
|
|
6971
7012
|
if (O !== 0) setSignal(o[r], r);
|
|
6972
7013
|
}
|
|
6973
7014
|
}
|
|
6974
7015
|
this.kt = _;
|
|
6975
7016
|
this.Wt = R;
|
|
6976
|
-
i && (this.
|
|
6977
|
-
o && (this.
|
|
7017
|
+
i && (this.Qt = i);
|
|
7018
|
+
o && (this.xt = o);
|
|
6978
7019
|
this.Lt = t;
|
|
6979
7020
|
// save a copy of the mapped items for the next update
|
|
6980
7021
|
this.Vt = e.slice(0);
|
|
@@ -7089,12 +7130,12 @@ function boundaryComputed(e, t) {
|
|
|
7089
7130
|
});
|
|
7090
7131
|
n.yt = (e, t) => {
|
|
7091
7132
|
// Use passed values if provided, otherwise read from node
|
|
7092
|
-
const r = e !== undefined ? e : n.
|
|
7093
|
-
const i = t !== undefined ? t : n.
|
|
7133
|
+
const r = e !== undefined ? e : n.xe;
|
|
7134
|
+
const i = t !== undefined ? t : n.me;
|
|
7094
7135
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
7095
7136
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
7096
7137
|
// a boundary that handles it is found.
|
|
7097
|
-
n.
|
|
7138
|
+
n.xe &= ~n.Yt;
|
|
7098
7139
|
const o = n.Ze.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
7099
7140
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
7100
7141
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
@@ -7102,8 +7143,8 @@ function boundaryComputed(e, t) {
|
|
|
7102
7143
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
7103
7144
|
const s = r & ~n.Yt & (STATUS_PENDING | STATUS_ERROR);
|
|
7104
7145
|
if (s) {
|
|
7105
|
-
n.
|
|
7106
|
-
if (n.
|
|
7146
|
+
n.xe &= ~s;
|
|
7147
|
+
if (n.me === i && !(n.xe & (STATUS_PENDING | STATUS_ERROR))) n.me = undefined;
|
|
7107
7148
|
}
|
|
7108
7149
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
7109
7150
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -7306,7 +7347,7 @@ class CollectionQueue extends Queue {
|
|
|
7306
7347
|
ownedWrite: true,
|
|
7307
7348
|
gt: true
|
|
7308
7349
|
});
|
|
7309
|
-
|
|
7350
|
+
me;
|
|
7310
7351
|
Jt=signal(false, {
|
|
7311
7352
|
ownedWrite: true,
|
|
7312
7353
|
gt: true
|
|
@@ -7352,13 +7393,13 @@ class CollectionQueue extends Queue {
|
|
|
7352
7393
|
if (this.Tn & STATUS_PENDING && this.rn) return super.notify(e, t, n, r);
|
|
7353
7394
|
if (n & this.Tn) {
|
|
7354
7395
|
this.Zt = true;
|
|
7355
|
-
const t = r?.source || e.
|
|
7396
|
+
const t = r?.source || e.me?.source;
|
|
7356
7397
|
if (t) {
|
|
7357
7398
|
const e = this.Bt.size === 0;
|
|
7358
7399
|
this.Bt.add(t);
|
|
7359
7400
|
if (e) setSignal(this.zt, true);
|
|
7360
7401
|
if (this.Tn & STATUS_ERROR) {
|
|
7361
|
-
setSignal(this.
|
|
7402
|
+
setSignal(this.me, unwrapStatusError(t.me));
|
|
7362
7403
|
}
|
|
7363
7404
|
}
|
|
7364
7405
|
}
|
|
@@ -7371,11 +7412,11 @@ class CollectionQueue extends Queue {
|
|
|
7371
7412
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7372
7413
|
// status of its own, so the count is the liveness test. The release
|
|
7373
7414
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7374
|
-
if (e.
|
|
7415
|
+
if (e.D & REACTIVE_DISPOSED || !e.W && !(e.xe & this.Tn) && !(this.Tn & STATUS_ERROR && e.xe & STATUS_PENDING)) this.Bt.delete(e);
|
|
7375
7416
|
}
|
|
7376
7417
|
if (!this.Bt.size) {
|
|
7377
7418
|
if (this.Tn & STATUS_PENDING && this.Zt && !this.rn && this.On) {
|
|
7378
|
-
this.Zt = !!(this.On.
|
|
7419
|
+
this.Zt = !!(this.On.xe & this.Tn);
|
|
7379
7420
|
} else {
|
|
7380
7421
|
this.Zt = false;
|
|
7381
7422
|
}
|
|
@@ -7397,7 +7438,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7397
7438
|
const i = createOwner();
|
|
7398
7439
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
7399
7440
|
const o = new CollectionQueue(e);
|
|
7400
|
-
if (e === STATUS_ERROR) o.
|
|
7441
|
+
if (e === STATUS_ERROR) o.me = signal(undefined, {
|
|
7401
7442
|
ownedWrite: true,
|
|
7402
7443
|
gt: true
|
|
7403
7444
|
});
|
|
@@ -7411,7 +7452,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7411
7452
|
} catch (e) {
|
|
7412
7453
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7413
7454
|
}
|
|
7414
|
-
o.Zt = t || !!(s.
|
|
7455
|
+
o.Zt = t || !!(s.xe & e) || s.me instanceof NotReadyError;
|
|
7415
7456
|
});
|
|
7416
7457
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7417
7458
|
if (u) {
|
|
@@ -7488,7 +7529,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7488
7529
|
* }
|
|
7489
7530
|
* ```
|
|
7490
7531
|
*/ function createErrorBoundary(e, t) {
|
|
7491
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
7532
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.me), () => {
|
|
7492
7533
|
for (const t of e.Bt) recompute(t);
|
|
7493
7534
|
schedule();
|
|
7494
7535
|
}));
|