@solidjs/signals 2.0.0-beta.23 → 2.0.0-beta.25
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 +615 -125
- package/dist/node.cjs +1551 -1092
- package/dist/prod/core/core.js +106 -69
- package/dist/prod/core/effect.js +9 -9
- package/dist/prod/core/error.js +9 -0
- package/dist/prod/core/graph.js +3 -3
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/optimistic.js +6 -4
- package/dist/prod/core/owner.js +10 -10
- package/dist/prod/core/scheduler.js +6 -6
- package/dist/prod/core/verdict.js +2 -2
- package/dist/prod/map.js +53 -29
- package/dist/prod/store/optimistic.js +40 -31
- package/dist/prod/store/projection.js +25 -18
- package/dist/prod/store/reconcile.js +433 -208
- package/dist/prod/store/store.js +250 -116
- package/dist/prod/store/utils.js +34 -22
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/error.d.ts +1 -1
- package/dist/types/store/optimistic.d.ts +1 -1
- package/dist/types/store/reconcile.d.ts +17 -8
- package/dist/types/store/store.d.ts +20 -2
- package/dist/types-cjs/core/core.d.cts +15 -0
- package/dist/types-cjs/core/error.d.cts +1 -1
- package/dist/types-cjs/store/optimistic.d.cts +1 -1
- package/dist/types-cjs/store/reconcile.d.cts +17 -8
- package/dist/types-cjs/store/store.d.cts +20 -2
- 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
|
}
|
|
@@ -214,7 +223,7 @@ const activeLanes = new Set;
|
|
|
214
223
|
l: [ [], [] ],
|
|
215
224
|
S: null,
|
|
216
225
|
T: activeTransition,
|
|
217
|
-
|
|
226
|
+
O: r
|
|
218
227
|
};
|
|
219
228
|
signalLanes.set(e, t);
|
|
220
229
|
activeLanes.add(t);
|
|
@@ -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._, t);
|
|
237
|
+
adoptCompanionLane(e.p, t);
|
|
229
238
|
return t;
|
|
230
239
|
}
|
|
231
240
|
|
|
@@ -236,7 +245,7 @@ function adoptCompanionLane(e, t) {
|
|
|
236
245
|
const r = findLane(n);
|
|
237
246
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
238
247
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
239
|
-
if (r !== t && r.o === e && !r.
|
|
248
|
+
if (r !== t && r.o === e && !r.O) r.O = t;
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
/**
|
|
@@ -315,9 +324,9 @@ function resolveTransition(e) {
|
|
|
315
324
|
if (i !== n && !hasActiveOverride(e)) {
|
|
316
325
|
// Parent-child lanes stay independent so isPending resolves without
|
|
317
326
|
// waiting for the parent's async. The child keeps ownership.
|
|
318
|
-
if (n.
|
|
327
|
+
if (n.O && findLane(n.O) === i) {
|
|
319
328
|
e.i = t;
|
|
320
|
-
} else if (i.
|
|
329
|
+
} else if (i.O && findLane(i.O) === n) ; else mergeLanes(n, i);
|
|
321
330
|
}
|
|
322
331
|
return;
|
|
323
332
|
}
|
|
@@ -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,22 +376,22 @@ 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.L.length === 0 && t.V.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.G !== null) {
|
|
377
386
|
transientStoreNodes.delete(e);
|
|
378
387
|
continue;
|
|
379
388
|
}
|
|
380
|
-
if (e.
|
|
389
|
+
if (e.U !== NOT_PENDING) continue;
|
|
381
390
|
if (e.A !== undefined && e.A !== NOT_PENDING) continue;
|
|
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
396
|
e.W?.();
|
|
388
397
|
}
|
|
@@ -411,19 +420,19 @@ function setProjectionWriteActive(e) {
|
|
|
411
420
|
* land there directly — no per-field aliasing.
|
|
412
421
|
*/ function createBatch() {
|
|
413
422
|
return {
|
|
414
|
-
|
|
423
|
+
F: clock,
|
|
415
424
|
H: [],
|
|
416
|
-
|
|
417
|
-
|
|
425
|
+
M: new Map,
|
|
426
|
+
v: [],
|
|
418
427
|
L: [],
|
|
419
|
-
|
|
428
|
+
V: 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,12 +440,12 @@ 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
450
|
if (t.L.length) {
|
|
442
451
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
@@ -445,13 +454,13 @@ function mergeTransitionState(e, t) {
|
|
|
445
454
|
e.L.push(...t.L);
|
|
446
455
|
t.L.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.V) e.V.add(n);
|
|
458
|
+
for (const [n, r] of t.M) {
|
|
459
|
+
let t = e.M.get(n);
|
|
460
|
+
if (!t) e.M.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
|
-
static ce=null;
|
|
593
602
|
static ae=null;
|
|
603
|
+
static ce=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
|
-
static
|
|
600
|
-
static pe=null;
|
|
609
|
+
static Oe=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).
|
|
@@ -605,29 +614,29 @@ class GlobalQueue extends Queue {
|
|
|
605
614
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
606
615
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
607
616
|
// once the gate holds.
|
|
608
|
-
static
|
|
617
|
+
static _e=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,15 +646,15 @@ 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.
|
|
657
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.H.length > 0;
|
|
649
658
|
reassignPendingTransition(e.H);
|
|
650
659
|
activeTransition = null;
|
|
651
660
|
finalizePureQueue(null, true);
|
|
@@ -654,7 +663,7 @@ class GlobalQueue extends Queue {
|
|
|
654
663
|
const t = activeTransition;
|
|
655
664
|
const n = this.D;
|
|
656
665
|
n !== t && n.H.push(...t.H);
|
|
657
|
-
this.restoreQueues(t.
|
|
666
|
+
this.restoreQueues(t.j);
|
|
658
667
|
transitions.delete(t);
|
|
659
668
|
activeTransition = null;
|
|
660
669
|
reassignPendingTransition(n.H);
|
|
@@ -665,52 +674,52 @@ class GlobalQueue extends Queue {
|
|
|
665
674
|
// there and must survive to the next flush.
|
|
666
675
|
const e = createBatch();
|
|
667
676
|
e.H = n.H;
|
|
668
|
-
e.
|
|
677
|
+
e.v = n.v;
|
|
669
678
|
e.L = n.L;
|
|
670
|
-
e.
|
|
679
|
+
e.V = n.V;
|
|
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?.we) 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.M.get(n);
|
|
722
|
+
if (!r) activeTransition.M.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.F === 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.F = clock;
|
|
737
746
|
const t = this.D;
|
|
738
747
|
if (t !== activeTransition) {
|
|
739
748
|
// Adopt the ambient batch into the transaction, then make the
|
|
@@ -748,13 +757,13 @@ class GlobalQueue extends Queue {
|
|
|
748
757
|
n.T = activeTransition;
|
|
749
758
|
activeTransition.H.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
765
|
if (t.L.length) activeTransition.L.push(...t.L);
|
|
757
|
-
for (const e of t.
|
|
766
|
+
for (const e of t.V) activeTransition.V.add(e);
|
|
758
767
|
currentBatch = this.D = activeTransition;
|
|
759
768
|
}
|
|
760
769
|
for (const e of activeLanes) {
|
|
@@ -780,48 +789,48 @@ 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.me !== undefined;
|
|
784
793
|
const i = reaskArmed;
|
|
785
|
-
for (let o = e.
|
|
794
|
+
for (let o = e.G; o !== null; o = o.ve) {
|
|
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.
|
|
790
|
-
o.
|
|
797
|
+
if (i) o.Ve.Le &= ~REACTIVE_REASK;
|
|
798
|
+
if (r && o.Ve.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
799
|
+
o.Ve.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
791
800
|
continue;
|
|
792
801
|
}
|
|
793
802
|
if (t && n) {
|
|
794
|
-
o.
|
|
795
|
-
assignOrMergeLane(o.
|
|
803
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
804
|
+
assignOrMergeLane(o.Ve, n);
|
|
796
805
|
} else if (t) {
|
|
797
|
-
o.
|
|
806
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
798
807
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
799
|
-
o.
|
|
808
|
+
o.Ve.i = undefined;
|
|
800
809
|
}
|
|
801
|
-
enqueueSub(o.
|
|
810
|
+
enqueueSub(o.Ve);
|
|
802
811
|
}
|
|
803
812
|
}
|
|
804
813
|
|
|
805
814
|
function commitPendingNode(e) {
|
|
806
815
|
const t = e;
|
|
807
|
-
if (!t.
|
|
808
|
-
if (e.
|
|
809
|
-
e.
|
|
810
|
-
e.
|
|
816
|
+
if (!t.Ue) {
|
|
817
|
+
if (e.U !== NOT_PENDING) {
|
|
818
|
+
e.ke = e.U;
|
|
819
|
+
e.U = NOT_PENDING;
|
|
811
820
|
}
|
|
812
|
-
if (e.
|
|
821
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
813
822
|
return;
|
|
814
823
|
}
|
|
815
|
-
if (e.
|
|
816
|
-
e.
|
|
817
|
-
e.
|
|
824
|
+
if (e.U !== NOT_PENDING) {
|
|
825
|
+
e.ke = e.U;
|
|
826
|
+
e.U = NOT_PENDING;
|
|
818
827
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
819
|
-
if (e.
|
|
828
|
+
if (e.We && e.We !== EFFECT_TRACKED) e.Fe = true;
|
|
820
829
|
}
|
|
821
830
|
t.Le &= ~REACTIVE_MANUAL_WRITE;
|
|
822
|
-
if (!(t.
|
|
823
|
-
if (t.
|
|
824
|
-
if (e.
|
|
831
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
832
|
+
if (t.Qe !== null || t.He !== null) GlobalQueue.X(t, false, true);
|
|
833
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
825
834
|
}
|
|
826
835
|
|
|
827
836
|
function commitPendingNodes() {
|
|
@@ -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.
|
|
861
|
+
if (e && e.Y.size) {
|
|
862
|
+
for (const t of e.Y) {
|
|
854
863
|
if (t.Le & 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
|
|
@@ -863,23 +872,23 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
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
874
|
if (t.L.length) {
|
|
866
|
-
GlobalQueue.
|
|
875
|
+
GlobalQueue.ne(t.L);
|
|
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.V.size) GlobalQueue.ee(t.V, 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.Me?.();
|
|
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;
|
|
@@ -948,21 +957,21 @@ function runQueue$1(e, t) {
|
|
|
948
957
|
function reporterBlocksSource(e, t) {
|
|
949
958
|
if (e.Le & (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.xe & 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.M) {
|
|
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.M.delete(n); else if (n.xe & 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
|
}
|
|
@@ -1012,31 +1021,31 @@ 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.We === EFFECT_TRACKED) {
|
|
1016
1025
|
const t = e;
|
|
1017
1026
|
if (!t.Fe) {
|
|
1018
1027
|
t.Fe = true;
|
|
1019
|
-
t.
|
|
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) {
|
|
@@ -1067,23 +1076,23 @@ function deleteFromHeap(e, t) {
|
|
|
1067
1076
|
const n = e.Le;
|
|
1068
1077
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1069
1078
|
e.Le = n & -25;
|
|
1070
|
-
const r = e.
|
|
1071
|
-
if (e.
|
|
1072
|
-
const n = e.
|
|
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.
|
|
1094
|
+
for (let t = 0; t <= e.C; t++) {
|
|
1095
|
+
for (let n = e.h[t]; n !== undefined; n = n.tt) {
|
|
1087
1096
|
if (n.Le & REACTIVE_IN_HEAP) markNode(n);
|
|
1088
1097
|
}
|
|
1089
1098
|
}
|
|
@@ -1093,13 +1102,13 @@ function markNode(e, t = REACTIVE_DIRTY) {
|
|
|
1093
1102
|
const n = e.Le;
|
|
1094
1103
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1095
1104
|
e.Le = n & -4 | t;
|
|
1096
|
-
for (let t = e.
|
|
1097
|
-
markNode(t.
|
|
1105
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
1106
|
+
markNode(t.Ve, REACTIVE_CHECK);
|
|
1098
1107
|
}
|
|
1099
|
-
if (e.
|
|
1100
|
-
for (let t = e.
|
|
1101
|
-
for (let e = t.
|
|
1102
|
-
markNode(e.
|
|
1108
|
+
if (e.nt !== null) {
|
|
1109
|
+
for (let t = e.nt; t !== null; t = t.rt) {
|
|
1110
|
+
for (let e = t.G; e !== null; e = e.ve) {
|
|
1111
|
+
markNode(e.Ve, 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
1122
|
if (n.Le & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1114
|
-
n = e.h[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.
|
|
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.Ue && r.Xe >= n) n = r.Xe + 1;
|
|
1136
|
+
}
|
|
1137
|
+
if (e.Xe !== n) {
|
|
1138
|
+
e.Xe = n;
|
|
1139
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
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.Ve, queueFor(t.Ve));
|
|
1137
1146
|
}
|
|
1138
1147
|
}
|
|
1139
1148
|
}
|
|
@@ -1142,7 +1151,7 @@ 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
1156
|
const e = t.Le;
|
|
1148
1157
|
t.Le = e | REACTIVE_ZOMBIE;
|
|
@@ -1156,17 +1165,17 @@ 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
|
|
|
@@ -1181,54 +1190,54 @@ function disposeChildren(e, t = false, n) {
|
|
|
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._ || t.p) GlobalQueue.ce(t);
|
|
1185
1194
|
}
|
|
1186
|
-
if (t && e.
|
|
1187
|
-
let i = n ? e.
|
|
1195
|
+
if (t && e.Ue) e.ut = null;
|
|
1196
|
+
let i = n ? e.Qe : 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.Qe = 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.Le & 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.He : e.
|
|
1240
|
+
let n = t ? e.He : 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.He = null : e.
|
|
1250
|
+
t ? e.He = 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.Ge & 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
|
|
|
@@ -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
|
+
Ge: 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
|
-
|
|
1385
|
+
lt: 0,
|
|
1377
1386
|
He: null,
|
|
1378
|
-
|
|
1379
|
-
|
|
1387
|
+
Qe: 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,13 +1431,13 @@ 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.ve;
|
|
1437
|
+
const i = e.St;
|
|
1438
|
+
if (r !== null) r.St = i; else t.Tt = i;
|
|
1439
|
+
if (i !== null) i.ve = r; else {
|
|
1440
|
+
t.G = r;
|
|
1432
1441
|
if (r === null) {
|
|
1433
1442
|
t.W?.();
|
|
1434
1443
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
@@ -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.
|
|
1450
|
+
e.Ue && e.Ge & CONFIG_AUTO_DISPOSE && !(e.Le & REACTIVE_ZOMBIE) && !(e.xe & 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,18 +1482,18 @@ 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.
|
|
1485
|
+
const r = t.st;
|
|
1486
|
+
if (r !== null && r.Ye === e) {
|
|
1478
1487
|
r.Ot &&= n;
|
|
1479
1488
|
return;
|
|
1480
1489
|
}
|
|
1481
1490
|
let i = null;
|
|
1482
1491
|
const o = t.Le & 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._t = t.Rt;
|
|
1496
|
+
t.st = i;
|
|
1488
1497
|
// First touch of this pass: the previous pass's label is stale.
|
|
1489
1498
|
i.Ot = n;
|
|
1490
1499
|
return;
|
|
@@ -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.Ve === t && (!o || s._t === 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
1511
|
if (o) s.Ot &&= n; else s.Ot = n;
|
|
1503
1512
|
return;
|
|
1504
1513
|
}
|
|
1505
|
-
const u = t.
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1514
|
+
const u = t.st = e.Tt = {
|
|
1515
|
+
Ye: e,
|
|
1516
|
+
Ve: t,
|
|
1517
|
+
Ke: i,
|
|
1518
|
+
St: s,
|
|
1519
|
+
ve: null,
|
|
1520
|
+
_t: t.Rt,
|
|
1512
1521
|
Ot: 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.ve = u; else e.G = 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.G; n !== null; n = n.ve) t(n.Ve, 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.G; e !== null; e = e.ve) t(e.Ve, 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.F = 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.xe &= ~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.F = 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
1636
|
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1628
1637
|
globalQueue.initTransition(resolveTransition(e));
|
|
1629
|
-
const o = !!(e.
|
|
1638
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1630
1639
|
trimStaleDeps(e);
|
|
1631
1640
|
clearStatus(e);
|
|
1632
1641
|
const s = resolveLane(e);
|
|
@@ -1644,8 +1653,8 @@ function handleAsync(e, t, n) {
|
|
|
1644
1653
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
1645
1654
|
// has committed by then, so corrections reveal atomically with their
|
|
1646
1655
|
// transition rather than escaping it.
|
|
1647
|
-
if (e.
|
|
1648
|
-
e.
|
|
1656
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
1657
|
+
e.U = r;
|
|
1649
1658
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
1650
1659
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
1651
1660
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -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.F = 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.We;
|
|
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.F = 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.Ge & CONFIG_AUTO_DISPOSE && !e.G && !(e.xe & STATUS_PENDING)) {
|
|
1702
1711
|
unobserved(e);
|
|
1703
1712
|
}
|
|
1704
1713
|
};
|
|
@@ -1747,13 +1756,13 @@ function handleAsync(e, t, n) {
|
|
|
1747
1756
|
} catch {}
|
|
1748
1757
|
});
|
|
1749
1758
|
const iterate = () => {
|
|
1750
|
-
let u, l,
|
|
1759
|
+
let u, l, a = false, c = false, f = true;
|
|
1751
1760
|
n.next().then(n => {
|
|
1752
1761
|
if (f) {
|
|
1753
1762
|
u = n;
|
|
1754
|
-
|
|
1763
|
+
a = 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;
|
|
@@ -1771,26 +1780,26 @@ function handleAsync(e, t, n) {
|
|
|
1771
1780
|
}, n => {
|
|
1772
1781
|
if (f) {
|
|
1773
1782
|
l = n;
|
|
1774
|
-
|
|
1775
|
-
} else if (e.
|
|
1783
|
+
c = true;
|
|
1784
|
+
} else if (e.ut === t) {
|
|
1776
1785
|
i = true;
|
|
1777
1786
|
handleError(n);
|
|
1778
1787
|
}
|
|
1779
1788
|
});
|
|
1780
1789
|
f = false;
|
|
1781
|
-
if (
|
|
1790
|
+
if (c) {
|
|
1782
1791
|
// Match the promise branch, but only rethrow during the initial read.
|
|
1783
1792
|
i = true;
|
|
1784
1793
|
handleError(l);
|
|
1785
1794
|
if (s) throw l;
|
|
1786
1795
|
return true;
|
|
1787
1796
|
}
|
|
1788
|
-
if (
|
|
1797
|
+
if (a && !u.done) {
|
|
1789
1798
|
o = u.value;
|
|
1790
1799
|
r = true;
|
|
1791
1800
|
return iterate();
|
|
1792
1801
|
}
|
|
1793
|
-
return
|
|
1802
|
+
return a && u.done;
|
|
1794
1803
|
};
|
|
1795
1804
|
const u = iterate();
|
|
1796
1805
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
@@ -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.xe = t ? 0 : e.xe & 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._ || e.p) GlobalQueue.le(e);
|
|
1827
|
+
if (e.nt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1828
|
+
if (e.Nt) e.Nt();
|
|
1820
1829
|
}
|
|
1821
1830
|
|
|
1822
1831
|
function notifyStatus(e, t, n, r, i) {
|
|
@@ -1829,37 +1838,37 @@ 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.xe = STATUS_PENDING | e.xe & 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.xe = t | (t !== STATUS_ERROR ? e.xe & 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.ae !== null) GlobalQueue.ae(e);
|
|
1843
1852
|
}
|
|
1844
1853
|
if (i && !r) {
|
|
1845
1854
|
assignOrMergeLane(e, i);
|
|
1846
1855
|
}
|
|
1847
|
-
const
|
|
1848
|
-
const
|
|
1849
|
-
if (e.
|
|
1856
|
+
const a = r || l;
|
|
1857
|
+
const c = r || u ? undefined : i;
|
|
1858
|
+
if (e.Nt) {
|
|
1850
1859
|
if (r && t === STATUS_PENDING) {
|
|
1851
1860
|
return;
|
|
1852
1861
|
}
|
|
1853
|
-
if (
|
|
1854
|
-
e.
|
|
1862
|
+
if (a) {
|
|
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.F = 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`
|
|
@@ -1870,15 +1879,15 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1870
1879
|
schedule();
|
|
1871
1880
|
return;
|
|
1872
1881
|
}
|
|
1873
|
-
if (!
|
|
1874
|
-
notifyStatus(e, t, n,
|
|
1882
|
+
if (!a && !e.T) queuePendingNode(e);
|
|
1883
|
+
notifyStatus(e, t, n, a, c);
|
|
1875
1884
|
}
|
|
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
|
-
if (t.
|
|
1950
|
+
if (t.Ue) {
|
|
1942
1951
|
const e = t;
|
|
1943
|
-
e.
|
|
1952
|
+
e.Ge &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1944
1953
|
if (e.Le & REACTIVE_SNAPSHOT_STALE) {
|
|
1945
1954
|
e.Le &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1946
1955
|
e.Le |= REACTIVE_DIRTY;
|
|
1947
|
-
if (dirtyQueue.
|
|
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.me;
|
|
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,36 +1977,36 @@ function clearSnapshots() {
|
|
|
1965
1977
|
}
|
|
1966
1978
|
|
|
1967
1979
|
function recompute(e, t = false) {
|
|
1968
|
-
const n = e.
|
|
1980
|
+
const n = e.We;
|
|
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.He = e.
|
|
1977
|
-
e.
|
|
1978
|
-
e.
|
|
1979
|
-
e.
|
|
1980
|
-
e.
|
|
1988
|
+
e.He = e.Et;
|
|
1989
|
+
e.Qe = e.it;
|
|
1990
|
+
e.Et = null;
|
|
1991
|
+
e.it = null;
|
|
1992
|
+
e.lt = 0;
|
|
1981
1993
|
} else ;
|
|
1982
1994
|
}
|
|
1983
1995
|
let r = !!(e.Le & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1984
1996
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1985
|
-
const o = !!(e.
|
|
1997
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1986
1998
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1987
1999
|
// the recompute wipes _flags below.
|
|
1988
2000
|
const s = (e.Le & REACTIVE_REASK) !== 0;
|
|
1989
2001
|
const u = context;
|
|
1990
2002
|
context = e;
|
|
1991
|
-
e.
|
|
1992
|
-
e.
|
|
2003
|
+
e.st = null;
|
|
2004
|
+
e.Rt++;
|
|
1993
2005
|
e.Le = REACTIVE_RECOMPUTING_DEPS;
|
|
1994
|
-
e.
|
|
1995
|
-
let l = e.
|
|
1996
|
-
let
|
|
1997
|
-
let
|
|
2006
|
+
e.F = clock;
|
|
2007
|
+
let l = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2008
|
+
let a = e.Xe;
|
|
2009
|
+
let c = tracking;
|
|
1998
2010
|
let f = currentOptimisticLane;
|
|
1999
2011
|
tracking = true;
|
|
2000
2012
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
@@ -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,56 @@ 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.
|
|
2029
|
-
l = e.
|
|
2030
|
-
e.
|
|
2040
|
+
if (!false && e.Ge & CONFIG_SYNC) {
|
|
2041
|
+
l = e.Ue(l);
|
|
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.
|
|
2038
|
-
const n = e.
|
|
2049
|
+
const t = e.ut;
|
|
2050
|
+
const n = e.Ue(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
|
-
clearStatus
|
|
2056
|
+
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2057
|
+
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2058
|
+
// the flags write (create or not) stores the 0 already there.
|
|
2059
|
+
if (e.xe !== 0 || e.Nt !== undefined || e.De || e.ht || e.It || e.$e !== undefined || e._ !== undefined || e.p !== undefined || e.nt !== null) clearStatus(e, t);
|
|
2045
2060
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2046
|
-
if (e.i) GlobalQueue.
|
|
2061
|
+
if (e.i) GlobalQueue.ge(e);
|
|
2047
2062
|
} catch (t) {
|
|
2048
2063
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2049
2064
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2050
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
2065
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.Ce(e);
|
|
2051
2066
|
let n = false;
|
|
2052
2067
|
if (t instanceof NotReadyError) {
|
|
2053
|
-
e.
|
|
2054
|
-
if (GlobalQueue.
|
|
2068
|
+
e.It = true;
|
|
2069
|
+
if (GlobalQueue.Se !== null) n = GlobalQueue.Se(e, s);
|
|
2055
2070
|
}
|
|
2056
2071
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2057
|
-
if (n) GlobalQueue.
|
|
2072
|
+
if (n) GlobalQueue.Te(e);
|
|
2058
2073
|
} finally {
|
|
2059
|
-
tracking =
|
|
2074
|
+
tracking = c;
|
|
2060
2075
|
latestReadActive = E;
|
|
2061
|
-
if (
|
|
2076
|
+
if (d) stale = S;
|
|
2062
2077
|
e.Le = REACTIVE_NONE | (t ? e.Le & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2063
2078
|
context = u;
|
|
2064
2079
|
}
|
|
2065
|
-
if (!e.
|
|
2080
|
+
if (!e.De) {
|
|
2066
2081
|
trimStaleDeps(e);
|
|
2067
|
-
const s = i ? unwrapOverride(e.A) : e.
|
|
2082
|
+
const s = i ? unwrapOverride(e.A) : e.U === NOT_PENDING ? e.ke : e.U;
|
|
2068
2083
|
let u = false;
|
|
2069
2084
|
try {
|
|
2070
|
-
u = !n && o || !e.
|
|
2085
|
+
u = !n && o || !e.At || !e.At(s, l);
|
|
2071
2086
|
} catch (t) {
|
|
2072
2087
|
// A throwing user comparator is an error of this node's computation.
|
|
2073
2088
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2081,62 +2096,69 @@ function recompute(e, t = false) {
|
|
|
2081
2096
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2082
2097
|
// effect() can call its runner synchronously for the first run.
|
|
2083
2098
|
if (n && u) {
|
|
2084
|
-
e.Fe = !e.
|
|
2099
|
+
e.Fe = !e.De;
|
|
2085
2100
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2086
2101
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2087
|
-
if (!t) e.
|
|
2102
|
+
if (!t) e.Be.enqueue(n, e.Pt ??= GlobalQueue.J.bind(null, e));
|
|
2088
2103
|
}
|
|
2089
|
-
if (e.
|
|
2104
|
+
if (e.De) ; else if (u) {
|
|
2090
2105
|
const o = i ? e.A : undefined;
|
|
2091
|
-
if (t ||
|
|
2092
|
-
|
|
2106
|
+
if (t ||
|
|
2107
|
+
// Plain sync flush (no transition on either side) commits effect
|
|
2108
|
+
// values directly — the pending round-trip (queuePendingNode +
|
|
2109
|
+
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2110
|
+
// paying it per effect on the plain path is pure overhead.
|
|
2111
|
+
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2112
|
+
e.ke = l;
|
|
2093
2113
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2094
2114
|
// override unconditionally. The direct _value commit is the lane's
|
|
2095
2115
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
2096
2116
|
// commit can't clobber the fresh value.
|
|
2097
2117
|
if (i && r) {
|
|
2098
2118
|
e.A = l === undefined ? OVERRIDE_UNDEFINED : l;
|
|
2099
|
-
e.
|
|
2119
|
+
e.U = NOT_PENDING;
|
|
2100
2120
|
}
|
|
2101
2121
|
} else {
|
|
2102
|
-
e.
|
|
2122
|
+
e.U = l;
|
|
2103
2123
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2104
2124
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2105
2125
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2106
2126
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2107
2127
|
// pending value commits before effects run.
|
|
2108
|
-
if ((activeTransition || e.T) && GlobalQueue.
|
|
2128
|
+
if ((activeTransition || e.T) && GlobalQueue.ue !== null) GlobalQueue.ue(e, l);
|
|
2109
2129
|
}
|
|
2110
|
-
|
|
2130
|
+
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2131
|
+
// subscriber-less node has nothing to notify.
|
|
2132
|
+
if (e.G !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2111
2133
|
} else if (i) {
|
|
2112
2134
|
// Unchanged value (equals the override) recomputed while the override
|
|
2113
2135
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2114
2136
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2115
|
-
if (e.
|
|
2116
|
-
e.
|
|
2117
|
-
} else if (e.
|
|
2118
|
-
for (let t = e.
|
|
2119
|
-
insertIntoHeapHeight(t.
|
|
2137
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2138
|
+
e.U = l;
|
|
2139
|
+
} else if (e.Xe != a) {
|
|
2140
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
2141
|
+
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2120
2142
|
}
|
|
2121
2143
|
}
|
|
2122
2144
|
}
|
|
2123
2145
|
currentOptimisticLane = f;
|
|
2124
|
-
const T = e.
|
|
2146
|
+
const T = e.U !== NOT_PENDING || e.Qe !== null || e.He !== null || (e.xe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2125
2147
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2126
2148
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2127
2149
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2128
2150
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2129
2151
|
// _transition.
|
|
2130
|
-
T && (!t || e.
|
|
2152
|
+
T && (!t || e.xe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2131
2153
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2132
2154
|
}
|
|
2133
2155
|
|
|
2134
2156
|
function updateIfNecessary(e) {
|
|
2135
2157
|
if (e.Le & REACTIVE_CHECK) {
|
|
2136
|
-
for (let t = e.
|
|
2137
|
-
const n = t.
|
|
2138
|
-
const r = n.
|
|
2139
|
-
if (r.
|
|
2158
|
+
for (let t = e.je; t; t = t.Ke) {
|
|
2159
|
+
const n = t.Ye;
|
|
2160
|
+
const r = n.qe || n;
|
|
2161
|
+
if (r.Ue) {
|
|
2140
2162
|
updateIfNecessary(r);
|
|
2141
2163
|
}
|
|
2142
2164
|
if (e.Le & REACTIVE_DIRTY) {
|
|
@@ -2144,7 +2166,7 @@ function updateIfNecessary(e) {
|
|
|
2144
2166
|
}
|
|
2145
2167
|
}
|
|
2146
2168
|
}
|
|
2147
|
-
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.
|
|
2169
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.De && e.F < clock && !e.ut) {
|
|
2148
2170
|
recompute(e);
|
|
2149
2171
|
}
|
|
2150
2172
|
e.Le = e.Le & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -2154,37 +2176,37 @@ function computed(e, t) {
|
|
|
2154
2176
|
const n = t?.transparent ?? false;
|
|
2155
2177
|
const r = {
|
|
2156
2178
|
id: inheritId(t, n, context),
|
|
2157
|
-
|
|
2158
|
-
|
|
2179
|
+
Ge: (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),
|
|
2180
|
+
At: t?.equals != null ? t.equals : isEqual,
|
|
2159
2181
|
W: t?.unobserved,
|
|
2160
|
-
|
|
2161
|
-
|
|
2182
|
+
Et: null,
|
|
2183
|
+
Be: context?.Be ?? globalQueue,
|
|
2162
2184
|
dt: context?.dt ?? defaultContext,
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
ut: null,
|
|
2172
|
-
It: 0,
|
|
2173
|
-
k: null,
|
|
2174
|
-
_t: null,
|
|
2175
|
-
Z: context,
|
|
2185
|
+
lt: 0,
|
|
2186
|
+
Ue: e,
|
|
2187
|
+
ke: undefined,
|
|
2188
|
+
Xe: 0,
|
|
2189
|
+
nt: null,
|
|
2190
|
+
tt: undefined,
|
|
2191
|
+
et: null,
|
|
2192
|
+
je: null,
|
|
2176
2193
|
st: null,
|
|
2177
|
-
|
|
2194
|
+
Rt: 0,
|
|
2195
|
+
G: null,
|
|
2196
|
+
Tt: null,
|
|
2197
|
+
B: context,
|
|
2178
2198
|
ot: null,
|
|
2199
|
+
ct: null,
|
|
2200
|
+
it: null,
|
|
2179
2201
|
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2202
|
+
xe: STATUS_UNINITIALIZED,
|
|
2203
|
+
F: clock,
|
|
2204
|
+
U: NOT_PENDING,
|
|
2183
2205
|
He: null,
|
|
2184
|
-
|
|
2185
|
-
|
|
2206
|
+
Qe: null,
|
|
2207
|
+
ut: null,
|
|
2186
2208
|
T: null,
|
|
2187
|
-
|
|
2209
|
+
ht: false
|
|
2188
2210
|
};
|
|
2189
2211
|
setupComputedNode(r, t);
|
|
2190
2212
|
return r;
|
|
@@ -2199,44 +2221,44 @@ function computed(e, t) {
|
|
|
2199
2221
|
const s = o?.transparent ?? false;
|
|
2200
2222
|
const u = {
|
|
2201
2223
|
id: inheritId(o, s, context),
|
|
2202
|
-
|
|
2203
|
-
|
|
2224
|
+
Ge: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2225
|
+
At: false,
|
|
2204
2226
|
W: o?.unobserved,
|
|
2205
|
-
|
|
2206
|
-
|
|
2227
|
+
Et: null,
|
|
2228
|
+
Be: context?.Be ?? globalQueue,
|
|
2207
2229
|
dt: context?.dt ?? defaultContext,
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
ut: null,
|
|
2217
|
-
It: 0,
|
|
2218
|
-
k: null,
|
|
2219
|
-
_t: null,
|
|
2220
|
-
Z: context,
|
|
2230
|
+
lt: 0,
|
|
2231
|
+
Ue: e,
|
|
2232
|
+
ke: undefined,
|
|
2233
|
+
Xe: 0,
|
|
2234
|
+
nt: null,
|
|
2235
|
+
tt: undefined,
|
|
2236
|
+
et: null,
|
|
2237
|
+
je: null,
|
|
2221
2238
|
st: null,
|
|
2222
|
-
|
|
2239
|
+
Rt: 0,
|
|
2240
|
+
G: null,
|
|
2241
|
+
Tt: null,
|
|
2242
|
+
B: context,
|
|
2223
2243
|
ot: null,
|
|
2244
|
+
ct: null,
|
|
2245
|
+
it: null,
|
|
2224
2246
|
Le: REACTIVE_LAZY,
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2247
|
+
xe: STATUS_UNINITIALIZED,
|
|
2248
|
+
F: clock,
|
|
2249
|
+
U: NOT_PENDING,
|
|
2228
2250
|
He: null,
|
|
2229
|
-
|
|
2230
|
-
|
|
2251
|
+
Qe: null,
|
|
2252
|
+
ut: null,
|
|
2231
2253
|
T: null,
|
|
2232
|
-
|
|
2254
|
+
ht: false,
|
|
2233
2255
|
Fe: false,
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2256
|
+
gt: undefined,
|
|
2257
|
+
bt: t,
|
|
2258
|
+
Dt: n,
|
|
2259
|
+
ft: undefined,
|
|
2260
|
+
We: r,
|
|
2261
|
+
Nt: i
|
|
2240
2262
|
};
|
|
2241
2263
|
setupComputedNode(u, lazyOptions);
|
|
2242
2264
|
return u;
|
|
@@ -2247,24 +2269,24 @@ const lazyOptions = {
|
|
|
2247
2269
|
};
|
|
2248
2270
|
|
|
2249
2271
|
function setupComputedNode(e, t) {
|
|
2250
|
-
e.
|
|
2251
|
-
const n = context?.
|
|
2272
|
+
e.et = e;
|
|
2273
|
+
const n = context?.ze ? context.Je : context;
|
|
2252
2274
|
if (context) {
|
|
2253
|
-
const t = context.
|
|
2275
|
+
const t = context.it;
|
|
2254
2276
|
if (t === null) {
|
|
2255
|
-
context.
|
|
2277
|
+
context.it = e;
|
|
2256
2278
|
} else {
|
|
2257
|
-
e.
|
|
2258
|
-
t.
|
|
2259
|
-
context.
|
|
2279
|
+
e.ot = t;
|
|
2280
|
+
t.ct = e;
|
|
2281
|
+
context.it = e;
|
|
2260
2282
|
}
|
|
2261
2283
|
}
|
|
2262
|
-
if (n) e.
|
|
2263
|
-
if (GlobalQueue.
|
|
2284
|
+
if (n) e.Xe = n.Xe + 1;
|
|
2285
|
+
if (GlobalQueue.oe !== null) GlobalQueue.oe(e);
|
|
2264
2286
|
!t?.lazy && recompute(e, true);
|
|
2265
2287
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2266
|
-
if (!(e.
|
|
2267
|
-
e.
|
|
2288
|
+
if (!(e.xe & STATUS_PENDING) && !(e.Ge & CONFIG_NO_SNAPSHOT)) {
|
|
2289
|
+
e.me = e.ke === undefined ? NO_SNAPSHOT : e.ke;
|
|
2268
2290
|
snapshotSources.add(e);
|
|
2269
2291
|
}
|
|
2270
2292
|
}
|
|
@@ -2272,20 +2294,20 @@ function setupComputedNode(e, t) {
|
|
|
2272
2294
|
|
|
2273
2295
|
function signal(e, t, n = null) {
|
|
2274
2296
|
const r = {
|
|
2275
|
-
|
|
2276
|
-
|
|
2297
|
+
At: t?.equals != null ? t.equals : isEqual,
|
|
2298
|
+
Ge: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0),
|
|
2277
2299
|
W: t?.unobserved,
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2300
|
+
ke: e,
|
|
2301
|
+
G: null,
|
|
2302
|
+
Tt: null,
|
|
2303
|
+
F: clock,
|
|
2304
|
+
qe: n,
|
|
2305
|
+
rt: n?.nt || null,
|
|
2306
|
+
U: NOT_PENDING
|
|
2285
2307
|
};
|
|
2286
|
-
n && (n.
|
|
2287
|
-
if (snapshotCaptureActive && !(r.
|
|
2288
|
-
r.
|
|
2308
|
+
n && (n.nt = r);
|
|
2309
|
+
if (snapshotCaptureActive && !(r.Ge & CONFIG_NO_SNAPSHOT) && !((n?.xe ?? 0) & STATUS_PENDING)) {
|
|
2310
|
+
r.me = e === undefined ? NO_SNAPSHOT : e;
|
|
2289
2311
|
snapshotSources.add(r);
|
|
2290
2312
|
}
|
|
2291
2313
|
return r;
|
|
@@ -2329,11 +2351,11 @@ function isEqual(e, t) {
|
|
|
2329
2351
|
* );
|
|
2330
2352
|
* ```
|
|
2331
2353
|
*/ function untrack(e, t) {
|
|
2332
|
-
if (GlobalQueue.
|
|
2354
|
+
if (GlobalQueue.se === null && !tracking && true) return e();
|
|
2333
2355
|
const n = tracking;
|
|
2334
2356
|
tracking = false;
|
|
2335
2357
|
try {
|
|
2336
|
-
if (GlobalQueue.
|
|
2358
|
+
if (GlobalQueue.se !== null) return GlobalQueue.se(e);
|
|
2337
2359
|
return e();
|
|
2338
2360
|
} finally {
|
|
2339
2361
|
tracking = n;
|
|
@@ -2355,76 +2377,97 @@ function isEqual(e, t) {
|
|
|
2355
2377
|
}
|
|
2356
2378
|
}
|
|
2357
2379
|
|
|
2380
|
+
/**
|
|
2381
|
+
* Sentinel returned by readNodeFast when the plain-signal fast path does not
|
|
2382
|
+
* apply and the caller must fall back to the full read().
|
|
2383
|
+
*/ const READ_SLOW = Symbol("read-slow");
|
|
2384
|
+
|
|
2385
|
+
/**
|
|
2386
|
+
* read()'s plain-signal fast path as a standalone entry for hot callers
|
|
2387
|
+
* (store traps). Safe to substitute for read() only because the bail
|
|
2388
|
+
* conditions mirror read()'s prelude and fast-path guard exactly: the
|
|
2389
|
+
* latestRead and pendingCheck windows run side-effectful hooks before the
|
|
2390
|
+
* fast path, `_fn` nodes need prepareComputed, and firewall / override /
|
|
2391
|
+
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2392
|
+
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2393
|
+
*/ function readNodeFast(e) {
|
|
2394
|
+
if (latestReadActive || pendingCheckActive || e.Ue || e.qe || e.A !== undefined || e.me !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2395
|
+
let t = context;
|
|
2396
|
+
if (t?.ze) t = t.Je;
|
|
2397
|
+
if (t && tracking) link(e, t);
|
|
2398
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2358
2401
|
function read(e) {
|
|
2359
2402
|
// Handle latest() mode: read from _latestValueComputed
|
|
2360
2403
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
2361
2404
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
2362
2405
|
// than the original node (which stays "pending" while held in a transition).
|
|
2363
|
-
if (latestReadActive) return GlobalQueue.
|
|
2406
|
+
if (latestReadActive) return GlobalQueue.fe(e);
|
|
2364
2407
|
let t = context;
|
|
2365
|
-
if (t?.
|
|
2408
|
+
if (t?.ze) t = t.Je;
|
|
2366
2409
|
const n = e;
|
|
2367
|
-
const r = e.
|
|
2410
|
+
const r = e.qe;
|
|
2368
2411
|
const i = r || e;
|
|
2369
2412
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2370
2413
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2371
2414
|
// recompute don't collect into the probe.
|
|
2372
2415
|
if (pendingCheckActive) {
|
|
2373
|
-
GlobalQueue.
|
|
2374
|
-
} else if (typeof n.
|
|
2416
|
+
GlobalQueue.Ee(e, t, i, r);
|
|
2417
|
+
} else if (typeof n.Ue === "function") {
|
|
2375
2418
|
prepareComputed(e, false);
|
|
2376
2419
|
}
|
|
2377
|
-
if (!n.
|
|
2420
|
+
if (!n.Ue && i === e && e.A === undefined && e.me === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2378
2421
|
if (t && tracking) link(e, t);
|
|
2379
|
-
return !t || e.
|
|
2422
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2380
2423
|
}
|
|
2381
2424
|
if (t && tracking) {
|
|
2382
2425
|
link(e, t, pendingCheckActive);
|
|
2383
|
-
if (i.
|
|
2426
|
+
if (i.Ue) {
|
|
2384
2427
|
const n = queueFor(e);
|
|
2385
|
-
if (i.
|
|
2428
|
+
if (i.Xe >= n.P) {
|
|
2386
2429
|
markNode(t);
|
|
2387
2430
|
markHeap(n);
|
|
2388
2431
|
updateIfNecessary(i);
|
|
2389
2432
|
}
|
|
2390
|
-
const r = i.
|
|
2433
|
+
const r = i.Xe;
|
|
2391
2434
|
// parent check is shallow, might need to be recursive
|
|
2392
|
-
if (r >= t.
|
|
2393
|
-
t.
|
|
2435
|
+
if (r >= t.Xe && e.B !== t) {
|
|
2436
|
+
t.Xe = r + 1;
|
|
2394
2437
|
}
|
|
2395
2438
|
}
|
|
2396
2439
|
}
|
|
2397
|
-
if (i.
|
|
2440
|
+
if (i.xe & STATUS_PENDING) {
|
|
2398
2441
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2399
2442
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2400
2443
|
// is installed): under a lane, only same-lane pending async without an
|
|
2401
2444
|
// active override throws.
|
|
2402
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2445
|
+
if (currentOptimisticLane === null || GlobalQueue.Ne(i)) {
|
|
2403
2446
|
if (!tracking && e !== t) link(e, t);
|
|
2404
|
-
throw i.
|
|
2447
|
+
throw i.De;
|
|
2405
2448
|
}
|
|
2406
|
-
} else if (t && i !== e && i.
|
|
2449
|
+
} else if (t && i !== e && i.xe & STATUS_UNINITIALIZED) {
|
|
2407
2450
|
if (!tracking && e !== t) link(e, t);
|
|
2408
|
-
throw i.
|
|
2409
|
-
} else if (!t && i.
|
|
2410
|
-
throw i.
|
|
2451
|
+
throw i.De;
|
|
2452
|
+
} else if (!t && i.xe & STATUS_UNINITIALIZED) {
|
|
2453
|
+
throw i.De;
|
|
2411
2454
|
}
|
|
2412
2455
|
}
|
|
2413
|
-
if (e.
|
|
2456
|
+
if (e.Ue && e.xe & STATUS_ERROR) {
|
|
2414
2457
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2415
2458
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2416
2459
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2417
2460
|
// - el._time < clock: only on a later cycle than the one the error was found
|
|
2418
|
-
if (tracking && !pendingCheckActive && e.
|
|
2461
|
+
if (tracking && !pendingCheckActive && e.F < clock) {
|
|
2419
2462
|
recompute(e);
|
|
2420
2463
|
return read(e);
|
|
2421
|
-
} else throw e.
|
|
2464
|
+
} else throw e.De;
|
|
2422
2465
|
}
|
|
2423
|
-
if (snapshotCaptureActive && t && t.
|
|
2424
|
-
const n = e.
|
|
2466
|
+
if (snapshotCaptureActive && t && t.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2467
|
+
const n = e.me;
|
|
2425
2468
|
if (n !== undefined) {
|
|
2426
2469
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2427
|
-
const i = e.
|
|
2470
|
+
const i = e.U !== NOT_PENDING ? e.U : e.ke;
|
|
2428
2471
|
if (i !== r) t.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
2429
2472
|
return r;
|
|
2430
2473
|
}
|
|
@@ -2440,18 +2483,18 @@ function read(e) {
|
|
|
2440
2483
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2441
2484
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2442
2485
|
// engine — a non-null lane implies it is installed.)
|
|
2443
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2444
|
-
return e.
|
|
2486
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.he(e, i, t)) {
|
|
2487
|
+
return e.ke;
|
|
2445
2488
|
}
|
|
2446
2489
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
2447
2490
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2448
2491
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2449
2492
|
// (The lane-context clause lives with the engine.)
|
|
2450
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.
|
|
2493
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.U === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.ke : e.U;
|
|
2451
2494
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2452
2495
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2453
2496
|
if (pendingCheckActive) GlobalQueue.de(e, o);
|
|
2454
|
-
if (!t && i === e && typeof n.
|
|
2497
|
+
if (!t && i === e && typeof n.Ue === "function" && e.Ge & CONFIG_AUTO_DISPOSE && !(i.xe & STATUS_PENDING) && !e.G) {
|
|
2455
2498
|
unobserved(e);
|
|
2456
2499
|
}
|
|
2457
2500
|
return o;
|
|
@@ -2463,17 +2506,20 @@ function setSignal(e, t) {
|
|
|
2463
2506
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2464
2507
|
// _overrideValue slot, and every module that creates one installs the
|
|
2465
2508
|
// engine first.
|
|
2466
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2467
|
-
const n = e.
|
|
2509
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue._e(e, t);
|
|
2510
|
+
const n = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2468
2511
|
if (typeof t === "function") t = t(n);
|
|
2469
2512
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2470
2513
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2471
|
-
const r = !!(e.
|
|
2514
|
+
const r = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(n, t);
|
|
2472
2515
|
if (!r) return t;
|
|
2473
|
-
if (e.
|
|
2474
|
-
e.
|
|
2475
|
-
|
|
2476
|
-
|
|
2516
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2517
|
+
e.U = t;
|
|
2518
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2519
|
+
// neither companion present the call is a guaranteed no-op (companions are
|
|
2520
|
+
// only ever created, never removed, and creating one installs the hook).
|
|
2521
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2522
|
+
e.F = clock;
|
|
2477
2523
|
insertSubs(e);
|
|
2478
2524
|
schedule();
|
|
2479
2525
|
return t;
|
|
@@ -2487,7 +2533,7 @@ function setSignal(e, t) {
|
|
|
2487
2533
|
* cleanup point.
|
|
2488
2534
|
*/ function suppressComputedRecompute(e) {
|
|
2489
2535
|
deleteFromHeap(e, queueFor(e));
|
|
2490
|
-
if (!(e.Le & REACTIVE_MANUAL_WRITE) && e.
|
|
2536
|
+
if (!(e.Le & REACTIVE_MANUAL_WRITE) && e.U === NOT_PENDING) {
|
|
2491
2537
|
queuePendingNode(e);
|
|
2492
2538
|
schedule();
|
|
2493
2539
|
}
|
|
@@ -2570,7 +2616,7 @@ function staleValues(e, t = true) {
|
|
|
2570
2616
|
if (!t) {
|
|
2571
2617
|
return;
|
|
2572
2618
|
}
|
|
2573
|
-
if (typeof t.
|
|
2619
|
+
if (typeof t.Ue === "function" && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2574
2620
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2575
2621
|
// same question: mark it so the recompute classifies any resulting
|
|
2576
2622
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2630,11 +2676,11 @@ function wireExternalSource(e) {
|
|
|
2630
2676
|
equals: false,
|
|
2631
2677
|
ownedWrite: true
|
|
2632
2678
|
});
|
|
2633
|
-
const n = externalSourceConfig.factory(e.
|
|
2679
|
+
const n = externalSourceConfig.factory(e.Ue, () => {
|
|
2634
2680
|
setSignal(t, undefined);
|
|
2635
2681
|
});
|
|
2636
2682
|
cleanup(() => n.dispose());
|
|
2637
|
-
e.
|
|
2683
|
+
e.Ue = e => {
|
|
2638
2684
|
read(t);
|
|
2639
2685
|
return n.track(e);
|
|
2640
2686
|
};
|
|
@@ -2648,8 +2694,8 @@ function externalUntrack(e) {
|
|
|
2648
2694
|
// removed on reset) so core's null checks stay equivalent to the old
|
|
2649
2695
|
// `externalSourceConfig` truthiness checks.
|
|
2650
2696
|
function syncExternalHooks() {
|
|
2651
|
-
GlobalQueue.
|
|
2652
|
-
GlobalQueue.
|
|
2697
|
+
GlobalQueue.oe = externalSourceConfig ? wireExternalSource : null;
|
|
2698
|
+
GlobalQueue.se = externalSourceConfig ? externalUntrack : null;
|
|
2653
2699
|
}
|
|
2654
2700
|
|
|
2655
2701
|
function enableExternalSource(e) {
|
|
@@ -2756,9 +2802,9 @@ function isUndefined(e) {
|
|
|
2756
2802
|
*/
|
|
2757
2803
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, t) {
|
|
2758
2804
|
const n = e.A !== NOT_PENDING;
|
|
2759
|
-
const r = n ? unwrapOverride(e.A) : e.
|
|
2805
|
+
const r = n ? unwrapOverride(e.A) : e.ke;
|
|
2760
2806
|
if (typeof t === "function") t = t(r);
|
|
2761
|
-
const i = !!(e.
|
|
2807
|
+
const i = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(r, t);
|
|
2762
2808
|
if (!i) {
|
|
2763
2809
|
// Same-value write with an active override still entangles the current
|
|
2764
2810
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2772,7 +2818,7 @@ function isUndefined(e) {
|
|
|
2772
2818
|
// No revert target is stashed: while the override is active every reader
|
|
2773
2819
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
2774
2820
|
// reverting is just dropping the override — _value is already correct.
|
|
2775
|
-
else globalQueue.D.
|
|
2821
|
+
else globalQueue.D.v.push(e);
|
|
2776
2822
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
2777
2823
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
2778
2824
|
// which a shared subscriber can merge across transactions (#2912).
|
|
@@ -2783,8 +2829,10 @@ function isUndefined(e) {
|
|
|
2783
2829
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
2784
2830
|
// writes off the optimistic path into permanent commits (#2898).
|
|
2785
2831
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2786
|
-
|
|
2787
|
-
|
|
2832
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2833
|
+
// neither companion present the call is a guaranteed no-op.
|
|
2834
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2835
|
+
e.F = clock;
|
|
2788
2836
|
insertSubs(e, true);
|
|
2789
2837
|
schedule();
|
|
2790
2838
|
return t;
|
|
@@ -2795,9 +2843,9 @@ function isUndefined(e) {
|
|
|
2795
2843
|
* while one of its optimistic nodes holds an active override that is still
|
|
2796
2844
|
* pending on real (non-affects-sentinel) async.
|
|
2797
2845
|
*/ function transitionBlocked(e) {
|
|
2798
|
-
for (let t = 0; t < e.
|
|
2799
|
-
const n = e.
|
|
2800
|
-
if (hasActiveOverride(n) && "
|
|
2846
|
+
for (let t = 0; t < e.v.length; t++) {
|
|
2847
|
+
const n = e.v[t];
|
|
2848
|
+
if (hasActiveOverride(n) && "xe" in n && n.xe & STATUS_PENDING && n.De instanceof NotReadyError) {
|
|
2801
2849
|
return true;
|
|
2802
2850
|
}
|
|
2803
2851
|
}
|
|
@@ -2815,10 +2863,10 @@ function resolveOptimisticNodes(e) {
|
|
|
2815
2863
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2816
2864
|
// override-covered authoritative values hold in _pendingValue and
|
|
2817
2865
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2818
|
-
if (!(t.
|
|
2866
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
2819
2867
|
const r = t.A;
|
|
2820
2868
|
t.A = NOT_PENDING;
|
|
2821
|
-
if (r !== NOT_PENDING && t.
|
|
2869
|
+
if (r !== NOT_PENDING && t.ke !== unwrapOverride(r)) insertSubs(t, true);
|
|
2822
2870
|
t.T = null;
|
|
2823
2871
|
t.R = null;
|
|
2824
2872
|
}
|
|
@@ -2827,9 +2875,9 @@ function resolveOptimisticNodes(e) {
|
|
|
2827
2875
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2828
2876
|
for (let n = 0; n < t; n++) {
|
|
2829
2877
|
const t = e[n];
|
|
2830
|
-
if (t.
|
|
2878
|
+
if (t._ || t.p) GlobalQueue.ce(t);
|
|
2831
2879
|
const r = t.t;
|
|
2832
|
-
if (r && (r.
|
|
2880
|
+
if (r && (r._ === t || r.p === t)) GlobalQueue.ce(r);
|
|
2833
2881
|
}
|
|
2834
2882
|
e.splice(0, t);
|
|
2835
2883
|
}
|
|
@@ -2882,10 +2930,10 @@ function cleanupCompletedLanes(e) {
|
|
|
2882
2930
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2883
2931
|
* is recorded for replay at commit.
|
|
2884
2932
|
*/ function gatedRead(e, t, n) {
|
|
2885
|
-
if (latestReadActive || e.
|
|
2933
|
+
if (latestReadActive || e.U === NOT_PENDING || e.Ue || t !== e && !(t.Le & REACTIVE_MANUAL_WRITE)) {
|
|
2886
2934
|
return false;
|
|
2887
2935
|
}
|
|
2888
|
-
activeTransition.
|
|
2936
|
+
activeTransition.Y.add(n);
|
|
2889
2937
|
return true;
|
|
2890
2938
|
}
|
|
2891
2939
|
|
|
@@ -2893,7 +2941,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2893
2941
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2894
2942
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2895
2943
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2896
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.
|
|
2944
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.xe & STATUS_PENDING);
|
|
2897
2945
|
}
|
|
2898
2946
|
|
|
2899
2947
|
/**
|
|
@@ -2902,8 +2950,8 @@ function cleanupCompletedLanes(e) {
|
|
|
2902
2950
|
* can run before its OPT-dirty child propagates).
|
|
2903
2951
|
*/ function recomputeLane(e, t) {
|
|
2904
2952
|
if (t) return resolveLane(e) ?? null;
|
|
2905
|
-
for (let t = e.
|
|
2906
|
-
const n = t.
|
|
2953
|
+
for (let t = e.je; t; t = t.Ke) {
|
|
2954
|
+
const n = t.Ye;
|
|
2907
2955
|
if (n.Le & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2908
2956
|
const t = resolveLane(n);
|
|
2909
2957
|
if (t) {
|
|
@@ -2921,7 +2969,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2921
2969
|
if (t.o !== e) {
|
|
2922
2970
|
t.u.add(e);
|
|
2923
2971
|
e.i = t;
|
|
2924
|
-
GlobalQueue.
|
|
2972
|
+
GlobalQueue.le !== null && GlobalQueue.le(t.o);
|
|
2925
2973
|
}
|
|
2926
2974
|
}
|
|
2927
2975
|
|
|
@@ -2929,13 +2977,13 @@ function cleanupCompletedLanes(e) {
|
|
|
2929
2977
|
const t = resolveLane(e);
|
|
2930
2978
|
if (t) {
|
|
2931
2979
|
t.u.delete(e);
|
|
2932
|
-
GlobalQueue.
|
|
2980
|
+
GlobalQueue.le !== null && GlobalQueue.le(t.o);
|
|
2933
2981
|
}
|
|
2934
2982
|
}
|
|
2935
2983
|
|
|
2936
2984
|
function trackOptimisticStore(e) {
|
|
2937
2985
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
2938
|
-
globalQueue.D.
|
|
2986
|
+
globalQueue.D.V.add(e);
|
|
2939
2987
|
schedule();
|
|
2940
2988
|
}
|
|
2941
2989
|
|
|
@@ -2944,19 +2992,19 @@ function trackOptimisticStore(e) {
|
|
|
2944
2992
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
2945
2993
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
2946
2994
|
*/ function installOptimisticEngine() {
|
|
2947
|
-
if (GlobalQueue.
|
|
2948
|
-
GlobalQueue.
|
|
2949
|
-
GlobalQueue.
|
|
2950
|
-
GlobalQueue.
|
|
2951
|
-
GlobalQueue.
|
|
2952
|
-
GlobalQueue.
|
|
2953
|
-
GlobalQueue.
|
|
2954
|
-
GlobalQueue.
|
|
2955
|
-
GlobalQueue.
|
|
2995
|
+
if (GlobalQueue._e !== null) return;
|
|
2996
|
+
GlobalQueue._e = optimisticWrite;
|
|
2997
|
+
GlobalQueue.pe = resolveOptimisticNodes;
|
|
2998
|
+
GlobalQueue.Re = transitionBlocked;
|
|
2999
|
+
GlobalQueue.Ie = cleanupCompletedLanes;
|
|
3000
|
+
GlobalQueue.Ae = runLaneEffects;
|
|
3001
|
+
GlobalQueue.he = gatedRead;
|
|
3002
|
+
GlobalQueue.Ne = laneSuspends;
|
|
3003
|
+
GlobalQueue.ye = laneReadsCommitted;
|
|
2956
3004
|
GlobalQueue.Pe = recomputeLane;
|
|
2957
|
-
GlobalQueue.
|
|
2958
|
-
GlobalQueue.
|
|
2959
|
-
GlobalQueue.
|
|
3005
|
+
GlobalQueue.Ce = laneAsyncPending;
|
|
3006
|
+
GlobalQueue.ge = laneAsyncSettled;
|
|
3007
|
+
GlobalQueue.be = trackOptimisticStore;
|
|
2960
3008
|
}
|
|
2961
3009
|
|
|
2962
3010
|
/**
|
|
@@ -2975,21 +3023,21 @@ let pendingProbe = null;
|
|
|
2975
3023
|
* Get or create the pending signal for a node (lazy).
|
|
2976
3024
|
* Used by isPending() to track pending state reactively.
|
|
2977
3025
|
*/ function getPendingSignal(e) {
|
|
2978
|
-
if (!e.
|
|
3026
|
+
if (!e._) {
|
|
2979
3027
|
// Start false, write true if pending - ensures reversion returns to false
|
|
2980
|
-
e.
|
|
3028
|
+
e._ = optimisticSignal(false, {
|
|
2981
3029
|
ownedWrite: true
|
|
2982
3030
|
});
|
|
2983
|
-
e.
|
|
2984
|
-
if (computePendingState(e)) setSignal(e.
|
|
3031
|
+
e._.t = e;
|
|
3032
|
+
if (computePendingState(e)) setSignal(e._, true);
|
|
2985
3033
|
}
|
|
2986
|
-
return e.
|
|
3034
|
+
return e._;
|
|
2987
3035
|
}
|
|
2988
3036
|
|
|
2989
3037
|
function collectPendingSources(e) {
|
|
2990
3038
|
if (!pendingProbe) return;
|
|
2991
3039
|
pendingProbe.sources.add(e);
|
|
2992
|
-
const t = e.
|
|
3040
|
+
const t = e.qe || e;
|
|
2993
3041
|
if (t !== e) pendingProbe.sources.add(t);
|
|
2994
3042
|
}
|
|
2995
3043
|
|
|
@@ -3013,26 +3061,26 @@ function collectPendingSources(e) {
|
|
|
3013
3061
|
* (`_pendingObserver`) are skipped so an `isPending` wrapper memo never
|
|
3014
3062
|
* inherits the coverage it reports on.
|
|
3015
3063
|
*/ function markWalk(e, t) {
|
|
3016
|
-
if (e.
|
|
3064
|
+
if (e.k) return true;
|
|
3017
3065
|
// A real error outranks an inherited mark (A16/A24c): an errored node
|
|
3018
3066
|
// answers probes with its error, not a coverage verdict, and coverage does
|
|
3019
3067
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3020
3068
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3021
3069
|
// pending (the count check above), also matching.
|
|
3022
|
-
if (e.
|
|
3070
|
+
if (e.xe & STATUS_ERROR) return false;
|
|
3023
3071
|
if (t.has(e)) return false;
|
|
3024
3072
|
t.add(e);
|
|
3025
|
-
const n = e.
|
|
3073
|
+
const n = e.qe;
|
|
3026
3074
|
if (n && markWalk(n, t)) return true;
|
|
3027
3075
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3028
3076
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3029
3077
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3030
3078
|
// latch a stale verdict on the companion.
|
|
3031
3079
|
const r = e;
|
|
3032
|
-
const i = r.Le & REACTIVE_RECOMPUTING_DEPS ? r.
|
|
3080
|
+
const i = r.Le & REACTIVE_RECOMPUTING_DEPS ? r.st : undefined;
|
|
3033
3081
|
if (i !== null) {
|
|
3034
|
-
for (let e = r.
|
|
3035
|
-
if (!e.Ot && markWalk(e.
|
|
3082
|
+
for (let e = r.je ?? null; e !== null; e = e.Ke) {
|
|
3083
|
+
if (!e.Ot && markWalk(e.Ye, t)) return true;
|
|
3036
3084
|
if (e === i) break;
|
|
3037
3085
|
}
|
|
3038
3086
|
}
|
|
@@ -3045,14 +3093,14 @@ function collectPendingSources(e) {
|
|
|
3045
3093
|
|
|
3046
3094
|
function quietPending(e) {
|
|
3047
3095
|
if (e.$e) {
|
|
3048
|
-
for (const t of e.$e) if (!t.
|
|
3096
|
+
for (const t of e.$e) if (!t.ht) return false;
|
|
3049
3097
|
return true;
|
|
3050
3098
|
}
|
|
3051
|
-
return e.
|
|
3099
|
+
return e.ht;
|
|
3052
3100
|
}
|
|
3053
3101
|
|
|
3054
3102
|
function newQuestionInFlight(e) {
|
|
3055
|
-
return !!(e.
|
|
3103
|
+
return !!(e.xe & STATUS_PENDING) && !(e.xe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3056
3104
|
}
|
|
3057
3105
|
|
|
3058
3106
|
function computePendingState(e) {
|
|
@@ -3062,37 +3110,37 @@ function computePendingState(e) {
|
|
|
3062
3110
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3063
3111
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3064
3112
|
if (markCovered(e)) return true;
|
|
3065
|
-
const n = e.
|
|
3113
|
+
const n = e.qe;
|
|
3066
3114
|
if (e.t) {
|
|
3067
3115
|
const t = e.t;
|
|
3068
|
-
const n = t.
|
|
3116
|
+
const n = t.qe || t;
|
|
3069
3117
|
return newQuestionInFlight(n);
|
|
3070
3118
|
}
|
|
3071
|
-
if (n && e.
|
|
3072
|
-
return !!(n.Le & REACTIVE_MANUAL_WRITE) || !n.
|
|
3119
|
+
if (n && e.U !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3120
|
+
return !!(n.Le & REACTIVE_MANUAL_WRITE) || !n.ut && !(n.xe & STATUS_PENDING) || !!(n.xe & STATUS_PENDING) && quietPending(n);
|
|
3073
3121
|
}
|
|
3074
|
-
if (e.
|
|
3075
|
-
if (hasActiveOverride(e)) return !e.
|
|
3122
|
+
if (e.U !== NOT_PENDING && !(t.xe & STATUS_UNINITIALIZED)) {
|
|
3123
|
+
if (hasActiveOverride(e)) return !e.At || !e.At(e.U, unwrapOverride(e.A));
|
|
3076
3124
|
return true;
|
|
3077
3125
|
}
|
|
3078
3126
|
return newQuestionInFlight(t);
|
|
3079
3127
|
}
|
|
3080
3128
|
|
|
3081
3129
|
function syncCompanions(e, t) {
|
|
3082
|
-
if (e.
|
|
3083
|
-
if (e.
|
|
3130
|
+
if (e._) updatePendingSignal(e);
|
|
3131
|
+
if (e.p) setSignal(e.p, t);
|
|
3084
3132
|
}
|
|
3085
3133
|
|
|
3086
3134
|
function updatePendingSignal(e) {
|
|
3087
|
-
if (e.
|
|
3088
|
-
setSignal(e.
|
|
3135
|
+
if (e._) {
|
|
3136
|
+
setSignal(e._, computePendingState(e));
|
|
3089
3137
|
}
|
|
3090
|
-
if (e.
|
|
3138
|
+
if (e.p) updatePendingSignal(e.p);
|
|
3091
3139
|
}
|
|
3092
3140
|
|
|
3093
3141
|
function updateChildCompanions(e) {
|
|
3094
|
-
for (let t = e.
|
|
3095
|
-
if (t.
|
|
3142
|
+
for (let t = e.nt; t !== null; t = t.rt) {
|
|
3143
|
+
if (t._ || t.p) updatePendingSignal(t);
|
|
3096
3144
|
}
|
|
3097
3145
|
}
|
|
3098
3146
|
|
|
@@ -3110,9 +3158,9 @@ function updateChildCompanions(e) {
|
|
|
3110
3158
|
const visit = e => {
|
|
3111
3159
|
if (r.has(e)) return;
|
|
3112
3160
|
r.add(e);
|
|
3113
|
-
if (e.
|
|
3114
|
-
for (let t = e.
|
|
3115
|
-
for (let t = e.
|
|
3161
|
+
if (e._ || e.p) n(e);
|
|
3162
|
+
for (let t = e.G; t !== null; t = t.ve) visit(t.Ve);
|
|
3163
|
+
for (let t = e.nt ?? null; t !== null; t = t.rt) {
|
|
3116
3164
|
visit(t);
|
|
3117
3165
|
}
|
|
3118
3166
|
};
|
|
@@ -3120,20 +3168,20 @@ function updateChildCompanions(e) {
|
|
|
3120
3168
|
}
|
|
3121
3169
|
|
|
3122
3170
|
function snapCompanionsToState(e) {
|
|
3123
|
-
const t = e.
|
|
3171
|
+
const t = e._;
|
|
3124
3172
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3125
3173
|
const n = computePendingState(e);
|
|
3126
|
-
if (t.
|
|
3127
|
-
t.
|
|
3128
|
-
t.
|
|
3129
|
-
t.
|
|
3174
|
+
if (t.ke !== n || t.U !== NOT_PENDING) {
|
|
3175
|
+
t.ke = n;
|
|
3176
|
+
t.U = NOT_PENDING;
|
|
3177
|
+
t.F = clock;
|
|
3130
3178
|
insertSubs(t);
|
|
3131
3179
|
schedule();
|
|
3132
3180
|
}
|
|
3133
3181
|
}
|
|
3134
|
-
const n = e.
|
|
3182
|
+
const n = e.p;
|
|
3135
3183
|
if (n && !(n.Le & REACTIVE_DISPOSED)) {
|
|
3136
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.
|
|
3184
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.ke, e.ke) && !(n.Le & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3137
3185
|
n.Le |= REACTIVE_DIRTY;
|
|
3138
3186
|
insertIntoHeap(n, queueFor(n));
|
|
3139
3187
|
insertSubs(n);
|
|
@@ -3144,7 +3192,7 @@ function snapCompanionsToState(e) {
|
|
|
3144
3192
|
}
|
|
3145
3193
|
|
|
3146
3194
|
function getLatestValueComputed(e) {
|
|
3147
|
-
if (!e.
|
|
3195
|
+
if (!e.p) {
|
|
3148
3196
|
const t = latestReadActive;
|
|
3149
3197
|
setLatestReadActive(false);
|
|
3150
3198
|
const n = pendingCheckActive;
|
|
@@ -3152,21 +3200,21 @@ function getLatestValueComputed(e) {
|
|
|
3152
3200
|
const r = context;
|
|
3153
3201
|
setContextInternal(null);
|
|
3154
3202
|
// Detach from owner so it isn't disposed with effects
|
|
3155
|
-
e.
|
|
3156
|
-
e.
|
|
3203
|
+
e.p = optimisticComputed(() => read(e));
|
|
3204
|
+
e.p.t = e;
|
|
3157
3205
|
// Parent-child lane relationship
|
|
3158
3206
|
setContextInternal(r);
|
|
3159
3207
|
setPendingCheckActive(n);
|
|
3160
3208
|
setLatestReadActive(t);
|
|
3161
3209
|
}
|
|
3162
|
-
return e.
|
|
3210
|
+
return e.p;
|
|
3163
3211
|
}
|
|
3164
3212
|
|
|
3165
3213
|
/** The latest()-mode read path, installed as GlobalQueue._latestRead. */ function latestRead(e) {
|
|
3166
3214
|
const t = getLatestValueComputed(e);
|
|
3167
3215
|
const n = latestReadActive;
|
|
3168
3216
|
setLatestReadActive(false);
|
|
3169
|
-
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
3217
|
+
const r = e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.ke;
|
|
3170
3218
|
let i;
|
|
3171
3219
|
try {
|
|
3172
3220
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -3175,18 +3223,18 @@ function getLatestValueComputed(e) {
|
|
|
3175
3223
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3176
3224
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3177
3225
|
const e = queueFor(t);
|
|
3178
|
-
if (t.
|
|
3226
|
+
if (t.Xe >= e.P && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3179
3227
|
markHeap(e);
|
|
3180
3228
|
prepareComputed(t, true);
|
|
3181
3229
|
}
|
|
3182
3230
|
i = read(t);
|
|
3183
3231
|
} catch (t) {
|
|
3184
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3232
|
+
if (t instanceof NotReadyError && (!context || !(e.xe & STATUS_UNINITIALIZED))) return r;
|
|
3185
3233
|
throw t;
|
|
3186
3234
|
} finally {
|
|
3187
3235
|
setLatestReadActive(n);
|
|
3188
3236
|
}
|
|
3189
|
-
if (t.
|
|
3237
|
+
if (t.xe & STATUS_PENDING) return r;
|
|
3190
3238
|
if (stale && currentOptimisticLane && t.i) {
|
|
3191
3239
|
const e = findLane(t.i);
|
|
3192
3240
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3198,18 +3246,18 @@ function getLatestValueComputed(e) {
|
|
|
3198
3246
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
3199
3247
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
3200
3248
|
// other transition's committed view, matching read()'s own selection.
|
|
3201
|
-
if (t.
|
|
3249
|
+
if (t.U !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.T && activeTransition !== t.T)) return t.U;
|
|
3202
3250
|
return i;
|
|
3203
3251
|
}
|
|
3204
3252
|
|
|
3205
3253
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3206
3254
|
setPendingCheckActive(false);
|
|
3207
|
-
if (typeof e.
|
|
3208
|
-
const i = n.
|
|
3255
|
+
if (typeof e.Ue === "function") prepareComputed(e, true);
|
|
3256
|
+
const i = n.xe;
|
|
3209
3257
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3210
3258
|
if (tracking && e !== t) link(e, t);
|
|
3211
3259
|
setPendingCheckActive(true);
|
|
3212
|
-
throw n.
|
|
3260
|
+
throw n.De;
|
|
3213
3261
|
}
|
|
3214
3262
|
collectPendingSources(e);
|
|
3215
3263
|
if (r) collectPendingSources(r);
|
|
@@ -3217,14 +3265,14 @@ function getLatestValueComputed(e) {
|
|
|
3217
3265
|
}
|
|
3218
3266
|
|
|
3219
3267
|
function recordFreshRead(e, t) {
|
|
3220
|
-
if (pendingProbe !== null && e.
|
|
3268
|
+
if (pendingProbe !== null && e.U !== NOT_PENDING && t === e.U) pendingProbe.freshReads.add(e);
|
|
3221
3269
|
}
|
|
3222
3270
|
|
|
3223
3271
|
function applyReask(e, t) {
|
|
3224
|
-
const n = !!(e.
|
|
3225
|
-
const r = t && !(n && !e.
|
|
3226
|
-
const i = n && e.
|
|
3227
|
-
e.
|
|
3272
|
+
const n = !!(e.xe & STATUS_PENDING);
|
|
3273
|
+
const r = t && !(n && !e.ht);
|
|
3274
|
+
const i = n && e.ht !== r;
|
|
3275
|
+
e.ht = r;
|
|
3228
3276
|
return i;
|
|
3229
3277
|
}
|
|
3230
3278
|
|
|
@@ -3264,7 +3312,7 @@ function isPending(e) {
|
|
|
3264
3312
|
} catch (e) {
|
|
3265
3313
|
collectPending();
|
|
3266
3314
|
if (e instanceof NotReadyError) {
|
|
3267
|
-
const t = !!(e.source?.
|
|
3315
|
+
const t = !!(e.source?.xe & STATUS_UNINITIALIZED);
|
|
3268
3316
|
if (r.found && !t) return true;
|
|
3269
3317
|
if (context && t) throw e;
|
|
3270
3318
|
}
|
|
@@ -3278,25 +3326,25 @@ function isPending(e) {
|
|
|
3278
3326
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
3279
3327
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
3280
3328
|
// direct calls used, so behavior is identical once this module loads.
|
|
3281
|
-
GlobalQueue.
|
|
3329
|
+
GlobalQueue.ue = syncCompanions;
|
|
3282
3330
|
|
|
3283
|
-
GlobalQueue.
|
|
3331
|
+
GlobalQueue.le = updatePendingSignal;
|
|
3284
3332
|
|
|
3285
3333
|
GlobalQueue.ae = updateChildCompanions;
|
|
3286
3334
|
|
|
3287
|
-
GlobalQueue.
|
|
3335
|
+
GlobalQueue.ce = snapCompanionsToState;
|
|
3288
3336
|
|
|
3289
|
-
GlobalQueue.
|
|
3337
|
+
GlobalQueue.fe = latestRead;
|
|
3290
3338
|
|
|
3291
|
-
GlobalQueue.
|
|
3339
|
+
GlobalQueue.Ee = pendingCheckRead;
|
|
3292
3340
|
|
|
3293
3341
|
GlobalQueue.de = recordFreshRead;
|
|
3294
3342
|
|
|
3295
|
-
GlobalQueue.
|
|
3343
|
+
GlobalQueue.Se = applyReask;
|
|
3296
3344
|
|
|
3297
|
-
GlobalQueue.
|
|
3345
|
+
GlobalQueue.Te = repollDownstreamVerdicts;
|
|
3298
3346
|
|
|
3299
|
-
GlobalQueue.
|
|
3347
|
+
GlobalQueue.Oe = witnessAffects;
|
|
3300
3348
|
|
|
3301
3349
|
/**
|
|
3302
3350
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3306,16 +3354,16 @@ GlobalQueue.pe = witnessAffects;
|
|
|
3306
3354
|
const i = !!r?.user;
|
|
3307
3355
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3308
3356
|
recompute(o, true);
|
|
3309
|
-
!r?.defer && (o.
|
|
3357
|
+
!r?.defer && (o.We === EFFECT_USER || r?.schedule ? o.Be.enqueue(o.We, runEffect.bind(null, o)) : runEffect(o));
|
|
3310
3358
|
}
|
|
3311
3359
|
|
|
3312
3360
|
function notifyEffectStatus(e, t) {
|
|
3313
3361
|
// Use passed values if provided, otherwise read from node
|
|
3314
|
-
const n = e !== undefined ? e : this.
|
|
3315
|
-
const r = t !== undefined ? t : this.
|
|
3362
|
+
const n = e !== undefined ? e : this.xe;
|
|
3363
|
+
const r = t !== undefined ? t : this.De;
|
|
3316
3364
|
if (n & STATUS_ERROR) {
|
|
3317
|
-
this.
|
|
3318
|
-
if (this.
|
|
3365
|
+
this.Be.notify(this, STATUS_PENDING, 0);
|
|
3366
|
+
if (this.We === EFFECT_USER) {
|
|
3319
3367
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3320
3368
|
// queue it like the effect function. It runs in the same imperative,
|
|
3321
3369
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3325,18 +3373,18 @@ function notifyEffectStatus(e, t) {
|
|
|
3325
3373
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3326
3374
|
// `status` arg without node-state writes) don't queue: the status
|
|
3327
3375
|
// re-propagates unblocked at commit.
|
|
3328
|
-
if (this.
|
|
3376
|
+
if (this.xe & STATUS_ERROR) {
|
|
3329
3377
|
this.Fe = true;
|
|
3330
|
-
this.
|
|
3378
|
+
this.Be.enqueue(this.We, this.Pt ??= runEffect.bind(null, this));
|
|
3331
3379
|
}
|
|
3332
3380
|
return;
|
|
3333
3381
|
}
|
|
3334
|
-
if (!this.
|
|
3382
|
+
if (!this.Be.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3335
3383
|
haltReactivity(unwrapStatusError(r));
|
|
3336
3384
|
throw r;
|
|
3337
3385
|
}
|
|
3338
|
-
} else if (this.
|
|
3339
|
-
this.
|
|
3386
|
+
} else if (this.We === EFFECT_RENDER) {
|
|
3387
|
+
this.Be.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3340
3388
|
}
|
|
3341
3389
|
}
|
|
3342
3390
|
|
|
@@ -3352,46 +3400,46 @@ function runEffect(e) {
|
|
|
3352
3400
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3353
3401
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3354
3402
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3355
|
-
if (e.
|
|
3356
|
-
const t = unwrapStatusError(e.
|
|
3357
|
-
e.
|
|
3403
|
+
if (e.xe & STATUS_ERROR && e.We === EFFECT_USER) {
|
|
3404
|
+
const t = unwrapStatusError(e.De);
|
|
3405
|
+
e.gt = e.ke;
|
|
3358
3406
|
e.Fe = false;
|
|
3359
3407
|
try {
|
|
3360
|
-
e.
|
|
3361
|
-
const t = e.
|
|
3362
|
-
e.
|
|
3408
|
+
e.Dt ? e.Dt(t, () => {
|
|
3409
|
+
const t = e.ft;
|
|
3410
|
+
e.ft = undefined;
|
|
3363
3411
|
t?.();
|
|
3364
3412
|
}) : console.error(t);
|
|
3365
3413
|
} catch (t) {
|
|
3366
|
-
if (!e.
|
|
3414
|
+
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3367
3415
|
haltReactivity(t);
|
|
3368
3416
|
throw t;
|
|
3369
3417
|
}
|
|
3370
3418
|
}
|
|
3371
3419
|
return;
|
|
3372
3420
|
}
|
|
3373
|
-
const t = e.
|
|
3374
|
-
e.
|
|
3421
|
+
const t = e.ft;
|
|
3422
|
+
e.ft = undefined;
|
|
3375
3423
|
try {
|
|
3376
3424
|
t?.();
|
|
3377
|
-
const n = e.
|
|
3425
|
+
const n = e.bt(e.ke, e.gt);
|
|
3378
3426
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3379
3427
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3380
|
-
e.
|
|
3428
|
+
e.ft = n;
|
|
3381
3429
|
} catch (t) {
|
|
3382
|
-
e.
|
|
3383
|
-
e.
|
|
3384
|
-
if (!e.
|
|
3430
|
+
e.De = new StatusError(e, t);
|
|
3431
|
+
e.xe |= STATUS_ERROR;
|
|
3432
|
+
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3385
3433
|
haltReactivity(t);
|
|
3386
3434
|
throw t;
|
|
3387
3435
|
}
|
|
3388
3436
|
} finally {
|
|
3389
|
-
e.
|
|
3437
|
+
e.gt = e.ke;
|
|
3390
3438
|
e.Fe = false;
|
|
3391
3439
|
}
|
|
3392
3440
|
}
|
|
3393
3441
|
|
|
3394
|
-
GlobalQueue.
|
|
3442
|
+
GlobalQueue.J = runEffect;
|
|
3395
3443
|
|
|
3396
3444
|
/**
|
|
3397
3445
|
* Internal tracked effect - bypasses heap, goes directly to effect queue.
|
|
@@ -3406,32 +3454,32 @@ GlobalQueue.ee = runEffect;
|
|
|
3406
3454
|
} finally {}
|
|
3407
3455
|
};
|
|
3408
3456
|
const n = computed(() => {
|
|
3409
|
-
const t = n.
|
|
3410
|
-
n.
|
|
3457
|
+
const t = n.ft;
|
|
3458
|
+
n.ft = undefined;
|
|
3411
3459
|
t?.();
|
|
3412
3460
|
const r = staleValues(e);
|
|
3413
|
-
n.
|
|
3461
|
+
n.ft = r;
|
|
3414
3462
|
}, {
|
|
3415
3463
|
...t,
|
|
3416
3464
|
lazy: true
|
|
3417
3465
|
});
|
|
3418
|
-
n.
|
|
3419
|
-
n.
|
|
3466
|
+
n.ft = undefined;
|
|
3467
|
+
n.Ge = n.Ge & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3420
3468
|
n.Fe = true;
|
|
3421
|
-
n.
|
|
3422
|
-
n.
|
|
3423
|
-
const r = e !== undefined ? e : n.
|
|
3469
|
+
n.We = EFFECT_TRACKED;
|
|
3470
|
+
n.Nt = (e, t) => {
|
|
3471
|
+
const r = e !== undefined ? e : n.xe;
|
|
3424
3472
|
if (r & STATUS_ERROR) {
|
|
3425
|
-
n.
|
|
3426
|
-
const e = t !== undefined ? t : n.
|
|
3427
|
-
if (!n.
|
|
3473
|
+
n.Be.notify(n, STATUS_PENDING, 0);
|
|
3474
|
+
const e = t !== undefined ? t : n.De;
|
|
3475
|
+
if (!n.Be.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3428
3476
|
haltReactivity(unwrapStatusError(e));
|
|
3429
3477
|
throw e;
|
|
3430
3478
|
}
|
|
3431
3479
|
}
|
|
3432
3480
|
};
|
|
3433
|
-
n.
|
|
3434
|
-
n.
|
|
3481
|
+
n.Ze = run;
|
|
3482
|
+
n.Be.enqueue(EFFECT_USER, run);
|
|
3435
3483
|
}
|
|
3436
3484
|
|
|
3437
3485
|
function restoreTransition(e, t) {
|
|
@@ -3612,7 +3660,7 @@ function accessor(e) {
|
|
|
3612
3660
|
function createSignal(e, t) {
|
|
3613
3661
|
if (typeof e === "function") {
|
|
3614
3662
|
const n = computed(e, t);
|
|
3615
|
-
n.
|
|
3663
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3616
3664
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3617
3665
|
}
|
|
3618
3666
|
const n = signal(e, t);
|
|
@@ -3824,9 +3872,9 @@ function createEffect(e, t, n) {
|
|
|
3824
3872
|
// route through the inherited queue.
|
|
3825
3873
|
const i = getOwner();
|
|
3826
3874
|
const o = new MicrotaskQueue;
|
|
3827
|
-
o.
|
|
3875
|
+
o.B = i.Be;
|
|
3828
3876
|
// notify() forwards up the normal chain
|
|
3829
|
-
i.
|
|
3877
|
+
i.Be = o;
|
|
3830
3878
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
3831
3879
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
3832
3880
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -3853,7 +3901,7 @@ function createOptimistic(e, t) {
|
|
|
3853
3901
|
installOptimisticEngine();
|
|
3854
3902
|
if (typeof e === "function") {
|
|
3855
3903
|
const n = optimisticComputed(e, t);
|
|
3856
|
-
n.
|
|
3904
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3857
3905
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3858
3906
|
}
|
|
3859
3907
|
const n = optimisticSignal(e, t);
|
|
@@ -3942,7 +3990,7 @@ function createOptimistic(e, t) {
|
|
|
3942
3990
|
* on owner disposal
|
|
3943
3991
|
*/ function onSettled(e) {
|
|
3944
3992
|
const t = getOwner();
|
|
3945
|
-
t && !(t.
|
|
3993
|
+
t && !(t.Ge & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3946
3994
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3947
3995
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3948
3996
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4046,28 +4094,68 @@ function keyedMatch(e, t, n) {
|
|
|
4046
4094
|
// and `in` dependencies should follow the new value's membership. Use
|
|
4047
4095
|
// membership rather than length arithmetic so sparse arrays and named array
|
|
4048
4096
|
// props behave like normal property reads.
|
|
4097
|
+
// Inline key iteration on purpose: these loops run per array target per
|
|
4098
|
+
// reconcile pass, and a shared helper means a closure + per-key call in
|
|
4099
|
+
// instruction counts. String-only records (the common case) iterate in
|
|
4100
|
+
// place; symbol-bearing records take the nodeKeys array path.
|
|
4049
4101
|
function syncArrayNodeMembership(e, t) {
|
|
4050
4102
|
let n = e[STORE_NODE];
|
|
4051
4103
|
if (n) {
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4104
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4105
|
+
const e = nodeKeys(n);
|
|
4106
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4107
|
+
e[r] in t || setSignal(n[e[r]], undefined);
|
|
4108
|
+
}
|
|
4109
|
+
} else {
|
|
4110
|
+
for (const e in n) {
|
|
4111
|
+
e in t || setSignal(n[e], undefined);
|
|
4112
|
+
}
|
|
4056
4113
|
}
|
|
4057
4114
|
}
|
|
4058
4115
|
if (n = e[STORE_HAS]) {
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4116
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4117
|
+
const e = nodeKeys(n);
|
|
4118
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4119
|
+
setSignal(n[e[r]], e[r] in t);
|
|
4120
|
+
}
|
|
4121
|
+
} else {
|
|
4122
|
+
for (const e in n) {
|
|
4123
|
+
setSignal(n[e], e in t);
|
|
4124
|
+
}
|
|
4063
4125
|
}
|
|
4064
4126
|
}
|
|
4065
4127
|
}
|
|
4066
4128
|
|
|
4129
|
+
// Recurse into a matched wrappable child pair without manufacturing a proxy:
|
|
4130
|
+
// resolve the child's target through the lookup and dispatch directly. A
|
|
4131
|
+
// lookup miss means the child was never observed — no proxy, no nodes, no
|
|
4132
|
+
// subscribers anywhere below — so the parent's swap making `next`
|
|
4133
|
+
// authoritative IS the whole update; a later read wraps next's child on
|
|
4134
|
+
// demand. This turns the diff from O(previous graph) into O(observed graph)
|
|
4135
|
+
// and drops the wrap()/$PROXY/$TARGET round-trip per visited child.
|
|
4136
|
+
// Wrap-family stores (projections/optimistic) own child proxy creation and
|
|
4137
|
+
// keep the proxy-based recursion.
|
|
4138
|
+
function applyStateChild(e, t, n, r) {
|
|
4139
|
+
if (n[STORE_WRAP] !== undefined) {
|
|
4140
|
+
applyState(e, wrap(t, n), r);
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const i = t[$TARGET] ?? storeLookup.get(t);
|
|
4144
|
+
if (i === undefined) return;
|
|
4145
|
+
e = unwrap(e);
|
|
4146
|
+
if (i[STORE_SHALLOW]) {
|
|
4147
|
+
applyStateShallow(e, i);
|
|
4148
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4149
|
+
applyStateSlow(e, i, r);
|
|
4150
|
+
} else {
|
|
4151
|
+
applyStateFast(e, i, r);
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4067
4155
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
4068
4156
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
4069
4157
|
function applyArrayItem(e, t, n, r, i) {
|
|
4070
|
-
if (isWrappable(e) && isWrappable(t)) {
|
|
4158
|
+
if (isWrappable(e) && isWrappable(t) && !(rawValuesUsed && (isRawValue(t) || isRawValue(e)))) {
|
|
4071
4159
|
const o = wrap(t, n);
|
|
4072
4160
|
r && setSignal(r, o);
|
|
4073
4161
|
applyState(e, o, i);
|
|
@@ -4087,18 +4175,51 @@ function applyArrayItem(e, t, n, r, i) {
|
|
|
4087
4175
|
* `$TRACK` absence (an enumeration-tracked record already diffs every key).
|
|
4088
4176
|
*/ function applyDescendants(e, t, n, r, i, o, s) {
|
|
4089
4177
|
const u = n[STORE_LOOKUP] || storeLookup;
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4178
|
+
if (o) {
|
|
4179
|
+
const n = getKeys(e, o).concat(getStoreSymbols(e, o));
|
|
4180
|
+
for (let l = 0, a = n.length; l < a; l++) {
|
|
4181
|
+
const a = n[l];
|
|
4182
|
+
if (r?.[a]) continue;
|
|
4094
4183
|
// main loop already diffed this slot
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4184
|
+
const c = unwrap(getOverrideValue(e, o, a, s));
|
|
4185
|
+
if (!isWrappable(c)) continue;
|
|
4186
|
+
descendInto(c, t[a], u, i);
|
|
4187
|
+
}
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
// No-override path (every applyStateFast call): iterate in place instead of
|
|
4191
|
+
// building keys + symbols + concat arrays per object per pass. The cheap
|
|
4192
|
+
// bails (noded key, primitive value) stay inline — only genuine descent
|
|
4193
|
+
// candidates pay a call.
|
|
4194
|
+
for (const n in e) {
|
|
4195
|
+
if (r?.[n]) continue;
|
|
4196
|
+
// main loop already diffed this slot
|
|
4197
|
+
const o = unwrap(e[n]);
|
|
4198
|
+
if (!isWrappable(o)) continue;
|
|
4199
|
+
descendInto(o, t[n], u, i);
|
|
4200
|
+
}
|
|
4201
|
+
const l = Object.getOwnPropertySymbols(e);
|
|
4202
|
+
for (let n = 0, o = l.length; n < o; n++) {
|
|
4203
|
+
if (Object.prototype.propertyIsEnumerable.call(e, l[n])) {
|
|
4204
|
+
if (r?.[l[n]]) continue;
|
|
4205
|
+
const o = unwrap(e[l[n]]);
|
|
4206
|
+
if (!isWrappable(o)) continue;
|
|
4207
|
+
descendInto(o, t[l[n]], u, i);
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
|
|
4212
|
+
function descendInto(e, t, n, r) {
|
|
4213
|
+
const i = lookupTarget(e, n);
|
|
4214
|
+
if (!i?.[STORE_DESC]) return;
|
|
4215
|
+
const o = unwrap(t);
|
|
4216
|
+
if (e === o || !isWrappable(o) || Array.isArray(e) !== Array.isArray(o) || r(e) != null && r(e) !== r(o)) return;
|
|
4217
|
+
if (i[STORE_SHALLOW]) {
|
|
4218
|
+
applyStateShallow(o, i);
|
|
4219
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4220
|
+
applyStateSlow(o, i, r);
|
|
4221
|
+
} else {
|
|
4222
|
+
applyStateFast(o, i, r);
|
|
4102
4223
|
}
|
|
4103
4224
|
}
|
|
4104
4225
|
|
|
@@ -4113,36 +4234,134 @@ function applyState(e, t, n) {
|
|
|
4113
4234
|
e = unwrap(e);
|
|
4114
4235
|
const r = t?.[$TARGET];
|
|
4115
4236
|
if (!r) return;
|
|
4116
|
-
if (r[
|
|
4237
|
+
if (r[STORE_SHALLOW]) {
|
|
4238
|
+
applyStateShallow(e, r);
|
|
4239
|
+
} else if (r[STORE_OVERRIDE] || r[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4117
4240
|
applyStateSlow(e, r, n);
|
|
4118
4241
|
} else {
|
|
4119
4242
|
applyStateFast(e, r, n);
|
|
4120
4243
|
}
|
|
4121
4244
|
}
|
|
4122
4245
|
|
|
4246
|
+
// Shallow boundary diff: the target's own keys are reactive, its values are
|
|
4247
|
+
// raw records replaced by reference — no recursion, no wrapping. Arrays merge
|
|
4248
|
+
// positionally (below a shallow boundary the VALUE is the identity; keyed
|
|
4249
|
+
// row identity belongs to the consumer, e.g. <For keyed>). Incoming
|
|
4250
|
+
// wrappables are sticky-marked raw so they present raw through every store.
|
|
4251
|
+
// One pass over a shallow target's node record: replace changed slots with
|
|
4252
|
+
// raw next values, null out slots absent from next. Returns whether anything
|
|
4253
|
+
// differed.
|
|
4254
|
+
function shallowDiffNodes(e, t, n, r) {
|
|
4255
|
+
let i = false;
|
|
4256
|
+
for (const o in e) {
|
|
4257
|
+
if (r && o === "length") continue;
|
|
4258
|
+
if (o in t) {
|
|
4259
|
+
const r = t[o];
|
|
4260
|
+
if (r !== n(o)) {
|
|
4261
|
+
i = true;
|
|
4262
|
+
setSignal(e[o], r);
|
|
4263
|
+
}
|
|
4264
|
+
} else {
|
|
4265
|
+
i = true;
|
|
4266
|
+
setSignal(e[o], undefined);
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
return i;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
function applyStateShallow(e, t, n) {
|
|
4273
|
+
const r = t[STORE_VALUE];
|
|
4274
|
+
const i = t[STORE_OVERRIDE];
|
|
4275
|
+
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4276
|
+
if (e === r && !i && !o) return;
|
|
4277
|
+
// Setter-staged writes fold into the diff: previous values resolve through
|
|
4278
|
+
// the override layers (so a replaced slot compares against what readers
|
|
4279
|
+
// saw), and the regular override clears with the swap — reconcile makes
|
|
4280
|
+
// `next` the authoritative base, same as the deep slow path.
|
|
4281
|
+
const prevAt = e => {
|
|
4282
|
+
const t = getOverrideValue(r, i, e, o);
|
|
4283
|
+
return t === $DELETED ? undefined : t;
|
|
4284
|
+
};
|
|
4285
|
+
t[STORE_OVERRIDE] = undefined;
|
|
4286
|
+
const s = t[STORE_LOOKUP];
|
|
4287
|
+
s !== undefined ? s.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4288
|
+
t[STORE_VALUE] = e;
|
|
4289
|
+
markRawIngest(e);
|
|
4290
|
+
const u = t[STORE_NODE];
|
|
4291
|
+
const l = u && u[$TRACK];
|
|
4292
|
+
let a = false;
|
|
4293
|
+
if (Array.isArray(r)) {
|
|
4294
|
+
const n = i?.length ?? o?.length ?? r.length;
|
|
4295
|
+
if (u) {
|
|
4296
|
+
a = shallowDiffNodes(u, e, prevAt, true);
|
|
4297
|
+
if (u.length && n !== e.length) setSignal(u.length, e.length);
|
|
4298
|
+
}
|
|
4299
|
+
if (!a && (l || t[STORE_HAS])) {
|
|
4300
|
+
// Slots without nodes still feed $TRACK enumerators / `in` probes.
|
|
4301
|
+
if (n !== e.length) a = true; else {
|
|
4302
|
+
for (let t = 0, n = e.length; t < n; t++) {
|
|
4303
|
+
if (prevAt(t) !== e[t]) {
|
|
4304
|
+
a = true;
|
|
4305
|
+
break;
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
} else {
|
|
4311
|
+
if (u) {
|
|
4312
|
+
a = shallowDiffNodes(u, e, prevAt, false);
|
|
4313
|
+
}
|
|
4314
|
+
if (!a && (l || t[STORE_HAS])) a = true;
|
|
4315
|
+
}
|
|
4316
|
+
let c = t[STORE_HAS];
|
|
4317
|
+
if (c) {
|
|
4318
|
+
for (const t in c) {
|
|
4319
|
+
setSignal(c[t], t in e);
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
a && notifySelf(t);
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4123
4325
|
function applyStateFast(e, t, n) {
|
|
4124
4326
|
const r = t[STORE_VALUE];
|
|
4125
4327
|
if (e === r) return;
|
|
4126
4328
|
const i = t[STORE_NODE];
|
|
4127
4329
|
// swap
|
|
4128
|
-
|
|
4330
|
+
{
|
|
4331
|
+
const n = t[STORE_LOOKUP];
|
|
4332
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4333
|
+
}
|
|
4129
4334
|
t[STORE_VALUE] = e;
|
|
4130
4335
|
// merge
|
|
4131
4336
|
if (Array.isArray(r)) {
|
|
4132
4337
|
let o = false;
|
|
4133
4338
|
const s = r.length;
|
|
4134
4339
|
if (e.length && s && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4135
|
-
let u, l,
|
|
4136
|
-
for (
|
|
4137
|
-
|
|
4340
|
+
let u, l, a, c, f, E, d, S;
|
|
4341
|
+
for (a = 0, c = Math.min(s, e.length); a < c && keyedMatch(E = r[a], e[a], n); a++) {
|
|
4342
|
+
// keyedMatch established both sides wrappable unless they're the
|
|
4343
|
+
// SAME reference — and an identical slot is a guaranteed no-op
|
|
4344
|
+
// (the child's STORE_VALUE tracks the previous graph), so skip
|
|
4345
|
+
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
4346
|
+
// replace the slot node instead of recursing.
|
|
4347
|
+
if (E !== e[a]) {
|
|
4348
|
+
if (rawValuesUsed && (isRawValue(E) || isRawValue(e[a]))) {
|
|
4349
|
+
i?.[a] && setSignal(i[a], wrapValue(e[a], t));
|
|
4350
|
+
} else applyStateChild(e[a], E, t, n);
|
|
4351
|
+
}
|
|
4138
4352
|
}
|
|
4139
|
-
|
|
4140
|
-
|
|
4353
|
+
// Every position key-matched at equal length (the steady-state shape
|
|
4354
|
+
// of a polling tick): membership, length, and order are unchanged —
|
|
4355
|
+
// nothing below could do observable work, so skip the staging
|
|
4356
|
+
// allocations and membership sync outright.
|
|
4357
|
+
if (a === e.length && a === s) return;
|
|
4358
|
+
const T = new Array(e.length), O = new Map;
|
|
4359
|
+
for (c = s - 1, f = e.length - 1; c >= a && f >= a && keyedMatch(E = r[c], e[f], n); c--,
|
|
4141
4360
|
f--) {
|
|
4142
4361
|
T[f] = E;
|
|
4143
4362
|
}
|
|
4144
|
-
if (
|
|
4145
|
-
for (l =
|
|
4363
|
+
if (a > f || a > c) {
|
|
4364
|
+
for (l = a; l <= f; l++) {
|
|
4146
4365
|
o = true;
|
|
4147
4366
|
i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4148
4367
|
}
|
|
@@ -4155,34 +4374,36 @@ function applyStateFast(e, t, n) {
|
|
|
4155
4374
|
s !== e.length && i?.length && setSignal(i.length, e.length);
|
|
4156
4375
|
return;
|
|
4157
4376
|
}
|
|
4158
|
-
|
|
4159
|
-
for (l = f; l >=
|
|
4377
|
+
d = new Array(f + 1);
|
|
4378
|
+
for (l = f; l >= a; l--) {
|
|
4160
4379
|
E = e[l];
|
|
4161
|
-
|
|
4162
|
-
u =
|
|
4163
|
-
|
|
4164
|
-
|
|
4380
|
+
S = itemKey(E, n);
|
|
4381
|
+
u = O.get(S);
|
|
4382
|
+
d[l] = u === undefined ? -1 : u;
|
|
4383
|
+
O.set(S, l);
|
|
4165
4384
|
}
|
|
4166
|
-
for (u =
|
|
4385
|
+
for (u = a; u <= c; u++) {
|
|
4167
4386
|
E = r[u];
|
|
4168
|
-
|
|
4169
|
-
l =
|
|
4387
|
+
S = itemKey(E, n);
|
|
4388
|
+
l = O.get(S);
|
|
4170
4389
|
if (l !== undefined && l !== -1) {
|
|
4171
4390
|
T[l] = E;
|
|
4172
|
-
l =
|
|
4173
|
-
|
|
4391
|
+
l = d[l];
|
|
4392
|
+
O.set(S, l);
|
|
4174
4393
|
}
|
|
4175
4394
|
}
|
|
4176
|
-
for (l =
|
|
4395
|
+
for (l = a; l < e.length; l++) {
|
|
4177
4396
|
if (l in T) {
|
|
4178
4397
|
applyArrayItem(e[l], T[l], t, i?.[l], n);
|
|
4179
4398
|
} else i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4180
4399
|
}
|
|
4181
|
-
if (
|
|
4400
|
+
if (a < e.length) o = true;
|
|
4182
4401
|
} else if (e.length) {
|
|
4183
4402
|
for (let s = 0, u = e.length; s < u; s++) {
|
|
4184
4403
|
const u = r[s];
|
|
4185
|
-
if (isWrappable(u) && isWrappable(e[s]))
|
|
4404
|
+
if (isWrappable(u) && isWrappable(e[s]) && !(rawValuesUsed && (isRawValue(u) || isRawValue(e[s])))) {
|
|
4405
|
+
if (u !== e[s]) applyStateChild(e[s], u, t, n);
|
|
4406
|
+
} else {
|
|
4186
4407
|
if (u !== e[s]) o = true;
|
|
4187
4408
|
i?.[s] && setSignal(i[s], wrapValue(e[s], t));
|
|
4188
4409
|
}
|
|
@@ -4201,17 +4422,43 @@ function applyStateFast(e, t, n) {
|
|
|
4201
4422
|
let s;
|
|
4202
4423
|
if (o) {
|
|
4203
4424
|
s = o[$TRACK];
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4425
|
+
// The per-key body is duplicated across both loops on purpose: this is
|
|
4426
|
+
// the hottest object-diff site and a shared helper costs a per-key call
|
|
4427
|
+
// in instruction counts (CodSpeed regressed ~7% on deep-tree reconciles
|
|
4428
|
+
// with the extracted form).
|
|
4429
|
+
if (s || symbolKeyedRecords.has(o)) {
|
|
4430
|
+
const i = s ? getAllKeys(r, undefined, e) : nodeKeys(o);
|
|
4431
|
+
for (let u = 0, l = i.length; u < l; u++) {
|
|
4432
|
+
const l = i[u];
|
|
4433
|
+
const a = o[l];
|
|
4434
|
+
const c = unwrap(r[l]);
|
|
4435
|
+
const f = unwrap(e[l]);
|
|
4436
|
+
if (c === f) continue;
|
|
4437
|
+
if (!c || !isWrappable(c) || !isWrappable(f) ||
|
|
4438
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4439
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4440
|
+
rawValuesUsed && (isRawValue(c) || isRawValue(f)) || Array.isArray(c) !== Array.isArray(f) || n(c) != null && n(c) !== n(f)) {
|
|
4441
|
+
s && setSignal(s, void 0);
|
|
4442
|
+
a && setSignal(a, isWrappable(f) ? wrap(f, t) : f);
|
|
4443
|
+
} else applyStateChild(f, c, t, n);
|
|
4444
|
+
}
|
|
4445
|
+
} else {
|
|
4446
|
+
// Untracked, string-only node records (the overwhelmingly common case)
|
|
4447
|
+
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
4448
|
+
// per pass, which dominates allocation on large-graph reconciles.
|
|
4449
|
+
for (const i in o) {
|
|
4450
|
+
const u = o[i];
|
|
4451
|
+
const l = unwrap(r[i]);
|
|
4452
|
+
const a = unwrap(e[i]);
|
|
4453
|
+
if (l === a) continue;
|
|
4454
|
+
if (!l || !isWrappable(l) || !isWrappable(a) ||
|
|
4455
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4456
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4457
|
+
rawValuesUsed && (isRawValue(l) || isRawValue(a)) || Array.isArray(l) !== Array.isArray(a) || n(l) != null && n(l) !== n(a)) {
|
|
4458
|
+
s && setSignal(s, void 0);
|
|
4459
|
+
u && setSignal(u, isWrappable(a) ? wrap(a, t) : a);
|
|
4460
|
+
} else applyStateChild(a, l, t, n);
|
|
4461
|
+
}
|
|
4215
4462
|
}
|
|
4216
4463
|
}
|
|
4217
4464
|
if (!s && t[STORE_DESC]) applyDescendants(r, e, t, o, n);
|
|
@@ -4231,7 +4478,10 @@ function applyStateSlow(e, t, n) {
|
|
|
4231
4478
|
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4232
4479
|
let s = t[STORE_NODE];
|
|
4233
4480
|
// swap
|
|
4234
|
-
|
|
4481
|
+
{
|
|
4482
|
+
const n = t[STORE_LOOKUP];
|
|
4483
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4484
|
+
}
|
|
4235
4485
|
t[STORE_VALUE] = e;
|
|
4236
4486
|
t[STORE_OVERRIDE] = undefined;
|
|
4237
4487
|
// merge
|
|
@@ -4239,23 +4489,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4239
4489
|
let u = false;
|
|
4240
4490
|
const l = getOverrideValue(r, i, "length", o);
|
|
4241
4491
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4242
|
-
let
|
|
4243
|
-
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(
|
|
4244
|
-
isWrappable(
|
|
4492
|
+
let a, c, f, E, d, S, T, O;
|
|
4493
|
+
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4494
|
+
if (isWrappable(S) && isWrappable(e[f]) && S !== e[f]) {
|
|
4495
|
+
if (rawValuesUsed && (isRawValue(S) || isRawValue(e[f]))) {
|
|
4496
|
+
s?.[f] && setSignal(s[f], wrapValue(e[f], t));
|
|
4497
|
+
} else applyState(e[f], wrap(S, t), n);
|
|
4498
|
+
}
|
|
4245
4499
|
}
|
|
4246
|
-
const
|
|
4247
|
-
for (E = l - 1,
|
|
4248
|
-
|
|
4249
|
-
|
|
4500
|
+
const _ = new Array(e.length), p = new Map;
|
|
4501
|
+
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4502
|
+
d--) {
|
|
4503
|
+
_[d] = S;
|
|
4250
4504
|
}
|
|
4251
|
-
if (f >
|
|
4252
|
-
for (
|
|
4505
|
+
if (f > d || f > E) {
|
|
4506
|
+
for (c = f; c <= d; c++) {
|
|
4253
4507
|
u = true;
|
|
4254
|
-
s?.[
|
|
4508
|
+
s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4255
4509
|
}
|
|
4256
|
-
for (;
|
|
4510
|
+
for (;c < e.length; c++) {
|
|
4257
4511
|
u = true;
|
|
4258
|
-
applyArrayItem(e[
|
|
4512
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4259
4513
|
}
|
|
4260
4514
|
const r = e.length;
|
|
4261
4515
|
syncArrayNodeMembership(t, e);
|
|
@@ -4263,44 +4517,46 @@ function applyStateSlow(e, t, n) {
|
|
|
4263
4517
|
l !== r && s?.length && setSignal(s.length, r);
|
|
4264
4518
|
return;
|
|
4265
4519
|
}
|
|
4266
|
-
T = new Array(
|
|
4267
|
-
for (
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
T[
|
|
4272
|
-
|
|
4520
|
+
T = new Array(d + 1);
|
|
4521
|
+
for (c = d; c >= f; c--) {
|
|
4522
|
+
S = e[c];
|
|
4523
|
+
O = itemKey(S, n);
|
|
4524
|
+
a = p.get(O);
|
|
4525
|
+
T[c] = a === undefined ? -1 : a;
|
|
4526
|
+
p.set(O, c);
|
|
4273
4527
|
}
|
|
4274
|
-
for (
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
if (
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4528
|
+
for (a = f; a <= E; a++) {
|
|
4529
|
+
S = getOverrideValue(r, i, a, o);
|
|
4530
|
+
O = itemKey(S, n);
|
|
4531
|
+
c = p.get(O);
|
|
4532
|
+
if (c !== undefined && c !== -1) {
|
|
4533
|
+
_[c] = S;
|
|
4534
|
+
c = T[c];
|
|
4535
|
+
p.set(O, c);
|
|
4282
4536
|
}
|
|
4283
4537
|
}
|
|
4284
|
-
for (
|
|
4285
|
-
if (
|
|
4286
|
-
applyArrayItem(e[
|
|
4287
|
-
} else s?.[
|
|
4538
|
+
for (c = f; c < e.length; c++) {
|
|
4539
|
+
if (c in _) {
|
|
4540
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4541
|
+
} else s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4288
4542
|
}
|
|
4289
4543
|
if (f < e.length) u = true;
|
|
4290
4544
|
} else if (e.length) {
|
|
4291
|
-
for (let l = 0,
|
|
4292
|
-
const
|
|
4293
|
-
if (isWrappable(
|
|
4294
|
-
if (
|
|
4545
|
+
for (let l = 0, a = e.length; l < a; l++) {
|
|
4546
|
+
const a = getOverrideValue(r, i, l, o);
|
|
4547
|
+
if (isWrappable(a) && isWrappable(e[l]) && !(rawValuesUsed && (isRawValue(a) || isRawValue(e[l])))) {
|
|
4548
|
+
if (a !== e[l]) applyState(e[l], wrap(a, t), n);
|
|
4549
|
+
} else {
|
|
4550
|
+
if (a !== e[l]) u = true;
|
|
4295
4551
|
s?.[l] && setSignal(s[l], wrapValue(e[l], t));
|
|
4296
4552
|
}
|
|
4297
4553
|
}
|
|
4298
4554
|
}
|
|
4299
|
-
const
|
|
4555
|
+
const a = e.length;
|
|
4300
4556
|
syncArrayNodeMembership(t, e);
|
|
4301
|
-
if (l !==
|
|
4557
|
+
if (l !== a) {
|
|
4302
4558
|
u = true;
|
|
4303
|
-
s?.length && setSignal(s.length,
|
|
4559
|
+
s?.length && setSignal(s.length, a);
|
|
4304
4560
|
}
|
|
4305
4561
|
u && notifySelf(t);
|
|
4306
4562
|
return;
|
|
@@ -4310,16 +4566,16 @@ function applyStateSlow(e, t, n) {
|
|
|
4310
4566
|
if (s) {
|
|
4311
4567
|
u = s[$TRACK];
|
|
4312
4568
|
const l = u ? getAllKeys(r, i, e) : nodeKeys(s);
|
|
4313
|
-
for (let
|
|
4314
|
-
const
|
|
4315
|
-
const f = s[
|
|
4316
|
-
const E = unwrap(getOverrideValue(r, i,
|
|
4317
|
-
let
|
|
4318
|
-
if (E ===
|
|
4319
|
-
if (!E || !isWrappable(E) || !isWrappable(
|
|
4569
|
+
for (let a = 0, c = l.length; a < c; a++) {
|
|
4570
|
+
const c = l[a];
|
|
4571
|
+
const f = s[c];
|
|
4572
|
+
const E = unwrap(getOverrideValue(r, i, c, o));
|
|
4573
|
+
let d = unwrap(e[c]);
|
|
4574
|
+
if (E === d) continue;
|
|
4575
|
+
if (!E || !isWrappable(E) || !isWrappable(d) || rawValuesUsed && (isRawValue(E) || isRawValue(d)) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4320
4576
|
u && setSignal(u, void 0);
|
|
4321
|
-
f && setSignal(f, isWrappable(
|
|
4322
|
-
} else applyState(
|
|
4577
|
+
f && setSignal(f, isWrappable(d) ? wrap(d, t) : d);
|
|
4578
|
+
} else applyState(d, wrap(E, t), n);
|
|
4323
4579
|
}
|
|
4324
4580
|
}
|
|
4325
4581
|
if (!u && t[STORE_DESC]) applyDescendants(r, e, t, s, n, i, o);
|
|
@@ -4333,17 +4589,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4333
4589
|
}
|
|
4334
4590
|
}
|
|
4335
4591
|
|
|
4592
|
+
// No-key reconcile: every item reports "no key", which routes array diffs to
|
|
4593
|
+
// the positional branch and object descent to plain per-property merging.
|
|
4594
|
+
const NOKEY = () => null;
|
|
4595
|
+
|
|
4336
4596
|
/**
|
|
4337
4597
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
4338
|
-
* preserving
|
|
4339
|
-
*
|
|
4340
|
-
*
|
|
4598
|
+
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
4599
|
+
*
|
|
4600
|
+
* With a `key` (default `"id"`), array items whose key matches between old
|
|
4601
|
+
* and new states keep their identity (updated in place, moves and removals
|
|
4602
|
+
* update the corresponding signals) — the shape for keyed server payloads.
|
|
4603
|
+
* Items without the key field fall back to positional matching.
|
|
4341
4604
|
*
|
|
4342
|
-
*
|
|
4343
|
-
*
|
|
4605
|
+
* With `key: null`, matching is purely positional: index N of the new array
|
|
4606
|
+
* merges into index N of the old, and object properties merge recursively —
|
|
4607
|
+
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
4608
|
+
* monitors), where no keyed diff pass is needed or wanted.
|
|
4344
4609
|
*
|
|
4345
4610
|
* @param value the next state to merge in
|
|
4346
|
-
* @param key property name (string) or extractor function for stable
|
|
4611
|
+
* @param key property name (string) or extractor function for stable
|
|
4612
|
+
* identity (default `"id"`); pass `null` for positional merging
|
|
4347
4613
|
*
|
|
4348
4614
|
* @example
|
|
4349
4615
|
* ```ts
|
|
@@ -4351,12 +4617,19 @@ function applyStateSlow(e, t, n) {
|
|
|
4351
4617
|
*
|
|
4352
4618
|
* async function refresh() {
|
|
4353
4619
|
* const fresh = await api.getTodos();
|
|
4354
|
-
* setTodos(reconcile(fresh
|
|
4620
|
+
* setTodos(reconcile(fresh)); // diff-merge by `id`
|
|
4355
4621
|
* }
|
|
4622
|
+
*
|
|
4623
|
+
* // fixed-shape polling data — positional merge
|
|
4624
|
+
* setStats(reconcile(nextStats, null));
|
|
4356
4625
|
* ```
|
|
4357
|
-
*/ function reconcile(e, t) {
|
|
4626
|
+
*/ function reconcile(e, t = "id") {
|
|
4358
4627
|
return n => {
|
|
4359
4628
|
if (n == null) throw new Error("");
|
|
4629
|
+
if (t === null) {
|
|
4630
|
+
applyState(e, n, NOKEY);
|
|
4631
|
+
return;
|
|
4632
|
+
}
|
|
4360
4633
|
const r = typeof t === "string" ? e => e[t] : t;
|
|
4361
4634
|
const i = r(n);
|
|
4362
4635
|
if (i !== undefined && r(e) !== i) throw new Error("");
|
|
@@ -4367,9 +4640,16 @@ function applyStateSlow(e, t, n) {
|
|
|
4367
4640
|
function createProjectionInternal(e, t, n) {
|
|
4368
4641
|
let r;
|
|
4369
4642
|
const i = new WeakMap;
|
|
4643
|
+
// A shallow projection's children are raw and never wrapped, so the
|
|
4644
|
+
// wrapper only ever runs for the root — flagging unconditionally is safe.
|
|
4645
|
+
const o = !!n?.shallow;
|
|
4370
4646
|
const wrapper = e => {
|
|
4371
4647
|
e[STORE_WRAP] = wrapProjection;
|
|
4372
4648
|
e[STORE_LOOKUP] = i;
|
|
4649
|
+
if (o) {
|
|
4650
|
+
e[STORE_SHALLOW] = true;
|
|
4651
|
+
markRawIngest(e[STORE_VALUE]);
|
|
4652
|
+
}
|
|
4373
4653
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
4374
4654
|
get() {
|
|
4375
4655
|
return r;
|
|
@@ -4384,14 +4664,14 @@ function createProjectionInternal(e, t, n) {
|
|
|
4384
4664
|
i.set(e, t);
|
|
4385
4665
|
return t;
|
|
4386
4666
|
};
|
|
4387
|
-
const
|
|
4667
|
+
const s = wrapProjection(t);
|
|
4388
4668
|
r = computed(() => {
|
|
4389
4669
|
if (!r) r = getOwner();
|
|
4390
|
-
runProjectionComputed(
|
|
4670
|
+
runProjectionComputed(s, e, n?.key || "id");
|
|
4391
4671
|
}, undefined);
|
|
4392
|
-
r.
|
|
4672
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
4393
4673
|
return {
|
|
4394
|
-
store:
|
|
4674
|
+
store: s,
|
|
4395
4675
|
node: r
|
|
4396
4676
|
};
|
|
4397
4677
|
}
|
|
@@ -4458,7 +4738,7 @@ function createProjectionInternal(e, t, n) {
|
|
|
4458
4738
|
const o = getOwner();
|
|
4459
4739
|
let s = false;
|
|
4460
4740
|
let u;
|
|
4461
|
-
const l = new Proxy(e, createWriteTraps(() => !s || o.
|
|
4741
|
+
const l = new Proxy(e, createWriteTraps(() => !s || o.ut === u, i));
|
|
4462
4742
|
storeSetter(l, i => {
|
|
4463
4743
|
u = t(i);
|
|
4464
4744
|
s = true;
|
|
@@ -4539,19 +4819,45 @@ function createWriteTraps(e, t) {
|
|
|
4539
4819
|
// the record witnesses it into the active isPending() probe.
|
|
4540
4820
|
$AFFECTS = Symbol(0);
|
|
4541
4821
|
|
|
4542
|
-
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d";
|
|
4822
|
+
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d", STORE_SHALLOW = "s";
|
|
4543
4823
|
|
|
4544
4824
|
const STORE_SELF_PENDING = Symbol(0);
|
|
4545
4825
|
|
|
4826
|
+
// Every StoreNode field is initialized up front, in one fixed order, so all
|
|
4827
|
+
// targets share a single hidden class. The traps and reconcile read these
|
|
4828
|
+
// fields on their hottest paths; fields added lazily in varying orders made
|
|
4829
|
+
// those loads megamorphic across a large store graph (dictionary-mode probes
|
|
4830
|
+
// on every trap hit). Assignments elsewhere must never `delete` a field —
|
|
4831
|
+
// write `undefined` instead, or the shape degrades again.
|
|
4832
|
+
function initStoreFields(e) {
|
|
4833
|
+
e[STORE_OVERRIDE] = undefined;
|
|
4834
|
+
e[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
4835
|
+
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
4836
|
+
e[STORE_NODE] = undefined;
|
|
4837
|
+
e[STORE_HAS] = undefined;
|
|
4838
|
+
e[STORE_CUSTOM_PROTO] = undefined;
|
|
4839
|
+
e[STORE_WRAP] = undefined;
|
|
4840
|
+
e[STORE_LOOKUP] = undefined;
|
|
4841
|
+
e[STORE_FIREWALL] = undefined;
|
|
4842
|
+
e[STORE_OPTIMISTIC] = undefined;
|
|
4843
|
+
e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
4844
|
+
e[STORE_PARENT] = undefined;
|
|
4845
|
+
e[STORE_DESC] = undefined;
|
|
4846
|
+
e[STORE_SHALLOW] = undefined;
|
|
4847
|
+
e[$PROXY] = null;
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4546
4850
|
function createStoreProxy(e, t = storeTraps, n) {
|
|
4547
4851
|
let r;
|
|
4548
4852
|
if (Array.isArray(e)) {
|
|
4549
4853
|
r = [];
|
|
4550
|
-
r
|
|
4854
|
+
r[STORE_VALUE] = e;
|
|
4855
|
+
initStoreFields(r);
|
|
4551
4856
|
} else {
|
|
4552
4857
|
r = {
|
|
4553
|
-
|
|
4858
|
+
[STORE_VALUE]: e
|
|
4554
4859
|
};
|
|
4860
|
+
initStoreFields(r);
|
|
4555
4861
|
const t = e?.[$TARGET]?.[STORE_VALUE] ?? e;
|
|
4556
4862
|
const n = Object.getPrototypeOf(t);
|
|
4557
4863
|
if (n !== null && n !== Object.prototype) {
|
|
@@ -4562,24 +4868,99 @@ function createStoreProxy(e, t = storeTraps, n) {
|
|
|
4562
4868
|
return r[$PROXY] = new Proxy(r, t);
|
|
4563
4869
|
}
|
|
4564
4870
|
|
|
4871
|
+
// The global lookup maps raw value -> StoreNode TARGET (not proxy): reconcile
|
|
4872
|
+
// and the unwrap/snapshot walks resolve targets through it constantly, and a
|
|
4873
|
+
// target hit is a plain field read away from its proxy while a proxy hit
|
|
4874
|
+
// costs a trap to get back to the target. Per-family STORE_LOOKUP maps
|
|
4875
|
+
// (projections/optimistic) still map raw -> proxy — their wrap functions own
|
|
4876
|
+
// that contract — so mixed-lookup consumers resolve through lookupTarget().
|
|
4565
4877
|
const storeLookup = new WeakMap;
|
|
4566
4878
|
|
|
4567
4879
|
// Node records that hold at least one user (non-`$TRACK`) symbol-keyed node.
|
|
4568
4880
|
// Lets reconcile enumerate symbols only for records that need it (#2851).
|
|
4569
4881
|
const symbolKeyedRecords = new WeakSet;
|
|
4570
4882
|
|
|
4883
|
+
function lookupTarget(e, t) {
|
|
4884
|
+
if (t !== undefined && t !== storeLookup) {
|
|
4885
|
+
const n = t.get(e);
|
|
4886
|
+
if (n !== undefined) return n[$TARGET];
|
|
4887
|
+
}
|
|
4888
|
+
return storeLookup.get(e);
|
|
4889
|
+
}
|
|
4890
|
+
|
|
4891
|
+
// Values marked raw never acquire a proxy identity: wrap() serves them as-is
|
|
4892
|
+
// everywhere — deep stores hold them as leaf values replaced by reference.
|
|
4893
|
+
// Once raw, always raw (identity stays single, just unwrapped). Consulted
|
|
4894
|
+
// only on wrap-creation and ingest paths; reads never touch it.
|
|
4895
|
+
const rawValues = new WeakSet;
|
|
4896
|
+
|
|
4897
|
+
/**
|
|
4898
|
+
* Marks a value as raw: no store will ever wrap it — every store presents it
|
|
4899
|
+
* as-is, tracked by reference at whatever slot holds it and updated by
|
|
4900
|
+
* replacement. Useful for class instances and external objects (editors,
|
|
4901
|
+
* scene graphs, Maps) and for record-shaped data updated wholesale. Sticky
|
|
4902
|
+
* for the value's lifetime.
|
|
4903
|
+
*/
|
|
4904
|
+
// Flipped on the first mark and exported as a LIVE binding: reconcile
|
|
4905
|
+
// consults it on every recursable pair, and importing the boolean directly
|
|
4906
|
+
// lets those sites skip even the function call when no shallow store or raw
|
|
4907
|
+
// mark exists anywhere in the app.
|
|
4908
|
+
let rawValuesUsed = false;
|
|
4909
|
+
|
|
4910
|
+
function isRawValue(e) {
|
|
4911
|
+
return rawValuesUsed && rawValues.has(e);
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
function markRawOne(e) {
|
|
4915
|
+
if (isWrappable(e)) {
|
|
4916
|
+
rawValuesUsed = true;
|
|
4917
|
+
rawValues.add(e);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
function markRawIngest(e) {
|
|
4922
|
+
if (Array.isArray(e)) {
|
|
4923
|
+
for (let t = 0, n = e.length; t < n; t++) markRawOne(e[t]);
|
|
4924
|
+
} else {
|
|
4925
|
+
for (const t in e) markRawOne(e[t]);
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4571
4929
|
function wrap(e, t) {
|
|
4930
|
+
// Raw is raw in every family: the mark must preempt family wrapping too,
|
|
4931
|
+
// or a shallow projection/optimistic store would proxy its raw records.
|
|
4932
|
+
if (rawValuesUsed && rawValues.has(e)) return e;
|
|
4572
4933
|
if (t?.[STORE_WRAP]) {
|
|
4573
4934
|
const n = t[STORE_WRAP](e, t);
|
|
4574
4935
|
const r = n[$TARGET];
|
|
4575
4936
|
if (r && !r[STORE_PARENT] && r !== t) r[STORE_PARENT] = t;
|
|
4576
4937
|
return n;
|
|
4577
4938
|
}
|
|
4578
|
-
|
|
4579
|
-
if (
|
|
4580
|
-
|
|
4581
|
-
|
|
4939
|
+
const n = storeLookup.get(e);
|
|
4940
|
+
if (n !== undefined) return n[$PROXY];
|
|
4941
|
+
let r = e[$PROXY];
|
|
4942
|
+
if (!r) {
|
|
4943
|
+
r = createStoreProxy(e);
|
|
4944
|
+
const n = r[$TARGET];
|
|
4945
|
+
storeLookup.set(e, n);
|
|
4946
|
+
if (t) n[STORE_PARENT] = t;
|
|
4582
4947
|
}
|
|
4948
|
+
return r;
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// Shallow store root: the target itself is fully reactive (per-key nodes,
|
|
4952
|
+
// membership, $TRACK); its values are served raw. Seed values are marked at
|
|
4953
|
+
// creation; reconcile and the set trap mark on ingest.
|
|
4954
|
+
function wrapShallow(e) {
|
|
4955
|
+
const t = storeLookup.get(e);
|
|
4956
|
+
if (t !== undefined) {
|
|
4957
|
+
if (t[STORE_SHALLOW]) return t[$PROXY];
|
|
4958
|
+
}
|
|
4959
|
+
const n = createStoreProxy(e);
|
|
4960
|
+
const r = n[$TARGET];
|
|
4961
|
+
r[STORE_SHALLOW] = true;
|
|
4962
|
+
storeLookup.set(e, r);
|
|
4963
|
+
markRawIngest(e);
|
|
4583
4964
|
return n;
|
|
4584
4965
|
}
|
|
4585
4966
|
|
|
@@ -4601,7 +4982,7 @@ function writeOnly(e) {
|
|
|
4601
4982
|
}
|
|
4602
4983
|
|
|
4603
4984
|
function unwrapStoreValue(e, t, n) {
|
|
4604
|
-
const r = e?.[$TARGET] ||
|
|
4985
|
+
const r = e?.[$TARGET] || lookupTarget(e, n);
|
|
4605
4986
|
if (!r) return e;
|
|
4606
4987
|
const i = r[STORE_OVERRIDE];
|
|
4607
4988
|
if (!i) return r[STORE_VALUE];
|
|
@@ -4665,7 +5046,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
4665
5046
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
4666
5047
|
* override, else held pending value, else committed value.
|
|
4667
5048
|
*/ function visibleNodeValue(e) {
|
|
4668
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
5049
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.U !== NOT_PENDING ? e.U : e.ke;
|
|
4669
5050
|
}
|
|
4670
5051
|
|
|
4671
5052
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -4720,7 +5101,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4720
5101
|
}
|
|
4721
5102
|
if (o && n in o) {
|
|
4722
5103
|
const e = o[n];
|
|
4723
|
-
s.
|
|
5104
|
+
s.me = e === undefined ? NO_SNAPSHOT : e;
|
|
4724
5105
|
snapshotSources?.add(s);
|
|
4725
5106
|
}
|
|
4726
5107
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -4749,8 +5130,8 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4749
5130
|
*/ function inheritAffectsMarks(e, t, n) {
|
|
4750
5131
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
4751
5132
|
for (const [r, i] of affectsScopes) {
|
|
4752
|
-
if (r.
|
|
4753
|
-
GlobalQueue.
|
|
5133
|
+
if (r.k && i.scope.has(t) && (i.key === undefined || i.key === n)) {
|
|
5134
|
+
GlobalQueue.re(e);
|
|
4754
5135
|
i.inherited.push(e);
|
|
4755
5136
|
}
|
|
4756
5137
|
}
|
|
@@ -4773,7 +5154,7 @@ const affectsScopes = new Map;
|
|
|
4773
5154
|
// holds the root, and must still descend to pick up records added since.
|
|
4774
5155
|
i) {
|
|
4775
5156
|
if (!isWrappable(e)) return;
|
|
4776
|
-
const o = e[$TARGET] || (r
|
|
5157
|
+
const o = e[$TARGET] || lookupTarget(e, r);
|
|
4777
5158
|
const s = o ? o[STORE_VALUE] : e;
|
|
4778
5159
|
if (i.has(s)) return;
|
|
4779
5160
|
i.add(s);
|
|
@@ -4800,9 +5181,9 @@ i) {
|
|
|
4800
5181
|
const l = o || r ? getStoreSymbols(s, u) : [];
|
|
4801
5182
|
for (let e = 0, o = l.length; e < o; e++) {
|
|
4802
5183
|
const o = l[e];
|
|
4803
|
-
const
|
|
4804
|
-
if (!
|
|
4805
|
-
walkAffectsScope(
|
|
5184
|
+
const a = getPropertyDescriptor(s, u, o);
|
|
5185
|
+
if (!a || a.get) continue;
|
|
5186
|
+
walkAffectsScope(a.value, t, n, r, i);
|
|
4806
5187
|
}
|
|
4807
5188
|
} else {
|
|
4808
5189
|
const e = o || r ? getStoreKeys(s, u) : getKeys(s, u);
|
|
@@ -4838,11 +5219,11 @@ i) {
|
|
|
4838
5219
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
4839
5220
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
4840
5221
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
4841
|
-
if (n?.
|
|
5222
|
+
if (n?.k) GlobalQueue.Oe(n);
|
|
4842
5223
|
if (affectsScopes.size) {
|
|
4843
5224
|
const r = e[STORE_VALUE];
|
|
4844
5225
|
for (const [e, i] of affectsScopes) {
|
|
4845
|
-
if (e !== n && e.
|
|
5226
|
+
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.Oe(e);
|
|
4846
5227
|
}
|
|
4847
5228
|
}
|
|
4848
5229
|
}
|
|
@@ -4859,11 +5240,11 @@ i) {
|
|
|
4859
5240
|
* @internal
|
|
4860
5241
|
*/ function getStoreAffectsNodes(e, t) {
|
|
4861
5242
|
const n = getNodes(e, STORE_NODE);
|
|
4862
|
-
GlobalQueue.
|
|
5243
|
+
GlobalQueue.te ||= e => {
|
|
4863
5244
|
const t = affectsScopes.get(e);
|
|
4864
5245
|
if (!t) return;
|
|
4865
5246
|
affectsScopes.delete(e);
|
|
4866
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
5247
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.ie(t.inherited[e]);
|
|
4867
5248
|
};
|
|
4868
5249
|
if (t === undefined) {
|
|
4869
5250
|
const t = getNode(e, n, $AFFECTS, undefined, false);
|
|
@@ -4990,7 +5371,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
4990
5371
|
}
|
|
4991
5372
|
const r = e[STORE_VALUE];
|
|
4992
5373
|
const i = r[n];
|
|
4993
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5374
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.xe ?? 0) & STATUS_PENDING)) {
|
|
4994
5375
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
4995
5376
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
4996
5377
|
snapshotSources?.add(e);
|
|
@@ -5018,7 +5399,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5018
5399
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
5019
5400
|
// optimistic engine before wrapping.
|
|
5020
5401
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
5021
|
-
GlobalQueue.
|
|
5402
|
+
GlobalQueue.be(t);
|
|
5022
5403
|
}
|
|
5023
5404
|
}
|
|
5024
5405
|
|
|
@@ -5055,24 +5436,24 @@ function notifyStoreProperty(e, t, n, r, i, o) {
|
|
|
5055
5436
|
const n = upsertStoreNode(e, getNodes(e, STORE_HAS), t, o);
|
|
5056
5437
|
setSignal(n, u);
|
|
5057
5438
|
}
|
|
5058
|
-
const
|
|
5439
|
+
const a = getNodes(e, STORE_NODE);
|
|
5059
5440
|
if (n === "set") {
|
|
5060
|
-
if (
|
|
5061
|
-
setSignal(
|
|
5441
|
+
if (a[t]) {
|
|
5442
|
+
setSignal(a[t], () => isWrappable(r) ? wrap(r, e) : r);
|
|
5062
5443
|
} else if (!s) {
|
|
5063
|
-
const n = upsertStoreNode(e,
|
|
5444
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5064
5445
|
setSignal(n, () => isWrappable(r) ? wrap(r, e) : r);
|
|
5065
5446
|
}
|
|
5066
5447
|
} else if (n === "invalidate") {
|
|
5067
|
-
if (
|
|
5068
|
-
setSignal(
|
|
5069
|
-
delete
|
|
5448
|
+
if (a[t]) {
|
|
5449
|
+
setSignal(a[t], {});
|
|
5450
|
+
delete a[t];
|
|
5070
5451
|
}
|
|
5071
5452
|
} else {
|
|
5072
|
-
if (
|
|
5073
|
-
setSignal(
|
|
5453
|
+
if (a[t]) {
|
|
5454
|
+
setSignal(a[t], undefined);
|
|
5074
5455
|
} else if (!s) {
|
|
5075
|
-
const n = upsertStoreNode(e,
|
|
5456
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5076
5457
|
setSignal(n, undefined);
|
|
5077
5458
|
}
|
|
5078
5459
|
}
|
|
@@ -5091,7 +5472,7 @@ let Writing = null;
|
|
|
5091
5472
|
* itself (the derive function works its own draft while uninitialized).
|
|
5092
5473
|
*/ function throwIfUninitialized(e) {
|
|
5093
5474
|
const t = e[STORE_FIREWALL];
|
|
5094
|
-
if (t && t.
|
|
5475
|
+
if (t && t.xe & STATUS_UNINITIALIZED) throw t.De ?? new NotReadyError(t);
|
|
5095
5476
|
}
|
|
5096
5477
|
|
|
5097
5478
|
const storeTraps = {
|
|
@@ -5104,6 +5485,33 @@ const storeTraps = {
|
|
|
5104
5485
|
trackSelf(e);
|
|
5105
5486
|
return n;
|
|
5106
5487
|
}
|
|
5488
|
+
// Hot path: an existing node on a plain target — no firewall (so neither
|
|
5489
|
+
// selfRead nor the uninitialized guard can apply), no override layers,
|
|
5490
|
+
// no write scope, and a raw (non-proxy) source. This is the shape of
|
|
5491
|
+
// every effect re-read of a settled store; it pays one node read and the
|
|
5492
|
+
// wrap check, nothing else. Any exotic bit falls through to the full
|
|
5493
|
+
// resolution below, and dev strictRead keeps its warning path.
|
|
5494
|
+
if (e[STORE_FIREWALL] === undefined && e[STORE_OVERRIDE] === undefined && e[STORE_OPTIMISTIC_OVERRIDE] === undefined && !writeOverride && (Writing === null || !Writing.has(n))) {
|
|
5495
|
+
const n = e[STORE_NODE];
|
|
5496
|
+
const r = n && n[t];
|
|
5497
|
+
if (r !== undefined && e[STORE_VALUE][$TARGET] === undefined) {
|
|
5498
|
+
// readNodeFast is read()'s plain-signal fast path hoisted over the
|
|
5499
|
+
// call; READ_SLOW means a global read window (latest/pending-check/
|
|
5500
|
+
// transition/lane/snapshot capture) or a node layer is active, and
|
|
5501
|
+
// only then does the full read() resolution have anything to do.
|
|
5502
|
+
let t = readNodeFast(r);
|
|
5503
|
+
if (t === READ_SLOW) t = read(r);
|
|
5504
|
+
if (t === $DELETED) t = undefined;
|
|
5505
|
+
// Every node-writing site wraps wrappables before setSignal (see the
|
|
5506
|
+
// dev assertion below), so re-wrapping on read is redundant — except
|
|
5507
|
+
// during snapshot capture, where read() can surface a raw captured
|
|
5508
|
+
// value seeded from snapshot props.
|
|
5509
|
+
if (!snapshotCaptureActive) {
|
|
5510
|
+
return t;
|
|
5511
|
+
}
|
|
5512
|
+
return isWrappable(t) ? wrap(t, e) : t;
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5107
5515
|
const r = getObserver() === e[STORE_FIREWALL];
|
|
5108
5516
|
const i = getNodes(e, STORE_NODE);
|
|
5109
5517
|
const o = r ? undefined : i[t];
|
|
@@ -5113,33 +5521,38 @@ const storeTraps = {
|
|
|
5113
5521
|
}
|
|
5114
5522
|
const u = getOverlayLayer(e, t);
|
|
5115
5523
|
const l = !!u;
|
|
5116
|
-
const
|
|
5117
|
-
const
|
|
5524
|
+
const a = !!e[STORE_VALUE][$TARGET];
|
|
5525
|
+
const c = u ?? e[STORE_VALUE];
|
|
5118
5526
|
if (!o) {
|
|
5119
|
-
const r = Object.getOwnPropertyDescriptor(
|
|
5527
|
+
const r = Object.getOwnPropertyDescriptor(c, t);
|
|
5120
5528
|
if (r && r.get) return r.get.call(n);
|
|
5121
5529
|
if (!r && !l && e[STORE_CUSTOM_PROTO]) {
|
|
5122
|
-
const e = unwrapStoreValue(
|
|
5530
|
+
const e = unwrapStoreValue(c);
|
|
5123
5531
|
if (hasInheritedAccessor(e, t)) {
|
|
5124
|
-
return Reflect.get(
|
|
5532
|
+
return Reflect.get(c, t, n);
|
|
5125
5533
|
}
|
|
5126
5534
|
}
|
|
5127
5535
|
}
|
|
5128
5536
|
if (writeOnly(n)) {
|
|
5129
5537
|
if (isPrototypePollutionKey$1(t) && !hasOwnStoreProperty(e, t)) return undefined;
|
|
5130
|
-
let n = o && (l || !
|
|
5538
|
+
let n = o && (l || !a) ? visibleNodeValue(o) : c[t];
|
|
5131
5539
|
n === $DELETED && (n = undefined);
|
|
5132
5540
|
if (!isWrappable(n)) return n;
|
|
5541
|
+
// Shallow boundary: records are replaced, never edited in place. Reads
|
|
5542
|
+
// inside a setter serve the raw so read-then-replace, filter/pop and
|
|
5543
|
+
// projection derives all work; in-place mutation of a raw is inert by
|
|
5544
|
+
// construction — the same contract as a markRaw child in a deep store.
|
|
5545
|
+
if (e[STORE_SHALLOW]) return n;
|
|
5133
5546
|
const r = wrap(n, e);
|
|
5134
5547
|
Writing?.add(r);
|
|
5135
5548
|
return r;
|
|
5136
5549
|
}
|
|
5137
|
-
let f = o ? l || !
|
|
5550
|
+
let f = o ? l || !a ? read(i[t]) : (read(i[t]), c[t]) : c[t];
|
|
5138
5551
|
f === $DELETED && (f = undefined);
|
|
5139
5552
|
if (!o) {
|
|
5140
|
-
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(
|
|
5553
|
+
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(c, t)) {
|
|
5141
5554
|
let t;
|
|
5142
|
-
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(
|
|
5555
|
+
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(c) : f;
|
|
5143
5556
|
} else if (getObserver() && !r) {
|
|
5144
5557
|
return read(getNode(e, i, t, isWrappable(f) ? wrap(f, e) : f, isEqual, e[STORE_SNAPSHOT_PROPS]));
|
|
5145
5558
|
}
|
|
@@ -5177,37 +5590,38 @@ const storeTraps = {
|
|
|
5177
5590
|
const {base: i, overrideKey: o, state: s} = prepareStoreWrite(e, r, t);
|
|
5178
5591
|
const u = getOverlayLayer(e, t);
|
|
5179
5592
|
const l = u ? u[t] : i;
|
|
5180
|
-
const
|
|
5181
|
-
const
|
|
5593
|
+
const a = u ? u[t] !== $DELETED : t in e[STORE_VALUE];
|
|
5594
|
+
const c = unwrapStoreValue(n);
|
|
5595
|
+
if (e[STORE_SHALLOW] && isWrappable(c)) rawValues.add(c);
|
|
5182
5596
|
// Symbol-keyed writes on arrays are metadata, not index writes — never run
|
|
5183
5597
|
// them through the numeric index/length machinery (`parseInt` on a symbol
|
|
5184
5598
|
// throws). #2769
|
|
5185
5599
|
const f = typeof t === "string" ? Number(t) : -1;
|
|
5186
5600
|
const E = Array.isArray(s) && Number.isInteger(f) && f >= 0 && f < 4294967295 && String(f) === t;
|
|
5187
|
-
const
|
|
5188
|
-
const
|
|
5189
|
-
const T = E &&
|
|
5190
|
-
if (l ===
|
|
5601
|
+
const d = E ? f + 1 : 0;
|
|
5602
|
+
const S = E && (getOverlayLayer(e, "length") ?? s).length;
|
|
5603
|
+
const T = E && d > S ? d : undefined;
|
|
5604
|
+
if (l === c && T === undefined) return true;
|
|
5191
5605
|
armOptimisticStoreWrite(e, r);
|
|
5192
|
-
if (
|
|
5606
|
+
if (c !== undefined && c === i && T === undefined) {
|
|
5193
5607
|
delete e[o]?.[t];
|
|
5194
5608
|
if (o === STORE_OPTIMISTIC_OVERRIDE) delete e[STORE_OPTIMISTIC_OWNERS]?.[t];
|
|
5195
5609
|
} else {
|
|
5196
5610
|
const n = e[o] || (e[o] = Object.create(null));
|
|
5197
|
-
n[t] =
|
|
5611
|
+
n[t] = c;
|
|
5198
5612
|
stampOptimisticOwner(e, o, t);
|
|
5199
5613
|
if (T !== undefined) {
|
|
5200
5614
|
n.length = T;
|
|
5201
5615
|
stampOptimisticOwner(e, o, "length");
|
|
5202
5616
|
}
|
|
5203
5617
|
}
|
|
5204
|
-
notifyStoreProperty(e, t, "set",
|
|
5618
|
+
notifyStoreProperty(e, t, "set", c, l, a);
|
|
5205
5619
|
// Shrinking an array's length must remove the truncated indices, otherwise
|
|
5206
5620
|
// they leak through `has`, `ownKeys`, and (tracked) index reads from the
|
|
5207
5621
|
// underlying value. Mark each as deleted and notify so reactive reads update. #2768
|
|
5208
|
-
if (Array.isArray(s) && t === "length" && typeof
|
|
5622
|
+
if (Array.isArray(s) && t === "length" && typeof c === "number" && typeof l === "number" && c < l) {
|
|
5209
5623
|
const t = e[o] || (e[o] = Object.create(null));
|
|
5210
|
-
for (let n =
|
|
5624
|
+
for (let n = c; n < l; n++) {
|
|
5211
5625
|
if (t[n] === $DELETED) continue;
|
|
5212
5626
|
const r = n in t ? t[n] : s[n];
|
|
5213
5627
|
if (!(n in t) && !(n in s)) continue;
|
|
@@ -5222,7 +5636,7 @@ const storeTraps = {
|
|
|
5222
5636
|
if (t.length) {
|
|
5223
5637
|
setSignal(t.length, T);
|
|
5224
5638
|
} else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
|
|
5225
|
-
const n = upsertStoreNode(e, t, "length",
|
|
5639
|
+
const n = upsertStoreNode(e, t, "length", S, e[STORE_SNAPSHOT_PROPS]);
|
|
5226
5640
|
setSignal(n, T);
|
|
5227
5641
|
}
|
|
5228
5642
|
}
|
|
@@ -5370,7 +5784,7 @@ function storeSetter(e, t) {
|
|
|
5370
5784
|
}
|
|
5371
5785
|
|
|
5372
5786
|
function createStore(e, t, n) {
|
|
5373
|
-
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : wrap(e);
|
|
5787
|
+
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : t?.shallow ? wrapShallow(e) : wrap(e);
|
|
5374
5788
|
return [ i, r ? e => {
|
|
5375
5789
|
// Mark the projection as manually written before notifying property nodes.
|
|
5376
5790
|
suppressComputedRecompute(i[$REFRESH]);
|
|
@@ -5386,7 +5800,7 @@ function createStore(e, t, n) {
|
|
|
5386
5800
|
* nothing is stored downstream and nothing can be stranded or stripped by
|
|
5387
5801
|
* mid-window recomputes.
|
|
5388
5802
|
*/ function markAffects(e) {
|
|
5389
|
-
e.
|
|
5803
|
+
e.k = (e.k || 0) + 1;
|
|
5390
5804
|
shiftAffectsMarks(1);
|
|
5391
5805
|
}
|
|
5392
5806
|
|
|
@@ -5402,17 +5816,17 @@ function createStore(e, t, n) {
|
|
|
5402
5816
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5403
5817
|
* no visual change.
|
|
5404
5818
|
*/ function notifyMarkBoundaries(e) {
|
|
5405
|
-
if (!e.
|
|
5819
|
+
if (!e.G && !e.nt) return;
|
|
5406
5820
|
const t = new NotReadyError(e);
|
|
5407
|
-
t.
|
|
5821
|
+
t.we = true;
|
|
5408
5822
|
const n = new Set;
|
|
5409
5823
|
const visit = e => {
|
|
5410
5824
|
if (n.has(e)) return;
|
|
5411
5825
|
n.add(e);
|
|
5412
5826
|
// Display consumers (render effects, boundary computeds) act on the
|
|
5413
5827
|
// notification; descent stops there, exactly like the status rails.
|
|
5414
|
-
if (e.
|
|
5415
|
-
e.
|
|
5828
|
+
if (e.Nt) {
|
|
5829
|
+
e.Nt(STATUS_PENDING, t);
|
|
5416
5830
|
return;
|
|
5417
5831
|
}
|
|
5418
5832
|
forEachDependent(e, visit);
|
|
@@ -5433,7 +5847,7 @@ function createStore(e, t, n) {
|
|
|
5433
5847
|
globalQueue.D.L.push(e);
|
|
5434
5848
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5435
5849
|
// without them there is no materialized verdict to poke.
|
|
5436
|
-
GlobalQueue.
|
|
5850
|
+
GlobalQueue.Te !== null && GlobalQueue.Te(e);
|
|
5437
5851
|
notifyMarkBoundaries(e);
|
|
5438
5852
|
schedule();
|
|
5439
5853
|
}
|
|
@@ -5445,10 +5859,10 @@ function createStore(e, t, n) {
|
|
|
5445
5859
|
* setSignal would open a fresh override window that nothing settles).
|
|
5446
5860
|
*/ function releaseAffectsMark(e) {
|
|
5447
5861
|
shiftAffectsMarks(-1);
|
|
5448
|
-
e.
|
|
5449
|
-
if (!e.
|
|
5450
|
-
GlobalQueue.
|
|
5451
|
-
GlobalQueue.
|
|
5862
|
+
e.k--;
|
|
5863
|
+
if (!e.k) {
|
|
5864
|
+
GlobalQueue.Te !== null && GlobalQueue.Te(e, true);
|
|
5865
|
+
GlobalQueue.te?.(e);
|
|
5452
5866
|
}
|
|
5453
5867
|
}
|
|
5454
5868
|
|
|
@@ -5465,11 +5879,11 @@ function createStore(e, t, n) {
|
|
|
5465
5879
|
// Each call site is gated by state only this module creates (a non-empty
|
|
5466
5880
|
// `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
|
|
5467
5881
|
// hooks are installed before the first time any of them can fire.
|
|
5468
|
-
GlobalQueue.
|
|
5882
|
+
GlobalQueue.ne = releaseAffectsMarks;
|
|
5469
5883
|
|
|
5470
|
-
GlobalQueue.
|
|
5884
|
+
GlobalQueue.re = markAffects;
|
|
5471
5885
|
|
|
5472
|
-
GlobalQueue.
|
|
5886
|
+
GlobalQueue.ie = releaseAffectsMark;
|
|
5473
5887
|
|
|
5474
5888
|
function affects(e, t) {
|
|
5475
5889
|
const n = e?.[$TARGET];
|
|
@@ -5490,8 +5904,10 @@ function createOptimisticStore(e, t, n) {
|
|
|
5490
5904
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
5491
5905
|
// node can be created.
|
|
5492
5906
|
installOptimisticEngine();
|
|
5493
|
-
GlobalQueue.
|
|
5907
|
+
GlobalQueue.ee ||= clearOptimisticStores;
|
|
5494
5908
|
const r = typeof e === "function";
|
|
5909
|
+
// Plain form: the second slot carries options.
|
|
5910
|
+
if (!r && n === undefined) n = t;
|
|
5495
5911
|
const i = r ? t : e;
|
|
5496
5912
|
const o = r ? e : undefined;
|
|
5497
5913
|
// Create optimistic projection store
|
|
@@ -5555,30 +5971,32 @@ function clearOptimisticStores(e, t) {
|
|
|
5555
5971
|
delete n[l];
|
|
5556
5972
|
if (i) delete i[l];
|
|
5557
5973
|
s = true;
|
|
5558
|
-
const
|
|
5559
|
-
if (
|
|
5974
|
+
const a = r?.[l];
|
|
5975
|
+
if (a) {
|
|
5560
5976
|
// Clear lane association so effects go to regular queue
|
|
5561
|
-
|
|
5977
|
+
a.i = undefined;
|
|
5562
5978
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
5563
5979
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
5564
5980
|
const t = getOverlayLayer(e, l);
|
|
5565
5981
|
const n = t ? t[l] : e[STORE_VALUE][l];
|
|
5566
5982
|
const r = n === $DELETED ? undefined : n;
|
|
5567
5983
|
const i = isWrappable(r) ? wrap(r, e) : r;
|
|
5568
|
-
const o = visibleNodeValue(
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
if (!
|
|
5574
|
-
insertSubs(
|
|
5984
|
+
const o = visibleNodeValue(a);
|
|
5985
|
+
a.A = NOT_PENDING;
|
|
5986
|
+
a.R = null;
|
|
5987
|
+
a.U = NOT_PENDING;
|
|
5988
|
+
a.ke = i;
|
|
5989
|
+
if (!a.At || !a.At(o, i)) {
|
|
5990
|
+
insertSubs(a, true);
|
|
5575
5991
|
schedule();
|
|
5576
5992
|
}
|
|
5577
5993
|
}
|
|
5578
5994
|
}
|
|
5579
5995
|
if (!u) {
|
|
5580
|
-
delete
|
|
5581
|
-
delete
|
|
5996
|
+
// Assignment, not delete: StoreNode targets share one pre-initialized
|
|
5997
|
+
// hidden class (see createStoreProxy) and a delete would demote it.
|
|
5998
|
+
e[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
5999
|
+
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
5582
6000
|
}
|
|
5583
6001
|
// Notify $TRACK
|
|
5584
6002
|
if (s && r?.[$TRACK]) {
|
|
@@ -5593,9 +6011,14 @@ function clearOptimisticStores(e, t) {
|
|
|
5593
6011
|
function createOptimisticProjectionInternal(e, t, n) {
|
|
5594
6012
|
let r;
|
|
5595
6013
|
const i = new WeakMap;
|
|
6014
|
+
const o = !!n?.shallow;
|
|
5596
6015
|
const wrapper = e => {
|
|
5597
6016
|
e[STORE_WRAP] = wrapProjection;
|
|
5598
6017
|
e[STORE_LOOKUP] = i;
|
|
6018
|
+
if (o) {
|
|
6019
|
+
e[STORE_SHALLOW] = true;
|
|
6020
|
+
markRawIngest(e[STORE_VALUE]);
|
|
6021
|
+
}
|
|
5599
6022
|
e[STORE_OPTIMISTIC] = true;
|
|
5600
6023
|
// Mark as optimistic store
|
|
5601
6024
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
@@ -5612,7 +6035,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5612
6035
|
i.set(e, t);
|
|
5613
6036
|
return t;
|
|
5614
6037
|
};
|
|
5615
|
-
const
|
|
6038
|
+
const s = wrapProjection(t);
|
|
5616
6039
|
// If there's a projection function, create a computed to drive it
|
|
5617
6040
|
if (e) {
|
|
5618
6041
|
// All writes inside firewall recompute must go to STORE_OVERRIDE (base), not
|
|
@@ -5621,7 +6044,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5621
6044
|
// async yields because they fire outside any enclosing try/finally. It also
|
|
5622
6045
|
// consumes stale optimistic overlays once fresh projected data lands.
|
|
5623
6046
|
const clearProjectionOverride = () => {
|
|
5624
|
-
const e =
|
|
6047
|
+
const e = s[$TARGET];
|
|
5625
6048
|
if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e);
|
|
5626
6049
|
};
|
|
5627
6050
|
const wrapCommit = e => {
|
|
@@ -5637,15 +6060,15 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5637
6060
|
r = computed(() => {
|
|
5638
6061
|
setProjectionWriteActive(true);
|
|
5639
6062
|
try {
|
|
5640
|
-
runProjectionComputed(
|
|
6063
|
+
runProjectionComputed(s, e, n?.key || "id", wrapCommit, clearProjectionOverride);
|
|
5641
6064
|
} finally {
|
|
5642
6065
|
setProjectionWriteActive(false);
|
|
5643
6066
|
}
|
|
5644
6067
|
}, undefined);
|
|
5645
|
-
r.
|
|
6068
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
5646
6069
|
}
|
|
5647
6070
|
return {
|
|
5648
|
-
store:
|
|
6071
|
+
store: s,
|
|
5649
6072
|
node: r
|
|
5650
6073
|
};
|
|
5651
6074
|
}
|
|
@@ -5751,11 +6174,11 @@ function updatePath(e, t, n = 0) {
|
|
|
5751
6174
|
});
|
|
5752
6175
|
|
|
5753
6176
|
function snapshotImpl(e, t, n, r) {
|
|
5754
|
-
let i, o, s, u, l,
|
|
6177
|
+
let i, o, s, u, l, a;
|
|
5755
6178
|
if (!isWrappable(e)) return e;
|
|
5756
6179
|
if (n && n.has(e)) return n.get(e);
|
|
5757
6180
|
if (!n) n = new Map;
|
|
5758
|
-
if (i = e[$TARGET] ||
|
|
6181
|
+
if (i = e[$TARGET] || lookupTarget(e, r)) {
|
|
5759
6182
|
if (t) {
|
|
5760
6183
|
trackSelf(i, $TRACK);
|
|
5761
6184
|
// A tracked walk reads THROUGH the record without touching the proxy
|
|
@@ -5763,6 +6186,18 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5763
6186
|
if (pendingCheckActive) witnessAffectsMark(i);
|
|
5764
6187
|
}
|
|
5765
6188
|
s = mergedOverlay(i);
|
|
6189
|
+
// A derived store's STORE_VALUE is the inner store's live proxy
|
|
6190
|
+
// (store-in-store: createOptimisticStore/createProjection over a store).
|
|
6191
|
+
// Without an overlay of its own, the fast path below would map to — and
|
|
6192
|
+
// could return — that proxy verbatim. Recurse instead so the
|
|
6193
|
+
// inner store's own target branch unwraps it (chains of any depth).
|
|
6194
|
+
// With an overlay, a fresh `result` is always built, so the walk over the
|
|
6195
|
+
// inner proxy already copies plain values.
|
|
6196
|
+
if (!s && i[STORE_VALUE][$TARGET]) {
|
|
6197
|
+
l = snapshotImpl(i[STORE_VALUE], t, n, r);
|
|
6198
|
+
n.set(e, l);
|
|
6199
|
+
return l;
|
|
6200
|
+
}
|
|
5766
6201
|
o = Array.isArray(i[STORE_VALUE]);
|
|
5767
6202
|
n.set(e, s ? u = o ? [] : Object.create(Object.getPrototypeOf(i[STORE_VALUE])) : i[STORE_VALUE]);
|
|
5768
6203
|
e = i[STORE_VALUE];
|
|
@@ -5773,26 +6208,26 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5773
6208
|
}
|
|
5774
6209
|
if (o) {
|
|
5775
6210
|
const o = s?.length ?? e.length;
|
|
5776
|
-
for (let
|
|
5777
|
-
|
|
5778
|
-
if (
|
|
5779
|
-
if (t && isWrappable(
|
|
5780
|
-
if ((l = snapshotImpl(
|
|
6211
|
+
for (let c = 0; c < o; c++) {
|
|
6212
|
+
a = s && c in s ? s[c] : e[c];
|
|
6213
|
+
if (a === $DELETED) continue;
|
|
6214
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6215
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5781
6216
|
if (!u) n.set(e, u = [ ...e ]);
|
|
5782
|
-
u[
|
|
6217
|
+
u[c] = l;
|
|
5783
6218
|
}
|
|
5784
6219
|
}
|
|
5785
6220
|
// Enumerate array symbols separately to avoid scanning indices twice.
|
|
5786
6221
|
// Spread copies omit symbols, so assign them after the numeric walk.
|
|
5787
|
-
const
|
|
5788
|
-
for (let o = 0, f =
|
|
5789
|
-
const f =
|
|
6222
|
+
const c = r ? getStoreSymbols(e, s) : [];
|
|
6223
|
+
for (let o = 0, f = c.length; o < f; o++) {
|
|
6224
|
+
const f = c[o];
|
|
5790
6225
|
const E = getPropertyDescriptor(e, s, f);
|
|
5791
6226
|
if (!E || E.get) continue;
|
|
5792
|
-
|
|
5793
|
-
if (t && isWrappable(
|
|
5794
|
-
l = snapshotImpl(
|
|
5795
|
-
if (l !==
|
|
6227
|
+
a = s && f in s ? s[f] : e[f];
|
|
6228
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6229
|
+
l = snapshotImpl(a, t, n, r);
|
|
6230
|
+
if (l !== a || u) {
|
|
5796
6231
|
if (!u) n.set(e, u = Object.assign([ ...e ], e));
|
|
5797
6232
|
u[f] = l;
|
|
5798
6233
|
}
|
|
@@ -5807,31 +6242,31 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5807
6242
|
// A lookup means this object belongs to an immutable store backing tree,
|
|
5808
6243
|
// even if that nested value has not needed its own proxy yet.
|
|
5809
6244
|
const o = r ? getStoreKeys(e, undefined) : getKeys(e, undefined);
|
|
5810
|
-
for (let s = 0,
|
|
5811
|
-
const
|
|
5812
|
-
const f = Object.getOwnPropertyDescriptor(e,
|
|
6245
|
+
for (let s = 0, c = o.length; s < c; s++) {
|
|
6246
|
+
const c = o[s];
|
|
6247
|
+
const f = Object.getOwnPropertyDescriptor(e, c);
|
|
5813
6248
|
if (f.get) continue;
|
|
5814
|
-
|
|
5815
|
-
if (t && isWrappable(
|
|
5816
|
-
if ((l = snapshotImpl(
|
|
6249
|
+
a = f.value;
|
|
6250
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6251
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5817
6252
|
if (!u) {
|
|
5818
6253
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5819
6254
|
Object.assign(u, e);
|
|
5820
6255
|
}
|
|
5821
|
-
u[
|
|
6256
|
+
u[c] = l;
|
|
5822
6257
|
}
|
|
5823
6258
|
}
|
|
5824
6259
|
} else {
|
|
5825
6260
|
// An override only exists on a store record, and the target branch above
|
|
5826
6261
|
// always set `lookup` alongside it — so this branch is always store-keyed.
|
|
5827
6262
|
const o = getStoreKeys(e, s);
|
|
5828
|
-
for (let
|
|
5829
|
-
let f = o[
|
|
6263
|
+
for (let c = 0, f = o.length; c < f; c++) {
|
|
6264
|
+
let f = o[c];
|
|
5830
6265
|
const E = getPropertyDescriptor(e, s, f);
|
|
5831
6266
|
if (E.get) continue;
|
|
5832
|
-
|
|
5833
|
-
if (t && isWrappable(
|
|
5834
|
-
if ((l = snapshotImpl(
|
|
6267
|
+
a = f in s ? s[f] : e[f];
|
|
6268
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6269
|
+
if ((l = snapshotImpl(a, t, n, r)) !== e[f] || u) {
|
|
5835
6270
|
if (!u) {
|
|
5836
6271
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5837
6272
|
Object.assign(u, e);
|
|
@@ -6055,23 +6490,23 @@ function mapArray(e, t, n) {
|
|
|
6055
6490
|
const o = t;
|
|
6056
6491
|
const s = {
|
|
6057
6492
|
wt: createOwner(),
|
|
6058
|
-
|
|
6493
|
+
vt: 0,
|
|
6059
6494
|
Lt: e,
|
|
6060
|
-
Ut: [],
|
|
6061
|
-
kt: o,
|
|
6062
6495
|
Vt: [],
|
|
6063
|
-
|
|
6064
|
-
|
|
6496
|
+
Gt: o,
|
|
6497
|
+
Ut: [],
|
|
6498
|
+
kt: [],
|
|
6499
|
+
Wt: r,
|
|
6065
6500
|
Ft: r || n?.keyed === false ? [] : undefined,
|
|
6066
|
-
|
|
6067
|
-
|
|
6501
|
+
xt: i && n?.keyed !== false ? [] : undefined,
|
|
6502
|
+
Qt: n?.keyed === false,
|
|
6068
6503
|
Ht: n?.fallback
|
|
6069
6504
|
};
|
|
6070
6505
|
const u = computed(updateKeyedMap.bind(s));
|
|
6071
6506
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6072
6507
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6073
|
-
s.wt.
|
|
6074
|
-
u.
|
|
6508
|
+
s.wt.Je = u;
|
|
6509
|
+
u.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6075
6510
|
return accessor(u);
|
|
6076
6511
|
}
|
|
6077
6512
|
|
|
@@ -6096,45 +6531,45 @@ function updateKeyedMap() {
|
|
|
6096
6531
|
let n, r, i, o,
|
|
6097
6532
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6098
6533
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6099
|
-
s = this.Ft ? this.
|
|
6534
|
+
s = this.Ft ? this.Qt ? () => {
|
|
6100
6535
|
i[r] = signal(e[r], pureOptions);
|
|
6101
|
-
return this.
|
|
6536
|
+
return this.Gt(accessor(i[r]), r);
|
|
6102
6537
|
} : () => {
|
|
6103
6538
|
i[r] = signal(e[r], pureOptions);
|
|
6104
6539
|
o && (o[r] = signal(r, pureOptions));
|
|
6105
|
-
return this.
|
|
6106
|
-
} : this.
|
|
6540
|
+
return this.Gt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6541
|
+
} : this.xt ? () => {
|
|
6107
6542
|
const t = e[r];
|
|
6108
6543
|
o[r] = signal(r, pureOptions);
|
|
6109
|
-
return this.
|
|
6544
|
+
return this.Gt(t, accessor(o[r]));
|
|
6110
6545
|
} : () => {
|
|
6111
6546
|
const t = e[r];
|
|
6112
|
-
return this.
|
|
6547
|
+
return this.Gt(t);
|
|
6113
6548
|
};
|
|
6114
6549
|
// fast path for empty arrays
|
|
6115
6550
|
if (t === 0) {
|
|
6116
|
-
if (this.
|
|
6551
|
+
if (this.vt !== 0) {
|
|
6117
6552
|
this.wt.dispose(false);
|
|
6118
|
-
this.
|
|
6119
|
-
this.Ut = [];
|
|
6553
|
+
this.kt = [];
|
|
6120
6554
|
this.Vt = [];
|
|
6121
|
-
this.
|
|
6555
|
+
this.Ut = [];
|
|
6556
|
+
this.vt = 0;
|
|
6122
6557
|
this.Ft && (this.Ft = []);
|
|
6123
|
-
this.
|
|
6558
|
+
this.xt && (this.xt = []);
|
|
6124
6559
|
}
|
|
6125
|
-
if (this.Ht && !this.
|
|
6560
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6126
6561
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6127
6562
|
// dispose it before re-creating
|
|
6128
|
-
this.
|
|
6129
|
-
this.
|
|
6563
|
+
this.kt[0]?.dispose();
|
|
6564
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6130
6565
|
}
|
|
6131
6566
|
}
|
|
6132
6567
|
// fast path for new create
|
|
6133
|
-
else if (this.
|
|
6568
|
+
else if (this.vt === 0) {
|
|
6134
6569
|
const u = new Array(t);
|
|
6135
6570
|
const l = new Array(t);
|
|
6136
6571
|
i = this.Ft && new Array(t);
|
|
6137
|
-
o = this.
|
|
6572
|
+
o = this.xt && new Array(t);
|
|
6138
6573
|
try {
|
|
6139
6574
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6140
6575
|
} catch (e) {
|
|
@@ -6142,58 +6577,67 @@ function updateKeyedMap() {
|
|
|
6142
6577
|
throw e;
|
|
6143
6578
|
}
|
|
6144
6579
|
// commit
|
|
6145
|
-
if (this.
|
|
6580
|
+
if (this.kt[0]) this.kt[0].dispose();
|
|
6146
6581
|
// previous fallback
|
|
6147
|
-
this.
|
|
6148
|
-
this.
|
|
6582
|
+
this.Ut = u;
|
|
6583
|
+
this.kt = l;
|
|
6149
6584
|
i && (this.Ft = i);
|
|
6150
|
-
o && (this.
|
|
6151
|
-
this.
|
|
6152
|
-
this.
|
|
6585
|
+
o && (this.xt = o);
|
|
6586
|
+
this.Vt = e.slice(0);
|
|
6587
|
+
this.vt = t;
|
|
6153
6588
|
} else {
|
|
6154
|
-
let u, l,
|
|
6155
|
-
i = this.Ft ? new Array(t) : undefined;
|
|
6156
|
-
o = this.Wt ? new Array(t) : undefined;
|
|
6589
|
+
let u, l, a, c, f, E, d, S, T;
|
|
6157
6590
|
// skip common prefix
|
|
6158
|
-
for (u = 0, l = Math.min(this.
|
|
6591
|
+
for (u = 0, l = Math.min(this.vt, t); u < l && (this.Vt[u] === e[u] || this.Ft && compare(this.Wt, this.Vt[u], e[u])); u++) {
|
|
6159
6592
|
if (this.Ft) setSignal(this.Ft[u], e[u]);
|
|
6160
6593
|
}
|
|
6161
|
-
// common suffix
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6594
|
+
// skip common suffix — counted only; retained entries land in one pass
|
|
6595
|
+
// at commit instead of being staged and copied twice
|
|
6596
|
+
for (l = this.vt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.Ft && compare(this.Wt, this.Vt[l], e[a])); l--,
|
|
6597
|
+
a--) ;
|
|
6598
|
+
// no structural change (every position matched in place at equal
|
|
6599
|
+
// length — the common post-reconcile shape): keep the same mapped
|
|
6600
|
+
// array identity so downstream consumers don't re-run at all
|
|
6601
|
+
if (u === t && this.vt === t) {
|
|
6602
|
+
this.Vt = e.slice(0);
|
|
6603
|
+
return;
|
|
6168
6604
|
}
|
|
6169
|
-
|
|
6605
|
+
const O = t - this.vt;
|
|
6606
|
+
const _ = new Array(t);
|
|
6607
|
+
const p = new Array(t);
|
|
6608
|
+
i = this.Ft ? new Array(t) : undefined;
|
|
6609
|
+
o = this.xt ? new Array(t) : undefined;
|
|
6610
|
+
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6611
|
+
// scanning backwards so we encounter them in natural order
|
|
6170
6612
|
E = new Map;
|
|
6171
|
-
|
|
6172
|
-
for (r =
|
|
6173
|
-
|
|
6174
|
-
f = this.
|
|
6613
|
+
d = new Array(a + 1);
|
|
6614
|
+
for (r = a; r >= u; r--) {
|
|
6615
|
+
c = e[r];
|
|
6616
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6175
6617
|
n = E.get(f);
|
|
6176
|
-
|
|
6618
|
+
d[r] = n === undefined ? -1 : n;
|
|
6177
6619
|
E.set(f, r);
|
|
6178
6620
|
}
|
|
6179
|
-
// 1) step through
|
|
6621
|
+
// 1) step through the old changed window and see if items can be found
|
|
6622
|
+
// in the new set; if so, stage them at their new positions; if not,
|
|
6623
|
+
// queue them for disposal at commit
|
|
6180
6624
|
for (n = u; n <= l; n++) {
|
|
6181
|
-
|
|
6182
|
-
f = this.
|
|
6625
|
+
c = this.Vt[n];
|
|
6626
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6183
6627
|
r = E.get(f);
|
|
6184
6628
|
if (r !== undefined && r !== -1) {
|
|
6185
|
-
_[r] = this.
|
|
6186
|
-
p[r] = this.
|
|
6629
|
+
_[r] = this.Ut[n];
|
|
6630
|
+
p[r] = this.kt[n];
|
|
6187
6631
|
i && (i[r] = this.Ft[n]);
|
|
6188
|
-
o && (o[r] = this.
|
|
6189
|
-
r =
|
|
6632
|
+
o && (o[r] = this.xt[n]);
|
|
6633
|
+
r = d[r];
|
|
6190
6634
|
E.set(f, r);
|
|
6191
|
-
} else (
|
|
6635
|
+
} else (S ??= []).push(this.kt[n]);
|
|
6192
6636
|
}
|
|
6193
6637
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6194
6638
|
try {
|
|
6195
|
-
for (r = u; r
|
|
6196
|
-
if (r
|
|
6639
|
+
for (r = u; r <= a; r++) {
|
|
6640
|
+
if (p[r] !== undefined) continue;
|
|
6197
6641
|
(T ??= []).push(p[r] = createOwner());
|
|
6198
6642
|
_[r] = runWithOwner(p[r], s);
|
|
6199
6643
|
}
|
|
@@ -6201,27 +6645,42 @@ function updateKeyedMap() {
|
|
|
6201
6645
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
6202
6646
|
throw e;
|
|
6203
6647
|
}
|
|
6204
|
-
// 3) commit: land
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6648
|
+
// 3) commit: land the retained prefix and suffix plus the staged window
|
|
6649
|
+
// into the fresh arrays, swap them in (new identity for downstream
|
|
6650
|
+
// change propagation), then dispose exited rows
|
|
6651
|
+
for (n = 0; n < u; n++) {
|
|
6652
|
+
_[n] = this.Ut[n];
|
|
6653
|
+
p[n] = this.kt[n];
|
|
6654
|
+
i && (i[n] = this.Ft[n]);
|
|
6655
|
+
o && (o[n] = this.xt[n]);
|
|
6656
|
+
}
|
|
6657
|
+
for (r = u; r <= a; r++) {
|
|
6658
|
+
if (i) setSignal(i[r], e[r]);
|
|
6659
|
+
if (o) setSignal(o[r], r);
|
|
6660
|
+
}
|
|
6661
|
+
for (r = a + 1; r < t; r++) {
|
|
6662
|
+
_[r] = this.Ut[r - O];
|
|
6663
|
+
p[r] = this.kt[r - O];
|
|
6208
6664
|
if (i) {
|
|
6209
|
-
|
|
6210
|
-
setSignal(
|
|
6665
|
+
i[r] = this.Ft[r - O];
|
|
6666
|
+
setSignal(i[r], e[r]);
|
|
6211
6667
|
}
|
|
6212
6668
|
if (o) {
|
|
6213
|
-
|
|
6214
|
-
setSignal(
|
|
6669
|
+
o[r] = this.xt[r - O];
|
|
6670
|
+
if (O !== 0) setSignal(o[r], r);
|
|
6215
6671
|
}
|
|
6216
6672
|
}
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6673
|
+
this.Ut = _;
|
|
6674
|
+
this.kt = p;
|
|
6675
|
+
i && (this.Ft = i);
|
|
6676
|
+
o && (this.xt = o);
|
|
6677
|
+
this.vt = t;
|
|
6678
|
+
// save a copy of the mapped items for the next update
|
|
6679
|
+
this.Vt = e.slice(0);
|
|
6680
|
+
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6222
6681
|
}
|
|
6223
6682
|
});
|
|
6224
|
-
return this.
|
|
6683
|
+
return this.Ut;
|
|
6225
6684
|
}
|
|
6226
6685
|
|
|
6227
6686
|
/**
|
|
@@ -6242,21 +6701,21 @@ function updateKeyedMap() {
|
|
|
6242
6701
|
const r = t;
|
|
6243
6702
|
const i = {
|
|
6244
6703
|
wt: createOwner(),
|
|
6245
|
-
|
|
6246
|
-
|
|
6704
|
+
vt: 0,
|
|
6705
|
+
Mt: 0,
|
|
6247
6706
|
$t: e,
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6707
|
+
Gt: r,
|
|
6708
|
+
kt: [],
|
|
6709
|
+
Ut: [],
|
|
6710
|
+
jt: n?.from,
|
|
6252
6711
|
Ht: n?.fallback
|
|
6253
6712
|
};
|
|
6254
6713
|
const o = computed(updateRepeat.bind(i));
|
|
6255
6714
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6256
6715
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6257
6716
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6258
|
-
i.wt.
|
|
6259
|
-
o.
|
|
6717
|
+
i.wt.Je = o;
|
|
6718
|
+
o.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6260
6719
|
return accessor(o);
|
|
6261
6720
|
}
|
|
6262
6721
|
|
|
@@ -6269,54 +6728,54 @@ function updateKeyedMap() {
|
|
|
6269
6728
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
6270
6729
|
function updateRepeat() {
|
|
6271
6730
|
const e = this.$t();
|
|
6272
|
-
const t = this.
|
|
6731
|
+
const t = this.jt?.() || 0;
|
|
6273
6732
|
runWithOwner(this.wt, () => {
|
|
6274
6733
|
if (e === 0) {
|
|
6275
|
-
if (this.
|
|
6734
|
+
if (this.vt !== 0) {
|
|
6276
6735
|
this.wt.dispose(false);
|
|
6277
|
-
this.
|
|
6278
|
-
this.
|
|
6279
|
-
this.
|
|
6736
|
+
this.kt = [];
|
|
6737
|
+
this.Ut = [];
|
|
6738
|
+
this.vt = 0;
|
|
6280
6739
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6281
|
-
this.
|
|
6740
|
+
this.Mt = 0;
|
|
6282
6741
|
}
|
|
6283
|
-
if (this.Ht && !this.
|
|
6742
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6284
6743
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6285
6744
|
// dispose it before re-creating
|
|
6286
|
-
this.
|
|
6287
|
-
this.
|
|
6745
|
+
this.kt[0]?.dispose();
|
|
6746
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6288
6747
|
}
|
|
6289
6748
|
return;
|
|
6290
6749
|
}
|
|
6291
6750
|
const n = t + e;
|
|
6292
|
-
const r = this.
|
|
6751
|
+
const r = this.Mt + this.vt;
|
|
6293
6752
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6294
6753
|
// windows are disjoint or when coming from empty/fallback.
|
|
6295
|
-
const i = Math.max(t, this.
|
|
6754
|
+
const i = Math.max(t, this.Mt);
|
|
6296
6755
|
const o = Math.min(n, r);
|
|
6297
6756
|
const s = new Array(e);
|
|
6298
6757
|
const u = new Array(e);
|
|
6299
6758
|
for (let e = i; e < o; e++) {
|
|
6300
|
-
u[e - t] = this.
|
|
6301
|
-
s[e - t] = this.
|
|
6759
|
+
u[e - t] = this.kt[e - this.Mt];
|
|
6760
|
+
s[e - t] = this.Ut[e - this.Mt];
|
|
6302
6761
|
}
|
|
6303
6762
|
try {
|
|
6304
6763
|
for (let e = t; e < n; e++) {
|
|
6305
6764
|
if (e >= i && e < o) continue;
|
|
6306
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
6765
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Gt(e));
|
|
6307
6766
|
}
|
|
6308
6767
|
} catch (e) {
|
|
6309
6768
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6310
6769
|
throw e;
|
|
6311
6770
|
}
|
|
6312
6771
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6313
|
-
if (this.
|
|
6314
|
-
this.
|
|
6315
|
-
this.
|
|
6316
|
-
this.
|
|
6317
|
-
this.
|
|
6772
|
+
if (this.vt === 0) this.kt[0]?.dispose(); else for (let e = this.Mt; e < r; e++) if (e < t || e >= n) this.kt[e - this.Mt].dispose();
|
|
6773
|
+
this.Ut = s;
|
|
6774
|
+
this.kt = u;
|
|
6775
|
+
this.Mt = t;
|
|
6776
|
+
this.vt = e;
|
|
6318
6777
|
});
|
|
6319
|
-
return this.
|
|
6778
|
+
return this.Ut;
|
|
6320
6779
|
}
|
|
6321
6780
|
|
|
6322
6781
|
function compare(e, t, n) {
|
|
@@ -6327,23 +6786,23 @@ function boundaryComputed(e, t) {
|
|
|
6327
6786
|
const n = computed(e, {
|
|
6328
6787
|
lazy: true
|
|
6329
6788
|
});
|
|
6330
|
-
n.
|
|
6789
|
+
n.Nt = (e, t) => {
|
|
6331
6790
|
// Use passed values if provided, otherwise read from node
|
|
6332
|
-
const r = e !== undefined ? e : n.
|
|
6333
|
-
const i = t !== undefined ? t : n.
|
|
6791
|
+
const r = e !== undefined ? e : n.xe;
|
|
6792
|
+
const i = t !== undefined ? t : n.De;
|
|
6334
6793
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6335
6794
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6336
6795
|
// a boundary that handles it is found.
|
|
6337
|
-
n.
|
|
6338
|
-
const o = n.
|
|
6796
|
+
n.xe &= ~n.Kt;
|
|
6797
|
+
const o = n.Be.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6339
6798
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6340
6799
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
6341
6800
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
6342
6801
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6343
|
-
const s = r & ~n.
|
|
6802
|
+
const s = r & ~n.Kt & (STATUS_PENDING | STATUS_ERROR);
|
|
6344
6803
|
if (s) {
|
|
6345
|
-
n.
|
|
6346
|
-
if (n.
|
|
6804
|
+
n.xe &= ~s;
|
|
6805
|
+
if (n.De === i && !(n.xe & (STATUS_PENDING | STATUS_ERROR))) n.De = undefined;
|
|
6347
6806
|
}
|
|
6348
6807
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6349
6808
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6354,16 +6813,16 @@ function boundaryComputed(e, t) {
|
|
|
6354
6813
|
throw i;
|
|
6355
6814
|
}
|
|
6356
6815
|
};
|
|
6357
|
-
n.
|
|
6358
|
-
n.
|
|
6816
|
+
n.Kt = t;
|
|
6817
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6359
6818
|
recompute(n, true);
|
|
6360
6819
|
return n;
|
|
6361
6820
|
}
|
|
6362
6821
|
|
|
6363
6822
|
function createBoundChildren(e, t, n, r) {
|
|
6364
|
-
const i = e.
|
|
6365
|
-
i.addChild(e.
|
|
6366
|
-
cleanup(() => i.removeChild(e.
|
|
6823
|
+
const i = e.Be;
|
|
6824
|
+
i.addChild(e.Be = n);
|
|
6825
|
+
cleanup(() => i.removeChild(e.Be));
|
|
6367
6826
|
return runWithOwner(e, () => {
|
|
6368
6827
|
const e = computed(t);
|
|
6369
6828
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -6385,53 +6844,53 @@ function isRevealController(e) {
|
|
|
6385
6844
|
}
|
|
6386
6845
|
|
|
6387
6846
|
function isSlotReady(e) {
|
|
6388
|
-
return isRevealController(e) ? e.
|
|
6847
|
+
return isRevealController(e) ? e.Yt() : e.qt.size === 0 && !e.Bt;
|
|
6389
6848
|
}
|
|
6390
6849
|
|
|
6391
6850
|
function isSlotMinimallyReady(e) {
|
|
6392
|
-
return isRevealController(e) ? e.
|
|
6851
|
+
return isRevealController(e) ? e.Zt() : isSlotReady(e);
|
|
6393
6852
|
}
|
|
6394
6853
|
|
|
6395
6854
|
function setSlotState(e, t, n, r) {
|
|
6396
|
-
setSignal(e.
|
|
6397
|
-
setSignal(e.
|
|
6855
|
+
setSignal(e.Xt, n);
|
|
6856
|
+
setSignal(e.zt, r);
|
|
6398
6857
|
if (isRevealController(e)) {
|
|
6399
|
-
if (!n && e.
|
|
6400
|
-
return e.
|
|
6858
|
+
if (!n && e.Jt === t) e.Jt = undefined;
|
|
6859
|
+
return e.en(n, r);
|
|
6401
6860
|
}
|
|
6402
|
-
if (!n && e.
|
|
6861
|
+
if (!n && e.tn === t && e.nn) e.tn = undefined;
|
|
6403
6862
|
}
|
|
6404
6863
|
|
|
6405
6864
|
class RevealController {
|
|
6865
|
+
rn;
|
|
6406
6866
|
sn;
|
|
6407
|
-
un;
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
zt=signal(false, {
|
|
6867
|
+
un=[];
|
|
6868
|
+
Jt;
|
|
6869
|
+
Xt=signal(false, {
|
|
6411
6870
|
ownedWrite: true,
|
|
6412
|
-
|
|
6871
|
+
Ct: true
|
|
6413
6872
|
});
|
|
6414
|
-
|
|
6873
|
+
zt=signal(false, {
|
|
6415
6874
|
ownedWrite: true,
|
|
6416
|
-
|
|
6875
|
+
Ct: true
|
|
6417
6876
|
});
|
|
6418
|
-
|
|
6877
|
+
ln=true;
|
|
6419
6878
|
an=true;
|
|
6420
|
-
|
|
6879
|
+
cn=false;
|
|
6421
6880
|
constructor(e, t) {
|
|
6422
|
-
this.
|
|
6423
|
-
this.
|
|
6881
|
+
this.rn = e;
|
|
6882
|
+
this.sn = t;
|
|
6424
6883
|
}
|
|
6425
|
-
|
|
6426
|
-
for (let t = 0; t < this.
|
|
6427
|
-
const n = this.
|
|
6428
|
-
if ((isRevealController(n) ? n.
|
|
6884
|
+
fn(e) {
|
|
6885
|
+
for (let t = 0; t < this.un.length; t++) {
|
|
6886
|
+
const n = this.un[t];
|
|
6887
|
+
if ((isRevealController(n) ? n.Jt : n.tn) !== this) continue;
|
|
6429
6888
|
if (e(n) === false) return false;
|
|
6430
6889
|
}
|
|
6431
6890
|
return true;
|
|
6432
6891
|
}
|
|
6433
|
-
|
|
6434
|
-
return this.
|
|
6892
|
+
Yt() {
|
|
6893
|
+
return this.fn(isSlotReady);
|
|
6435
6894
|
}
|
|
6436
6895
|
/**
|
|
6437
6896
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -6439,13 +6898,13 @@ class RevealController {
|
|
|
6439
6898
|
* - `together`: every direct slot is minimally ready.
|
|
6440
6899
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
6441
6900
|
* - `natural`: any owned slot is minimally ready.
|
|
6442
|
-
*/
|
|
6443
|
-
const e = untrack(this.
|
|
6444
|
-
if (e === "together") return this.
|
|
6901
|
+
*/ Zt() {
|
|
6902
|
+
const e = untrack(this.rn);
|
|
6903
|
+
if (e === "together") return this.fn(isSlotMinimallyReady);
|
|
6445
6904
|
if (e === "natural") {
|
|
6446
6905
|
let e = false;
|
|
6447
6906
|
let t = false;
|
|
6448
|
-
this.
|
|
6907
|
+
this.fn(n => {
|
|
6449
6908
|
e = true;
|
|
6450
6909
|
if (isSlotMinimallyReady(n)) {
|
|
6451
6910
|
t = true;
|
|
@@ -6456,45 +6915,45 @@ class RevealController {
|
|
|
6456
6915
|
}
|
|
6457
6916
|
// sequential: only the first owned slot matters.
|
|
6458
6917
|
let t = true;
|
|
6459
|
-
this.
|
|
6918
|
+
this.fn(e => {
|
|
6460
6919
|
t = isSlotMinimallyReady(e);
|
|
6461
6920
|
return false;
|
|
6462
6921
|
});
|
|
6463
6922
|
return t;
|
|
6464
6923
|
}
|
|
6465
|
-
|
|
6466
|
-
if (this.
|
|
6467
|
-
this.
|
|
6468
|
-
const t = untrack(this.
|
|
6469
|
-
setSignal(e.
|
|
6470
|
-
untrack(() => this.
|
|
6924
|
+
En(e) {
|
|
6925
|
+
if (this.un.includes(e)) return;
|
|
6926
|
+
this.un.push(e);
|
|
6927
|
+
const t = untrack(this.rn);
|
|
6928
|
+
setSignal(e.Xt, true), setSignal(e.zt, t === "sequential" ? !!untrack(this.sn) : false);
|
|
6929
|
+
untrack(() => this.en());
|
|
6471
6930
|
}
|
|
6472
6931
|
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.
|
|
6932
|
+
const t = this.un.indexOf(e);
|
|
6933
|
+
if (t >= 0) this.un.splice(t, 1);
|
|
6934
|
+
untrack(() => this.en());
|
|
6935
|
+
}
|
|
6936
|
+
en(e, t) {
|
|
6937
|
+
if (this.cn) return;
|
|
6938
|
+
this.cn = true;
|
|
6939
|
+
const n = this.ln;
|
|
6481
6940
|
const r = this.an;
|
|
6482
6941
|
try {
|
|
6483
|
-
const n = e ?? read(this.
|
|
6942
|
+
const n = e ?? read(this.Xt), r = untrack(this.rn), i = r === "sequential" && !!untrack(this.sn), o = t ?? i;
|
|
6484
6943
|
if (n) {
|
|
6485
6944
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
6486
6945
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
6487
6946
|
// held; it resumes once the outer releases us.
|
|
6488
|
-
this.
|
|
6947
|
+
this.fn(e => setSlotState(e, this, true, o));
|
|
6489
6948
|
} else if (r === "natural") {
|
|
6490
6949
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
6491
6950
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
6492
6951
|
// so the parent backpointer survives for upward readiness notifications.
|
|
6493
|
-
this.
|
|
6952
|
+
this.fn(e => {
|
|
6494
6953
|
if (isRevealController(e)) {
|
|
6495
|
-
setSignal(e.Jt, false);
|
|
6496
6954
|
setSignal(e.zt, false);
|
|
6497
|
-
e.
|
|
6955
|
+
setSignal(e.Xt, false);
|
|
6956
|
+
e.en(false, false);
|
|
6498
6957
|
} else {
|
|
6499
6958
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
6500
6959
|
}
|
|
@@ -6505,11 +6964,11 @@ class RevealController {
|
|
|
6505
6964
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
6506
6965
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
6507
6966
|
// cohesive reveal without waiting for every grandchild.
|
|
6508
|
-
const e = this.
|
|
6509
|
-
this.
|
|
6967
|
+
const e = this.fn(isSlotMinimallyReady);
|
|
6968
|
+
this.fn(t => setSlotState(t, this, !e, false));
|
|
6510
6969
|
} else {
|
|
6511
6970
|
let e = false;
|
|
6512
|
-
this.
|
|
6971
|
+
this.fn(t => {
|
|
6513
6972
|
if (e) return setSlotState(t, this, true, i);
|
|
6514
6973
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
6515
6974
|
e = true;
|
|
@@ -6520,63 +6979,63 @@ class RevealController {
|
|
|
6520
6979
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
6521
6980
|
// backpointer survives for upward readiness notifications.
|
|
6522
6981
|
if (isRevealController(t)) {
|
|
6523
|
-
setSignal(t.Jt, false);
|
|
6524
6982
|
setSignal(t.zt, false);
|
|
6525
|
-
t.
|
|
6983
|
+
setSignal(t.Xt, false);
|
|
6984
|
+
t.en(false, false);
|
|
6526
6985
|
} else {
|
|
6527
6986
|
setSlotState(t, this, true, false);
|
|
6528
6987
|
}
|
|
6529
6988
|
});
|
|
6530
6989
|
}
|
|
6531
6990
|
} finally {
|
|
6532
|
-
this.
|
|
6533
|
-
this.an = this.
|
|
6534
|
-
this.
|
|
6991
|
+
this.ln = this.Yt();
|
|
6992
|
+
this.an = this.Zt();
|
|
6993
|
+
this.cn = false;
|
|
6535
6994
|
}
|
|
6536
|
-
if (this.
|
|
6995
|
+
if (this.Jt && (n !== this.ln || r !== this.an)) this.Jt.en();
|
|
6537
6996
|
}
|
|
6538
6997
|
}
|
|
6539
6998
|
|
|
6540
6999
|
class CollectionQueue extends Queue {
|
|
7000
|
+
Sn;
|
|
7001
|
+
qt=new Set;
|
|
6541
7002
|
Tn;
|
|
6542
|
-
Bt=
|
|
6543
|
-
|
|
6544
|
-
Zt=true;
|
|
6545
|
-
zt=signal(false, {
|
|
7003
|
+
Bt=true;
|
|
7004
|
+
Xt=signal(false, {
|
|
6546
7005
|
ownedWrite: true,
|
|
6547
|
-
|
|
7006
|
+
Ct: true
|
|
6548
7007
|
});
|
|
6549
|
-
|
|
6550
|
-
|
|
7008
|
+
De;
|
|
7009
|
+
zt=signal(false, {
|
|
6551
7010
|
ownedWrite: true,
|
|
6552
|
-
|
|
7011
|
+
Ct: true
|
|
6553
7012
|
});
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
7013
|
+
tn;
|
|
7014
|
+
nn=false;
|
|
7015
|
+
On;
|
|
7016
|
+
_n=ON_INIT;
|
|
6558
7017
|
constructor(e) {
|
|
6559
7018
|
super();
|
|
6560
|
-
this.
|
|
7019
|
+
this.Sn = e;
|
|
6561
7020
|
}
|
|
6562
7021
|
run(e) {
|
|
6563
|
-
if (!e || read(this.
|
|
7022
|
+
if (!e || read(this.Xt) && (!_revealUsed || read(this.zt))) return;
|
|
6564
7023
|
return super.run(e);
|
|
6565
7024
|
}
|
|
6566
7025
|
notify(e, t, n, r) {
|
|
6567
|
-
if (!(t & this.
|
|
6568
|
-
if (this.
|
|
7026
|
+
if (!(t & this.Sn)) return super.notify(e, t, n, r);
|
|
7027
|
+
if (this.nn && this.On) {
|
|
6569
7028
|
const e = untrack(() => {
|
|
6570
7029
|
try {
|
|
6571
|
-
return this.
|
|
7030
|
+
return this.On();
|
|
6572
7031
|
} catch {
|
|
6573
7032
|
return ON_INIT;
|
|
6574
7033
|
}
|
|
6575
7034
|
});
|
|
6576
|
-
if (e !== this.
|
|
6577
|
-
this.
|
|
6578
|
-
this.
|
|
6579
|
-
this.
|
|
7035
|
+
if (e !== this._n) {
|
|
7036
|
+
this._n = e;
|
|
7037
|
+
this.nn = false;
|
|
7038
|
+
this.qt.clear();
|
|
6580
7039
|
}
|
|
6581
7040
|
}
|
|
6582
7041
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -6589,47 +7048,47 @@ class CollectionQueue extends Queue {
|
|
|
6589
7048
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
6590
7049
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
6591
7050
|
// (the Loading > Errored > content composition escape, #2856).
|
|
6592
|
-
if (this.
|
|
6593
|
-
if (n & this.
|
|
6594
|
-
this.
|
|
6595
|
-
const t = r?.source || e.
|
|
7051
|
+
if (this.Sn & STATUS_PENDING && this.nn) return super.notify(e, t, n, r);
|
|
7052
|
+
if (n & this.Sn) {
|
|
7053
|
+
this.Bt = true;
|
|
7054
|
+
const t = r?.source || e.De?.source;
|
|
6596
7055
|
if (t) {
|
|
6597
|
-
const e = this.
|
|
6598
|
-
this.
|
|
6599
|
-
if (e) setSignal(this.
|
|
6600
|
-
if (this.
|
|
6601
|
-
setSignal(this.
|
|
7056
|
+
const e = this.qt.size === 0;
|
|
7057
|
+
this.qt.add(t);
|
|
7058
|
+
if (e) setSignal(this.Xt, true);
|
|
7059
|
+
if (this.Sn & STATUS_ERROR) {
|
|
7060
|
+
setSignal(this.De, unwrapStatusError(t.De));
|
|
6602
7061
|
}
|
|
6603
7062
|
}
|
|
6604
7063
|
}
|
|
6605
|
-
t &= ~this.
|
|
7064
|
+
t &= ~this.Sn;
|
|
6606
7065
|
return t ? super.notify(e, t, n, r) : true;
|
|
6607
7066
|
}
|
|
6608
|
-
|
|
6609
|
-
for (const e of this.
|
|
7067
|
+
Me() {
|
|
7068
|
+
for (const e of this.qt) {
|
|
6610
7069
|
// A source with a live affects() mark holds display state for the
|
|
6611
7070
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
6612
7071
|
// status of its own, so the count is the liveness test. The release
|
|
6613
7072
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
6614
|
-
if (e.Le & REACTIVE_DISPOSED || !e.
|
|
7073
|
+
if (e.Le & REACTIVE_DISPOSED || !e.k && !(e.xe & this.Sn) && !(this.Sn & STATUS_ERROR && e.xe & STATUS_PENDING)) this.qt.delete(e);
|
|
6615
7074
|
}
|
|
6616
|
-
if (!this.
|
|
6617
|
-
if (this.
|
|
6618
|
-
this.
|
|
7075
|
+
if (!this.qt.size) {
|
|
7076
|
+
if (this.Sn & STATUS_PENDING && this.Bt && !this.nn && this.Tn) {
|
|
7077
|
+
this.Bt = !!(this.Tn.xe & this.Sn);
|
|
6619
7078
|
} else {
|
|
6620
|
-
this.
|
|
7079
|
+
this.Bt = false;
|
|
6621
7080
|
}
|
|
6622
|
-
if (!this.
|
|
6623
|
-
setSignal(this.
|
|
6624
|
-
if (this.
|
|
7081
|
+
if (!this.Bt) {
|
|
7082
|
+
setSignal(this.Xt, false);
|
|
7083
|
+
if (this.On) {
|
|
6625
7084
|
try {
|
|
6626
|
-
this.
|
|
7085
|
+
this._n = untrack(() => this.On());
|
|
6627
7086
|
} catch {
|
|
6628
7087
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
6629
7088
|
}
|
|
6630
7089
|
}
|
|
6631
7090
|
}
|
|
6632
|
-
if (_revealUsed) this.
|
|
7091
|
+
if (_revealUsed) this.tn?.en();
|
|
6633
7092
|
}
|
|
6634
7093
|
}
|
|
6635
7094
|
|
|
@@ -6637,12 +7096,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6637
7096
|
const i = createOwner();
|
|
6638
7097
|
if (_revealUsed) setContext(RevealControllerContext, null, i);
|
|
6639
7098
|
const o = new CollectionQueue(e);
|
|
6640
|
-
if (e === STATUS_ERROR) o.
|
|
7099
|
+
if (e === STATUS_ERROR) o.De = signal(undefined, {
|
|
6641
7100
|
ownedWrite: true,
|
|
6642
|
-
|
|
7101
|
+
Ct: true
|
|
6643
7102
|
});
|
|
6644
|
-
if (r) o.
|
|
6645
|
-
const s = o.
|
|
7103
|
+
if (r) o.On = r;
|
|
7104
|
+
const s = o.Tn = createBoundChildren(i, t, o, e);
|
|
6646
7105
|
// Prime source tracking so reveal registration sees pending sources.
|
|
6647
7106
|
untrack(() => {
|
|
6648
7107
|
let t = false;
|
|
@@ -6651,23 +7110,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6651
7110
|
} catch (e) {
|
|
6652
7111
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
6653
7112
|
}
|
|
6654
|
-
o.
|
|
7113
|
+
o.Bt = t || !!(s.xe & e) || s.De instanceof NotReadyError;
|
|
6655
7114
|
});
|
|
6656
7115
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
6657
7116
|
if (u) {
|
|
6658
|
-
o.
|
|
6659
|
-
u.
|
|
7117
|
+
o.tn = u;
|
|
7118
|
+
u.En(o);
|
|
6660
7119
|
cleanup(() => u.dn(o));
|
|
6661
7120
|
}
|
|
6662
7121
|
return accessor(computed(() => {
|
|
6663
|
-
if (!read(o.
|
|
7122
|
+
if (!read(o.Xt)) {
|
|
6664
7123
|
const e = read(s);
|
|
6665
|
-
if (!untrack(() => read(o.
|
|
7124
|
+
if (!untrack(() => read(o.Xt))) return o.nn = true, e;
|
|
6666
7125
|
}
|
|
6667
7126
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
6668
7127
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
6669
7128
|
// outside a `createRevealOrder` scope.
|
|
6670
|
-
if (_revealUsed && read(o.
|
|
7129
|
+
if (_revealUsed && read(o.zt)) return undefined;
|
|
6671
7130
|
return n(o);
|
|
6672
7131
|
},
|
|
6673
7132
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -6675,7 +7134,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6675
7134
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
6676
7135
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
6677
7136
|
{
|
|
6678
|
-
|
|
7137
|
+
Ct: true
|
|
6679
7138
|
}));
|
|
6680
7139
|
}
|
|
6681
7140
|
|
|
@@ -6728,8 +7187,8 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6728
7187
|
* }
|
|
6729
7188
|
* ```
|
|
6730
7189
|
*/ function createErrorBoundary(e, t) {
|
|
6731
|
-
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.
|
|
6732
|
-
for (const t of e.
|
|
7190
|
+
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.De), () => {
|
|
7191
|
+
for (const t of e.qt) recompute(t);
|
|
6733
7192
|
schedule();
|
|
6734
7193
|
}));
|
|
6735
7194
|
}
|
|
@@ -6786,11 +7245,11 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6786
7245
|
computed(() => {
|
|
6787
7246
|
i();
|
|
6788
7247
|
o();
|
|
6789
|
-
s.
|
|
7248
|
+
s.en();
|
|
6790
7249
|
});
|
|
6791
7250
|
if (r) {
|
|
6792
|
-
s.
|
|
6793
|
-
r.
|
|
7251
|
+
s.Jt = r;
|
|
7252
|
+
r.En(s);
|
|
6794
7253
|
cleanup(() => r.dn(s));
|
|
6795
7254
|
}
|
|
6796
7255
|
return t;
|