@solidjs/signals 2.0.0-beta.28 → 2.0.0-beta.30
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 +22 -1
- package/dist/node.cjs +430 -413
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/scheduler.js +39 -22
- package/dist/prod/core/verdict.js +1 -1
- package/dist/prod/map.js +56 -56
- 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,19 @@ 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
|
-
currentBatch = this.
|
|
807
|
+
if (t.G.length) activeTransition.G.push(...t.G);
|
|
808
|
+
for (const e of t.V) activeTransition.V.add(e);
|
|
809
|
+
currentBatch = this.m = activeTransition;
|
|
793
810
|
}
|
|
794
811
|
for (const e of activeLanes) {
|
|
795
812
|
if (!e.T) e.T = activeTransition;
|
|
@@ -798,7 +815,7 @@ class GlobalQueue extends Queue {
|
|
|
798
815
|
}
|
|
799
816
|
|
|
800
817
|
function queuePendingNode(e) {
|
|
801
|
-
currentBatch.
|
|
818
|
+
currentBatch.M.push(e);
|
|
802
819
|
}
|
|
803
820
|
|
|
804
821
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -814,21 +831,21 @@ function insertSubs(e, t = false) {
|
|
|
814
831
|
// Get source lane: prefer node's own lane over current context
|
|
815
832
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
816
833
|
const n = e.i || currentOptimisticLane;
|
|
817
|
-
const r = e.
|
|
834
|
+
const r = e.Le !== undefined;
|
|
818
835
|
const i = reaskArmed;
|
|
819
|
-
for (let o = e.
|
|
836
|
+
for (let o = e.U; o !== null; o = o.Ge) {
|
|
820
837
|
// A value-change notification is a new question for the subscriber: any
|
|
821
838
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
822
|
-
if (i) o.Ve.
|
|
839
|
+
if (i) o.Ve.D &= ~REACTIVE_REASK;
|
|
823
840
|
if (r && o.Ve.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
824
|
-
o.Ve.
|
|
841
|
+
o.Ve.D |= REACTIVE_SNAPSHOT_STALE;
|
|
825
842
|
continue;
|
|
826
843
|
}
|
|
827
844
|
if (t && n) {
|
|
828
|
-
o.Ve.
|
|
845
|
+
o.Ve.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
829
846
|
assignOrMergeLane(o.Ve, n);
|
|
830
847
|
} else if (t) {
|
|
831
|
-
o.Ve.
|
|
848
|
+
o.Ve.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
832
849
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
833
850
|
o.Ve.i = undefined;
|
|
834
851
|
}
|
|
@@ -839,27 +856,27 @@ function insertSubs(e, t = false) {
|
|
|
839
856
|
function commitPendingNode(e) {
|
|
840
857
|
const t = e;
|
|
841
858
|
if (!t.ke) {
|
|
842
|
-
if (e.
|
|
843
|
-
e.We = e.
|
|
844
|
-
e.
|
|
859
|
+
if (e.k !== NOT_PENDING) {
|
|
860
|
+
e.We = e.k;
|
|
861
|
+
e.k = NOT_PENDING;
|
|
845
862
|
}
|
|
846
|
-
if (e._ || e.R) GlobalQueue.
|
|
863
|
+
if (e._ || e.R) GlobalQueue.Ee(e);
|
|
847
864
|
return;
|
|
848
865
|
}
|
|
849
|
-
if (e.
|
|
850
|
-
e.We = e.
|
|
851
|
-
e.
|
|
866
|
+
if (e.k !== NOT_PENDING) {
|
|
867
|
+
e.We = e.k;
|
|
868
|
+
e.k = NOT_PENDING;
|
|
852
869
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
853
870
|
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.xe = true;
|
|
854
871
|
}
|
|
855
|
-
t.
|
|
872
|
+
t.D &= ~REACTIVE_MANUAL_WRITE;
|
|
856
873
|
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
857
|
-
if (t.He !== null || t.Me !== null) GlobalQueue.
|
|
858
|
-
if (e._ || e.R) GlobalQueue.
|
|
874
|
+
if (t.He !== null || t.Me !== null) GlobalQueue.ee(t, false, true);
|
|
875
|
+
if (e._ || e.R) GlobalQueue.Ee(e);
|
|
859
876
|
}
|
|
860
877
|
|
|
861
878
|
function commitPendingNodes() {
|
|
862
|
-
const e = currentBatch.
|
|
879
|
+
const e = currentBatch.M;
|
|
863
880
|
for (let t = 0; t < e.length; t++) {
|
|
864
881
|
commitPendingNode(e[t]);
|
|
865
882
|
}
|
|
@@ -871,24 +888,24 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
871
888
|
// For completing transitions or no-transition, resolve pending and revert optimistic
|
|
872
889
|
const n = !t;
|
|
873
890
|
if (n) commitPendingNodes();
|
|
874
|
-
if (!t && globalQueue.
|
|
891
|
+
if (!t && globalQueue.v.length) checkBoundaryChildren(globalQueue);
|
|
875
892
|
const r = dirtyQueue.C >= dirtyQueue.P;
|
|
876
|
-
if (r) runHeap(dirtyQueue, GlobalQueue.
|
|
893
|
+
if (r) runHeap(dirtyQueue, GlobalQueue.J);
|
|
877
894
|
if (n) {
|
|
878
895
|
if (r) commitPendingNodes();
|
|
879
896
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
880
|
-
const t = e ?? globalQueue.
|
|
897
|
+
const t = e ?? globalQueue.m;
|
|
881
898
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
882
899
|
// which installed the engine's hooks.
|
|
883
|
-
if (t.
|
|
900
|
+
if (t.L.length) GlobalQueue.Ie(t.L);
|
|
884
901
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
885
902
|
// so they re-run with the now-committed values visible.
|
|
886
|
-
if (e && e.
|
|
887
|
-
for (const t of e.
|
|
888
|
-
if (t.
|
|
903
|
+
if (e && e.q.size) {
|
|
904
|
+
for (const t of e.q) {
|
|
905
|
+
if (t.D & REACTIVE_DISPOSED) continue;
|
|
889
906
|
enqueueSub(t);
|
|
890
907
|
}
|
|
891
|
-
e.
|
|
908
|
+
e.q.clear();
|
|
892
909
|
}
|
|
893
910
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
894
911
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
@@ -896,23 +913,23 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
896
913
|
// held boundary display state through the visual channel, and their
|
|
897
914
|
// release is the display-state update point — re-run the boundary sweep
|
|
898
915
|
// (the earlier sweep above ran while the marks were still live).
|
|
899
|
-
if (t.
|
|
900
|
-
GlobalQueue.
|
|
901
|
-
if (globalQueue.
|
|
916
|
+
if (t.G.length) {
|
|
917
|
+
GlobalQueue.ie(t.G);
|
|
918
|
+
if (globalQueue.v.length) checkBoundaryChildren(globalQueue);
|
|
902
919
|
}
|
|
903
920
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
904
921
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
905
922
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
906
923
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
907
|
-
if (t.
|
|
924
|
+
if (t.V.size) GlobalQueue.ne(t.V, e);
|
|
908
925
|
sweepTransientStoreNodes();
|
|
909
926
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
910
|
-
if (activeLanes.size) GlobalQueue.
|
|
927
|
+
if (activeLanes.size) GlobalQueue.he(e);
|
|
911
928
|
}
|
|
912
929
|
}
|
|
913
930
|
|
|
914
931
|
function checkBoundaryChildren(e) {
|
|
915
|
-
for (const t of e.
|
|
932
|
+
for (const t of e.v) {
|
|
916
933
|
t.$e?.();
|
|
917
934
|
checkBoundaryChildren(t);
|
|
918
935
|
}
|
|
@@ -947,7 +964,7 @@ const globalQueue = new GlobalQueue;
|
|
|
947
964
|
// property hop through `_batch` was a measured instruction-count regression
|
|
948
965
|
// (CodSpeed update1to1, PR #2905). The field stays authoritative for
|
|
949
966
|
// cross-module readers; every `_batch` assignment updates both.
|
|
950
|
-
let currentBatch = globalQueue.
|
|
967
|
+
let currentBatch = globalQueue.m;
|
|
951
968
|
|
|
952
969
|
function flush(e) {
|
|
953
970
|
if (e) {
|
|
@@ -964,7 +981,7 @@ function flush(e) {
|
|
|
964
981
|
}
|
|
965
982
|
}
|
|
966
983
|
}
|
|
967
|
-
if (globalQueue.
|
|
984
|
+
if (globalQueue.B) {
|
|
968
985
|
return;
|
|
969
986
|
}
|
|
970
987
|
if (halted) return;
|
|
@@ -980,7 +997,7 @@ function runQueue$1(e, t) {
|
|
|
980
997
|
}
|
|
981
998
|
|
|
982
999
|
function reporterBlocksSource(e, t) {
|
|
983
|
-
if (e.
|
|
1000
|
+
if (e.D & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
984
1001
|
if (e.je?.has(t)) return true;
|
|
985
1002
|
for (let n = e.Ke; n; n = n.Ye) {
|
|
986
1003
|
let e = n.qe;
|
|
@@ -989,14 +1006,14 @@ function reporterBlocksSource(e, t) {
|
|
|
989
1006
|
e = e.t;
|
|
990
1007
|
}
|
|
991
1008
|
}
|
|
992
|
-
return !!(e.Qe & STATUS_PENDING && e.
|
|
1009
|
+
return !!(e.Qe & STATUS_PENDING && e.me instanceof NotReadyError && e.me.source === t);
|
|
993
1010
|
}
|
|
994
1011
|
|
|
995
1012
|
function transitionComplete(e) {
|
|
996
1013
|
if (e.I) return true;
|
|
997
|
-
if (e
|
|
1014
|
+
if (e.j.length) return false;
|
|
998
1015
|
let t = true;
|
|
999
|
-
for (const [n, r] of e
|
|
1016
|
+
for (const [n, r] of e.$) {
|
|
1000
1017
|
let i = false;
|
|
1001
1018
|
for (const e of r) {
|
|
1002
1019
|
if (reporterBlocksSource(e, n)) {
|
|
@@ -1005,7 +1022,7 @@ function transitionComplete(e) {
|
|
|
1005
1022
|
}
|
|
1006
1023
|
r.delete(e);
|
|
1007
1024
|
}
|
|
1008
|
-
if (!i) e
|
|
1025
|
+
if (!i) e.$.delete(n); else if (n.Qe & STATUS_PENDING && n.me?.source === n) {
|
|
1009
1026
|
t = false;
|
|
1010
1027
|
break;
|
|
1011
1028
|
}
|
|
@@ -1013,7 +1030,7 @@ function transitionComplete(e) {
|
|
|
1013
1030
|
// Override blockage lives with the engine (absent hook = "no optimistic
|
|
1014
1031
|
// blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
|
|
1015
1032
|
// no-ops when the transition holds neither, so no pre-check is needed.
|
|
1016
|
-
if (t && GlobalQueue.
|
|
1033
|
+
if (t && GlobalQueue.Ae?.(e)) t = false;
|
|
1017
1034
|
t && (e.I = true);
|
|
1018
1035
|
return t;
|
|
1019
1036
|
}
|
|
@@ -1034,7 +1051,7 @@ function runInTransition(e, t) {
|
|
|
1034
1051
|
}
|
|
1035
1052
|
|
|
1036
1053
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1037
|
-
return e.
|
|
1054
|
+
return e.D & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1038
1055
|
}
|
|
1039
1056
|
|
|
1040
1057
|
/**
|
|
@@ -1056,7 +1073,7 @@ function runInTransition(e, t) {
|
|
|
1056
1073
|
}
|
|
1057
1074
|
|
|
1058
1075
|
function actualInsertIntoHeap(e, t) {
|
|
1059
|
-
const n = (e.
|
|
1076
|
+
const n = (e.Z?.Je ? e.Z.et?.ze : e.Z?.ze) ?? -1;
|
|
1060
1077
|
if (n >= e.ze) e.ze = n + 1;
|
|
1061
1078
|
const r = e.ze;
|
|
1062
1079
|
const i = t.h[r];
|
|
@@ -1070,12 +1087,12 @@ function actualInsertIntoHeap(e, t) {
|
|
|
1070
1087
|
}
|
|
1071
1088
|
|
|
1072
1089
|
function insertIntoHeap(e, t) {
|
|
1073
|
-
let n = e.
|
|
1090
|
+
let n = e.D;
|
|
1074
1091
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1075
1092
|
if (n & REACTIVE_CHECK) {
|
|
1076
|
-
e.
|
|
1093
|
+
e.D = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1077
1094
|
} else {
|
|
1078
|
-
e.
|
|
1095
|
+
e.D = n | REACTIVE_IN_HEAP;
|
|
1079
1096
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1080
1097
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1081
1098
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1087,16 +1104,16 @@ function insertIntoHeap(e, t) {
|
|
|
1087
1104
|
}
|
|
1088
1105
|
|
|
1089
1106
|
function insertIntoHeapHeight(e, t) {
|
|
1090
|
-
let n = e.
|
|
1107
|
+
let n = e.D;
|
|
1091
1108
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1092
|
-
e.
|
|
1109
|
+
e.D = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1093
1110
|
actualInsertIntoHeap(e, t);
|
|
1094
1111
|
}
|
|
1095
1112
|
|
|
1096
1113
|
function deleteFromHeap(e, t) {
|
|
1097
|
-
const n = e.
|
|
1114
|
+
const n = e.D;
|
|
1098
1115
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1099
|
-
e.
|
|
1116
|
+
e.D = n & -25;
|
|
1100
1117
|
const r = e.ze;
|
|
1101
1118
|
if (e.tt === e) t.h[r] = undefined; else {
|
|
1102
1119
|
const n = e.nt;
|
|
@@ -1114,21 +1131,21 @@ function markHeap(e) {
|
|
|
1114
1131
|
e.N = true;
|
|
1115
1132
|
for (let t = 0; t <= e.C; t++) {
|
|
1116
1133
|
for (let n = e.h[t]; n !== undefined; n = n.nt) {
|
|
1117
|
-
if (n.
|
|
1134
|
+
if (n.D & REACTIVE_IN_HEAP) markNode(n);
|
|
1118
1135
|
}
|
|
1119
1136
|
}
|
|
1120
1137
|
}
|
|
1121
1138
|
|
|
1122
1139
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1123
|
-
const n = e.
|
|
1140
|
+
const n = e.D;
|
|
1124
1141
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1125
|
-
e.
|
|
1126
|
-
for (let t = e.
|
|
1142
|
+
e.D = n & -4 | t;
|
|
1143
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1127
1144
|
markNode(t.Ve, REACTIVE_CHECK);
|
|
1128
1145
|
}
|
|
1129
1146
|
if (e.rt !== null) {
|
|
1130
1147
|
for (let t = e.rt; t !== null; t = t.it) {
|
|
1131
|
-
for (let e = t.
|
|
1148
|
+
for (let e = t.U; e !== null; e = e.Ge) {
|
|
1132
1149
|
markNode(e.Ve, REACTIVE_CHECK);
|
|
1133
1150
|
}
|
|
1134
1151
|
}
|
|
@@ -1140,7 +1157,7 @@ function runHeap(e, t) {
|
|
|
1140
1157
|
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1141
1158
|
let n = e.h[e.P];
|
|
1142
1159
|
while (n !== undefined) {
|
|
1143
|
-
if (n.
|
|
1160
|
+
if (n.D & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1144
1161
|
n = e.h[e.P];
|
|
1145
1162
|
}
|
|
1146
1163
|
}
|
|
@@ -1157,7 +1174,7 @@ function adjustHeight(e, t) {
|
|
|
1157
1174
|
}
|
|
1158
1175
|
if (e.ze !== n) {
|
|
1159
1176
|
e.ze = n;
|
|
1160
|
-
for (let t = e.
|
|
1177
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1161
1178
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1162
1179
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1163
1180
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
@@ -1174,8 +1191,8 @@ const PENDING_OWNER = {};
|
|
|
1174
1191
|
function markDisposal(e) {
|
|
1175
1192
|
let t = e.ot;
|
|
1176
1193
|
while (t) {
|
|
1177
|
-
const e = t.
|
|
1178
|
-
t.
|
|
1194
|
+
const e = t.D;
|
|
1195
|
+
t.D = e | REACTIVE_ZOMBIE;
|
|
1179
1196
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1180
1197
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1181
1198
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1201,17 +1218,17 @@ function dispose(e) {
|
|
|
1201
1218
|
}
|
|
1202
1219
|
|
|
1203
1220
|
function disposeChildren(e, t = false, n) {
|
|
1204
|
-
const r = e.
|
|
1221
|
+
const r = e.D;
|
|
1205
1222
|
if (r & REACTIVE_DISPOSED) return;
|
|
1206
1223
|
if (t) {
|
|
1207
|
-
e.
|
|
1224
|
+
e.D = r | REACTIVE_DISPOSED;
|
|
1208
1225
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1209
1226
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1210
1227
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1211
1228
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1212
1229
|
// false, and notifies subscribers still watching the companion.
|
|
1213
1230
|
const t = e;
|
|
1214
|
-
if (t._ || t.R) GlobalQueue.
|
|
1231
|
+
if (t._ || t.R) GlobalQueue.Ee(t);
|
|
1215
1232
|
}
|
|
1216
1233
|
if (t && e.ke) e.lt = null;
|
|
1217
1234
|
let i = n ? e.He : e.ot;
|
|
@@ -1240,10 +1257,10 @@ function disposeChildren(e, t = false, n) {
|
|
|
1240
1257
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1241
1258
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1242
1259
|
// walks that already advanced past us still reach later siblings.
|
|
1243
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.
|
|
1260
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.Z !== null && !(e.Z.D & REACTIVE_DISPOSED)) {
|
|
1244
1261
|
const t = e.ft;
|
|
1245
1262
|
const n = e.st;
|
|
1246
|
-
if (t !== null) t.st = n; else e.
|
|
1263
|
+
if (t !== null) t.st = n; else e.Z.ot = n;
|
|
1247
1264
|
if (n !== null) n.ft = t;
|
|
1248
1265
|
e.ft = null;
|
|
1249
1266
|
}
|
|
@@ -1273,7 +1290,7 @@ function runDisposal(e, t) {
|
|
|
1273
1290
|
|
|
1274
1291
|
function childId(e, t) {
|
|
1275
1292
|
let n = e;
|
|
1276
|
-
while (n.Ue & CONFIG_TRANSPARENT && n.
|
|
1293
|
+
while (n.Ue & CONFIG_TRANSPARENT && n.Z) n = n.Z;
|
|
1277
1294
|
if (n.id != null) return formatId(n.id, t ? n.ct++ : n.ct);
|
|
1278
1295
|
throw new Error("");
|
|
1279
1296
|
}
|
|
@@ -1375,7 +1392,7 @@ function formatId(e, t) {
|
|
|
1375
1392
|
* }
|
|
1376
1393
|
* ```
|
|
1377
1394
|
*/ function isDisposed(e) {
|
|
1378
|
-
return !!(e.
|
|
1395
|
+
return !!(e.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1379
1396
|
}
|
|
1380
1397
|
|
|
1381
1398
|
function disposeRootSelf(e = true) {
|
|
@@ -1406,7 +1423,7 @@ function disposeRootSelf(e = true) {
|
|
|
1406
1423
|
ct: 0,
|
|
1407
1424
|
Me: null,
|
|
1408
1425
|
He: null,
|
|
1409
|
-
|
|
1426
|
+
Z: t,
|
|
1410
1427
|
dispose: disposeRootSelf
|
|
1411
1428
|
};
|
|
1412
1429
|
if (t) {
|
|
@@ -1454,13 +1471,13 @@ function disposeRootSelf(e = true) {
|
|
|
1454
1471
|
function unlinkSubs(e) {
|
|
1455
1472
|
const t = e.qe;
|
|
1456
1473
|
const n = e.Ye;
|
|
1457
|
-
const r = e.
|
|
1474
|
+
const r = e.Ge;
|
|
1458
1475
|
const i = e.Tt;
|
|
1459
1476
|
if (r !== null) r.Tt = i; else t.Ot = i;
|
|
1460
|
-
if (i !== null) i.
|
|
1461
|
-
t.
|
|
1477
|
+
if (i !== null) i.Ge = r; else {
|
|
1478
|
+
t.U = r;
|
|
1462
1479
|
if (r === null) {
|
|
1463
|
-
t.
|
|
1480
|
+
t.F?.();
|
|
1464
1481
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1465
1482
|
// A pending node is exempt: its in-flight async work (or the
|
|
1466
1483
|
// transition holding it) is an observer — tearing down would orphan
|
|
@@ -1468,7 +1485,7 @@ function unlinkSubs(e) {
|
|
|
1468
1485
|
// this same last-one-out check when that observer releases (the
|
|
1469
1486
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1470
1487
|
const e = t;
|
|
1471
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.
|
|
1488
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.D & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1472
1489
|
}
|
|
1473
1490
|
}
|
|
1474
1491
|
return n;
|
|
@@ -1509,7 +1526,7 @@ function link(e, t, n = false) {
|
|
|
1509
1526
|
return;
|
|
1510
1527
|
}
|
|
1511
1528
|
let i = null;
|
|
1512
|
-
const o = t.
|
|
1529
|
+
const o = t.D & REACTIVE_RECOMPUTING_DEPS;
|
|
1513
1530
|
if (o) {
|
|
1514
1531
|
i = r !== null ? r.Ye : t.Ke;
|
|
1515
1532
|
if (i !== null && i.qe === e) {
|
|
@@ -1537,12 +1554,12 @@ function link(e, t, n = false) {
|
|
|
1537
1554
|
Ve: t,
|
|
1538
1555
|
Ye: i,
|
|
1539
1556
|
Tt: s,
|
|
1540
|
-
|
|
1557
|
+
Ge: null,
|
|
1541
1558
|
Rt: t.It,
|
|
1542
1559
|
_t: n
|
|
1543
1560
|
};
|
|
1544
1561
|
if (r !== null) r.Ye = u; else t.Ke = u;
|
|
1545
|
-
if (s !== null) s.
|
|
1562
|
+
if (s !== null) s.Ge = u; else e.U = u;
|
|
1546
1563
|
}
|
|
1547
1564
|
|
|
1548
1565
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1569,24 +1586,24 @@ function clearPendingSources(e) {
|
|
|
1569
1586
|
|
|
1570
1587
|
function setPendingError(e, t, n) {
|
|
1571
1588
|
if (!t) {
|
|
1572
|
-
e.
|
|
1589
|
+
e.me = null;
|
|
1573
1590
|
return;
|
|
1574
1591
|
}
|
|
1575
1592
|
if (n instanceof NotReadyError && n.source === t) {
|
|
1576
|
-
e.
|
|
1593
|
+
e.me = n;
|
|
1577
1594
|
return;
|
|
1578
1595
|
}
|
|
1579
|
-
const r = e.
|
|
1596
|
+
const r = e.me;
|
|
1580
1597
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
1581
|
-
e.
|
|
1598
|
+
e.me = new NotReadyError(t);
|
|
1582
1599
|
}
|
|
1583
1600
|
}
|
|
1584
1601
|
|
|
1585
1602
|
function forEachDependent(e, t) {
|
|
1586
|
-
for (let n = e.
|
|
1603
|
+
for (let n = e.U; n !== null; n = n.Ge) t(n.Ve, n);
|
|
1587
1604
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1588
1605
|
for (let n = e.rt ?? null; n !== null; n = n.it) {
|
|
1589
|
-
for (let e = n.
|
|
1606
|
+
for (let e = n.U; e !== null; e = e.Ge) t(e.Ve, e);
|
|
1590
1607
|
}
|
|
1591
1608
|
}
|
|
1592
1609
|
|
|
@@ -1601,7 +1618,7 @@ function forEachDependent(e, t) {
|
|
|
1601
1618
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1602
1619
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1603
1620
|
function releaseIfSettledUnobserved(e) {
|
|
1604
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.
|
|
1621
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.D & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1605
1622
|
}
|
|
1606
1623
|
|
|
1607
1624
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -1614,7 +1631,7 @@ function releaseSettledDependents(e) {
|
|
|
1614
1631
|
const visit = e => {
|
|
1615
1632
|
if (n.has(e)) return;
|
|
1616
1633
|
n.add(e);
|
|
1617
|
-
if (!e.
|
|
1634
|
+
if (!e.U && e.Ue & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
1618
1635
|
forEachDependent(e, visit);
|
|
1619
1636
|
};
|
|
1620
1637
|
forEachDependent(e, visit);
|
|
@@ -1642,7 +1659,7 @@ function settleErroredDependents(e, t) {
|
|
|
1642
1659
|
const visit = e => {
|
|
1643
1660
|
if (r.has(e)) return;
|
|
1644
1661
|
r.add(e);
|
|
1645
|
-
if (e.
|
|
1662
|
+
if (e.me === t) {
|
|
1646
1663
|
enqueueSub(e);
|
|
1647
1664
|
n = true;
|
|
1648
1665
|
}
|
|
@@ -1657,11 +1674,11 @@ function settlePendingSource(e) {
|
|
|
1657
1674
|
let n;
|
|
1658
1675
|
const r = new Set;
|
|
1659
1676
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1660
|
-
const i = GlobalQueue.
|
|
1677
|
+
const i = GlobalQueue.ce;
|
|
1661
1678
|
const settle = o => {
|
|
1662
1679
|
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1663
1680
|
r.add(o);
|
|
1664
|
-
o.
|
|
1681
|
+
o.H = clock;
|
|
1665
1682
|
const s = o.je?.values().next().value;
|
|
1666
1683
|
if (s) {
|
|
1667
1684
|
setPendingError(o, s);
|
|
@@ -1678,7 +1695,7 @@ function settlePendingSource(e) {
|
|
|
1678
1695
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1679
1696
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
1680
1697
|
// lists this walk is still iterating.
|
|
1681
|
-
if (!o.
|
|
1698
|
+
if (!o.U && o.Ue & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
1682
1699
|
}
|
|
1683
1700
|
forEachDependent(o, settle);
|
|
1684
1701
|
};
|
|
@@ -1721,7 +1738,7 @@ function handleAsync(e, t, n) {
|
|
|
1721
1738
|
// are the transaction's reveal machinery and always re-enter.
|
|
1722
1739
|
const settleTransition = () => {
|
|
1723
1740
|
const t = resolveTransition(e);
|
|
1724
|
-
if (t && e.Qe & STATUS_UNINITIALIZED && !currentTransition(t)
|
|
1741
|
+
if (t && e.Qe & STATUS_UNINITIALIZED && !currentTransition(t).$.has(e)) {
|
|
1725
1742
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1726
1743
|
// stash-path restamp both re-enter the transaction through it.
|
|
1727
1744
|
e.T = null;
|
|
@@ -1735,7 +1752,7 @@ function handleAsync(e, t, n) {
|
|
|
1735
1752
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1736
1753
|
const r = n instanceof NotReadyError;
|
|
1737
1754
|
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1738
|
-
e.
|
|
1755
|
+
e.H = clock;
|
|
1739
1756
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
1740
1757
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
1741
1758
|
// the error twin of settlePendingSource's release (#2934).
|
|
@@ -1746,7 +1763,7 @@ function handleAsync(e, t, n) {
|
|
|
1746
1763
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1747
1764
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1748
1765
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1749
|
-
if (e.
|
|
1766
|
+
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1750
1767
|
settleTransition();
|
|
1751
1768
|
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
1752
1769
|
trimStaleDeps(e);
|
|
@@ -1766,8 +1783,8 @@ function handleAsync(e, t, n) {
|
|
|
1766
1783
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
1767
1784
|
// has committed by then, so corrections reveal atomically with their
|
|
1768
1785
|
// transition rather than escaping it.
|
|
1769
|
-
if (e.
|
|
1770
|
-
e.
|
|
1786
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
1787
|
+
e.k = r;
|
|
1771
1788
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
1772
1789
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
1773
1790
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -1775,9 +1792,9 @@ function handleAsync(e, t, n) {
|
|
|
1775
1792
|
// only notified when the hold is visible to them: under an active
|
|
1776
1793
|
// override every reader sees the override (A17), so waking subs would
|
|
1777
1794
|
// re-show an unchanged view — the revert is the notification point.
|
|
1778
|
-
GlobalQueue.
|
|
1795
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e, r);
|
|
1779
1796
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1780
|
-
e.
|
|
1797
|
+
e.H = clock;
|
|
1781
1798
|
} else if (s) {
|
|
1782
1799
|
// Route through lane's effect queue for independent flushing
|
|
1783
1800
|
const t = e.Fe;
|
|
@@ -1786,11 +1803,11 @@ function handleAsync(e, t, n) {
|
|
|
1786
1803
|
try {
|
|
1787
1804
|
if (!t && o || !i || !i(r, n)) {
|
|
1788
1805
|
e.We = r;
|
|
1789
|
-
e.
|
|
1806
|
+
e.H = clock;
|
|
1790
1807
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1791
1808
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1792
1809
|
// (computePendingState doesn't read _value).
|
|
1793
|
-
GlobalQueue.
|
|
1810
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e, r);
|
|
1794
1811
|
insertSubs(e, true);
|
|
1795
1812
|
}
|
|
1796
1813
|
} catch (t) {
|
|
@@ -1822,7 +1839,7 @@ function handleAsync(e, t, n) {
|
|
|
1822
1839
|
// Returns whether the node released, so the iterator branch can stop
|
|
1823
1840
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1824
1841
|
const settleAutodispose = () => {
|
|
1825
|
-
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.
|
|
1842
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.Qe & STATUS_PENDING)) {
|
|
1826
1843
|
unobserved(e);
|
|
1827
1844
|
return true;
|
|
1828
1845
|
}
|
|
@@ -1945,11 +1962,11 @@ function clearStatus(e, t = false) {
|
|
|
1945
1962
|
// plain store to an existing slot — no shape change.)
|
|
1946
1963
|
e.Nt = false;
|
|
1947
1964
|
e.Qe = t ? 0 : e.Qe & STATUS_UNINITIALIZED;
|
|
1948
|
-
if (e.
|
|
1965
|
+
if (e.me) setPendingError(e);
|
|
1949
1966
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1950
1967
|
// once the verdict layer created them, which installs the hooks).
|
|
1951
|
-
if (e._ || e.R) GlobalQueue.
|
|
1952
|
-
if (e.rt && GlobalQueue.
|
|
1968
|
+
if (e._ || e.R) GlobalQueue.ce(e);
|
|
1969
|
+
if (e.rt && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1953
1970
|
if (e.yt) e.yt();
|
|
1954
1971
|
}
|
|
1955
1972
|
|
|
@@ -1970,10 +1987,10 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1970
1987
|
} else {
|
|
1971
1988
|
clearPendingSources(e);
|
|
1972
1989
|
e.Qe = t | (t !== STATUS_ERROR ? e.Qe & STATUS_UNINITIALIZED : 0);
|
|
1973
|
-
e.
|
|
1990
|
+
e.me = n;
|
|
1974
1991
|
}
|
|
1975
|
-
GlobalQueue.
|
|
1976
|
-
if (e.rt && GlobalQueue.
|
|
1992
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
1993
|
+
if (e.rt && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1977
1994
|
}
|
|
1978
1995
|
if (i && !r) {
|
|
1979
1996
|
assignOrMergeLane(e, i);
|
|
@@ -1992,8 +2009,8 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1992
2009
|
return;
|
|
1993
2010
|
}
|
|
1994
2011
|
forEachDependent(e, (e, r) => {
|
|
1995
|
-
e.
|
|
1996
|
-
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.
|
|
2012
|
+
e.H = clock;
|
|
2013
|
+
if (t === STATUS_PENDING && o && !e.je?.has(o) || t !== STATUS_PENDING && (e.me !== n || e.je)) {
|
|
1997
2014
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1998
2015
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1999
2016
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
@@ -2010,9 +2027,9 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
2010
2027
|
});
|
|
2011
2028
|
}
|
|
2012
2029
|
|
|
2013
|
-
GlobalQueue.
|
|
2030
|
+
GlobalQueue.J = recompute;
|
|
2014
2031
|
|
|
2015
|
-
GlobalQueue.
|
|
2032
|
+
GlobalQueue.ee = disposeChildren;
|
|
2016
2033
|
|
|
2017
2034
|
let tracking = false;
|
|
2018
2035
|
|
|
@@ -2045,7 +2062,7 @@ let snapshotSources = null;
|
|
|
2045
2062
|
function ownerInSnapshotScope(e) {
|
|
2046
2063
|
while (e) {
|
|
2047
2064
|
if (e.Pt) return true;
|
|
2048
|
-
e = e.
|
|
2065
|
+
e = e.Z;
|
|
2049
2066
|
}
|
|
2050
2067
|
return false;
|
|
2051
2068
|
}
|
|
@@ -2075,9 +2092,9 @@ function releaseSubtree(e) {
|
|
|
2075
2092
|
if (t.ke) {
|
|
2076
2093
|
const e = t;
|
|
2077
2094
|
e.Ue &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
2078
|
-
if (e.
|
|
2079
|
-
e.
|
|
2080
|
-
e.
|
|
2095
|
+
if (e.D & REACTIVE_SNAPSHOT_STALE) {
|
|
2096
|
+
e.D &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2097
|
+
e.D |= REACTIVE_DIRTY;
|
|
2081
2098
|
if (dirtyQueue.P > e.ze) dirtyQueue.P = e.ze;
|
|
2082
2099
|
insertIntoHeap(e, dirtyQueue);
|
|
2083
2100
|
}
|
|
@@ -2090,7 +2107,7 @@ function releaseSubtree(e) {
|
|
|
2090
2107
|
function clearSnapshots() {
|
|
2091
2108
|
if (snapshotSources) {
|
|
2092
2109
|
for (const e of snapshotSources) {
|
|
2093
|
-
delete e.
|
|
2110
|
+
delete e.Le;
|
|
2094
2111
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
2095
2112
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
2096
2113
|
// when present so signal-node sources don't grow the field.
|
|
@@ -2117,23 +2134,23 @@ function recompute(e, t = false) {
|
|
|
2117
2134
|
e.ct = 0;
|
|
2118
2135
|
} else ;
|
|
2119
2136
|
}
|
|
2120
|
-
let r = !!(e.
|
|
2137
|
+
let r = !!(e.D & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2121
2138
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
2122
2139
|
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
2123
2140
|
// Outgoing error, captured before the compute clears status: if this run
|
|
2124
2141
|
// recovers to an unchanged value, dependents still holding this object must
|
|
2125
2142
|
// be swept (settleErroredDependents, #2949).
|
|
2126
|
-
const s = e.Qe & STATUS_ERROR ? e.
|
|
2143
|
+
const s = e.Qe & STATUS_ERROR ? e.me : undefined;
|
|
2127
2144
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2128
2145
|
// the recompute wipes _flags below.
|
|
2129
|
-
const u = (e.
|
|
2146
|
+
const u = (e.D & REACTIVE_REASK) !== 0;
|
|
2130
2147
|
const l = context;
|
|
2131
2148
|
context = e;
|
|
2132
2149
|
e.ut = null;
|
|
2133
2150
|
e.It++;
|
|
2134
|
-
e.
|
|
2135
|
-
e.
|
|
2136
|
-
let a = e.
|
|
2151
|
+
e.D = REACTIVE_RECOMPUTING_DEPS;
|
|
2152
|
+
e.H = clock;
|
|
2153
|
+
let a = e.k === NOT_PENDING ? e.We : e.k;
|
|
2137
2154
|
let c = e.ze;
|
|
2138
2155
|
let f = tracking;
|
|
2139
2156
|
let E = currentOptimisticLane;
|
|
@@ -2150,13 +2167,13 @@ function recompute(e, t = false) {
|
|
|
2150
2167
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2151
2168
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2152
2169
|
if (r) {
|
|
2153
|
-
const t = GlobalQueue.
|
|
2170
|
+
const t = GlobalQueue.ge(e, true);
|
|
2154
2171
|
if (t) currentOptimisticLane = t;
|
|
2155
|
-
} else if (activeTransition && !t && activeTransition.
|
|
2172
|
+
} else if (activeTransition && !t && activeTransition.L.length) {
|
|
2156
2173
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2157
2174
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2158
2175
|
// recomputes under the right posture and propagates correctly.
|
|
2159
|
-
const t = GlobalQueue.
|
|
2176
|
+
const t = GlobalQueue.ge(e, false);
|
|
2160
2177
|
if (t) {
|
|
2161
2178
|
r = true;
|
|
2162
2179
|
currentOptimisticLane = t;
|
|
@@ -2185,30 +2202,30 @@ function recompute(e, t = false) {
|
|
|
2185
2202
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2186
2203
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2187
2204
|
// the flags write (create or not) stores the 0 already there.
|
|
2188
|
-
if (e.Qe !== 0 || e.yt !== undefined || e.
|
|
2205
|
+
if (e.Qe !== 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
2206
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2190
|
-
if (e.i) GlobalQueue.
|
|
2207
|
+
if (e.i) GlobalQueue.De(e);
|
|
2191
2208
|
} catch (t) {
|
|
2192
2209
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2193
2210
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2194
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2211
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.be(e);
|
|
2195
2212
|
let n = false;
|
|
2196
2213
|
if (t instanceof NotReadyError) {
|
|
2197
2214
|
e.At = true;
|
|
2198
|
-
if (GlobalQueue.
|
|
2215
|
+
if (GlobalQueue.Oe !== null) n = GlobalQueue.Oe(e, u);
|
|
2199
2216
|
}
|
|
2200
2217
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2201
|
-
if (n) GlobalQueue.
|
|
2218
|
+
if (n) GlobalQueue._e(e);
|
|
2202
2219
|
} finally {
|
|
2203
2220
|
tracking = f;
|
|
2204
2221
|
latestReadActive = d;
|
|
2205
2222
|
if (S) stale = T;
|
|
2206
|
-
e.
|
|
2223
|
+
e.D = REACTIVE_NONE | (t ? e.D & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2207
2224
|
context = l;
|
|
2208
2225
|
}
|
|
2209
|
-
if (!e.
|
|
2226
|
+
if (!e.me) {
|
|
2210
2227
|
trimStaleDeps(e);
|
|
2211
|
-
const u = i ? unwrapOverride(e.A) : e.
|
|
2228
|
+
const u = i ? unwrapOverride(e.A) : e.k === NOT_PENDING ? e.We : e.k;
|
|
2212
2229
|
let l = false;
|
|
2213
2230
|
try {
|
|
2214
2231
|
l = !n && o || !e.ht || !e.ht(u, a);
|
|
@@ -2225,12 +2242,12 @@ function recompute(e, t = false) {
|
|
|
2225
2242
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2226
2243
|
// effect() can call its runner synchronously for the first run.
|
|
2227
2244
|
if (n && l) {
|
|
2228
|
-
e.xe = !e.
|
|
2245
|
+
e.xe = !e.me;
|
|
2229
2246
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2230
2247
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2231
|
-
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.
|
|
2248
|
+
if (!t) e.Ze.enqueue(n, e.Ct ??= GlobalQueue.te.bind(null, e));
|
|
2232
2249
|
}
|
|
2233
|
-
if (e.
|
|
2250
|
+
if (e.me) ; else if (l) {
|
|
2234
2251
|
const o = i ? e.A : undefined;
|
|
2235
2252
|
if (t ||
|
|
2236
2253
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2245,28 +2262,28 @@ function recompute(e, t = false) {
|
|
|
2245
2262
|
// commit can't clobber the fresh value.
|
|
2246
2263
|
if (i && r) {
|
|
2247
2264
|
e.A = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
2248
|
-
e.
|
|
2265
|
+
e.k = NOT_PENDING;
|
|
2249
2266
|
}
|
|
2250
2267
|
} else {
|
|
2251
|
-
e.
|
|
2268
|
+
e.k = a;
|
|
2252
2269
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2253
2270
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2254
2271
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2255
2272
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2256
2273
|
// pending value commits before effects run.
|
|
2257
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2274
|
+
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e, a);
|
|
2258
2275
|
}
|
|
2259
2276
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2260
2277
|
// subscriber-less node has nothing to notify.
|
|
2261
|
-
if (e.
|
|
2278
|
+
if (e.U !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2262
2279
|
} else if (i) {
|
|
2263
2280
|
// Unchanged value (equals the override) recomputed while the override
|
|
2264
2281
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2265
2282
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2266
|
-
if (e.
|
|
2267
|
-
e.
|
|
2283
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2284
|
+
e.k = a;
|
|
2268
2285
|
} else if (e.ze != c) {
|
|
2269
|
-
for (let t = e.
|
|
2286
|
+
for (let t = e.U; t !== null; t = t.Ge) {
|
|
2270
2287
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2271
2288
|
}
|
|
2272
2289
|
}
|
|
@@ -2275,10 +2292,10 @@ function recompute(e, t = false) {
|
|
|
2275
2292
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
2276
2293
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2277
2294
|
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
2278
|
-
if (s !== undefined && !l && !e.
|
|
2295
|
+
if (s !== undefined && !l && !e.me) settleErroredDependents(e, s);
|
|
2279
2296
|
}
|
|
2280
2297
|
currentOptimisticLane = E;
|
|
2281
|
-
const O = e.
|
|
2298
|
+
const O = e.k !== NOT_PENDING || e.He !== null || e.Me !== null || (e.Qe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2282
2299
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2283
2300
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2284
2301
|
// under the override (A17). Revert no longer commits anything, so an
|
|
@@ -2289,22 +2306,22 @@ function recompute(e, t = false) {
|
|
|
2289
2306
|
}
|
|
2290
2307
|
|
|
2291
2308
|
function updateIfNecessary(e) {
|
|
2292
|
-
if (e.
|
|
2309
|
+
if (e.D & REACTIVE_CHECK) {
|
|
2293
2310
|
for (let t = e.Ke; t; t = t.Ye) {
|
|
2294
2311
|
const n = t.qe;
|
|
2295
2312
|
const r = n.Be || n;
|
|
2296
2313
|
if (r.ke) {
|
|
2297
2314
|
updateIfNecessary(r);
|
|
2298
2315
|
}
|
|
2299
|
-
if (e.
|
|
2316
|
+
if (e.D & REACTIVE_DIRTY) {
|
|
2300
2317
|
break;
|
|
2301
2318
|
}
|
|
2302
2319
|
}
|
|
2303
2320
|
}
|
|
2304
|
-
if (e.
|
|
2321
|
+
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.me && e.H < clock && !e.lt) {
|
|
2305
2322
|
recompute(e);
|
|
2306
2323
|
}
|
|
2307
|
-
e.
|
|
2324
|
+
e.D = e.D & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2308
2325
|
}
|
|
2309
2326
|
|
|
2310
2327
|
function computed(e, t) {
|
|
@@ -2313,7 +2330,7 @@ function computed(e, t) {
|
|
|
2313
2330
|
id: inheritId(t, n, context),
|
|
2314
2331
|
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
2332
|
ht: t?.equals != null ? t.equals : isEqual,
|
|
2316
|
-
|
|
2333
|
+
F: t?.unobserved,
|
|
2317
2334
|
dt: null,
|
|
2318
2335
|
Ze: context?.Ze ?? globalQueue,
|
|
2319
2336
|
St: context?.St ?? defaultContext,
|
|
@@ -2327,16 +2344,16 @@ function computed(e, t) {
|
|
|
2327
2344
|
Ke: null,
|
|
2328
2345
|
ut: null,
|
|
2329
2346
|
It: 0,
|
|
2330
|
-
|
|
2347
|
+
U: null,
|
|
2331
2348
|
Ot: null,
|
|
2332
|
-
|
|
2349
|
+
Z: context,
|
|
2333
2350
|
st: null,
|
|
2334
2351
|
ft: null,
|
|
2335
2352
|
ot: null,
|
|
2336
|
-
|
|
2353
|
+
D: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2337
2354
|
Qe: STATUS_UNINITIALIZED,
|
|
2338
|
-
|
|
2339
|
-
|
|
2355
|
+
H: clock,
|
|
2356
|
+
k: NOT_PENDING,
|
|
2340
2357
|
Me: null,
|
|
2341
2358
|
He: null,
|
|
2342
2359
|
lt: null,
|
|
@@ -2358,7 +2375,7 @@ function computed(e, t) {
|
|
|
2358
2375
|
id: inheritId(o, s, context),
|
|
2359
2376
|
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
2377
|
ht: false,
|
|
2361
|
-
|
|
2378
|
+
F: o?.unobserved,
|
|
2362
2379
|
dt: null,
|
|
2363
2380
|
Ze: context?.Ze ?? globalQueue,
|
|
2364
2381
|
St: context?.St ?? defaultContext,
|
|
@@ -2372,16 +2389,16 @@ function computed(e, t) {
|
|
|
2372
2389
|
Ke: null,
|
|
2373
2390
|
ut: null,
|
|
2374
2391
|
It: 0,
|
|
2375
|
-
|
|
2392
|
+
U: null,
|
|
2376
2393
|
Ot: null,
|
|
2377
|
-
|
|
2394
|
+
Z: context,
|
|
2378
2395
|
st: null,
|
|
2379
2396
|
ft: null,
|
|
2380
2397
|
ot: null,
|
|
2381
|
-
|
|
2398
|
+
D: REACTIVE_LAZY,
|
|
2382
2399
|
Qe: STATUS_UNINITIALIZED,
|
|
2383
|
-
|
|
2384
|
-
|
|
2400
|
+
H: clock,
|
|
2401
|
+
k: NOT_PENDING,
|
|
2385
2402
|
Me: null,
|
|
2386
2403
|
He: null,
|
|
2387
2404
|
lt: null,
|
|
@@ -2417,11 +2434,11 @@ function setupComputedNode(e, t) {
|
|
|
2417
2434
|
}
|
|
2418
2435
|
}
|
|
2419
2436
|
if (n) e.ze = n.ze + 1;
|
|
2420
|
-
if (GlobalQueue.
|
|
2437
|
+
if (GlobalQueue.ue !== null) GlobalQueue.ue(e);
|
|
2421
2438
|
!t?.lazy && recompute(e, true);
|
|
2422
2439
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2423
2440
|
if (!(e.Qe & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2424
|
-
e.
|
|
2441
|
+
e.Le = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2425
2442
|
snapshotSources.add(e);
|
|
2426
2443
|
}
|
|
2427
2444
|
}
|
|
@@ -2431,18 +2448,18 @@ function signal(e, t, n = null) {
|
|
|
2431
2448
|
const r = {
|
|
2432
2449
|
ht: t?.equals != null ? t.equals : isEqual,
|
|
2433
2450
|
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.gt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2434
|
-
|
|
2451
|
+
F: t?.unobserved,
|
|
2435
2452
|
We: e,
|
|
2436
|
-
|
|
2453
|
+
U: null,
|
|
2437
2454
|
Ot: null,
|
|
2438
|
-
|
|
2455
|
+
H: clock,
|
|
2439
2456
|
Be: n,
|
|
2440
2457
|
it: n?.rt || null,
|
|
2441
|
-
|
|
2458
|
+
k: NOT_PENDING
|
|
2442
2459
|
};
|
|
2443
2460
|
n && (n.rt = r);
|
|
2444
2461
|
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.Qe ?? 0) & STATUS_PENDING)) {
|
|
2445
|
-
r.
|
|
2462
|
+
r.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
2446
2463
|
snapshotSources.add(r);
|
|
2447
2464
|
}
|
|
2448
2465
|
return r;
|
|
@@ -2486,11 +2503,11 @@ function isEqual(e, t) {
|
|
|
2486
2503
|
* );
|
|
2487
2504
|
* ```
|
|
2488
2505
|
*/ function untrack(e, t) {
|
|
2489
|
-
if (GlobalQueue.
|
|
2506
|
+
if (GlobalQueue.le === null && !tracking && true) return e();
|
|
2490
2507
|
const n = tracking;
|
|
2491
2508
|
tracking = false;
|
|
2492
2509
|
try {
|
|
2493
|
-
if (GlobalQueue.
|
|
2510
|
+
if (GlobalQueue.le !== null) return GlobalQueue.le(e);
|
|
2494
2511
|
return e();
|
|
2495
2512
|
} finally {
|
|
2496
2513
|
tracking = n;
|
|
@@ -2502,10 +2519,10 @@ function isEqual(e, t) {
|
|
|
2502
2519
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2503
2520
|
* date so its status flags reflect the current graph.
|
|
2504
2521
|
*/ function prepareComputed(e, t) {
|
|
2505
|
-
if (e.
|
|
2506
|
-
e.
|
|
2522
|
+
if (e.D & REACTIVE_LAZY) {
|
|
2523
|
+
e.D &= ~REACTIVE_LAZY;
|
|
2507
2524
|
recompute(e, true);
|
|
2508
|
-
} else if (e.
|
|
2525
|
+
} else if (e.D & REACTIVE_DISPOSED) {
|
|
2509
2526
|
recompute(e, true);
|
|
2510
2527
|
} else if (t) {
|
|
2511
2528
|
updateIfNecessary(e);
|
|
@@ -2526,11 +2543,11 @@ function isEqual(e, t) {
|
|
|
2526
2543
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2527
2544
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2528
2545
|
*/ function readNodeFast(e) {
|
|
2529
|
-
if (latestReadActive || pendingCheckActive || e.ke || e.Be || e.A !== undefined || e.
|
|
2546
|
+
if (latestReadActive || pendingCheckActive || e.ke || e.Be || e.A !== undefined || e.Le !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2530
2547
|
let t = context;
|
|
2531
2548
|
if (t?.Je) t = t.et;
|
|
2532
2549
|
if (t && tracking) link(e, t);
|
|
2533
|
-
return !t || e.
|
|
2550
|
+
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2534
2551
|
}
|
|
2535
2552
|
|
|
2536
2553
|
function read(e) {
|
|
@@ -2538,7 +2555,7 @@ function read(e) {
|
|
|
2538
2555
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2539
2556
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2540
2557
|
// than the original node (which stays "pending" while held in a transition).
|
|
2541
|
-
if (latestReadActive) return GlobalQueue.
|
|
2558
|
+
if (latestReadActive) return GlobalQueue.de(e);
|
|
2542
2559
|
let t = context;
|
|
2543
2560
|
if (t?.Je) t = t.et;
|
|
2544
2561
|
const n = e;
|
|
@@ -2548,13 +2565,13 @@ function read(e) {
|
|
|
2548
2565
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2549
2566
|
// recompute don't collect into the probe.
|
|
2550
2567
|
if (pendingCheckActive) {
|
|
2551
|
-
GlobalQueue.
|
|
2568
|
+
GlobalQueue.Se(e, t, i, r);
|
|
2552
2569
|
} else if (typeof n.ke === "function") {
|
|
2553
2570
|
prepareComputed(e, false);
|
|
2554
2571
|
}
|
|
2555
|
-
if (!n.ke && i === e && e.A === undefined && e.
|
|
2572
|
+
if (!n.ke && i === e && e.A === undefined && e.Le === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2556
2573
|
if (t && tracking) link(e, t);
|
|
2557
|
-
return !t || e.
|
|
2574
|
+
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2558
2575
|
}
|
|
2559
2576
|
if (t && tracking) {
|
|
2560
2577
|
link(e, t, pendingCheckActive);
|
|
@@ -2567,7 +2584,7 @@ function read(e) {
|
|
|
2567
2584
|
}
|
|
2568
2585
|
const r = i.ze;
|
|
2569
2586
|
// parent check is shallow, might need to be recursive
|
|
2570
|
-
if (r >= t.ze && e.
|
|
2587
|
+
if (r >= t.ze && e.Z !== t) {
|
|
2571
2588
|
t.ze = r + 1;
|
|
2572
2589
|
}
|
|
2573
2590
|
}
|
|
@@ -2577,15 +2594,15 @@ function read(e) {
|
|
|
2577
2594
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2578
2595
|
// is installed): under a lane, only same-lane pending async without an
|
|
2579
2596
|
// active override throws.
|
|
2580
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2597
|
+
if (currentOptimisticLane === null || GlobalQueue.Pe(i)) {
|
|
2581
2598
|
if (!tracking && e !== t) link(e, t);
|
|
2582
|
-
throw i.
|
|
2599
|
+
throw i.me;
|
|
2583
2600
|
}
|
|
2584
2601
|
} else if (t && i !== e && i.Qe & STATUS_UNINITIALIZED) {
|
|
2585
2602
|
if (!tracking && e !== t) link(e, t);
|
|
2586
|
-
throw i.
|
|
2603
|
+
throw i.me;
|
|
2587
2604
|
} else if (!t && i.Qe & STATUS_UNINITIALIZED) {
|
|
2588
|
-
throw i.
|
|
2605
|
+
throw i.me;
|
|
2589
2606
|
}
|
|
2590
2607
|
}
|
|
2591
2608
|
// `owner` is the computed itself, or the firewall behind a store node —
|
|
@@ -2597,17 +2614,17 @@ function read(e) {
|
|
|
2597
2614
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2598
2615
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2599
2616
|
// - owner._time < clock: only on a later cycle than the one the error was found
|
|
2600
|
-
if (tracking && !pendingCheckActive && i.
|
|
2617
|
+
if (tracking && !pendingCheckActive && i.H < clock) {
|
|
2601
2618
|
recompute(i);
|
|
2602
2619
|
return read(e);
|
|
2603
|
-
} else throw i.
|
|
2620
|
+
} else throw i.me;
|
|
2604
2621
|
}
|
|
2605
2622
|
if (snapshotCaptureActive && t && t.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2606
|
-
const n = e.
|
|
2623
|
+
const n = e.Le;
|
|
2607
2624
|
if (n !== undefined) {
|
|
2608
2625
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2609
|
-
const i = e.
|
|
2610
|
-
if (i !== r) t.
|
|
2626
|
+
const i = e.k !== NOT_PENDING ? e.k : e.We;
|
|
2627
|
+
if (i !== r) t.D |= REACTIVE_SNAPSHOT_STALE;
|
|
2611
2628
|
return r;
|
|
2612
2629
|
}
|
|
2613
2630
|
}
|
|
@@ -2622,18 +2639,18 @@ function read(e) {
|
|
|
2622
2639
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2623
2640
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2624
2641
|
// engine — a non-null lane implies it is installed.)
|
|
2625
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2642
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.ye(e, i, t)) {
|
|
2626
2643
|
return e.We;
|
|
2627
2644
|
}
|
|
2628
2645
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2629
2646
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2630
2647
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2631
2648
|
// (The lane-context clause lives with the engine.)
|
|
2632
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2649
|
+
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
2650
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2634
2651
|
// 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.Qe & STATUS_PENDING) && !e.
|
|
2652
|
+
if (pendingCheckActive) GlobalQueue.Te(e, o);
|
|
2653
|
+
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.Qe & STATUS_PENDING) && !e.U) {
|
|
2637
2654
|
unobserved(e);
|
|
2638
2655
|
}
|
|
2639
2656
|
return o;
|
|
@@ -2645,20 +2662,20 @@ function setSignal(e, t) {
|
|
|
2645
2662
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2646
2663
|
// _overrideValue slot, and every module that creates one installs the
|
|
2647
2664
|
// engine first.
|
|
2648
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2649
|
-
const n = e.
|
|
2665
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.pe(e, t);
|
|
2666
|
+
const n = e.k === NOT_PENDING ? e.We : e.k;
|
|
2650
2667
|
if (typeof t === "function") t = t(n);
|
|
2651
2668
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2652
2669
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2653
2670
|
const r = !!(e.Qe & STATUS_UNINITIALIZED) || !e.ht || !e.ht(n, t);
|
|
2654
2671
|
if (!r) return t;
|
|
2655
|
-
if (e.
|
|
2656
|
-
e.
|
|
2672
|
+
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2673
|
+
e.k = t;
|
|
2657
2674
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2658
2675
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
2659
2676
|
// only ever created, never removed, and creating one installs the hook).
|
|
2660
|
-
(e._ !== undefined || e.R !== undefined) && GlobalQueue.
|
|
2661
|
-
e.
|
|
2677
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.ae !== null && GlobalQueue.ae(e, t);
|
|
2678
|
+
e.H = clock;
|
|
2662
2679
|
insertSubs(e);
|
|
2663
2680
|
schedule();
|
|
2664
2681
|
return t;
|
|
@@ -2672,11 +2689,11 @@ function setSignal(e, t) {
|
|
|
2672
2689
|
* cleanup point.
|
|
2673
2690
|
*/ function suppressComputedRecompute(e) {
|
|
2674
2691
|
deleteFromHeap(e, queueFor(e));
|
|
2675
|
-
if (!(e.
|
|
2692
|
+
if (!(e.D & REACTIVE_MANUAL_WRITE) && e.k === NOT_PENDING) {
|
|
2676
2693
|
queuePendingNode(e);
|
|
2677
2694
|
schedule();
|
|
2678
2695
|
}
|
|
2679
|
-
e.
|
|
2696
|
+
e.D = e.D & -4 | REACTIVE_MANUAL_WRITE;
|
|
2680
2697
|
}
|
|
2681
2698
|
|
|
2682
2699
|
/**
|
|
@@ -2755,7 +2772,7 @@ function staleValues(e, t = true) {
|
|
|
2755
2772
|
if (!t) {
|
|
2756
2773
|
return;
|
|
2757
2774
|
}
|
|
2758
|
-
if (typeof t.ke === "function" && !(t.
|
|
2775
|
+
if (typeof t.ke === "function" && !(t.D & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2759
2776
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2760
2777
|
// same question: mark it so the recompute classifies any resulting
|
|
2761
2778
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2763,11 +2780,11 @@ function staleValues(e, t = true) {
|
|
|
2763
2780
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2764
2781
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2765
2782
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2766
|
-
if (!(t.
|
|
2767
|
-
t.
|
|
2783
|
+
if (!(t.D & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2784
|
+
t.D |= REACTIVE_REASK;
|
|
2768
2785
|
armReaskClear();
|
|
2769
2786
|
}
|
|
2770
|
-
t.
|
|
2787
|
+
t.D = t.D & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2771
2788
|
insertIntoHeap(t, queueFor(t));
|
|
2772
2789
|
schedule();
|
|
2773
2790
|
}
|
|
@@ -2833,8 +2850,8 @@ function externalUntrack(e) {
|
|
|
2833
2850
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2834
2851
|
// `externalSourceConfig` truthiness checks.
|
|
2835
2852
|
function syncExternalHooks() {
|
|
2836
|
-
GlobalQueue.
|
|
2837
|
-
GlobalQueue.
|
|
2853
|
+
GlobalQueue.ue = externalSourceConfig ? wireExternalSource : null;
|
|
2854
|
+
GlobalQueue.le = externalSourceConfig ? externalUntrack : null;
|
|
2838
2855
|
}
|
|
2839
2856
|
|
|
2840
2857
|
function enableExternalSource(e) {
|
|
@@ -2957,7 +2974,7 @@ function isUndefined(e) {
|
|
|
2957
2974
|
// No revert target is stashed: while the override is active every reader
|
|
2958
2975
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
2959
2976
|
// reverting is just dropping the override — _value is already correct.
|
|
2960
|
-
else globalQueue.
|
|
2977
|
+
else globalQueue.m.L.push(e);
|
|
2961
2978
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2962
2979
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2963
2980
|
// which a shared subscriber can merge across transactions (#2912).
|
|
@@ -2970,8 +2987,8 @@ function isUndefined(e) {
|
|
|
2970
2987
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2971
2988
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2972
2989
|
// neither companion present the call is a guaranteed no-op.
|
|
2973
|
-
(e._ !== undefined || e.R !== undefined) && GlobalQueue.
|
|
2974
|
-
e.
|
|
2990
|
+
(e._ !== undefined || e.R !== undefined) && GlobalQueue.ae !== null && GlobalQueue.ae(e, t);
|
|
2991
|
+
e.H = clock;
|
|
2975
2992
|
insertSubs(e, true);
|
|
2976
2993
|
schedule();
|
|
2977
2994
|
return t;
|
|
@@ -2982,9 +2999,9 @@ function isUndefined(e) {
|
|
|
2982
2999
|
* while one of its optimistic nodes holds an active override that is still
|
|
2983
3000
|
* pending on real (non-affects-sentinel) async.
|
|
2984
3001
|
*/ function transitionBlocked(e) {
|
|
2985
|
-
for (let t = 0; t < e.
|
|
2986
|
-
const n = e.
|
|
2987
|
-
if (hasActiveOverride(n) && "Qe" in n && n.Qe & STATUS_PENDING && n.
|
|
3002
|
+
for (let t = 0; t < e.L.length; t++) {
|
|
3003
|
+
const n = e.L[t];
|
|
3004
|
+
if (hasActiveOverride(n) && "Qe" in n && n.Qe & STATUS_PENDING && n.me instanceof NotReadyError) {
|
|
2988
3005
|
return true;
|
|
2989
3006
|
}
|
|
2990
3007
|
}
|
|
@@ -3014,9 +3031,9 @@ function resolveOptimisticNodes(e) {
|
|
|
3014
3031
|
// transition that produced them (A19 — pending is a property of the data).
|
|
3015
3032
|
for (let n = 0; n < t; n++) {
|
|
3016
3033
|
const t = e[n];
|
|
3017
|
-
if (t._ || t.R) GlobalQueue.
|
|
3034
|
+
if (t._ || t.R) GlobalQueue.Ee(t);
|
|
3018
3035
|
const r = t.t;
|
|
3019
|
-
if (r && (r._ === t || r.R === t)) GlobalQueue.
|
|
3036
|
+
if (r && (r._ === t || r.R === t)) GlobalQueue.Ee(r);
|
|
3020
3037
|
}
|
|
3021
3038
|
e.splice(0, t);
|
|
3022
3039
|
}
|
|
@@ -3069,10 +3086,10 @@ function cleanupCompletedLanes(e) {
|
|
|
3069
3086
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
3070
3087
|
* is recorded for replay at commit.
|
|
3071
3088
|
*/ function gatedRead(e, t, n) {
|
|
3072
|
-
if (latestReadActive || e.
|
|
3089
|
+
if (latestReadActive || e.k === NOT_PENDING || e.ke || t !== e && !(t.D & REACTIVE_MANUAL_WRITE)) {
|
|
3073
3090
|
return false;
|
|
3074
3091
|
}
|
|
3075
|
-
activeTransition.
|
|
3092
|
+
activeTransition.q.add(n);
|
|
3076
3093
|
return true;
|
|
3077
3094
|
}
|
|
3078
3095
|
|
|
@@ -3091,10 +3108,10 @@ function cleanupCompletedLanes(e) {
|
|
|
3091
3108
|
if (t) return resolveLane(e) ?? null;
|
|
3092
3109
|
for (let t = e.Ke; t; t = t.Ye) {
|
|
3093
3110
|
const n = t.qe;
|
|
3094
|
-
if (n.
|
|
3111
|
+
if (n.D & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
3095
3112
|
const t = resolveLane(n);
|
|
3096
3113
|
if (t) {
|
|
3097
|
-
e.
|
|
3114
|
+
e.D |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
3098
3115
|
assignOrMergeLane(e, t);
|
|
3099
3116
|
return t;
|
|
3100
3117
|
}
|
|
@@ -3108,7 +3125,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3108
3125
|
if (t.o !== e) {
|
|
3109
3126
|
t.u.add(e);
|
|
3110
3127
|
e.i = t;
|
|
3111
|
-
GlobalQueue.
|
|
3128
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
3112
3129
|
}
|
|
3113
3130
|
}
|
|
3114
3131
|
|
|
@@ -3116,13 +3133,13 @@ function cleanupCompletedLanes(e) {
|
|
|
3116
3133
|
const t = resolveLane(e);
|
|
3117
3134
|
if (t) {
|
|
3118
3135
|
t.u.delete(e);
|
|
3119
|
-
GlobalQueue.
|
|
3136
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(t.o);
|
|
3120
3137
|
}
|
|
3121
3138
|
}
|
|
3122
3139
|
|
|
3123
3140
|
function trackOptimisticStore(e) {
|
|
3124
3141
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
3125
|
-
globalQueue.
|
|
3142
|
+
globalQueue.m.V.add(e);
|
|
3126
3143
|
schedule();
|
|
3127
3144
|
}
|
|
3128
3145
|
|
|
@@ -3131,19 +3148,19 @@ function trackOptimisticStore(e) {
|
|
|
3131
3148
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
3132
3149
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
3133
3150
|
*/ 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.
|
|
3151
|
+
if (GlobalQueue.pe !== null) return;
|
|
3152
|
+
GlobalQueue.pe = optimisticWrite;
|
|
3153
|
+
GlobalQueue.Ie = resolveOptimisticNodes;
|
|
3154
|
+
GlobalQueue.Ae = transitionBlocked;
|
|
3155
|
+
GlobalQueue.he = cleanupCompletedLanes;
|
|
3156
|
+
GlobalQueue.Ne = runLaneEffects;
|
|
3157
|
+
GlobalQueue.ye = gatedRead;
|
|
3158
|
+
GlobalQueue.Pe = laneSuspends;
|
|
3159
|
+
GlobalQueue.Ce = laneReadsCommitted;
|
|
3160
|
+
GlobalQueue.ge = recomputeLane;
|
|
3161
|
+
GlobalQueue.be = laneAsyncPending;
|
|
3162
|
+
GlobalQueue.De = laneAsyncSettled;
|
|
3163
|
+
GlobalQueue.we = trackOptimisticStore;
|
|
3147
3164
|
}
|
|
3148
3165
|
|
|
3149
3166
|
/**
|
|
@@ -3200,7 +3217,7 @@ function collectPendingSources(e) {
|
|
|
3200
3217
|
* (`_pendingObserver`) are skipped so an `isPending` wrapper memo never
|
|
3201
3218
|
* inherits the coverage it reports on.
|
|
3202
3219
|
*/ function markWalk(e, t) {
|
|
3203
|
-
if (e.
|
|
3220
|
+
if (e.W) return true;
|
|
3204
3221
|
// A real error outranks an inherited mark (A16/A24c): an errored node
|
|
3205
3222
|
// answers probes with its error, not a coverage verdict, and coverage does
|
|
3206
3223
|
// not flow through it — matching the rails' behavior, where propagation
|
|
@@ -3216,7 +3233,7 @@ function collectPendingSources(e) {
|
|
|
3216
3233
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3217
3234
|
// latch a stale verdict on the companion.
|
|
3218
3235
|
const r = e;
|
|
3219
|
-
const i = r.
|
|
3236
|
+
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.ut : undefined;
|
|
3220
3237
|
if (i !== null) {
|
|
3221
3238
|
for (let e = r.Ke ?? null; e !== null; e = e.Ye) {
|
|
3222
3239
|
if (!e._t && markWalk(e.qe, t)) return true;
|
|
@@ -3244,7 +3261,7 @@ function newQuestionInFlight(e) {
|
|
|
3244
3261
|
|
|
3245
3262
|
function computePendingState(e) {
|
|
3246
3263
|
const t = e;
|
|
3247
|
-
if (t.
|
|
3264
|
+
if (t.D & REACTIVE_DISPOSED) return false;
|
|
3248
3265
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3249
3266
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3250
3267
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
@@ -3255,11 +3272,11 @@ function computePendingState(e) {
|
|
|
3255
3272
|
const n = t.Be || t;
|
|
3256
3273
|
return newQuestionInFlight(n);
|
|
3257
3274
|
}
|
|
3258
|
-
if (n && e.
|
|
3259
|
-
return !!(n.
|
|
3275
|
+
if (n && e.k !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3276
|
+
return !!(n.D & REACTIVE_MANUAL_WRITE) || !n.lt && !(n.Qe & STATUS_PENDING) || !!(n.Qe & STATUS_PENDING) && quietPending(n);
|
|
3260
3277
|
}
|
|
3261
|
-
if (e.
|
|
3262
|
-
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.
|
|
3278
|
+
if (e.k !== NOT_PENDING && !(t.Qe & STATUS_UNINITIALIZED)) {
|
|
3279
|
+
if (hasActiveOverride(e)) return !e.ht || !e.ht(e.k, unwrapOverride(e.A));
|
|
3263
3280
|
return true;
|
|
3264
3281
|
}
|
|
3265
3282
|
return newQuestionInFlight(t);
|
|
@@ -3298,7 +3315,7 @@ function updateChildCompanions(e) {
|
|
|
3298
3315
|
if (r.has(e)) return;
|
|
3299
3316
|
r.add(e);
|
|
3300
3317
|
if (e._ || e.R) n(e);
|
|
3301
|
-
for (let t = e.
|
|
3318
|
+
for (let t = e.U; t !== null; t = t.Ge) visit(t.Ve);
|
|
3302
3319
|
for (let t = e.rt ?? null; t !== null; t = t.it) {
|
|
3303
3320
|
visit(t);
|
|
3304
3321
|
}
|
|
@@ -3310,18 +3327,18 @@ function snapCompanionsToState(e) {
|
|
|
3310
3327
|
const t = e._;
|
|
3311
3328
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3312
3329
|
const n = computePendingState(e);
|
|
3313
|
-
if (t.We !== n || t.
|
|
3330
|
+
if (t.We !== n || t.k !== NOT_PENDING) {
|
|
3314
3331
|
t.We = n;
|
|
3315
|
-
t.
|
|
3316
|
-
t.
|
|
3332
|
+
t.k = NOT_PENDING;
|
|
3333
|
+
t.H = clock;
|
|
3317
3334
|
insertSubs(t);
|
|
3318
3335
|
schedule();
|
|
3319
3336
|
}
|
|
3320
3337
|
}
|
|
3321
3338
|
const n = e.R;
|
|
3322
|
-
if (n && !(n.
|
|
3323
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.
|
|
3324
|
-
n.
|
|
3339
|
+
if (n && !(n.D & REACTIVE_DISPOSED)) {
|
|
3340
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.k === NOT_PENDING && !Object.is(n.We, e.We) && !(n.D & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3341
|
+
n.D |= REACTIVE_DIRTY;
|
|
3325
3342
|
insertIntoHeap(n, queueFor(n));
|
|
3326
3343
|
insertSubs(n);
|
|
3327
3344
|
schedule();
|
|
@@ -3362,7 +3379,7 @@ function getLatestValueComputed(e) {
|
|
|
3362
3379
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3363
3380
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3364
3381
|
const e = queueFor(t);
|
|
3365
|
-
if (t.ze >= e.P && !(t.
|
|
3382
|
+
if (t.ze >= e.P && !(t.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3366
3383
|
markHeap(e);
|
|
3367
3384
|
prepareComputed(t, true);
|
|
3368
3385
|
}
|
|
@@ -3385,7 +3402,7 @@ function getLatestValueComputed(e) {
|
|
|
3385
3402
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
3386
3403
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
3387
3404
|
// other transition's committed view, matching read()'s own selection.
|
|
3388
|
-
if (t.
|
|
3405
|
+
if (t.k !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.T && activeTransition !== t.T)) return t.k;
|
|
3389
3406
|
return i;
|
|
3390
3407
|
}
|
|
3391
3408
|
|
|
@@ -3396,7 +3413,7 @@ function getLatestValueComputed(e) {
|
|
|
3396
3413
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3397
3414
|
if (tracking && e !== t) link(e, t);
|
|
3398
3415
|
setPendingCheckActive(true);
|
|
3399
|
-
throw n.
|
|
3416
|
+
throw n.me;
|
|
3400
3417
|
}
|
|
3401
3418
|
collectPendingSources(e);
|
|
3402
3419
|
if (r) collectPendingSources(r);
|
|
@@ -3404,7 +3421,7 @@ function getLatestValueComputed(e) {
|
|
|
3404
3421
|
}
|
|
3405
3422
|
|
|
3406
3423
|
function recordFreshRead(e, t) {
|
|
3407
|
-
if (pendingProbe !== null && e.
|
|
3424
|
+
if (pendingProbe !== null && e.k !== NOT_PENDING && t === e.k) pendingProbe.freshReads.add(e);
|
|
3408
3425
|
}
|
|
3409
3426
|
|
|
3410
3427
|
function applyReask(e, t) {
|
|
@@ -3465,25 +3482,25 @@ function isPending(e) {
|
|
|
3465
3482
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3466
3483
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3467
3484
|
// direct calls used, so behavior is identical once this module loads.
|
|
3468
|
-
GlobalQueue.
|
|
3485
|
+
GlobalQueue.ae = syncCompanions;
|
|
3469
3486
|
|
|
3470
|
-
GlobalQueue.
|
|
3487
|
+
GlobalQueue.ce = updatePendingSignal;
|
|
3471
3488
|
|
|
3472
|
-
GlobalQueue.
|
|
3489
|
+
GlobalQueue.fe = updateChildCompanions;
|
|
3473
3490
|
|
|
3474
|
-
GlobalQueue.
|
|
3491
|
+
GlobalQueue.Ee = snapCompanionsToState;
|
|
3475
3492
|
|
|
3476
|
-
GlobalQueue.
|
|
3493
|
+
GlobalQueue.de = latestRead;
|
|
3477
3494
|
|
|
3478
|
-
GlobalQueue.
|
|
3495
|
+
GlobalQueue.Se = pendingCheckRead;
|
|
3479
3496
|
|
|
3480
|
-
GlobalQueue.
|
|
3497
|
+
GlobalQueue.Te = recordFreshRead;
|
|
3481
3498
|
|
|
3482
|
-
GlobalQueue.
|
|
3499
|
+
GlobalQueue.Oe = applyReask;
|
|
3483
3500
|
|
|
3484
|
-
GlobalQueue.
|
|
3501
|
+
GlobalQueue._e = repollDownstreamVerdicts;
|
|
3485
3502
|
|
|
3486
|
-
GlobalQueue.
|
|
3503
|
+
GlobalQueue.Re = witnessAffects;
|
|
3487
3504
|
|
|
3488
3505
|
/**
|
|
3489
3506
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3499,7 +3516,7 @@ GlobalQueue._e = witnessAffects;
|
|
|
3499
3516
|
function notifyEffectStatus(e, t) {
|
|
3500
3517
|
// Use passed values if provided, otherwise read from node
|
|
3501
3518
|
const n = e !== undefined ? e : this.Qe;
|
|
3502
|
-
const r = t !== undefined ? t : this.
|
|
3519
|
+
const r = t !== undefined ? t : this.me;
|
|
3503
3520
|
if (n & STATUS_ERROR) {
|
|
3504
3521
|
this.Ze.notify(this, STATUS_PENDING, 0);
|
|
3505
3522
|
if (this.Fe === EFFECT_USER) {
|
|
@@ -3528,7 +3545,7 @@ function notifyEffectStatus(e, t) {
|
|
|
3528
3545
|
}
|
|
3529
3546
|
|
|
3530
3547
|
function runEffect(e) {
|
|
3531
|
-
if (!e.xe || e.
|
|
3548
|
+
if (!e.xe || e.D & REACTIVE_DISPOSED) return;
|
|
3532
3549
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3533
3550
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3534
3551
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3540,7 +3557,7 @@ function runEffect(e) {
|
|
|
3540
3557
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3541
3558
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3542
3559
|
if (e.Qe & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3543
|
-
const t = unwrapStatusError(e.
|
|
3560
|
+
const t = unwrapStatusError(e.me);
|
|
3544
3561
|
e.bt = e.We;
|
|
3545
3562
|
e.xe = false;
|
|
3546
3563
|
try {
|
|
@@ -3566,7 +3583,7 @@ function runEffect(e) {
|
|
|
3566
3583
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3567
3584
|
e.Et = n;
|
|
3568
3585
|
} catch (t) {
|
|
3569
|
-
e.
|
|
3586
|
+
e.me = new StatusError(e, t);
|
|
3570
3587
|
e.Qe |= STATUS_ERROR;
|
|
3571
3588
|
if (!e.Ze.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3572
3589
|
haltReactivity(t);
|
|
@@ -3578,7 +3595,7 @@ function runEffect(e) {
|
|
|
3578
3595
|
}
|
|
3579
3596
|
}
|
|
3580
3597
|
|
|
3581
|
-
GlobalQueue.
|
|
3598
|
+
GlobalQueue.te = runEffect;
|
|
3582
3599
|
|
|
3583
3600
|
/**
|
|
3584
3601
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3586,7 +3603,7 @@ GlobalQueue.ee = runEffect;
|
|
|
3586
3603
|
* Uses stale reads.
|
|
3587
3604
|
*/ function trackedEffect(e, t) {
|
|
3588
3605
|
const run = () => {
|
|
3589
|
-
if (!n.xe || n.
|
|
3606
|
+
if (!n.xe || n.D & REACTIVE_DISPOSED) return;
|
|
3590
3607
|
try {
|
|
3591
3608
|
n.xe = false;
|
|
3592
3609
|
recompute(n);
|
|
@@ -3610,7 +3627,7 @@ GlobalQueue.ee = runEffect;
|
|
|
3610
3627
|
const r = e !== undefined ? e : n.Qe;
|
|
3611
3628
|
if (r & STATUS_ERROR) {
|
|
3612
3629
|
n.Ze.notify(n, STATUS_PENDING, 0);
|
|
3613
|
-
const e = t !== undefined ? t : n.
|
|
3630
|
+
const e = t !== undefined ? t : n.me;
|
|
3614
3631
|
if (!n.Ze.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3615
3632
|
haltReactivity(unwrapStatusError(e));
|
|
3616
3633
|
throw e;
|
|
@@ -3695,11 +3712,11 @@ function restoreTransition(e, t) {
|
|
|
3695
3712
|
const i = e(...t);
|
|
3696
3713
|
globalQueue.initTransition();
|
|
3697
3714
|
let o = activeTransition;
|
|
3698
|
-
o
|
|
3715
|
+
o.j.push(i);
|
|
3699
3716
|
const done = (e, t, s = false) => {
|
|
3700
3717
|
o = currentTransition(o);
|
|
3701
|
-
const u = o
|
|
3702
|
-
if (u >= 0) o
|
|
3718
|
+
const u = o.j.indexOf(i);
|
|
3719
|
+
if (u >= 0) o.j.splice(u, 1);
|
|
3703
3720
|
// Re-adopt through initTransition like every other resumption site:
|
|
3704
3721
|
// a bare setActiveTransition leaves globalQueue._batch as a detached
|
|
3705
3722
|
// ambient batch, and anything registered before the scheduled flush
|
|
@@ -4016,7 +4033,7 @@ function createEffect(e, t, n) {
|
|
|
4016
4033
|
// route through the inherited queue.
|
|
4017
4034
|
const i = getOwner();
|
|
4018
4035
|
const o = new MicrotaskQueue;
|
|
4019
|
-
o.
|
|
4036
|
+
o.Z = i.Ze;
|
|
4020
4037
|
// notify() forwards up the normal chain
|
|
4021
4038
|
i.Ze = o;
|
|
4022
4039
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
@@ -5287,7 +5304,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
5287
5304
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
5288
5305
|
* override, else held pending value, else committed value.
|
|
5289
5306
|
*/ function visibleNodeValue(e) {
|
|
5290
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
5307
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.k !== NOT_PENDING ? e.k : e.We;
|
|
5291
5308
|
}
|
|
5292
5309
|
|
|
5293
5310
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -5342,7 +5359,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5342
5359
|
}
|
|
5343
5360
|
if (o && n in o) {
|
|
5344
5361
|
const e = o[n];
|
|
5345
|
-
s.
|
|
5362
|
+
s.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
5346
5363
|
snapshotSources?.add(s);
|
|
5347
5364
|
}
|
|
5348
5365
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -5371,8 +5388,8 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
5371
5388
|
*/ function inheritAffectsMarks(e, t, n) {
|
|
5372
5389
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
5373
5390
|
for (const [r, i] of affectsScopes) {
|
|
5374
|
-
if (r.
|
|
5375
|
-
GlobalQueue.
|
|
5391
|
+
if (r.W && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
5392
|
+
GlobalQueue.oe(e);
|
|
5376
5393
|
i.inherited.push(e);
|
|
5377
5394
|
}
|
|
5378
5395
|
}
|
|
@@ -5460,11 +5477,11 @@ i) {
|
|
|
5460
5477
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
5461
5478
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
5462
5479
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
5463
|
-
if (n?.
|
|
5480
|
+
if (n?.W) GlobalQueue.Re(n);
|
|
5464
5481
|
if (affectsScopes.size) {
|
|
5465
5482
|
const r = e[STORE_VALUE];
|
|
5466
5483
|
for (const [e, i] of affectsScopes) {
|
|
5467
|
-
if (e !== n && e.
|
|
5484
|
+
if (e !== n && e.W && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.Re(e);
|
|
5468
5485
|
}
|
|
5469
5486
|
}
|
|
5470
5487
|
}
|
|
@@ -5481,11 +5498,11 @@ i) {
|
|
|
5481
5498
|
* @internal
|
|
5482
5499
|
*/ function getStoreAffectsNodes(e, t) {
|
|
5483
5500
|
const n = getNodes(e, STORE_NODE);
|
|
5484
|
-
GlobalQueue.
|
|
5501
|
+
GlobalQueue.re ||= e => {
|
|
5485
5502
|
const t = affectsScopes.get(e);
|
|
5486
5503
|
if (!t) return;
|
|
5487
5504
|
affectsScopes.delete(e);
|
|
5488
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
5505
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.se(t.inherited[e]);
|
|
5489
5506
|
};
|
|
5490
5507
|
if (t === undefined) {
|
|
5491
5508
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -5640,7 +5657,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5640
5657
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5641
5658
|
// optimistic engine before wrapping.
|
|
5642
5659
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5643
|
-
GlobalQueue.
|
|
5660
|
+
GlobalQueue.we(t);
|
|
5644
5661
|
}
|
|
5645
5662
|
}
|
|
5646
5663
|
|
|
@@ -5736,7 +5753,7 @@ let Writing = null;
|
|
|
5736
5753
|
const t = e[STORE_FIREWALL];
|
|
5737
5754
|
if (!t) return;
|
|
5738
5755
|
const n = t.Qe;
|
|
5739
|
-
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.
|
|
5756
|
+
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.me ?? new NotReadyError(t);
|
|
5740
5757
|
}
|
|
5741
5758
|
|
|
5742
5759
|
const storeTraps = {
|
|
@@ -6082,7 +6099,7 @@ function createStore(e, t, n) {
|
|
|
6082
6099
|
* nothing is stored downstream and nothing can be stranded or stripped by
|
|
6083
6100
|
* mid-window recomputes.
|
|
6084
6101
|
*/ function markAffects(e) {
|
|
6085
|
-
e.
|
|
6102
|
+
e.W = (e.W || 0) + 1;
|
|
6086
6103
|
shiftAffectsMarks(1);
|
|
6087
6104
|
}
|
|
6088
6105
|
|
|
@@ -6098,9 +6115,9 @@ function createStore(e, t, n) {
|
|
|
6098
6115
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
6099
6116
|
* no visual change.
|
|
6100
6117
|
*/ function notifyMarkBoundaries(e) {
|
|
6101
|
-
if (!e.
|
|
6118
|
+
if (!e.U && !e.rt) return;
|
|
6102
6119
|
const t = new NotReadyError(e);
|
|
6103
|
-
t.
|
|
6120
|
+
t.ve = true;
|
|
6104
6121
|
const n = new Set;
|
|
6105
6122
|
const visit = e => {
|
|
6106
6123
|
if (n.has(e)) return;
|
|
@@ -6126,10 +6143,10 @@ function createStore(e, t, n) {
|
|
|
6126
6143
|
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
6127
6144
|
*/ function registerAffectsMark(e) {
|
|
6128
6145
|
markAffects(e);
|
|
6129
|
-
globalQueue.
|
|
6146
|
+
globalQueue.m.G.push(e);
|
|
6130
6147
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
6131
6148
|
// without them there is no materialized verdict to poke.
|
|
6132
|
-
GlobalQueue.
|
|
6149
|
+
GlobalQueue._e !== null && GlobalQueue._e(e);
|
|
6133
6150
|
notifyMarkBoundaries(e);
|
|
6134
6151
|
schedule();
|
|
6135
6152
|
}
|
|
@@ -6141,10 +6158,10 @@ function createStore(e, t, n) {
|
|
|
6141
6158
|
* setSignal would open a fresh override window that nothing settles).
|
|
6142
6159
|
*/ function releaseAffectsMark(e) {
|
|
6143
6160
|
shiftAffectsMarks(-1);
|
|
6144
|
-
e.
|
|
6145
|
-
if (!e.
|
|
6146
|
-
GlobalQueue.
|
|
6147
|
-
GlobalQueue.
|
|
6161
|
+
e.W--;
|
|
6162
|
+
if (!e.W) {
|
|
6163
|
+
GlobalQueue._e !== null && GlobalQueue._e(e, true);
|
|
6164
|
+
GlobalQueue.re?.(e);
|
|
6148
6165
|
}
|
|
6149
6166
|
}
|
|
6150
6167
|
|
|
@@ -6161,11 +6178,11 @@ function createStore(e, t, n) {
|
|
|
6161
6178
|
// Each call site is gated by state only this module creates (a non-empty
|
|
6162
6179
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
6163
6180
|
// hooks are installed before the first time any of them can fire.
|
|
6164
|
-
GlobalQueue.
|
|
6181
|
+
GlobalQueue.ie = releaseAffectsMarks;
|
|
6165
6182
|
|
|
6166
|
-
GlobalQueue.
|
|
6183
|
+
GlobalQueue.oe = markAffects;
|
|
6167
6184
|
|
|
6168
|
-
GlobalQueue.
|
|
6185
|
+
GlobalQueue.se = releaseAffectsMark;
|
|
6169
6186
|
|
|
6170
6187
|
function affects(e, t) {
|
|
6171
6188
|
const n = e?.[$TARGET];
|
|
@@ -6186,8 +6203,8 @@ function createOptimisticStore(e, t, n) {
|
|
|
6186
6203
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
6187
6204
|
// node can be created.
|
|
6188
6205
|
installOptimisticEngine();
|
|
6189
|
-
if (!GlobalQueue.
|
|
6190
|
-
GlobalQueue.
|
|
6206
|
+
if (!GlobalQueue.ne) {
|
|
6207
|
+
GlobalQueue.ne = clearOptimisticStores;
|
|
6191
6208
|
// Store half of the engine's override blockage (#2951): signal-form
|
|
6192
6209
|
// createOptimistic carries the pending async and the override on ONE node,
|
|
6193
6210
|
// so transitionBlocked sees both; a derived optimistic STORE splits them —
|
|
@@ -6198,9 +6215,9 @@ function createOptimisticStore(e, t, n) {
|
|
|
6198
6215
|
// clobbering instead of composing). Optimistic state clears when truth
|
|
6199
6216
|
// lands or its transaction ends — never mid-refetch. Wrapped here (engine
|
|
6200
6217
|
// is already installed above) so store-free apps never carry the check.
|
|
6201
|
-
const e = GlobalQueue.
|
|
6202
|
-
GlobalQueue.
|
|
6203
|
-
for (const e of t.
|
|
6218
|
+
const e = GlobalQueue.Ae;
|
|
6219
|
+
GlobalQueue.Ae = t => {
|
|
6220
|
+
for (const e of t.V) {
|
|
6204
6221
|
if ((e[$TARGET]?.[STORE_FIREWALL]?.Qe ?? 0) & STATUS_PENDING) return true;
|
|
6205
6222
|
}
|
|
6206
6223
|
return e(t);
|
|
@@ -6285,7 +6302,7 @@ function clearOptimisticStores(e, t) {
|
|
|
6285
6302
|
const o = visibleNodeValue(a);
|
|
6286
6303
|
a.A = NOT_PENDING;
|
|
6287
6304
|
a.p = null;
|
|
6288
|
-
a.
|
|
6305
|
+
a.k = NOT_PENDING;
|
|
6289
6306
|
a.We = i;
|
|
6290
6307
|
if (!a.ht || !a.ht(o, i)) {
|
|
6291
6308
|
insertSubs(a, true);
|
|
@@ -7090,7 +7107,7 @@ function boundaryComputed(e, t) {
|
|
|
7090
7107
|
n.yt = (e, t) => {
|
|
7091
7108
|
// Use passed values if provided, otherwise read from node
|
|
7092
7109
|
const r = e !== undefined ? e : n.Qe;
|
|
7093
|
-
const i = t !== undefined ? t : n.
|
|
7110
|
+
const i = t !== undefined ? t : n.me;
|
|
7094
7111
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
7095
7112
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
7096
7113
|
// a boundary that handles it is found.
|
|
@@ -7103,7 +7120,7 @@ function boundaryComputed(e, t) {
|
|
|
7103
7120
|
const s = r & ~n.Yt & (STATUS_PENDING | STATUS_ERROR);
|
|
7104
7121
|
if (s) {
|
|
7105
7122
|
n.Qe &= ~s;
|
|
7106
|
-
if (n.
|
|
7123
|
+
if (n.me === i && !(n.Qe & (STATUS_PENDING | STATUS_ERROR))) n.me = undefined;
|
|
7107
7124
|
}
|
|
7108
7125
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
7109
7126
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -7306,7 +7323,7 @@ class CollectionQueue extends Queue {
|
|
|
7306
7323
|
ownedWrite: true,
|
|
7307
7324
|
gt: true
|
|
7308
7325
|
});
|
|
7309
|
-
|
|
7326
|
+
me;
|
|
7310
7327
|
Jt=signal(false, {
|
|
7311
7328
|
ownedWrite: true,
|
|
7312
7329
|
gt: true
|
|
@@ -7352,13 +7369,13 @@ class CollectionQueue extends Queue {
|
|
|
7352
7369
|
if (this.Tn & STATUS_PENDING && this.rn) return super.notify(e, t, n, r);
|
|
7353
7370
|
if (n & this.Tn) {
|
|
7354
7371
|
this.Zt = true;
|
|
7355
|
-
const t = r?.source || e.
|
|
7372
|
+
const t = r?.source || e.me?.source;
|
|
7356
7373
|
if (t) {
|
|
7357
7374
|
const e = this.Bt.size === 0;
|
|
7358
7375
|
this.Bt.add(t);
|
|
7359
7376
|
if (e) setSignal(this.zt, true);
|
|
7360
7377
|
if (this.Tn & STATUS_ERROR) {
|
|
7361
|
-
setSignal(this.
|
|
7378
|
+
setSignal(this.me, unwrapStatusError(t.me));
|
|
7362
7379
|
}
|
|
7363
7380
|
}
|
|
7364
7381
|
}
|
|
@@ -7371,7 +7388,7 @@ class CollectionQueue extends Queue {
|
|
|
7371
7388
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7372
7389
|
// status of its own, so the count is the liveness test. The release
|
|
7373
7390
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7374
|
-
if (e.
|
|
7391
|
+
if (e.D & REACTIVE_DISPOSED || !e.W && !(e.Qe & this.Tn) && !(this.Tn & STATUS_ERROR && e.Qe & STATUS_PENDING)) this.Bt.delete(e);
|
|
7375
7392
|
}
|
|
7376
7393
|
if (!this.Bt.size) {
|
|
7377
7394
|
if (this.Tn & STATUS_PENDING && this.Zt && !this.rn && this.On) {
|
|
@@ -7397,7 +7414,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7397
7414
|
const i = createOwner();
|
|
7398
7415
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
7399
7416
|
const o = new CollectionQueue(e);
|
|
7400
|
-
if (e === STATUS_ERROR) o.
|
|
7417
|
+
if (e === STATUS_ERROR) o.me = signal(undefined, {
|
|
7401
7418
|
ownedWrite: true,
|
|
7402
7419
|
gt: true
|
|
7403
7420
|
});
|
|
@@ -7411,7 +7428,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7411
7428
|
} catch (e) {
|
|
7412
7429
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7413
7430
|
}
|
|
7414
|
-
o.Zt = t || !!(s.Qe & e) || s.
|
|
7431
|
+
o.Zt = t || !!(s.Qe & e) || s.me instanceof NotReadyError;
|
|
7415
7432
|
});
|
|
7416
7433
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7417
7434
|
if (u) {
|
|
@@ -7488,7 +7505,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7488
7505
|
* }
|
|
7489
7506
|
* ```
|
|
7490
7507
|
*/ function createErrorBoundary(e, t) {
|
|
7491
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
7508
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.me), () => {
|
|
7492
7509
|
for (const t of e.Bt) recompute(t);
|
|
7493
7510
|
schedule();
|
|
7494
7511
|
}));
|