@solidjs/signals 2.0.0-beta.23 → 2.0.0-beta.24
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 +171 -65
- package/dist/node.cjs +1116 -995
- package/dist/prod/core/core.js +14 -11
- package/dist/prod/core/error.js +9 -0
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/scheduler.js +6 -6
- package/dist/prod/core/verdict.js +1 -1
- package/dist/prod/map.js +53 -29
- package/dist/prod/store/optimistic.js +29 -27
- package/dist/prod/store/reconcile.js +92 -61
- package/dist/prod/store/store.js +142 -102
- package/dist/prod/store/utils.js +12 -0
- package/dist/types/core/error.d.ts +1 -1
- package/dist/types/store/reconcile.d.ts +17 -8
- package/dist/types-cjs/core/error.d.cts +1 -1
- package/dist/types-cjs/store/reconcile.d.cts +17 -8
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -26,7 +26,16 @@
|
|
|
26
26
|
*/ class NotReadyError extends Error {
|
|
27
27
|
source;
|
|
28
28
|
constructor(e) {
|
|
29
|
+
// Control-flow throw: it happens on every read of a pending source, so in
|
|
30
|
+
// production skip V8's eager stack capture (proportional to stack depth —
|
|
31
|
+
// real cost under SSR) by zeroing the V8-specific stackTraceLimit around
|
|
32
|
+
// super(). Dev keeps the stack for debuggability; non-V8 engines (no
|
|
33
|
+
// stackTraceLimit) take the plain path.
|
|
34
|
+
const t = Error;
|
|
35
|
+
const n = t.stackTraceLimit;
|
|
36
|
+
if (n !== undefined) t.stackTraceLimit = 0;
|
|
29
37
|
super();
|
|
38
|
+
if (n !== undefined) t.stackTraceLimit = n;
|
|
30
39
|
this.source = e;
|
|
31
40
|
}
|
|
32
41
|
}
|
|
@@ -224,8 +233,8 @@ const activeLanes = new Set;
|
|
|
224
233
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
225
234
|
// the owner's write merges the companion's subscribers into this lane and
|
|
226
235
|
// their effects wait on its async instead of flushing immediately.
|
|
227
|
-
adoptCompanionLane(e.
|
|
228
|
-
adoptCompanionLane(e.
|
|
236
|
+
adoptCompanionLane(e.O, t);
|
|
237
|
+
adoptCompanionLane(e.p, t);
|
|
229
238
|
return t;
|
|
230
239
|
}
|
|
231
240
|
|
|
@@ -330,15 +339,15 @@ const transitions = new Set;
|
|
|
330
339
|
const dirtyQueue = {
|
|
331
340
|
h: new Array(2e3).fill(undefined),
|
|
332
341
|
N: false,
|
|
333
|
-
|
|
334
|
-
|
|
342
|
+
P: 0,
|
|
343
|
+
C: 0
|
|
335
344
|
};
|
|
336
345
|
|
|
337
346
|
const zombieQueue = {
|
|
338
347
|
h: new Array(2e3).fill(undefined),
|
|
339
348
|
N: false,
|
|
340
|
-
|
|
341
|
-
|
|
349
|
+
P: 0,
|
|
350
|
+
C: 0
|
|
342
351
|
};
|
|
343
352
|
|
|
344
353
|
let clock = 0;
|
|
@@ -367,13 +376,13 @@ function registerTransientStoreNode(e) {
|
|
|
367
376
|
|
|
368
377
|
function canUseSimpleSyncFlush(e) {
|
|
369
378
|
const t = e.D;
|
|
370
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.
|
|
379
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.G.length === 0 && t.L.size === 0 && transientStoreNodes.size === 0;
|
|
371
380
|
}
|
|
372
381
|
|
|
373
382
|
function sweepTransientStoreNodes() {
|
|
374
383
|
if (transientStoreNodes.size === 0) return;
|
|
375
384
|
for (const e of transientStoreNodes) {
|
|
376
|
-
if (e.
|
|
385
|
+
if (e.U !== null) {
|
|
377
386
|
transientStoreNodes.delete(e);
|
|
378
387
|
continue;
|
|
379
388
|
}
|
|
@@ -382,9 +391,9 @@ function sweepTransientStoreNodes() {
|
|
|
382
391
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
383
392
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
384
393
|
// unmarked node for the same property).
|
|
385
|
-
if (e.
|
|
394
|
+
if (e.k) continue;
|
|
386
395
|
transientStoreNodes.delete(e);
|
|
387
|
-
e.
|
|
396
|
+
e.F?.();
|
|
388
397
|
}
|
|
389
398
|
}
|
|
390
399
|
|
|
@@ -411,19 +420,19 @@ function setProjectionWriteActive(e) {
|
|
|
411
420
|
* land there directly — no per-field aliasing.
|
|
412
421
|
*/ function createBatch() {
|
|
413
422
|
return {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
423
|
+
W: clock,
|
|
424
|
+
M: [],
|
|
425
|
+
H: new Map,
|
|
426
|
+
v: [],
|
|
417
427
|
G: [],
|
|
418
|
-
L:
|
|
419
|
-
U: new Set,
|
|
428
|
+
L: new Set,
|
|
420
429
|
$: [],
|
|
421
|
-
|
|
422
|
-
|
|
430
|
+
j: {
|
|
431
|
+
K: [ [], [] ],
|
|
423
432
|
m: []
|
|
424
433
|
},
|
|
425
434
|
I: false,
|
|
426
|
-
|
|
435
|
+
Y: new Set
|
|
427
436
|
};
|
|
428
437
|
}
|
|
429
438
|
|
|
@@ -431,27 +440,27 @@ function mergeTransitionState(e, t) {
|
|
|
431
440
|
t.I = e;
|
|
432
441
|
e.$.push(...t.$);
|
|
433
442
|
for (const n of activeLanes) if (n.T === t) n.T = e;
|
|
434
|
-
if (t.
|
|
443
|
+
if (t.v.length) {
|
|
435
444
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
436
445
|
// transition, and the adoption pass in initTransition would re-push its
|
|
437
446
|
// contents into the target — duplicating every entry.
|
|
438
|
-
e.
|
|
439
|
-
t.
|
|
447
|
+
e.v.push(...t.v);
|
|
448
|
+
t.v.length = 0;
|
|
440
449
|
}
|
|
441
|
-
if (t.
|
|
450
|
+
if (t.G.length) {
|
|
442
451
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
443
452
|
// transition, and the adoption pass in initTransition would re-push its
|
|
444
453
|
// contents into the target — double-releasing every mark.
|
|
445
|
-
e.
|
|
446
|
-
t.
|
|
454
|
+
e.G.push(...t.G);
|
|
455
|
+
t.G.length = 0;
|
|
447
456
|
}
|
|
448
|
-
for (const n of t.
|
|
449
|
-
for (const [n, r] of t.
|
|
450
|
-
let t = e.
|
|
451
|
-
if (!t) e.
|
|
457
|
+
for (const n of t.L) e.L.add(n);
|
|
458
|
+
for (const [n, r] of t.H) {
|
|
459
|
+
let t = e.H.get(n);
|
|
460
|
+
if (!t) e.H.set(n, t = new Set);
|
|
452
461
|
for (const e of r) t.add(e);
|
|
453
462
|
}
|
|
454
|
-
for (const n of t.
|
|
463
|
+
for (const n of t.Y) e.Y.add(n);
|
|
455
464
|
}
|
|
456
465
|
|
|
457
466
|
function schedule() {
|
|
@@ -461,7 +470,7 @@ function schedule() {
|
|
|
461
470
|
}
|
|
462
471
|
if (scheduled) return;
|
|
463
472
|
scheduled = true;
|
|
464
|
-
if (!syncDepth && !globalQueue.
|
|
473
|
+
if (!syncDepth && !globalQueue.q && !projectionWriteActive) queueMicrotask(flush);
|
|
465
474
|
}
|
|
466
475
|
|
|
467
476
|
/**
|
|
@@ -491,29 +500,29 @@ function notifyHalted() {
|
|
|
491
500
|
}
|
|
492
501
|
|
|
493
502
|
class Queue {
|
|
494
|
-
|
|
495
|
-
|
|
503
|
+
B=null;
|
|
504
|
+
K=[ [], [] ];
|
|
496
505
|
m=[];
|
|
497
506
|
created=clock;
|
|
498
507
|
addChild(e) {
|
|
499
508
|
this.m.push(e);
|
|
500
|
-
e.
|
|
509
|
+
e.B = this;
|
|
501
510
|
}
|
|
502
511
|
removeChild(e) {
|
|
503
512
|
const t = this.m.indexOf(e);
|
|
504
513
|
if (t >= 0) {
|
|
505
514
|
this.m.splice(t, 1);
|
|
506
|
-
e.
|
|
515
|
+
e.B = null;
|
|
507
516
|
}
|
|
508
517
|
}
|
|
509
518
|
notify(e, t, n, r) {
|
|
510
|
-
if (this.
|
|
519
|
+
if (this.B) return this.B.notify(e, t, n, r);
|
|
511
520
|
return false;
|
|
512
521
|
}
|
|
513
522
|
run(e) {
|
|
514
|
-
if (this.
|
|
515
|
-
const t = this.
|
|
516
|
-
this.
|
|
523
|
+
if (this.K[e - 1].length) {
|
|
524
|
+
const t = this.K[e - 1];
|
|
525
|
+
this.K[e - 1] = [];
|
|
517
526
|
runQueue$1(t, e);
|
|
518
527
|
}
|
|
519
528
|
for (let t = 0; t < this.m.length; t++) this.m[t].run?.(e);
|
|
@@ -525,21 +534,21 @@ class Queue {
|
|
|
525
534
|
const n = findLane(currentOptimisticLane);
|
|
526
535
|
n.l[e - 1].push(t);
|
|
527
536
|
} else {
|
|
528
|
-
this.
|
|
537
|
+
this.K[e - 1].push(t);
|
|
529
538
|
}
|
|
530
539
|
}
|
|
531
540
|
schedule();
|
|
532
541
|
}
|
|
533
542
|
stashQueues(e) {
|
|
534
|
-
e.
|
|
535
|
-
e.
|
|
536
|
-
this.
|
|
543
|
+
e.K[0].push(...this.K[0]);
|
|
544
|
+
e.K[1].push(...this.K[1]);
|
|
545
|
+
this.K = [ [], [] ];
|
|
537
546
|
for (let t = 0; t < this.m.length; t++) {
|
|
538
547
|
let n = this.m[t];
|
|
539
548
|
let r = e.m[t];
|
|
540
549
|
if (!r) {
|
|
541
550
|
r = {
|
|
542
|
-
|
|
551
|
+
K: [ [], [] ],
|
|
543
552
|
m: []
|
|
544
553
|
};
|
|
545
554
|
e.m[t] = r;
|
|
@@ -548,8 +557,8 @@ class Queue {
|
|
|
548
557
|
}
|
|
549
558
|
}
|
|
550
559
|
restoreQueues(e) {
|
|
551
|
-
this.
|
|
552
|
-
this.
|
|
560
|
+
this.K[0].push(...e.K[0]);
|
|
561
|
+
this.K[1].push(...e.K[1]);
|
|
553
562
|
for (let t = 0; t < e.m.length; t++) {
|
|
554
563
|
const n = e.m[t];
|
|
555
564
|
let r = this.m[t];
|
|
@@ -559,45 +568,45 @@ class Queue {
|
|
|
559
568
|
}
|
|
560
569
|
|
|
561
570
|
class GlobalQueue extends Queue {
|
|
562
|
-
|
|
571
|
+
q=false;
|
|
563
572
|
// The current transaction-shaped batch: a plain ambient batch while no
|
|
564
573
|
// transition is active, the active transition itself after initTransition.
|
|
565
574
|
D=createBatch();
|
|
575
|
+
static Z;
|
|
566
576
|
static X;
|
|
567
577
|
static J;
|
|
568
|
-
static ee;
|
|
569
|
-
static te=null;
|
|
578
|
+
static ee=null;
|
|
570
579
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
571
580
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
572
581
|
// _clearOptimisticStore).
|
|
573
|
-
static
|
|
582
|
+
static te=null;
|
|
574
583
|
// affects()-side hooks (wired by affects.ts, mirroring _update): the mark
|
|
575
584
|
// engine — count/register/release — lives with the feature. Every call site
|
|
576
585
|
// is gated by state only that module creates, so `!` invocations are safe
|
|
577
586
|
// once the gate holds.
|
|
587
|
+
static ne=null;
|
|
578
588
|
static re=null;
|
|
579
589
|
static ie=null;
|
|
580
|
-
static oe=null;
|
|
581
590
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
582
591
|
// config is active — including after _resetExternalSourceConfig()).
|
|
592
|
+
static oe=null;
|
|
583
593
|
static se=null;
|
|
584
|
-
static ue=null;
|
|
585
594
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
586
595
|
// imported; null in apps that never use them). Call sites either guard for
|
|
587
596
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
588
597
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
589
598
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
590
599
|
// isPending()/latest()).
|
|
600
|
+
static ue=null;
|
|
591
601
|
static le=null;
|
|
592
602
|
static ce=null;
|
|
593
603
|
static ae=null;
|
|
594
604
|
static fe=null;
|
|
595
605
|
static Ee=null;
|
|
596
|
-
static Se=null;
|
|
597
606
|
static de=null;
|
|
607
|
+
static Se=null;
|
|
598
608
|
static Te=null;
|
|
599
609
|
static _e=null;
|
|
600
|
-
static pe=null;
|
|
601
610
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
602
611
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
603
612
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -606,28 +615,28 @@ class GlobalQueue extends Queue {
|
|
|
606
615
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
607
616
|
// once the gate holds.
|
|
608
617
|
static Oe=null;
|
|
618
|
+
static pe=null;
|
|
609
619
|
static Re=null;
|
|
610
620
|
static Ie=null;
|
|
611
621
|
static Ae=null;
|
|
612
622
|
static he=null;
|
|
613
623
|
static Ne=null;
|
|
614
624
|
static ye=null;
|
|
615
|
-
static Ce=null;
|
|
616
625
|
static Pe=null;
|
|
626
|
+
static Ce=null;
|
|
617
627
|
static ge=null;
|
|
618
628
|
static be=null;
|
|
619
|
-
static De=null;
|
|
620
629
|
flush() {
|
|
621
|
-
if (this.
|
|
622
|
-
this.
|
|
630
|
+
if (this.q) return;
|
|
631
|
+
this.q = true;
|
|
623
632
|
try {
|
|
624
633
|
if (false) ;
|
|
625
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
634
|
+
runHeap(dirtyQueue, GlobalQueue.Z);
|
|
626
635
|
if (activeTransition) {
|
|
627
636
|
const e = transitionComplete(activeTransition);
|
|
628
637
|
if (!e) {
|
|
629
638
|
const e = activeTransition;
|
|
630
|
-
runHeap(zombieQueue, GlobalQueue.
|
|
639
|
+
runHeap(zombieQueue, GlobalQueue.Z);
|
|
631
640
|
// Detach: the stashed transition keeps its batch; ambient work that
|
|
632
641
|
// follows lands in a fresh one. If the batch is already a separate
|
|
633
642
|
// ambient one — action done() restored activeTransition without
|
|
@@ -637,80 +646,80 @@ class GlobalQueue extends Queue {
|
|
|
637
646
|
if (this.D === e) currentBatch = this.D = createBatch();
|
|
638
647
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
639
648
|
if (activeLanes.size) {
|
|
640
|
-
GlobalQueue.
|
|
641
|
-
GlobalQueue.
|
|
649
|
+
GlobalQueue.Ae(EFFECT_RENDER);
|
|
650
|
+
GlobalQueue.Ae(EFFECT_USER);
|
|
642
651
|
}
|
|
643
|
-
this.stashQueues(e.
|
|
652
|
+
this.stashQueues(e.j);
|
|
644
653
|
clock++;
|
|
645
654
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
646
655
|
// scheduled so the outer drain loop commits them via the plain
|
|
647
656
|
// flush path instead of leaving them until the next natural flush.
|
|
648
|
-
scheduled = dirtyQueue.
|
|
649
|
-
reassignPendingTransition(e.
|
|
657
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.M.length > 0;
|
|
658
|
+
reassignPendingTransition(e.M);
|
|
650
659
|
activeTransition = null;
|
|
651
660
|
finalizePureQueue(null, true);
|
|
652
661
|
return;
|
|
653
662
|
}
|
|
654
663
|
const t = activeTransition;
|
|
655
664
|
const n = this.D;
|
|
656
|
-
n !== t && n.
|
|
657
|
-
this.restoreQueues(t.
|
|
665
|
+
n !== t && n.M.push(...t.M);
|
|
666
|
+
this.restoreQueues(t.j);
|
|
658
667
|
transitions.delete(t);
|
|
659
668
|
activeTransition = null;
|
|
660
|
-
reassignPendingTransition(n.
|
|
669
|
+
reassignPendingTransition(n.M);
|
|
661
670
|
finalizePureQueue(t);
|
|
662
671
|
if (n === t) {
|
|
663
672
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
664
673
|
// as the ambient batch — late registrations during finalization live
|
|
665
674
|
// there and must survive to the next flush.
|
|
666
675
|
const e = createBatch();
|
|
667
|
-
e.
|
|
676
|
+
e.M = n.M;
|
|
677
|
+
e.v = n.v;
|
|
668
678
|
e.G = n.G;
|
|
669
679
|
e.L = n.L;
|
|
670
|
-
e.U = n.U;
|
|
671
680
|
currentBatch = this.D = e;
|
|
672
681
|
}
|
|
673
682
|
} else {
|
|
674
683
|
if (canUseSimpleSyncFlush(this)) {
|
|
675
684
|
commitPendingNodes();
|
|
676
|
-
if (dirtyQueue.
|
|
677
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
685
|
+
if (dirtyQueue.C >= dirtyQueue.P) {
|
|
686
|
+
runHeap(dirtyQueue, GlobalQueue.Z);
|
|
678
687
|
commitPendingNodes();
|
|
679
688
|
}
|
|
680
689
|
} else {
|
|
681
|
-
if (transitions.size) runHeap(zombieQueue, GlobalQueue.
|
|
690
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue.Z);
|
|
682
691
|
finalizePureQueue();
|
|
683
692
|
}
|
|
684
693
|
}
|
|
685
694
|
clock++;
|
|
686
695
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
687
|
-
scheduled = dirtyQueue.
|
|
696
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P;
|
|
688
697
|
// Run lane effects first (for ready lanes), then regular effects
|
|
689
|
-
activeLanes.size && GlobalQueue.
|
|
698
|
+
activeLanes.size && GlobalQueue.Ae(EFFECT_RENDER);
|
|
690
699
|
this.run(EFFECT_RENDER);
|
|
691
|
-
activeLanes.size && GlobalQueue.
|
|
700
|
+
activeLanes.size && GlobalQueue.Ae(EFFECT_USER);
|
|
692
701
|
this.run(EFFECT_USER);
|
|
693
702
|
if (false) ;
|
|
694
703
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
695
704
|
if (false) ;
|
|
696
705
|
} finally {
|
|
697
|
-
this.
|
|
706
|
+
this.q = false;
|
|
698
707
|
}
|
|
699
708
|
}
|
|
700
709
|
notify(e, t, n, r) {
|
|
701
710
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
702
711
|
if (t & STATUS_PENDING) {
|
|
703
712
|
if (n & STATUS_PENDING) {
|
|
704
|
-
const t = r !== undefined ? r : e.
|
|
713
|
+
const t = r !== undefined ? r : e.De;
|
|
705
714
|
// A visibility-only mark notification (the affects() boundary
|
|
706
715
|
// channel) updates display state on its way up but must be invisible
|
|
707
716
|
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
708
717
|
// reporter and never counts toward the loading-boundary diagnostic.
|
|
709
|
-
if (t?.
|
|
718
|
+
if (t?.me) return true;
|
|
710
719
|
if (activeTransition && t) {
|
|
711
720
|
const n = t.source;
|
|
712
|
-
let r = activeTransition.
|
|
713
|
-
if (!r) activeTransition.
|
|
721
|
+
let r = activeTransition.H.get(n);
|
|
722
|
+
if (!r) activeTransition.H.set(n, r = new Set);
|
|
714
723
|
const i = r.size;
|
|
715
724
|
r.add(e);
|
|
716
725
|
if (r.size !== i) schedule();
|
|
@@ -723,7 +732,7 @@ class GlobalQueue extends Queue {
|
|
|
723
732
|
initTransition(e) {
|
|
724
733
|
if (e) e = currentTransition(e);
|
|
725
734
|
if (e && e === activeTransition) return;
|
|
726
|
-
if (!e && activeTransition && activeTransition.
|
|
735
|
+
if (!e && activeTransition && activeTransition.W === clock) return;
|
|
727
736
|
if (!activeTransition) {
|
|
728
737
|
activeTransition = e ?? createBatch();
|
|
729
738
|
} else if (e) {
|
|
@@ -733,7 +742,7 @@ class GlobalQueue extends Queue {
|
|
|
733
742
|
activeTransition = e;
|
|
734
743
|
}
|
|
735
744
|
transitions.add(activeTransition);
|
|
736
|
-
activeTransition.
|
|
745
|
+
activeTransition.W = clock;
|
|
737
746
|
const t = this.D;
|
|
738
747
|
if (t !== activeTransition) {
|
|
739
748
|
// Adopt the ambient batch into the transaction, then make the
|
|
@@ -743,18 +752,18 @@ class GlobalQueue extends Queue {
|
|
|
743
752
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
744
753
|
// downstream: propagation never queues pended subscribers as pending
|
|
745
754
|
// nodes, see propagateAffectsMark, #2893.
|
|
746
|
-
for (let e = 0; e < t.
|
|
747
|
-
const n = t.
|
|
755
|
+
for (let e = 0; e < t.M.length; e++) {
|
|
756
|
+
const n = t.M[e];
|
|
748
757
|
n.T = activeTransition;
|
|
749
|
-
activeTransition.
|
|
758
|
+
activeTransition.M.push(n);
|
|
750
759
|
}
|
|
751
|
-
for (let e = 0; e < t.
|
|
752
|
-
const n = t.
|
|
760
|
+
for (let e = 0; e < t.v.length; e++) {
|
|
761
|
+
const n = t.v[e];
|
|
753
762
|
n.T = activeTransition;
|
|
754
|
-
activeTransition.
|
|
763
|
+
activeTransition.v.push(n);
|
|
755
764
|
}
|
|
756
|
-
if (t.
|
|
757
|
-
for (const e of t.
|
|
765
|
+
if (t.G.length) activeTransition.G.push(...t.G);
|
|
766
|
+
for (const e of t.L) activeTransition.L.add(e);
|
|
758
767
|
currentBatch = this.D = activeTransition;
|
|
759
768
|
}
|
|
760
769
|
for (const e of activeLanes) {
|
|
@@ -764,7 +773,7 @@ class GlobalQueue extends Queue {
|
|
|
764
773
|
}
|
|
765
774
|
|
|
766
775
|
function queuePendingNode(e) {
|
|
767
|
-
currentBatch.
|
|
776
|
+
currentBatch.M.push(e);
|
|
768
777
|
}
|
|
769
778
|
|
|
770
779
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -780,25 +789,25 @@ function insertSubs(e, t = false) {
|
|
|
780
789
|
// Get source lane: prefer node's own lane over current context
|
|
781
790
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
782
791
|
const n = e.i || currentOptimisticLane;
|
|
783
|
-
const r = e.
|
|
792
|
+
const r = e.ve !== undefined;
|
|
784
793
|
const i = reaskArmed;
|
|
785
|
-
for (let o = e.
|
|
794
|
+
for (let o = e.U; o !== null; o = o.we) {
|
|
786
795
|
// A value-change notification is a new question for the subscriber: any
|
|
787
796
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
788
|
-
if (i) o.
|
|
789
|
-
if (r && o.Ue
|
|
790
|
-
o.
|
|
797
|
+
if (i) o.Le.Ge &= ~REACTIVE_REASK;
|
|
798
|
+
if (r && o.Le.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
799
|
+
o.Le.Ge |= REACTIVE_SNAPSHOT_STALE;
|
|
791
800
|
continue;
|
|
792
801
|
}
|
|
793
802
|
if (t && n) {
|
|
794
|
-
o.
|
|
795
|
-
assignOrMergeLane(o.
|
|
803
|
+
o.Le.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
804
|
+
assignOrMergeLane(o.Le, n);
|
|
796
805
|
} else if (t) {
|
|
797
|
-
o.
|
|
806
|
+
o.Le.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
798
807
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
799
|
-
o.
|
|
808
|
+
o.Le.i = undefined;
|
|
800
809
|
}
|
|
801
|
-
enqueueSub(o.
|
|
810
|
+
enqueueSub(o.Le);
|
|
802
811
|
}
|
|
803
812
|
}
|
|
804
813
|
|
|
@@ -806,26 +815,26 @@ function commitPendingNode(e) {
|
|
|
806
815
|
const t = e;
|
|
807
816
|
if (!t.Ve) {
|
|
808
817
|
if (e.V !== NOT_PENDING) {
|
|
809
|
-
e.
|
|
818
|
+
e.ke = e.V;
|
|
810
819
|
e.V = NOT_PENDING;
|
|
811
820
|
}
|
|
812
|
-
if (e.
|
|
821
|
+
if (e.O || e.p) GlobalQueue.ae(e);
|
|
813
822
|
return;
|
|
814
823
|
}
|
|
815
824
|
if (e.V !== NOT_PENDING) {
|
|
816
|
-
e.
|
|
825
|
+
e.ke = e.V;
|
|
817
826
|
e.V = NOT_PENDING;
|
|
818
827
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
819
|
-
if (e.
|
|
828
|
+
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.xe = true;
|
|
820
829
|
}
|
|
821
|
-
t.
|
|
822
|
-
if (!(t.
|
|
823
|
-
if (t.
|
|
824
|
-
if (e.
|
|
830
|
+
t.Ge &= ~REACTIVE_MANUAL_WRITE;
|
|
831
|
+
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
832
|
+
if (t.We !== null || t.Me !== null) GlobalQueue.X(t, false, true);
|
|
833
|
+
if (e.O || e.p) GlobalQueue.ae(e);
|
|
825
834
|
}
|
|
826
835
|
|
|
827
836
|
function commitPendingNodes() {
|
|
828
|
-
const e = currentBatch.
|
|
837
|
+
const e = currentBatch.M;
|
|
829
838
|
for (let t = 0; t < e.length; t++) {
|
|
830
839
|
commitPendingNode(e[t]);
|
|
831
840
|
}
|
|
@@ -838,23 +847,23 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
838
847
|
const n = !t;
|
|
839
848
|
if (n) commitPendingNodes();
|
|
840
849
|
if (!t && globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
841
|
-
const r = dirtyQueue.
|
|
842
|
-
if (r) runHeap(dirtyQueue, GlobalQueue.
|
|
850
|
+
const r = dirtyQueue.C >= dirtyQueue.P;
|
|
851
|
+
if (r) runHeap(dirtyQueue, GlobalQueue.Z);
|
|
843
852
|
if (n) {
|
|
844
853
|
if (r) commitPendingNodes();
|
|
845
854
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
846
855
|
const t = e ?? globalQueue.D;
|
|
847
856
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
848
857
|
// which installed the engine's hooks.
|
|
849
|
-
if (t.
|
|
858
|
+
if (t.v.length) GlobalQueue.pe(t.v);
|
|
850
859
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
851
860
|
// so they re-run with the now-committed values visible.
|
|
852
|
-
if (e && e.
|
|
853
|
-
for (const t of e.
|
|
854
|
-
if (t.
|
|
861
|
+
if (e && e.Y.size) {
|
|
862
|
+
for (const t of e.Y) {
|
|
863
|
+
if (t.Ge & REACTIVE_DISPOSED) continue;
|
|
855
864
|
enqueueSub(t);
|
|
856
865
|
}
|
|
857
|
-
e.
|
|
866
|
+
e.Y.clear();
|
|
858
867
|
}
|
|
859
868
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
860
869
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
@@ -862,24 +871,24 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
862
871
|
// held boundary display state through the visual channel, and their
|
|
863
872
|
// release is the display-state update point — re-run the boundary sweep
|
|
864
873
|
// (the earlier sweep above ran while the marks were still live).
|
|
865
|
-
if (t.
|
|
866
|
-
GlobalQueue.
|
|
874
|
+
if (t.G.length) {
|
|
875
|
+
GlobalQueue.ne(t.G);
|
|
867
876
|
if (globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
868
877
|
}
|
|
869
878
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
870
879
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
871
880
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
872
881
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
873
|
-
if (t.
|
|
882
|
+
if (t.L.size) GlobalQueue.ee(t.L, e);
|
|
874
883
|
sweepTransientStoreNodes();
|
|
875
884
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
876
|
-
if (activeLanes.size) GlobalQueue.
|
|
885
|
+
if (activeLanes.size) GlobalQueue.Ie(e);
|
|
877
886
|
}
|
|
878
887
|
}
|
|
879
888
|
|
|
880
889
|
function checkBoundaryChildren(e) {
|
|
881
890
|
for (const t of e.m) {
|
|
882
|
-
t.
|
|
891
|
+
t.He?.();
|
|
883
892
|
checkBoundaryChildren(t);
|
|
884
893
|
}
|
|
885
894
|
}
|
|
@@ -930,7 +939,7 @@ function flush(e) {
|
|
|
930
939
|
}
|
|
931
940
|
}
|
|
932
941
|
}
|
|
933
|
-
if (globalQueue.
|
|
942
|
+
if (globalQueue.q) {
|
|
934
943
|
return;
|
|
935
944
|
}
|
|
936
945
|
if (halted) return;
|
|
@@ -946,23 +955,23 @@ function runQueue$1(e, t) {
|
|
|
946
955
|
}
|
|
947
956
|
|
|
948
957
|
function reporterBlocksSource(e, t) {
|
|
949
|
-
if (e.
|
|
958
|
+
if (e.Ge & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
950
959
|
if (e.$e?.has(t)) return true;
|
|
951
|
-
for (let n = e.
|
|
952
|
-
let e = n.
|
|
960
|
+
for (let n = e.je; n; n = n.Ke) {
|
|
961
|
+
let e = n.Ye;
|
|
953
962
|
while (e) {
|
|
954
|
-
if (e === t || e.
|
|
963
|
+
if (e === t || e.qe === t) return true;
|
|
955
964
|
e = e.t;
|
|
956
965
|
}
|
|
957
966
|
}
|
|
958
|
-
return !!(e.
|
|
967
|
+
return !!(e.Qe & STATUS_PENDING && e.De instanceof NotReadyError && e.De.source === t);
|
|
959
968
|
}
|
|
960
969
|
|
|
961
970
|
function transitionComplete(e) {
|
|
962
971
|
if (e.I) return true;
|
|
963
972
|
if (e.$.length) return false;
|
|
964
973
|
let t = true;
|
|
965
|
-
for (const [n, r] of e.
|
|
974
|
+
for (const [n, r] of e.H) {
|
|
966
975
|
let i = false;
|
|
967
976
|
for (const e of r) {
|
|
968
977
|
if (reporterBlocksSource(e, n)) {
|
|
@@ -971,7 +980,7 @@ function transitionComplete(e) {
|
|
|
971
980
|
}
|
|
972
981
|
r.delete(e);
|
|
973
982
|
}
|
|
974
|
-
if (!i) e.
|
|
983
|
+
if (!i) e.H.delete(n); else if (n.Qe & STATUS_PENDING && n.De?.source === n) {
|
|
975
984
|
t = false;
|
|
976
985
|
break;
|
|
977
986
|
}
|
|
@@ -979,7 +988,7 @@ function transitionComplete(e) {
|
|
|
979
988
|
// Override blockage lives with the engine. Absent hook = "no optimistic
|
|
980
989
|
// blockage", which is exact: only _optimisticWrite (engine) pushes to
|
|
981
990
|
// _optimisticNodes, so without the engine the loop was vacuous anyway.
|
|
982
|
-
if (t && e.
|
|
991
|
+
if (t && e.v.length && GlobalQueue.Re(e)) t = false;
|
|
983
992
|
t && (e.I = true);
|
|
984
993
|
return t;
|
|
985
994
|
}
|
|
@@ -1004,7 +1013,7 @@ function runInTransition(e, t) {
|
|
|
1004
1013
|
}
|
|
1005
1014
|
|
|
1006
1015
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1007
|
-
return e.
|
|
1016
|
+
return e.Ge & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1008
1017
|
}
|
|
1009
1018
|
|
|
1010
1019
|
/**
|
|
@@ -1012,40 +1021,40 @@ function runInTransition(e, t) {
|
|
|
1012
1021
|
* the heap and go directly to their effect queue; everything else is inserted
|
|
1013
1022
|
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
1014
1023
|
*/ function enqueueSub(e) {
|
|
1015
|
-
if (e.
|
|
1024
|
+
if (e.Fe === EFFECT_TRACKED) {
|
|
1016
1025
|
const t = e;
|
|
1017
|
-
if (!t.
|
|
1018
|
-
t.
|
|
1019
|
-
t.
|
|
1026
|
+
if (!t.xe) {
|
|
1027
|
+
t.xe = true;
|
|
1028
|
+
t.Be.enqueue(EFFECT_USER, t.Ze);
|
|
1020
1029
|
}
|
|
1021
1030
|
return;
|
|
1022
1031
|
}
|
|
1023
1032
|
const t = queueFor(e);
|
|
1024
|
-
if (t.
|
|
1033
|
+
if (t.P > e.Xe) t.P = e.Xe;
|
|
1025
1034
|
insertIntoHeap(e, t);
|
|
1026
1035
|
}
|
|
1027
1036
|
|
|
1028
1037
|
function actualInsertIntoHeap(e, t) {
|
|
1029
|
-
const n = (e.
|
|
1030
|
-
if (n >= e.
|
|
1031
|
-
const r = e.
|
|
1038
|
+
const n = (e.B?.ze ? e.B.Je?.Xe : e.B?.Xe) ?? -1;
|
|
1039
|
+
if (n >= e.Xe) e.Xe = n + 1;
|
|
1040
|
+
const r = e.Xe;
|
|
1032
1041
|
const i = t.h[r];
|
|
1033
1042
|
if (i === undefined) t.h[r] = e; else {
|
|
1034
|
-
const t = i.
|
|
1035
|
-
t.
|
|
1036
|
-
e.
|
|
1037
|
-
i.
|
|
1043
|
+
const t = i.et;
|
|
1044
|
+
t.tt = e;
|
|
1045
|
+
e.et = t;
|
|
1046
|
+
i.et = e;
|
|
1038
1047
|
}
|
|
1039
|
-
if (r > t.
|
|
1048
|
+
if (r > t.C) t.C = r;
|
|
1040
1049
|
}
|
|
1041
1050
|
|
|
1042
1051
|
function insertIntoHeap(e, t) {
|
|
1043
|
-
let n = e.
|
|
1052
|
+
let n = e.Ge;
|
|
1044
1053
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1045
1054
|
if (n & REACTIVE_CHECK) {
|
|
1046
|
-
e.
|
|
1055
|
+
e.Ge = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1047
1056
|
} else {
|
|
1048
|
-
e.
|
|
1057
|
+
e.Ge = n | REACTIVE_IN_HEAP;
|
|
1049
1058
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1050
1059
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1051
1060
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1057,49 +1066,49 @@ function insertIntoHeap(e, t) {
|
|
|
1057
1066
|
}
|
|
1058
1067
|
|
|
1059
1068
|
function insertIntoHeapHeight(e, t) {
|
|
1060
|
-
let n = e.
|
|
1069
|
+
let n = e.Ge;
|
|
1061
1070
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1062
|
-
e.
|
|
1071
|
+
e.Ge = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1063
1072
|
actualInsertIntoHeap(e, t);
|
|
1064
1073
|
}
|
|
1065
1074
|
|
|
1066
1075
|
function deleteFromHeap(e, t) {
|
|
1067
|
-
const n = e.
|
|
1076
|
+
const n = e.Ge;
|
|
1068
1077
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1069
|
-
e.
|
|
1070
|
-
const r = e.
|
|
1071
|
-
if (e.
|
|
1072
|
-
const n = e.
|
|
1078
|
+
e.Ge = n & -25;
|
|
1079
|
+
const r = e.Xe;
|
|
1080
|
+
if (e.et === e) t.h[r] = undefined; else {
|
|
1081
|
+
const n = e.tt;
|
|
1073
1082
|
const i = t.h[r];
|
|
1074
1083
|
const o = n ?? i;
|
|
1075
|
-
if (e === i) t.h[r] = n; else e.tt
|
|
1076
|
-
o.
|
|
1084
|
+
if (e === i) t.h[r] = n; else e.et.tt = n;
|
|
1085
|
+
o.et = e.et;
|
|
1077
1086
|
}
|
|
1078
|
-
e.
|
|
1079
|
-
e.
|
|
1087
|
+
e.et = e;
|
|
1088
|
+
e.tt = undefined;
|
|
1080
1089
|
}
|
|
1081
1090
|
|
|
1082
1091
|
function markHeap(e) {
|
|
1083
1092
|
if (e.N) return;
|
|
1084
1093
|
e.N = true;
|
|
1085
|
-
for (let t = 0; t <= e.
|
|
1086
|
-
for (let n = e.h[t]; n !== undefined; n = n.
|
|
1087
|
-
if (n.
|
|
1094
|
+
for (let t = 0; t <= e.C; t++) {
|
|
1095
|
+
for (let n = e.h[t]; n !== undefined; n = n.tt) {
|
|
1096
|
+
if (n.Ge & REACTIVE_IN_HEAP) markNode(n);
|
|
1088
1097
|
}
|
|
1089
1098
|
}
|
|
1090
1099
|
}
|
|
1091
1100
|
|
|
1092
1101
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1093
|
-
const n = e.
|
|
1102
|
+
const n = e.Ge;
|
|
1094
1103
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1095
|
-
e.
|
|
1096
|
-
for (let t = e.
|
|
1097
|
-
markNode(t.
|
|
1098
|
-
}
|
|
1099
|
-
if (e.
|
|
1100
|
-
for (let t = e.
|
|
1101
|
-
for (let e = t.
|
|
1102
|
-
markNode(e.
|
|
1104
|
+
e.Ge = n & -4 | t;
|
|
1105
|
+
for (let t = e.U; t !== null; t = t.we) {
|
|
1106
|
+
markNode(t.Le, REACTIVE_CHECK);
|
|
1107
|
+
}
|
|
1108
|
+
if (e.nt !== null) {
|
|
1109
|
+
for (let t = e.nt; t !== null; t = t.rt) {
|
|
1110
|
+
for (let e = t.U; e !== null; e = e.we) {
|
|
1111
|
+
markNode(e.Le, REACTIVE_CHECK);
|
|
1103
1112
|
}
|
|
1104
1113
|
}
|
|
1105
1114
|
}
|
|
@@ -1107,33 +1116,33 @@ function markNode(e, t = REACTIVE_DIRTY) {
|
|
|
1107
1116
|
|
|
1108
1117
|
function runHeap(e, t) {
|
|
1109
1118
|
e.N = false;
|
|
1110
|
-
for (e.
|
|
1111
|
-
let n = e.h[e.
|
|
1119
|
+
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1120
|
+
let n = e.h[e.P];
|
|
1112
1121
|
while (n !== undefined) {
|
|
1113
|
-
if (n.
|
|
1114
|
-
n = e.h[e.
|
|
1122
|
+
if (n.Ge & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1123
|
+
n = e.h[e.P];
|
|
1115
1124
|
}
|
|
1116
1125
|
}
|
|
1117
|
-
e.
|
|
1126
|
+
e.C = 0;
|
|
1118
1127
|
}
|
|
1119
1128
|
|
|
1120
1129
|
function adjustHeight(e, t) {
|
|
1121
1130
|
deleteFromHeap(e, t);
|
|
1122
|
-
let n = e.
|
|
1123
|
-
for (let t = e.
|
|
1124
|
-
const e = t.
|
|
1125
|
-
const r = e.
|
|
1126
|
-
if (r.Ve && r.
|
|
1127
|
-
}
|
|
1128
|
-
if (e.
|
|
1129
|
-
e.
|
|
1130
|
-
for (let t = e.
|
|
1131
|
+
let n = e.Xe;
|
|
1132
|
+
for (let t = e.je; t; t = t.Ke) {
|
|
1133
|
+
const e = t.Ye;
|
|
1134
|
+
const r = e.qe || e;
|
|
1135
|
+
if (r.Ve && r.Xe >= n) n = r.Xe + 1;
|
|
1136
|
+
}
|
|
1137
|
+
if (e.Xe !== n) {
|
|
1138
|
+
e.Xe = n;
|
|
1139
|
+
for (let t = e.U; t !== null; t = t.we) {
|
|
1131
1140
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1132
1141
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1133
1142
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
1134
1143
|
// `zombieQueue`), breaking the flag/queue invariant `deleteFromHeap`
|
|
1135
1144
|
// relies on — the same corruption class as #2759.
|
|
1136
|
-
insertIntoHeapHeight(t.
|
|
1145
|
+
insertIntoHeapHeight(t.Le, queueFor(t.Le));
|
|
1137
1146
|
}
|
|
1138
1147
|
}
|
|
1139
1148
|
}
|
|
@@ -1142,10 +1151,10 @@ const PENDING_OWNER = {};
|
|
|
1142
1151
|
|
|
1143
1152
|
// Dummy owner to trigger store's read() path
|
|
1144
1153
|
function markDisposal(e) {
|
|
1145
|
-
let t = e.
|
|
1154
|
+
let t = e.it;
|
|
1146
1155
|
while (t) {
|
|
1147
|
-
const e = t.
|
|
1148
|
-
t.
|
|
1156
|
+
const e = t.Ge;
|
|
1157
|
+
t.Ge = e | REACTIVE_ZOMBIE;
|
|
1149
1158
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1150
1159
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1151
1160
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1156,79 +1165,79 @@ function markDisposal(e) {
|
|
|
1156
1165
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
1157
1166
|
}
|
|
1158
1167
|
markDisposal(t);
|
|
1159
|
-
t = t.
|
|
1168
|
+
t = t.ot;
|
|
1160
1169
|
}
|
|
1161
1170
|
}
|
|
1162
1171
|
|
|
1163
1172
|
function dispose(e) {
|
|
1164
|
-
let t = e.
|
|
1173
|
+
let t = e.je;
|
|
1165
1174
|
while (t !== null) {
|
|
1166
1175
|
t = unlinkSubs(t);
|
|
1167
1176
|
}
|
|
1168
|
-
e.
|
|
1169
|
-
e.
|
|
1177
|
+
e.je = null;
|
|
1178
|
+
e.st = null;
|
|
1170
1179
|
disposeChildren(e, true);
|
|
1171
1180
|
}
|
|
1172
1181
|
|
|
1173
1182
|
function disposeChildren(e, t = false, n) {
|
|
1174
|
-
const r = e.
|
|
1183
|
+
const r = e.Ge;
|
|
1175
1184
|
if (r & REACTIVE_DISPOSED) return;
|
|
1176
1185
|
if (t) {
|
|
1177
|
-
e.
|
|
1186
|
+
e.Ge = r | REACTIVE_DISPOSED;
|
|
1178
1187
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1179
1188
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1180
1189
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1181
1190
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1182
1191
|
// false, and notifies subscribers still watching the companion.
|
|
1183
1192
|
const t = e;
|
|
1184
|
-
if (t.
|
|
1193
|
+
if (t.O || t.p) GlobalQueue.ae(t);
|
|
1185
1194
|
}
|
|
1186
|
-
if (t && e.Ve) e.
|
|
1187
|
-
let i = n ? e.
|
|
1195
|
+
if (t && e.Ve) e.ut = null;
|
|
1196
|
+
let i = n ? e.We : e.it;
|
|
1188
1197
|
while (i) {
|
|
1189
|
-
const e = i.
|
|
1190
|
-
if (i.
|
|
1198
|
+
const e = i.ot;
|
|
1199
|
+
if (i.je) {
|
|
1191
1200
|
const e = i;
|
|
1192
1201
|
deleteFromHeap(e, queueFor(e));
|
|
1193
|
-
let t = e.
|
|
1202
|
+
let t = e.je;
|
|
1194
1203
|
do {
|
|
1195
1204
|
t = unlinkSubs(t);
|
|
1196
1205
|
} while (t !== null);
|
|
1197
|
-
e.
|
|
1198
|
-
e.
|
|
1206
|
+
e.je = null;
|
|
1207
|
+
e.st = null;
|
|
1199
1208
|
}
|
|
1200
1209
|
disposeChildren(i, true);
|
|
1201
1210
|
i = e;
|
|
1202
1211
|
}
|
|
1203
1212
|
if (n) {
|
|
1204
|
-
e.
|
|
1213
|
+
e.We = null;
|
|
1205
1214
|
} else {
|
|
1206
|
-
e.
|
|
1207
|
-
e.
|
|
1215
|
+
e.it = null;
|
|
1216
|
+
e.lt = 0;
|
|
1208
1217
|
}
|
|
1209
1218
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1210
1219
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1211
1220
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1212
1221
|
// walks that already advanced past us still reach later siblings.
|
|
1213
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.
|
|
1214
|
-
const t = e.
|
|
1215
|
-
const n = e.
|
|
1216
|
-
if (t !== null) t.
|
|
1217
|
-
if (n !== null) n.
|
|
1218
|
-
e.
|
|
1222
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.Ge & REACTIVE_DISPOSED)) {
|
|
1223
|
+
const t = e.ct;
|
|
1224
|
+
const n = e.ot;
|
|
1225
|
+
if (t !== null) t.ot = n; else e.B.it = n;
|
|
1226
|
+
if (n !== null) n.ct = t;
|
|
1227
|
+
e.ct = null;
|
|
1219
1228
|
}
|
|
1220
1229
|
runDisposal(e, n);
|
|
1221
1230
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
1222
1231
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
1223
|
-
if (t && e.
|
|
1224
|
-
const t = e.
|
|
1225
|
-
e.
|
|
1232
|
+
if (t && e.ft) {
|
|
1233
|
+
const t = e.ft;
|
|
1234
|
+
e.ft = undefined;
|
|
1226
1235
|
t();
|
|
1227
1236
|
}
|
|
1228
1237
|
}
|
|
1229
1238
|
|
|
1230
1239
|
function runDisposal(e, t) {
|
|
1231
|
-
let n = t ? e.
|
|
1240
|
+
let n = t ? e.Me : e.Et;
|
|
1232
1241
|
if (!n) return;
|
|
1233
1242
|
if (Array.isArray(n)) {
|
|
1234
1243
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1238,13 +1247,13 @@ function runDisposal(e, t) {
|
|
|
1238
1247
|
} else {
|
|
1239
1248
|
n.call(n);
|
|
1240
1249
|
}
|
|
1241
|
-
t ? e.
|
|
1250
|
+
t ? e.Me = null : e.Et = null;
|
|
1242
1251
|
}
|
|
1243
1252
|
|
|
1244
1253
|
function childId(e, t) {
|
|
1245
1254
|
let n = e;
|
|
1246
|
-
while (n.
|
|
1247
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1255
|
+
while (n.Ue & CONFIG_TRANSPARENT && n.B) n = n.B;
|
|
1256
|
+
if (n.id != null) return formatId(n.id, t ? n.lt++ : n.lt);
|
|
1248
1257
|
throw new Error("");
|
|
1249
1258
|
}
|
|
1250
1259
|
|
|
@@ -1325,7 +1334,7 @@ function formatId(e, t) {
|
|
|
1325
1334
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
1326
1335
|
*/ function cleanup(e) {
|
|
1327
1336
|
if (!context) return e;
|
|
1328
|
-
if (!context.
|
|
1337
|
+
if (!context.Et) context.Et = e; else if (Array.isArray(context.Et)) context.Et.push(e); else context.Et = [ context.Et, e ];
|
|
1329
1338
|
return e;
|
|
1330
1339
|
}
|
|
1331
1340
|
|
|
@@ -1345,7 +1354,7 @@ function formatId(e, t) {
|
|
|
1345
1354
|
* }
|
|
1346
1355
|
* ```
|
|
1347
1356
|
*/ function isDisposed(e) {
|
|
1348
|
-
return !!(e.
|
|
1357
|
+
return !!(e.Ge & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1349
1358
|
}
|
|
1350
1359
|
|
|
1351
1360
|
function disposeRootSelf(e = true) {
|
|
@@ -1364,29 +1373,29 @@ function disposeRootSelf(e = true) {
|
|
|
1364
1373
|
const n = e?.transparent ?? false;
|
|
1365
1374
|
const r = {
|
|
1366
1375
|
id: inheritId(e, n, t),
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1376
|
+
Ue: n ? CONFIG_TRANSPARENT : 0,
|
|
1377
|
+
ze: true,
|
|
1378
|
+
Je: t?.ze ? t.Je : t,
|
|
1379
|
+
it: null,
|
|
1370
1380
|
ot: null,
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
Ze: t?.Ze ?? globalQueue,
|
|
1381
|
+
ct: null,
|
|
1382
|
+
Et: null,
|
|
1383
|
+
Be: t?.Be ?? globalQueue,
|
|
1375
1384
|
dt: t?.dt || defaultContext,
|
|
1376
|
-
|
|
1377
|
-
He: null,
|
|
1385
|
+
lt: 0,
|
|
1378
1386
|
Me: null,
|
|
1379
|
-
|
|
1387
|
+
We: null,
|
|
1388
|
+
B: t,
|
|
1380
1389
|
dispose: disposeRootSelf
|
|
1381
1390
|
};
|
|
1382
1391
|
if (t) {
|
|
1383
|
-
const e = t.
|
|
1392
|
+
const e = t.it;
|
|
1384
1393
|
if (e === null) {
|
|
1385
|
-
t.
|
|
1394
|
+
t.it = r;
|
|
1386
1395
|
} else {
|
|
1387
|
-
r.
|
|
1388
|
-
e.
|
|
1389
|
-
t.
|
|
1396
|
+
r.ot = e;
|
|
1397
|
+
e.ct = r;
|
|
1398
|
+
t.it = r;
|
|
1390
1399
|
}
|
|
1391
1400
|
}
|
|
1392
1401
|
return r;
|
|
@@ -1422,15 +1431,15 @@ function disposeRootSelf(e = true) {
|
|
|
1422
1431
|
|
|
1423
1432
|
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L100
|
|
1424
1433
|
function unlinkSubs(e) {
|
|
1425
|
-
const t = e.
|
|
1426
|
-
const n = e.
|
|
1427
|
-
const r = e.
|
|
1428
|
-
const i = e.
|
|
1429
|
-
if (r !== null) r.
|
|
1430
|
-
if (i !== null) i.
|
|
1431
|
-
t.
|
|
1434
|
+
const t = e.Ye;
|
|
1435
|
+
const n = e.Ke;
|
|
1436
|
+
const r = e.we;
|
|
1437
|
+
const i = e.St;
|
|
1438
|
+
if (r !== null) r.St = i; else t.Tt = i;
|
|
1439
|
+
if (i !== null) i.we = r; else {
|
|
1440
|
+
t.U = r;
|
|
1432
1441
|
if (r === null) {
|
|
1433
|
-
t.
|
|
1442
|
+
t.F?.();
|
|
1434
1443
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1435
1444
|
// A pending node is exempt: its in-flight async work (or the
|
|
1436
1445
|
// transition holding it) is an observer — tearing down would orphan
|
|
@@ -1438,31 +1447,31 @@ function unlinkSubs(e) {
|
|
|
1438
1447
|
// this same last-one-out check when that observer releases (the
|
|
1439
1448
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1440
1449
|
const e = t;
|
|
1441
|
-
e.Ve && e.
|
|
1450
|
+
e.Ve && e.Ue & CONFIG_AUTO_DISPOSE && !(e.Ge & REACTIVE_ZOMBIE) && !(e.Qe & STATUS_PENDING) && unobserved(e);
|
|
1442
1451
|
}
|
|
1443
1452
|
}
|
|
1444
1453
|
return n;
|
|
1445
1454
|
}
|
|
1446
1455
|
|
|
1447
1456
|
function trimStaleDeps(e) {
|
|
1448
|
-
const t = e.
|
|
1449
|
-
let n = t !== null ? t.
|
|
1457
|
+
const t = e.st;
|
|
1458
|
+
let n = t !== null ? t.Ke : e.je;
|
|
1450
1459
|
if (n !== null) {
|
|
1451
1460
|
do {
|
|
1452
1461
|
n = unlinkSubs(n);
|
|
1453
1462
|
} while (n !== null);
|
|
1454
|
-
if (t !== null) t.
|
|
1463
|
+
if (t !== null) t.Ke = null; else e.je = null;
|
|
1455
1464
|
}
|
|
1456
1465
|
}
|
|
1457
1466
|
|
|
1458
1467
|
function unobserved(e) {
|
|
1459
1468
|
deleteFromHeap(e, queueFor(e));
|
|
1460
|
-
let t = e.
|
|
1469
|
+
let t = e.je;
|
|
1461
1470
|
while (t !== null) {
|
|
1462
1471
|
t = unlinkSubs(t);
|
|
1463
1472
|
}
|
|
1464
|
-
e.
|
|
1465
|
-
e.
|
|
1473
|
+
e.je = null;
|
|
1474
|
+
e.st = null;
|
|
1466
1475
|
disposeChildren(e, true);
|
|
1467
1476
|
}
|
|
1468
1477
|
|
|
@@ -1473,20 +1482,20 @@ function link(e, t, n = false) {
|
|
|
1473
1482
|
// not relabel the value dependency as probe-only — the value read is what
|
|
1474
1483
|
// real-error propagation and affects() coverage key off, regardless of
|
|
1475
1484
|
// read order within the computation.
|
|
1476
|
-
const r = t.
|
|
1477
|
-
if (r !== null && r.
|
|
1478
|
-
r.
|
|
1485
|
+
const r = t.st;
|
|
1486
|
+
if (r !== null && r.Ye === e) {
|
|
1487
|
+
r._t &&= n;
|
|
1479
1488
|
return;
|
|
1480
1489
|
}
|
|
1481
1490
|
let i = null;
|
|
1482
|
-
const o = t.
|
|
1491
|
+
const o = t.Ge & REACTIVE_RECOMPUTING_DEPS;
|
|
1483
1492
|
if (o) {
|
|
1484
|
-
i = r !== null ? r.
|
|
1485
|
-
if (i !== null && i.
|
|
1486
|
-
i.
|
|
1487
|
-
t.
|
|
1493
|
+
i = r !== null ? r.Ke : t.je;
|
|
1494
|
+
if (i !== null && i.Ye === e) {
|
|
1495
|
+
i.Ot = t.Rt;
|
|
1496
|
+
t.st = i;
|
|
1488
1497
|
// First touch of this pass: the previous pass's label is stale.
|
|
1489
|
-
i.
|
|
1498
|
+
i._t = n;
|
|
1490
1499
|
return;
|
|
1491
1500
|
}
|
|
1492
1501
|
}
|
|
@@ -1495,24 +1504,24 @@ function link(e, t, n = false) {
|
|
|
1495
1504
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
1496
1505
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1497
1506
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1498
|
-
const s = e.
|
|
1499
|
-
if (s !== null && s.
|
|
1507
|
+
const s = e.Tt;
|
|
1508
|
+
if (s !== null && s.Le === t && (!o || s.Ot === t.Rt)) {
|
|
1500
1509
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1501
1510
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1502
|
-
if (o) s.
|
|
1511
|
+
if (o) s._t &&= n; else s._t = n;
|
|
1503
1512
|
return;
|
|
1504
1513
|
}
|
|
1505
|
-
const u = t.
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1514
|
+
const u = t.st = e.Tt = {
|
|
1515
|
+
Ye: e,
|
|
1516
|
+
Le: t,
|
|
1517
|
+
Ke: i,
|
|
1518
|
+
St: s,
|
|
1519
|
+
we: null,
|
|
1520
|
+
Ot: t.Rt,
|
|
1521
|
+
_t: n
|
|
1513
1522
|
};
|
|
1514
|
-
if (r !== null) r.
|
|
1515
|
-
if (s !== null) s.
|
|
1523
|
+
if (r !== null) r.Ke = u; else t.je = u;
|
|
1524
|
+
if (s !== null) s.we = u; else e.U = u;
|
|
1516
1525
|
}
|
|
1517
1526
|
|
|
1518
1527
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1539,24 +1548,24 @@ function clearPendingSources(e) {
|
|
|
1539
1548
|
|
|
1540
1549
|
function setPendingError(e, t, n) {
|
|
1541
1550
|
if (!t) {
|
|
1542
|
-
e.
|
|
1551
|
+
e.De = null;
|
|
1543
1552
|
return;
|
|
1544
1553
|
}
|
|
1545
1554
|
if (n instanceof NotReadyError && n.source === t) {
|
|
1546
|
-
e.
|
|
1555
|
+
e.De = n;
|
|
1547
1556
|
return;
|
|
1548
1557
|
}
|
|
1549
|
-
const r = e.
|
|
1558
|
+
const r = e.De;
|
|
1550
1559
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
1551
|
-
e.
|
|
1560
|
+
e.De = new NotReadyError(t);
|
|
1552
1561
|
}
|
|
1553
1562
|
}
|
|
1554
1563
|
|
|
1555
1564
|
function forEachDependent(e, t) {
|
|
1556
|
-
for (let n = e.
|
|
1565
|
+
for (let n = e.U; n !== null; n = n.we) t(n.Le, n);
|
|
1557
1566
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1558
|
-
for (let n = e.
|
|
1559
|
-
for (let e = n.
|
|
1567
|
+
for (let n = e.nt ?? null; n !== null; n = n.rt) {
|
|
1568
|
+
for (let e = n.U; e !== null; e = e.we) t(e.Le, e);
|
|
1560
1569
|
}
|
|
1561
1570
|
}
|
|
1562
1571
|
|
|
@@ -1567,24 +1576,24 @@ function settlePendingSource(e) {
|
|
|
1567
1576
|
let t = false;
|
|
1568
1577
|
const n = new Set;
|
|
1569
1578
|
// Companion updates no-op without the verdict layer (null hook).
|
|
1570
|
-
const r = GlobalQueue.
|
|
1579
|
+
const r = GlobalQueue.le;
|
|
1571
1580
|
const settle = i => {
|
|
1572
1581
|
if (n.has(i) || !removePendingSource(i, e)) return;
|
|
1573
1582
|
n.add(i);
|
|
1574
|
-
i.
|
|
1583
|
+
i.W = clock;
|
|
1575
1584
|
const o = i.$e?.values().next().value;
|
|
1576
1585
|
if (o) {
|
|
1577
1586
|
setPendingError(i, o);
|
|
1578
1587
|
r !== null && r(i);
|
|
1579
1588
|
} else {
|
|
1580
|
-
i.
|
|
1589
|
+
i.Qe &= ~STATUS_PENDING;
|
|
1581
1590
|
setPendingError(i);
|
|
1582
1591
|
r !== null && r(i);
|
|
1583
|
-
if (i.
|
|
1592
|
+
if (i.It) {
|
|
1584
1593
|
enqueueSub(i);
|
|
1585
1594
|
t = true;
|
|
1586
1595
|
}
|
|
1587
|
-
i.
|
|
1596
|
+
i.It = false;
|
|
1588
1597
|
}
|
|
1589
1598
|
forEachDependent(i, settle);
|
|
1590
1599
|
};
|
|
@@ -1607,26 +1616,26 @@ function handleAsync(e, t, n) {
|
|
|
1607
1616
|
});
|
|
1608
1617
|
}
|
|
1609
1618
|
if (!i && !r) {
|
|
1610
|
-
e.
|
|
1619
|
+
e.ut = null;
|
|
1611
1620
|
return t;
|
|
1612
1621
|
}
|
|
1613
|
-
e.
|
|
1622
|
+
e.ut = t;
|
|
1614
1623
|
let o;
|
|
1615
1624
|
const handleError = n => {
|
|
1616
|
-
if (e.
|
|
1625
|
+
if (e.ut !== t) return;
|
|
1617
1626
|
globalQueue.initTransition(resolveTransition(e));
|
|
1618
1627
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1619
1628
|
notifyStatus(e, n instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1620
|
-
e.
|
|
1629
|
+
e.W = clock;
|
|
1621
1630
|
};
|
|
1622
1631
|
const asyncWrite = (r, i) => {
|
|
1623
|
-
if (e.
|
|
1632
|
+
if (e.ut !== t) return;
|
|
1624
1633
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1625
1634
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1626
1635
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1627
|
-
if (e.
|
|
1636
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1628
1637
|
globalQueue.initTransition(resolveTransition(e));
|
|
1629
|
-
const o = !!(e.
|
|
1638
|
+
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
1630
1639
|
trimStaleDeps(e);
|
|
1631
1640
|
clearStatus(e);
|
|
1632
1641
|
const s = resolveLane(e);
|
|
@@ -1653,22 +1662,22 @@ function handleAsync(e, t, n) {
|
|
|
1653
1662
|
// only notified when the hold is visible to them: under an active
|
|
1654
1663
|
// override every reader sees the override (A17), so waking subs would
|
|
1655
1664
|
// re-show an unchanged view — the revert is the notification point.
|
|
1656
|
-
GlobalQueue.
|
|
1665
|
+
GlobalQueue.ue !== null && GlobalQueue.ue(e, r);
|
|
1657
1666
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1658
|
-
e.
|
|
1667
|
+
e.W = clock;
|
|
1659
1668
|
} else if (s) {
|
|
1660
1669
|
// Route through lane's effect queue for independent flushing
|
|
1661
|
-
const t = e.
|
|
1662
|
-
const n = e.
|
|
1663
|
-
const i = e.
|
|
1670
|
+
const t = e.Fe;
|
|
1671
|
+
const n = e.ke;
|
|
1672
|
+
const i = e.At;
|
|
1664
1673
|
try {
|
|
1665
1674
|
if (!t && o || !i || !i(r, n)) {
|
|
1666
|
-
e.
|
|
1667
|
-
e.
|
|
1675
|
+
e.ke = r;
|
|
1676
|
+
e.W = clock;
|
|
1668
1677
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1669
1678
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1670
1679
|
// (computePendingState doesn't read _value).
|
|
1671
|
-
GlobalQueue.
|
|
1680
|
+
GlobalQueue.ue !== null && GlobalQueue.ue(e, r);
|
|
1672
1681
|
insertSubs(e, true);
|
|
1673
1682
|
}
|
|
1674
1683
|
} catch (t) {
|
|
@@ -1698,7 +1707,7 @@ function handleAsync(e, t, n) {
|
|
|
1698
1707
|
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1699
1708
|
// it runs the same last-one-out check the other release sites run.
|
|
1700
1709
|
const settleAutodispose = () => {
|
|
1701
|
-
if (e.
|
|
1710
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.Qe & STATUS_PENDING)) {
|
|
1702
1711
|
unobserved(e);
|
|
1703
1712
|
}
|
|
1704
1713
|
};
|
|
@@ -1753,7 +1762,7 @@ function handleAsync(e, t, n) {
|
|
|
1753
1762
|
u = n;
|
|
1754
1763
|
c = true;
|
|
1755
1764
|
if (n.done) i = true;
|
|
1756
|
-
} else if (e.
|
|
1765
|
+
} else if (e.ut !== t) {
|
|
1757
1766
|
return;
|
|
1758
1767
|
} else if (!n.done) {
|
|
1759
1768
|
r = true;
|
|
@@ -1772,7 +1781,7 @@ function handleAsync(e, t, n) {
|
|
|
1772
1781
|
if (f) {
|
|
1773
1782
|
l = n;
|
|
1774
1783
|
a = true;
|
|
1775
|
-
} else if (e.
|
|
1784
|
+
} else if (e.ut === t) {
|
|
1776
1785
|
i = true;
|
|
1777
1786
|
handleError(n);
|
|
1778
1787
|
}
|
|
@@ -1805,18 +1814,18 @@ function handleAsync(e, t, n) {
|
|
|
1805
1814
|
|
|
1806
1815
|
function clearStatus(e, t = false) {
|
|
1807
1816
|
if (e.$e) clearPendingSources(e);
|
|
1808
|
-
if (e.
|
|
1817
|
+
if (e.It) e.It = false;
|
|
1809
1818
|
// The pending window is over; its quiet classification dies with it.
|
|
1810
1819
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1811
1820
|
// plain store to an existing slot — no shape change.)
|
|
1812
|
-
e.
|
|
1813
|
-
e.
|
|
1814
|
-
if (e.
|
|
1821
|
+
e.ht = false;
|
|
1822
|
+
e.Qe = t ? 0 : e.Qe & STATUS_UNINITIALIZED;
|
|
1823
|
+
if (e.De) setPendingError(e);
|
|
1815
1824
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1816
1825
|
// once the verdict layer created them, which installs the hooks).
|
|
1817
|
-
if (e.
|
|
1818
|
-
if (e.
|
|
1819
|
-
if (e.
|
|
1826
|
+
if (e.O || e.p) GlobalQueue.le(e);
|
|
1827
|
+
if (e.nt && GlobalQueue.ce !== null) GlobalQueue.ce(e);
|
|
1828
|
+
if (e.Nt) e.Nt();
|
|
1820
1829
|
}
|
|
1821
1830
|
|
|
1822
1831
|
function notifyStatus(e, t, n, r, i) {
|
|
@@ -1829,43 +1838,43 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1829
1838
|
if (!r) {
|
|
1830
1839
|
if (t === STATUS_PENDING && o) {
|
|
1831
1840
|
addPendingSource(e, o);
|
|
1832
|
-
e.
|
|
1841
|
+
e.Qe = STATUS_PENDING | e.Qe & STATUS_UNINITIALIZED;
|
|
1833
1842
|
// Preserve the current source on this propagation so render-effect notification
|
|
1834
1843
|
// can register every distinct pending source with the transition.
|
|
1835
1844
|
setPendingError(e, o, n);
|
|
1836
1845
|
} else {
|
|
1837
1846
|
clearPendingSources(e);
|
|
1838
|
-
e.
|
|
1839
|
-
e.
|
|
1847
|
+
e.Qe = t | (t !== STATUS_ERROR ? e.Qe & STATUS_UNINITIALIZED : 0);
|
|
1848
|
+
e.De = n;
|
|
1840
1849
|
}
|
|
1841
|
-
GlobalQueue.
|
|
1842
|
-
if (e.
|
|
1850
|
+
GlobalQueue.le !== null && GlobalQueue.le(e);
|
|
1851
|
+
if (e.nt && GlobalQueue.ce !== null) GlobalQueue.ce(e);
|
|
1843
1852
|
}
|
|
1844
1853
|
if (i && !r) {
|
|
1845
1854
|
assignOrMergeLane(e, i);
|
|
1846
1855
|
}
|
|
1847
1856
|
const c = r || l;
|
|
1848
1857
|
const a = r || u ? undefined : i;
|
|
1849
|
-
if (e.
|
|
1858
|
+
if (e.Nt) {
|
|
1850
1859
|
if (r && t === STATUS_PENDING) {
|
|
1851
1860
|
return;
|
|
1852
1861
|
}
|
|
1853
1862
|
if (c) {
|
|
1854
|
-
e.
|
|
1863
|
+
e.Nt(t, n);
|
|
1855
1864
|
} else {
|
|
1856
|
-
e.
|
|
1865
|
+
e.Nt();
|
|
1857
1866
|
}
|
|
1858
1867
|
return;
|
|
1859
1868
|
}
|
|
1860
1869
|
forEachDependent(e, (e, r) => {
|
|
1861
|
-
e.
|
|
1862
|
-
if (t === STATUS_PENDING && o && !e.$e?.has(o) || t !== STATUS_PENDING && (e.
|
|
1870
|
+
e.W = clock;
|
|
1871
|
+
if (t === STATUS_PENDING && o && !e.$e?.has(o) || t !== STATUS_PENDING && (e.De !== n || e.$e)) {
|
|
1863
1872
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1864
1873
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1865
1874
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1866
1875
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1867
1876
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1868
|
-
if (r.
|
|
1877
|
+
if (r._t && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1869
1878
|
enqueueSub(e);
|
|
1870
1879
|
schedule();
|
|
1871
1880
|
return;
|
|
@@ -1876,9 +1885,9 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1876
1885
|
});
|
|
1877
1886
|
}
|
|
1878
1887
|
|
|
1879
|
-
GlobalQueue.
|
|
1888
|
+
GlobalQueue.Z = recompute;
|
|
1880
1889
|
|
|
1881
|
-
GlobalQueue.
|
|
1890
|
+
GlobalQueue.X = disposeChildren;
|
|
1882
1891
|
|
|
1883
1892
|
let tracking = false;
|
|
1884
1893
|
|
|
@@ -1910,8 +1919,8 @@ let snapshotSources = null;
|
|
|
1910
1919
|
|
|
1911
1920
|
function ownerInSnapshotScope(e) {
|
|
1912
1921
|
while (e) {
|
|
1913
|
-
if (e.
|
|
1914
|
-
e = e.
|
|
1922
|
+
if (e.yt) return true;
|
|
1923
|
+
e = e.B;
|
|
1915
1924
|
}
|
|
1916
1925
|
return false;
|
|
1917
1926
|
}
|
|
@@ -1922,42 +1931,45 @@ function setSnapshotCapture(e) {
|
|
|
1922
1931
|
}
|
|
1923
1932
|
|
|
1924
1933
|
function markSnapshotScope(e) {
|
|
1925
|
-
e.
|
|
1934
|
+
e.yt = true;
|
|
1926
1935
|
}
|
|
1927
1936
|
|
|
1928
1937
|
function releaseSnapshotScope(e) {
|
|
1929
|
-
e.
|
|
1938
|
+
e.yt = false;
|
|
1930
1939
|
releaseSubtree(e);
|
|
1931
1940
|
schedule();
|
|
1932
1941
|
}
|
|
1933
1942
|
|
|
1934
1943
|
function releaseSubtree(e) {
|
|
1935
|
-
let t = e.
|
|
1944
|
+
let t = e.it;
|
|
1936
1945
|
while (t) {
|
|
1937
|
-
if (t.
|
|
1938
|
-
t = t.
|
|
1946
|
+
if (t.yt) {
|
|
1947
|
+
t = t.ot;
|
|
1939
1948
|
continue;
|
|
1940
1949
|
}
|
|
1941
1950
|
if (t.Ve) {
|
|
1942
1951
|
const e = t;
|
|
1943
|
-
e.
|
|
1944
|
-
if (e.
|
|
1945
|
-
e.
|
|
1946
|
-
e.
|
|
1947
|
-
if (dirtyQueue.
|
|
1952
|
+
e.Ue &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1953
|
+
if (e.Ge & REACTIVE_SNAPSHOT_STALE) {
|
|
1954
|
+
e.Ge &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1955
|
+
e.Ge |= REACTIVE_DIRTY;
|
|
1956
|
+
if (dirtyQueue.P > e.Xe) dirtyQueue.P = e.Xe;
|
|
1948
1957
|
insertIntoHeap(e, dirtyQueue);
|
|
1949
1958
|
}
|
|
1950
1959
|
}
|
|
1951
1960
|
releaseSubtree(t);
|
|
1952
|
-
t = t.
|
|
1961
|
+
t = t.ot;
|
|
1953
1962
|
}
|
|
1954
1963
|
}
|
|
1955
1964
|
|
|
1956
1965
|
function clearSnapshots() {
|
|
1957
1966
|
if (snapshotSources) {
|
|
1958
1967
|
for (const e of snapshotSources) {
|
|
1959
|
-
delete e.
|
|
1960
|
-
|
|
1968
|
+
delete e.ve;
|
|
1969
|
+
// StoreNode targets share one pre-initialized hidden class (see
|
|
1970
|
+
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
1971
|
+
// when present so signal-node sources don't grow the field.
|
|
1972
|
+
if (e[STORE_SNAPSHOT_PROPS] !== undefined) e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
1961
1973
|
}
|
|
1962
1974
|
snapshotSources = null;
|
|
1963
1975
|
}
|
|
@@ -1965,35 +1977,35 @@ function clearSnapshots() {
|
|
|
1965
1977
|
}
|
|
1966
1978
|
|
|
1967
1979
|
function recompute(e, t = false) {
|
|
1968
|
-
const n = e.
|
|
1980
|
+
const n = e.Fe;
|
|
1969
1981
|
if (!t) {
|
|
1970
1982
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
1971
1983
|
deleteFromHeap(e, queueFor(e));
|
|
1972
|
-
e.
|
|
1984
|
+
e.ut = null;
|
|
1973
1985
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
1974
|
-
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.
|
|
1986
|
+
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.it !== null || e.Et !== null) {
|
|
1975
1987
|
markDisposal(e);
|
|
1976
|
-
e.
|
|
1977
|
-
e.
|
|
1978
|
-
e.
|
|
1979
|
-
e.
|
|
1980
|
-
e.
|
|
1988
|
+
e.Me = e.Et;
|
|
1989
|
+
e.We = e.it;
|
|
1990
|
+
e.Et = null;
|
|
1991
|
+
e.it = null;
|
|
1992
|
+
e.lt = 0;
|
|
1981
1993
|
} else ;
|
|
1982
1994
|
}
|
|
1983
|
-
let r = !!(e.
|
|
1995
|
+
let r = !!(e.Ge & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1984
1996
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1985
|
-
const o = !!(e.
|
|
1997
|
+
const o = !!(e.Qe & STATUS_UNINITIALIZED);
|
|
1986
1998
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1987
1999
|
// the recompute wipes _flags below.
|
|
1988
|
-
const s = (e.
|
|
2000
|
+
const s = (e.Ge & REACTIVE_REASK) !== 0;
|
|
1989
2001
|
const u = context;
|
|
1990
2002
|
context = e;
|
|
1991
|
-
e.
|
|
1992
|
-
e.
|
|
1993
|
-
e.
|
|
1994
|
-
e.
|
|
1995
|
-
let l = e.V === NOT_PENDING ? e.
|
|
1996
|
-
let c = e.
|
|
2003
|
+
e.st = null;
|
|
2004
|
+
e.Rt++;
|
|
2005
|
+
e.Ge = REACTIVE_RECOMPUTING_DEPS;
|
|
2006
|
+
e.W = clock;
|
|
2007
|
+
let l = e.V === NOT_PENDING ? e.ke : e.V;
|
|
2008
|
+
let c = e.Xe;
|
|
1997
2009
|
let a = tracking;
|
|
1998
2010
|
let f = currentOptimisticLane;
|
|
1999
2011
|
tracking = true;
|
|
@@ -2011,7 +2023,7 @@ function recompute(e, t = false) {
|
|
|
2011
2023
|
if (r) {
|
|
2012
2024
|
const t = GlobalQueue.Pe(e, true);
|
|
2013
2025
|
if (t) currentOptimisticLane = t;
|
|
2014
|
-
} else if (activeTransition && !t && activeTransition.
|
|
2026
|
+
} else if (activeTransition && !t && activeTransition.v.length) {
|
|
2015
2027
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2016
2028
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2017
2029
|
// recomputes under the right posture and propagates correctly.
|
|
@@ -2021,53 +2033,53 @@ function recompute(e, t = false) {
|
|
|
2021
2033
|
currentOptimisticLane = t;
|
|
2022
2034
|
}
|
|
2023
2035
|
}
|
|
2024
|
-
const
|
|
2025
|
-
const
|
|
2026
|
-
if (
|
|
2036
|
+
const d = n && n !== EFFECT_USER;
|
|
2037
|
+
const S = stale;
|
|
2038
|
+
if (d) stale = true;
|
|
2027
2039
|
try {
|
|
2028
|
-
if (!false && e.
|
|
2040
|
+
if (!false && e.Ue & CONFIG_SYNC) {
|
|
2029
2041
|
l = e.Ve(l);
|
|
2030
|
-
e.
|
|
2042
|
+
e.ut = null;
|
|
2031
2043
|
} else {
|
|
2032
2044
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2033
2045
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2034
2046
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2035
2047
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2036
2048
|
// iteration drive updates.
|
|
2037
|
-
const t = e.
|
|
2049
|
+
const t = e.ut;
|
|
2038
2050
|
const n = e.Ve(l);
|
|
2039
2051
|
const r = typeof n === "object" && n !== null;
|
|
2040
|
-
const i = e.
|
|
2052
|
+
const i = e.ut !== t;
|
|
2041
2053
|
l = i || !r ? n : handleAsync(e, n);
|
|
2042
|
-
if (!i && !r) e.
|
|
2054
|
+
if (!i && !r) e.ut = null;
|
|
2043
2055
|
}
|
|
2044
2056
|
clearStatus(e, t);
|
|
2045
2057
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2046
|
-
if (e.i) GlobalQueue.
|
|
2058
|
+
if (e.i) GlobalQueue.ge(e);
|
|
2047
2059
|
} catch (t) {
|
|
2048
2060
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2049
2061
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2050
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2062
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.Ce(e);
|
|
2051
2063
|
let n = false;
|
|
2052
2064
|
if (t instanceof NotReadyError) {
|
|
2053
|
-
e.
|
|
2054
|
-
if (GlobalQueue.
|
|
2065
|
+
e.It = true;
|
|
2066
|
+
if (GlobalQueue.Se !== null) n = GlobalQueue.Se(e, s);
|
|
2055
2067
|
}
|
|
2056
2068
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2057
|
-
if (n) GlobalQueue.
|
|
2069
|
+
if (n) GlobalQueue.Te(e);
|
|
2058
2070
|
} finally {
|
|
2059
2071
|
tracking = a;
|
|
2060
2072
|
latestReadActive = E;
|
|
2061
|
-
if (
|
|
2062
|
-
e.
|
|
2073
|
+
if (d) stale = S;
|
|
2074
|
+
e.Ge = REACTIVE_NONE | (t ? e.Ge & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2063
2075
|
context = u;
|
|
2064
2076
|
}
|
|
2065
|
-
if (!e.
|
|
2077
|
+
if (!e.De) {
|
|
2066
2078
|
trimStaleDeps(e);
|
|
2067
|
-
const s = i ? unwrapOverride(e.A) : e.V === NOT_PENDING ? e.
|
|
2079
|
+
const s = i ? unwrapOverride(e.A) : e.V === NOT_PENDING ? e.ke : e.V;
|
|
2068
2080
|
let u = false;
|
|
2069
2081
|
try {
|
|
2070
|
-
u = !n && o || !e.
|
|
2082
|
+
u = !n && o || !e.At || !e.At(s, l);
|
|
2071
2083
|
} catch (t) {
|
|
2072
2084
|
// A throwing user comparator is an error of this node's computation.
|
|
2073
2085
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2081,15 +2093,15 @@ function recompute(e, t = false) {
|
|
|
2081
2093
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2082
2094
|
// effect() can call its runner synchronously for the first run.
|
|
2083
2095
|
if (n && u) {
|
|
2084
|
-
e.
|
|
2096
|
+
e.xe = !e.De;
|
|
2085
2097
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2086
2098
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2087
|
-
if (!t) e.
|
|
2099
|
+
if (!t) e.Be.enqueue(n, e.Pt ??= GlobalQueue.J.bind(null, e));
|
|
2088
2100
|
}
|
|
2089
|
-
if (e.
|
|
2101
|
+
if (e.De) ; else if (u) {
|
|
2090
2102
|
const o = i ? e.A : undefined;
|
|
2091
2103
|
if (t || n && activeTransition !== e.T || r) {
|
|
2092
|
-
e.
|
|
2104
|
+
e.ke = l;
|
|
2093
2105
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2094
2106
|
// override unconditionally. The direct _value commit is the lane's
|
|
2095
2107
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
@@ -2105,7 +2117,7 @@ function recompute(e, t = false) {
|
|
|
2105
2117
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2106
2118
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2107
2119
|
// pending value commits before effects run.
|
|
2108
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2120
|
+
if ((activeTransition || e.T) && GlobalQueue.ue !== null) GlobalQueue.ue(e, l);
|
|
2109
2121
|
}
|
|
2110
2122
|
if (!i || r || e.A !== o) insertSubs(e, r || i);
|
|
2111
2123
|
} else if (i) {
|
|
@@ -2114,77 +2126,77 @@ function recompute(e, t = false) {
|
|
|
2114
2126
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2115
2127
|
if (e.V === NOT_PENDING) queuePendingNode(e);
|
|
2116
2128
|
e.V = l;
|
|
2117
|
-
} else if (e.
|
|
2118
|
-
for (let t = e.
|
|
2119
|
-
insertIntoHeapHeight(t.
|
|
2129
|
+
} else if (e.Xe != c) {
|
|
2130
|
+
for (let t = e.U; t !== null; t = t.we) {
|
|
2131
|
+
insertIntoHeapHeight(t.Le, queueFor(t.Le));
|
|
2120
2132
|
}
|
|
2121
2133
|
}
|
|
2122
2134
|
}
|
|
2123
2135
|
currentOptimisticLane = f;
|
|
2124
|
-
const T = e.V !== NOT_PENDING || e.
|
|
2136
|
+
const T = e.V !== NOT_PENDING || e.We !== null || e.Me !== null || (e.Qe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2125
2137
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2126
2138
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2127
2139
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2128
2140
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2129
2141
|
// _transition.
|
|
2130
|
-
T && (!t || e.
|
|
2142
|
+
T && (!t || e.Qe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2131
2143
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2132
2144
|
}
|
|
2133
2145
|
|
|
2134
2146
|
function updateIfNecessary(e) {
|
|
2135
|
-
if (e.
|
|
2136
|
-
for (let t = e.
|
|
2137
|
-
const n = t.
|
|
2138
|
-
const r = n.
|
|
2147
|
+
if (e.Ge & REACTIVE_CHECK) {
|
|
2148
|
+
for (let t = e.je; t; t = t.Ke) {
|
|
2149
|
+
const n = t.Ye;
|
|
2150
|
+
const r = n.qe || n;
|
|
2139
2151
|
if (r.Ve) {
|
|
2140
2152
|
updateIfNecessary(r);
|
|
2141
2153
|
}
|
|
2142
|
-
if (e.
|
|
2154
|
+
if (e.Ge & REACTIVE_DIRTY) {
|
|
2143
2155
|
break;
|
|
2144
2156
|
}
|
|
2145
2157
|
}
|
|
2146
2158
|
}
|
|
2147
|
-
if (e.
|
|
2159
|
+
if (e.Ge & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.De && e.W < clock && !e.ut) {
|
|
2148
2160
|
recompute(e);
|
|
2149
2161
|
}
|
|
2150
|
-
e.
|
|
2162
|
+
e.Ge = e.Ge & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2151
2163
|
}
|
|
2152
2164
|
|
|
2153
2165
|
function computed(e, t) {
|
|
2154
2166
|
const n = t?.transparent ?? false;
|
|
2155
2167
|
const r = {
|
|
2156
2168
|
id: inheritId(t, n, context),
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2169
|
+
Ue: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2170
|
+
At: t?.equals != null ? t.equals : isEqual,
|
|
2171
|
+
F: t?.unobserved,
|
|
2172
|
+
Et: null,
|
|
2173
|
+
Be: context?.Be ?? globalQueue,
|
|
2162
2174
|
dt: context?.dt ?? defaultContext,
|
|
2163
|
-
|
|
2175
|
+
lt: 0,
|
|
2164
2176
|
Ve: e,
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
ut: null,
|
|
2172
|
-
It: 0,
|
|
2173
|
-
k: null,
|
|
2174
|
-
_t: null,
|
|
2175
|
-
Z: context,
|
|
2177
|
+
ke: undefined,
|
|
2178
|
+
Xe: 0,
|
|
2179
|
+
nt: null,
|
|
2180
|
+
tt: undefined,
|
|
2181
|
+
et: null,
|
|
2182
|
+
je: null,
|
|
2176
2183
|
st: null,
|
|
2177
|
-
|
|
2184
|
+
Rt: 0,
|
|
2185
|
+
U: null,
|
|
2186
|
+
Tt: null,
|
|
2187
|
+
B: context,
|
|
2178
2188
|
ot: null,
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2189
|
+
ct: null,
|
|
2190
|
+
it: null,
|
|
2191
|
+
Ge: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2192
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2193
|
+
W: clock,
|
|
2182
2194
|
V: NOT_PENDING,
|
|
2183
|
-
He: null,
|
|
2184
2195
|
Me: null,
|
|
2185
|
-
|
|
2196
|
+
We: null,
|
|
2197
|
+
ut: null,
|
|
2186
2198
|
T: null,
|
|
2187
|
-
|
|
2199
|
+
ht: false
|
|
2188
2200
|
};
|
|
2189
2201
|
setupComputedNode(r, t);
|
|
2190
2202
|
return r;
|
|
@@ -2199,44 +2211,44 @@ function computed(e, t) {
|
|
|
2199
2211
|
const s = o?.transparent ?? false;
|
|
2200
2212
|
const u = {
|
|
2201
2213
|
id: inheritId(o, s, context),
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2214
|
+
Ue: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2215
|
+
At: false,
|
|
2216
|
+
F: o?.unobserved,
|
|
2217
|
+
Et: null,
|
|
2218
|
+
Be: context?.Be ?? globalQueue,
|
|
2207
2219
|
dt: context?.dt ?? defaultContext,
|
|
2208
|
-
|
|
2220
|
+
lt: 0,
|
|
2209
2221
|
Ve: e,
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
ut: null,
|
|
2217
|
-
It: 0,
|
|
2218
|
-
k: null,
|
|
2219
|
-
_t: null,
|
|
2220
|
-
Z: context,
|
|
2222
|
+
ke: undefined,
|
|
2223
|
+
Xe: 0,
|
|
2224
|
+
nt: null,
|
|
2225
|
+
tt: undefined,
|
|
2226
|
+
et: null,
|
|
2227
|
+
je: null,
|
|
2221
2228
|
st: null,
|
|
2222
|
-
|
|
2229
|
+
Rt: 0,
|
|
2230
|
+
U: null,
|
|
2231
|
+
Tt: null,
|
|
2232
|
+
B: context,
|
|
2223
2233
|
ot: null,
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2234
|
+
ct: null,
|
|
2235
|
+
it: null,
|
|
2236
|
+
Ge: REACTIVE_LAZY,
|
|
2237
|
+
Qe: STATUS_UNINITIALIZED,
|
|
2238
|
+
W: clock,
|
|
2227
2239
|
V: NOT_PENDING,
|
|
2228
|
-
He: null,
|
|
2229
2240
|
Me: null,
|
|
2230
|
-
|
|
2241
|
+
We: null,
|
|
2242
|
+
ut: null,
|
|
2231
2243
|
T: null,
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2244
|
+
ht: false,
|
|
2245
|
+
xe: false,
|
|
2246
|
+
gt: undefined,
|
|
2247
|
+
bt: t,
|
|
2248
|
+
Dt: n,
|
|
2249
|
+
ft: undefined,
|
|
2250
|
+
Fe: r,
|
|
2251
|
+
Nt: i
|
|
2240
2252
|
};
|
|
2241
2253
|
setupComputedNode(u, lazyOptions);
|
|
2242
2254
|
return u;
|
|
@@ -2247,24 +2259,24 @@ const lazyOptions = {
|
|
|
2247
2259
|
};
|
|
2248
2260
|
|
|
2249
2261
|
function setupComputedNode(e, t) {
|
|
2250
|
-
e.
|
|
2251
|
-
const n = context?.
|
|
2262
|
+
e.et = e;
|
|
2263
|
+
const n = context?.ze ? context.Je : context;
|
|
2252
2264
|
if (context) {
|
|
2253
|
-
const t = context.
|
|
2265
|
+
const t = context.it;
|
|
2254
2266
|
if (t === null) {
|
|
2255
|
-
context.
|
|
2267
|
+
context.it = e;
|
|
2256
2268
|
} else {
|
|
2257
|
-
e.
|
|
2258
|
-
t.
|
|
2259
|
-
context.
|
|
2269
|
+
e.ot = t;
|
|
2270
|
+
t.ct = e;
|
|
2271
|
+
context.it = e;
|
|
2260
2272
|
}
|
|
2261
2273
|
}
|
|
2262
|
-
if (n) e.
|
|
2263
|
-
if (GlobalQueue.
|
|
2274
|
+
if (n) e.Xe = n.Xe + 1;
|
|
2275
|
+
if (GlobalQueue.oe !== null) GlobalQueue.oe(e);
|
|
2264
2276
|
!t?.lazy && recompute(e, true);
|
|
2265
2277
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2266
|
-
if (!(e.
|
|
2267
|
-
e.
|
|
2278
|
+
if (!(e.Qe & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2279
|
+
e.ve = e.ke === undefined ? NO_SNAPSHOT : e.ke;
|
|
2268
2280
|
snapshotSources.add(e);
|
|
2269
2281
|
}
|
|
2270
2282
|
}
|
|
@@ -2272,20 +2284,20 @@ function setupComputedNode(e, t) {
|
|
|
2272
2284
|
|
|
2273
2285
|
function signal(e, t, n = null) {
|
|
2274
2286
|
const r = {
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2287
|
+
At: t?.equals != null ? t.equals : isEqual,
|
|
2288
|
+
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0),
|
|
2289
|
+
F: t?.unobserved,
|
|
2290
|
+
ke: e,
|
|
2291
|
+
U: null,
|
|
2292
|
+
Tt: null,
|
|
2293
|
+
W: clock,
|
|
2294
|
+
qe: n,
|
|
2295
|
+
rt: n?.nt || null,
|
|
2284
2296
|
V: NOT_PENDING
|
|
2285
2297
|
};
|
|
2286
|
-
n && (n.
|
|
2287
|
-
if (snapshotCaptureActive && !(r.
|
|
2288
|
-
r.
|
|
2298
|
+
n && (n.nt = r);
|
|
2299
|
+
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.Qe ?? 0) & STATUS_PENDING)) {
|
|
2300
|
+
r.ve = e === undefined ? NO_SNAPSHOT : e;
|
|
2289
2301
|
snapshotSources.add(r);
|
|
2290
2302
|
}
|
|
2291
2303
|
return r;
|
|
@@ -2329,11 +2341,11 @@ function isEqual(e, t) {
|
|
|
2329
2341
|
* );
|
|
2330
2342
|
* ```
|
|
2331
2343
|
*/ function untrack(e, t) {
|
|
2332
|
-
if (GlobalQueue.
|
|
2344
|
+
if (GlobalQueue.se === null && !tracking && true) return e();
|
|
2333
2345
|
const n = tracking;
|
|
2334
2346
|
tracking = false;
|
|
2335
2347
|
try {
|
|
2336
|
-
if (GlobalQueue.
|
|
2348
|
+
if (GlobalQueue.se !== null) return GlobalQueue.se(e);
|
|
2337
2349
|
return e();
|
|
2338
2350
|
} finally {
|
|
2339
2351
|
tracking = n;
|
|
@@ -2345,10 +2357,10 @@ function isEqual(e, t) {
|
|
|
2345
2357
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2346
2358
|
* date so its status flags reflect the current graph.
|
|
2347
2359
|
*/ function prepareComputed(e, t) {
|
|
2348
|
-
if (e.
|
|
2349
|
-
e.
|
|
2360
|
+
if (e.Ge & REACTIVE_LAZY) {
|
|
2361
|
+
e.Ge &= ~REACTIVE_LAZY;
|
|
2350
2362
|
recompute(e, true);
|
|
2351
|
-
} else if (e.
|
|
2363
|
+
} else if (e.Ge & REACTIVE_DISPOSED) {
|
|
2352
2364
|
recompute(e, true);
|
|
2353
2365
|
} else if (t) {
|
|
2354
2366
|
updateIfNecessary(e);
|
|
@@ -2360,72 +2372,72 @@ function read(e) {
|
|
|
2360
2372
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2361
2373
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2362
2374
|
// than the original node (which stays "pending" while held in a transition).
|
|
2363
|
-
if (latestReadActive) return GlobalQueue.
|
|
2375
|
+
if (latestReadActive) return GlobalQueue.fe(e);
|
|
2364
2376
|
let t = context;
|
|
2365
|
-
if (t?.
|
|
2377
|
+
if (t?.ze) t = t.Je;
|
|
2366
2378
|
const n = e;
|
|
2367
|
-
const r = e.
|
|
2379
|
+
const r = e.qe;
|
|
2368
2380
|
const i = r || e;
|
|
2369
2381
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2370
2382
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2371
2383
|
// recompute don't collect into the probe.
|
|
2372
2384
|
if (pendingCheckActive) {
|
|
2373
|
-
GlobalQueue.
|
|
2385
|
+
GlobalQueue.Ee(e, t, i, r);
|
|
2374
2386
|
} else if (typeof n.Ve === "function") {
|
|
2375
2387
|
prepareComputed(e, false);
|
|
2376
2388
|
}
|
|
2377
|
-
if (!n.Ve && i === e && e.A === undefined && e.
|
|
2389
|
+
if (!n.Ve && i === e && e.A === undefined && e.ve === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2378
2390
|
if (t && tracking) link(e, t);
|
|
2379
|
-
return !t || e.V === NOT_PENDING ? e.
|
|
2391
|
+
return !t || e.V === NOT_PENDING ? e.ke : e.V;
|
|
2380
2392
|
}
|
|
2381
2393
|
if (t && tracking) {
|
|
2382
2394
|
link(e, t, pendingCheckActive);
|
|
2383
2395
|
if (i.Ve) {
|
|
2384
2396
|
const n = queueFor(e);
|
|
2385
|
-
if (i.
|
|
2397
|
+
if (i.Xe >= n.P) {
|
|
2386
2398
|
markNode(t);
|
|
2387
2399
|
markHeap(n);
|
|
2388
2400
|
updateIfNecessary(i);
|
|
2389
2401
|
}
|
|
2390
|
-
const r = i.
|
|
2402
|
+
const r = i.Xe;
|
|
2391
2403
|
// parent check is shallow, might need to be recursive
|
|
2392
|
-
if (r >= t.
|
|
2393
|
-
t.
|
|
2404
|
+
if (r >= t.Xe && e.B !== t) {
|
|
2405
|
+
t.Xe = r + 1;
|
|
2394
2406
|
}
|
|
2395
2407
|
}
|
|
2396
2408
|
}
|
|
2397
|
-
if (i.
|
|
2409
|
+
if (i.Qe & STATUS_PENDING) {
|
|
2398
2410
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2399
2411
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2400
2412
|
// is installed): under a lane, only same-lane pending async without an
|
|
2401
2413
|
// active override throws.
|
|
2402
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2414
|
+
if (currentOptimisticLane === null || GlobalQueue.Ne(i)) {
|
|
2403
2415
|
if (!tracking && e !== t) link(e, t);
|
|
2404
|
-
throw i.
|
|
2416
|
+
throw i.De;
|
|
2405
2417
|
}
|
|
2406
|
-
} else if (t && i !== e && i.
|
|
2418
|
+
} else if (t && i !== e && i.Qe & STATUS_UNINITIALIZED) {
|
|
2407
2419
|
if (!tracking && e !== t) link(e, t);
|
|
2408
|
-
throw i.
|
|
2409
|
-
} else if (!t && i.
|
|
2410
|
-
throw i.
|
|
2420
|
+
throw i.De;
|
|
2421
|
+
} else if (!t && i.Qe & STATUS_UNINITIALIZED) {
|
|
2422
|
+
throw i.De;
|
|
2411
2423
|
}
|
|
2412
2424
|
}
|
|
2413
|
-
if (e.Ve && e.
|
|
2425
|
+
if (e.Ve && e.Qe & STATUS_ERROR) {
|
|
2414
2426
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2415
2427
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2416
2428
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2417
2429
|
// - el._time < clock: only on a later cycle than the one the error was found
|
|
2418
|
-
if (tracking && !pendingCheckActive && e.
|
|
2430
|
+
if (tracking && !pendingCheckActive && e.W < clock) {
|
|
2419
2431
|
recompute(e);
|
|
2420
2432
|
return read(e);
|
|
2421
|
-
} else throw e.
|
|
2433
|
+
} else throw e.De;
|
|
2422
2434
|
}
|
|
2423
|
-
if (snapshotCaptureActive && t && t.
|
|
2424
|
-
const n = e.
|
|
2435
|
+
if (snapshotCaptureActive && t && t.Ue & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2436
|
+
const n = e.ve;
|
|
2425
2437
|
if (n !== undefined) {
|
|
2426
2438
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2427
|
-
const i = e.V !== NOT_PENDING ? e.V : e.
|
|
2428
|
-
if (i !== r) t.
|
|
2439
|
+
const i = e.V !== NOT_PENDING ? e.V : e.ke;
|
|
2440
|
+
if (i !== r) t.Ge |= REACTIVE_SNAPSHOT_STALE;
|
|
2429
2441
|
return r;
|
|
2430
2442
|
}
|
|
2431
2443
|
}
|
|
@@ -2440,18 +2452,18 @@ function read(e) {
|
|
|
2440
2452
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2441
2453
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2442
2454
|
// engine — a non-null lane implies it is installed.)
|
|
2443
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2444
|
-
return e.
|
|
2455
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.he(e, i, t)) {
|
|
2456
|
+
return e.ke;
|
|
2445
2457
|
}
|
|
2446
2458
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2447
2459
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2448
2460
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2449
2461
|
// (The lane-context clause lives with the engine.)
|
|
2450
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2462
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.V === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.ke : e.V;
|
|
2451
2463
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2452
2464
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2453
2465
|
if (pendingCheckActive) GlobalQueue.de(e, o);
|
|
2454
|
-
if (!t && i === e && typeof n.Ve === "function" && e.
|
|
2466
|
+
if (!t && i === e && typeof n.Ve === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.Qe & STATUS_PENDING) && !e.U) {
|
|
2455
2467
|
unobserved(e);
|
|
2456
2468
|
}
|
|
2457
2469
|
return o;
|
|
@@ -2464,16 +2476,16 @@ function setSignal(e, t) {
|
|
|
2464
2476
|
// _overrideValue slot, and every module that creates one installs the
|
|
2465
2477
|
// engine first.
|
|
2466
2478
|
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.Oe(e, t);
|
|
2467
|
-
const n = e.V === NOT_PENDING ? e.
|
|
2479
|
+
const n = e.V === NOT_PENDING ? e.ke : e.V;
|
|
2468
2480
|
if (typeof t === "function") t = t(n);
|
|
2469
2481
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2470
2482
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2471
|
-
const r = !!(e.
|
|
2483
|
+
const r = !!(e.Qe & STATUS_UNINITIALIZED) || !e.At || !e.At(n, t);
|
|
2472
2484
|
if (!r) return t;
|
|
2473
2485
|
if (e.V === NOT_PENDING) queuePendingNode(e);
|
|
2474
2486
|
e.V = t;
|
|
2475
|
-
GlobalQueue.
|
|
2476
|
-
e.
|
|
2487
|
+
GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2488
|
+
e.W = clock;
|
|
2477
2489
|
insertSubs(e);
|
|
2478
2490
|
schedule();
|
|
2479
2491
|
return t;
|
|
@@ -2487,11 +2499,11 @@ function setSignal(e, t) {
|
|
|
2487
2499
|
* cleanup point.
|
|
2488
2500
|
*/ function suppressComputedRecompute(e) {
|
|
2489
2501
|
deleteFromHeap(e, queueFor(e));
|
|
2490
|
-
if (!(e.
|
|
2502
|
+
if (!(e.Ge & REACTIVE_MANUAL_WRITE) && e.V === NOT_PENDING) {
|
|
2491
2503
|
queuePendingNode(e);
|
|
2492
2504
|
schedule();
|
|
2493
2505
|
}
|
|
2494
|
-
e.
|
|
2506
|
+
e.Ge = e.Ge & -4 | REACTIVE_MANUAL_WRITE;
|
|
2495
2507
|
}
|
|
2496
2508
|
|
|
2497
2509
|
/**
|
|
@@ -2570,7 +2582,7 @@ function staleValues(e, t = true) {
|
|
|
2570
2582
|
if (!t) {
|
|
2571
2583
|
return;
|
|
2572
2584
|
}
|
|
2573
|
-
if (typeof t.Ve === "function" && !(t.
|
|
2585
|
+
if (typeof t.Ve === "function" && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2574
2586
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2575
2587
|
// same question: mark it so the recompute classifies any resulting
|
|
2576
2588
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2578,11 +2590,11 @@ function staleValues(e, t = true) {
|
|
|
2578
2590
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2579
2591
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2580
2592
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2581
|
-
if (!(t.
|
|
2582
|
-
t.
|
|
2593
|
+
if (!(t.Ge & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2594
|
+
t.Ge |= REACTIVE_REASK;
|
|
2583
2595
|
armReaskClear();
|
|
2584
2596
|
}
|
|
2585
|
-
t.
|
|
2597
|
+
t.Ge = t.Ge & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2586
2598
|
insertIntoHeap(t, queueFor(t));
|
|
2587
2599
|
schedule();
|
|
2588
2600
|
}
|
|
@@ -2648,8 +2660,8 @@ function externalUntrack(e) {
|
|
|
2648
2660
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2649
2661
|
// `externalSourceConfig` truthiness checks.
|
|
2650
2662
|
function syncExternalHooks() {
|
|
2651
|
-
GlobalQueue.
|
|
2652
|
-
GlobalQueue.
|
|
2663
|
+
GlobalQueue.oe = externalSourceConfig ? wireExternalSource : null;
|
|
2664
|
+
GlobalQueue.se = externalSourceConfig ? externalUntrack : null;
|
|
2653
2665
|
}
|
|
2654
2666
|
|
|
2655
2667
|
function enableExternalSource(e) {
|
|
@@ -2756,9 +2768,9 @@ function isUndefined(e) {
|
|
|
2756
2768
|
*/
|
|
2757
2769
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, t) {
|
|
2758
2770
|
const n = e.A !== NOT_PENDING;
|
|
2759
|
-
const r = n ? unwrapOverride(e.A) : e.
|
|
2771
|
+
const r = n ? unwrapOverride(e.A) : e.ke;
|
|
2760
2772
|
if (typeof t === "function") t = t(r);
|
|
2761
|
-
const i = !!(e.
|
|
2773
|
+
const i = !!(e.Qe & STATUS_UNINITIALIZED) || !e.At || !e.At(r, t);
|
|
2762
2774
|
if (!i) {
|
|
2763
2775
|
// Same-value write with an active override still entangles the current
|
|
2764
2776
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2772,7 +2784,7 @@ function isUndefined(e) {
|
|
|
2772
2784
|
// No revert target is stashed: while the override is active every reader
|
|
2773
2785
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
2774
2786
|
// reverting is just dropping the override — _value is already correct.
|
|
2775
|
-
else globalQueue.D.
|
|
2787
|
+
else globalQueue.D.v.push(e);
|
|
2776
2788
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2777
2789
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2778
2790
|
// which a shared subscriber can merge across transactions (#2912).
|
|
@@ -2783,8 +2795,8 @@ function isUndefined(e) {
|
|
|
2783
2795
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
2784
2796
|
// writes off the optimistic path into permanent commits (#2898).
|
|
2785
2797
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2786
|
-
GlobalQueue.
|
|
2787
|
-
e.
|
|
2798
|
+
GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2799
|
+
e.W = clock;
|
|
2788
2800
|
insertSubs(e, true);
|
|
2789
2801
|
schedule();
|
|
2790
2802
|
return t;
|
|
@@ -2795,9 +2807,9 @@ function isUndefined(e) {
|
|
|
2795
2807
|
* while one of its optimistic nodes holds an active override that is still
|
|
2796
2808
|
* pending on real (non-affects-sentinel) async.
|
|
2797
2809
|
*/ function transitionBlocked(e) {
|
|
2798
|
-
for (let t = 0; t < e.
|
|
2799
|
-
const n = e.
|
|
2800
|
-
if (hasActiveOverride(n) && "
|
|
2810
|
+
for (let t = 0; t < e.v.length; t++) {
|
|
2811
|
+
const n = e.v[t];
|
|
2812
|
+
if (hasActiveOverride(n) && "Qe" in n && n.Qe & STATUS_PENDING && n.De instanceof NotReadyError) {
|
|
2801
2813
|
return true;
|
|
2802
2814
|
}
|
|
2803
2815
|
}
|
|
@@ -2815,10 +2827,10 @@ function resolveOptimisticNodes(e) {
|
|
|
2815
2827
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2816
2828
|
// override-covered authoritative values hold in _pendingValue and
|
|
2817
2829
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2818
|
-
if (!(t.
|
|
2830
|
+
if (!(t.Qe & STATUS_PENDING)) t.Qe &= ~STATUS_UNINITIALIZED;
|
|
2819
2831
|
const r = t.A;
|
|
2820
2832
|
t.A = NOT_PENDING;
|
|
2821
|
-
if (r !== NOT_PENDING && t.
|
|
2833
|
+
if (r !== NOT_PENDING && t.ke !== unwrapOverride(r)) insertSubs(t, true);
|
|
2822
2834
|
t.T = null;
|
|
2823
2835
|
t.R = null;
|
|
2824
2836
|
}
|
|
@@ -2827,9 +2839,9 @@ function resolveOptimisticNodes(e) {
|
|
|
2827
2839
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2828
2840
|
for (let n = 0; n < t; n++) {
|
|
2829
2841
|
const t = e[n];
|
|
2830
|
-
if (t.
|
|
2842
|
+
if (t.O || t.p) GlobalQueue.ae(t);
|
|
2831
2843
|
const r = t.t;
|
|
2832
|
-
if (r && (r.
|
|
2844
|
+
if (r && (r.O === t || r.p === t)) GlobalQueue.ae(r);
|
|
2833
2845
|
}
|
|
2834
2846
|
e.splice(0, t);
|
|
2835
2847
|
}
|
|
@@ -2882,10 +2894,10 @@ function cleanupCompletedLanes(e) {
|
|
|
2882
2894
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2883
2895
|
* is recorded for replay at commit.
|
|
2884
2896
|
*/ function gatedRead(e, t, n) {
|
|
2885
|
-
if (latestReadActive || e.V === NOT_PENDING || e.Ve || t !== e && !(t.
|
|
2897
|
+
if (latestReadActive || e.V === NOT_PENDING || e.Ve || t !== e && !(t.Ge & REACTIVE_MANUAL_WRITE)) {
|
|
2886
2898
|
return false;
|
|
2887
2899
|
}
|
|
2888
|
-
activeTransition.
|
|
2900
|
+
activeTransition.Y.add(n);
|
|
2889
2901
|
return true;
|
|
2890
2902
|
}
|
|
2891
2903
|
|
|
@@ -2893,7 +2905,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2893
2905
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2894
2906
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2895
2907
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2896
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.
|
|
2908
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.Qe & STATUS_PENDING);
|
|
2897
2909
|
}
|
|
2898
2910
|
|
|
2899
2911
|
/**
|
|
@@ -2902,12 +2914,12 @@ function cleanupCompletedLanes(e) {
|
|
|
2902
2914
|
* can run before its OPT-dirty child propagates).
|
|
2903
2915
|
*/ function recomputeLane(e, t) {
|
|
2904
2916
|
if (t) return resolveLane(e) ?? null;
|
|
2905
|
-
for (let t = e.
|
|
2906
|
-
const n = t.
|
|
2907
|
-
if (n.
|
|
2917
|
+
for (let t = e.je; t; t = t.Ke) {
|
|
2918
|
+
const n = t.Ye;
|
|
2919
|
+
if (n.Ge & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2908
2920
|
const t = resolveLane(n);
|
|
2909
2921
|
if (t) {
|
|
2910
|
-
e.
|
|
2922
|
+
e.Ge |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
2911
2923
|
assignOrMergeLane(e, t);
|
|
2912
2924
|
return t;
|
|
2913
2925
|
}
|
|
@@ -2921,7 +2933,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2921
2933
|
if (t.o !== e) {
|
|
2922
2934
|
t.u.add(e);
|
|
2923
2935
|
e.i = t;
|
|
2924
|
-
GlobalQueue.
|
|
2936
|
+
GlobalQueue.le !== null && GlobalQueue.le(t.o);
|
|
2925
2937
|
}
|
|
2926
2938
|
}
|
|
2927
2939
|
|
|
@@ -2929,13 +2941,13 @@ function cleanupCompletedLanes(e) {
|
|
|
2929
2941
|
const t = resolveLane(e);
|
|
2930
2942
|
if (t) {
|
|
2931
2943
|
t.u.delete(e);
|
|
2932
|
-
GlobalQueue.
|
|
2944
|
+
GlobalQueue.le !== null && GlobalQueue.le(t.o);
|
|
2933
2945
|
}
|
|
2934
2946
|
}
|
|
2935
2947
|
|
|
2936
2948
|
function trackOptimisticStore(e) {
|
|
2937
2949
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
2938
|
-
globalQueue.D.
|
|
2950
|
+
globalQueue.D.L.add(e);
|
|
2939
2951
|
schedule();
|
|
2940
2952
|
}
|
|
2941
2953
|
|
|
@@ -2946,17 +2958,17 @@ function trackOptimisticStore(e) {
|
|
|
2946
2958
|
*/ function installOptimisticEngine() {
|
|
2947
2959
|
if (GlobalQueue.Oe !== null) return;
|
|
2948
2960
|
GlobalQueue.Oe = optimisticWrite;
|
|
2949
|
-
GlobalQueue.
|
|
2950
|
-
GlobalQueue.
|
|
2951
|
-
GlobalQueue.
|
|
2952
|
-
GlobalQueue.
|
|
2953
|
-
GlobalQueue.
|
|
2954
|
-
GlobalQueue.
|
|
2955
|
-
GlobalQueue.
|
|
2961
|
+
GlobalQueue.pe = resolveOptimisticNodes;
|
|
2962
|
+
GlobalQueue.Re = transitionBlocked;
|
|
2963
|
+
GlobalQueue.Ie = cleanupCompletedLanes;
|
|
2964
|
+
GlobalQueue.Ae = runLaneEffects;
|
|
2965
|
+
GlobalQueue.he = gatedRead;
|
|
2966
|
+
GlobalQueue.Ne = laneSuspends;
|
|
2967
|
+
GlobalQueue.ye = laneReadsCommitted;
|
|
2956
2968
|
GlobalQueue.Pe = recomputeLane;
|
|
2957
|
-
GlobalQueue.
|
|
2958
|
-
GlobalQueue.
|
|
2959
|
-
GlobalQueue.
|
|
2969
|
+
GlobalQueue.Ce = laneAsyncPending;
|
|
2970
|
+
GlobalQueue.ge = laneAsyncSettled;
|
|
2971
|
+
GlobalQueue.be = trackOptimisticStore;
|
|
2960
2972
|
}
|
|
2961
2973
|
|
|
2962
2974
|
/**
|
|
@@ -2975,21 +2987,21 @@ let pendingProbe = null;
|
|
|
2975
2987
|
* Get or create the pending signal for a node (lazy).
|
|
2976
2988
|
* Used by isPending() to track pending state reactively.
|
|
2977
2989
|
*/ function getPendingSignal(e) {
|
|
2978
|
-
if (!e.
|
|
2990
|
+
if (!e.O) {
|
|
2979
2991
|
// Start false, write true if pending - ensures reversion returns to false
|
|
2980
|
-
e.
|
|
2992
|
+
e.O = optimisticSignal(false, {
|
|
2981
2993
|
ownedWrite: true
|
|
2982
2994
|
});
|
|
2983
|
-
e.
|
|
2984
|
-
if (computePendingState(e)) setSignal(e.
|
|
2995
|
+
e.O.t = e;
|
|
2996
|
+
if (computePendingState(e)) setSignal(e.O, true);
|
|
2985
2997
|
}
|
|
2986
|
-
return e.
|
|
2998
|
+
return e.O;
|
|
2987
2999
|
}
|
|
2988
3000
|
|
|
2989
3001
|
function collectPendingSources(e) {
|
|
2990
3002
|
if (!pendingProbe) return;
|
|
2991
3003
|
pendingProbe.sources.add(e);
|
|
2992
|
-
const t = e.
|
|
3004
|
+
const t = e.qe || e;
|
|
2993
3005
|
if (t !== e) pendingProbe.sources.add(t);
|
|
2994
3006
|
}
|
|
2995
3007
|
|
|
@@ -3013,26 +3025,26 @@ function collectPendingSources(e) {
|
|
|
3013
3025
|
* (`_pendingObserver`) are skipped so an `isPending` wrapper memo never
|
|
3014
3026
|
* inherits the coverage it reports on.
|
|
3015
3027
|
*/ function markWalk(e, t) {
|
|
3016
|
-
if (e.
|
|
3028
|
+
if (e.k) return true;
|
|
3017
3029
|
// A real error outranks an inherited mark (A16/A24c): an errored node
|
|
3018
3030
|
// answers probes with its error, not a coverage verdict, and coverage does
|
|
3019
3031
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3020
3032
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3021
3033
|
// pending (the count check above), also matching.
|
|
3022
|
-
if (e.
|
|
3034
|
+
if (e.Qe & STATUS_ERROR) return false;
|
|
3023
3035
|
if (t.has(e)) return false;
|
|
3024
3036
|
t.add(e);
|
|
3025
|
-
const n = e.
|
|
3037
|
+
const n = e.qe;
|
|
3026
3038
|
if (n && markWalk(n, t)) return true;
|
|
3027
3039
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3028
3040
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3029
3041
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3030
3042
|
// latch a stale verdict on the companion.
|
|
3031
3043
|
const r = e;
|
|
3032
|
-
const i = r.
|
|
3044
|
+
const i = r.Ge & REACTIVE_RECOMPUTING_DEPS ? r.st : undefined;
|
|
3033
3045
|
if (i !== null) {
|
|
3034
|
-
for (let e = r.
|
|
3035
|
-
if (!e.
|
|
3046
|
+
for (let e = r.je ?? null; e !== null; e = e.Ke) {
|
|
3047
|
+
if (!e._t && markWalk(e.Ye, t)) return true;
|
|
3036
3048
|
if (e === i) break;
|
|
3037
3049
|
}
|
|
3038
3050
|
}
|
|
@@ -3045,54 +3057,54 @@ function collectPendingSources(e) {
|
|
|
3045
3057
|
|
|
3046
3058
|
function quietPending(e) {
|
|
3047
3059
|
if (e.$e) {
|
|
3048
|
-
for (const t of e.$e) if (!t.
|
|
3060
|
+
for (const t of e.$e) if (!t.ht) return false;
|
|
3049
3061
|
return true;
|
|
3050
3062
|
}
|
|
3051
|
-
return e.
|
|
3063
|
+
return e.ht;
|
|
3052
3064
|
}
|
|
3053
3065
|
|
|
3054
3066
|
function newQuestionInFlight(e) {
|
|
3055
|
-
return !!(e.
|
|
3067
|
+
return !!(e.Qe & STATUS_PENDING) && !(e.Qe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3056
3068
|
}
|
|
3057
3069
|
|
|
3058
3070
|
function computePendingState(e) {
|
|
3059
3071
|
const t = e;
|
|
3060
|
-
if (t.
|
|
3072
|
+
if (t.Ge & REACTIVE_DISPOSED) return false;
|
|
3061
3073
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3062
3074
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3063
3075
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3064
3076
|
if (markCovered(e)) return true;
|
|
3065
|
-
const n = e.
|
|
3077
|
+
const n = e.qe;
|
|
3066
3078
|
if (e.t) {
|
|
3067
3079
|
const t = e.t;
|
|
3068
|
-
const n = t.
|
|
3080
|
+
const n = t.qe || t;
|
|
3069
3081
|
return newQuestionInFlight(n);
|
|
3070
3082
|
}
|
|
3071
3083
|
if (n && e.V !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3072
|
-
return !!(n.
|
|
3084
|
+
return !!(n.Ge & REACTIVE_MANUAL_WRITE) || !n.ut && !(n.Qe & STATUS_PENDING) || !!(n.Qe & STATUS_PENDING) && quietPending(n);
|
|
3073
3085
|
}
|
|
3074
|
-
if (e.V !== NOT_PENDING && !(t.
|
|
3075
|
-
if (hasActiveOverride(e)) return !e.
|
|
3086
|
+
if (e.V !== NOT_PENDING && !(t.Qe & STATUS_UNINITIALIZED)) {
|
|
3087
|
+
if (hasActiveOverride(e)) return !e.At || !e.At(e.V, unwrapOverride(e.A));
|
|
3076
3088
|
return true;
|
|
3077
3089
|
}
|
|
3078
3090
|
return newQuestionInFlight(t);
|
|
3079
3091
|
}
|
|
3080
3092
|
|
|
3081
3093
|
function syncCompanions(e, t) {
|
|
3082
|
-
if (e.
|
|
3083
|
-
if (e.
|
|
3094
|
+
if (e.O) updatePendingSignal(e);
|
|
3095
|
+
if (e.p) setSignal(e.p, t);
|
|
3084
3096
|
}
|
|
3085
3097
|
|
|
3086
3098
|
function updatePendingSignal(e) {
|
|
3087
|
-
if (e.
|
|
3088
|
-
setSignal(e.
|
|
3099
|
+
if (e.O) {
|
|
3100
|
+
setSignal(e.O, computePendingState(e));
|
|
3089
3101
|
}
|
|
3090
|
-
if (e.
|
|
3102
|
+
if (e.p) updatePendingSignal(e.p);
|
|
3091
3103
|
}
|
|
3092
3104
|
|
|
3093
3105
|
function updateChildCompanions(e) {
|
|
3094
|
-
for (let t = e.
|
|
3095
|
-
if (t.
|
|
3106
|
+
for (let t = e.nt; t !== null; t = t.rt) {
|
|
3107
|
+
if (t.O || t.p) updatePendingSignal(t);
|
|
3096
3108
|
}
|
|
3097
3109
|
}
|
|
3098
3110
|
|
|
@@ -3110,9 +3122,9 @@ function updateChildCompanions(e) {
|
|
|
3110
3122
|
const visit = e => {
|
|
3111
3123
|
if (r.has(e)) return;
|
|
3112
3124
|
r.add(e);
|
|
3113
|
-
if (e.
|
|
3114
|
-
for (let t = e.
|
|
3115
|
-
for (let t = e.
|
|
3125
|
+
if (e.O || e.p) n(e);
|
|
3126
|
+
for (let t = e.U; t !== null; t = t.we) visit(t.Le);
|
|
3127
|
+
for (let t = e.nt ?? null; t !== null; t = t.rt) {
|
|
3116
3128
|
visit(t);
|
|
3117
3129
|
}
|
|
3118
3130
|
};
|
|
@@ -3120,21 +3132,21 @@ function updateChildCompanions(e) {
|
|
|
3120
3132
|
}
|
|
3121
3133
|
|
|
3122
3134
|
function snapCompanionsToState(e) {
|
|
3123
|
-
const t = e.
|
|
3135
|
+
const t = e.O;
|
|
3124
3136
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3125
3137
|
const n = computePendingState(e);
|
|
3126
|
-
if (t.
|
|
3127
|
-
t.
|
|
3138
|
+
if (t.ke !== n || t.V !== NOT_PENDING) {
|
|
3139
|
+
t.ke = n;
|
|
3128
3140
|
t.V = NOT_PENDING;
|
|
3129
|
-
t.
|
|
3141
|
+
t.W = clock;
|
|
3130
3142
|
insertSubs(t);
|
|
3131
3143
|
schedule();
|
|
3132
3144
|
}
|
|
3133
3145
|
}
|
|
3134
|
-
const n = e.
|
|
3135
|
-
if (n && !(n.
|
|
3136
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.V === NOT_PENDING && !Object.is(n.
|
|
3137
|
-
n.
|
|
3146
|
+
const n = e.p;
|
|
3147
|
+
if (n && !(n.Ge & REACTIVE_DISPOSED)) {
|
|
3148
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.V === NOT_PENDING && !Object.is(n.ke, e.ke) && !(n.Ge & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3149
|
+
n.Ge |= REACTIVE_DIRTY;
|
|
3138
3150
|
insertIntoHeap(n, queueFor(n));
|
|
3139
3151
|
insertSubs(n);
|
|
3140
3152
|
schedule();
|
|
@@ -3144,7 +3156,7 @@ function snapCompanionsToState(e) {
|
|
|
3144
3156
|
}
|
|
3145
3157
|
|
|
3146
3158
|
function getLatestValueComputed(e) {
|
|
3147
|
-
if (!e.
|
|
3159
|
+
if (!e.p) {
|
|
3148
3160
|
const t = latestReadActive;
|
|
3149
3161
|
setLatestReadActive(false);
|
|
3150
3162
|
const n = pendingCheckActive;
|
|
@@ -3152,21 +3164,21 @@ function getLatestValueComputed(e) {
|
|
|
3152
3164
|
const r = context;
|
|
3153
3165
|
setContextInternal(null);
|
|
3154
3166
|
// Detach from owner so it isn't disposed with effects
|
|
3155
|
-
e.
|
|
3156
|
-
e.
|
|
3167
|
+
e.p = optimisticComputed(() => read(e));
|
|
3168
|
+
e.p.t = e;
|
|
3157
3169
|
// Parent-child lane relationship
|
|
3158
3170
|
setContextInternal(r);
|
|
3159
3171
|
setPendingCheckActive(n);
|
|
3160
3172
|
setLatestReadActive(t);
|
|
3161
3173
|
}
|
|
3162
|
-
return e.
|
|
3174
|
+
return e.p;
|
|
3163
3175
|
}
|
|
3164
3176
|
|
|
3165
3177
|
/** The latest()-mode read path, installed as GlobalQueue._latestRead. */ function latestRead(e) {
|
|
3166
3178
|
const t = getLatestValueComputed(e);
|
|
3167
3179
|
const n = latestReadActive;
|
|
3168
3180
|
setLatestReadActive(false);
|
|
3169
|
-
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
3181
|
+
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.ke;
|
|
3170
3182
|
let i;
|
|
3171
3183
|
try {
|
|
3172
3184
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -3175,18 +3187,18 @@ function getLatestValueComputed(e) {
|
|
|
3175
3187
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3176
3188
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3177
3189
|
const e = queueFor(t);
|
|
3178
|
-
if (t.
|
|
3190
|
+
if (t.Xe >= e.P && !(t.Ge & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3179
3191
|
markHeap(e);
|
|
3180
3192
|
prepareComputed(t, true);
|
|
3181
3193
|
}
|
|
3182
3194
|
i = read(t);
|
|
3183
3195
|
} catch (t) {
|
|
3184
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3196
|
+
if (t instanceof NotReadyError && (!context || !(e.Qe & STATUS_UNINITIALIZED))) return r;
|
|
3185
3197
|
throw t;
|
|
3186
3198
|
} finally {
|
|
3187
3199
|
setLatestReadActive(n);
|
|
3188
3200
|
}
|
|
3189
|
-
if (t.
|
|
3201
|
+
if (t.Qe & STATUS_PENDING) return r;
|
|
3190
3202
|
if (stale && currentOptimisticLane && t.i) {
|
|
3191
3203
|
const e = findLane(t.i);
|
|
3192
3204
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3205,11 +3217,11 @@ function getLatestValueComputed(e) {
|
|
|
3205
3217
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3206
3218
|
setPendingCheckActive(false);
|
|
3207
3219
|
if (typeof e.Ve === "function") prepareComputed(e, true);
|
|
3208
|
-
const i = n.
|
|
3220
|
+
const i = n.Qe;
|
|
3209
3221
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3210
3222
|
if (tracking && e !== t) link(e, t);
|
|
3211
3223
|
setPendingCheckActive(true);
|
|
3212
|
-
throw n.
|
|
3224
|
+
throw n.De;
|
|
3213
3225
|
}
|
|
3214
3226
|
collectPendingSources(e);
|
|
3215
3227
|
if (r) collectPendingSources(r);
|
|
@@ -3221,10 +3233,10 @@ function recordFreshRead(e, t) {
|
|
|
3221
3233
|
}
|
|
3222
3234
|
|
|
3223
3235
|
function applyReask(e, t) {
|
|
3224
|
-
const n = !!(e.
|
|
3225
|
-
const r = t && !(n && !e.
|
|
3226
|
-
const i = n && e.
|
|
3227
|
-
e.
|
|
3236
|
+
const n = !!(e.Qe & STATUS_PENDING);
|
|
3237
|
+
const r = t && !(n && !e.ht);
|
|
3238
|
+
const i = n && e.ht !== r;
|
|
3239
|
+
e.ht = r;
|
|
3228
3240
|
return i;
|
|
3229
3241
|
}
|
|
3230
3242
|
|
|
@@ -3264,7 +3276,7 @@ function isPending(e) {
|
|
|
3264
3276
|
} catch (e) {
|
|
3265
3277
|
collectPending();
|
|
3266
3278
|
if (e instanceof NotReadyError) {
|
|
3267
|
-
const t = !!(e.source?.
|
|
3279
|
+
const t = !!(e.source?.Qe & STATUS_UNINITIALIZED);
|
|
3268
3280
|
if (r.found && !t) return true;
|
|
3269
3281
|
if (context && t) throw e;
|
|
3270
3282
|
}
|
|
@@ -3278,25 +3290,25 @@ function isPending(e) {
|
|
|
3278
3290
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3279
3291
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3280
3292
|
// direct calls used, so behavior is identical once this module loads.
|
|
3281
|
-
GlobalQueue.
|
|
3293
|
+
GlobalQueue.ue = syncCompanions;
|
|
3282
3294
|
|
|
3283
|
-
GlobalQueue.
|
|
3295
|
+
GlobalQueue.le = updatePendingSignal;
|
|
3284
3296
|
|
|
3285
|
-
GlobalQueue.
|
|
3297
|
+
GlobalQueue.ce = updateChildCompanions;
|
|
3286
3298
|
|
|
3287
|
-
GlobalQueue.
|
|
3299
|
+
GlobalQueue.ae = snapCompanionsToState;
|
|
3288
3300
|
|
|
3289
|
-
GlobalQueue.
|
|
3301
|
+
GlobalQueue.fe = latestRead;
|
|
3290
3302
|
|
|
3291
|
-
GlobalQueue.
|
|
3303
|
+
GlobalQueue.Ee = pendingCheckRead;
|
|
3292
3304
|
|
|
3293
3305
|
GlobalQueue.de = recordFreshRead;
|
|
3294
3306
|
|
|
3295
|
-
GlobalQueue.
|
|
3307
|
+
GlobalQueue.Se = applyReask;
|
|
3296
3308
|
|
|
3297
|
-
GlobalQueue.
|
|
3309
|
+
GlobalQueue.Te = repollDownstreamVerdicts;
|
|
3298
3310
|
|
|
3299
|
-
GlobalQueue.
|
|
3311
|
+
GlobalQueue._e = witnessAffects;
|
|
3300
3312
|
|
|
3301
3313
|
/**
|
|
3302
3314
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3306,16 +3318,16 @@ GlobalQueue.pe = witnessAffects;
|
|
|
3306
3318
|
const i = !!r?.user;
|
|
3307
3319
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3308
3320
|
recompute(o, true);
|
|
3309
|
-
!r?.defer && (o.
|
|
3321
|
+
!r?.defer && (o.Fe === EFFECT_USER || r?.schedule ? o.Be.enqueue(o.Fe, runEffect.bind(null, o)) : runEffect(o));
|
|
3310
3322
|
}
|
|
3311
3323
|
|
|
3312
3324
|
function notifyEffectStatus(e, t) {
|
|
3313
3325
|
// Use passed values if provided, otherwise read from node
|
|
3314
|
-
const n = e !== undefined ? e : this.
|
|
3315
|
-
const r = t !== undefined ? t : this.
|
|
3326
|
+
const n = e !== undefined ? e : this.Qe;
|
|
3327
|
+
const r = t !== undefined ? t : this.De;
|
|
3316
3328
|
if (n & STATUS_ERROR) {
|
|
3317
|
-
this.
|
|
3318
|
-
if (this.
|
|
3329
|
+
this.Be.notify(this, STATUS_PENDING, 0);
|
|
3330
|
+
if (this.Fe === EFFECT_USER) {
|
|
3319
3331
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3320
3332
|
// queue it like the effect function. It runs in the same imperative,
|
|
3321
3333
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3325,23 +3337,23 @@ function notifyEffectStatus(e, t) {
|
|
|
3325
3337
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3326
3338
|
// `status` arg without node-state writes) don't queue: the status
|
|
3327
3339
|
// re-propagates unblocked at commit.
|
|
3328
|
-
if (this.
|
|
3329
|
-
this.
|
|
3330
|
-
this.
|
|
3340
|
+
if (this.Qe & STATUS_ERROR) {
|
|
3341
|
+
this.xe = true;
|
|
3342
|
+
this.Be.enqueue(this.Fe, this.Pt ??= runEffect.bind(null, this));
|
|
3331
3343
|
}
|
|
3332
3344
|
return;
|
|
3333
3345
|
}
|
|
3334
|
-
if (!this.
|
|
3346
|
+
if (!this.Be.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3335
3347
|
haltReactivity(unwrapStatusError(r));
|
|
3336
3348
|
throw r;
|
|
3337
3349
|
}
|
|
3338
|
-
} else if (this.
|
|
3339
|
-
this.
|
|
3350
|
+
} else if (this.Fe === EFFECT_RENDER) {
|
|
3351
|
+
this.Be.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3340
3352
|
}
|
|
3341
3353
|
}
|
|
3342
3354
|
|
|
3343
3355
|
function runEffect(e) {
|
|
3344
|
-
if (!e.
|
|
3356
|
+
if (!e.xe || e.Ge & REACTIVE_DISPOSED) return;
|
|
3345
3357
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3346
3358
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3347
3359
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3352,46 +3364,46 @@ function runEffect(e) {
|
|
|
3352
3364
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3353
3365
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3354
3366
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3355
|
-
if (e.
|
|
3356
|
-
const t = unwrapStatusError(e.
|
|
3357
|
-
e.
|
|
3358
|
-
e.
|
|
3367
|
+
if (e.Qe & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3368
|
+
const t = unwrapStatusError(e.De);
|
|
3369
|
+
e.gt = e.ke;
|
|
3370
|
+
e.xe = false;
|
|
3359
3371
|
try {
|
|
3360
|
-
e.
|
|
3361
|
-
const t = e.
|
|
3362
|
-
e.
|
|
3372
|
+
e.Dt ? e.Dt(t, () => {
|
|
3373
|
+
const t = e.ft;
|
|
3374
|
+
e.ft = undefined;
|
|
3363
3375
|
t?.();
|
|
3364
3376
|
}) : console.error(t);
|
|
3365
3377
|
} catch (t) {
|
|
3366
|
-
if (!e.
|
|
3378
|
+
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3367
3379
|
haltReactivity(t);
|
|
3368
3380
|
throw t;
|
|
3369
3381
|
}
|
|
3370
3382
|
}
|
|
3371
3383
|
return;
|
|
3372
3384
|
}
|
|
3373
|
-
const t = e.
|
|
3374
|
-
e.
|
|
3385
|
+
const t = e.ft;
|
|
3386
|
+
e.ft = undefined;
|
|
3375
3387
|
try {
|
|
3376
3388
|
t?.();
|
|
3377
|
-
const n = e.
|
|
3389
|
+
const n = e.bt(e.ke, e.gt);
|
|
3378
3390
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3379
3391
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3380
|
-
e.
|
|
3392
|
+
e.ft = n;
|
|
3381
3393
|
} catch (t) {
|
|
3382
|
-
e.
|
|
3383
|
-
e.
|
|
3384
|
-
if (!e.
|
|
3394
|
+
e.De = new StatusError(e, t);
|
|
3395
|
+
e.Qe |= STATUS_ERROR;
|
|
3396
|
+
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3385
3397
|
haltReactivity(t);
|
|
3386
3398
|
throw t;
|
|
3387
3399
|
}
|
|
3388
3400
|
} finally {
|
|
3389
|
-
e.
|
|
3390
|
-
e.
|
|
3401
|
+
e.gt = e.ke;
|
|
3402
|
+
e.xe = false;
|
|
3391
3403
|
}
|
|
3392
3404
|
}
|
|
3393
3405
|
|
|
3394
|
-
GlobalQueue.
|
|
3406
|
+
GlobalQueue.J = runEffect;
|
|
3395
3407
|
|
|
3396
3408
|
/**
|
|
3397
3409
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3399,39 +3411,39 @@ GlobalQueue.ee = runEffect;
|
|
|
3399
3411
|
* Uses stale reads.
|
|
3400
3412
|
*/ function trackedEffect(e, t) {
|
|
3401
3413
|
const run = () => {
|
|
3402
|
-
if (!n.
|
|
3414
|
+
if (!n.xe || n.Ge & REACTIVE_DISPOSED) return;
|
|
3403
3415
|
try {
|
|
3404
|
-
n.
|
|
3416
|
+
n.xe = false;
|
|
3405
3417
|
recompute(n);
|
|
3406
3418
|
} finally {}
|
|
3407
3419
|
};
|
|
3408
3420
|
const n = computed(() => {
|
|
3409
|
-
const t = n.
|
|
3410
|
-
n.
|
|
3421
|
+
const t = n.ft;
|
|
3422
|
+
n.ft = undefined;
|
|
3411
3423
|
t?.();
|
|
3412
3424
|
const r = staleValues(e);
|
|
3413
|
-
n.
|
|
3425
|
+
n.ft = r;
|
|
3414
3426
|
}, {
|
|
3415
3427
|
...t,
|
|
3416
3428
|
lazy: true
|
|
3417
3429
|
});
|
|
3418
|
-
n.
|
|
3419
|
-
n.
|
|
3420
|
-
n.
|
|
3421
|
-
n.
|
|
3422
|
-
n.
|
|
3423
|
-
const r = e !== undefined ? e : n.
|
|
3430
|
+
n.ft = undefined;
|
|
3431
|
+
n.Ue = n.Ue & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3432
|
+
n.xe = true;
|
|
3433
|
+
n.Fe = EFFECT_TRACKED;
|
|
3434
|
+
n.Nt = (e, t) => {
|
|
3435
|
+
const r = e !== undefined ? e : n.Qe;
|
|
3424
3436
|
if (r & STATUS_ERROR) {
|
|
3425
|
-
n.
|
|
3426
|
-
const e = t !== undefined ? t : n.
|
|
3427
|
-
if (!n.
|
|
3437
|
+
n.Be.notify(n, STATUS_PENDING, 0);
|
|
3438
|
+
const e = t !== undefined ? t : n.De;
|
|
3439
|
+
if (!n.Be.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3428
3440
|
haltReactivity(unwrapStatusError(e));
|
|
3429
3441
|
throw e;
|
|
3430
3442
|
}
|
|
3431
3443
|
}
|
|
3432
3444
|
};
|
|
3433
|
-
n.
|
|
3434
|
-
n.
|
|
3445
|
+
n.Ze = run;
|
|
3446
|
+
n.Be.enqueue(EFFECT_USER, run);
|
|
3435
3447
|
}
|
|
3436
3448
|
|
|
3437
3449
|
function restoreTransition(e, t) {
|
|
@@ -3612,7 +3624,7 @@ function accessor(e) {
|
|
|
3612
3624
|
function createSignal(e, t) {
|
|
3613
3625
|
if (typeof e === "function") {
|
|
3614
3626
|
const n = computed(e, t);
|
|
3615
|
-
n.
|
|
3627
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3616
3628
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3617
3629
|
}
|
|
3618
3630
|
const n = signal(e, t);
|
|
@@ -3824,9 +3836,9 @@ function createEffect(e, t, n) {
|
|
|
3824
3836
|
// route through the inherited queue.
|
|
3825
3837
|
const i = getOwner();
|
|
3826
3838
|
const o = new MicrotaskQueue;
|
|
3827
|
-
o.
|
|
3839
|
+
o.B = i.Be;
|
|
3828
3840
|
// notify() forwards up the normal chain
|
|
3829
|
-
i.
|
|
3841
|
+
i.Be = o;
|
|
3830
3842
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
3831
3843
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
3832
3844
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -3853,7 +3865,7 @@ function createOptimistic(e, t) {
|
|
|
3853
3865
|
installOptimisticEngine();
|
|
3854
3866
|
if (typeof e === "function") {
|
|
3855
3867
|
const n = optimisticComputed(e, t);
|
|
3856
|
-
n.
|
|
3868
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
3857
3869
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3858
3870
|
}
|
|
3859
3871
|
const n = optimisticSignal(e, t);
|
|
@@ -3942,7 +3954,7 @@ function createOptimistic(e, t) {
|
|
|
3942
3954
|
* on owner disposal
|
|
3943
3955
|
*/ function onSettled(e) {
|
|
3944
3956
|
const t = getOwner();
|
|
3945
|
-
t && !(t.
|
|
3957
|
+
t && !(t.Ue & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3946
3958
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3947
3959
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3948
3960
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4096,9 +4108,9 @@ function applyArrayItem(e, t, n, r, i) {
|
|
|
4096
4108
|
if (!isWrappable(f)) continue;
|
|
4097
4109
|
const E = (u.get(f) ?? storeLookup.get(f))?.[$TARGET];
|
|
4098
4110
|
if (!E?.[STORE_DESC]) continue;
|
|
4099
|
-
const
|
|
4100
|
-
if (f ===
|
|
4101
|
-
applyState(
|
|
4111
|
+
const d = unwrap(t[a]);
|
|
4112
|
+
if (f === d || !isWrappable(d) || Array.isArray(f) !== Array.isArray(d) || i(f) != null && i(f) !== i(d)) continue;
|
|
4113
|
+
applyState(d, wrap(f, n), i);
|
|
4102
4114
|
}
|
|
4103
4115
|
}
|
|
4104
4116
|
|
|
@@ -4132,7 +4144,7 @@ function applyStateFast(e, t, n) {
|
|
|
4132
4144
|
let o = false;
|
|
4133
4145
|
const s = r.length;
|
|
4134
4146
|
if (e.length && s && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4135
|
-
let u, l, c, a, f, E,
|
|
4147
|
+
let u, l, c, a, f, E, d, S;
|
|
4136
4148
|
for (c = 0, a = Math.min(s, e.length); c < a && keyedMatch(E = r[c], e[c], n); c++) {
|
|
4137
4149
|
isWrappable(E) && isWrappable(e[c]) && applyState(e[c], wrap(E, t), n);
|
|
4138
4150
|
}
|
|
@@ -4155,22 +4167,22 @@ function applyStateFast(e, t, n) {
|
|
|
4155
4167
|
s !== e.length && i?.length && setSignal(i.length, e.length);
|
|
4156
4168
|
return;
|
|
4157
4169
|
}
|
|
4158
|
-
|
|
4170
|
+
d = new Array(f + 1);
|
|
4159
4171
|
for (l = f; l >= c; l--) {
|
|
4160
4172
|
E = e[l];
|
|
4161
|
-
|
|
4162
|
-
u = _.get(
|
|
4163
|
-
|
|
4164
|
-
_.set(
|
|
4173
|
+
S = itemKey(E, n);
|
|
4174
|
+
u = _.get(S);
|
|
4175
|
+
d[l] = u === undefined ? -1 : u;
|
|
4176
|
+
_.set(S, l);
|
|
4165
4177
|
}
|
|
4166
4178
|
for (u = c; u <= a; u++) {
|
|
4167
4179
|
E = r[u];
|
|
4168
|
-
|
|
4169
|
-
l = _.get(
|
|
4180
|
+
S = itemKey(E, n);
|
|
4181
|
+
l = _.get(S);
|
|
4170
4182
|
if (l !== undefined && l !== -1) {
|
|
4171
4183
|
T[l] = E;
|
|
4172
|
-
l =
|
|
4173
|
-
_.set(
|
|
4184
|
+
l = d[l];
|
|
4185
|
+
_.set(S, l);
|
|
4174
4186
|
}
|
|
4175
4187
|
}
|
|
4176
4188
|
for (l = c; l < e.length; l++) {
|
|
@@ -4201,17 +4213,18 @@ function applyStateFast(e, t, n) {
|
|
|
4201
4213
|
let s;
|
|
4202
4214
|
if (o) {
|
|
4203
4215
|
s = o[$TRACK];
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4216
|
+
if (s || symbolKeyedRecords.has(o)) {
|
|
4217
|
+
const i = s ? getAllKeys(r, undefined, e) : nodeKeys(o);
|
|
4218
|
+
for (let u = 0, l = i.length; u < l; u++) {
|
|
4219
|
+
diffNodeKey(i[u], o, r, e, t, s, n);
|
|
4220
|
+
}
|
|
4221
|
+
} else {
|
|
4222
|
+
// Untracked, string-only node records (the overwhelmingly common case)
|
|
4223
|
+
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
4224
|
+
// per pass, which dominates allocation on large-graph reconciles.
|
|
4225
|
+
for (const i in o) {
|
|
4226
|
+
diffNodeKey(i, o, r, e, t, s, n);
|
|
4227
|
+
}
|
|
4215
4228
|
}
|
|
4216
4229
|
}
|
|
4217
4230
|
if (!s && t[STORE_DESC]) applyDescendants(r, e, t, o, n);
|
|
@@ -4225,6 +4238,19 @@ function applyStateFast(e, t, n) {
|
|
|
4225
4238
|
}
|
|
4226
4239
|
}
|
|
4227
4240
|
|
|
4241
|
+
// One node-key step of the fast object diff — shared by the array-iterating
|
|
4242
|
+
// (tracked / symbol-keyed) and for-in (plain) loops in applyStateFast.
|
|
4243
|
+
function diffNodeKey(e, t, n, r, i, o, s) {
|
|
4244
|
+
const u = t[e];
|
|
4245
|
+
const l = unwrap(n[e]);
|
|
4246
|
+
let c = unwrap(r[e]);
|
|
4247
|
+
if (l === c) return;
|
|
4248
|
+
if (!l || !isWrappable(l) || !isWrappable(c) || Array.isArray(l) !== Array.isArray(c) || s(l) != null && s(l) !== s(c)) {
|
|
4249
|
+
o && setSignal(o, void 0);
|
|
4250
|
+
u && setSignal(u, isWrappable(c) ? wrap(c, i) : c);
|
|
4251
|
+
} else applyState(c, wrap(l, i), s);
|
|
4252
|
+
}
|
|
4253
|
+
|
|
4228
4254
|
function applyStateSlow(e, t, n) {
|
|
4229
4255
|
const r = t[STORE_VALUE];
|
|
4230
4256
|
const i = t[STORE_OVERRIDE];
|
|
@@ -4239,23 +4265,23 @@ function applyStateSlow(e, t, n) {
|
|
|
4239
4265
|
let u = false;
|
|
4240
4266
|
const l = getOverrideValue(r, i, "length", o);
|
|
4241
4267
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4242
|
-
let c, a, f, E,
|
|
4243
|
-
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(
|
|
4244
|
-
isWrappable(
|
|
4268
|
+
let c, a, f, E, d, S, T, _;
|
|
4269
|
+
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4270
|
+
isWrappable(S) && isWrappable(e[f]) && applyState(e[f], wrap(S, t), n);
|
|
4245
4271
|
}
|
|
4246
|
-
const
|
|
4247
|
-
for (E = l - 1,
|
|
4248
|
-
|
|
4249
|
-
|
|
4272
|
+
const O = new Array(e.length), p = new Map;
|
|
4273
|
+
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4274
|
+
d--) {
|
|
4275
|
+
O[d] = S;
|
|
4250
4276
|
}
|
|
4251
|
-
if (f >
|
|
4252
|
-
for (a = f; a <=
|
|
4277
|
+
if (f > d || f > E) {
|
|
4278
|
+
for (a = f; a <= d; a++) {
|
|
4253
4279
|
u = true;
|
|
4254
4280
|
s?.[a] && setSignal(s[a], wrapValue(e[a], t));
|
|
4255
4281
|
}
|
|
4256
4282
|
for (;a < e.length; a++) {
|
|
4257
4283
|
u = true;
|
|
4258
|
-
applyArrayItem(e[a],
|
|
4284
|
+
applyArrayItem(e[a], O[a], t, s?.[a], n);
|
|
4259
4285
|
}
|
|
4260
4286
|
const r = e.length;
|
|
4261
4287
|
syncArrayNodeMembership(t, e);
|
|
@@ -4263,27 +4289,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4263
4289
|
l !== r && s?.length && setSignal(s.length, r);
|
|
4264
4290
|
return;
|
|
4265
4291
|
}
|
|
4266
|
-
T = new Array(
|
|
4267
|
-
for (a =
|
|
4268
|
-
|
|
4269
|
-
_ = itemKey(
|
|
4270
|
-
c =
|
|
4292
|
+
T = new Array(d + 1);
|
|
4293
|
+
for (a = d; a >= f; a--) {
|
|
4294
|
+
S = e[a];
|
|
4295
|
+
_ = itemKey(S, n);
|
|
4296
|
+
c = p.get(_);
|
|
4271
4297
|
T[a] = c === undefined ? -1 : c;
|
|
4272
|
-
|
|
4298
|
+
p.set(_, a);
|
|
4273
4299
|
}
|
|
4274
4300
|
for (c = f; c <= E; c++) {
|
|
4275
|
-
|
|
4276
|
-
_ = itemKey(
|
|
4277
|
-
a =
|
|
4301
|
+
S = getOverrideValue(r, i, c, o);
|
|
4302
|
+
_ = itemKey(S, n);
|
|
4303
|
+
a = p.get(_);
|
|
4278
4304
|
if (a !== undefined && a !== -1) {
|
|
4279
|
-
|
|
4305
|
+
O[a] = S;
|
|
4280
4306
|
a = T[a];
|
|
4281
|
-
|
|
4307
|
+
p.set(_, a);
|
|
4282
4308
|
}
|
|
4283
4309
|
}
|
|
4284
4310
|
for (a = f; a < e.length; a++) {
|
|
4285
|
-
if (a in
|
|
4286
|
-
applyArrayItem(e[a],
|
|
4311
|
+
if (a in O) {
|
|
4312
|
+
applyArrayItem(e[a], O[a], t, s?.[a], n);
|
|
4287
4313
|
} else s?.[a] && setSignal(s[a], wrapValue(e[a], t));
|
|
4288
4314
|
}
|
|
4289
4315
|
if (f < e.length) u = true;
|
|
@@ -4314,12 +4340,12 @@ function applyStateSlow(e, t, n) {
|
|
|
4314
4340
|
const a = l[c];
|
|
4315
4341
|
const f = s[a];
|
|
4316
4342
|
const E = unwrap(getOverrideValue(r, i, a, o));
|
|
4317
|
-
let
|
|
4318
|
-
if (E ===
|
|
4319
|
-
if (!E || !isWrappable(E) || !isWrappable(
|
|
4343
|
+
let d = unwrap(e[a]);
|
|
4344
|
+
if (E === d) continue;
|
|
4345
|
+
if (!E || !isWrappable(E) || !isWrappable(d) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4320
4346
|
u && setSignal(u, void 0);
|
|
4321
|
-
f && setSignal(f, isWrappable(
|
|
4322
|
-
} else applyState(
|
|
4347
|
+
f && setSignal(f, isWrappable(d) ? wrap(d, t) : d);
|
|
4348
|
+
} else applyState(d, wrap(E, t), n);
|
|
4323
4349
|
}
|
|
4324
4350
|
}
|
|
4325
4351
|
if (!u && t[STORE_DESC]) applyDescendants(r, e, t, s, n, i, o);
|
|
@@ -4333,17 +4359,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4333
4359
|
}
|
|
4334
4360
|
}
|
|
4335
4361
|
|
|
4362
|
+
// No-key reconcile: every item reports "no key", which routes array diffs to
|
|
4363
|
+
// the positional branch and object descent to plain per-property merging.
|
|
4364
|
+
const NOKEY = () => null;
|
|
4365
|
+
|
|
4336
4366
|
/**
|
|
4337
4367
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
4338
|
-
* preserving
|
|
4339
|
-
*
|
|
4340
|
-
*
|
|
4368
|
+
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
4369
|
+
*
|
|
4370
|
+
* With a `key` (default `"id"`), array items whose key matches between old
|
|
4371
|
+
* and new states keep their identity (updated in place, moves and removals
|
|
4372
|
+
* update the corresponding signals) — the shape for keyed server payloads.
|
|
4373
|
+
* Items without the key field fall back to positional matching.
|
|
4341
4374
|
*
|
|
4342
|
-
*
|
|
4343
|
-
*
|
|
4375
|
+
* With `key: null`, matching is purely positional: index N of the new array
|
|
4376
|
+
* merges into index N of the old, and object properties merge recursively —
|
|
4377
|
+
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
4378
|
+
* monitors), where no keyed diff pass is needed or wanted.
|
|
4344
4379
|
*
|
|
4345
4380
|
* @param value the next state to merge in
|
|
4346
|
-
* @param key property name (string) or extractor function for stable
|
|
4381
|
+
* @param key property name (string) or extractor function for stable
|
|
4382
|
+
* identity (default `"id"`); pass `null` for positional merging
|
|
4347
4383
|
*
|
|
4348
4384
|
* @example
|
|
4349
4385
|
* ```ts
|
|
@@ -4351,12 +4387,19 @@ function applyStateSlow(e, t, n) {
|
|
|
4351
4387
|
*
|
|
4352
4388
|
* async function refresh() {
|
|
4353
4389
|
* const fresh = await api.getTodos();
|
|
4354
|
-
* setTodos(reconcile(fresh
|
|
4390
|
+
* setTodos(reconcile(fresh)); // diff-merge by `id`
|
|
4355
4391
|
* }
|
|
4392
|
+
*
|
|
4393
|
+
* // fixed-shape polling data — positional merge
|
|
4394
|
+
* setStats(reconcile(nextStats, null));
|
|
4356
4395
|
* ```
|
|
4357
|
-
*/ function reconcile(e, t) {
|
|
4396
|
+
*/ function reconcile(e, t = "id") {
|
|
4358
4397
|
return n => {
|
|
4359
4398
|
if (n == null) throw new Error("");
|
|
4399
|
+
if (t === null) {
|
|
4400
|
+
applyState(e, n, NOKEY);
|
|
4401
|
+
return;
|
|
4402
|
+
}
|
|
4360
4403
|
const r = typeof t === "string" ? e => e[t] : t;
|
|
4361
4404
|
const i = r(n);
|
|
4362
4405
|
if (i !== undefined && r(e) !== i) throw new Error("");
|
|
@@ -4389,7 +4432,7 @@ function createProjectionInternal(e, t, n) {
|
|
|
4389
4432
|
if (!r) r = getOwner();
|
|
4390
4433
|
runProjectionComputed(o, e, n?.key || "id");
|
|
4391
4434
|
}, undefined);
|
|
4392
|
-
r.
|
|
4435
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
4393
4436
|
return {
|
|
4394
4437
|
store: o,
|
|
4395
4438
|
node: r
|
|
@@ -4458,7 +4501,7 @@ function createProjectionInternal(e, t, n) {
|
|
|
4458
4501
|
const o = getOwner();
|
|
4459
4502
|
let s = false;
|
|
4460
4503
|
let u;
|
|
4461
|
-
const l = new Proxy(e, createWriteTraps(() => !s || o.
|
|
4504
|
+
const l = new Proxy(e, createWriteTraps(() => !s || o.ut === u, i));
|
|
4462
4505
|
storeSetter(l, i => {
|
|
4463
4506
|
u = t(i);
|
|
4464
4507
|
s = true;
|
|
@@ -4543,15 +4586,40 @@ const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
|
4543
4586
|
|
|
4544
4587
|
const STORE_SELF_PENDING = Symbol(0);
|
|
4545
4588
|
|
|
4589
|
+
// Every StoreNode field is initialized up front, in one fixed order, so all
|
|
4590
|
+
// targets share a single hidden class. The traps and reconcile read these
|
|
4591
|
+
// fields on their hottest paths; fields added lazily in varying orders made
|
|
4592
|
+
// those loads megamorphic across a large store graph (dictionary-mode probes
|
|
4593
|
+
// on every trap hit). Assignments elsewhere must never `delete` a field —
|
|
4594
|
+
// write `undefined` instead, or the shape degrades again.
|
|
4595
|
+
function initStoreFields(e) {
|
|
4596
|
+
e[STORE_OVERRIDE] = undefined;
|
|
4597
|
+
e[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
4598
|
+
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
4599
|
+
e[STORE_NODE] = undefined;
|
|
4600
|
+
e[STORE_HAS] = undefined;
|
|
4601
|
+
e[STORE_CUSTOM_PROTO] = undefined;
|
|
4602
|
+
e[STORE_WRAP] = undefined;
|
|
4603
|
+
e[STORE_LOOKUP] = undefined;
|
|
4604
|
+
e[STORE_FIREWALL] = undefined;
|
|
4605
|
+
e[STORE_OPTIMISTIC] = undefined;
|
|
4606
|
+
e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
4607
|
+
e[STORE_PARENT] = undefined;
|
|
4608
|
+
e[STORE_DESC] = undefined;
|
|
4609
|
+
e[$PROXY] = null;
|
|
4610
|
+
}
|
|
4611
|
+
|
|
4546
4612
|
function createStoreProxy(e, t = storeTraps, n) {
|
|
4547
4613
|
let r;
|
|
4548
4614
|
if (Array.isArray(e)) {
|
|
4549
4615
|
r = [];
|
|
4550
|
-
r
|
|
4616
|
+
r[STORE_VALUE] = e;
|
|
4617
|
+
initStoreFields(r);
|
|
4551
4618
|
} else {
|
|
4552
4619
|
r = {
|
|
4553
|
-
|
|
4620
|
+
[STORE_VALUE]: e
|
|
4554
4621
|
};
|
|
4622
|
+
initStoreFields(r);
|
|
4555
4623
|
const t = e?.[$TARGET]?.[STORE_VALUE] ?? e;
|
|
4556
4624
|
const n = Object.getPrototypeOf(t);
|
|
4557
4625
|
if (n !== null && n !== Object.prototype) {
|
|
@@ -4665,7 +4733,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
4665
4733
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
4666
4734
|
* override, else held pending value, else committed value.
|
|
4667
4735
|
*/ function visibleNodeValue(e) {
|
|
4668
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.V !== NOT_PENDING ? e.V : e.
|
|
4736
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.V !== NOT_PENDING ? e.V : e.ke;
|
|
4669
4737
|
}
|
|
4670
4738
|
|
|
4671
4739
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -4720,7 +4788,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4720
4788
|
}
|
|
4721
4789
|
if (o && n in o) {
|
|
4722
4790
|
const e = o[n];
|
|
4723
|
-
s.
|
|
4791
|
+
s.ve = e === undefined ? NO_SNAPSHOT : e;
|
|
4724
4792
|
snapshotSources?.add(s);
|
|
4725
4793
|
}
|
|
4726
4794
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -4749,8 +4817,8 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4749
4817
|
*/ function inheritAffectsMarks(e, t, n) {
|
|
4750
4818
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
4751
4819
|
for (const [r, i] of affectsScopes) {
|
|
4752
|
-
if (r.
|
|
4753
|
-
GlobalQueue.
|
|
4820
|
+
if (r.k && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
4821
|
+
GlobalQueue.re(e);
|
|
4754
4822
|
i.inherited.push(e);
|
|
4755
4823
|
}
|
|
4756
4824
|
}
|
|
@@ -4838,11 +4906,11 @@ i) {
|
|
|
4838
4906
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
4839
4907
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
4840
4908
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
4841
|
-
if (n?.
|
|
4909
|
+
if (n?.k) GlobalQueue._e(n);
|
|
4842
4910
|
if (affectsScopes.size) {
|
|
4843
4911
|
const r = e[STORE_VALUE];
|
|
4844
4912
|
for (const [e, i] of affectsScopes) {
|
|
4845
|
-
if (e !== n && e.
|
|
4913
|
+
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue._e(e);
|
|
4846
4914
|
}
|
|
4847
4915
|
}
|
|
4848
4916
|
}
|
|
@@ -4859,11 +4927,11 @@ i) {
|
|
|
4859
4927
|
* @internal
|
|
4860
4928
|
*/ function getStoreAffectsNodes(e, t) {
|
|
4861
4929
|
const n = getNodes(e, STORE_NODE);
|
|
4862
|
-
GlobalQueue.
|
|
4930
|
+
GlobalQueue.te ||= e => {
|
|
4863
4931
|
const t = affectsScopes.get(e);
|
|
4864
4932
|
if (!t) return;
|
|
4865
4933
|
affectsScopes.delete(e);
|
|
4866
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
4934
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.ie(t.inherited[e]);
|
|
4867
4935
|
};
|
|
4868
4936
|
if (t === undefined) {
|
|
4869
4937
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -4990,7 +5058,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
4990
5058
|
}
|
|
4991
5059
|
const r = e[STORE_VALUE];
|
|
4992
5060
|
const i = r[n];
|
|
4993
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5061
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.Qe ?? 0) & STATUS_PENDING)) {
|
|
4994
5062
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
4995
5063
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
4996
5064
|
snapshotSources?.add(e);
|
|
@@ -5018,7 +5086,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5018
5086
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5019
5087
|
// optimistic engine before wrapping.
|
|
5020
5088
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5021
|
-
GlobalQueue.
|
|
5089
|
+
GlobalQueue.be(t);
|
|
5022
5090
|
}
|
|
5023
5091
|
}
|
|
5024
5092
|
|
|
@@ -5091,7 +5159,7 @@ let Writing = null;
|
|
|
5091
5159
|
* itself (the derive function works its own draft while uninitialized).
|
|
5092
5160
|
*/ function throwIfUninitialized(e) {
|
|
5093
5161
|
const t = e[STORE_FIREWALL];
|
|
5094
|
-
if (t && t.
|
|
5162
|
+
if (t && t.Qe & STATUS_UNINITIALIZED) throw t.De ?? new NotReadyError(t);
|
|
5095
5163
|
}
|
|
5096
5164
|
|
|
5097
5165
|
const storeTraps = {
|
|
@@ -5104,6 +5172,21 @@ const storeTraps = {
|
|
|
5104
5172
|
trackSelf(e);
|
|
5105
5173
|
return n;
|
|
5106
5174
|
}
|
|
5175
|
+
// Hot path: an existing node on a plain target — no firewall (so neither
|
|
5176
|
+
// selfRead nor the uninitialized guard can apply), no override layers,
|
|
5177
|
+
// no write scope, and a raw (non-proxy) source. This is the shape of
|
|
5178
|
+
// every effect re-read of a settled store; it pays one node read and the
|
|
5179
|
+
// wrap check, nothing else. Any exotic bit falls through to the full
|
|
5180
|
+
// resolution below, and dev strictRead keeps its warning path.
|
|
5181
|
+
if (e[STORE_FIREWALL] === undefined && e[STORE_OVERRIDE] === undefined && e[STORE_OPTIMISTIC_OVERRIDE] === undefined && !writeOverride && (Writing === null || !Writing.has(n))) {
|
|
5182
|
+
const n = e[STORE_NODE];
|
|
5183
|
+
const r = n && n[t];
|
|
5184
|
+
if (r !== undefined && e[STORE_VALUE][$TARGET] === undefined) {
|
|
5185
|
+
let t = read(r);
|
|
5186
|
+
if (t === $DELETED) t = undefined;
|
|
5187
|
+
return isWrappable(t) ? wrap(t, e) : t;
|
|
5188
|
+
}
|
|
5189
|
+
}
|
|
5107
5190
|
const r = getObserver() === e[STORE_FIREWALL];
|
|
5108
5191
|
const i = getNodes(e, STORE_NODE);
|
|
5109
5192
|
const o = r ? undefined : i[t];
|
|
@@ -5184,9 +5267,9 @@ const storeTraps = {
|
|
|
5184
5267
|
// throws). #2769
|
|
5185
5268
|
const f = typeof t === "string" ? Number(t) : -1;
|
|
5186
5269
|
const E = Array.isArray(s) && Number.isInteger(f) && f >= 0 && f < 4294967295 && String(f) === t;
|
|
5187
|
-
const
|
|
5188
|
-
const
|
|
5189
|
-
const T = E &&
|
|
5270
|
+
const d = E ? f + 1 : 0;
|
|
5271
|
+
const S = E && (getOverlayLayer(e, "length") ?? s).length;
|
|
5272
|
+
const T = E && d > S ? d : undefined;
|
|
5190
5273
|
if (l === a && T === undefined) return true;
|
|
5191
5274
|
armOptimisticStoreWrite(e, r);
|
|
5192
5275
|
if (a !== undefined && a === i && T === undefined) {
|
|
@@ -5222,7 +5305,7 @@ const storeTraps = {
|
|
|
5222
5305
|
if (t.length) {
|
|
5223
5306
|
setSignal(t.length, T);
|
|
5224
5307
|
} else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
|
|
5225
|
-
const n = upsertStoreNode(e, t, "length",
|
|
5308
|
+
const n = upsertStoreNode(e, t, "length", S, e[STORE_SNAPSHOT_PROPS]);
|
|
5226
5309
|
setSignal(n, T);
|
|
5227
5310
|
}
|
|
5228
5311
|
}
|
|
@@ -5386,7 +5469,7 @@ function createStore(e, t, n) {
|
|
|
5386
5469
|
* nothing is stored downstream and nothing can be stranded or stripped by
|
|
5387
5470
|
* mid-window recomputes.
|
|
5388
5471
|
*/ function markAffects(e) {
|
|
5389
|
-
e.
|
|
5472
|
+
e.k = (e.k || 0) + 1;
|
|
5390
5473
|
shiftAffectsMarks(1);
|
|
5391
5474
|
}
|
|
5392
5475
|
|
|
@@ -5402,17 +5485,17 @@ function createStore(e, t, n) {
|
|
|
5402
5485
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5403
5486
|
* no visual change.
|
|
5404
5487
|
*/ function notifyMarkBoundaries(e) {
|
|
5405
|
-
if (!e.
|
|
5488
|
+
if (!e.U && !e.nt) return;
|
|
5406
5489
|
const t = new NotReadyError(e);
|
|
5407
|
-
t.
|
|
5490
|
+
t.me = true;
|
|
5408
5491
|
const n = new Set;
|
|
5409
5492
|
const visit = e => {
|
|
5410
5493
|
if (n.has(e)) return;
|
|
5411
5494
|
n.add(e);
|
|
5412
5495
|
// Display consumers (render effects, boundary computeds) act on the
|
|
5413
5496
|
// notification; descent stops there, exactly like the status rails.
|
|
5414
|
-
if (e.
|
|
5415
|
-
e.
|
|
5497
|
+
if (e.Nt) {
|
|
5498
|
+
e.Nt(STATUS_PENDING, t);
|
|
5416
5499
|
return;
|
|
5417
5500
|
}
|
|
5418
5501
|
forEachDependent(e, visit);
|
|
@@ -5430,10 +5513,10 @@ function createStore(e, t, n) {
|
|
|
5430
5513
|
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
5431
5514
|
*/ function registerAffectsMark(e) {
|
|
5432
5515
|
markAffects(e);
|
|
5433
|
-
globalQueue.D.
|
|
5516
|
+
globalQueue.D.G.push(e);
|
|
5434
5517
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5435
5518
|
// without them there is no materialized verdict to poke.
|
|
5436
|
-
GlobalQueue.
|
|
5519
|
+
GlobalQueue.Te !== null && GlobalQueue.Te(e);
|
|
5437
5520
|
notifyMarkBoundaries(e);
|
|
5438
5521
|
schedule();
|
|
5439
5522
|
}
|
|
@@ -5445,10 +5528,10 @@ function createStore(e, t, n) {
|
|
|
5445
5528
|
* setSignal would open a fresh override window that nothing settles).
|
|
5446
5529
|
*/ function releaseAffectsMark(e) {
|
|
5447
5530
|
shiftAffectsMarks(-1);
|
|
5448
|
-
e.
|
|
5449
|
-
if (!e.
|
|
5450
|
-
GlobalQueue.
|
|
5451
|
-
GlobalQueue.
|
|
5531
|
+
e.k--;
|
|
5532
|
+
if (!e.k) {
|
|
5533
|
+
GlobalQueue.Te !== null && GlobalQueue.Te(e, true);
|
|
5534
|
+
GlobalQueue.te?.(e);
|
|
5452
5535
|
}
|
|
5453
5536
|
}
|
|
5454
5537
|
|
|
@@ -5465,11 +5548,11 @@ function createStore(e, t, n) {
|
|
|
5465
5548
|
// Each call site is gated by state only this module creates (a non-empty
|
|
5466
5549
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
5467
5550
|
// hooks are installed before the first time any of them can fire.
|
|
5468
|
-
GlobalQueue.
|
|
5551
|
+
GlobalQueue.ne = releaseAffectsMarks;
|
|
5469
5552
|
|
|
5470
|
-
GlobalQueue.
|
|
5553
|
+
GlobalQueue.re = markAffects;
|
|
5471
5554
|
|
|
5472
|
-
GlobalQueue.
|
|
5555
|
+
GlobalQueue.ie = releaseAffectsMark;
|
|
5473
5556
|
|
|
5474
5557
|
function affects(e, t) {
|
|
5475
5558
|
const n = e?.[$TARGET];
|
|
@@ -5490,7 +5573,7 @@ function createOptimisticStore(e, t, n) {
|
|
|
5490
5573
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
5491
5574
|
// node can be created.
|
|
5492
5575
|
installOptimisticEngine();
|
|
5493
|
-
GlobalQueue.
|
|
5576
|
+
GlobalQueue.ee ||= clearOptimisticStores;
|
|
5494
5577
|
const r = typeof e === "function";
|
|
5495
5578
|
const i = r ? t : e;
|
|
5496
5579
|
const o = r ? e : undefined;
|
|
@@ -5569,16 +5652,18 @@ function clearOptimisticStores(e, t) {
|
|
|
5569
5652
|
c.A = NOT_PENDING;
|
|
5570
5653
|
c.R = null;
|
|
5571
5654
|
c.V = NOT_PENDING;
|
|
5572
|
-
c.
|
|
5573
|
-
if (!c.
|
|
5655
|
+
c.ke = i;
|
|
5656
|
+
if (!c.At || !c.At(o, i)) {
|
|
5574
5657
|
insertSubs(c, true);
|
|
5575
5658
|
schedule();
|
|
5576
5659
|
}
|
|
5577
5660
|
}
|
|
5578
5661
|
}
|
|
5579
5662
|
if (!u) {
|
|
5580
|
-
delete
|
|
5581
|
-
delete
|
|
5663
|
+
// Assignment, not delete: StoreNode targets share one pre-initialized
|
|
5664
|
+
// hidden class (see createStoreProxy) and a delete would demote it.
|
|
5665
|
+
e[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
5666
|
+
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
5582
5667
|
}
|
|
5583
5668
|
// Notify $TRACK
|
|
5584
5669
|
if (s && r?.[$TRACK]) {
|
|
@@ -5642,7 +5727,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5642
5727
|
setProjectionWriteActive(false);
|
|
5643
5728
|
}
|
|
5644
5729
|
}, undefined);
|
|
5645
|
-
r.
|
|
5730
|
+
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
5646
5731
|
}
|
|
5647
5732
|
return {
|
|
5648
5733
|
store: o,
|
|
@@ -5763,6 +5848,18 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5763
5848
|
if (pendingCheckActive) witnessAffectsMark(i);
|
|
5764
5849
|
}
|
|
5765
5850
|
s = mergedOverlay(i);
|
|
5851
|
+
// A derived store's STORE_VALUE is the inner store's live proxy
|
|
5852
|
+
// (store-in-store: createOptimisticStore/createProjection over a store).
|
|
5853
|
+
// Without an overlay of its own, the fast path below would map to — and
|
|
5854
|
+
// could return — that proxy verbatim. Recurse instead so the
|
|
5855
|
+
// inner store's own target branch unwraps it (chains of any depth).
|
|
5856
|
+
// With an overlay, a fresh `result` is always built, so the walk over the
|
|
5857
|
+
// inner proxy already copies plain values.
|
|
5858
|
+
if (!s && i[STORE_VALUE][$TARGET]) {
|
|
5859
|
+
l = snapshotImpl(i[STORE_VALUE], t, n, r);
|
|
5860
|
+
n.set(e, l);
|
|
5861
|
+
return l;
|
|
5862
|
+
}
|
|
5766
5863
|
o = Array.isArray(i[STORE_VALUE]);
|
|
5767
5864
|
n.set(e, s ? u = o ? [] : Object.create(Object.getPrototypeOf(i[STORE_VALUE])) : i[STORE_VALUE]);
|
|
5768
5865
|
e = i[STORE_VALUE];
|
|
@@ -6054,24 +6151,24 @@ function mapArray(e, t, n) {
|
|
|
6054
6151
|
const i = t.length > 1;
|
|
6055
6152
|
const o = t;
|
|
6056
6153
|
const s = {
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6154
|
+
vt: createOwner(),
|
|
6155
|
+
wt: 0,
|
|
6156
|
+
Gt: e,
|
|
6157
|
+
Lt: [],
|
|
6158
|
+
Ut: o,
|
|
6062
6159
|
Vt: [],
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6160
|
+
kt: [],
|
|
6161
|
+
Ft: r,
|
|
6162
|
+
xt: r || n?.keyed === false ? [] : undefined,
|
|
6163
|
+
Qt: i && n?.keyed !== false ? [] : undefined,
|
|
6164
|
+
Wt: n?.keyed === false,
|
|
6165
|
+
Mt: n?.fallback
|
|
6069
6166
|
};
|
|
6070
6167
|
const u = computed(updateKeyedMap.bind(s));
|
|
6071
6168
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6072
6169
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6073
|
-
s.
|
|
6074
|
-
u.
|
|
6170
|
+
s.vt.Je = u;
|
|
6171
|
+
u.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6075
6172
|
return accessor(u);
|
|
6076
6173
|
}
|
|
6077
6174
|
|
|
@@ -6089,52 +6186,52 @@ const pureOptions = {
|
|
|
6089
6186
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6090
6187
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6091
6188
|
function updateKeyedMap() {
|
|
6092
|
-
const e = this.
|
|
6189
|
+
const e = this.Gt() || [], t = e.length;
|
|
6093
6190
|
e[$TRACK];
|
|
6094
6191
|
// top level tracking
|
|
6095
|
-
runWithOwner(this.
|
|
6192
|
+
runWithOwner(this.vt, () => {
|
|
6096
6193
|
let n, r, i, o,
|
|
6097
6194
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6098
6195
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6099
|
-
s = this.
|
|
6196
|
+
s = this.xt ? this.Wt ? () => {
|
|
6100
6197
|
i[r] = signal(e[r], pureOptions);
|
|
6101
|
-
return this.
|
|
6198
|
+
return this.Ut(accessor(i[r]), r);
|
|
6102
6199
|
} : () => {
|
|
6103
6200
|
i[r] = signal(e[r], pureOptions);
|
|
6104
6201
|
o && (o[r] = signal(r, pureOptions));
|
|
6105
|
-
return this.
|
|
6106
|
-
} : this.
|
|
6202
|
+
return this.Ut(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6203
|
+
} : this.Qt ? () => {
|
|
6107
6204
|
const t = e[r];
|
|
6108
6205
|
o[r] = signal(r, pureOptions);
|
|
6109
|
-
return this.
|
|
6206
|
+
return this.Ut(t, accessor(o[r]));
|
|
6110
6207
|
} : () => {
|
|
6111
6208
|
const t = e[r];
|
|
6112
|
-
return this.
|
|
6209
|
+
return this.Ut(t);
|
|
6113
6210
|
};
|
|
6114
6211
|
// fast path for empty arrays
|
|
6115
6212
|
if (t === 0) {
|
|
6116
|
-
if (this.
|
|
6117
|
-
this.
|
|
6118
|
-
this.
|
|
6119
|
-
this.
|
|
6213
|
+
if (this.wt !== 0) {
|
|
6214
|
+
this.vt.dispose(false);
|
|
6215
|
+
this.kt = [];
|
|
6216
|
+
this.Lt = [];
|
|
6120
6217
|
this.Vt = [];
|
|
6121
|
-
this.
|
|
6122
|
-
this.
|
|
6123
|
-
this.
|
|
6218
|
+
this.wt = 0;
|
|
6219
|
+
this.xt && (this.xt = []);
|
|
6220
|
+
this.Qt && (this.Qt = []);
|
|
6124
6221
|
}
|
|
6125
|
-
if (this.
|
|
6222
|
+
if (this.Mt && !this.Vt[0]) {
|
|
6126
6223
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6127
6224
|
// dispose it before re-creating
|
|
6128
|
-
this.
|
|
6129
|
-
this.Vt[0] = runWithOwner(this.
|
|
6225
|
+
this.kt[0]?.dispose();
|
|
6226
|
+
this.Vt[0] = runWithOwner(this.kt[0] = createOwner(), this.Mt);
|
|
6130
6227
|
}
|
|
6131
6228
|
}
|
|
6132
6229
|
// fast path for new create
|
|
6133
|
-
else if (this.
|
|
6230
|
+
else if (this.wt === 0) {
|
|
6134
6231
|
const u = new Array(t);
|
|
6135
6232
|
const l = new Array(t);
|
|
6136
|
-
i = this.
|
|
6137
|
-
o = this.
|
|
6233
|
+
i = this.xt && new Array(t);
|
|
6234
|
+
o = this.Qt && new Array(t);
|
|
6138
6235
|
try {
|
|
6139
6236
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6140
6237
|
} catch (e) {
|
|
@@ -6142,83 +6239,107 @@ function updateKeyedMap() {
|
|
|
6142
6239
|
throw e;
|
|
6143
6240
|
}
|
|
6144
6241
|
// commit
|
|
6145
|
-
if (this.
|
|
6242
|
+
if (this.kt[0]) this.kt[0].dispose();
|
|
6146
6243
|
// previous fallback
|
|
6147
6244
|
this.Vt = u;
|
|
6148
|
-
this.
|
|
6149
|
-
i && (this.
|
|
6150
|
-
o && (this.
|
|
6151
|
-
this.
|
|
6152
|
-
this.
|
|
6245
|
+
this.kt = l;
|
|
6246
|
+
i && (this.xt = i);
|
|
6247
|
+
o && (this.Qt = o);
|
|
6248
|
+
this.Lt = e.slice(0);
|
|
6249
|
+
this.wt = t;
|
|
6153
6250
|
} else {
|
|
6154
|
-
let u, l, c, a, f, E,
|
|
6155
|
-
i = this.Ft ? new Array(t) : undefined;
|
|
6156
|
-
o = this.Wt ? new Array(t) : undefined;
|
|
6251
|
+
let u, l, c, a, f, E, d, S, T;
|
|
6157
6252
|
// skip common prefix
|
|
6158
|
-
for (u = 0, l = Math.min(this.
|
|
6159
|
-
if (this.
|
|
6253
|
+
for (u = 0, l = Math.min(this.wt, t); u < l && (this.Lt[u] === e[u] || this.xt && compare(this.Ft, this.Lt[u], e[u])); u++) {
|
|
6254
|
+
if (this.xt) setSignal(this.xt[u], e[u]);
|
|
6160
6255
|
}
|
|
6161
|
-
// common suffix
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6256
|
+
// skip common suffix — counted only; retained entries land in one pass
|
|
6257
|
+
// at commit instead of being staged and copied twice
|
|
6258
|
+
for (l = this.wt - 1, c = t - 1; l >= u && c >= u && (this.Lt[l] === e[c] || this.xt && compare(this.Ft, this.Lt[l], e[c])); l--,
|
|
6259
|
+
c--) ;
|
|
6260
|
+
// no structural change (every position matched in place at equal
|
|
6261
|
+
// length — the common post-reconcile shape): keep the same mapped
|
|
6262
|
+
// array identity so downstream consumers don't re-run at all
|
|
6263
|
+
if (u === t && this.wt === t) {
|
|
6264
|
+
this.Lt = e.slice(0);
|
|
6265
|
+
return;
|
|
6168
6266
|
}
|
|
6169
|
-
|
|
6267
|
+
const _ = t - this.wt;
|
|
6268
|
+
const O = new Array(t);
|
|
6269
|
+
const p = new Array(t);
|
|
6270
|
+
i = this.xt ? new Array(t) : undefined;
|
|
6271
|
+
o = this.Qt ? new Array(t) : undefined;
|
|
6272
|
+
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6273
|
+
// scanning backwards so we encounter them in natural order
|
|
6170
6274
|
E = new Map;
|
|
6171
|
-
|
|
6275
|
+
d = new Array(c + 1);
|
|
6172
6276
|
for (r = c; r >= u; r--) {
|
|
6173
6277
|
a = e[r];
|
|
6174
|
-
f = this.
|
|
6278
|
+
f = this.Ft ? this.Ft(a) : a;
|
|
6175
6279
|
n = E.get(f);
|
|
6176
|
-
|
|
6280
|
+
d[r] = n === undefined ? -1 : n;
|
|
6177
6281
|
E.set(f, r);
|
|
6178
6282
|
}
|
|
6179
|
-
// 1) step through
|
|
6283
|
+
// 1) step through the old changed window and see if items can be found
|
|
6284
|
+
// in the new set; if so, stage them at their new positions; if not,
|
|
6285
|
+
// queue them for disposal at commit
|
|
6180
6286
|
for (n = u; n <= l; n++) {
|
|
6181
|
-
a = this.
|
|
6182
|
-
f = this.
|
|
6287
|
+
a = this.Lt[n];
|
|
6288
|
+
f = this.Ft ? this.Ft(a) : a;
|
|
6183
6289
|
r = E.get(f);
|
|
6184
6290
|
if (r !== undefined && r !== -1) {
|
|
6185
|
-
|
|
6186
|
-
p[r] = this.
|
|
6187
|
-
i && (i[r] = this.
|
|
6188
|
-
o && (o[r] = this.
|
|
6189
|
-
r =
|
|
6291
|
+
O[r] = this.Vt[n];
|
|
6292
|
+
p[r] = this.kt[n];
|
|
6293
|
+
i && (i[r] = this.xt[n]);
|
|
6294
|
+
o && (o[r] = this.Qt[n]);
|
|
6295
|
+
r = d[r];
|
|
6190
6296
|
E.set(f, r);
|
|
6191
|
-
} else (
|
|
6297
|
+
} else (S ??= []).push(this.kt[n]);
|
|
6192
6298
|
}
|
|
6193
6299
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6194
6300
|
try {
|
|
6195
|
-
for (r = u; r
|
|
6196
|
-
if (r
|
|
6301
|
+
for (r = u; r <= c; r++) {
|
|
6302
|
+
if (p[r] !== undefined) continue;
|
|
6197
6303
|
(T ??= []).push(p[r] = createOwner());
|
|
6198
|
-
|
|
6304
|
+
O[r] = runWithOwner(p[r], s);
|
|
6199
6305
|
}
|
|
6200
6306
|
} catch (e) {
|
|
6201
6307
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
6202
6308
|
throw e;
|
|
6203
6309
|
}
|
|
6204
|
-
// 3) commit: land
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6310
|
+
// 3) commit: land the retained prefix and suffix plus the staged window
|
|
6311
|
+
// into the fresh arrays, swap them in (new identity for downstream
|
|
6312
|
+
// change propagation), then dispose exited rows
|
|
6313
|
+
for (n = 0; n < u; n++) {
|
|
6314
|
+
O[n] = this.Vt[n];
|
|
6315
|
+
p[n] = this.kt[n];
|
|
6316
|
+
i && (i[n] = this.xt[n]);
|
|
6317
|
+
o && (o[n] = this.Qt[n]);
|
|
6318
|
+
}
|
|
6319
|
+
for (r = u; r <= c; r++) {
|
|
6320
|
+
if (i) setSignal(i[r], e[r]);
|
|
6321
|
+
if (o) setSignal(o[r], r);
|
|
6322
|
+
}
|
|
6323
|
+
for (r = c + 1; r < t; r++) {
|
|
6324
|
+
O[r] = this.Vt[r - _];
|
|
6325
|
+
p[r] = this.kt[r - _];
|
|
6208
6326
|
if (i) {
|
|
6209
|
-
|
|
6210
|
-
setSignal(
|
|
6327
|
+
i[r] = this.xt[r - _];
|
|
6328
|
+
setSignal(i[r], e[r]);
|
|
6211
6329
|
}
|
|
6212
6330
|
if (o) {
|
|
6213
|
-
|
|
6214
|
-
setSignal(
|
|
6331
|
+
o[r] = this.Qt[r - _];
|
|
6332
|
+
if (_ !== 0) setSignal(o[r], r);
|
|
6215
6333
|
}
|
|
6216
6334
|
}
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6335
|
+
this.Vt = O;
|
|
6336
|
+
this.kt = p;
|
|
6337
|
+
i && (this.xt = i);
|
|
6338
|
+
o && (this.Qt = o);
|
|
6339
|
+
this.wt = t;
|
|
6340
|
+
// save a copy of the mapped items for the next update
|
|
6341
|
+
this.Lt = e.slice(0);
|
|
6342
|
+
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6222
6343
|
}
|
|
6223
6344
|
});
|
|
6224
6345
|
return this.Vt;
|
|
@@ -6241,22 +6362,22 @@ function updateKeyedMap() {
|
|
|
6241
6362
|
*/ function repeat(e, t, n) {
|
|
6242
6363
|
const r = t;
|
|
6243
6364
|
const i = {
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6365
|
+
vt: createOwner(),
|
|
6366
|
+
wt: 0,
|
|
6367
|
+
Ht: 0,
|
|
6247
6368
|
$t: e,
|
|
6248
|
-
|
|
6249
|
-
|
|
6369
|
+
Ut: r,
|
|
6370
|
+
kt: [],
|
|
6250
6371
|
Vt: [],
|
|
6251
|
-
|
|
6252
|
-
|
|
6372
|
+
jt: n?.from,
|
|
6373
|
+
Mt: n?.fallback
|
|
6253
6374
|
};
|
|
6254
6375
|
const o = computed(updateRepeat.bind(i));
|
|
6255
6376
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6256
6377
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6257
6378
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6258
|
-
i.
|
|
6259
|
-
o.
|
|
6379
|
+
i.vt.Je = o;
|
|
6380
|
+
o.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6260
6381
|
return accessor(o);
|
|
6261
6382
|
}
|
|
6262
6383
|
|
|
@@ -6269,52 +6390,52 @@ function updateKeyedMap() {
|
|
|
6269
6390
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
6270
6391
|
function updateRepeat() {
|
|
6271
6392
|
const e = this.$t();
|
|
6272
|
-
const t = this.
|
|
6273
|
-
runWithOwner(this.
|
|
6393
|
+
const t = this.jt?.() || 0;
|
|
6394
|
+
runWithOwner(this.vt, () => {
|
|
6274
6395
|
if (e === 0) {
|
|
6275
|
-
if (this.
|
|
6276
|
-
this.
|
|
6277
|
-
this.
|
|
6396
|
+
if (this.wt !== 0) {
|
|
6397
|
+
this.vt.dispose(false);
|
|
6398
|
+
this.kt = [];
|
|
6278
6399
|
this.Vt = [];
|
|
6279
|
-
this.
|
|
6400
|
+
this.wt = 0;
|
|
6280
6401
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6281
|
-
this.
|
|
6402
|
+
this.Ht = 0;
|
|
6282
6403
|
}
|
|
6283
|
-
if (this.
|
|
6404
|
+
if (this.Mt && !this.Vt[0]) {
|
|
6284
6405
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6285
6406
|
// dispose it before re-creating
|
|
6286
|
-
this.
|
|
6287
|
-
this.Vt[0] = runWithOwner(this.
|
|
6407
|
+
this.kt[0]?.dispose();
|
|
6408
|
+
this.Vt[0] = runWithOwner(this.kt[0] = createOwner(), this.Mt);
|
|
6288
6409
|
}
|
|
6289
6410
|
return;
|
|
6290
6411
|
}
|
|
6291
6412
|
const n = t + e;
|
|
6292
|
-
const r = this.
|
|
6413
|
+
const r = this.Ht + this.wt;
|
|
6293
6414
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6294
6415
|
// windows are disjoint or when coming from empty/fallback.
|
|
6295
|
-
const i = Math.max(t, this.
|
|
6416
|
+
const i = Math.max(t, this.Ht);
|
|
6296
6417
|
const o = Math.min(n, r);
|
|
6297
6418
|
const s = new Array(e);
|
|
6298
6419
|
const u = new Array(e);
|
|
6299
6420
|
for (let e = i; e < o; e++) {
|
|
6300
|
-
u[e - t] = this.
|
|
6301
|
-
s[e - t] = this.Vt[e - this.
|
|
6421
|
+
u[e - t] = this.kt[e - this.Ht];
|
|
6422
|
+
s[e - t] = this.Vt[e - this.Ht];
|
|
6302
6423
|
}
|
|
6303
6424
|
try {
|
|
6304
6425
|
for (let e = t; e < n; e++) {
|
|
6305
6426
|
if (e >= i && e < o) continue;
|
|
6306
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
6427
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Ut(e));
|
|
6307
6428
|
}
|
|
6308
6429
|
} catch (e) {
|
|
6309
6430
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6310
6431
|
throw e;
|
|
6311
6432
|
}
|
|
6312
6433
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6313
|
-
if (this.
|
|
6434
|
+
if (this.wt === 0) this.kt[0]?.dispose(); else for (let e = this.Ht; e < r; e++) if (e < t || e >= n) this.kt[e - this.Ht].dispose();
|
|
6314
6435
|
this.Vt = s;
|
|
6315
|
-
this.
|
|
6316
|
-
this.
|
|
6317
|
-
this.
|
|
6436
|
+
this.kt = u;
|
|
6437
|
+
this.Ht = t;
|
|
6438
|
+
this.wt = e;
|
|
6318
6439
|
});
|
|
6319
6440
|
return this.Vt;
|
|
6320
6441
|
}
|
|
@@ -6327,23 +6448,23 @@ function boundaryComputed(e, t) {
|
|
|
6327
6448
|
const n = computed(e, {
|
|
6328
6449
|
lazy: true
|
|
6329
6450
|
});
|
|
6330
|
-
n.
|
|
6451
|
+
n.Nt = (e, t) => {
|
|
6331
6452
|
// Use passed values if provided, otherwise read from node
|
|
6332
|
-
const r = e !== undefined ? e : n.
|
|
6333
|
-
const i = t !== undefined ? t : n.
|
|
6453
|
+
const r = e !== undefined ? e : n.Qe;
|
|
6454
|
+
const i = t !== undefined ? t : n.De;
|
|
6334
6455
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6335
6456
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6336
6457
|
// a boundary that handles it is found.
|
|
6337
|
-
n.
|
|
6338
|
-
const o = n.
|
|
6458
|
+
n.Qe &= ~n.Kt;
|
|
6459
|
+
const o = n.Be.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6339
6460
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6340
6461
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
6341
6462
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
6342
6463
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6343
|
-
const s = r & ~n.
|
|
6464
|
+
const s = r & ~n.Kt & (STATUS_PENDING | STATUS_ERROR);
|
|
6344
6465
|
if (s) {
|
|
6345
|
-
n.
|
|
6346
|
-
if (n.
|
|
6466
|
+
n.Qe &= ~s;
|
|
6467
|
+
if (n.De === i && !(n.Qe & (STATUS_PENDING | STATUS_ERROR))) n.De = undefined;
|
|
6347
6468
|
}
|
|
6348
6469
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6349
6470
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6354,16 +6475,16 @@ function boundaryComputed(e, t) {
|
|
|
6354
6475
|
throw i;
|
|
6355
6476
|
}
|
|
6356
6477
|
};
|
|
6357
|
-
n.
|
|
6358
|
-
n.
|
|
6478
|
+
n.Kt = t;
|
|
6479
|
+
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6359
6480
|
recompute(n, true);
|
|
6360
6481
|
return n;
|
|
6361
6482
|
}
|
|
6362
6483
|
|
|
6363
6484
|
function createBoundChildren(e, t, n, r) {
|
|
6364
|
-
const i = e.
|
|
6365
|
-
i.addChild(e.
|
|
6366
|
-
cleanup(() => i.removeChild(e.
|
|
6485
|
+
const i = e.Be;
|
|
6486
|
+
i.addChild(e.Be = n);
|
|
6487
|
+
cleanup(() => i.removeChild(e.Be));
|
|
6367
6488
|
return runWithOwner(e, () => {
|
|
6368
6489
|
const e = computed(t);
|
|
6369
6490
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -6385,53 +6506,53 @@ function isRevealController(e) {
|
|
|
6385
6506
|
}
|
|
6386
6507
|
|
|
6387
6508
|
function isSlotReady(e) {
|
|
6388
|
-
return isRevealController(e) ? e.
|
|
6509
|
+
return isRevealController(e) ? e.Yt() : e.qt.size === 0 && !e.Bt;
|
|
6389
6510
|
}
|
|
6390
6511
|
|
|
6391
6512
|
function isSlotMinimallyReady(e) {
|
|
6392
|
-
return isRevealController(e) ? e.
|
|
6513
|
+
return isRevealController(e) ? e.Zt() : isSlotReady(e);
|
|
6393
6514
|
}
|
|
6394
6515
|
|
|
6395
6516
|
function setSlotState(e, t, n, r) {
|
|
6396
|
-
setSignal(e.
|
|
6397
|
-
setSignal(e.
|
|
6517
|
+
setSignal(e.Xt, n);
|
|
6518
|
+
setSignal(e.zt, r);
|
|
6398
6519
|
if (isRevealController(e)) {
|
|
6399
|
-
if (!n && e.
|
|
6400
|
-
return e.
|
|
6520
|
+
if (!n && e.Jt === t) e.Jt = undefined;
|
|
6521
|
+
return e.en(n, r);
|
|
6401
6522
|
}
|
|
6402
|
-
if (!n && e.
|
|
6523
|
+
if (!n && e.tn === t && e.nn) e.tn = undefined;
|
|
6403
6524
|
}
|
|
6404
6525
|
|
|
6405
6526
|
class RevealController {
|
|
6527
|
+
rn;
|
|
6406
6528
|
sn;
|
|
6407
|
-
un;
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
zt=signal(false, {
|
|
6529
|
+
un=[];
|
|
6530
|
+
Jt;
|
|
6531
|
+
Xt=signal(false, {
|
|
6411
6532
|
ownedWrite: true,
|
|
6412
|
-
|
|
6533
|
+
Ct: true
|
|
6413
6534
|
});
|
|
6414
|
-
|
|
6535
|
+
zt=signal(false, {
|
|
6415
6536
|
ownedWrite: true,
|
|
6416
|
-
|
|
6537
|
+
Ct: true
|
|
6417
6538
|
});
|
|
6539
|
+
ln=true;
|
|
6418
6540
|
cn=true;
|
|
6419
|
-
an=
|
|
6420
|
-
fn=false;
|
|
6541
|
+
an=false;
|
|
6421
6542
|
constructor(e, t) {
|
|
6422
|
-
this.
|
|
6423
|
-
this.
|
|
6543
|
+
this.rn = e;
|
|
6544
|
+
this.sn = t;
|
|
6424
6545
|
}
|
|
6425
|
-
|
|
6426
|
-
for (let t = 0; t < this.
|
|
6427
|
-
const n = this.
|
|
6428
|
-
if ((isRevealController(n) ? n.
|
|
6546
|
+
fn(e) {
|
|
6547
|
+
for (let t = 0; t < this.un.length; t++) {
|
|
6548
|
+
const n = this.un[t];
|
|
6549
|
+
if ((isRevealController(n) ? n.Jt : n.tn) !== this) continue;
|
|
6429
6550
|
if (e(n) === false) return false;
|
|
6430
6551
|
}
|
|
6431
6552
|
return true;
|
|
6432
6553
|
}
|
|
6433
|
-
|
|
6434
|
-
return this.
|
|
6554
|
+
Yt() {
|
|
6555
|
+
return this.fn(isSlotReady);
|
|
6435
6556
|
}
|
|
6436
6557
|
/**
|
|
6437
6558
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -6439,13 +6560,13 @@ class RevealController {
|
|
|
6439
6560
|
* - `together`: every direct slot is minimally ready.
|
|
6440
6561
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
6441
6562
|
* - `natural`: any owned slot is minimally ready.
|
|
6442
|
-
*/
|
|
6443
|
-
const e = untrack(this.
|
|
6444
|
-
if (e === "together") return this.
|
|
6563
|
+
*/ Zt() {
|
|
6564
|
+
const e = untrack(this.rn);
|
|
6565
|
+
if (e === "together") return this.fn(isSlotMinimallyReady);
|
|
6445
6566
|
if (e === "natural") {
|
|
6446
6567
|
let e = false;
|
|
6447
6568
|
let t = false;
|
|
6448
|
-
this.
|
|
6569
|
+
this.fn(n => {
|
|
6449
6570
|
e = true;
|
|
6450
6571
|
if (isSlotMinimallyReady(n)) {
|
|
6451
6572
|
t = true;
|
|
@@ -6456,45 +6577,45 @@ class RevealController {
|
|
|
6456
6577
|
}
|
|
6457
6578
|
// sequential: only the first owned slot matters.
|
|
6458
6579
|
let t = true;
|
|
6459
|
-
this.
|
|
6580
|
+
this.fn(e => {
|
|
6460
6581
|
t = isSlotMinimallyReady(e);
|
|
6461
6582
|
return false;
|
|
6462
6583
|
});
|
|
6463
6584
|
return t;
|
|
6464
6585
|
}
|
|
6465
|
-
|
|
6466
|
-
if (this.
|
|
6467
|
-
this.
|
|
6468
|
-
const t = untrack(this.
|
|
6469
|
-
setSignal(e.
|
|
6470
|
-
untrack(() => this.
|
|
6586
|
+
En(e) {
|
|
6587
|
+
if (this.un.includes(e)) return;
|
|
6588
|
+
this.un.push(e);
|
|
6589
|
+
const t = untrack(this.rn);
|
|
6590
|
+
setSignal(e.Xt, true), setSignal(e.zt, t === "sequential" ? !!untrack(this.sn) : false);
|
|
6591
|
+
untrack(() => this.en());
|
|
6471
6592
|
}
|
|
6472
6593
|
dn(e) {
|
|
6473
|
-
const t = this.
|
|
6474
|
-
if (t >= 0) this.
|
|
6475
|
-
untrack(() => this.
|
|
6476
|
-
}
|
|
6477
|
-
|
|
6478
|
-
if (this.
|
|
6479
|
-
this.
|
|
6480
|
-
const n = this.
|
|
6481
|
-
const r = this.
|
|
6594
|
+
const t = this.un.indexOf(e);
|
|
6595
|
+
if (t >= 0) this.un.splice(t, 1);
|
|
6596
|
+
untrack(() => this.en());
|
|
6597
|
+
}
|
|
6598
|
+
en(e, t) {
|
|
6599
|
+
if (this.an) return;
|
|
6600
|
+
this.an = true;
|
|
6601
|
+
const n = this.ln;
|
|
6602
|
+
const r = this.cn;
|
|
6482
6603
|
try {
|
|
6483
|
-
const n = e ?? read(this.
|
|
6604
|
+
const n = e ?? read(this.Xt), r = untrack(this.rn), i = r === "sequential" && !!untrack(this.sn), o = t ?? i;
|
|
6484
6605
|
if (n) {
|
|
6485
6606
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
6486
6607
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
6487
6608
|
// held; it resumes once the outer releases us.
|
|
6488
|
-
this.
|
|
6609
|
+
this.fn(e => setSlotState(e, this, true, o));
|
|
6489
6610
|
} else if (r === "natural") {
|
|
6490
6611
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
6491
6612
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
6492
6613
|
// so the parent backpointer survives for upward readiness notifications.
|
|
6493
|
-
this.
|
|
6614
|
+
this.fn(e => {
|
|
6494
6615
|
if (isRevealController(e)) {
|
|
6495
|
-
setSignal(e.Jt, false);
|
|
6496
6616
|
setSignal(e.zt, false);
|
|
6497
|
-
e.
|
|
6617
|
+
setSignal(e.Xt, false);
|
|
6618
|
+
e.en(false, false);
|
|
6498
6619
|
} else {
|
|
6499
6620
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
6500
6621
|
}
|
|
@@ -6505,11 +6626,11 @@ class RevealController {
|
|
|
6505
6626
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
6506
6627
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
6507
6628
|
// cohesive reveal without waiting for every grandchild.
|
|
6508
|
-
const e = this.
|
|
6509
|
-
this.
|
|
6629
|
+
const e = this.fn(isSlotMinimallyReady);
|
|
6630
|
+
this.fn(t => setSlotState(t, this, !e, false));
|
|
6510
6631
|
} else {
|
|
6511
6632
|
let e = false;
|
|
6512
|
-
this.
|
|
6633
|
+
this.fn(t => {
|
|
6513
6634
|
if (e) return setSlotState(t, this, true, i);
|
|
6514
6635
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
6515
6636
|
e = true;
|
|
@@ -6520,63 +6641,63 @@ class RevealController {
|
|
|
6520
6641
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
6521
6642
|
// backpointer survives for upward readiness notifications.
|
|
6522
6643
|
if (isRevealController(t)) {
|
|
6523
|
-
setSignal(t.Jt, false);
|
|
6524
6644
|
setSignal(t.zt, false);
|
|
6525
|
-
t.
|
|
6645
|
+
setSignal(t.Xt, false);
|
|
6646
|
+
t.en(false, false);
|
|
6526
6647
|
} else {
|
|
6527
6648
|
setSlotState(t, this, true, false);
|
|
6528
6649
|
}
|
|
6529
6650
|
});
|
|
6530
6651
|
}
|
|
6531
6652
|
} finally {
|
|
6532
|
-
this.
|
|
6533
|
-
this.
|
|
6534
|
-
this.
|
|
6653
|
+
this.ln = this.Yt();
|
|
6654
|
+
this.cn = this.Zt();
|
|
6655
|
+
this.an = false;
|
|
6535
6656
|
}
|
|
6536
|
-
if (this.
|
|
6657
|
+
if (this.Jt && (n !== this.ln || r !== this.cn)) this.Jt.en();
|
|
6537
6658
|
}
|
|
6538
6659
|
}
|
|
6539
6660
|
|
|
6540
6661
|
class CollectionQueue extends Queue {
|
|
6662
|
+
Sn;
|
|
6663
|
+
qt=new Set;
|
|
6541
6664
|
Tn;
|
|
6542
|
-
Bt=
|
|
6543
|
-
|
|
6544
|
-
Zt=true;
|
|
6545
|
-
zt=signal(false, {
|
|
6665
|
+
Bt=true;
|
|
6666
|
+
Xt=signal(false, {
|
|
6546
6667
|
ownedWrite: true,
|
|
6547
|
-
|
|
6668
|
+
Ct: true
|
|
6548
6669
|
});
|
|
6549
|
-
|
|
6550
|
-
|
|
6670
|
+
De;
|
|
6671
|
+
zt=signal(false, {
|
|
6551
6672
|
ownedWrite: true,
|
|
6552
|
-
|
|
6673
|
+
Ct: true
|
|
6553
6674
|
});
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6675
|
+
tn;
|
|
6676
|
+
nn=false;
|
|
6677
|
+
_n;
|
|
6557
6678
|
On=ON_INIT;
|
|
6558
6679
|
constructor(e) {
|
|
6559
6680
|
super();
|
|
6560
|
-
this.
|
|
6681
|
+
this.Sn = e;
|
|
6561
6682
|
}
|
|
6562
6683
|
run(e) {
|
|
6563
|
-
if (!e || read(this.
|
|
6684
|
+
if (!e || read(this.Xt) && (!_revealUsed || read(this.zt))) return;
|
|
6564
6685
|
return super.run(e);
|
|
6565
6686
|
}
|
|
6566
6687
|
notify(e, t, n, r) {
|
|
6567
|
-
if (!(t & this.
|
|
6568
|
-
if (this.
|
|
6688
|
+
if (!(t & this.Sn)) return super.notify(e, t, n, r);
|
|
6689
|
+
if (this.nn && this._n) {
|
|
6569
6690
|
const e = untrack(() => {
|
|
6570
6691
|
try {
|
|
6571
|
-
return this.
|
|
6692
|
+
return this._n();
|
|
6572
6693
|
} catch {
|
|
6573
6694
|
return ON_INIT;
|
|
6574
6695
|
}
|
|
6575
6696
|
});
|
|
6576
6697
|
if (e !== this.On) {
|
|
6577
6698
|
this.On = e;
|
|
6578
|
-
this.
|
|
6579
|
-
this.
|
|
6699
|
+
this.nn = false;
|
|
6700
|
+
this.qt.clear();
|
|
6580
6701
|
}
|
|
6581
6702
|
}
|
|
6582
6703
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -6589,47 +6710,47 @@ class CollectionQueue extends Queue {
|
|
|
6589
6710
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
6590
6711
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
6591
6712
|
// (the Loading > Errored > content composition escape, #2856).
|
|
6592
|
-
if (this.
|
|
6593
|
-
if (n & this.
|
|
6594
|
-
this.
|
|
6595
|
-
const t = r?.source || e.
|
|
6713
|
+
if (this.Sn & STATUS_PENDING && this.nn) return super.notify(e, t, n, r);
|
|
6714
|
+
if (n & this.Sn) {
|
|
6715
|
+
this.Bt = true;
|
|
6716
|
+
const t = r?.source || e.De?.source;
|
|
6596
6717
|
if (t) {
|
|
6597
|
-
const e = this.
|
|
6598
|
-
this.
|
|
6599
|
-
if (e) setSignal(this.
|
|
6600
|
-
if (this.
|
|
6601
|
-
setSignal(this.
|
|
6718
|
+
const e = this.qt.size === 0;
|
|
6719
|
+
this.qt.add(t);
|
|
6720
|
+
if (e) setSignal(this.Xt, true);
|
|
6721
|
+
if (this.Sn & STATUS_ERROR) {
|
|
6722
|
+
setSignal(this.De, unwrapStatusError(t.De));
|
|
6602
6723
|
}
|
|
6603
6724
|
}
|
|
6604
6725
|
}
|
|
6605
|
-
t &= ~this.
|
|
6726
|
+
t &= ~this.Sn;
|
|
6606
6727
|
return t ? super.notify(e, t, n, r) : true;
|
|
6607
6728
|
}
|
|
6608
|
-
|
|
6609
|
-
for (const e of this.
|
|
6729
|
+
He() {
|
|
6730
|
+
for (const e of this.qt) {
|
|
6610
6731
|
// A source with a live affects() mark holds display state for the
|
|
6611
6732
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
6612
6733
|
// status of its own, so the count is the liveness test. The release
|
|
6613
6734
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
6614
|
-
if (e.
|
|
6735
|
+
if (e.Ge & REACTIVE_DISPOSED || !e.k && !(e.Qe & this.Sn) && !(this.Sn & STATUS_ERROR && e.Qe & STATUS_PENDING)) this.qt.delete(e);
|
|
6615
6736
|
}
|
|
6616
|
-
if (!this.
|
|
6617
|
-
if (this.
|
|
6618
|
-
this.
|
|
6737
|
+
if (!this.qt.size) {
|
|
6738
|
+
if (this.Sn & STATUS_PENDING && this.Bt && !this.nn && this.Tn) {
|
|
6739
|
+
this.Bt = !!(this.Tn.Qe & this.Sn);
|
|
6619
6740
|
} else {
|
|
6620
|
-
this.
|
|
6741
|
+
this.Bt = false;
|
|
6621
6742
|
}
|
|
6622
|
-
if (!this.
|
|
6623
|
-
setSignal(this.
|
|
6624
|
-
if (this.
|
|
6743
|
+
if (!this.Bt) {
|
|
6744
|
+
setSignal(this.Xt, false);
|
|
6745
|
+
if (this._n) {
|
|
6625
6746
|
try {
|
|
6626
|
-
this.On = untrack(() => this.
|
|
6747
|
+
this.On = untrack(() => this._n());
|
|
6627
6748
|
} catch {
|
|
6628
6749
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
6629
6750
|
}
|
|
6630
6751
|
}
|
|
6631
6752
|
}
|
|
6632
|
-
if (_revealUsed) this.
|
|
6753
|
+
if (_revealUsed) this.tn?.en();
|
|
6633
6754
|
}
|
|
6634
6755
|
}
|
|
6635
6756
|
|
|
@@ -6637,12 +6758,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6637
6758
|
const i = createOwner();
|
|
6638
6759
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
6639
6760
|
const o = new CollectionQueue(e);
|
|
6640
|
-
if (e === STATUS_ERROR) o.
|
|
6761
|
+
if (e === STATUS_ERROR) o.De = signal(undefined, {
|
|
6641
6762
|
ownedWrite: true,
|
|
6642
|
-
|
|
6763
|
+
Ct: true
|
|
6643
6764
|
});
|
|
6644
|
-
if (r) o.
|
|
6645
|
-
const s = o.
|
|
6765
|
+
if (r) o._n = r;
|
|
6766
|
+
const s = o.Tn = createBoundChildren(i, t, o, e);
|
|
6646
6767
|
// Prime source tracking so reveal registration sees pending sources.
|
|
6647
6768
|
untrack(() => {
|
|
6648
6769
|
let t = false;
|
|
@@ -6651,23 +6772,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6651
6772
|
} catch (e) {
|
|
6652
6773
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
6653
6774
|
}
|
|
6654
|
-
o.
|
|
6775
|
+
o.Bt = t || !!(s.Qe & e) || s.De instanceof NotReadyError;
|
|
6655
6776
|
});
|
|
6656
6777
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
6657
6778
|
if (u) {
|
|
6658
|
-
o.
|
|
6659
|
-
u.
|
|
6779
|
+
o.tn = u;
|
|
6780
|
+
u.En(o);
|
|
6660
6781
|
cleanup(() => u.dn(o));
|
|
6661
6782
|
}
|
|
6662
6783
|
return accessor(computed(() => {
|
|
6663
|
-
if (!read(o.
|
|
6784
|
+
if (!read(o.Xt)) {
|
|
6664
6785
|
const e = read(s);
|
|
6665
|
-
if (!untrack(() => read(o.
|
|
6786
|
+
if (!untrack(() => read(o.Xt))) return o.nn = true, e;
|
|
6666
6787
|
}
|
|
6667
6788
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
6668
6789
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
6669
6790
|
// outside a `createRevealOrder` scope.
|
|
6670
|
-
if (_revealUsed && read(o.
|
|
6791
|
+
if (_revealUsed && read(o.zt)) return undefined;
|
|
6671
6792
|
return n(o);
|
|
6672
6793
|
},
|
|
6673
6794
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -6675,7 +6796,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6675
6796
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
6676
6797
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
6677
6798
|
{
|
|
6678
|
-
|
|
6799
|
+
Ct: true
|
|
6679
6800
|
}));
|
|
6680
6801
|
}
|
|
6681
6802
|
|
|
@@ -6728,8 +6849,8 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6728
6849
|
* }
|
|
6729
6850
|
* ```
|
|
6730
6851
|
*/ function createErrorBoundary(e, t) {
|
|
6731
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
6732
|
-
for (const t of e.
|
|
6852
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.De), () => {
|
|
6853
|
+
for (const t of e.qt) recompute(t);
|
|
6733
6854
|
schedule();
|
|
6734
6855
|
}));
|
|
6735
6856
|
}
|
|
@@ -6786,11 +6907,11 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6786
6907
|
computed(() => {
|
|
6787
6908
|
i();
|
|
6788
6909
|
o();
|
|
6789
|
-
s.
|
|
6910
|
+
s.en();
|
|
6790
6911
|
});
|
|
6791
6912
|
if (r) {
|
|
6792
|
-
s.
|
|
6793
|
-
r.
|
|
6913
|
+
s.Jt = r;
|
|
6914
|
+
r.En(s);
|
|
6794
6915
|
cleanup(() => r.dn(s));
|
|
6795
6916
|
}
|
|
6796
6917
|
return t;
|