@solidjs/signals 2.0.0-rc.5 → 2.0.0-rc.6
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 +475 -72
- package/dist/node.cjs +851 -662
- package/dist/prod/core/async.js +41 -19
- package/dist/prod/core/core.js +58 -62
- package/dist/prod/core/effect.js +6 -6
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +4 -4
- package/dist/prod/core/optimistic.js +16 -16
- package/dist/prod/core/owner.js +4 -4
- package/dist/prod/core/scheduler.js +45 -32
- package/dist/prod/core/verdict.js +23 -19
- package/dist/prod/signals.js +68 -1
- package/dist/prod/store/next/optimistic.js +137 -64
- package/dist/prod/store/next/projection.js +2 -2
- package/dist/prod/store/next/store.js +122 -106
- package/dist/types/core/attribution-hooks.d.ts +11 -0
- package/dist/types/core/attribution.d.ts +48 -0
- package/dist/types/core/dev.d.ts +8 -2
- package/dist/types/core/scheduler.d.ts +5 -0
- package/dist/types/signals.d.ts +0 -11
- package/dist/types/store/next/target.d.ts +10 -0
- package/dist/types-cjs/core/attribution-hooks.d.cts +11 -0
- package/dist/types-cjs/core/attribution.d.cts +48 -0
- package/dist/types-cjs/core/dev.d.cts +8 -2
- package/dist/types-cjs/core/scheduler.d.cts +5 -0
- package/dist/types-cjs/signals.d.cts +0 -11
- package/dist/types-cjs/store/next/target.d.cts +10 -0
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -496,11 +496,11 @@ function canUseSimpleSyncFlush(e) {
|
|
|
496
496
|
function sweepTransientStoreNodes() {
|
|
497
497
|
if (transientStoreNodes.size === 0) return;
|
|
498
498
|
for (const e of transientStoreNodes) {
|
|
499
|
-
if (e
|
|
499
|
+
if (e.B !== null) {
|
|
500
500
|
transientStoreNodes.delete(e);
|
|
501
501
|
continue;
|
|
502
502
|
}
|
|
503
|
-
if (e
|
|
503
|
+
if (e.$ !== NOT_PENDING) continue;
|
|
504
504
|
if (e.o?.m !== undefined && e.o?.m !== NOT_PENDING) continue;
|
|
505
505
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
506
506
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
@@ -630,7 +630,7 @@ function mergeTransitionState(e, t) {
|
|
|
630
630
|
let n = false;
|
|
631
631
|
for (let i = e.oe; i !== null; i = i.se) {
|
|
632
632
|
const r = i.ue;
|
|
633
|
-
if (r
|
|
633
|
+
if (r.$ !== NOT_PENDING) {
|
|
634
634
|
const e = r.O;
|
|
635
635
|
const i = e != null ? currentTransition(e) : null;
|
|
636
636
|
// Skip the awaiting transaction's own cargo (t === target: a
|
|
@@ -682,7 +682,7 @@ function mergeTransitionState(e, t) {
|
|
|
682
682
|
// duplicate fire of an unchanged view.
|
|
683
683
|
if (!hasActiveOverride$1(i)) {
|
|
684
684
|
i.D |= CONFIG_HELD_TRUTH;
|
|
685
|
-
for (let e = i
|
|
685
|
+
for (let e = i.B; e !== null; e = e.fe) {
|
|
686
686
|
const t = e.ce;
|
|
687
687
|
if (t.ae && !(t.D & CONFIG_AUTHORITATIVE_READ)) enqueueSub(t);
|
|
688
688
|
}
|
|
@@ -884,8 +884,8 @@ class GlobalQueue extends Queue {
|
|
|
884
884
|
static We=null;
|
|
885
885
|
static je=null;
|
|
886
886
|
static Me=null;
|
|
887
|
-
static $e=null;
|
|
888
887
|
static Be=null;
|
|
888
|
+
static $e=null;
|
|
889
889
|
/** Authoritative-view reader wakeup (until()): installed at first until() call.
|
|
890
890
|
* Call sites are gated by CONFIG_AUTHORITATIVE_OBSERVED, which only until()'s
|
|
891
891
|
* carve-out read can set, so `!` invocations are safe once the gate holds. */
|
|
@@ -1133,7 +1133,7 @@ function insertSubs(e, t = false) {
|
|
|
1133
1133
|
const i = (n & CONFIG_HAS_LANE ? e.o?.l : undefined) || currentOptimisticLane;
|
|
1134
1134
|
const r = (n & CONFIG_HAS_SNAPSHOT) !== 0 && e.o?.et !== undefined;
|
|
1135
1135
|
const o = reaskArmed;
|
|
1136
|
-
for (let n = e
|
|
1136
|
+
for (let n = e.B; n !== null; n = n.fe) {
|
|
1137
1137
|
const e = n.ce;
|
|
1138
1138
|
// A value-change notification is a new question for the subscriber: any
|
|
1139
1139
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
@@ -1166,26 +1166,32 @@ function insertSubs(e, t = false) {
|
|
|
1166
1166
|
function commitPendingNode(e) {
|
|
1167
1167
|
const t = e;
|
|
1168
1168
|
if (!t.it) {
|
|
1169
|
-
if (e
|
|
1170
|
-
e.ot = e
|
|
1171
|
-
e
|
|
1169
|
+
if (e.$ !== NOT_PENDING) {
|
|
1170
|
+
e.ot = e.$;
|
|
1171
|
+
e.$ = NOT_PENDING;
|
|
1172
1172
|
}
|
|
1173
1173
|
if (e.D & CONFIG_HAS_COMPANIONS) GlobalQueue.we(e);
|
|
1174
1174
|
return;
|
|
1175
1175
|
}
|
|
1176
|
-
if (e
|
|
1177
|
-
e.ot = e
|
|
1178
|
-
e
|
|
1176
|
+
if (e.$ !== NOT_PENDING) {
|
|
1177
|
+
e.ot = e.$;
|
|
1178
|
+
e.$ = NOT_PENDING;
|
|
1179
1179
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
1180
1180
|
if (e.ae && e.ae !== EFFECT_TRACKED) e.st = true;
|
|
1181
|
+
// A quiet re-ask classification preserved through a held landing dies
|
|
1182
|
+
// with the value commit — the commit IS the reveal (#3178). Gated on the
|
|
1183
|
+
// staged value: status propagation queues pending nodes whose windows
|
|
1184
|
+
// are still OPEN (no staged value), and their live classification must
|
|
1185
|
+
// survive this sweep.
|
|
1186
|
+
if (e.o) e.o.ut = false;
|
|
1181
1187
|
}
|
|
1182
1188
|
// The committed hold is the first observable answer for a loading-window
|
|
1183
1189
|
// node — the window closes here, not at compute time (#2990). Unconditional
|
|
1184
1190
|
// store to an always-present computed slot.
|
|
1185
|
-
t.
|
|
1191
|
+
t.lt = false;
|
|
1186
1192
|
t.L &= ~REACTIVE_MANUAL_WRITE;
|
|
1187
|
-
if (!(t.
|
|
1188
|
-
if (t.o != null && (t.o.
|
|
1193
|
+
if (!(t.ct & STATUS_PENDING)) t.ct &= ~STATUS_UNINITIALIZED;
|
|
1194
|
+
if (t.o != null && (t.o.dt !== null || t.o.Et !== null)) GlobalQueue.Te(t, false, true);
|
|
1189
1195
|
if (e.D & CONFIG_HAS_COMPANIONS) GlobalQueue.we(e);
|
|
1190
1196
|
}
|
|
1191
1197
|
|
|
@@ -1314,7 +1320,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
1314
1320
|
|
|
1315
1321
|
function checkBoundaryChildren(e) {
|
|
1316
1322
|
for (const t of e.W) {
|
|
1317
|
-
t.
|
|
1323
|
+
t.St?.();
|
|
1318
1324
|
checkBoundaryChildren(t);
|
|
1319
1325
|
}
|
|
1320
1326
|
}
|
|
@@ -1382,15 +1388,15 @@ function runQueue$1(e, t) {
|
|
|
1382
1388
|
|
|
1383
1389
|
function reporterBlocksSource(e, t) {
|
|
1384
1390
|
if (e.L & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
1385
|
-
if (e.o?.
|
|
1391
|
+
if (e.o?.Tt?.has(t)) return true;
|
|
1386
1392
|
for (let n = e.oe; n; n = n.se) {
|
|
1387
1393
|
let e = n.ue;
|
|
1388
1394
|
while (e) {
|
|
1389
|
-
if (e === t || e.
|
|
1395
|
+
if (e === t || e._t === t) return true;
|
|
1390
1396
|
e = e.o?.i;
|
|
1391
1397
|
}
|
|
1392
1398
|
}
|
|
1393
|
-
return !!(e.
|
|
1399
|
+
return !!(e.ct & STATUS_PENDING && e.o?.ze instanceof NotReadyError && e.o?.ze.source === t);
|
|
1394
1400
|
}
|
|
1395
1401
|
|
|
1396
1402
|
function transitionComplete(e) {
|
|
@@ -1406,7 +1412,7 @@ function transitionComplete(e) {
|
|
|
1406
1412
|
}
|
|
1407
1413
|
i.delete(e);
|
|
1408
1414
|
}
|
|
1409
|
-
if (!r) e.J.delete(n); else if (n.
|
|
1415
|
+
if (!r) e.J.delete(n); else if (n.ct & STATUS_PENDING && n.o?.ze?.source === n) {
|
|
1410
1416
|
t = false;
|
|
1411
1417
|
break;
|
|
1412
1418
|
}
|
|
@@ -1419,6 +1425,13 @@ function transitionComplete(e) {
|
|
|
1419
1425
|
return t;
|
|
1420
1426
|
}
|
|
1421
1427
|
|
|
1428
|
+
/** A fresh, unentered transaction (#3146): the optimistic store's truth
|
|
1429
|
+
* flight DECLARES an owned transaction instead of relying on whatever the
|
|
1430
|
+
* ambient adoption machinery stamped on its firewall. Activate it with
|
|
1431
|
+
* initTransition; it is a plain batch until then. */ function createTransition() {
|
|
1432
|
+
return createBatch();
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1422
1435
|
function currentTransition(e) {
|
|
1423
1436
|
while (e.P && typeof e.P === "object") e = e.P;
|
|
1424
1437
|
return e;
|
|
@@ -1470,25 +1483,25 @@ function runInTransition(e, t) {
|
|
|
1470
1483
|
const t = e;
|
|
1471
1484
|
if (!t.st) {
|
|
1472
1485
|
t.st = true;
|
|
1473
|
-
t.
|
|
1486
|
+
t.At.enqueue(EFFECT_USER, t.Ot);
|
|
1474
1487
|
}
|
|
1475
1488
|
return;
|
|
1476
1489
|
}
|
|
1477
1490
|
const t = queueFor(e);
|
|
1478
|
-
if (t.H > e.
|
|
1491
|
+
if (t.H > e.Nt) t.H = e.Nt;
|
|
1479
1492
|
insertIntoHeap(e, t);
|
|
1480
1493
|
}
|
|
1481
1494
|
|
|
1482
1495
|
function actualInsertIntoHeap(e, t) {
|
|
1483
|
-
const n = (e.pe?.
|
|
1484
|
-
if (n >= e.
|
|
1485
|
-
const i = e.
|
|
1496
|
+
const n = (e.pe?.It ? e.pe.Rt?.Nt : e.pe?.Nt) ?? -1;
|
|
1497
|
+
if (n >= e.Nt) e.Nt = n + 1;
|
|
1498
|
+
const i = e.Nt;
|
|
1486
1499
|
const r = t.G[i];
|
|
1487
1500
|
if (r === undefined) t.G[i] = e; else {
|
|
1488
|
-
const t = r.
|
|
1489
|
-
t.
|
|
1490
|
-
e.
|
|
1491
|
-
r.
|
|
1501
|
+
const t = r.Ct;
|
|
1502
|
+
t.gt = e;
|
|
1503
|
+
e.Ct = t;
|
|
1504
|
+
r.Ct = e;
|
|
1492
1505
|
}
|
|
1493
1506
|
if (i > t.U) t.U = i;
|
|
1494
1507
|
}
|
|
@@ -1524,23 +1537,23 @@ function deleteFromHeap(e, t) {
|
|
|
1524
1537
|
const n = e.L;
|
|
1525
1538
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1526
1539
|
e.L = n & -25;
|
|
1527
|
-
const i = e.
|
|
1528
|
-
if (e.
|
|
1529
|
-
const n = e.
|
|
1540
|
+
const i = e.Nt;
|
|
1541
|
+
if (e.Ct === e) t.G[i] = undefined; else {
|
|
1542
|
+
const n = e.gt;
|
|
1530
1543
|
const r = t.G[i];
|
|
1531
1544
|
const o = n ?? r;
|
|
1532
|
-
if (e === r) t.G[i] = n; else e.
|
|
1533
|
-
o.
|
|
1545
|
+
if (e === r) t.G[i] = n; else e.Ct.gt = n;
|
|
1546
|
+
o.Ct = e.Ct;
|
|
1534
1547
|
}
|
|
1535
|
-
e.
|
|
1536
|
-
e.
|
|
1548
|
+
e.Ct = e;
|
|
1549
|
+
e.gt = undefined;
|
|
1537
1550
|
}
|
|
1538
1551
|
|
|
1539
1552
|
function markHeap(e) {
|
|
1540
1553
|
if (e.F) return;
|
|
1541
1554
|
e.F = true;
|
|
1542
1555
|
for (let t = 0; t <= e.U; t++) {
|
|
1543
|
-
for (let n = e.G[t]; n !== undefined; n = n.
|
|
1556
|
+
for (let n = e.G[t]; n !== undefined; n = n.gt) {
|
|
1544
1557
|
if (n.L & REACTIVE_IN_HEAP) markNode(n);
|
|
1545
1558
|
}
|
|
1546
1559
|
}
|
|
@@ -1550,15 +1563,15 @@ function markNode(e, t = REACTIVE_DIRTY) {
|
|
|
1550
1563
|
const n = e.L;
|
|
1551
1564
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1552
1565
|
e.L = n & -4 | t;
|
|
1553
|
-
for (let t = e
|
|
1566
|
+
for (let t = e.B; t !== null; t = t.fe) {
|
|
1554
1567
|
markNode(t.ce, REACTIVE_CHECK);
|
|
1555
1568
|
}
|
|
1556
1569
|
// Firewall children (projection machinery only): gate the cold-extension
|
|
1557
1570
|
// deref on the config bit — markNode runs per sub edge per write, and an
|
|
1558
1571
|
// unconditional _x chase here taxed every propagation (diamond -22%).
|
|
1559
1572
|
if (e.D & CONFIG_FW_CHILDREN) {
|
|
1560
|
-
for (let t = e.o.
|
|
1561
|
-
for (let e = t
|
|
1573
|
+
for (let t = e.o.vt; t !== null; t = t.yt) {
|
|
1574
|
+
for (let e = t.B; e !== null; e = e.fe) {
|
|
1562
1575
|
markNode(e.ce, REACTIVE_CHECK);
|
|
1563
1576
|
}
|
|
1564
1577
|
}
|
|
@@ -1579,15 +1592,15 @@ function runHeap(e, t) {
|
|
|
1579
1592
|
|
|
1580
1593
|
function adjustHeight(e, t) {
|
|
1581
1594
|
deleteFromHeap(e, t);
|
|
1582
|
-
let n = e.
|
|
1595
|
+
let n = e.Nt;
|
|
1583
1596
|
for (let t = e.oe; t; t = t.se) {
|
|
1584
1597
|
const e = t.ue;
|
|
1585
|
-
const i = e.
|
|
1586
|
-
if (i.it && i.
|
|
1598
|
+
const i = e._t || e;
|
|
1599
|
+
if (i.it && i.Nt >= n) n = i.Nt + 1;
|
|
1587
1600
|
}
|
|
1588
|
-
if (e.
|
|
1589
|
-
e.
|
|
1590
|
-
for (let t = e
|
|
1601
|
+
if (e.Nt !== n) {
|
|
1602
|
+
e.Nt = n;
|
|
1603
|
+
for (let t = e.B; t !== null; t = t.fe) {
|
|
1591
1604
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1592
1605
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1593
1606
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
@@ -1602,7 +1615,7 @@ const PENDING_OWNER = {};
|
|
|
1602
1615
|
|
|
1603
1616
|
// Dummy owner to trigger store's read() path
|
|
1604
1617
|
function markDisposal(e) {
|
|
1605
|
-
let t = e.
|
|
1618
|
+
let t = e.wt;
|
|
1606
1619
|
while (t) {
|
|
1607
1620
|
const e = t.L;
|
|
1608
1621
|
t.L = e | REACTIVE_ZOMBIE;
|
|
@@ -1616,7 +1629,7 @@ function markDisposal(e) {
|
|
|
1616
1629
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
1617
1630
|
}
|
|
1618
1631
|
markDisposal(t);
|
|
1619
|
-
t = t.
|
|
1632
|
+
t = t.Pt;
|
|
1620
1633
|
}
|
|
1621
1634
|
}
|
|
1622
1635
|
|
|
@@ -1644,10 +1657,10 @@ function disposeChildren(e, t = false, n) {
|
|
|
1644
1657
|
const t = e;
|
|
1645
1658
|
if (t.o?.I || t.o?.R) GlobalQueue.we(t);
|
|
1646
1659
|
}
|
|
1647
|
-
if (t && e.it && e.o !== null) e.o.
|
|
1648
|
-
let r = n ? e.o?.
|
|
1660
|
+
if (t && e.it && e.o !== null) e.o.bt = null;
|
|
1661
|
+
let r = n ? e.o?.dt ?? null : e.wt;
|
|
1649
1662
|
while (r) {
|
|
1650
|
-
const e = r.
|
|
1663
|
+
const e = r.Pt;
|
|
1651
1664
|
const t = r;
|
|
1652
1665
|
// Owner teardown is death regardless of the child's own lifecycle
|
|
1653
1666
|
// (#3024): strip AUTO_DISPOSE so a post-disposal read freezes at the
|
|
@@ -1670,34 +1683,34 @@ function disposeChildren(e, t = false, n) {
|
|
|
1670
1683
|
r = e;
|
|
1671
1684
|
}
|
|
1672
1685
|
if (n) {
|
|
1673
|
-
if (e.o !== null) e.o.
|
|
1686
|
+
if (e.o !== null) e.o.dt = null;
|
|
1674
1687
|
} else {
|
|
1675
|
-
e.
|
|
1676
|
-
e.
|
|
1688
|
+
e.wt = null;
|
|
1689
|
+
e.Dt = 0;
|
|
1677
1690
|
}
|
|
1678
1691
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1679
1692
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1680
1693
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1681
1694
|
// walks that already advanced past us still reach later siblings.
|
|
1682
1695
|
if (t && !n && !(i & REACTIVE_ZOMBIE) && e.pe !== null && !(e.pe.L & REACTIVE_DISPOSED)) {
|
|
1683
|
-
const t = e.
|
|
1684
|
-
const n = e.
|
|
1685
|
-
if (t !== null) t.
|
|
1686
|
-
if (n !== null) n.
|
|
1687
|
-
e.
|
|
1696
|
+
const t = e.Gt;
|
|
1697
|
+
const n = e.Pt;
|
|
1698
|
+
if (t !== null) t.Pt = n; else e.pe.wt = n;
|
|
1699
|
+
if (n !== null) n.Gt = t;
|
|
1700
|
+
e.Gt = null;
|
|
1688
1701
|
}
|
|
1689
1702
|
runDisposal(e, n);
|
|
1690
1703
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
1691
1704
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
1692
|
-
if (t && e.
|
|
1693
|
-
const t = e.
|
|
1694
|
-
e.
|
|
1705
|
+
if (t && e.kt) {
|
|
1706
|
+
const t = e.kt;
|
|
1707
|
+
e.kt = undefined;
|
|
1695
1708
|
t();
|
|
1696
1709
|
}
|
|
1697
1710
|
}
|
|
1698
1711
|
|
|
1699
1712
|
function runDisposal(e, t) {
|
|
1700
|
-
let n = t ? e.o?.
|
|
1713
|
+
let n = t ? e.o?.Et : e.xt;
|
|
1701
1714
|
if (!n) return;
|
|
1702
1715
|
if (Array.isArray(n)) {
|
|
1703
1716
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1708,14 +1721,14 @@ function runDisposal(e, t) {
|
|
|
1708
1721
|
n.call(n);
|
|
1709
1722
|
}
|
|
1710
1723
|
if (t) {
|
|
1711
|
-
if (e.o !== null) e.o.
|
|
1712
|
-
} else e.
|
|
1724
|
+
if (e.o !== null) e.o.Et = null;
|
|
1725
|
+
} else e.xt = null;
|
|
1713
1726
|
}
|
|
1714
1727
|
|
|
1715
1728
|
function childId(e, t) {
|
|
1716
1729
|
let n = e;
|
|
1717
1730
|
while (n.D & CONFIG_TRANSPARENT && n.pe) n = n.pe;
|
|
1718
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1731
|
+
if (n.id != null) return formatId(n.id, t ? n.Dt++ : n.Dt);
|
|
1719
1732
|
throw new Error("");
|
|
1720
1733
|
}
|
|
1721
1734
|
|
|
@@ -1796,7 +1809,7 @@ function formatId(e, t) {
|
|
|
1796
1809
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
1797
1810
|
*/ function cleanup(e) {
|
|
1798
1811
|
if (!context) return e;
|
|
1799
|
-
if (!context.
|
|
1812
|
+
if (!context.xt) context.xt = e; else if (Array.isArray(context.xt)) context.xt.push(e); else context.xt = [ context.xt, e ];
|
|
1800
1813
|
return e;
|
|
1801
1814
|
}
|
|
1802
1815
|
|
|
@@ -1836,27 +1849,27 @@ function disposeRootSelf(e = true) {
|
|
|
1836
1849
|
const i = {
|
|
1837
1850
|
id: inheritId(e, n, t),
|
|
1838
1851
|
D: n ? CONFIG_TRANSPARENT : 0,
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
bt: null,
|
|
1852
|
+
It: true,
|
|
1853
|
+
Rt: t?.It ? t.Rt : t,
|
|
1854
|
+
wt: null,
|
|
1855
|
+
Pt: null,
|
|
1844
1856
|
Gt: null,
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1857
|
+
xt: null,
|
|
1858
|
+
At: t?.At ?? globalQueue,
|
|
1859
|
+
Ft: t?.Ft || defaultContext,
|
|
1860
|
+
Dt: 0,
|
|
1848
1861
|
o: null,
|
|
1849
1862
|
pe: t,
|
|
1850
1863
|
dispose: disposeRootSelf
|
|
1851
1864
|
};
|
|
1852
1865
|
if (t) {
|
|
1853
|
-
const e = t.
|
|
1866
|
+
const e = t.wt;
|
|
1854
1867
|
if (e === null) {
|
|
1855
|
-
t.
|
|
1868
|
+
t.wt = i;
|
|
1856
1869
|
} else {
|
|
1857
|
-
i.
|
|
1858
|
-
e.
|
|
1859
|
-
t.
|
|
1870
|
+
i.Pt = e;
|
|
1871
|
+
e.Gt = i;
|
|
1872
|
+
t.wt = i;
|
|
1860
1873
|
}
|
|
1861
1874
|
}
|
|
1862
1875
|
return i;
|
|
@@ -1895,10 +1908,10 @@ function unlinkSubs(e) {
|
|
|
1895
1908
|
const t = e.ue;
|
|
1896
1909
|
const n = e.se;
|
|
1897
1910
|
const i = e.fe;
|
|
1898
|
-
const r = e.
|
|
1899
|
-
if (i !== null) i.
|
|
1911
|
+
const r = e.Ht;
|
|
1912
|
+
if (i !== null) i.Ht = r; else t.Ut = r;
|
|
1900
1913
|
if (r !== null) r.fe = i; else {
|
|
1901
|
-
t
|
|
1914
|
+
t.B = i;
|
|
1902
1915
|
if (i === null) {
|
|
1903
1916
|
t.o?.Y?.();
|
|
1904
1917
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
@@ -1908,7 +1921,7 @@ function unlinkSubs(e) {
|
|
|
1908
1921
|
// this same last-one-out check when that observer releases (the
|
|
1909
1922
|
// untracked-read dormancy sweep guards on pending identically).
|
|
1910
1923
|
const e = t;
|
|
1911
|
-
e.it && e.D & CONFIG_AUTO_DISPOSE && !(e.L & REACTIVE_ZOMBIE) && !(e.
|
|
1924
|
+
e.it && e.D & CONFIG_AUTO_DISPOSE && !(e.L & REACTIVE_ZOMBIE) && !(e.ct & STATUS_PENDING) && unobserved(e);
|
|
1912
1925
|
}
|
|
1913
1926
|
}
|
|
1914
1927
|
return n;
|
|
@@ -1974,7 +1987,7 @@ function sweepDormant() {
|
|
|
1974
1987
|
// is an observer; the settle path re-runs last-one-out), lost its
|
|
1975
1988
|
// AUTO_DISPOSE bit (owner teardown strips it, #3024), or already been
|
|
1976
1989
|
// torn down.
|
|
1977
|
-
if (!e
|
|
1990
|
+
if (!e.B && e.D & CONFIG_AUTO_DISPOSE && !(e.ct & STATUS_PENDING) && !(e.L & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
1978
1991
|
unobserved(e);
|
|
1979
1992
|
}
|
|
1980
1993
|
}
|
|
@@ -1990,7 +2003,7 @@ function link(e, t, n = false) {
|
|
|
1990
2003
|
// read order within the computation.
|
|
1991
2004
|
const i = t.le;
|
|
1992
2005
|
if (i !== null && i.ue === e) {
|
|
1993
|
-
i.
|
|
2006
|
+
i.Lt &&= n;
|
|
1994
2007
|
return;
|
|
1995
2008
|
}
|
|
1996
2009
|
let r = null;
|
|
@@ -2001,7 +2014,7 @@ function link(e, t, n = false) {
|
|
|
2001
2014
|
r.tt = t.nt;
|
|
2002
2015
|
t.le = r;
|
|
2003
2016
|
// First touch of this pass: the previous pass's label is stale.
|
|
2004
|
-
r.
|
|
2017
|
+
r.Lt = n;
|
|
2005
2018
|
return;
|
|
2006
2019
|
}
|
|
2007
2020
|
}
|
|
@@ -2010,24 +2023,24 @@ function link(e, t, n = false) {
|
|
|
2010
2023
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
2011
2024
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
2012
2025
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
2013
|
-
const s = e.
|
|
2026
|
+
const s = e.Ut;
|
|
2014
2027
|
if (s !== null && s.ce === t && (!o || s.tt === t.nt)) {
|
|
2015
2028
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
2016
2029
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
2017
|
-
if (o) s.
|
|
2030
|
+
if (o) s.Lt &&= n; else s.Lt = n;
|
|
2018
2031
|
return;
|
|
2019
2032
|
}
|
|
2020
|
-
const u = t.le = e.
|
|
2033
|
+
const u = t.le = e.Ut = {
|
|
2021
2034
|
ue: e,
|
|
2022
2035
|
ce: t,
|
|
2023
2036
|
se: r,
|
|
2024
|
-
|
|
2037
|
+
Ht: s,
|
|
2025
2038
|
fe: null,
|
|
2026
2039
|
tt: t.nt,
|
|
2027
|
-
|
|
2040
|
+
Lt: n
|
|
2028
2041
|
};
|
|
2029
2042
|
if (i !== null) i.se = u; else t.oe = u;
|
|
2030
|
-
if (s !== null) s.fe = u; else e
|
|
2043
|
+
if (s !== null) s.fe = u; else e.B = u;
|
|
2031
2044
|
// New subscriber edge: staged-rewrite skips (§12d) must not miss it.
|
|
2032
2045
|
bumpNotifyEpoch();
|
|
2033
2046
|
}
|
|
@@ -2038,20 +2051,22 @@ function link(e, t, n = false) {
|
|
|
2038
2051
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
2039
2052
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
2040
2053
|
function addPendingSource(e, t) {
|
|
2041
|
-
if (e.o?.
|
|
2042
|
-
(ext(e).
|
|
2054
|
+
if (e.o?.Tt?.has(t)) return false;
|
|
2055
|
+
(ext(e).Tt ??= new Set).add(t);
|
|
2043
2056
|
return true;
|
|
2044
2057
|
}
|
|
2045
2058
|
|
|
2046
2059
|
function removePendingSource(e, t) {
|
|
2047
|
-
|
|
2048
|
-
if (
|
|
2060
|
+
const n = e.o?.Tt;
|
|
2061
|
+
if (!n?.delete(t)) return false;
|
|
2062
|
+
if (!n.size) e.o.Tt = undefined;
|
|
2049
2063
|
return true;
|
|
2050
2064
|
}
|
|
2051
2065
|
|
|
2052
2066
|
function clearPendingSources(e) {
|
|
2053
|
-
|
|
2054
|
-
|
|
2067
|
+
// This set is node-owned and never shared; dropping the sole reference
|
|
2068
|
+
// releases the set and every entry without a redundant clear() walk.
|
|
2069
|
+
if (e.o !== null) e.o.Tt = undefined;
|
|
2055
2070
|
}
|
|
2056
2071
|
|
|
2057
2072
|
/**
|
|
@@ -2061,13 +2076,13 @@ function clearPendingSources(e) {
|
|
|
2061
2076
|
* with NO read-visible pending status, no downstream propagation, no
|
|
2062
2077
|
* transition, no lane registration. Commit #0 keeps serving.
|
|
2063
2078
|
*/ function parkLoadingWindow(e, t) {
|
|
2064
|
-
ext(e).
|
|
2079
|
+
ext(e).Vt = true;
|
|
2065
2080
|
if (t.source) addPendingSource(e, t.source);
|
|
2066
2081
|
// A settled error is the node's answer ("the error stays the answer until
|
|
2067
2082
|
// this retry can actually run") — the park must not replace it: reads
|
|
2068
2083
|
// throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
|
|
2069
2084
|
// a pending-class NotReadyError from a read-invisible park (#2989).
|
|
2070
|
-
if (!(e.
|
|
2085
|
+
if (!(e.ct & STATUS_ERROR)) setPendingError(e, t.source, t);
|
|
2071
2086
|
}
|
|
2072
2087
|
|
|
2073
2088
|
function setPendingError(e, t, n) {
|
|
@@ -2086,10 +2101,10 @@ function setPendingError(e, t, n) {
|
|
|
2086
2101
|
}
|
|
2087
2102
|
|
|
2088
2103
|
function forEachDependent(e, t) {
|
|
2089
|
-
for (let n = e
|
|
2104
|
+
for (let n = e.B; n !== null; n = n.fe) t(n.ce, n);
|
|
2090
2105
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
2091
|
-
for (let n = e.o?.
|
|
2092
|
-
for (let e = n
|
|
2106
|
+
for (let n = e.o?.vt ?? null; n !== null; n = n.yt) {
|
|
2107
|
+
for (let e = n.B; e !== null; e = e.fe) t(e.ce, e);
|
|
2093
2108
|
}
|
|
2094
2109
|
}
|
|
2095
2110
|
|
|
@@ -2104,7 +2119,7 @@ function forEachDependent(e, t) {
|
|
|
2104
2119
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
2105
2120
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
2106
2121
|
function releaseIfSettledUnobserved(e) {
|
|
2107
|
-
e.it && e.D & CONFIG_AUTO_DISPOSE && !e
|
|
2122
|
+
e.it && e.D & CONFIG_AUTO_DISPOSE && !e.B && !(e.L & REACTIVE_ZOMBIE) && !(e.ct & STATUS_PENDING) && unobserved(e);
|
|
2108
2123
|
}
|
|
2109
2124
|
|
|
2110
2125
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -2117,7 +2132,7 @@ function releaseSettledDependents(e) {
|
|
|
2117
2132
|
const visit = e => {
|
|
2118
2133
|
if (n.has(e)) return;
|
|
2119
2134
|
n.add(e);
|
|
2120
|
-
if (!e
|
|
2135
|
+
if (!e.B && e.D & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
2121
2136
|
forEachDependent(e, visit);
|
|
2122
2137
|
};
|
|
2123
2138
|
forEachDependent(e, visit);
|
|
@@ -2156,6 +2171,10 @@ function settleErroredDependents(e, t) {
|
|
|
2156
2171
|
}
|
|
2157
2172
|
|
|
2158
2173
|
function settlePendingSource(e) {
|
|
2174
|
+
// The normal landing path already cleared the source's own set. Superseded
|
|
2175
|
+
// re-parks arrive here with an abandoned self entry, which must retire in
|
|
2176
|
+
// the same walk as its propagated copies.
|
|
2177
|
+
removePendingSource(e, e);
|
|
2159
2178
|
let t = false;
|
|
2160
2179
|
let n;
|
|
2161
2180
|
const i = new Set;
|
|
@@ -2165,29 +2184,29 @@ function settlePendingSource(e) {
|
|
|
2165
2184
|
if (i.has(o) || !removePendingSource(o, e)) return;
|
|
2166
2185
|
i.add(o);
|
|
2167
2186
|
o.Z = clock;
|
|
2168
|
-
const s = o.o?.
|
|
2187
|
+
const s = o.o?.Tt?.values().next().value;
|
|
2169
2188
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
2170
2189
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
2171
2190
|
// otherwise): the settled error stays the answer through the settle —
|
|
2172
2191
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
2173
2192
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
2174
|
-
const u = o.
|
|
2193
|
+
const u = o.ct & STATUS_ERROR;
|
|
2175
2194
|
if (s) {
|
|
2176
2195
|
if (!u) setPendingError(o, s);
|
|
2177
2196
|
r?.(o);
|
|
2178
2197
|
} else {
|
|
2179
|
-
o.
|
|
2198
|
+
o.ct &= ~STATUS_PENDING;
|
|
2180
2199
|
if (!u) setPendingError(o);
|
|
2181
2200
|
r?.(o);
|
|
2182
|
-
if (o.o?.
|
|
2201
|
+
if (o.o?.Vt) {
|
|
2183
2202
|
enqueueSub(o);
|
|
2184
2203
|
t = true;
|
|
2185
2204
|
}
|
|
2186
|
-
if (o.o !== null) o.o.
|
|
2205
|
+
if (o.o !== null) o.o.Vt = false;
|
|
2187
2206
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
2188
2207
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
2189
2208
|
// lists this walk is still iterating.
|
|
2190
|
-
if (!o
|
|
2209
|
+
if (!o.B && o.D & CONFIG_AUTO_DISPOSE) (n ??= []).push(o);
|
|
2191
2210
|
}
|
|
2192
2211
|
forEachDependent(o, settle);
|
|
2193
2212
|
};
|
|
@@ -2204,9 +2223,9 @@ function isThenable(e) {
|
|
|
2204
2223
|
}
|
|
2205
2224
|
|
|
2206
2225
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
|
|
2207
|
-
const t = e.o?.
|
|
2226
|
+
const t = e.o?.Qt;
|
|
2208
2227
|
if (t != null) {
|
|
2209
|
-
e.o.
|
|
2228
|
+
e.o.Qt = null;
|
|
2210
2229
|
t();
|
|
2211
2230
|
}
|
|
2212
2231
|
}
|
|
@@ -2221,9 +2240,9 @@ function handleAsync(e, t, n) {
|
|
|
2221
2240
|
});
|
|
2222
2241
|
}
|
|
2223
2242
|
if (!r && !i) {
|
|
2224
|
-
if (e.o !== null) e.o.
|
|
2243
|
+
if (e.o !== null) e.o.bt = null;
|
|
2225
2244
|
// A sync landing is the first real answer for a loadingValue node.
|
|
2226
|
-
e.
|
|
2245
|
+
e.lt = false;
|
|
2227
2246
|
return t;
|
|
2228
2247
|
}
|
|
2229
2248
|
// Flight replacement relies on recompute's supersede release for iterator
|
|
@@ -2231,7 +2250,7 @@ function handleAsync(e, t, n) {
|
|
|
2231
2250
|
// self-registration — runs during a recompute of `el`, which has already
|
|
2232
2251
|
// fired _flightTeardown. A future non-recompute registration path must
|
|
2233
2252
|
// release it here before overwriting _inFlight.
|
|
2234
|
-
ext(e).
|
|
2253
|
+
ext(e).bt = t;
|
|
2235
2254
|
let o;
|
|
2236
2255
|
// Settle-time transition re-entry. The loading rail is invisible to
|
|
2237
2256
|
// transactions (#2933): a boundary-caught first load never registers as an
|
|
@@ -2245,7 +2264,7 @@ function handleAsync(e, t, n) {
|
|
|
2245
2264
|
// are the transaction's reveal machinery and always re-enter.
|
|
2246
2265
|
const settleTransition = () => {
|
|
2247
2266
|
const t = resolveTransition(e);
|
|
2248
|
-
if (t && e.
|
|
2267
|
+
if (t && e.ct & STATUS_UNINITIALIZED && !currentTransition(t).J.has(e)) {
|
|
2249
2268
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
2250
2269
|
// stash-path restamp both re-enter the transaction through it.
|
|
2251
2270
|
e.O = null;
|
|
@@ -2254,21 +2273,25 @@ function handleAsync(e, t, n) {
|
|
|
2254
2273
|
globalQueue.initTransition(t);
|
|
2255
2274
|
};
|
|
2256
2275
|
const handleError = n => {
|
|
2257
|
-
if (e.o?.
|
|
2276
|
+
if (e.o?.bt !== t) return;
|
|
2258
2277
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
2259
2278
|
let i = n instanceof NotReadyError;
|
|
2260
|
-
if (i && e.
|
|
2279
|
+
if (i && e.lt) {
|
|
2261
2280
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
2262
2281
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
2263
2282
|
// dependency throws. The dead flight is released so the clock-gated
|
|
2264
2283
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
2265
|
-
if (e.o !== null) e.o.
|
|
2284
|
+
if (e.o !== null) e.o.bt = null;
|
|
2266
2285
|
parkLoadingWindow(e, n);
|
|
2267
2286
|
e.Z = clock;
|
|
2268
2287
|
return;
|
|
2269
2288
|
}
|
|
2270
2289
|
settleTransition();
|
|
2271
2290
|
notifyStatus(e, i ? STATUS_PENDING : STATUS_ERROR, n);
|
|
2291
|
+
// A NotReady rejection is a landing into another pending source. The
|
|
2292
|
+
// rejected flight will never settle its self entry, so transfer ownership
|
|
2293
|
+
// after notifyStatus has propagated the replacement source.
|
|
2294
|
+
if (i) settlePendingSource(e);
|
|
2272
2295
|
e.Z = clock;
|
|
2273
2296
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
2274
2297
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
@@ -2276,17 +2299,25 @@ function handleAsync(e, t, n) {
|
|
|
2276
2299
|
if (!i) releaseSettledDependents(e);
|
|
2277
2300
|
};
|
|
2278
2301
|
const asyncWrite = (i, r) => {
|
|
2279
|
-
if (e.o?.
|
|
2302
|
+
if (e.o?.bt !== t) return;
|
|
2280
2303
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
2281
2304
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
2282
2305
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
2283
2306
|
if (e.L & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
2284
2307
|
settleTransition();
|
|
2285
|
-
const o = !!(e.
|
|
2308
|
+
const o = !!(e.ct & STATUS_UNINITIALIZED);
|
|
2309
|
+
// Captured before clearStatus wipes it: a quiet re-ask's landing may be
|
|
2310
|
+
// transition-held below, and the displayed value keeps answering the same
|
|
2311
|
+
// question until the hold commits — the classification must survive to
|
|
2312
|
+
// that reveal or companion synchronization briefly classifies the held
|
|
2313
|
+
// old value as pending, a one-frame pulse to direct observers (#3178).
|
|
2314
|
+
// A truthy capture implies `_x` exists, so the restore writes it directly.
|
|
2315
|
+
const s = e.o?.ut;
|
|
2286
2316
|
trimStaleDeps(e);
|
|
2287
2317
|
clearStatus(e);
|
|
2288
|
-
|
|
2289
|
-
|
|
2318
|
+
if (s) e.o.ut = true;
|
|
2319
|
+
const u = resolveLane(e);
|
|
2320
|
+
if (u) u.T.delete(e);
|
|
2290
2321
|
if (n) {
|
|
2291
2322
|
n(i);
|
|
2292
2323
|
if (o) clearStatus(e, true);
|
|
@@ -2300,8 +2331,8 @@ function handleAsync(e, t, n) {
|
|
|
2300
2331
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
2301
2332
|
// has committed by then, so corrections reveal atomically with their
|
|
2302
2333
|
// transition rather than escaping it.
|
|
2303
|
-
if (e
|
|
2304
|
-
e
|
|
2334
|
+
if (e.$ === NOT_PENDING) queuePendingNode(e);
|
|
2335
|
+
e.$ = i;
|
|
2305
2336
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
2306
2337
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
2307
2338
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -2325,11 +2356,11 @@ function handleAsync(e, t, n) {
|
|
|
2325
2356
|
GlobalQueue.Ke?.(e);
|
|
2326
2357
|
}
|
|
2327
2358
|
e.Z = clock;
|
|
2328
|
-
} else if (
|
|
2359
|
+
} else if (u) {
|
|
2329
2360
|
// Route through lane's effect queue for independent flushing
|
|
2330
2361
|
const t = e.ae;
|
|
2331
2362
|
const n = e.ot;
|
|
2332
|
-
const r = e.
|
|
2363
|
+
const r = e.Wt;
|
|
2333
2364
|
try {
|
|
2334
2365
|
if (!t && o || !r || !r(i, n)) {
|
|
2335
2366
|
e.ot = i;
|
|
@@ -2361,8 +2392,12 @@ function handleAsync(e, t, n) {
|
|
|
2361
2392
|
// (`_pendingValue` set above or inside setSignal) is not — the verdict's
|
|
2362
2393
|
// held-value branch is window-gated, and commitPendingNode closes the
|
|
2363
2394
|
// window when the hold commits, so no one-frame isPending pulse can leak
|
|
2364
|
-
// to live observers between the landing and its commit (#2990).
|
|
2365
|
-
|
|
2395
|
+
// to live observers between the landing and its commit (#2990). The
|
|
2396
|
+
// quiet re-ask classification follows the same schedule (#3178).
|
|
2397
|
+
if (e.$ === NOT_PENDING) {
|
|
2398
|
+
e.lt = false;
|
|
2399
|
+
if (s) e.o.ut = false;
|
|
2400
|
+
}
|
|
2366
2401
|
settlePendingSource(e);
|
|
2367
2402
|
schedule();
|
|
2368
2403
|
flush();
|
|
@@ -2376,7 +2411,7 @@ function handleAsync(e, t, n) {
|
|
|
2376
2411
|
// Returns whether the node released, so the iterator branch can stop
|
|
2377
2412
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
2378
2413
|
const settleAutodispose = () => {
|
|
2379
|
-
if (e.D & CONFIG_AUTO_DISPOSE && !e
|
|
2414
|
+
if (e.D & CONFIG_AUTO_DISPOSE && !e.B && !(e.ct & STATUS_PENDING)) {
|
|
2380
2415
|
unobserved(e);
|
|
2381
2416
|
return true;
|
|
2382
2417
|
}
|
|
@@ -2411,7 +2446,7 @@ function handleAsync(e, t, n) {
|
|
|
2411
2446
|
// owner-death backstop, but its disposal list can be zombie-deferred
|
|
2412
2447
|
// until the SUPERSEDING flight settles. The teardown slot fires at the
|
|
2413
2448
|
// _inFlight release sites so supersede stops this stream immediately.
|
|
2414
|
-
ext(e).
|
|
2449
|
+
ext(e).Qt = close;
|
|
2415
2450
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
2416
2451
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
2417
2452
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
@@ -2441,7 +2476,7 @@ function handleAsync(e, t, n) {
|
|
|
2441
2476
|
n = i;
|
|
2442
2477
|
f = true;
|
|
2443
2478
|
if (i.done) u = true;
|
|
2444
|
-
} else if (e.o?.
|
|
2479
|
+
} else if (e.o?.bt !== t) {
|
|
2445
2480
|
return;
|
|
2446
2481
|
} else if (!i.done) {
|
|
2447
2482
|
s = true;
|
|
@@ -2461,7 +2496,7 @@ function handleAsync(e, t, n) {
|
|
|
2461
2496
|
if (a && l) {
|
|
2462
2497
|
i = n;
|
|
2463
2498
|
c = true;
|
|
2464
|
-
} else if (e.o?.
|
|
2499
|
+
} else if (e.o?.bt === t) {
|
|
2465
2500
|
u = true;
|
|
2466
2501
|
handleError(n);
|
|
2467
2502
|
settleAutodispose();
|
|
@@ -2521,13 +2556,13 @@ function handleAsync(e, t, n) {
|
|
|
2521
2556
|
// becomes disposal-bearing, which is exactly the class a directly
|
|
2522
2557
|
// returned iterable already occupies.
|
|
2523
2558
|
const registerDeferredClose = t => {
|
|
2524
|
-
if (!e.
|
|
2559
|
+
if (!e.xt) e.xt = t; else if (Array.isArray(e.xt)) e.xt.push(t); else e.xt = [ e.xt, t ];
|
|
2525
2560
|
};
|
|
2526
2561
|
t.then(i => {
|
|
2527
2562
|
if (s) {
|
|
2528
2563
|
o = i;
|
|
2529
2564
|
n = true;
|
|
2530
|
-
} else if (e.o?.
|
|
2565
|
+
} else if (e.o?.bt === t && !(e.L & REACTIVE_DISPOSED) && flattenIfIterable(i, registerDeferredClose)) ; else {
|
|
2531
2566
|
asyncWrite(i);
|
|
2532
2567
|
settleAutodispose();
|
|
2533
2568
|
}
|
|
@@ -2552,12 +2587,12 @@ function handleAsync(e, t, n) {
|
|
|
2552
2587
|
// is opened — first-flight work on a loadingValue node is loading-class
|
|
2553
2588
|
// (invisible to boundaries and transitions); the flight itself is
|
|
2554
2589
|
// already registered in _inFlight and lands through asyncWrite.
|
|
2555
|
-
if (e.
|
|
2590
|
+
if (e.lt) return e.ot;
|
|
2556
2591
|
globalQueue.initTransition(resolveTransition(e));
|
|
2557
2592
|
throw new NotReadyError(context);
|
|
2558
2593
|
} else if (!flattenIfIterable(o)) {
|
|
2559
2594
|
// Synchronously-resolved promise: the first real answer landed.
|
|
2560
|
-
e.
|
|
2595
|
+
e.lt = false;
|
|
2561
2596
|
}
|
|
2562
2597
|
// A sync-resolved promise holding an AsyncIterable flattened LIVE (we
|
|
2563
2598
|
// are still inside the synchronous read): full initial-drain semantics
|
|
@@ -2567,30 +2602,30 @@ function handleAsync(e, t, n) {
|
|
|
2567
2602
|
if (s !== null) {
|
|
2568
2603
|
if (!s) {
|
|
2569
2604
|
// Loading window: serve commit #0 (see the promise branch above).
|
|
2570
|
-
if (e.
|
|
2605
|
+
if (e.lt) return e.ot;
|
|
2571
2606
|
globalQueue.initTransition(resolveTransition(e));
|
|
2572
2607
|
throw new NotReadyError(context);
|
|
2573
2608
|
}
|
|
2574
2609
|
// A sync first yield (or immediate empty completion) is the first real
|
|
2575
2610
|
// answer; async yields clear inside asyncWrite.
|
|
2576
|
-
e.
|
|
2611
|
+
e.lt = false;
|
|
2577
2612
|
}
|
|
2578
2613
|
return o;
|
|
2579
2614
|
}
|
|
2580
2615
|
|
|
2581
2616
|
function clearStatus(e, t = false) {
|
|
2582
|
-
if (e.o?.
|
|
2583
|
-
if (e.o?.
|
|
2617
|
+
if (e.o?.Tt) clearPendingSources(e);
|
|
2618
|
+
if (e.o?.Vt) if (e.o !== null) e.o.Vt = false;
|
|
2584
2619
|
// The pending window is over; its quiet classification dies with it.
|
|
2585
2620
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
2586
2621
|
// plain store to an existing slot — no shape change.)
|
|
2587
|
-
if (e.o !== null) e.o.
|
|
2588
|
-
e.
|
|
2622
|
+
if (e.o !== null) e.o.ut = false;
|
|
2623
|
+
e.ct = t ? 0 : e.ct & STATUS_UNINITIALIZED;
|
|
2589
2624
|
if (e.o?.ze) setPendingError(e);
|
|
2590
2625
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
2591
2626
|
// once the verdict layer created them, which installs the hooks).
|
|
2592
2627
|
if (e.o?.I || e.o?.R) GlobalQueue.ve(e);
|
|
2593
|
-
if (e.o?.
|
|
2628
|
+
if (e.o?.vt && e.D & CONFIG_CHILD_COMPANIONS && GlobalQueue.ye !== null) GlobalQueue.ye(e);
|
|
2594
2629
|
const n = statusNotifierOf(e);
|
|
2595
2630
|
if (n) n.call(e);
|
|
2596
2631
|
}
|
|
@@ -2605,17 +2640,17 @@ function notifyStatus(e, t, n, i, r) {
|
|
|
2605
2640
|
if (!i) {
|
|
2606
2641
|
if (t === STATUS_PENDING && o) {
|
|
2607
2642
|
addPendingSource(e, o);
|
|
2608
|
-
e.
|
|
2643
|
+
e.ct = STATUS_PENDING | e.ct & STATUS_UNINITIALIZED;
|
|
2609
2644
|
// Preserve the current source on this propagation so render-effect notification
|
|
2610
2645
|
// can register every distinct pending source with the transition.
|
|
2611
2646
|
setPendingError(e, o, n);
|
|
2612
2647
|
} else {
|
|
2613
2648
|
clearPendingSources(e);
|
|
2614
|
-
e.
|
|
2649
|
+
e.ct = t | (t !== STATUS_ERROR ? e.ct & STATUS_UNINITIALIZED : 0);
|
|
2615
2650
|
ext(e).ze = n;
|
|
2616
2651
|
}
|
|
2617
2652
|
GlobalQueue.ve?.(e);
|
|
2618
|
-
if (e.o?.
|
|
2653
|
+
if (e.o?.vt && e.D & CONFIG_CHILD_COMPANIONS && GlobalQueue.ye !== null) GlobalQueue.ye(e);
|
|
2619
2654
|
}
|
|
2620
2655
|
if (r && !i) {
|
|
2621
2656
|
assignOrMergeLane(e, r);
|
|
@@ -2636,13 +2671,13 @@ function notifyStatus(e, t, n, i, r) {
|
|
|
2636
2671
|
}
|
|
2637
2672
|
forEachDependent(e, (e, i) => {
|
|
2638
2673
|
e.Z = clock;
|
|
2639
|
-
if (t === STATUS_PENDING && o && !e.o?.
|
|
2674
|
+
if (t === STATUS_PENDING && o && !e.o?.Tt?.has(o) || t !== STATUS_PENDING && (e.o?.ze !== n || e.o?.Tt)) {
|
|
2640
2675
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
2641
2676
|
// It exists so the observer re-runs when the source settles, but it must
|
|
2642
2677
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
2643
2678
|
// read swallows those, and the async path must match. Re-run the observer
|
|
2644
2679
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
2645
|
-
if (i.
|
|
2680
|
+
if (i.Lt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
2646
2681
|
enqueueSub(e);
|
|
2647
2682
|
schedule();
|
|
2648
2683
|
return;
|
|
@@ -2687,7 +2722,7 @@ let snapshotSources = null;
|
|
|
2687
2722
|
|
|
2688
2723
|
function ownerInSnapshotScope(e) {
|
|
2689
2724
|
while (e) {
|
|
2690
|
-
if (e.
|
|
2725
|
+
if (e.jt) return true;
|
|
2691
2726
|
e = e.pe;
|
|
2692
2727
|
}
|
|
2693
2728
|
return false;
|
|
@@ -2699,20 +2734,20 @@ function setSnapshotCapture(e) {
|
|
|
2699
2734
|
}
|
|
2700
2735
|
|
|
2701
2736
|
function markSnapshotScope(e) {
|
|
2702
|
-
e.
|
|
2737
|
+
e.jt = true;
|
|
2703
2738
|
}
|
|
2704
2739
|
|
|
2705
2740
|
function releaseSnapshotScope(e) {
|
|
2706
|
-
e.
|
|
2741
|
+
e.jt = false;
|
|
2707
2742
|
releaseSubtree(e);
|
|
2708
2743
|
schedule();
|
|
2709
2744
|
}
|
|
2710
2745
|
|
|
2711
2746
|
function releaseSubtree(e) {
|
|
2712
|
-
let t = e.
|
|
2747
|
+
let t = e.wt;
|
|
2713
2748
|
while (t) {
|
|
2714
|
-
if (t.
|
|
2715
|
-
t = t.
|
|
2749
|
+
if (t.jt) {
|
|
2750
|
+
t = t.Pt;
|
|
2716
2751
|
continue;
|
|
2717
2752
|
}
|
|
2718
2753
|
if (t.it) {
|
|
@@ -2721,12 +2756,12 @@ function releaseSubtree(e) {
|
|
|
2721
2756
|
if (e.L & REACTIVE_SNAPSHOT_STALE) {
|
|
2722
2757
|
e.L &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2723
2758
|
e.L |= REACTIVE_DIRTY;
|
|
2724
|
-
if (dirtyQueue.H > e.
|
|
2759
|
+
if (dirtyQueue.H > e.Nt) dirtyQueue.H = e.Nt;
|
|
2725
2760
|
insertIntoHeap(e, dirtyQueue);
|
|
2726
2761
|
}
|
|
2727
2762
|
}
|
|
2728
2763
|
releaseSubtree(t);
|
|
2729
|
-
t = t.
|
|
2764
|
+
t = t.Pt;
|
|
2730
2765
|
}
|
|
2731
2766
|
}
|
|
2732
2767
|
|
|
@@ -2752,7 +2787,7 @@ function recompute(e, t = false) {
|
|
|
2752
2787
|
if (e.O && (!n || activeTransition) && activeTransition !== e.O) globalQueue.initTransition(e.O);
|
|
2753
2788
|
deleteFromHeap(e, queueFor(e));
|
|
2754
2789
|
if (e.o !== null) {
|
|
2755
|
-
e.o.
|
|
2790
|
+
e.o.bt = null;
|
|
2756
2791
|
// Supersede is where an iterator flight dies (#3122): close it now.
|
|
2757
2792
|
// Its cleanup(close) registration may sit in a zombie-deferred
|
|
2758
2793
|
// disposal list that a held transition only drains when the
|
|
@@ -2761,30 +2796,30 @@ function recompute(e, t = false) {
|
|
|
2761
2796
|
releaseFlightTeardown(e);
|
|
2762
2797
|
}
|
|
2763
2798
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
2764
|
-
if (e.O || n === EFFECT_TRACKED) disposeChildren(e); else if (e.
|
|
2799
|
+
if (e.O || n === EFFECT_TRACKED) disposeChildren(e); else if (e.wt !== null || e.xt !== null) {
|
|
2765
2800
|
markDisposal(e);
|
|
2766
2801
|
const t = ext(e);
|
|
2767
|
-
t.
|
|
2768
|
-
t.
|
|
2769
|
-
e.
|
|
2770
|
-
e.
|
|
2771
|
-
e.
|
|
2802
|
+
t.Et = e.xt;
|
|
2803
|
+
t.dt = e.wt;
|
|
2804
|
+
e.xt = null;
|
|
2805
|
+
e.wt = null;
|
|
2806
|
+
e.Dt = 0;
|
|
2772
2807
|
} else ;
|
|
2773
2808
|
}
|
|
2774
2809
|
let i = !!(e.L & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2775
2810
|
const r = (e.D & CONFIG_OPTIMISTIC) !== 0 && e.o?.m !== NOT_PENDING && e.o?.m !== undefined;
|
|
2776
|
-
const o = !!(e.
|
|
2811
|
+
const o = !!(e.ct & STATUS_UNINITIALIZED);
|
|
2777
2812
|
// Outgoing error, captured before the compute clears status: if this run
|
|
2778
2813
|
// recovers to an unchanged value, dependents still holding this object must
|
|
2779
2814
|
// be swept (settleErroredDependents, #2949).
|
|
2780
|
-
const s = e.
|
|
2815
|
+
const s = e.ct & STATUS_ERROR ? e.o?.ze : undefined;
|
|
2781
2816
|
// Pending SOURCE-hood, captured before the compute clears status: a node
|
|
2782
2817
|
// whose own flight parked dependents self-registers in _pendingSources
|
|
2783
2818
|
// (notifyStatus, isSource). If this recompute supersedes that flight and
|
|
2784
2819
|
// settles synchronously, those dependents settle HERE — asyncWrite's
|
|
2785
2820
|
// settlePendingSource walk never runs for a landing that was preempted
|
|
2786
2821
|
// (#3181).
|
|
2787
|
-
const u =
|
|
2822
|
+
const u = e.o?.Tt?.has(e);
|
|
2788
2823
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2789
2824
|
// the recompute wipes _flags below.
|
|
2790
2825
|
const l = (e.L & REACTIVE_REASK) !== 0;
|
|
@@ -2792,15 +2827,15 @@ function recompute(e, t = false) {
|
|
|
2792
2827
|
// is transition-held below, the window must stay open until the hold
|
|
2793
2828
|
// commits (commitPendingNode) — a closed window plus a held value reads as
|
|
2794
2829
|
// a pending frame to live observers of the verdict (#2990).
|
|
2795
|
-
const f = e.
|
|
2830
|
+
const f = e.lt;
|
|
2796
2831
|
const c = context;
|
|
2797
2832
|
context = e;
|
|
2798
2833
|
e.le = null;
|
|
2799
2834
|
e.nt++;
|
|
2800
2835
|
e.L = REACTIVE_RECOMPUTING_DEPS;
|
|
2801
2836
|
e.Z = clock;
|
|
2802
|
-
let a = e
|
|
2803
|
-
let d = e.
|
|
2837
|
+
let a = e.$ === NOT_PENDING ? e.ot : e.$;
|
|
2838
|
+
let d = e.Nt;
|
|
2804
2839
|
let p = false;
|
|
2805
2840
|
let E = tracking;
|
|
2806
2841
|
let S = currentOptimisticLane;
|
|
@@ -2817,7 +2852,7 @@ function recompute(e, t = false) {
|
|
|
2817
2852
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
2818
2853
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
2819
2854
|
if (i) {
|
|
2820
|
-
const t = GlobalQueue
|
|
2855
|
+
const t = GlobalQueue.Be(e, true);
|
|
2821
2856
|
if (t) currentOptimisticLane = t;
|
|
2822
2857
|
// `false` = wake-only lane demotion: recompute plain so a mid-tick
|
|
2823
2858
|
// latest()/isPending() pull stages instead of direct-committing (#3009).
|
|
@@ -2827,7 +2862,7 @@ function recompute(e, t = false) {
|
|
|
2827
2862
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
2828
2863
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
2829
2864
|
// recomputes under the right posture and propagates correctly.
|
|
2830
|
-
const t = GlobalQueue
|
|
2865
|
+
const t = GlobalQueue.Be(e, false);
|
|
2831
2866
|
if (t) {
|
|
2832
2867
|
i = true;
|
|
2833
2868
|
currentOptimisticLane = t;
|
|
@@ -2839,39 +2874,39 @@ function recompute(e, t = false) {
|
|
|
2839
2874
|
try {
|
|
2840
2875
|
if (!false && e.D & CONFIG_SYNC) {
|
|
2841
2876
|
a = e.it(a);
|
|
2842
|
-
if (e.o !== null) e.o.
|
|
2843
|
-
e.
|
|
2877
|
+
if (e.o !== null) e.o.bt = null;
|
|
2878
|
+
e.lt = false;
|
|
2844
2879
|
} else {
|
|
2845
2880
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2846
2881
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2847
2882
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2848
2883
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2849
2884
|
// iteration drive updates.
|
|
2850
|
-
const t = e.o?.
|
|
2885
|
+
const t = e.o?.bt;
|
|
2851
2886
|
const n = e.it(a);
|
|
2852
2887
|
const i = typeof n === "object" && n !== null;
|
|
2853
|
-
const r = e.o?.
|
|
2888
|
+
const r = e.o?.bt !== t;
|
|
2854
2889
|
a = r || !i ? n : handleAsync(e, n);
|
|
2855
2890
|
if (!r && !i) {
|
|
2856
|
-
if (e.o !== null) e.o.
|
|
2891
|
+
if (e.o !== null) e.o.bt = null;
|
|
2857
2892
|
// A sync (non-object) return is the first real answer; async-shaped
|
|
2858
2893
|
// results clear inside handleAsync at their own landing points, and a
|
|
2859
2894
|
// self-registered flight (inFlightChanged — projections) clears when
|
|
2860
2895
|
// its internal handleAsync lands.
|
|
2861
|
-
e.
|
|
2896
|
+
e.lt = false;
|
|
2862
2897
|
}
|
|
2863
2898
|
}
|
|
2864
2899
|
// On a status-free node clearStatus is a guaranteed no-op: every field
|
|
2865
2900
|
// its body gates on is either _statusFlags or lives in the cold
|
|
2866
2901
|
// extension — no extension, no status to clear. (_x from an unrelated
|
|
2867
2902
|
// installer just makes clearStatus a cheap re-verified no-op.)
|
|
2868
|
-
if (e.
|
|
2903
|
+
if (e.ct !== 0 || e.o !== null) clearStatus(e, t);
|
|
2869
2904
|
// _optimisticLane is only ever assigned by engine paths (CONFIG_HAS_LANE
|
|
2870
2905
|
// is their sticky presence mark).
|
|
2871
2906
|
if (e.D & CONFIG_HAS_LANE && e.o?.l) GlobalQueue.Ye(e);
|
|
2872
2907
|
} catch (t) {
|
|
2873
2908
|
const n = t instanceof NotReadyError;
|
|
2874
|
-
if (n && e.
|
|
2909
|
+
if (n && e.lt) {
|
|
2875
2910
|
// Loading window with an unready sync dependency: register for the
|
|
2876
2911
|
// source's settle (the settlePendingSource walk runs off
|
|
2877
2912
|
// _pendingSources + _blocked alone) but take NO read-visible pending
|
|
@@ -2883,13 +2918,16 @@ function recompute(e, t = false) {
|
|
|
2883
2918
|
} else {
|
|
2884
2919
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2885
2920
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2886
|
-
if (n && currentOptimisticLane) GlobalQueue
|
|
2921
|
+
if (n && currentOptimisticLane) GlobalQueue.$e(e);
|
|
2887
2922
|
let i = false;
|
|
2888
2923
|
if (n) {
|
|
2889
|
-
ext(e).
|
|
2924
|
+
ext(e).Vt = true;
|
|
2890
2925
|
if (GlobalQueue.De !== null) i = GlobalQueue.De(e, l);
|
|
2891
2926
|
}
|
|
2892
2927
|
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.l : undefined);
|
|
2928
|
+
// The replacement source is fully propagated now. If no new flight
|
|
2929
|
+
// re-owned self, retire the superseded flight and its dependent copies.
|
|
2930
|
+
if (n && u && !e.o?.bt) settlePendingSource(e);
|
|
2893
2931
|
if (i) GlobalQueue.Ge(e);
|
|
2894
2932
|
}
|
|
2895
2933
|
} finally {
|
|
@@ -2907,10 +2945,10 @@ function recompute(e, t = false) {
|
|
|
2907
2945
|
}
|
|
2908
2946
|
if (!e.o?.ze) {
|
|
2909
2947
|
trimStaleDeps(e);
|
|
2910
|
-
const l = r ? unwrapOverride(e.o?.m) : e
|
|
2948
|
+
const l = r ? unwrapOverride(e.o?.m) : e.$ === NOT_PENDING ? e.ot : e.$;
|
|
2911
2949
|
let c = false;
|
|
2912
2950
|
try {
|
|
2913
|
-
c = !n && o || !e.
|
|
2951
|
+
c = !n && o || !e.Wt || !e.Wt(l, a);
|
|
2914
2952
|
} catch (t) {
|
|
2915
2953
|
// A throwing user comparator is an error of this node's computation.
|
|
2916
2954
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2927,7 +2965,7 @@ function recompute(e, t = false) {
|
|
|
2927
2965
|
e.st = !e.o?.ze;
|
|
2928
2966
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2929
2967
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2930
|
-
if (!t) e.
|
|
2968
|
+
if (!t) e.At.enqueue(n, e.Mt ??= GlobalQueue._e.bind(null, e));
|
|
2931
2969
|
}
|
|
2932
2970
|
if (e.o?.ze) ; else if (c) {
|
|
2933
2971
|
const o = r ? e.o?.m : undefined;
|
|
@@ -2948,13 +2986,13 @@ function recompute(e, t = false) {
|
|
|
2948
2986
|
// commit can't clobber the fresh value.
|
|
2949
2987
|
if (r && i) {
|
|
2950
2988
|
ext(e).m = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
2951
|
-
e
|
|
2989
|
+
e.$ = NOT_PENDING;
|
|
2952
2990
|
}
|
|
2953
2991
|
} else {
|
|
2954
|
-
e
|
|
2992
|
+
e.$ = a;
|
|
2955
2993
|
// A window landing that gets held re-opens the window until the hold
|
|
2956
2994
|
// commits — the verdict's held-value branch is window-gated (#2990).
|
|
2957
|
-
if (f) e.
|
|
2995
|
+
if (f) e.lt = true;
|
|
2958
2996
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2959
2997
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2960
2998
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
@@ -2964,14 +3002,14 @@ function recompute(e, t = false) {
|
|
|
2964
3002
|
}
|
|
2965
3003
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2966
3004
|
// subscriber-less node has nothing to notify.
|
|
2967
|
-
if (e
|
|
3005
|
+
if (e.B !== null && (!r || i || e.o?.m !== o)) insertSubs(e, i || r);
|
|
2968
3006
|
} else if (r) {
|
|
2969
3007
|
// Unchanged value (equals the override) recomputed while the override
|
|
2970
3008
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2971
3009
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2972
|
-
if (e
|
|
2973
|
-
e
|
|
2974
|
-
if (f) e.
|
|
3010
|
+
if (e.$ === NOT_PENDING) queuePendingNode(e);
|
|
3011
|
+
e.$ = a;
|
|
3012
|
+
if (f) e.lt = true;
|
|
2975
3013
|
// see the held branch above (#2990)
|
|
2976
3014
|
// A authoritative-view reader (until()) observed this node past its
|
|
2977
3015
|
// override — and "authoritative arrival equal to the override" is
|
|
@@ -2979,8 +3017,8 @@ function recompute(e, t = false) {
|
|
|
2979
3017
|
// A17 silence holds for every ordinary subscriber. (Hook installed by
|
|
2980
3018
|
// until(), the only setter of the gating bit.)
|
|
2981
3019
|
if (e.D & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.Ke(e);
|
|
2982
|
-
} else if (e.
|
|
2983
|
-
for (let t = e
|
|
3020
|
+
} else if (e.Nt != d) {
|
|
3021
|
+
for (let t = e.B; t !== null; t = t.fe) {
|
|
2984
3022
|
insertIntoHeapHeight(t.ce, queueFor(t.ce));
|
|
2985
3023
|
}
|
|
2986
3024
|
}
|
|
@@ -2990,26 +3028,19 @@ function recompute(e, t = false) {
|
|
|
2990
3028
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2991
3029
|
// (el._x?._error re-set), so this only runs on a genuinely clean recovery.
|
|
2992
3030
|
if (s !== undefined && !c && !e.o?.ze) settleErroredDependents(e, s);
|
|
2993
|
-
//
|
|
2994
|
-
//
|
|
2995
|
-
//
|
|
2996
|
-
|
|
2997
|
-
// is the dangerous shape (a projection reconciling in place: a memo over
|
|
2998
|
-
// it re-throws its cached NotReadyError forever, and every reader that
|
|
2999
|
-
// suspended through that memo re-parks on the dead source), but the walk
|
|
3000
|
-
// runs on the changed shape too, exactly as the landing path does —
|
|
3001
|
-
// insertSubs notifies value SUBSCRIBERS, not pending REGISTRANTS, and
|
|
3002
|
-
// the two sets only partially overlap.
|
|
3003
|
-
if (u && !(e.lt & STATUS_PENDING)) settlePendingSource(e);
|
|
3031
|
+
// #3181: a synchronous settle supersedes the old landing callback, so
|
|
3032
|
+
// recompute owns its pending-source sweep. An uninitialized node without
|
|
3033
|
+
// a replacement source still has no truth to reveal and must stay parked.
|
|
3034
|
+
if (u && !(e.ct & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
|
|
3004
3035
|
}
|
|
3005
3036
|
currentOptimisticLane = S;
|
|
3006
|
-
const A = e
|
|
3037
|
+
const A = e.$ !== NOT_PENDING || e.o !== null && (e.o.dt !== null || e.o.Et !== null) || (e.ct & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
3007
3038
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
3008
3039
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
3009
3040
|
// under the override (A17). Revert no longer commits anything, so an
|
|
3010
3041
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
3011
3042
|
// _transition.
|
|
3012
|
-
A && (!t || e.
|
|
3043
|
+
A && (!t || e.ct & STATUS_PENDING) && (!e.O || r) && queuePendingNode(e);
|
|
3013
3044
|
e.O && n && activeTransition !== e.O && runInTransition(e.O, () => recompute(e));
|
|
3014
3045
|
// Missed-wake reschedule (see the finally above): values this pass read
|
|
3015
3046
|
// before the nested commit are stale, so run again now that the heap will
|
|
@@ -3033,7 +3064,7 @@ function updateIfNecessary(e) {
|
|
|
3033
3064
|
if (e.L & REACTIVE_CHECK) {
|
|
3034
3065
|
for (let t = e.oe; t; t = t.se) {
|
|
3035
3066
|
const n = t.ue;
|
|
3036
|
-
const i = n.
|
|
3067
|
+
const i = n._t || n;
|
|
3037
3068
|
if (i.it) {
|
|
3038
3069
|
updateIfNecessary(i);
|
|
3039
3070
|
}
|
|
@@ -3042,7 +3073,7 @@ function updateIfNecessary(e) {
|
|
|
3042
3073
|
}
|
|
3043
3074
|
}
|
|
3044
3075
|
}
|
|
3045
|
-
if (e.L & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?.ze && e.Z < clock && !e.o?.
|
|
3076
|
+
if (e.L & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?.ze && e.Z < clock && !e.o?.bt) {
|
|
3046
3077
|
recompute(e);
|
|
3047
3078
|
}
|
|
3048
3079
|
e.L = e.L & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -3056,34 +3087,34 @@ function computed(e, t) {
|
|
|
3056
3087
|
const i = t !== null && typeof t === "object" && "loadingValue" in t;
|
|
3057
3088
|
const r = {
|
|
3058
3089
|
id: inheritId(t, n, context),
|
|
3059
|
-
D: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3090
|
+
D: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.qt ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
3091
|
+
Wt: t?.equals ?? isEqual,
|
|
3092
|
+
xt: null,
|
|
3093
|
+
At: context?.At ?? globalQueue,
|
|
3094
|
+
Ft: context?.Ft ?? defaultContext,
|
|
3095
|
+
Dt: 0,
|
|
3065
3096
|
it: e,
|
|
3066
3097
|
ot: i ? t.loadingValue : undefined,
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3098
|
+
Nt: 0,
|
|
3099
|
+
gt: undefined,
|
|
3100
|
+
Ct: null,
|
|
3070
3101
|
oe: null,
|
|
3071
3102
|
le: null,
|
|
3072
3103
|
nt: 0,
|
|
3073
|
-
|
|
3074
|
-
|
|
3104
|
+
B: null,
|
|
3105
|
+
Ut: null,
|
|
3075
3106
|
pe: context,
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3107
|
+
Pt: null,
|
|
3108
|
+
Gt: null,
|
|
3109
|
+
wt: null,
|
|
3079
3110
|
L: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
3080
3111
|
// A loadingValue node is born committed: commit #0 is already in _value.
|
|
3081
|
-
|
|
3112
|
+
ct: i ? 0 : STATUS_UNINITIALIZED,
|
|
3082
3113
|
Z: clock,
|
|
3083
|
-
|
|
3114
|
+
$: NOT_PENDING,
|
|
3084
3115
|
O: null,
|
|
3085
3116
|
Je: -1,
|
|
3086
|
-
|
|
3117
|
+
lt: i,
|
|
3087
3118
|
// Cold machinery (async/transition/optimistic/verdict slots) lives one
|
|
3088
3119
|
// hop away in the lazily-allocated extension — the core literal MUST
|
|
3089
3120
|
// stay under V8's in-object boundary (§12: past ~39 fields every
|
|
@@ -3107,18 +3138,18 @@ function computed(e, t) {
|
|
|
3107
3138
|
R: undefined,
|
|
3108
3139
|
i: undefined,
|
|
3109
3140
|
K: 0,
|
|
3110
|
-
|
|
3111
|
-
|
|
3141
|
+
bt: null,
|
|
3142
|
+
Qt: null,
|
|
3112
3143
|
ze: undefined,
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3144
|
+
Vt: undefined,
|
|
3145
|
+
Tt: undefined,
|
|
3146
|
+
Bt: undefined,
|
|
3147
|
+
ut: false,
|
|
3148
|
+
vt: null,
|
|
3118
3149
|
Y: undefined,
|
|
3119
3150
|
et: undefined,
|
|
3120
|
-
|
|
3121
|
-
|
|
3151
|
+
Et: null,
|
|
3152
|
+
dt: null,
|
|
3122
3153
|
$t: undefined
|
|
3123
3154
|
};
|
|
3124
3155
|
}
|
|
@@ -3132,38 +3163,38 @@ function computed(e, t) {
|
|
|
3132
3163
|
const o = r?.transparent ?? false;
|
|
3133
3164
|
const s = {
|
|
3134
3165
|
id: inheritId(r, o, context),
|
|
3135
|
-
D: (o ? CONFIG_TRANSPARENT : 0) | (r?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (r?.sync ? CONFIG_SYNC : 0) | (r?.
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3166
|
+
D: (o ? CONFIG_TRANSPARENT : 0) | (r?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (r?.sync ? CONFIG_SYNC : 0) | (r?.Kt ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
3167
|
+
Wt: false,
|
|
3168
|
+
xt: null,
|
|
3169
|
+
At: context?.At ?? globalQueue,
|
|
3170
|
+
Ft: context?.Ft ?? defaultContext,
|
|
3171
|
+
Dt: 0,
|
|
3141
3172
|
it: e,
|
|
3142
3173
|
ot: undefined,
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3174
|
+
Nt: 0,
|
|
3175
|
+
gt: undefined,
|
|
3176
|
+
Ct: null,
|
|
3146
3177
|
oe: null,
|
|
3147
3178
|
le: null,
|
|
3148
3179
|
nt: 0,
|
|
3149
|
-
|
|
3150
|
-
|
|
3180
|
+
B: null,
|
|
3181
|
+
Ut: null,
|
|
3151
3182
|
pe: context,
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3183
|
+
Pt: null,
|
|
3184
|
+
Gt: null,
|
|
3185
|
+
wt: null,
|
|
3155
3186
|
L: REACTIVE_LAZY,
|
|
3156
|
-
|
|
3187
|
+
ct: STATUS_UNINITIALIZED,
|
|
3157
3188
|
Z: clock,
|
|
3158
|
-
|
|
3189
|
+
$: NOT_PENDING,
|
|
3159
3190
|
O: null,
|
|
3160
3191
|
Je: -1,
|
|
3161
|
-
|
|
3192
|
+
lt: false,
|
|
3162
3193
|
st: false,
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3194
|
+
Yt: undefined,
|
|
3195
|
+
Zt: t,
|
|
3196
|
+
zt: n,
|
|
3197
|
+
kt: undefined,
|
|
3167
3198
|
ae: i,
|
|
3168
3199
|
o: null
|
|
3169
3200
|
};
|
|
@@ -3193,7 +3224,7 @@ function setEffectStatusNotify(e) {
|
|
|
3193
3224
|
* the field) fall back to the shared notifier. Presence doubles as the
|
|
3194
3225
|
* "display consumer" membership test in the status walks, exactly as the
|
|
3195
3226
|
* per-node field did when every effect carried one. */ function statusNotifierOf(e) {
|
|
3196
|
-
const t = e.o?.
|
|
3227
|
+
const t = e.o?.Bt;
|
|
3197
3228
|
if (t !== undefined) return t;
|
|
3198
3229
|
return e.ae ? effectStatusNotify ?? undefined : undefined;
|
|
3199
3230
|
}
|
|
@@ -3203,23 +3234,23 @@ const lazyOptions = {
|
|
|
3203
3234
|
};
|
|
3204
3235
|
|
|
3205
3236
|
function setupComputedNode(e, t) {
|
|
3206
|
-
e.
|
|
3207
|
-
const n = context?.
|
|
3237
|
+
e.Ct = e;
|
|
3238
|
+
const n = context?.It ? context.Rt : context;
|
|
3208
3239
|
if (context) {
|
|
3209
|
-
const t = context.
|
|
3240
|
+
const t = context.wt;
|
|
3210
3241
|
if (t === null) {
|
|
3211
|
-
context.
|
|
3242
|
+
context.wt = e;
|
|
3212
3243
|
} else {
|
|
3213
|
-
e.
|
|
3214
|
-
t.
|
|
3215
|
-
context.
|
|
3244
|
+
e.Pt = t;
|
|
3245
|
+
t.Gt = e;
|
|
3246
|
+
context.wt = e;
|
|
3216
3247
|
}
|
|
3217
3248
|
}
|
|
3218
|
-
if (n) e.
|
|
3249
|
+
if (n) e.Nt = n.Nt + 1;
|
|
3219
3250
|
if (GlobalQueue.Re !== null) GlobalQueue.Re(e);
|
|
3220
3251
|
!t?.lazy && recompute(e, true);
|
|
3221
3252
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
3222
|
-
if (!(e.
|
|
3253
|
+
if (!(e.ct & STATUS_PENDING) && !(e.D & CONFIG_NO_SNAPSHOT)) {
|
|
3223
3254
|
ext(e).et = e.ot === undefined ? NO_SNAPSHOT : e.ot;
|
|
3224
3255
|
e.D |= CONFIG_HAS_SNAPSHOT;
|
|
3225
3256
|
snapshotSources.add(e);
|
|
@@ -3229,15 +3260,15 @@ function setupComputedNode(e, t) {
|
|
|
3229
3260
|
|
|
3230
3261
|
function signal(e, t, n = null) {
|
|
3231
3262
|
const i = {
|
|
3232
|
-
|
|
3233
|
-
D: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.
|
|
3263
|
+
Wt: t?.equals ?? isEqual,
|
|
3264
|
+
D: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.qt ? CONFIG_NO_SNAPSHOT : 0),
|
|
3234
3265
|
ot: e,
|
|
3235
|
-
|
|
3236
|
-
|
|
3266
|
+
B: null,
|
|
3267
|
+
Ut: null,
|
|
3237
3268
|
Z: clock,
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3269
|
+
_t: n,
|
|
3270
|
+
yt: n?.o?.vt || null,
|
|
3271
|
+
$: NOT_PENDING,
|
|
3241
3272
|
// Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
|
|
3242
3273
|
// materialize one signal per touched leaf, so signal bytes are store
|
|
3243
3274
|
// bytes. _time is write-only on signals (every read site is computed-
|
|
@@ -3249,10 +3280,10 @@ function signal(e, t, n = null) {
|
|
|
3249
3280
|
};
|
|
3250
3281
|
if (t?.unobserved) ext(i).Y = t.unobserved;
|
|
3251
3282
|
if (n) {
|
|
3252
|
-
ext(n).
|
|
3283
|
+
ext(n).vt = i;
|
|
3253
3284
|
n.D |= CONFIG_FW_CHILDREN;
|
|
3254
3285
|
}
|
|
3255
|
-
if (snapshotCaptureActive && !(i.D & CONFIG_NO_SNAPSHOT) && !((n?.
|
|
3286
|
+
if (snapshotCaptureActive && !(i.D & CONFIG_NO_SNAPSHOT) && !((n?.ct ?? 0) & STATUS_PENDING)) {
|
|
3256
3287
|
ext(i).et = e === undefined ? NO_SNAPSHOT : e;
|
|
3257
3288
|
i.D |= CONFIG_HAS_SNAPSHOT;
|
|
3258
3289
|
snapshotSources.add(i);
|
|
@@ -3354,7 +3385,7 @@ function isEqual(e, t) {
|
|
|
3354
3385
|
* Pay-for-use: reached through GlobalQueue._notifyAuthoritativeObservers,
|
|
3355
3386
|
* installed at first until() call — apps that never use until() shake it.
|
|
3356
3387
|
*/ function notifyAuthoritativeObservers(e) {
|
|
3357
|
-
for (let t = e
|
|
3388
|
+
for (let t = e.B; t !== null; t = t.fe) {
|
|
3358
3389
|
const e = t.ce;
|
|
3359
3390
|
if (!(e.D & CONFIG_AUTHORITATIVE_READ)) continue;
|
|
3360
3391
|
// Missed-wake latch (#3037), same contract as insertSubs: the reader may
|
|
@@ -3374,15 +3405,15 @@ function isEqual(e, t) {
|
|
|
3374
3405
|
}
|
|
3375
3406
|
|
|
3376
3407
|
function readNodeFast(e) {
|
|
3377
|
-
if (latestReadActive || pendingCheckActive || e.it || e.
|
|
3408
|
+
if (latestReadActive || pendingCheckActive || e.it || e._t || e.o?.m !== undefined || e.o?.et !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
3378
3409
|
let t = context;
|
|
3379
|
-
if (t?.
|
|
3410
|
+
if (t?.It) t = t.Rt;
|
|
3380
3411
|
if (t && tracking) link(e, t);
|
|
3381
3412
|
// Children-forbidden readers (createTrackedEffect / onSettled callbacks) get
|
|
3382
3413
|
// committed visibility: like the effect half of createEffect and event
|
|
3383
3414
|
// handlers, effect-phase code never observes its own unsettled write — the
|
|
3384
3415
|
// write lands in the same flush's continuation (#3006).
|
|
3385
|
-
return !t || e
|
|
3416
|
+
return !t || e.$ === NOT_PENDING || t.D & CONFIG_CHILDREN_FORBIDDEN ? e.ot : e.$;
|
|
3386
3417
|
}
|
|
3387
3418
|
|
|
3388
3419
|
function read(e) {
|
|
@@ -3392,9 +3423,9 @@ function read(e) {
|
|
|
3392
3423
|
// than the original node (which stays "pending" while held in a transition).
|
|
3393
3424
|
if (latestReadActive) return GlobalQueue.Pe(e);
|
|
3394
3425
|
let t = context;
|
|
3395
|
-
if (t?.
|
|
3426
|
+
if (t?.It) t = t.Rt;
|
|
3396
3427
|
const n = e;
|
|
3397
|
-
const i = e.
|
|
3428
|
+
const i = e._t;
|
|
3398
3429
|
const r = i || e;
|
|
3399
3430
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
3400
3431
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
@@ -3407,13 +3438,13 @@ function read(e) {
|
|
|
3407
3438
|
if (!n.it && r === e && e.o?.m === undefined && e.o?.et === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
3408
3439
|
if (t && tracking) link(e, t);
|
|
3409
3440
|
// Committed visibility for children-forbidden readers — see readNodeFast.
|
|
3410
|
-
return !t || e
|
|
3441
|
+
return !t || e.$ === NOT_PENDING || t.D & CONFIG_CHILDREN_FORBIDDEN ? e.ot : e.$;
|
|
3411
3442
|
}
|
|
3412
3443
|
if (t && tracking) {
|
|
3413
3444
|
link(e, t, pendingCheckActive);
|
|
3414
3445
|
if (r.it) {
|
|
3415
3446
|
const n = queueFor(e);
|
|
3416
|
-
if (r.
|
|
3447
|
+
if (r.Nt >= n.H) {
|
|
3417
3448
|
markNode(t);
|
|
3418
3449
|
markHeap(n);
|
|
3419
3450
|
updateIfNecessary(r);
|
|
@@ -3425,14 +3456,14 @@ function read(e) {
|
|
|
3425
3456
|
// node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
|
|
3426
3457
|
// a dead target serves its last value, which is already quiescent.
|
|
3427
3458
|
else if (t.D & CONFIG_FRESH_READ) updateIfNecessary(r);
|
|
3428
|
-
const i = r.
|
|
3459
|
+
const i = r.Nt;
|
|
3429
3460
|
// parent check is shallow, might need to be recursive
|
|
3430
|
-
if (i >= t.
|
|
3431
|
-
t.
|
|
3461
|
+
if (i >= t.Nt && e.pe !== t) {
|
|
3462
|
+
t.Nt = i + 1;
|
|
3432
3463
|
}
|
|
3433
3464
|
}
|
|
3434
3465
|
}
|
|
3435
|
-
if (r.
|
|
3466
|
+
if (r.ct & STATUS_PENDING) {
|
|
3436
3467
|
if (t && !(stale && r.O && activeTransition !== r.O)) {
|
|
3437
3468
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
3438
3469
|
// is installed): under a lane, only same-lane pending async without an
|
|
@@ -3441,7 +3472,7 @@ function read(e) {
|
|
|
3441
3472
|
if (!tracking && e !== t) link(e, t);
|
|
3442
3473
|
throw r.o?.ze;
|
|
3443
3474
|
}
|
|
3444
|
-
} else if (t && r.
|
|
3475
|
+
} else if (t && r.ct & STATUS_UNINITIALIZED) {
|
|
3445
3476
|
// A stale (render) reader of a node held pending in ANOTHER transition
|
|
3446
3477
|
// normally keeps showing the node's committed value instead of
|
|
3447
3478
|
// entangling the two transactions — but an uninitialized node has no
|
|
@@ -3454,7 +3485,7 @@ function read(e) {
|
|
|
3454
3485
|
// never re-ran when either landed (#3043 port).
|
|
3455
3486
|
if (!tracking && e !== t) link(e, t);
|
|
3456
3487
|
throw r.o?.ze;
|
|
3457
|
-
} else if (!t && r.
|
|
3488
|
+
} else if (!t && r.ct & STATUS_UNINITIALIZED) {
|
|
3458
3489
|
throw r.o?.ze;
|
|
3459
3490
|
}
|
|
3460
3491
|
}
|
|
@@ -3462,7 +3493,7 @@ function read(e) {
|
|
|
3462
3493
|
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
3463
3494
|
// an errored derive throws for every late reader instead of silently
|
|
3464
3495
|
// serving node values (the seed, or last-good data after a failed refetch).
|
|
3465
|
-
if (r.it && r.
|
|
3496
|
+
if (r.it && r.ct & STATUS_ERROR) {
|
|
3466
3497
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
3467
3498
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
3468
3499
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
@@ -3476,7 +3507,7 @@ function read(e) {
|
|
|
3476
3507
|
const n = e.o?.et;
|
|
3477
3508
|
if (n !== undefined) {
|
|
3478
3509
|
const i = n === NO_SNAPSHOT ? undefined : n;
|
|
3479
|
-
const r = e
|
|
3510
|
+
const r = e.$ !== NOT_PENDING ? e.$ : e.ot;
|
|
3480
3511
|
if (r !== i) t.L |= REACTIVE_SNAPSHOT_STALE;
|
|
3481
3512
|
return i;
|
|
3482
3513
|
}
|
|
@@ -3511,7 +3542,7 @@ function read(e) {
|
|
|
3511
3542
|
// (The lane-context clause lives with the engine.) Children-forbidden readers
|
|
3512
3543
|
// (createTrackedEffect / onSettled callbacks) get committed visibility — see
|
|
3513
3544
|
// readNodeFast (#3006).
|
|
3514
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.Me(e, r, t) || e
|
|
3545
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.Me(e, r, t) || e.$ === NOT_PENDING || t.D & CONFIG_CHILDREN_FORBIDDEN || stale && e.O && activeTransition !== e.O ||
|
|
3515
3546
|
// A17 for HELD truth (#3164, see CONFIG_HELD_TRUTH): staged confirming
|
|
3516
3547
|
// truth — fold-staged onto an armed family, or entangle-stolen by an
|
|
3517
3548
|
// awaited until() — is masked from ordinary readers until its
|
|
@@ -3520,11 +3551,11 @@ function read(e) {
|
|
|
3520
3551
|
// compose override + staged truth into a state no timeline contains).
|
|
3521
3552
|
// Authoritative readers (until()'s predicate) and latest() see the
|
|
3522
3553
|
// staged truth — the tunnel that keeps the hold deadlock-free.
|
|
3523
|
-
e.D & CONFIG_HELD_TRUTH && !latestReadActive && !(t.D & CONFIG_AUTHORITATIVE_READ) ? e.ot : e
|
|
3554
|
+
e.D & CONFIG_HELD_TRUTH && !latestReadActive && !(t.D & CONFIG_AUTHORITATIVE_READ) ? e.ot : e.$;
|
|
3524
3555
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
3525
3556
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
3526
3557
|
if (pendingCheckActive) GlobalQueue.me(e, o);
|
|
3527
|
-
if (!t && r === e && typeof n.it === "function" && e.D & CONFIG_AUTO_DISPOSE && !(r.
|
|
3558
|
+
if (!t && r === e && typeof n.it === "function" && e.D & CONFIG_AUTO_DISPOSE && !(r.ct & STATUS_PENDING) && !e.B) {
|
|
3528
3559
|
// Deferred, not inline (#3078): an inline unobserved() here made untracked
|
|
3529
3560
|
// reads destructive — dispose on this read, full revival recompute on the
|
|
3530
3561
|
// next — so consecutive reads could answer differently with no write in
|
|
@@ -3545,15 +3576,15 @@ function setSignal(e, t) {
|
|
|
3545
3576
|
// always-present config instead of a missing-property probe), and every
|
|
3546
3577
|
// module that installs one installs the engine first.
|
|
3547
3578
|
if (e.D & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.Fe(e, t);
|
|
3548
|
-
const n = e
|
|
3579
|
+
const n = e.$ === NOT_PENDING ? e.ot : e.$;
|
|
3549
3580
|
if (typeof t === "function") t = t(n);
|
|
3550
3581
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
3551
3582
|
// user comparator must not run against `undefined` (matches recompute).
|
|
3552
|
-
const i = !!(e.
|
|
3583
|
+
const i = !!(e.ct & STATUS_UNINITIALIZED) || !e.Wt || !e.Wt(n, t);
|
|
3553
3584
|
if (!i) return t;
|
|
3554
|
-
const r = e
|
|
3585
|
+
const r = e.$ !== NOT_PENDING;
|
|
3555
3586
|
if (!r) queuePendingNode(e);
|
|
3556
|
-
e
|
|
3587
|
+
e.$ = t;
|
|
3557
3588
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
3558
3589
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
3559
3590
|
// only ever created, never removed, and creating one installs the hook and
|
|
@@ -3582,12 +3613,12 @@ function setSignal(e, t) {
|
|
|
3582
3613
|
* cleanup point.
|
|
3583
3614
|
*/ function suppressComputedRecompute(e) {
|
|
3584
3615
|
deleteFromHeap(e, queueFor(e));
|
|
3585
|
-
if (!(e.L & REACTIVE_MANUAL_WRITE) && e
|
|
3616
|
+
if (!(e.L & REACTIVE_MANUAL_WRITE) && e.$ === NOT_PENDING) {
|
|
3586
3617
|
queuePendingNode(e);
|
|
3587
3618
|
schedule();
|
|
3588
3619
|
}
|
|
3589
3620
|
e.L = e.L & -4 | REACTIVE_MANUAL_WRITE;
|
|
3590
|
-
e.
|
|
3621
|
+
e.Xt = clock;
|
|
3591
3622
|
}
|
|
3592
3623
|
|
|
3593
3624
|
/**
|
|
@@ -3657,7 +3688,7 @@ function staleValues(e, t = true) {
|
|
|
3657
3688
|
// refresh is a later, explicit re-ask and lifts the mask — otherwise
|
|
3658
3689
|
// any setStore early in an action silently swallows every refresh()
|
|
3659
3690
|
// for the rest of the transaction (#3026).
|
|
3660
|
-
if (e.
|
|
3691
|
+
if (e.Xt === clock) return;
|
|
3661
3692
|
e.L &= ~REACTIVE_MANUAL_WRITE;
|
|
3662
3693
|
// No REASK below: the batch carries a manual value change, so the
|
|
3663
3694
|
// recompute is not a quiet re-ask of an unchanged question.
|
|
@@ -3797,7 +3828,7 @@ function enableExternalSource(e) {
|
|
|
3797
3828
|
if (!t) {
|
|
3798
3829
|
throw new NoOwnerError;
|
|
3799
3830
|
}
|
|
3800
|
-
const n = hasContext(e, t) ? t.
|
|
3831
|
+
const n = hasContext(e, t) ? t.Ft[e.id] : e.defaultValue;
|
|
3801
3832
|
if (isUndefined(n)) {
|
|
3802
3833
|
throw new ContextNotFoundError;
|
|
3803
3834
|
}
|
|
@@ -3818,14 +3849,14 @@ function enableExternalSource(e) {
|
|
|
3818
3849
|
}
|
|
3819
3850
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
3820
3851
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
3821
|
-
n.
|
|
3822
|
-
...n.
|
|
3852
|
+
n.Ft = {
|
|
3853
|
+
...n.Ft,
|
|
3823
3854
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
3824
3855
|
};
|
|
3825
3856
|
}
|
|
3826
3857
|
|
|
3827
3858
|
function hasContext(e, t) {
|
|
3828
|
-
return !isUndefined(t?.
|
|
3859
|
+
return !isUndefined(t?.Ft[e.id]);
|
|
3829
3860
|
}
|
|
3830
3861
|
|
|
3831
3862
|
function isUndefined(e) {
|
|
@@ -3849,14 +3880,14 @@ function isUndefined(e) {
|
|
|
3849
3880
|
const n = e.o?.m !== NOT_PENDING;
|
|
3850
3881
|
const i = n ? unwrapOverride(e.o?.m) : e.ot;
|
|
3851
3882
|
if (typeof t === "function") t = t(i);
|
|
3852
|
-
const r = !!(e.
|
|
3883
|
+
const r = !!(e.ct & STATUS_UNINITIALIZED) ||
|
|
3853
3884
|
// A dirty node's _value is stale (its queued recompute hasn't run — e.g.
|
|
3854
3885
|
// a latest() shadow marked by the previous landing's companion snap), so
|
|
3855
3886
|
// equality against it must not swallow the write. Without this, a sync
|
|
3856
3887
|
// push returning the shadow to that stale value was dropped, the snap
|
|
3857
3888
|
// recompute then committed the parent's old value, and the banner showed
|
|
3858
3889
|
// the previous transition's target (#3041 follow-up).
|
|
3859
|
-
!!((e.L ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.
|
|
3890
|
+
!!((e.L ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.Wt || !e.Wt(i, t);
|
|
3860
3891
|
if (!r) {
|
|
3861
3892
|
// Same-value write with an active override still entangles the current
|
|
3862
3893
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -3899,7 +3930,7 @@ function isUndefined(e) {
|
|
|
3899
3930
|
*/ function transitionBlocked(e) {
|
|
3900
3931
|
for (let t = 0; t < e.j.length; t++) {
|
|
3901
3932
|
const n = e.j[t];
|
|
3902
|
-
if (hasActiveOverride$1(n) && "
|
|
3933
|
+
if (hasActiveOverride$1(n) && "ct" in n && n.ct & STATUS_PENDING && n.o?.ze instanceof NotReadyError) {
|
|
3903
3934
|
return true;
|
|
3904
3935
|
}
|
|
3905
3936
|
}
|
|
@@ -3917,7 +3948,7 @@ function resolveOptimisticNodes(e) {
|
|
|
3917
3948
|
// Revert is a pure drop: there is no revert target to commit —
|
|
3918
3949
|
// override-covered authoritative values hold in _pendingValue and
|
|
3919
3950
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
3920
|
-
if (!(t.
|
|
3951
|
+
if (!(t.ct & STATUS_PENDING)) t.ct &= ~STATUS_UNINITIALIZED;
|
|
3921
3952
|
const i = t.o?.m;
|
|
3922
3953
|
ext(t).m = NOT_PENDING;
|
|
3923
3954
|
if (i !== NOT_PENDING && t.ot !== unwrapOverride(i)) insertSubs(t, true);
|
|
@@ -3987,7 +4018,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3987
4018
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
3988
4019
|
* is recorded for replay at commit.
|
|
3989
4020
|
*/ function gatedRead(e, t, n) {
|
|
3990
|
-
if (latestReadActive || e
|
|
4021
|
+
if (latestReadActive || e.$ === NOT_PENDING || e.it || t !== e && !(t.L & REACTIVE_MANUAL_WRITE)) {
|
|
3991
4022
|
return false;
|
|
3992
4023
|
}
|
|
3993
4024
|
activeTransition.ie.add(n);
|
|
@@ -3998,7 +4029,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3998
4029
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3999
4030
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
4000
4031
|
*/ function laneReadsCommitted(e, t, n) {
|
|
4001
|
-
if (e.o?.m !== undefined || !!e.o?.l || !!(t.
|
|
4032
|
+
if (e.o?.m !== undefined || !!e.o?.l || !!(t.ct & STATUS_PENDING)) {
|
|
4002
4033
|
// The committed view hides a staged in-flight value that will promote
|
|
4003
4034
|
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
4004
4035
|
// signals for replay at commit; async memos are excluded from it by the
|
|
@@ -4007,7 +4038,7 @@ function cleanupCompletedLanes(e) {
|
|
|
4007
4038
|
// committed value to a reader that never re-ran after the landing, so a
|
|
4008
4039
|
// pending-gated branch stayed one value behind permanently (#3041
|
|
4009
4040
|
// follow-up). Record the reader under the same replay contract.
|
|
4010
|
-
if (e
|
|
4041
|
+
if (e.$ !== NOT_PENDING) (activeTransition ?? globalQueue.V).ie.add(n);
|
|
4011
4042
|
return true;
|
|
4012
4043
|
}
|
|
4013
4044
|
if (t === e && stale && n.o?.i !== e) {
|
|
@@ -4022,7 +4053,7 @@ function cleanupCompletedLanes(e) {
|
|
|
4022
4053
|
// into the transaction (#3041 follow-up: a pending-gated branch that
|
|
4023
4054
|
// first read its async source during the landing flush stayed one value
|
|
4024
4055
|
// behind permanently); with none, into the ambient batch.
|
|
4025
|
-
if (e
|
|
4056
|
+
if (e.$ !== NOT_PENDING) (activeTransition ?? globalQueue.V).ie.add(n);
|
|
4026
4057
|
return true;
|
|
4027
4058
|
}
|
|
4028
4059
|
return false;
|
|
@@ -4103,8 +4134,8 @@ function trackOptimisticStore(e) {
|
|
|
4103
4134
|
GlobalQueue.We = gatedRead;
|
|
4104
4135
|
GlobalQueue.je = laneSuspends;
|
|
4105
4136
|
GlobalQueue.Me = laneReadsCommitted;
|
|
4106
|
-
GlobalQueue
|
|
4107
|
-
GlobalQueue
|
|
4137
|
+
GlobalQueue.Be = recomputeLane;
|
|
4138
|
+
GlobalQueue.$e = laneAsyncPending;
|
|
4108
4139
|
GlobalQueue.Ye = laneAsyncSettled;
|
|
4109
4140
|
GlobalQueue.Ze = trackOptimisticStore;
|
|
4110
4141
|
}
|
|
@@ -4140,7 +4171,7 @@ let pendingProbe = null;
|
|
|
4140
4171
|
* O(all-leaves-ever-read)-per-update pathology). Entries are permanent like
|
|
4141
4172
|
* the companions themselves; a store with no leaf-level isPending()/latest()
|
|
4142
4173
|
* reads never allocates the set or pays the walk. */ function markFirewallChildCompanions(e) {
|
|
4143
|
-
const t = e.
|
|
4174
|
+
const t = e._t;
|
|
4144
4175
|
if (!t) return;
|
|
4145
4176
|
t.D |= CONFIG_CHILD_COMPANIONS;
|
|
4146
4177
|
(ext(t).$t ??= new Set).add(e);
|
|
@@ -4165,7 +4196,7 @@ function getPendingSignal(e) {
|
|
|
4165
4196
|
function collectPendingSources(e) {
|
|
4166
4197
|
if (!pendingProbe) return;
|
|
4167
4198
|
pendingProbe.sources.add(e);
|
|
4168
|
-
const t = e.
|
|
4199
|
+
const t = e._t || e;
|
|
4169
4200
|
if (t !== e) pendingProbe.sources.add(t);
|
|
4170
4201
|
}
|
|
4171
4202
|
|
|
@@ -4195,10 +4226,10 @@ function collectPendingSources(e) {
|
|
|
4195
4226
|
// not flow through it — matching the rails' behavior, where propagation
|
|
4196
4227
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
4197
4228
|
// pending (the count check above), also matching.
|
|
4198
|
-
if (e.
|
|
4229
|
+
if (e.ct & STATUS_ERROR) return false;
|
|
4199
4230
|
if (t.has(e)) return false;
|
|
4200
4231
|
t.add(e);
|
|
4201
|
-
const n = e.
|
|
4232
|
+
const n = e._t;
|
|
4202
4233
|
if (n && markWalk(n, t)) return true;
|
|
4203
4234
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
4204
4235
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
@@ -4208,7 +4239,7 @@ function collectPendingSources(e) {
|
|
|
4208
4239
|
const r = i.L & REACTIVE_RECOMPUTING_DEPS ? i.le : undefined;
|
|
4209
4240
|
if (r !== null) {
|
|
4210
4241
|
for (let e = i.oe ?? null; e !== null; e = e.se) {
|
|
4211
|
-
if (!e.
|
|
4242
|
+
if (!e.Lt && markWalk(e.ue, t)) return true;
|
|
4212
4243
|
if (e === r) break;
|
|
4213
4244
|
}
|
|
4214
4245
|
}
|
|
@@ -4220,11 +4251,11 @@ function collectPendingSources(e) {
|
|
|
4220
4251
|
}
|
|
4221
4252
|
|
|
4222
4253
|
function quietPending(e) {
|
|
4223
|
-
if (e.o?.
|
|
4224
|
-
for (const t of e.o.
|
|
4254
|
+
if (e.o?.Tt) {
|
|
4255
|
+
for (const t of e.o.Tt) if (!t.o?.ut) return false;
|
|
4225
4256
|
return true;
|
|
4226
4257
|
}
|
|
4227
|
-
return e.o?.
|
|
4258
|
+
return e.o?.ut ?? false;
|
|
4228
4259
|
}
|
|
4229
4260
|
|
|
4230
4261
|
// NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
|
|
@@ -4235,7 +4266,7 @@ function quietPending(e) {
|
|
|
4235
4266
|
// verdict fully correlated with transition-class machinery and keeps server
|
|
4236
4267
|
// (always false) and client hydration trivially consistent.
|
|
4237
4268
|
function newQuestionInFlight(e) {
|
|
4238
|
-
return !!(e.
|
|
4269
|
+
return !!(e.ct & STATUS_PENDING) && !(e.ct & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
4239
4270
|
}
|
|
4240
4271
|
|
|
4241
4272
|
function computePendingState(e) {
|
|
@@ -4245,22 +4276,26 @@ function computePendingState(e) {
|
|
|
4245
4276
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
4246
4277
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
4247
4278
|
if (markCovered(e)) return true;
|
|
4248
|
-
const n = e.
|
|
4279
|
+
const n = e._t;
|
|
4249
4280
|
if (e.o?.i) {
|
|
4250
4281
|
const t = e.o?.i;
|
|
4251
|
-
const n = t.
|
|
4282
|
+
const n = t._t || t;
|
|
4252
4283
|
return newQuestionInFlight(n);
|
|
4253
4284
|
}
|
|
4254
|
-
if (n && e
|
|
4255
|
-
return !!(n.L & REACTIVE_MANUAL_WRITE) || !n.o?.
|
|
4285
|
+
if (n && e.$ !== NOT_PENDING && !hasActiveOverride$1(e)) {
|
|
4286
|
+
return !!(n.L & REACTIVE_MANUAL_WRITE) || !n.o?.bt && !(n.ct & STATUS_PENDING) || !!(n.ct & STATUS_PENDING) && quietPending(n);
|
|
4256
4287
|
}
|
|
4257
4288
|
// `!comp._loading`: a hold created while the loading window is still open is
|
|
4258
4289
|
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
4259
4290
|
// rest of the window (the UNINITIALIZED check suppresses exactly this frame
|
|
4260
4291
|
// for windowless first loads; born-committed nodes need their own gate, #2990).
|
|
4261
|
-
if (e
|
|
4262
|
-
if (hasActiveOverride$1(e)) return !e.
|
|
4263
|
-
|
|
4292
|
+
if (e.$ !== NOT_PENDING && !(t.ct & STATUS_UNINITIALIZED) && !t.lt) {
|
|
4293
|
+
if (hasActiveOverride$1(e)) return !e.Wt || !e.Wt(e.$, unwrapOverride(e.o?.m));
|
|
4294
|
+
// A quiet re-ask's held landing still answers the same question: the
|
|
4295
|
+
// classification survives the landing (asyncWrite) and dies with the
|
|
4296
|
+
// commit (commitPendingNode) — verdict-quiet through the reveal, like
|
|
4297
|
+
// the loading window above (#3178).
|
|
4298
|
+
if (!t.o?.ut) return true;
|
|
4264
4299
|
}
|
|
4265
4300
|
return newQuestionInFlight(t);
|
|
4266
4301
|
}
|
|
@@ -4298,8 +4333,8 @@ function updateChildCompanions(e) {
|
|
|
4298
4333
|
if (i.has(e)) return;
|
|
4299
4334
|
i.add(e);
|
|
4300
4335
|
if (e.o?.I || e.o?.R) n(e);
|
|
4301
|
-
for (let t = e
|
|
4302
|
-
for (let t = e.o?.
|
|
4336
|
+
for (let t = e.B; t !== null; t = t.fe) visit(t.ce);
|
|
4337
|
+
for (let t = e.o?.vt ?? null; t !== null; t = t.yt) {
|
|
4303
4338
|
visit(t);
|
|
4304
4339
|
}
|
|
4305
4340
|
};
|
|
@@ -4345,16 +4380,16 @@ function snapCompanionsToState(e) {
|
|
|
4345
4380
|
const t = e.o?.I;
|
|
4346
4381
|
if (t && (t.o?.m === undefined || t.o?.m === NOT_PENDING)) {
|
|
4347
4382
|
const n = computePendingState(e);
|
|
4348
|
-
if (t.ot !== n || t
|
|
4383
|
+
if (t.ot !== n || t.$ !== NOT_PENDING) {
|
|
4349
4384
|
t.ot = n;
|
|
4350
|
-
t
|
|
4385
|
+
t.$ = NOT_PENDING;
|
|
4351
4386
|
insertSubs(t);
|
|
4352
4387
|
schedule();
|
|
4353
4388
|
}
|
|
4354
4389
|
}
|
|
4355
4390
|
const n = e.o?.R;
|
|
4356
4391
|
if (n && !(n.L & REACTIVE_DISPOSED)) {
|
|
4357
|
-
if ((n.o?.m === undefined || n.o?.m === NOT_PENDING) && n
|
|
4392
|
+
if ((n.o?.m === undefined || n.o?.m === NOT_PENDING) && n.$ === NOT_PENDING && !Object.is(n.ot, e.ot) && !(n.L & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
4358
4393
|
n.L |= REACTIVE_DIRTY;
|
|
4359
4394
|
insertIntoHeap(n, queueFor(n));
|
|
4360
4395
|
insertSubs(n);
|
|
@@ -4391,7 +4426,7 @@ function getLatestValueComputed(e) {
|
|
|
4391
4426
|
// created lazily, possibly after the write was processed — syncCompanions
|
|
4392
4427
|
// only pushes into companions that already exist, so the first latest()
|
|
4393
4428
|
// read inside a held transition showed the committed value (#3041).
|
|
4394
|
-
if (e
|
|
4429
|
+
if (e.$ !== NOT_PENDING && !hasActiveOverride$1(e)) setSignal(t, e.$);
|
|
4395
4430
|
setContextInternal(r);
|
|
4396
4431
|
setPendingCheckActive(i);
|
|
4397
4432
|
setLatestReadActive(n);
|
|
@@ -4412,7 +4447,7 @@ function getLatestValueComputed(e) {
|
|
|
4412
4447
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
4413
4448
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
4414
4449
|
const e = queueFor(t);
|
|
4415
|
-
if (t.
|
|
4450
|
+
if (t.Nt >= e.H && !(t.L & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
4416
4451
|
markHeap(e);
|
|
4417
4452
|
// Suspend probe collection during the pull (mirrors pendingCheckRead's
|
|
4418
4453
|
// prepare): a probe through latest() answers for the SHADOW — the
|
|
@@ -4433,12 +4468,12 @@ function getLatestValueComputed(e) {
|
|
|
4433
4468
|
}
|
|
4434
4469
|
r = read(t);
|
|
4435
4470
|
} catch (t) {
|
|
4436
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
4471
|
+
if (t instanceof NotReadyError && (!context || !(e.ct & STATUS_UNINITIALIZED))) return i;
|
|
4437
4472
|
throw t;
|
|
4438
4473
|
} finally {
|
|
4439
4474
|
setLatestReadActive(n);
|
|
4440
4475
|
}
|
|
4441
|
-
if (t.
|
|
4476
|
+
if (t.ct & STATUS_PENDING) return i;
|
|
4442
4477
|
if (stale && currentOptimisticLane && t.o?.l) {
|
|
4443
4478
|
const e = findLane(t.o?.l);
|
|
4444
4479
|
const n = findLane(currentOptimisticLane);
|
|
@@ -4450,7 +4485,7 @@ function getLatestValueComputed(e) {
|
|
|
4450
4485
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
4451
4486
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
4452
4487
|
// other transition's committed view, matching read()'s own selection.
|
|
4453
|
-
if (t
|
|
4488
|
+
if (t.$ !== NOT_PENDING && !hasActiveOverride$1(t) && !(stale && t.O && activeTransition !== t.O)) return t.$;
|
|
4454
4489
|
return r;
|
|
4455
4490
|
}
|
|
4456
4491
|
|
|
@@ -4466,14 +4501,14 @@ function getLatestValueComputed(e) {
|
|
|
4466
4501
|
if (typeof e.it !== "function") return false;
|
|
4467
4502
|
const t = e.o?.i;
|
|
4468
4503
|
if (t === undefined) return false;
|
|
4469
|
-
const n = t.
|
|
4470
|
-
return !(n.
|
|
4504
|
+
const n = t._t || t;
|
|
4505
|
+
return !(n.ct & STATUS_UNINITIALIZED);
|
|
4471
4506
|
}
|
|
4472
4507
|
|
|
4473
4508
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
4474
4509
|
setPendingCheckActive(false);
|
|
4475
4510
|
if (typeof e.it === "function") prepareComputed(e, true);
|
|
4476
|
-
const r = n.
|
|
4511
|
+
const r = n.ct;
|
|
4477
4512
|
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED &&
|
|
4478
4513
|
// The suspend-throw is for a genuinely-first-load source: the tracked
|
|
4479
4514
|
// reader has nothing to pair a verdict with, so it parks on the source.
|
|
@@ -4520,24 +4555,24 @@ function getLatestValueComputed(e) {
|
|
|
4520
4555
|
// writes whose source async is still computing.
|
|
4521
4556
|
if (!t) return false;
|
|
4522
4557
|
for (const [e, t] of n.J) {
|
|
4523
|
-
if (t.size && e.
|
|
4558
|
+
if (t.size && e.ct & STATUS_PENDING && e.o?.ze?.source === e) return true;
|
|
4524
4559
|
}
|
|
4525
4560
|
return false;
|
|
4526
4561
|
}
|
|
4527
4562
|
|
|
4528
4563
|
function recordFreshRead(e, t) {
|
|
4529
|
-
if (pendingProbe !== null && e
|
|
4564
|
+
if (pendingProbe !== null && e.$ !== NOT_PENDING && t === e.$) {
|
|
4530
4565
|
if (heldAwaitingAsync(e)) return;
|
|
4531
4566
|
pendingProbe.freshReads.add(e);
|
|
4532
4567
|
}
|
|
4533
4568
|
}
|
|
4534
4569
|
|
|
4535
4570
|
function applyReask(e, t) {
|
|
4536
|
-
const n = !!(e.
|
|
4537
|
-
const i = t && !(n && !e.o?.
|
|
4538
|
-
const r = n && (e.o?.
|
|
4571
|
+
const n = !!(e.ct & STATUS_PENDING);
|
|
4572
|
+
const i = t && !(n && !e.o?.ut);
|
|
4573
|
+
const r = n && (e.o?.ut ?? false) !== i;
|
|
4539
4574
|
// Allocation-free for the quiet case: false is the extension default.
|
|
4540
|
-
if (i) ext(e).
|
|
4575
|
+
if (i) ext(e).ut = true; else if (e.o !== null) e.o.ut = false;
|
|
4541
4576
|
return r;
|
|
4542
4577
|
}
|
|
4543
4578
|
|
|
@@ -4604,7 +4639,7 @@ function isPending(e) {
|
|
|
4604
4639
|
} catch (e) {
|
|
4605
4640
|
collectPending();
|
|
4606
4641
|
if (e instanceof NotReadyError) {
|
|
4607
|
-
const t = !!(e.source?.
|
|
4642
|
+
const t = !!(e.source?.ct & STATUS_UNINITIALIZED);
|
|
4608
4643
|
if (i.found && !t) return true;
|
|
4609
4644
|
if (context && t) throw e;
|
|
4610
4645
|
}
|
|
@@ -4648,15 +4683,15 @@ GlobalQueue.xe = wakeSuppressedProbes;
|
|
|
4648
4683
|
const r = !!i?.user;
|
|
4649
4684
|
const o = createEffectNode(e, t, n, r ? EFFECT_USER : EFFECT_RENDER, i);
|
|
4650
4685
|
recompute(o, true);
|
|
4651
|
-
!i?.defer && (o.ae === EFFECT_USER || i?.schedule ? o.
|
|
4686
|
+
!i?.defer && (o.ae === EFFECT_USER || i?.schedule ? o.At.enqueue(o.ae, runEffect.bind(null, o)) : runEffect(o));
|
|
4652
4687
|
}
|
|
4653
4688
|
|
|
4654
4689
|
function notifyEffectStatus(e, t) {
|
|
4655
4690
|
// Use passed values if provided, otherwise read from node
|
|
4656
|
-
const n = e !== undefined ? e : this.
|
|
4691
|
+
const n = e !== undefined ? e : this.ct;
|
|
4657
4692
|
const i = t !== undefined ? t : this.o?.ze;
|
|
4658
4693
|
if (n & STATUS_ERROR) {
|
|
4659
|
-
this.
|
|
4694
|
+
this.At.notify(this, STATUS_PENDING, 0);
|
|
4660
4695
|
if (this.ae === EFFECT_USER) {
|
|
4661
4696
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
4662
4697
|
// queue it like the effect function. It runs in the same imperative,
|
|
@@ -4667,18 +4702,18 @@ function notifyEffectStatus(e, t) {
|
|
|
4667
4702
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
4668
4703
|
// `status` arg without node-state writes) don't queue: the status
|
|
4669
4704
|
// re-propagates unblocked at commit.
|
|
4670
|
-
if (this.
|
|
4705
|
+
if (this.ct & STATUS_ERROR) {
|
|
4671
4706
|
this.st = true;
|
|
4672
|
-
this.
|
|
4707
|
+
this.At.enqueue(this.ae, this.Mt ??= runEffect.bind(null, this));
|
|
4673
4708
|
}
|
|
4674
4709
|
return;
|
|
4675
4710
|
}
|
|
4676
|
-
if (!this.
|
|
4711
|
+
if (!this.At.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
4677
4712
|
haltReactivity(unwrapStatusError(i));
|
|
4678
4713
|
throw i;
|
|
4679
4714
|
}
|
|
4680
4715
|
} else if (this.ae === EFFECT_RENDER) {
|
|
4681
|
-
this.
|
|
4716
|
+
this.At.notify(this, STATUS_PENDING | STATUS_ERROR, n, i);
|
|
4682
4717
|
}
|
|
4683
4718
|
}
|
|
4684
4719
|
|
|
@@ -4694,41 +4729,41 @@ function runEffect(e) {
|
|
|
4694
4729
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
4695
4730
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
4696
4731
|
// same flush must not be hijacked by a later-arriving error status.
|
|
4697
|
-
if (e.
|
|
4732
|
+
if (e.ct & STATUS_ERROR && e.ae === EFFECT_USER) {
|
|
4698
4733
|
const t = unwrapStatusError(e.o?.ze);
|
|
4699
|
-
e.
|
|
4734
|
+
e.Yt = e.ot;
|
|
4700
4735
|
e.st = false;
|
|
4701
4736
|
try {
|
|
4702
|
-
e.
|
|
4703
|
-
const t = e.
|
|
4704
|
-
e.
|
|
4737
|
+
e.zt ? e.zt(t, () => {
|
|
4738
|
+
const t = e.kt;
|
|
4739
|
+
e.kt = undefined;
|
|
4705
4740
|
t?.();
|
|
4706
4741
|
}) : console.error(t);
|
|
4707
4742
|
} catch (t) {
|
|
4708
|
-
if (!e.
|
|
4743
|
+
if (!e.At.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
4709
4744
|
haltReactivity(t);
|
|
4710
4745
|
throw t;
|
|
4711
4746
|
}
|
|
4712
4747
|
}
|
|
4713
4748
|
return;
|
|
4714
4749
|
}
|
|
4715
|
-
const t = e.
|
|
4716
|
-
e.
|
|
4750
|
+
const t = e.kt;
|
|
4751
|
+
e.kt = undefined;
|
|
4717
4752
|
try {
|
|
4718
4753
|
t?.();
|
|
4719
|
-
const n = e.
|
|
4754
|
+
const n = e.Zt(e.ot, e.Yt);
|
|
4720
4755
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
4721
4756
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
4722
|
-
e.
|
|
4757
|
+
e.kt = n;
|
|
4723
4758
|
} catch (t) {
|
|
4724
4759
|
ext(e).ze = new StatusError(e, t);
|
|
4725
|
-
e.
|
|
4726
|
-
if (!e.
|
|
4760
|
+
e.ct |= STATUS_ERROR;
|
|
4761
|
+
if (!e.At.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
4727
4762
|
haltReactivity(t);
|
|
4728
4763
|
throw t;
|
|
4729
4764
|
}
|
|
4730
4765
|
} finally {
|
|
4731
|
-
e.
|
|
4766
|
+
e.Yt = e.ot;
|
|
4732
4767
|
e.st = false;
|
|
4733
4768
|
}
|
|
4734
4769
|
}
|
|
@@ -4748,24 +4783,24 @@ GlobalQueue._e = runEffect;
|
|
|
4748
4783
|
} finally {}
|
|
4749
4784
|
};
|
|
4750
4785
|
const n = computed(() => {
|
|
4751
|
-
const t = n.
|
|
4752
|
-
n.
|
|
4786
|
+
const t = n.kt;
|
|
4787
|
+
n.kt = undefined;
|
|
4753
4788
|
t?.();
|
|
4754
4789
|
const i = staleValues(e);
|
|
4755
|
-
n.
|
|
4790
|
+
n.kt = i;
|
|
4756
4791
|
}, {
|
|
4757
4792
|
...t,
|
|
4758
4793
|
lazy: true
|
|
4759
4794
|
});
|
|
4760
|
-
n.
|
|
4795
|
+
n.kt = undefined;
|
|
4761
4796
|
n.D = n.D & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
4762
4797
|
n.st = true;
|
|
4763
4798
|
n.ae = EFFECT_TRACKED;
|
|
4764
4799
|
// Status dispatch rides the SHARED notifier (statusNotifierOf keys off
|
|
4765
4800
|
// _type): its error arm is behavior-identical to the closure that used to
|
|
4766
4801
|
// live here, without the per-node NodeExtension allocation.
|
|
4767
|
-
n.
|
|
4768
|
-
n.
|
|
4802
|
+
n.Ot = run;
|
|
4803
|
+
n.At.enqueue(EFFECT_USER, run);
|
|
4769
4804
|
}
|
|
4770
4805
|
|
|
4771
4806
|
// Install the shared effect status notifier (statusNotifierOf serves it to
|
|
@@ -4967,7 +5002,74 @@ function createMemo(e, t) {
|
|
|
4967
5002
|
return accessor(computed(e, t));
|
|
4968
5003
|
}
|
|
4969
5004
|
|
|
4970
|
-
|
|
5005
|
+
/**
|
|
5006
|
+
* Creates a reactive effect with **separate compute and effect phases**.
|
|
5007
|
+
*
|
|
5008
|
+
* - `compute(prev)` runs reactively — *put all reactive reads here*. The
|
|
5009
|
+
* returned value is passed to `effect` and is also the new "previous" value
|
|
5010
|
+
* for the next run.
|
|
5011
|
+
* - `effect(next, prev?)` runs imperatively (untracked) after the queue
|
|
5012
|
+
* flushes. *Put DOM writes / fetch / logging / subscriptions here.* It may
|
|
5013
|
+
* return a cleanup function which runs before the next effect or on
|
|
5014
|
+
* disposal.
|
|
5015
|
+
*
|
|
5016
|
+
* Reactive reads inside `effect` will *not* re-trigger this effect — that's
|
|
5017
|
+
* intentional. If you need a single-phase tracked effect, use
|
|
5018
|
+
* `createTrackedEffect` (with the tradeoffs noted there).
|
|
5019
|
+
*
|
|
5020
|
+
* Pass an `EffectBundle` (`{ effect, error }`) instead of a plain function to
|
|
5021
|
+
* intercept **compute-phase** errors — errors thrown by `compute` or arriving
|
|
5022
|
+
* from upstream reactive sources (including async rejections), which your own
|
|
5023
|
+
* code has no frame to `try/catch`. The `error` handler is the error arm of
|
|
5024
|
+
* the effect phase: it runs on the same schedule and in the same imperative,
|
|
5025
|
+
* writable scope as `effect` (setting error state via signals is fine), and
|
|
5026
|
+
* only for *settled* errors — a transient error that recovers before the
|
|
5027
|
+
* effect phase runs `effect` with the recovered value instead, and a held
|
|
5028
|
+
* transition defers it exactly as it defers `effect`. Without an `error`
|
|
5029
|
+
* handler a compute-phase error is logged and the effect simply skips that
|
|
5030
|
+
* run — a non-render effect's reactivity failing does not crash the app.
|
|
5031
|
+
* Rethrowing from `error` escalates it to the nearest error boundary
|
|
5032
|
+
* (halting the system if none exists).
|
|
5033
|
+
*
|
|
5034
|
+
* The **effect phase is different**: it is your own imperative code, so handle
|
|
5035
|
+
* failures with `try/catch` where they occur. An uncaught effect-phase throw
|
|
5036
|
+
* is treated as an unhandled application error — caught by the nearest
|
|
5037
|
+
* `createErrorBoundary`/`<Errored>`, and permanently halting the reactive
|
|
5038
|
+
* system if there is none. It is *not* routed to the bundle's `error` handler.
|
|
5039
|
+
*
|
|
5040
|
+
* ```typescript
|
|
5041
|
+
* createEffect<T>(compute, effectFn | { effect, error }, options?: EffectOptions);
|
|
5042
|
+
* ```
|
|
5043
|
+
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
5044
|
+
* @param effectFn a function that receives the new value and is used to perform side effects (return a cleanup function), or an `EffectBundle` with `effect` and `error` handlers
|
|
5045
|
+
* @param options `EffectOptions` -- name, defer, schedule, transparent
|
|
5046
|
+
*
|
|
5047
|
+
* @example
|
|
5048
|
+
* ```ts
|
|
5049
|
+
* const [count, setCount] = createSignal(0);
|
|
5050
|
+
*
|
|
5051
|
+
* createEffect(
|
|
5052
|
+
* () => count(), // compute: tracks `count`
|
|
5053
|
+
* value => console.log(value) // effect: side effect
|
|
5054
|
+
* );
|
|
5055
|
+
*
|
|
5056
|
+
* setCount(1); // logs 1 after the next flush
|
|
5057
|
+
* ```
|
|
5058
|
+
*
|
|
5059
|
+
* @example
|
|
5060
|
+
* ```ts
|
|
5061
|
+
* createEffect(
|
|
5062
|
+
* () => userId(),
|
|
5063
|
+
* id => {
|
|
5064
|
+
* const ctrl = new AbortController();
|
|
5065
|
+
* fetch(`/users/${id}`, { signal: ctrl.signal });
|
|
5066
|
+
* return () => ctrl.abort(); // cleanup before next run / disposal
|
|
5067
|
+
* }
|
|
5068
|
+
* );
|
|
5069
|
+
* ```
|
|
5070
|
+
*
|
|
5071
|
+
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
|
|
5072
|
+
*/ function createEffect(e, t, n) {
|
|
4971
5073
|
effect(e, t.effect || t, t.error, {
|
|
4972
5074
|
user: true,
|
|
4973
5075
|
...n
|
|
@@ -5142,9 +5244,9 @@ function createEffect(e, t, n) {
|
|
|
5142
5244
|
// route through the inherited queue.
|
|
5143
5245
|
const r = getOwner();
|
|
5144
5246
|
const o = new MicrotaskQueue;
|
|
5145
|
-
o.pe = r.
|
|
5247
|
+
o.pe = r.At;
|
|
5146
5248
|
// notify() forwards up the normal chain
|
|
5147
|
-
r.
|
|
5249
|
+
r.At = o;
|
|
5148
5250
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
5149
5251
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
5150
5252
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -5164,7 +5266,7 @@ function createEffect(e, t, n) {
|
|
|
5164
5266
|
// stale mainline value and resolves with old data.
|
|
5165
5267
|
{
|
|
5166
5268
|
user: true,
|
|
5167
|
-
|
|
5269
|
+
Kt: CONFIG_DIRECT_COMMIT
|
|
5168
5270
|
});
|
|
5169
5271
|
});
|
|
5170
5272
|
});
|
|
@@ -5250,8 +5352,8 @@ function createEffect(e, t, n) {
|
|
|
5250
5352
|
if (r === null) {
|
|
5251
5353
|
r = getOwner();
|
|
5252
5354
|
const e = new MicrotaskQueue;
|
|
5253
|
-
e.pe = r.
|
|
5254
|
-
r.
|
|
5355
|
+
e.pe = r.At;
|
|
5356
|
+
r.At = e;
|
|
5255
5357
|
}
|
|
5256
5358
|
return read(t);
|
|
5257
5359
|
}, t => {
|
|
@@ -5262,7 +5364,7 @@ function createEffect(e, t, n) {
|
|
|
5262
5364
|
dispose(r);
|
|
5263
5365
|
}, {
|
|
5264
5366
|
user: true,
|
|
5265
|
-
|
|
5367
|
+
Kt: CONFIG_DIRECT_COMMIT | CONFIG_AUTHORITATIVE_READ | CONFIG_FRESH_READ
|
|
5266
5368
|
});
|
|
5267
5369
|
make();
|
|
5268
5370
|
});
|
|
@@ -5347,8 +5449,8 @@ function createEffect(e, t, n) {
|
|
|
5347
5449
|
// entire point of the hold.
|
|
5348
5450
|
const u = getOwner();
|
|
5349
5451
|
const l = new MicrotaskQueue;
|
|
5350
|
-
l.pe = u.
|
|
5351
|
-
u.
|
|
5452
|
+
l.pe = u.At;
|
|
5453
|
+
u.At = l;
|
|
5352
5454
|
let f;
|
|
5353
5455
|
let c;
|
|
5354
5456
|
const settle = e => {
|
|
@@ -5377,7 +5479,7 @@ function createEffect(e, t, n) {
|
|
|
5377
5479
|
// the hold itself is keeping uncommitted.
|
|
5378
5480
|
{
|
|
5379
5481
|
user: true,
|
|
5380
|
-
|
|
5482
|
+
Kt: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
|
|
5381
5483
|
});
|
|
5382
5484
|
if (t?.timeout !== undefined) f = setTimeout(() => settle(() => r(new TimeoutError)), t.timeout);
|
|
5383
5485
|
if (o !== undefined) {
|
|
@@ -5871,7 +5973,7 @@ r) {
|
|
|
5871
5973
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5872
5974
|
* no visual change.
|
|
5873
5975
|
*/ function notifyMarkBoundaries(e) {
|
|
5874
|
-
if (!e
|
|
5976
|
+
if (!e.B && !e.o?.vt) return;
|
|
5875
5977
|
const t = new NotReadyError(e);
|
|
5876
5978
|
t.Xe = true;
|
|
5877
5979
|
const n = new Set;
|
|
@@ -6529,7 +6631,7 @@ function drainFolds() {
|
|
|
6529
6631
|
!plainProto(t.ovl ? t.v : r) ? Reflect.ownKeys(o) : e;
|
|
6530
6632
|
for (const e of n) {
|
|
6531
6633
|
const t = o[e];
|
|
6532
|
-
if (t !== undefined && t
|
|
6634
|
+
if (t !== undefined && t.$ !== NOT_PENDING) {
|
|
6533
6635
|
i = true;
|
|
6534
6636
|
break;
|
|
6535
6637
|
}
|
|
@@ -6962,7 +7064,7 @@ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
|
6962
7064
|
* / onSettled callbacks) get COMMITTED visibility (#3006), same as core. */ function inOwnerContext() {
|
|
6963
7065
|
const e = getOwner();
|
|
6964
7066
|
if (e === null) return false;
|
|
6965
|
-
const t = e.
|
|
7067
|
+
const t = e.It ? e.Rt : e;
|
|
6966
7068
|
return t != null && !(t.D & CONFIG_CHILDREN_FORBIDDEN);
|
|
6967
7069
|
}
|
|
6968
7070
|
|
|
@@ -6973,7 +7075,7 @@ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
|
6973
7075
|
* committed to them regardless of staged writes. */ function inForbiddenScope() {
|
|
6974
7076
|
const e = getOwner();
|
|
6975
7077
|
if (e === null) return false;
|
|
6976
|
-
const t = e.
|
|
7078
|
+
const t = e.It ? e.Rt : e;
|
|
6977
7079
|
return t != null && !!(t.D & CONFIG_CHILDREN_FORBIDDEN);
|
|
6978
7080
|
}
|
|
6979
7081
|
|
|
@@ -6984,7 +7086,7 @@ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
|
6984
7086
|
if (t === null) return false;
|
|
6985
7087
|
for (const e of Reflect.ownKeys(t)) {
|
|
6986
7088
|
const n = t[e];
|
|
6987
|
-
if (n
|
|
7089
|
+
if (n.$ !== NOT_PENDING && n.O != null && n.O.P !== true) return true;
|
|
6988
7090
|
}
|
|
6989
7091
|
return false;
|
|
6990
7092
|
}
|
|
@@ -6998,28 +7100,39 @@ function readSource(e) {
|
|
|
6998
7100
|
const t = heldMaskView(e);
|
|
6999
7101
|
if (t !== null) return t;
|
|
7000
7102
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7103
|
+
return pendingBackingVisible(e, false) ? e.pb : e.v;
|
|
7104
|
+
}
|
|
7105
|
+
|
|
7106
|
+
/** The single pb-vs-committed visibility decision (#3147), shared by per-key
|
|
7107
|
+
* backing reads (readSource) and deep()/snapshot composition (snapshotWalk)
|
|
7108
|
+
* so the two reader families can never disagree about a HELD landing.
|
|
7109
|
+
*
|
|
7110
|
+
* Signal-parity visibility (core read(): owner-context reads serve
|
|
7111
|
+
* _pendingValue, context-free reads serve committed — effects recompute
|
|
7112
|
+
* BEFORE commitPendingNodes in the flush, so the pending view must be
|
|
7113
|
+
* servable). Drafts (setter window OR projection write-override) and
|
|
7114
|
+
* owner-context reads see the pending backing; context-free reads see
|
|
7115
|
+
* committed. Node reads apply the same rule, so all homes agree.
|
|
7116
|
+
*
|
|
7117
|
+
* `speculative` is deep()/snapshot's posture: an untrack/deep PEEK that sees
|
|
7118
|
+
* ordinary pending staging regardless of owner context (the documented
|
|
7119
|
+
* divergence from context-free per-key reads) — but never through a hold:
|
|
7120
|
+
* held truth stays masked exactly as it is for per-key readers. */ function pendingBackingVisible(e, t) {
|
|
7121
|
+
return e.pb !== null && (inDraft(e) || getWriteOverride() ||
|
|
7122
|
+
// Owner-context (and speculative-peek) readers see the pending
|
|
7123
|
+
// backing — EXCEPT held truth on an optimistic family (#3164 fold):
|
|
7124
|
+
// a live pb on an opt family outside the draft/write-override windows
|
|
7125
|
+
// is a staged landing (tentative drafts never outlive their setter),
|
|
7126
|
+
// and only the authoritative postures and latest() see it (the
|
|
7127
|
+
// backing-level twin of core read()'s A17-for-held-truth arm;
|
|
7128
|
+
// ordinary readers keep committed until the transaction's reveal).
|
|
7129
|
+
(t || inOwnerContext()) && !heldTruthMasked(e) ||
|
|
7016
7130
|
// A projection's pending backing is authoritative-elect: serve it to
|
|
7017
7131
|
// context-free readers too UNLESS a transition is holding the node
|
|
7018
7132
|
// commits (downstream async hold — stale committed is the contract)
|
|
7019
7133
|
// or the reader is a CHILDREN_FORBIDDEN scope, which never observes
|
|
7020
7134
|
// its own unsettled write (#3082, signal parity per #3006).
|
|
7021
|
-
e.fam !== null && !heldTruthMasked(e) && !foldHeld(e) && !inForbiddenScope())
|
|
7022
|
-
return e.v;
|
|
7135
|
+
e.fam !== null && !heldTruthMasked(e) && !foldHeld(e) && !inForbiddenScope());
|
|
7023
7136
|
}
|
|
7024
7137
|
|
|
7025
7138
|
/** #3164 fold: HELD truth on an optimistic family — a pending backing
|
|
@@ -7099,14 +7212,14 @@ function isOwnAccessor(e, t) {
|
|
|
7099
7212
|
// Authoritative-view reads (until()'s predicate) skip the override arm
|
|
7100
7213
|
// only: staged pending values are authoritative, overrides are the
|
|
7101
7214
|
// caller's optimism.
|
|
7102
|
-
const n = !authoritativeServe() && hasActiveOverride(e) ? unwrapOverride(e.o?.m) : e
|
|
7215
|
+
const n = !authoritativeServe() && hasActiveOverride(e) ? unwrapOverride(e.o?.m) : e.$ !== NOT_PENDING && (latestReadActive ||
|
|
7103
7216
|
// Owner-context pending visibility — except HELD truth (#3164,
|
|
7104
7217
|
// see CONFIG_HELD_TRUTH: fold-staged or entangle-stolen
|
|
7105
7218
|
// confirming truth), which only authoritative/latest readers
|
|
7106
7219
|
// see (core read()'s A17-for-held-truth twin; ordinary readers
|
|
7107
7220
|
// keep committed until the transaction's reveal — latest() is
|
|
7108
7221
|
// exempted by the leading arm above).
|
|
7109
|
-
(inOwnerContext() || authoritativeServe()) && !(e.D & CONFIG_HELD_TRUTH && !authoritativeServe())) ? e
|
|
7222
|
+
(inOwnerContext() || authoritativeServe()) && !(e.D & CONFIG_HELD_TRUTH && !authoritativeServe())) ? e.$ : t;
|
|
7110
7223
|
return n === FORCE ? t : n;
|
|
7111
7224
|
}
|
|
7112
7225
|
|
|
@@ -7197,7 +7310,7 @@ function isOwnAccessor(e, t) {
|
|
|
7197
7310
|
// proj R23); the derive is the author.
|
|
7198
7311
|
if (projectionWriteActive || getWriteOverride()) return;
|
|
7199
7312
|
const t = e.fam?.node;
|
|
7200
|
-
if (t != null && t.
|
|
7313
|
+
if (t != null && t.ct & (STATUS_UNINITIALIZED | STATUS_ERROR)) read(t);
|
|
7201
7314
|
}
|
|
7202
7315
|
|
|
7203
7316
|
/** latest() pull (#3075): bring the projection computed up to date so the
|
|
@@ -7696,12 +7809,17 @@ function snapshotWalk(e, t, n) {
|
|
|
7696
7809
|
if (e === undefined) break;
|
|
7697
7810
|
if (e.fam !== null) n = e.fam;
|
|
7698
7811
|
if (e.fam?.opt === true) (r ??= []).push(e);
|
|
7812
|
+
// The shared visibility decision (#3147): the speculative peek serves
|
|
7813
|
+
// pending staging, but a HELD landing is masked to committed exactly as
|
|
7814
|
+
// it is for per-key readers — the two families must answer alike while
|
|
7815
|
+
// a transaction holds store landings.
|
|
7816
|
+
const t = pendingBackingVisible(e, true);
|
|
7699
7817
|
// Snapshot runs mid-flush (tracked memos execute before commit), so a
|
|
7700
7818
|
// pending prototype overlay must present as a REAL merged container.
|
|
7701
|
-
if (e.ovl) materializePB(e);
|
|
7702
|
-
const
|
|
7703
|
-
if (
|
|
7704
|
-
i =
|
|
7819
|
+
if (t && e.ovl) materializePB(e);
|
|
7820
|
+
const o = t ? e.pb : e.v;
|
|
7821
|
+
if (o === i) break;
|
|
7822
|
+
i = o;
|
|
7705
7823
|
}
|
|
7706
7824
|
if (!isWrappable(i)) return i;
|
|
7707
7825
|
// Optimistic families: compose the visible view; a composed view is a fresh
|
|
@@ -8469,8 +8587,8 @@ function runProjectionComputedNext(e, t, n, i, r) {
|
|
|
8469
8587
|
// for the whole first flight — the derive works a detached shadow of the
|
|
8470
8588
|
// seed so draft writes cannot tear through to readers (#2988). Every commit
|
|
8471
8589
|
// point reconciles the shadow through the normal commit path.
|
|
8472
|
-
const l = o.
|
|
8473
|
-
const f = wrapDraft(e, () => !s || o.o?.
|
|
8590
|
+
const l = o.lt ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
|
|
8591
|
+
const f = wrapDraft(e, () => !s || o.o?.bt === u, r);
|
|
8474
8592
|
storeSetterNext(f, r => {
|
|
8475
8593
|
u = t(l ?? r);
|
|
8476
8594
|
s = true;
|
|
@@ -8484,7 +8602,7 @@ function runProjectionComputedNext(e, t, n, i, r) {
|
|
|
8484
8602
|
i ? i(write, t) : write();
|
|
8485
8603
|
};
|
|
8486
8604
|
const f = handleAsync(o, u, commit);
|
|
8487
|
-
if (!o.
|
|
8605
|
+
if (!o.lt) commit(f);
|
|
8488
8606
|
}, false);
|
|
8489
8607
|
return o;
|
|
8490
8608
|
}
|
|
@@ -8577,8 +8695,8 @@ const UNSET = Symbol();
|
|
|
8577
8695
|
i ??= n;
|
|
8578
8696
|
const r = new StatusError(i, e);
|
|
8579
8697
|
ext(i).ze = r;
|
|
8580
|
-
i.
|
|
8581
|
-
t = n.
|
|
8698
|
+
i.ct = (i.ct ?? 0) | STATUS_ERROR;
|
|
8699
|
+
t = n.At.notify(i, STATUS_ERROR, STATUS_ERROR, r);
|
|
8582
8700
|
}
|
|
8583
8701
|
if (!t && r === UNSET) r = e;
|
|
8584
8702
|
}
|
|
@@ -9164,14 +9282,22 @@ function installNextBlockedHalf() {
|
|
|
9164
9282
|
const e = GlobalQueue.Ue;
|
|
9165
9283
|
GlobalQueue.Ue = t => {
|
|
9166
9284
|
for (const e of t.q) {
|
|
9167
|
-
const
|
|
9168
|
-
const
|
|
9285
|
+
const n = e?.[$TARGET];
|
|
9286
|
+
const i = n?.fam;
|
|
9287
|
+
const r = i?.node;
|
|
9169
9288
|
// The hold exists to keep optimistic state alive until the store's own
|
|
9170
9289
|
// truth lands (#2951). Once the family carries NO live overrides (a
|
|
9171
9290
|
// landing consumed them, or they never existed), a pending firewall is
|
|
9172
9291
|
// no reason to park the transaction — blocking then leaks it forever
|
|
9173
9292
|
// when the in-flight question is never answered (undisposed fixtures).
|
|
9174
|
-
if (
|
|
9293
|
+
if (r == null || !(r.ct & STATUS_PENDING)) continue;
|
|
9294
|
+
// Ownership is declared (#3146): only the flight's OWN transaction
|
|
9295
|
+
// parks on the flight (the #2951 anchor routed the bare write there).
|
|
9296
|
+
// A transaction that merely brushed the store never waits for truth
|
|
9297
|
+
// it does not carry.
|
|
9298
|
+
const o = i.ft != null ? liveTransition(i.ft) : null;
|
|
9299
|
+
if (o !== null && o !== currentTransition(t)) continue;
|
|
9300
|
+
if (familyHasLiveOverrides(i)) return true;
|
|
9175
9301
|
}
|
|
9176
9302
|
return e(t);
|
|
9177
9303
|
};
|
|
@@ -9221,14 +9347,35 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
9221
9347
|
}
|
|
9222
9348
|
if (i) {
|
|
9223
9349
|
const t = e;
|
|
9350
|
+
// #3146: an async settle event belongs to the flight's OWN transaction.
|
|
9351
|
+
// A live declared one re-enters (a merge if the generic settle path
|
|
9352
|
+
// already entered a graph-stamped stranger — the landing supersedes any
|
|
9353
|
+
// recompute deriving from that stranger's world); a dead one renews (per
|
|
9354
|
+
// A18(1) each arrival reveals on its own schedule, so per-yield
|
|
9355
|
+
// transactions die with their commit and the next settle event opens the
|
|
9356
|
+
// flight's next one — still declared, never anonymous). An UNDECLARED
|
|
9357
|
+
// flight (loading window) keeps the ambient reveal (#2933: the loading
|
|
9358
|
+
// rail is transaction-invisible).
|
|
9359
|
+
const enterFlightTransition = () => {
|
|
9360
|
+
const e = o.ft;
|
|
9361
|
+
if (e == null) return;
|
|
9362
|
+
let t = liveTransition(e);
|
|
9363
|
+
if (t === null) o.ft = t = createTransition();
|
|
9364
|
+
o.node.O = t;
|
|
9365
|
+
globalQueue.initTransition(t);
|
|
9366
|
+
};
|
|
9224
9367
|
// Landing router (#3164 fold ruling): while a transaction retains
|
|
9225
9368
|
// optimistic edits on this family, truth landings stage INTO it and
|
|
9226
9369
|
// reveal atomically at settle; with no retainer they commit immediately
|
|
9227
9370
|
// under the authoritative posture (async commits land outside the
|
|
9228
|
-
// computed's sync body, so the posture is re-applied here)
|
|
9371
|
+
// computed's sync body, so the posture is re-applied here) — inside the
|
|
9372
|
+
// flight-owned transaction (#3146). Sync commits (the derive's body,
|
|
9373
|
+
// owner is the firewall itself) reveal with their own recompute's flush.
|
|
9229
9374
|
const wrapCommit = (e, t) => {
|
|
9230
9375
|
const n = retainingTransition(o);
|
|
9231
|
-
if (n
|
|
9376
|
+
if (n !== null) return void stageLanding(o, n, t);
|
|
9377
|
+
if (getOwner() !== o.node) enterFlightTransition();
|
|
9378
|
+
runAuthoritative(e);
|
|
9232
9379
|
};
|
|
9233
9380
|
// Draft writes (the derive mutating its draft, sync body and post-await
|
|
9234
9381
|
// continuations alike) are the same truth channel per-operation: bind
|
|
@@ -9240,12 +9387,49 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
9240
9387
|
const t = retainingTransition(o);
|
|
9241
9388
|
if (t === null) e(); else runFolded(t, e);
|
|
9242
9389
|
};
|
|
9390
|
+
// Flight declaration (#3146): a recompute that registered a truth-flight
|
|
9391
|
+
// OWNS its transaction. The ask's transaction is recorded on the family
|
|
9392
|
+
// (created by the flight's own pending throw when none was ambient, the
|
|
9393
|
+
// causing write's/refresh's when one was — graph-driven causality) and
|
|
9394
|
+
// the firewall is stamped so every settle path resolves the flight's
|
|
9395
|
+
// transaction by construction, not by whatever last brushed the node.
|
|
9396
|
+
// When the ask took none (a dead stale stamp — the previous flight's,
|
|
9397
|
+
// cleared nowhere — bare-returns the pre-throw entry), the flight opens
|
|
9398
|
+
// its own here, same activation point as the pre-throw's creation: the
|
|
9399
|
+
// ambient batch (the causing write, same-tick bare optimism) adopts into
|
|
9400
|
+
// it exactly as it would have there, and the pending notification that
|
|
9401
|
+
// follows this unwind registers observers against it. The flight
|
|
9402
|
+
// also registers as its own async reporter: the transaction lives
|
|
9403
|
+
// exactly as long as the question is unanswered, observed or not — the
|
|
9404
|
+
// #2951 refetch-hold no longer depends on a tracked observer having
|
|
9405
|
+
// happened to register one. Loading-window flights declare nothing
|
|
9406
|
+
// (#2933: the loading rail is transaction-invisible); a sync run clears
|
|
9407
|
+
// the declaration.
|
|
9408
|
+
const declareFlight = e => {
|
|
9409
|
+
if (e.o?.bt == null) {
|
|
9410
|
+
if (!e.lt) o.ft = null;
|
|
9411
|
+
return;
|
|
9412
|
+
}
|
|
9413
|
+
if (e.lt) return;
|
|
9414
|
+
let t = activeTransition;
|
|
9415
|
+
if (t === null) globalQueue.initTransition(t = createTransition());
|
|
9416
|
+
o.ft = t;
|
|
9417
|
+
e.O = t;
|
|
9418
|
+
let n = t.J.get(e);
|
|
9419
|
+
if (n === undefined) t.J.set(e, n = new Set);
|
|
9420
|
+
n.add(e);
|
|
9421
|
+
};
|
|
9243
9422
|
let i;
|
|
9244
9423
|
if (n?.seedLoadingValue) i = {
|
|
9245
9424
|
loadingValue: undefined
|
|
9246
9425
|
};
|
|
9247
9426
|
const r = computed(() => {
|
|
9248
|
-
|
|
9427
|
+
const e = getOwner();
|
|
9428
|
+
try {
|
|
9429
|
+
runAuthoritative(() => runProjectionComputedNext(s, t, n?.key === undefined ? "id" : n.key, wrapCommit, aroundDraftWrite));
|
|
9430
|
+
} finally {
|
|
9431
|
+
declareFlight(e);
|
|
9432
|
+
}
|
|
9249
9433
|
}, i);
|
|
9250
9434
|
r.D &= ~CONFIG_AUTO_DISPOSE;
|
|
9251
9435
|
o.node = r;
|
|
@@ -9429,13 +9613,18 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
9429
9613
|
* overrides — the same view the draft was seeded from) and emit engine writes
|
|
9430
9614
|
* for exactly the changed keys. Visible-view diffing keeps no-op writes from
|
|
9431
9615
|
* entangling lanes (RUL-10 / opt R38). */ function notifyOptimisticWrites(e, t) {
|
|
9432
|
-
// A bare write while the store's own truth is in flight rides
|
|
9433
|
-
// transaction (#2951
|
|
9434
|
-
//
|
|
9616
|
+
// A bare write while the store's own truth is in flight rides the FLIGHT'S
|
|
9617
|
+
// OWN transaction (#2951 via the #3146 declaration): entangle it so the
|
|
9618
|
+
// override survives until the refetch settles instead of flash-reverting
|
|
9435
9619
|
// at plain flush end. The blocked-check store-half keeps that transaction
|
|
9436
|
-
// from settling while the firewall is pending.
|
|
9437
|
-
|
|
9438
|
-
|
|
9620
|
+
// from settling while the firewall is pending. Declared ownership replaces
|
|
9621
|
+
// the old circumstantial route through the firewall's `_transition` stamp,
|
|
9622
|
+
// which was whatever last brushed the node.
|
|
9623
|
+
const n = e.fam?.ft;
|
|
9624
|
+
if (n != null) {
|
|
9625
|
+
const e = liveTransition(n);
|
|
9626
|
+
if (e !== null) globalQueue.initTransition(e);
|
|
9627
|
+
}
|
|
9439
9628
|
const i = e.v;
|
|
9440
9629
|
// Patch channel (override-application site): the draft IS the intended
|
|
9441
9630
|
// visible state; prev is the view before these overrides apply. Bypasses
|
|
@@ -9937,23 +10126,23 @@ function mapArray(e, t, n) {
|
|
|
9937
10126
|
const r = t.length > 1;
|
|
9938
10127
|
const o = t;
|
|
9939
10128
|
const s = {
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
rn: [],
|
|
10129
|
+
Jt: createOwner(),
|
|
10130
|
+
en: 0,
|
|
10131
|
+
tn: e,
|
|
10132
|
+
nn: [],
|
|
10133
|
+
rn: o,
|
|
9946
10134
|
sn: [],
|
|
9947
|
-
un:
|
|
9948
|
-
ln: i
|
|
9949
|
-
cn:
|
|
9950
|
-
an: n?.keyed
|
|
9951
|
-
dn: n?.
|
|
10135
|
+
un: [],
|
|
10136
|
+
ln: i,
|
|
10137
|
+
cn: i || n?.keyed === false ? [] : undefined,
|
|
10138
|
+
an: r && n?.keyed !== false ? [] : undefined,
|
|
10139
|
+
dn: n?.keyed === false,
|
|
10140
|
+
pn: n?.fallback
|
|
9952
10141
|
};
|
|
9953
10142
|
const u = computed(updateKeyedMap.bind(s));
|
|
9954
10143
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
9955
10144
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
9956
|
-
s.
|
|
10145
|
+
s.Jt.Rt = u;
|
|
9957
10146
|
u.D &= ~CONFIG_AUTO_DISPOSE;
|
|
9958
10147
|
return accessor(u);
|
|
9959
10148
|
}
|
|
@@ -9972,52 +10161,52 @@ const pureOptions = {
|
|
|
9972
10161
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
9973
10162
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
9974
10163
|
function updateKeyedMap() {
|
|
9975
|
-
const e = this.
|
|
10164
|
+
const e = this.tn() || [], t = e.length;
|
|
9976
10165
|
e[$TRACK];
|
|
9977
10166
|
// top level tracking
|
|
9978
|
-
runWithOwner(this.
|
|
10167
|
+
runWithOwner(this.Jt, () => {
|
|
9979
10168
|
let n, i, r, o,
|
|
9980
10169
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
9981
10170
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
9982
|
-
s = this.
|
|
10171
|
+
s = this.cn ? this.dn ? () => {
|
|
9983
10172
|
r[i] = signal(e[i], pureOptions);
|
|
9984
|
-
return this.
|
|
10173
|
+
return this.rn(accessor(r[i]), i);
|
|
9985
10174
|
} : () => {
|
|
9986
10175
|
r[i] = signal(e[i], pureOptions);
|
|
9987
10176
|
o && (o[i] = signal(i, pureOptions));
|
|
9988
|
-
return this.
|
|
9989
|
-
} : this.
|
|
10177
|
+
return this.rn(accessor(r[i]), o ? accessor(o[i]) : undefined);
|
|
10178
|
+
} : this.an ? () => {
|
|
9990
10179
|
const t = e[i];
|
|
9991
10180
|
o[i] = signal(i, pureOptions);
|
|
9992
|
-
return this.
|
|
10181
|
+
return this.rn(t, accessor(o[i]));
|
|
9993
10182
|
} : () => {
|
|
9994
10183
|
const t = e[i];
|
|
9995
|
-
return this.
|
|
10184
|
+
return this.rn(t);
|
|
9996
10185
|
};
|
|
9997
10186
|
// fast path for empty arrays
|
|
9998
10187
|
if (t === 0) {
|
|
9999
|
-
if (this.
|
|
10000
|
-
this.
|
|
10188
|
+
if (this.en !== 0) {
|
|
10189
|
+
this.Jt.dispose(false);
|
|
10190
|
+
this.un = [];
|
|
10191
|
+
this.nn = [];
|
|
10001
10192
|
this.sn = [];
|
|
10002
|
-
this.
|
|
10003
|
-
this.rn = [];
|
|
10004
|
-
this.Jt = 0;
|
|
10005
|
-
this.ln && (this.ln = []);
|
|
10193
|
+
this.en = 0;
|
|
10006
10194
|
this.cn && (this.cn = []);
|
|
10195
|
+
this.an && (this.an = []);
|
|
10007
10196
|
}
|
|
10008
|
-
if (this.
|
|
10197
|
+
if (this.pn && !this.sn[0]) {
|
|
10009
10198
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
10010
10199
|
// dispose it before re-creating
|
|
10011
|
-
this.
|
|
10012
|
-
this.
|
|
10200
|
+
this.un[0]?.dispose();
|
|
10201
|
+
this.sn[0] = runWithOwner(this.un[0] = createOwner(), this.pn);
|
|
10013
10202
|
}
|
|
10014
10203
|
}
|
|
10015
10204
|
// fast path for new create
|
|
10016
|
-
else if (this.
|
|
10205
|
+
else if (this.en === 0) {
|
|
10017
10206
|
const u = new Array(t);
|
|
10018
10207
|
const l = new Array(t);
|
|
10019
|
-
r = this.
|
|
10020
|
-
o = this.
|
|
10208
|
+
r = this.cn && new Array(t);
|
|
10209
|
+
o = this.an && new Array(t);
|
|
10021
10210
|
try {
|
|
10022
10211
|
for (i = 0; i < t; i++) u[i] = runWithOwner(l[i] = createOwner(), s);
|
|
10023
10212
|
} catch (e) {
|
|
@@ -10025,43 +10214,43 @@ function updateKeyedMap() {
|
|
|
10025
10214
|
throw e;
|
|
10026
10215
|
}
|
|
10027
10216
|
// commit
|
|
10028
|
-
if (this.
|
|
10217
|
+
if (this.un[0]) this.un[0].dispose();
|
|
10029
10218
|
// previous fallback
|
|
10030
|
-
this.
|
|
10031
|
-
this.
|
|
10032
|
-
r && (this.
|
|
10033
|
-
o && (this.
|
|
10034
|
-
this.
|
|
10035
|
-
this.
|
|
10219
|
+
this.sn = u;
|
|
10220
|
+
this.un = l;
|
|
10221
|
+
r && (this.cn = r);
|
|
10222
|
+
o && (this.an = o);
|
|
10223
|
+
this.nn = e.slice(0);
|
|
10224
|
+
this.en = t;
|
|
10036
10225
|
} else {
|
|
10037
10226
|
let u, l, f, c, a, d, p, E, S;
|
|
10038
10227
|
// skip common prefix
|
|
10039
|
-
for (u = 0, l = Math.min(this.
|
|
10040
|
-
if (this.
|
|
10228
|
+
for (u = 0, l = Math.min(this.en, t); u < l && (this.nn[u] === e[u] || this.cn && compare(this.ln, this.nn[u], e[u])); u++) {
|
|
10229
|
+
if (this.cn) setSignal(this.cn[u], e[u]);
|
|
10041
10230
|
}
|
|
10042
10231
|
// skip common suffix — counted only; retained entries land in one pass
|
|
10043
10232
|
// at commit instead of being staged and copied twice
|
|
10044
|
-
for (l = this.
|
|
10233
|
+
for (l = this.en - 1, f = t - 1; l >= u && f >= u && (this.nn[l] === e[f] || this.cn && compare(this.ln, this.nn[l], e[f])); l--,
|
|
10045
10234
|
f--) ;
|
|
10046
10235
|
// no structural change (every position matched in place at equal
|
|
10047
10236
|
// length — the common post-reconcile shape): keep the same mapped
|
|
10048
10237
|
// array identity so downstream consumers don't re-run at all
|
|
10049
|
-
if (u === t && this.
|
|
10050
|
-
this.
|
|
10238
|
+
if (u === t && this.en === t) {
|
|
10239
|
+
this.nn = e.slice(0);
|
|
10051
10240
|
return;
|
|
10052
10241
|
}
|
|
10053
|
-
const T = t - this.
|
|
10242
|
+
const T = t - this.en;
|
|
10054
10243
|
const _ = new Array(t);
|
|
10055
10244
|
const h = new Array(t);
|
|
10056
|
-
r = this.
|
|
10057
|
-
o = this.
|
|
10245
|
+
r = this.cn ? new Array(t) : undefined;
|
|
10246
|
+
o = this.an ? new Array(t) : undefined;
|
|
10058
10247
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
10059
10248
|
// scanning backwards so we encounter them in natural order
|
|
10060
10249
|
d = new Map;
|
|
10061
10250
|
p = new Array(f + 1);
|
|
10062
10251
|
for (i = f; i >= u; i--) {
|
|
10063
10252
|
c = e[i];
|
|
10064
|
-
a = this.
|
|
10253
|
+
a = this.ln ? this.ln(c) : c;
|
|
10065
10254
|
n = d.get(a);
|
|
10066
10255
|
p[i] = n === undefined ? -1 : n;
|
|
10067
10256
|
d.set(a, i);
|
|
@@ -10070,17 +10259,17 @@ function updateKeyedMap() {
|
|
|
10070
10259
|
// in the new set; if so, stage them at their new positions; if not,
|
|
10071
10260
|
// queue them for disposal at commit
|
|
10072
10261
|
for (n = u; n <= l; n++) {
|
|
10073
|
-
c = this.
|
|
10074
|
-
a = this.
|
|
10262
|
+
c = this.nn[n];
|
|
10263
|
+
a = this.ln ? this.ln(c) : c;
|
|
10075
10264
|
i = d.get(a);
|
|
10076
10265
|
if (i !== undefined && i !== -1) {
|
|
10077
|
-
_[i] = this.
|
|
10078
|
-
h[i] = this.
|
|
10079
|
-
r && (r[i] = this.
|
|
10080
|
-
o && (o[i] = this.
|
|
10266
|
+
_[i] = this.sn[n];
|
|
10267
|
+
h[i] = this.un[n];
|
|
10268
|
+
r && (r[i] = this.cn[n]);
|
|
10269
|
+
o && (o[i] = this.an[n]);
|
|
10081
10270
|
i = p[i];
|
|
10082
10271
|
d.set(a, i);
|
|
10083
|
-
} else (E ??= []).push(this.
|
|
10272
|
+
} else (E ??= []).push(this.un[n]);
|
|
10084
10273
|
}
|
|
10085
10274
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
10086
10275
|
try {
|
|
@@ -10097,38 +10286,38 @@ function updateKeyedMap() {
|
|
|
10097
10286
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
10098
10287
|
// change propagation), then dispose exited rows
|
|
10099
10288
|
for (n = 0; n < u; n++) {
|
|
10100
|
-
_[n] = this.
|
|
10101
|
-
h[n] = this.
|
|
10102
|
-
r && (r[n] = this.
|
|
10103
|
-
o && (o[n] = this.
|
|
10289
|
+
_[n] = this.sn[n];
|
|
10290
|
+
h[n] = this.un[n];
|
|
10291
|
+
r && (r[n] = this.cn[n]);
|
|
10292
|
+
o && (o[n] = this.an[n]);
|
|
10104
10293
|
}
|
|
10105
10294
|
for (i = u; i <= f; i++) {
|
|
10106
10295
|
if (r) setSignal(r[i], e[i]);
|
|
10107
10296
|
if (o) setSignal(o[i], i);
|
|
10108
10297
|
}
|
|
10109
10298
|
for (i = f + 1; i < t; i++) {
|
|
10110
|
-
_[i] = this.
|
|
10111
|
-
h[i] = this.
|
|
10299
|
+
_[i] = this.sn[i - T];
|
|
10300
|
+
h[i] = this.un[i - T];
|
|
10112
10301
|
if (r) {
|
|
10113
|
-
r[i] = this.
|
|
10302
|
+
r[i] = this.cn[i - T];
|
|
10114
10303
|
setSignal(r[i], e[i]);
|
|
10115
10304
|
}
|
|
10116
10305
|
if (o) {
|
|
10117
|
-
o[i] = this.
|
|
10306
|
+
o[i] = this.an[i - T];
|
|
10118
10307
|
if (T !== 0) setSignal(o[i], i);
|
|
10119
10308
|
}
|
|
10120
10309
|
}
|
|
10121
|
-
this.
|
|
10122
|
-
this.
|
|
10123
|
-
r && (this.
|
|
10124
|
-
o && (this.
|
|
10125
|
-
this.
|
|
10310
|
+
this.sn = _;
|
|
10311
|
+
this.un = h;
|
|
10312
|
+
r && (this.cn = r);
|
|
10313
|
+
o && (this.an = o);
|
|
10314
|
+
this.en = t;
|
|
10126
10315
|
// save a copy of the mapped items for the next update
|
|
10127
|
-
this.
|
|
10316
|
+
this.nn = e.slice(0);
|
|
10128
10317
|
if (E) for (n = 0; n < E.length; n++) E[n].dispose();
|
|
10129
10318
|
}
|
|
10130
10319
|
});
|
|
10131
|
-
return this.
|
|
10320
|
+
return this.sn;
|
|
10132
10321
|
}
|
|
10133
10322
|
|
|
10134
10323
|
/**
|
|
@@ -10148,21 +10337,21 @@ function updateKeyedMap() {
|
|
|
10148
10337
|
*/ function repeat(e, t, n) {
|
|
10149
10338
|
const i = t;
|
|
10150
10339
|
const r = {
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10340
|
+
Jt: createOwner(),
|
|
10341
|
+
en: 0,
|
|
10342
|
+
En: 0,
|
|
10343
|
+
Sn: e,
|
|
10344
|
+
rn: i,
|
|
10345
|
+
un: [],
|
|
10156
10346
|
sn: [],
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
dn: n?.fallback
|
|
10347
|
+
Tn: n?.from,
|
|
10348
|
+
pn: n?.fallback
|
|
10160
10349
|
};
|
|
10161
10350
|
const o = computed(updateRepeat.bind(r));
|
|
10162
10351
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
10163
10352
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
10164
10353
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
10165
|
-
r.
|
|
10354
|
+
r.Jt.Rt = o;
|
|
10166
10355
|
o.D &= ~CONFIG_AUTO_DISPOSE;
|
|
10167
10356
|
return accessor(o);
|
|
10168
10357
|
}
|
|
@@ -10175,55 +10364,55 @@ function updateKeyedMap() {
|
|
|
10175
10364
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
10176
10365
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
10177
10366
|
function updateRepeat() {
|
|
10178
|
-
const e = this.
|
|
10179
|
-
const t = this.
|
|
10180
|
-
runWithOwner(this.
|
|
10367
|
+
const e = this.Sn();
|
|
10368
|
+
const t = this.Tn?.() || 0;
|
|
10369
|
+
runWithOwner(this.Jt, () => {
|
|
10181
10370
|
if (e === 0) {
|
|
10182
|
-
if (this.
|
|
10183
|
-
this.
|
|
10371
|
+
if (this.en !== 0) {
|
|
10372
|
+
this.Jt.dispose(false);
|
|
10373
|
+
this.un = [];
|
|
10184
10374
|
this.sn = [];
|
|
10185
|
-
this.
|
|
10186
|
-
this.Jt = 0;
|
|
10375
|
+
this.en = 0;
|
|
10187
10376
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
10188
|
-
this.
|
|
10377
|
+
this.En = 0;
|
|
10189
10378
|
}
|
|
10190
|
-
if (this.
|
|
10379
|
+
if (this.pn && !this.sn[0]) {
|
|
10191
10380
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
10192
10381
|
// dispose it before re-creating
|
|
10193
|
-
this.
|
|
10194
|
-
this.
|
|
10382
|
+
this.un[0]?.dispose();
|
|
10383
|
+
this.sn[0] = runWithOwner(this.un[0] = createOwner(), this.pn);
|
|
10195
10384
|
}
|
|
10196
10385
|
return;
|
|
10197
10386
|
}
|
|
10198
10387
|
const n = t + e;
|
|
10199
|
-
const i = this.
|
|
10388
|
+
const i = this.En + this.en;
|
|
10200
10389
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
10201
10390
|
// windows are disjoint or when coming from empty/fallback.
|
|
10202
|
-
const r = Math.max(t, this.
|
|
10391
|
+
const r = Math.max(t, this.En);
|
|
10203
10392
|
const o = Math.min(n, i);
|
|
10204
10393
|
const s = new Array(e);
|
|
10205
10394
|
const u = new Array(e);
|
|
10206
10395
|
for (let e = r; e < o; e++) {
|
|
10207
|
-
u[e - t] = this.
|
|
10208
|
-
s[e - t] = this.
|
|
10396
|
+
u[e - t] = this.un[e - this.En];
|
|
10397
|
+
s[e - t] = this.sn[e - this.En];
|
|
10209
10398
|
}
|
|
10210
10399
|
try {
|
|
10211
10400
|
for (let e = t; e < n; e++) {
|
|
10212
10401
|
if (e >= r && e < o) continue;
|
|
10213
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
10402
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.rn(e));
|
|
10214
10403
|
}
|
|
10215
10404
|
} catch (e) {
|
|
10216
10405
|
for (let e = t; e < n; e++) if ((e < r || e >= o) && u[e - t]) u[e - t].dispose();
|
|
10217
10406
|
throw e;
|
|
10218
10407
|
}
|
|
10219
10408
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
10220
|
-
if (this.
|
|
10221
|
-
this.
|
|
10222
|
-
this.
|
|
10223
|
-
this.
|
|
10224
|
-
this.
|
|
10409
|
+
if (this.en === 0) this.un[0]?.dispose(); else for (let e = this.En; e < i; e++) if (e < t || e >= n) this.un[e - this.En].dispose();
|
|
10410
|
+
this.sn = s;
|
|
10411
|
+
this.un = u;
|
|
10412
|
+
this.En = t;
|
|
10413
|
+
this.en = e;
|
|
10225
10414
|
});
|
|
10226
|
-
return this.
|
|
10415
|
+
return this.sn;
|
|
10227
10416
|
}
|
|
10228
10417
|
|
|
10229
10418
|
function compare(e, t, n) {
|
|
@@ -10234,23 +10423,23 @@ function boundaryComputed(e, t) {
|
|
|
10234
10423
|
const n = computed(e, {
|
|
10235
10424
|
lazy: true
|
|
10236
10425
|
});
|
|
10237
|
-
ext(n).
|
|
10426
|
+
ext(n).Bt = (e, t) => {
|
|
10238
10427
|
// Use passed values if provided, otherwise read from node
|
|
10239
|
-
const i = e !== undefined ? e : n.
|
|
10428
|
+
const i = e !== undefined ? e : n.ct;
|
|
10240
10429
|
const r = t !== undefined ? t : n.o?.ze;
|
|
10241
10430
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
10242
10431
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
10243
10432
|
// a boundary that handles it is found.
|
|
10244
|
-
n.
|
|
10245
|
-
const o = n.
|
|
10433
|
+
n.ct &= ~n._n;
|
|
10434
|
+
const o = n.At.notify(n, STATUS_PENDING | STATUS_ERROR, i, r);
|
|
10246
10435
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
10247
10436
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
10248
10437
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
10249
10438
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
10250
|
-
const s = i & ~n.
|
|
10439
|
+
const s = i & ~n._n & (STATUS_PENDING | STATUS_ERROR);
|
|
10251
10440
|
if (s) {
|
|
10252
|
-
n.
|
|
10253
|
-
if (n.o?.ze === r && !(n.
|
|
10441
|
+
n.ct &= ~s;
|
|
10442
|
+
if (n.o?.ze === r && !(n.ct & (STATUS_PENDING | STATUS_ERROR))) if (n.o !== null) n.o.ze = undefined;
|
|
10254
10443
|
}
|
|
10255
10444
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
10256
10445
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -10261,16 +10450,16 @@ function boundaryComputed(e, t) {
|
|
|
10261
10450
|
throw r;
|
|
10262
10451
|
}
|
|
10263
10452
|
};
|
|
10264
|
-
n.
|
|
10453
|
+
n._n = t;
|
|
10265
10454
|
n.D &= ~CONFIG_AUTO_DISPOSE;
|
|
10266
10455
|
recompute(n, true);
|
|
10267
10456
|
return n;
|
|
10268
10457
|
}
|
|
10269
10458
|
|
|
10270
10459
|
function createBoundChildren(e, t, n, i) {
|
|
10271
|
-
const r = e.
|
|
10272
|
-
r.addChild(e.
|
|
10273
|
-
cleanup(() => r.removeChild(e.
|
|
10460
|
+
const r = e.At;
|
|
10461
|
+
r.addChild(e.At = n);
|
|
10462
|
+
cleanup(() => r.removeChild(e.At));
|
|
10274
10463
|
return runWithOwner(e, () => {
|
|
10275
10464
|
const e = computed(t);
|
|
10276
10465
|
return boundaryComputed(() => flatten(read(e)), i);
|
|
@@ -10292,53 +10481,53 @@ function isRevealController(e) {
|
|
|
10292
10481
|
}
|
|
10293
10482
|
|
|
10294
10483
|
function isSlotReady(e) {
|
|
10295
|
-
return isRevealController(e) ? e.
|
|
10484
|
+
return isRevealController(e) ? e.hn() : e.An.size === 0 && !e.On;
|
|
10296
10485
|
}
|
|
10297
10486
|
|
|
10298
10487
|
function isSlotMinimallyReady(e) {
|
|
10299
|
-
return isRevealController(e) ? e.
|
|
10488
|
+
return isRevealController(e) ? e.Nn() : isSlotReady(e);
|
|
10300
10489
|
}
|
|
10301
10490
|
|
|
10302
10491
|
function setSlotState(e, t, n, i) {
|
|
10303
|
-
setSignal(e.
|
|
10304
|
-
setSignal(e.
|
|
10492
|
+
setSignal(e.In, n);
|
|
10493
|
+
setSignal(e.Rn, i);
|
|
10305
10494
|
if (isRevealController(e)) {
|
|
10306
|
-
if (!n && e.
|
|
10307
|
-
return e.
|
|
10495
|
+
if (!n && e.Cn === t) e.Cn = undefined;
|
|
10496
|
+
return e.gn(n, i);
|
|
10308
10497
|
}
|
|
10309
|
-
if (!n && e.
|
|
10498
|
+
if (!n && e.vn === t && e.yn) e.vn = undefined;
|
|
10310
10499
|
}
|
|
10311
10500
|
|
|
10312
10501
|
class RevealController {
|
|
10313
|
-
yn;
|
|
10314
10502
|
wn;
|
|
10315
|
-
Pn
|
|
10316
|
-
|
|
10317
|
-
|
|
10503
|
+
Pn;
|
|
10504
|
+
bn=[];
|
|
10505
|
+
Cn;
|
|
10506
|
+
In=signal(false, {
|
|
10318
10507
|
ownedWrite: true,
|
|
10319
|
-
|
|
10508
|
+
qt: true
|
|
10320
10509
|
});
|
|
10321
|
-
|
|
10510
|
+
Rn=signal(false, {
|
|
10322
10511
|
ownedWrite: true,
|
|
10323
|
-
|
|
10512
|
+
qt: true
|
|
10324
10513
|
});
|
|
10325
|
-
bn=true;
|
|
10326
10514
|
mn=true;
|
|
10327
|
-
Dn=
|
|
10515
|
+
Dn=true;
|
|
10516
|
+
Gn=false;
|
|
10328
10517
|
constructor(e, t) {
|
|
10329
|
-
this.
|
|
10330
|
-
this.
|
|
10518
|
+
this.wn = e;
|
|
10519
|
+
this.Pn = t;
|
|
10331
10520
|
}
|
|
10332
|
-
|
|
10333
|
-
for (let t = 0; t < this.
|
|
10334
|
-
const n = this.
|
|
10335
|
-
if ((isRevealController(n) ? n.
|
|
10521
|
+
kn(e) {
|
|
10522
|
+
for (let t = 0; t < this.bn.length; t++) {
|
|
10523
|
+
const n = this.bn[t];
|
|
10524
|
+
if ((isRevealController(n) ? n.Cn : n.vn) !== this) continue;
|
|
10336
10525
|
if (e(n) === false) return false;
|
|
10337
10526
|
}
|
|
10338
10527
|
return true;
|
|
10339
10528
|
}
|
|
10340
|
-
|
|
10341
|
-
return this.
|
|
10529
|
+
hn() {
|
|
10530
|
+
return this.kn(isSlotReady);
|
|
10342
10531
|
}
|
|
10343
10532
|
/**
|
|
10344
10533
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -10346,13 +10535,13 @@ class RevealController {
|
|
|
10346
10535
|
* - `together`: every direct slot is minimally ready.
|
|
10347
10536
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
10348
10537
|
* - `natural`: any owned slot is minimally ready.
|
|
10349
|
-
*/
|
|
10350
|
-
const e = untrack(this.
|
|
10351
|
-
if (e === "together") return this.
|
|
10538
|
+
*/ Nn() {
|
|
10539
|
+
const e = untrack(this.wn);
|
|
10540
|
+
if (e === "together") return this.kn(isSlotMinimallyReady);
|
|
10352
10541
|
if (e === "natural") {
|
|
10353
10542
|
let e = false;
|
|
10354
10543
|
let t = false;
|
|
10355
|
-
this.
|
|
10544
|
+
this.kn(n => {
|
|
10356
10545
|
e = true;
|
|
10357
10546
|
if (isSlotMinimallyReady(n)) {
|
|
10358
10547
|
t = true;
|
|
@@ -10363,45 +10552,45 @@ class RevealController {
|
|
|
10363
10552
|
}
|
|
10364
10553
|
// sequential: only the first owned slot matters.
|
|
10365
10554
|
let t = true;
|
|
10366
|
-
this.
|
|
10555
|
+
this.kn(e => {
|
|
10367
10556
|
t = isSlotMinimallyReady(e);
|
|
10368
10557
|
return false;
|
|
10369
10558
|
});
|
|
10370
10559
|
return t;
|
|
10371
10560
|
}
|
|
10372
|
-
kn(e) {
|
|
10373
|
-
if (this.Pn.includes(e)) return;
|
|
10374
|
-
this.Pn.push(e);
|
|
10375
|
-
const t = untrack(this.yn);
|
|
10376
|
-
setSignal(e.Nn, true), setSignal(e.In, t === "sequential" ? !!untrack(this.wn) : false);
|
|
10377
|
-
untrack(() => this.Cn());
|
|
10378
|
-
}
|
|
10379
10561
|
xn(e) {
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
untrack(
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10386
|
-
|
|
10387
|
-
const
|
|
10388
|
-
|
|
10562
|
+
if (this.bn.includes(e)) return;
|
|
10563
|
+
this.bn.push(e);
|
|
10564
|
+
const t = untrack(this.wn);
|
|
10565
|
+
setSignal(e.In, true), setSignal(e.Rn, t === "sequential" ? !!untrack(this.Pn) : false);
|
|
10566
|
+
untrack(() => this.gn());
|
|
10567
|
+
}
|
|
10568
|
+
Fn(e) {
|
|
10569
|
+
const t = this.bn.indexOf(e);
|
|
10570
|
+
if (t >= 0) this.bn.splice(t, 1);
|
|
10571
|
+
untrack(() => this.gn());
|
|
10572
|
+
}
|
|
10573
|
+
gn(e, t) {
|
|
10574
|
+
if (this.Gn) return;
|
|
10575
|
+
this.Gn = true;
|
|
10576
|
+
const n = this.mn;
|
|
10577
|
+
const i = this.Dn;
|
|
10389
10578
|
try {
|
|
10390
|
-
const n = e ?? read(this.
|
|
10579
|
+
const n = e ?? read(this.In), i = untrack(this.wn), r = i === "sequential" && !!untrack(this.Pn), o = t ?? r;
|
|
10391
10580
|
if (n) {
|
|
10392
10581
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
10393
10582
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
10394
10583
|
// held; it resumes once the outer releases us.
|
|
10395
|
-
this.
|
|
10584
|
+
this.kn(e => setSlotState(e, this, true, o));
|
|
10396
10585
|
} else if (i === "natural") {
|
|
10397
10586
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
10398
10587
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
10399
10588
|
// so the parent backpointer survives for upward readiness notifications.
|
|
10400
|
-
this.
|
|
10589
|
+
this.kn(e => {
|
|
10401
10590
|
if (isRevealController(e)) {
|
|
10591
|
+
setSignal(e.Rn, false);
|
|
10402
10592
|
setSignal(e.In, false);
|
|
10403
|
-
|
|
10404
|
-
e.Cn(false, false);
|
|
10593
|
+
e.gn(false, false);
|
|
10405
10594
|
} else {
|
|
10406
10595
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
10407
10596
|
}
|
|
@@ -10412,11 +10601,11 @@ class RevealController {
|
|
|
10412
10601
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
10413
10602
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
10414
10603
|
// cohesive reveal without waiting for every grandchild.
|
|
10415
|
-
const e = this.
|
|
10416
|
-
this.
|
|
10604
|
+
const e = this.kn(isSlotMinimallyReady);
|
|
10605
|
+
this.kn(t => setSlotState(t, this, !e, false));
|
|
10417
10606
|
} else {
|
|
10418
10607
|
let e = false;
|
|
10419
|
-
this.
|
|
10608
|
+
this.kn(t => {
|
|
10420
10609
|
if (e) return setSlotState(t, this, true, r);
|
|
10421
10610
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
10422
10611
|
e = true;
|
|
@@ -10427,63 +10616,63 @@ class RevealController {
|
|
|
10427
10616
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
10428
10617
|
// backpointer survives for upward readiness notifications.
|
|
10429
10618
|
if (isRevealController(t)) {
|
|
10619
|
+
setSignal(t.Rn, false);
|
|
10430
10620
|
setSignal(t.In, false);
|
|
10431
|
-
|
|
10432
|
-
t.Cn(false, false);
|
|
10621
|
+
t.gn(false, false);
|
|
10433
10622
|
} else {
|
|
10434
10623
|
setSlotState(t, this, true, false);
|
|
10435
10624
|
}
|
|
10436
10625
|
});
|
|
10437
10626
|
}
|
|
10438
10627
|
} finally {
|
|
10439
|
-
this.
|
|
10440
|
-
this.
|
|
10441
|
-
this.
|
|
10628
|
+
this.mn = this.hn();
|
|
10629
|
+
this.Dn = this.Nn();
|
|
10630
|
+
this.Gn = false;
|
|
10442
10631
|
}
|
|
10443
|
-
if (this.
|
|
10632
|
+
if (this.Cn && (n !== this.mn || i !== this.Dn)) this.Cn.gn();
|
|
10444
10633
|
}
|
|
10445
10634
|
}
|
|
10446
10635
|
|
|
10447
10636
|
class CollectionQueue extends Queue {
|
|
10448
|
-
Fn;
|
|
10449
|
-
hn=new Set;
|
|
10450
10637
|
Hn;
|
|
10451
|
-
An=
|
|
10452
|
-
|
|
10638
|
+
An=new Set;
|
|
10639
|
+
Un;
|
|
10640
|
+
On=true;
|
|
10641
|
+
In=signal(false, {
|
|
10453
10642
|
ownedWrite: true,
|
|
10454
|
-
|
|
10643
|
+
qt: true
|
|
10455
10644
|
});
|
|
10456
10645
|
ze;
|
|
10457
|
-
|
|
10646
|
+
Rn=signal(false, {
|
|
10458
10647
|
ownedWrite: true,
|
|
10459
|
-
|
|
10648
|
+
qt: true
|
|
10460
10649
|
});
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10650
|
+
vn;
|
|
10651
|
+
yn=false;
|
|
10652
|
+
Ln;
|
|
10653
|
+
Vn=ON_INIT;
|
|
10465
10654
|
constructor(e) {
|
|
10466
10655
|
super();
|
|
10467
|
-
this.
|
|
10656
|
+
this.Hn = e;
|
|
10468
10657
|
}
|
|
10469
10658
|
run(e) {
|
|
10470
|
-
if (!e || read(this.
|
|
10659
|
+
if (!e || read(this.In) && (!_revealUsed || read(this.Rn))) return;
|
|
10471
10660
|
return super.run(e);
|
|
10472
10661
|
}
|
|
10473
10662
|
notify(e, t, n, i) {
|
|
10474
|
-
if (!(t & this.
|
|
10475
|
-
if (this.
|
|
10663
|
+
if (!(t & this.Hn)) return super.notify(e, t, n, i);
|
|
10664
|
+
if (this.yn && this.Ln) {
|
|
10476
10665
|
const e = untrack(() => {
|
|
10477
10666
|
try {
|
|
10478
|
-
return this.
|
|
10667
|
+
return this.Ln();
|
|
10479
10668
|
} catch {
|
|
10480
10669
|
return ON_INIT;
|
|
10481
10670
|
}
|
|
10482
10671
|
});
|
|
10483
|
-
if (e !== this.
|
|
10484
|
-
this.
|
|
10485
|
-
this.
|
|
10486
|
-
this.
|
|
10672
|
+
if (e !== this.Vn) {
|
|
10673
|
+
this.Vn = e;
|
|
10674
|
+
this.yn = false;
|
|
10675
|
+
this.An.clear();
|
|
10487
10676
|
}
|
|
10488
10677
|
}
|
|
10489
10678
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -10496,47 +10685,47 @@ class CollectionQueue extends Queue {
|
|
|
10496
10685
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
10497
10686
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
10498
10687
|
// (the Loading > Errored > content composition escape, #2856).
|
|
10499
|
-
if (this.
|
|
10500
|
-
if (n & this.
|
|
10501
|
-
this.
|
|
10688
|
+
if (this.Hn & STATUS_PENDING && this.yn) return super.notify(e, t, n, i);
|
|
10689
|
+
if (n & this.Hn) {
|
|
10690
|
+
this.On = true;
|
|
10502
10691
|
const t = i?.source || e.o?.ze?.source;
|
|
10503
10692
|
if (t) {
|
|
10504
|
-
const e = this.
|
|
10505
|
-
this.
|
|
10506
|
-
if (e) setSignal(this.
|
|
10507
|
-
if (this.
|
|
10693
|
+
const e = this.An.size === 0;
|
|
10694
|
+
this.An.add(t);
|
|
10695
|
+
if (e) setSignal(this.In, true);
|
|
10696
|
+
if (this.Hn & STATUS_ERROR) {
|
|
10508
10697
|
setSignal(this.ze, unwrapStatusError(t.o?.ze));
|
|
10509
10698
|
}
|
|
10510
10699
|
}
|
|
10511
10700
|
}
|
|
10512
|
-
t &= ~this.
|
|
10701
|
+
t &= ~this.Hn;
|
|
10513
10702
|
return t ? super.notify(e, t, n, i) : true;
|
|
10514
10703
|
}
|
|
10515
|
-
|
|
10516
|
-
for (const e of this.
|
|
10704
|
+
St() {
|
|
10705
|
+
for (const e of this.An) {
|
|
10517
10706
|
// A source with a live affects() mark holds display state for the
|
|
10518
10707
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
10519
10708
|
// status of its own, so the count is the liveness test. The release
|
|
10520
10709
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
10521
|
-
if (e.L & REACTIVE_DISPOSED || !e.o?.K && !(e.
|
|
10710
|
+
if (e.L & REACTIVE_DISPOSED || !e.o?.K && !(e.ct & this.Hn) && !(this.Hn & STATUS_ERROR && e.ct & STATUS_PENDING)) this.An.delete(e);
|
|
10522
10711
|
}
|
|
10523
|
-
if (!this.
|
|
10524
|
-
if (this.
|
|
10525
|
-
this.
|
|
10712
|
+
if (!this.An.size) {
|
|
10713
|
+
if (this.Hn & STATUS_PENDING && this.On && !this.yn && this.Un) {
|
|
10714
|
+
this.On = !!(this.Un.ct & this.Hn);
|
|
10526
10715
|
} else {
|
|
10527
|
-
this.
|
|
10716
|
+
this.On = false;
|
|
10528
10717
|
}
|
|
10529
|
-
if (!this.
|
|
10530
|
-
setSignal(this.
|
|
10531
|
-
if (this.
|
|
10718
|
+
if (!this.On) {
|
|
10719
|
+
setSignal(this.In, false);
|
|
10720
|
+
if (this.Ln) {
|
|
10532
10721
|
try {
|
|
10533
|
-
this.
|
|
10722
|
+
this.Vn = untrack(() => this.Ln());
|
|
10534
10723
|
} catch {
|
|
10535
10724
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
10536
10725
|
}
|
|
10537
10726
|
}
|
|
10538
10727
|
}
|
|
10539
|
-
if (_revealUsed) this.gn
|
|
10728
|
+
if (_revealUsed) this.vn?.gn();
|
|
10540
10729
|
}
|
|
10541
10730
|
}
|
|
10542
10731
|
|
|
@@ -10546,10 +10735,10 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
10546
10735
|
const o = new CollectionQueue(e);
|
|
10547
10736
|
if (e === STATUS_ERROR) o.ze = signal(undefined, {
|
|
10548
10737
|
ownedWrite: true,
|
|
10549
|
-
|
|
10738
|
+
qt: true
|
|
10550
10739
|
});
|
|
10551
|
-
if (i) o.
|
|
10552
|
-
const s = o.
|
|
10740
|
+
if (i) o.Ln = i;
|
|
10741
|
+
const s = o.Un = createBoundChildren(r, t, o, e);
|
|
10553
10742
|
// Prime source tracking so reveal registration sees pending sources.
|
|
10554
10743
|
untrack(() => {
|
|
10555
10744
|
let t = false;
|
|
@@ -10558,23 +10747,23 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
10558
10747
|
} catch (e) {
|
|
10559
10748
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
10560
10749
|
}
|
|
10561
|
-
o.
|
|
10750
|
+
o.On = t || !!(s.ct & e) || s.o?.ze instanceof NotReadyError;
|
|
10562
10751
|
});
|
|
10563
10752
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
10564
10753
|
if (u) {
|
|
10565
|
-
o.
|
|
10566
|
-
u.
|
|
10567
|
-
cleanup(() => u.
|
|
10754
|
+
o.vn = u;
|
|
10755
|
+
u.xn(o);
|
|
10756
|
+
cleanup(() => u.Fn(o));
|
|
10568
10757
|
}
|
|
10569
10758
|
return accessor(computed(() => {
|
|
10570
|
-
if (!read(o.
|
|
10759
|
+
if (!read(o.In)) {
|
|
10571
10760
|
const e = read(s);
|
|
10572
|
-
if (!untrack(() => read(o.
|
|
10761
|
+
if (!untrack(() => read(o.In))) return o.yn = true, e;
|
|
10573
10762
|
}
|
|
10574
10763
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
10575
10764
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
10576
10765
|
// outside a `createRevealOrder` scope.
|
|
10577
|
-
if (_revealUsed && read(o.
|
|
10766
|
+
if (_revealUsed && read(o.Rn)) return undefined;
|
|
10578
10767
|
return n(o);
|
|
10579
10768
|
},
|
|
10580
10769
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -10582,7 +10771,7 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
10582
10771
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
10583
10772
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
10584
10773
|
{
|
|
10585
|
-
|
|
10774
|
+
qt: true
|
|
10586
10775
|
}));
|
|
10587
10776
|
}
|
|
10588
10777
|
|
|
@@ -10636,7 +10825,7 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
10636
10825
|
* ```
|
|
10637
10826
|
*/ function createErrorBoundary(e, t) {
|
|
10638
10827
|
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.ze), () => {
|
|
10639
|
-
for (const t of e.
|
|
10828
|
+
for (const t of e.An) {
|
|
10640
10829
|
// Non-computed sources (patch-channel registrations under plain
|
|
10641
10830
|
// owners) are not recomputable — their reset is the record's next
|
|
10642
10831
|
// transition re-applying the patch (re-audit 2, P1-4).
|
|
@@ -10698,12 +10887,12 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
10698
10887
|
computed(() => {
|
|
10699
10888
|
r();
|
|
10700
10889
|
o();
|
|
10701
|
-
s.
|
|
10890
|
+
s.gn();
|
|
10702
10891
|
});
|
|
10703
10892
|
if (i) {
|
|
10704
|
-
s.
|
|
10705
|
-
i.
|
|
10706
|
-
cleanup(() => i.
|
|
10893
|
+
s.Cn = i;
|
|
10894
|
+
i.xn(s);
|
|
10895
|
+
cleanup(() => i.Fn(s));
|
|
10707
10896
|
}
|
|
10708
10897
|
return t;
|
|
10709
10898
|
});
|