@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.3
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 +120 -24
- package/dist/node.cjs +190 -99
- package/dist/prod/core/optimistic.js +37 -15
- package/dist/prod/core/scheduler.js +8 -8
- package/dist/prod/core/verdict.js +7 -0
- package/dist/prod/store/next/optimistic.js +3 -3
- package/dist/prod/store/next/projection.js +107 -45
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/package.json +15 -15
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
package/dist/node.cjs
CHANGED
|
@@ -675,8 +675,8 @@ class GlobalQueue extends Queue {
|
|
|
675
675
|
static Te=null;
|
|
676
676
|
static Ne=null;
|
|
677
677
|
static Ae=null;
|
|
678
|
-
static he=null;
|
|
679
678
|
static Oe=null;
|
|
679
|
+
static he=null;
|
|
680
680
|
static Ie=null;
|
|
681
681
|
static Re=null;
|
|
682
682
|
static Ce=null;
|
|
@@ -691,8 +691,8 @@ class GlobalQueue extends Queue {
|
|
|
691
691
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
692
692
|
// once the gate holds.
|
|
693
693
|
static ye=null;
|
|
694
|
-
static be=null;
|
|
695
694
|
static ve=null;
|
|
695
|
+
static be=null;
|
|
696
696
|
static Pe=null;
|
|
697
697
|
static we=null;
|
|
698
698
|
static De=null;
|
|
@@ -1007,7 +1007,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
1007
1007
|
const t = e ?? globalQueue.L;
|
|
1008
1008
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
1009
1009
|
// which installed the engine's hooks.
|
|
1010
|
-
if (t.H.length) GlobalQueue.
|
|
1010
|
+
if (t.H.length) GlobalQueue.ve(t.H);
|
|
1011
1011
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
1012
1012
|
// so they re-run with the now-committed values visible. The ambient batch
|
|
1013
1013
|
// replays too — laneReadsCommitted records readers whose committed-view
|
|
@@ -1146,7 +1146,7 @@ function transitionComplete(e) {
|
|
|
1146
1146
|
// Override blockage lives with the engine (absent hook = "no optimistic
|
|
1147
1147
|
// blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
|
|
1148
1148
|
// no-ops when the transition holds neither, so no pre-check is needed.
|
|
1149
|
-
if (t && GlobalQueue.
|
|
1149
|
+
if (t && GlobalQueue.be?.(e)) t = false;
|
|
1150
1150
|
t && (e.R = true);
|
|
1151
1151
|
return t;
|
|
1152
1152
|
}
|
|
@@ -1353,7 +1353,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1353
1353
|
const t = e;
|
|
1354
1354
|
if (t.i?.A || t.i?.O) GlobalQueue.Ne(t);
|
|
1355
1355
|
}
|
|
1356
|
-
if (t && e.Ke && e.i !== null) e.i.
|
|
1356
|
+
if (t && e.Ke && e.i !== null) e.i.Ot = null;
|
|
1357
1357
|
let r = n ? e.i?.Je ?? null : e.Nt;
|
|
1358
1358
|
while (r) {
|
|
1359
1359
|
const e = r.At;
|
|
@@ -1382,7 +1382,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1382
1382
|
if (e.i !== null) e.i.Je = null;
|
|
1383
1383
|
} else {
|
|
1384
1384
|
e.Nt = null;
|
|
1385
|
-
e.
|
|
1385
|
+
e.ht = 0;
|
|
1386
1386
|
}
|
|
1387
1387
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1388
1388
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
@@ -1424,7 +1424,7 @@ function runDisposal(e, t) {
|
|
|
1424
1424
|
function childId(e, t) {
|
|
1425
1425
|
let n = e;
|
|
1426
1426
|
while (n.P & CONFIG_TRANSPARENT && n.ie) n = n.ie;
|
|
1427
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1427
|
+
if (n.id != null) return formatId(n.id, t ? n.ht++ : n.ht);
|
|
1428
1428
|
throw new Error("");
|
|
1429
1429
|
}
|
|
1430
1430
|
|
|
@@ -1553,7 +1553,7 @@ function disposeRootSelf(e = true) {
|
|
|
1553
1553
|
Ct: null,
|
|
1554
1554
|
ut: t?.ut ?? globalQueue,
|
|
1555
1555
|
gt: t?.gt || defaultContext,
|
|
1556
|
-
|
|
1556
|
+
ht: 0,
|
|
1557
1557
|
i: null,
|
|
1558
1558
|
ie: t,
|
|
1559
1559
|
dispose: disposeRootSelf
|
|
@@ -1605,7 +1605,7 @@ function unlinkSubs(e) {
|
|
|
1605
1605
|
const n = e.rt;
|
|
1606
1606
|
const i = e.We;
|
|
1607
1607
|
const r = e.yt;
|
|
1608
|
-
if (i !== null) i.yt = r; else t.
|
|
1608
|
+
if (i !== null) i.yt = r; else t.vt = r;
|
|
1609
1609
|
if (r !== null) r.We = i; else {
|
|
1610
1610
|
t.M = i;
|
|
1611
1611
|
if (i === null) {
|
|
@@ -1663,7 +1663,7 @@ function link(e, t, n = false) {
|
|
|
1663
1663
|
// read order within the computation.
|
|
1664
1664
|
const i = t.$e;
|
|
1665
1665
|
if (i !== null && i.ot === e) {
|
|
1666
|
-
i.
|
|
1666
|
+
i.bt &&= n;
|
|
1667
1667
|
return;
|
|
1668
1668
|
}
|
|
1669
1669
|
let r = null;
|
|
@@ -1674,7 +1674,7 @@ function link(e, t, n = false) {
|
|
|
1674
1674
|
r.Me = t.qe;
|
|
1675
1675
|
t.$e = r;
|
|
1676
1676
|
// First touch of this pass: the previous pass's label is stale.
|
|
1677
|
-
r.
|
|
1677
|
+
r.bt = n;
|
|
1678
1678
|
return;
|
|
1679
1679
|
}
|
|
1680
1680
|
}
|
|
@@ -1683,21 +1683,21 @@ function link(e, t, n = false) {
|
|
|
1683
1683
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
1684
1684
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1685
1685
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1686
|
-
const s = e.
|
|
1686
|
+
const s = e.vt;
|
|
1687
1687
|
if (s !== null && s.je === t && (!o || s.Me === t.qe)) {
|
|
1688
1688
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1689
1689
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1690
|
-
if (o) s.
|
|
1690
|
+
if (o) s.bt &&= n; else s.bt = n;
|
|
1691
1691
|
return;
|
|
1692
1692
|
}
|
|
1693
|
-
const u = t.$e = e.
|
|
1693
|
+
const u = t.$e = e.vt = {
|
|
1694
1694
|
ot: e,
|
|
1695
1695
|
je: t,
|
|
1696
1696
|
rt: r,
|
|
1697
1697
|
yt: s,
|
|
1698
1698
|
We: null,
|
|
1699
1699
|
Me: t.qe,
|
|
1700
|
-
|
|
1700
|
+
bt: n
|
|
1701
1701
|
};
|
|
1702
1702
|
if (i !== null) i.rt = u; else t.it = u;
|
|
1703
1703
|
if (s !== null) s.We = u; else e.M = u;
|
|
@@ -1886,12 +1886,12 @@ function handleAsync(e, t, n) {
|
|
|
1886
1886
|
});
|
|
1887
1887
|
}
|
|
1888
1888
|
if (!r && !i) {
|
|
1889
|
-
if (e.i !== null) e.i.
|
|
1889
|
+
if (e.i !== null) e.i.Ot = null;
|
|
1890
1890
|
// A sync landing is the first real answer for a loadingValue node.
|
|
1891
1891
|
e.ze = false;
|
|
1892
1892
|
return t;
|
|
1893
1893
|
}
|
|
1894
|
-
ext(e).
|
|
1894
|
+
ext(e).Ot = t;
|
|
1895
1895
|
let o;
|
|
1896
1896
|
// Settle-time transition re-entry. The loading rail is invisible to
|
|
1897
1897
|
// transactions (#2933): a boundary-caught first load never registers as an
|
|
@@ -1914,7 +1914,7 @@ function handleAsync(e, t, n) {
|
|
|
1914
1914
|
globalQueue.initTransition(t);
|
|
1915
1915
|
};
|
|
1916
1916
|
const handleError = n => {
|
|
1917
|
-
if (e.i?.
|
|
1917
|
+
if (e.i?.Ot !== t) return;
|
|
1918
1918
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1919
1919
|
let i = n instanceof NotReadyError;
|
|
1920
1920
|
if (i && e.ze) {
|
|
@@ -1922,7 +1922,7 @@ function handleAsync(e, t, n) {
|
|
|
1922
1922
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
1923
1923
|
// dependency throws. The dead flight is released so the clock-gated
|
|
1924
1924
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
1925
|
-
if (e.i !== null) e.i.
|
|
1925
|
+
if (e.i !== null) e.i.Ot = null;
|
|
1926
1926
|
parkLoadingWindow(e, n);
|
|
1927
1927
|
e.B = clock;
|
|
1928
1928
|
return;
|
|
@@ -1936,7 +1936,7 @@ function handleAsync(e, t, n) {
|
|
|
1936
1936
|
if (!i) releaseSettledDependents(e);
|
|
1937
1937
|
};
|
|
1938
1938
|
const asyncWrite = (i, r) => {
|
|
1939
|
-
if (e.i?.
|
|
1939
|
+
if (e.i?.Ot !== t) return;
|
|
1940
1940
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1941
1941
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1942
1942
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
@@ -2085,7 +2085,7 @@ function handleAsync(e, t, n) {
|
|
|
2085
2085
|
n = i;
|
|
2086
2086
|
f = true;
|
|
2087
2087
|
if (i.done) u = true;
|
|
2088
|
-
} else if (e.i?.
|
|
2088
|
+
} else if (e.i?.Ot !== t) {
|
|
2089
2089
|
return;
|
|
2090
2090
|
} else if (!i.done) {
|
|
2091
2091
|
s = true;
|
|
@@ -2105,7 +2105,7 @@ function handleAsync(e, t, n) {
|
|
|
2105
2105
|
if (a && l) {
|
|
2106
2106
|
i = n;
|
|
2107
2107
|
c = true;
|
|
2108
|
-
} else if (e.i?.
|
|
2108
|
+
} else if (e.i?.Ot === t) {
|
|
2109
2109
|
u = true;
|
|
2110
2110
|
handleError(n);
|
|
2111
2111
|
settleAutodispose();
|
|
@@ -2171,7 +2171,7 @@ function handleAsync(e, t, n) {
|
|
|
2171
2171
|
if (s) {
|
|
2172
2172
|
o = i;
|
|
2173
2173
|
n = true;
|
|
2174
|
-
} else if (e.i?.
|
|
2174
|
+
} else if (e.i?.Ot === t && !(e.U & REACTIVE_DISPOSED) && flattenIfIterable(i, registerDeferredClose)) ; else {
|
|
2175
2175
|
asyncWrite(i);
|
|
2176
2176
|
settleAutodispose();
|
|
2177
2177
|
}
|
|
@@ -2284,7 +2284,7 @@ function notifyStatus(e, t, n, i, r) {
|
|
|
2284
2284
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
2285
2285
|
// read swallows those, and the async path must match. Re-run the observer
|
|
2286
2286
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
2287
|
-
if (i.
|
|
2287
|
+
if (i.bt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
2288
2288
|
enqueueSub(e);
|
|
2289
2289
|
schedule();
|
|
2290
2290
|
return;
|
|
@@ -2393,7 +2393,7 @@ function recompute(e, t = false) {
|
|
|
2393
2393
|
if (!t) {
|
|
2394
2394
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
2395
2395
|
deleteFromHeap(e, queueFor(e));
|
|
2396
|
-
if (e.i !== null) e.i.
|
|
2396
|
+
if (e.i !== null) e.i.Ot = null;
|
|
2397
2397
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
2398
2398
|
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Nt !== null || e.Ct !== null) {
|
|
2399
2399
|
markDisposal(e);
|
|
@@ -2402,7 +2402,7 @@ function recompute(e, t = false) {
|
|
|
2402
2402
|
t.Je = e.Nt;
|
|
2403
2403
|
e.Ct = null;
|
|
2404
2404
|
e.Nt = null;
|
|
2405
|
-
e.
|
|
2405
|
+
e.ht = 0;
|
|
2406
2406
|
} else ;
|
|
2407
2407
|
}
|
|
2408
2408
|
let i = !!(e.U & REACTIVE_OPTIMISTIC_DIRTY);
|
|
@@ -2466,7 +2466,7 @@ function recompute(e, t = false) {
|
|
|
2466
2466
|
try {
|
|
2467
2467
|
if (!false && e.P & CONFIG_SYNC) {
|
|
2468
2468
|
c = e.Ke(c);
|
|
2469
|
-
if (e.i !== null) e.i.
|
|
2469
|
+
if (e.i !== null) e.i.Ot = null;
|
|
2470
2470
|
e.ze = false;
|
|
2471
2471
|
} else {
|
|
2472
2472
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
@@ -2474,13 +2474,13 @@ function recompute(e, t = false) {
|
|
|
2474
2474
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2475
2475
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2476
2476
|
// iteration drive updates.
|
|
2477
|
-
const t = e.i?.
|
|
2477
|
+
const t = e.i?.Ot;
|
|
2478
2478
|
const n = e.Ke(c);
|
|
2479
2479
|
const i = typeof n === "object" && n !== null;
|
|
2480
|
-
const r = e.i?.
|
|
2480
|
+
const r = e.i?.Ot !== t;
|
|
2481
2481
|
c = r || !i ? n : handleAsync(e, n);
|
|
2482
2482
|
if (!r && !i) {
|
|
2483
|
-
if (e.i !== null) e.i.
|
|
2483
|
+
if (e.i !== null) e.i.Ot = null;
|
|
2484
2484
|
// A sync (non-object) return is the first real answer; async-shaped
|
|
2485
2485
|
// results clear inside handleAsync at their own landing points, and a
|
|
2486
2486
|
// self-registered flight (inFlightChanged — projections) clears when
|
|
@@ -2646,7 +2646,7 @@ function updateIfNecessary(e) {
|
|
|
2646
2646
|
}
|
|
2647
2647
|
}
|
|
2648
2648
|
}
|
|
2649
|
-
if (e.U & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.i?.Le && e.B < clock && !e.i?.
|
|
2649
|
+
if (e.U & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.i?.Le && e.B < clock && !e.i?.Ot) {
|
|
2650
2650
|
recompute(e);
|
|
2651
2651
|
}
|
|
2652
2652
|
e.U = e.U & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -2665,7 +2665,7 @@ function computed(e, t) {
|
|
|
2665
2665
|
Ct: null,
|
|
2666
2666
|
ut: context?.ut ?? globalQueue,
|
|
2667
2667
|
gt: context?.gt ?? defaultContext,
|
|
2668
|
-
|
|
2668
|
+
ht: 0,
|
|
2669
2669
|
Ke: e,
|
|
2670
2670
|
Be: i ? t.loadingValue : undefined,
|
|
2671
2671
|
ft: 0,
|
|
@@ -2675,7 +2675,7 @@ function computed(e, t) {
|
|
|
2675
2675
|
$e: null,
|
|
2676
2676
|
qe: 0,
|
|
2677
2677
|
M: null,
|
|
2678
|
-
|
|
2678
|
+
vt: null,
|
|
2679
2679
|
ie: context,
|
|
2680
2680
|
At: null,
|
|
2681
2681
|
It: null,
|
|
@@ -2711,7 +2711,7 @@ function computed(e, t) {
|
|
|
2711
2711
|
O: undefined,
|
|
2712
2712
|
t: undefined,
|
|
2713
2713
|
$: 0,
|
|
2714
|
-
|
|
2714
|
+
Ot: null,
|
|
2715
2715
|
Le: undefined,
|
|
2716
2716
|
Pt: undefined,
|
|
2717
2717
|
nt: undefined,
|
|
@@ -2740,7 +2740,7 @@ function computed(e, t) {
|
|
|
2740
2740
|
Ct: null,
|
|
2741
2741
|
ut: context?.ut ?? globalQueue,
|
|
2742
2742
|
gt: context?.gt ?? defaultContext,
|
|
2743
|
-
|
|
2743
|
+
ht: 0,
|
|
2744
2744
|
Ke: e,
|
|
2745
2745
|
Be: undefined,
|
|
2746
2746
|
ft: 0,
|
|
@@ -2750,7 +2750,7 @@ function computed(e, t) {
|
|
|
2750
2750
|
$e: null,
|
|
2751
2751
|
qe: 0,
|
|
2752
2752
|
M: null,
|
|
2753
|
-
|
|
2753
|
+
vt: null,
|
|
2754
2754
|
ie: context,
|
|
2755
2755
|
At: null,
|
|
2756
2756
|
It: null,
|
|
@@ -2812,7 +2812,7 @@ function signal(e, t, n = null) {
|
|
|
2812
2812
|
P: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ft ? CONFIG_NO_SNAPSHOT : 0),
|
|
2813
2813
|
Be: e,
|
|
2814
2814
|
M: null,
|
|
2815
|
-
|
|
2815
|
+
vt: null,
|
|
2816
2816
|
B: clock,
|
|
2817
2817
|
st: n,
|
|
2818
2818
|
Tt: n?.i?._t || null,
|
|
@@ -2951,7 +2951,7 @@ function read(e) {
|
|
|
2951
2951
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
2952
2952
|
// recompute don't collect into the probe.
|
|
2953
2953
|
if (pendingCheckActive) {
|
|
2954
|
-
GlobalQueue.
|
|
2954
|
+
GlobalQueue.Oe(e, t, r, i);
|
|
2955
2955
|
} else if (typeof n.Ke === "function") {
|
|
2956
2956
|
prepareComputed(e, false);
|
|
2957
2957
|
}
|
|
@@ -3048,7 +3048,7 @@ function read(e) {
|
|
|
3048
3048
|
const o = !t || currentOptimisticLane !== null && GlobalQueue.me(e, r, t) || e.q === NOT_PENDING || t.P & CONFIG_CHILDREN_FORBIDDEN || stale && e.T && activeTransition !== e.T ? e.Be : e.q;
|
|
3049
3049
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
3050
3050
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
3051
|
-
if (pendingCheckActive) GlobalQueue.
|
|
3051
|
+
if (pendingCheckActive) GlobalQueue.he(e, o);
|
|
3052
3052
|
if (!t && r === e && typeof n.Ke === "function" && e.P & CONFIG_AUTO_DISPOSE && !(r.Xe & STATUS_PENDING) && !e.M) {
|
|
3053
3053
|
unobserved(e);
|
|
3054
3054
|
}
|
|
@@ -3384,7 +3384,14 @@ function isUndefined(e) {
|
|
|
3384
3384
|
const n = e.i?.C !== NOT_PENDING;
|
|
3385
3385
|
const i = n ? unwrapOverride(e.i?.C) : e.Be;
|
|
3386
3386
|
if (typeof t === "function") t = t(i);
|
|
3387
|
-
const r = !!(e.Xe & STATUS_UNINITIALIZED) ||
|
|
3387
|
+
const r = !!(e.Xe & STATUS_UNINITIALIZED) ||
|
|
3388
|
+
// A dirty node's _value is stale (its queued recompute hasn't run — e.g.
|
|
3389
|
+
// a latest() shadow marked by the previous landing's companion snap), so
|
|
3390
|
+
// equality against it must not swallow the write. Without this, a sync
|
|
3391
|
+
// push returning the shadow to that stale value was dropped, the snap
|
|
3392
|
+
// recompute then committed the parent's old value, and the banner showed
|
|
3393
|
+
// the previous transition's target (#3041 follow-up).
|
|
3394
|
+
!!((e.U ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.wt || !e.wt(i, t);
|
|
3388
3395
|
if (!r) {
|
|
3389
3396
|
// Same-value write with an active override still entangles the current
|
|
3390
3397
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -3523,16 +3530,31 @@ function cleanupCompletedLanes(e) {
|
|
|
3523
3530
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3524
3531
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
3525
3532
|
*/ function laneReadsCommitted(e, t, n) {
|
|
3526
|
-
if (e.i?.C !== undefined || !!e.i?.o || !!(t.Xe & STATUS_PENDING))
|
|
3533
|
+
if (e.i?.C !== undefined || !!e.i?.o || !!(t.Xe & STATUS_PENDING)) {
|
|
3534
|
+
// The committed view hides a staged in-flight value that will promote
|
|
3535
|
+
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
3536
|
+
// signals for replay at commit; async memos are excluded from it by the
|
|
3537
|
+
// `_fn` check and reach here instead — a lane-assigned source whose async
|
|
3538
|
+
// already settled (laneAsyncSettled keeps _optimisticLane) served its
|
|
3539
|
+
// committed value to a reader that never re-ran after the landing, so a
|
|
3540
|
+
// pending-gated branch stayed one value behind permanently (#3041
|
|
3541
|
+
// follow-up). Record the reader under the same replay contract.
|
|
3542
|
+
if (e.q !== NOT_PENDING) (activeTransition ?? globalQueue.L).te.add(n);
|
|
3543
|
+
return true;
|
|
3544
|
+
}
|
|
3527
3545
|
if (t === e && stale && n.i?.t !== e) {
|
|
3528
|
-
// The committed view can hide a
|
|
3529
|
-
//
|
|
3530
|
-
//
|
|
3531
|
-
//
|
|
3532
|
-
//
|
|
3533
|
-
//
|
|
3534
|
-
//
|
|
3535
|
-
|
|
3546
|
+
// The committed view can hide a staged write (a lane member — even just
|
|
3547
|
+
// an isPending companion flip — puts the reader "under a lane"). The
|
|
3548
|
+
// staged value commits with no re-delivery (commitPendingNode never
|
|
3549
|
+
// re-notifies), so record the reader for replay at commit — the same
|
|
3550
|
+
// contract gatedRead provides (#2963). gatedRead itself only covers
|
|
3551
|
+
// signal reads where the reading computed differs from the source; the
|
|
3552
|
+
// owner === el memo/self read lands here instead. With a transaction
|
|
3553
|
+
// active the staged value promotes silently at ITS landing, so record
|
|
3554
|
+
// into the transaction (#3041 follow-up: a pending-gated branch that
|
|
3555
|
+
// first read its async source during the landing flush stayed one value
|
|
3556
|
+
// behind permanently); with none, into the ambient batch.
|
|
3557
|
+
if (e.q !== NOT_PENDING) (activeTransition ?? globalQueue.L).te.add(n);
|
|
3536
3558
|
return true;
|
|
3537
3559
|
}
|
|
3538
3560
|
return false;
|
|
@@ -3606,8 +3628,8 @@ function trackOptimisticStore(e) {
|
|
|
3606
3628
|
*/ function installOptimisticEngine() {
|
|
3607
3629
|
if (GlobalQueue.ye !== null) return;
|
|
3608
3630
|
GlobalQueue.ye = optimisticWrite;
|
|
3609
|
-
GlobalQueue.
|
|
3610
|
-
GlobalQueue.
|
|
3631
|
+
GlobalQueue.ve = resolveOptimisticNodes;
|
|
3632
|
+
GlobalQueue.be = transitionBlocked;
|
|
3611
3633
|
GlobalQueue.Pe = cleanupCompletedLanes;
|
|
3612
3634
|
GlobalQueue.we = runLaneEffects;
|
|
3613
3635
|
GlobalQueue.De = gatedRead;
|
|
@@ -3718,7 +3740,7 @@ function collectPendingSources(e) {
|
|
|
3718
3740
|
const r = i.U & REACTIVE_RECOMPUTING_DEPS ? i.$e : undefined;
|
|
3719
3741
|
if (r !== null) {
|
|
3720
3742
|
for (let e = i.it ?? null; e !== null; e = e.rt) {
|
|
3721
|
-
if (!e.
|
|
3743
|
+
if (!e.bt && markWalk(e.ot, t)) return true;
|
|
3722
3744
|
if (e === r) break;
|
|
3723
3745
|
}
|
|
3724
3746
|
}
|
|
@@ -3762,7 +3784,7 @@ function computePendingState(e) {
|
|
|
3762
3784
|
return newQuestionInFlight(n);
|
|
3763
3785
|
}
|
|
3764
3786
|
if (n && e.q !== NOT_PENDING && !hasActiveOverride$1(e)) {
|
|
3765
|
-
return !!(n.U & REACTIVE_MANUAL_WRITE) || !n.i?.
|
|
3787
|
+
return !!(n.U & REACTIVE_MANUAL_WRITE) || !n.i?.Ot && !(n.Xe & STATUS_PENDING) || !!(n.Xe & STATUS_PENDING) && quietPending(n);
|
|
3766
3788
|
}
|
|
3767
3789
|
// `!comp._loading`: a hold created while the loading window is still open is
|
|
3768
3790
|
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
@@ -3876,6 +3898,13 @@ function snapCompanionsToState(e) {
|
|
|
3876
3898
|
|
|
3877
3899
|
function getLatestValueComputed(e) {
|
|
3878
3900
|
let t = e.i?.O;
|
|
3901
|
+
// A shadow disposed while unobserved (its gated reader unmounted at a
|
|
3902
|
+
// landing) is a corpse: sync writes into it equality-swallow against its
|
|
3903
|
+
// frozen _value, and a later read revives it via recompute — clearing
|
|
3904
|
+
// DISPOSED and re-deriving from the committed view, so the banner showed
|
|
3905
|
+
// the previous transition's target (#3041 follow-up). Treat it as absent;
|
|
3906
|
+
// recreation backfills from the in-flight write below.
|
|
3907
|
+
if (t && t.U & REACTIVE_DISPOSED) t = undefined;
|
|
3879
3908
|
if (!t) {
|
|
3880
3909
|
const n = latestReadActive;
|
|
3881
3910
|
setLatestReadActive(false);
|
|
@@ -4064,9 +4093,9 @@ GlobalQueue.Ne = snapCompanionsToState;
|
|
|
4064
4093
|
|
|
4065
4094
|
GlobalQueue.Ae = latestRead;
|
|
4066
4095
|
|
|
4067
|
-
GlobalQueue.
|
|
4096
|
+
GlobalQueue.Oe = pendingCheckRead;
|
|
4068
4097
|
|
|
4069
|
-
GlobalQueue.
|
|
4098
|
+
GlobalQueue.he = recordFreshRead;
|
|
4070
4099
|
|
|
4071
4100
|
GlobalQueue.Ie = applyReask;
|
|
4072
4101
|
|
|
@@ -6972,68 +7001,130 @@ function descend(e, t, n, i, r = false) {
|
|
|
6972
7001
|
* loading windows, handleAsync landings, commit-through-setter) on next
|
|
6973
7002
|
* primitives; the generic draft write-traps are reused from the legacy
|
|
6974
7003
|
* module unchanged.
|
|
6975
|
-
*/
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
7004
|
+
*/
|
|
7005
|
+
/**
|
|
7006
|
+
* Wrap a store proxy as a projection DRAFT: every operation carries the write
|
|
7007
|
+
* override (the derive is the author — its ops must not hit the §6c firewall
|
|
7008
|
+
* gate, even in a continuation after an `await`/`yield` where the sync write
|
|
7009
|
+
* scope has closed).
|
|
7010
|
+
*
|
|
7011
|
+
* FAKE TARGET, not the store proxy itself (#3060): after a proxy trap
|
|
7012
|
+
* returns, the engine runs spec invariant validation against the proxy's
|
|
7013
|
+
* TARGET — [[OwnPropertyKeys]] after ownKeys, [[GetOwnProperty]] after
|
|
7014
|
+
* set/getOwnPropertyDescriptor/defineProperty. With the store proxy as
|
|
7015
|
+
* target those checks re-enter the store's traps OUTSIDE the override
|
|
7016
|
+
* bracket (the trap's finally has already run), so `Object.keys(state)` in
|
|
7017
|
+
* a derive continuation fired the firewall gate and re-threw the
|
|
7018
|
+
* projection's own pending NotReadyError into the derive. A dummy of
|
|
7019
|
+
* matching kind (array/object, same trick as the store's own TargetShape)
|
|
7020
|
+
* keeps invariant validation away from the store entirely; the traps
|
|
7021
|
+
* forward to the closed-over inner proxy inside the bracket.
|
|
7022
|
+
*
|
|
7023
|
+
* Save/restore projectionWriteActive, never hard-reset: the draft can be
|
|
7024
|
+
* driven from inside an enclosing authoritative-write scope (next-store
|
|
7025
|
+
* optimistic derives), and a hard `false` would clobber it mid-derive.
|
|
7026
|
+
*/ function wrapDraft(e, t, n) {
|
|
7027
|
+
const i = {
|
|
7028
|
+
get(i, r) {
|
|
7029
|
+
let o;
|
|
7030
|
+
const s = projectionWriteActive;
|
|
7031
|
+
setWriteOverride(true);
|
|
7032
|
+
setProjectionWriteActive(true);
|
|
7033
|
+
try {
|
|
7034
|
+
o = e[r];
|
|
7035
|
+
} finally {
|
|
7036
|
+
setWriteOverride(false);
|
|
7037
|
+
setProjectionWriteActive(s);
|
|
7038
|
+
}
|
|
7039
|
+
if (r === $TARGET) return o;
|
|
7040
|
+
return typeof o === "object" && o !== null ? wrapDraft(o, t, n) : o;
|
|
7041
|
+
},
|
|
7042
|
+
has(t, n) {
|
|
6981
7043
|
let i;
|
|
6982
7044
|
const r = projectionWriteActive;
|
|
6983
7045
|
setWriteOverride(true);
|
|
6984
7046
|
setProjectionWriteActive(true);
|
|
6985
7047
|
try {
|
|
6986
|
-
i = e
|
|
7048
|
+
i = n in e;
|
|
6987
7049
|
} finally {
|
|
6988
7050
|
setWriteOverride(false);
|
|
6989
7051
|
setProjectionWriteActive(r);
|
|
6990
7052
|
}
|
|
6991
|
-
|
|
6992
|
-
return typeof i === "object" && i !== null ? new Proxy(i, n) : i;
|
|
7053
|
+
return i;
|
|
6993
7054
|
},
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
const
|
|
7055
|
+
set(i, r, o) {
|
|
7056
|
+
if (t && !t()) return true;
|
|
7057
|
+
const s = projectionWriteActive;
|
|
6997
7058
|
setWriteOverride(true);
|
|
6998
7059
|
setProjectionWriteActive(true);
|
|
6999
7060
|
try {
|
|
7000
|
-
|
|
7061
|
+
e[r] = o;
|
|
7062
|
+
n?.();
|
|
7001
7063
|
} finally {
|
|
7002
7064
|
setWriteOverride(false);
|
|
7003
|
-
setProjectionWriteActive(
|
|
7065
|
+
setProjectionWriteActive(s);
|
|
7004
7066
|
}
|
|
7005
|
-
return
|
|
7067
|
+
return true;
|
|
7006
7068
|
},
|
|
7007
|
-
|
|
7008
|
-
if (
|
|
7069
|
+
deleteProperty(i, r) {
|
|
7070
|
+
if (t && !t()) return true;
|
|
7009
7071
|
const o = projectionWriteActive;
|
|
7010
7072
|
setWriteOverride(true);
|
|
7011
7073
|
setProjectionWriteActive(true);
|
|
7012
7074
|
try {
|
|
7013
|
-
|
|
7014
|
-
|
|
7075
|
+
delete e[r];
|
|
7076
|
+
n?.();
|
|
7015
7077
|
} finally {
|
|
7016
7078
|
setWriteOverride(false);
|
|
7017
7079
|
setProjectionWriteActive(o);
|
|
7018
7080
|
}
|
|
7019
7081
|
return true;
|
|
7020
7082
|
},
|
|
7021
|
-
|
|
7022
|
-
|
|
7083
|
+
ownKeys() {
|
|
7084
|
+
const t = projectionWriteActive;
|
|
7085
|
+
setWriteOverride(true);
|
|
7086
|
+
setProjectionWriteActive(true);
|
|
7087
|
+
try {
|
|
7088
|
+
return Reflect.ownKeys(e);
|
|
7089
|
+
} finally {
|
|
7090
|
+
setWriteOverride(false);
|
|
7091
|
+
setProjectionWriteActive(t);
|
|
7092
|
+
}
|
|
7093
|
+
},
|
|
7094
|
+
getOwnPropertyDescriptor(t, n) {
|
|
7095
|
+
let i;
|
|
7023
7096
|
const r = projectionWriteActive;
|
|
7024
7097
|
setWriteOverride(true);
|
|
7025
7098
|
setProjectionWriteActive(true);
|
|
7026
7099
|
try {
|
|
7027
|
-
|
|
7028
|
-
t?.();
|
|
7100
|
+
i = Reflect.getOwnPropertyDescriptor(e, n);
|
|
7029
7101
|
} finally {
|
|
7030
7102
|
setWriteOverride(false);
|
|
7031
7103
|
setProjectionWriteActive(r);
|
|
7032
7104
|
}
|
|
7105
|
+
// The dummy target doesn't hold the key, so a non-configurable report
|
|
7106
|
+
// would violate the proxy invariant. Store descriptors are already
|
|
7107
|
+
// normalized configurable; enforce it for raw leaves too.
|
|
7108
|
+
if (i) i.configurable = true;
|
|
7109
|
+
return i;
|
|
7110
|
+
},
|
|
7111
|
+
defineProperty(i, r, o) {
|
|
7112
|
+
if (t && !t()) return true;
|
|
7113
|
+
const s = projectionWriteActive;
|
|
7114
|
+
setWriteOverride(true);
|
|
7115
|
+
setProjectionWriteActive(true);
|
|
7116
|
+
try {
|
|
7117
|
+
Reflect.defineProperty(e, r, o);
|
|
7118
|
+
n?.();
|
|
7119
|
+
} finally {
|
|
7120
|
+
setWriteOverride(false);
|
|
7121
|
+
setProjectionWriteActive(s);
|
|
7122
|
+
}
|
|
7033
7123
|
return true;
|
|
7034
7124
|
}
|
|
7035
7125
|
};
|
|
7036
|
-
|
|
7126
|
+
// Matching-kind dummy so Array.isArray(draft) answers like the store.
|
|
7127
|
+
return new Proxy(Array.isArray(e) ? [] : {}, i);
|
|
7037
7128
|
}
|
|
7038
7129
|
|
|
7039
7130
|
function createProjectionNextInternal(e, t, n) {
|
|
@@ -7089,7 +7180,7 @@ function runProjectionComputedNext(e, t, n, i, r) {
|
|
|
7089
7180
|
// seed so draft writes cannot tear through to readers (#2988). Every commit
|
|
7090
7181
|
// point reconciles the shadow through the normal commit path.
|
|
7091
7182
|
const l = o.ze ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
|
|
7092
|
-
const f =
|
|
7183
|
+
const f = wrapDraft(e, () => !s || o.i?.Ot === u, r);
|
|
7093
7184
|
storeSetterNext(f, r => {
|
|
7094
7185
|
u = t(l ?? r);
|
|
7095
7186
|
s = true;
|
|
@@ -7144,8 +7235,8 @@ function installNextBlockedHalf() {
|
|
|
7144
7235
|
e.clear();
|
|
7145
7236
|
};
|
|
7146
7237
|
}
|
|
7147
|
-
const e = GlobalQueue.
|
|
7148
|
-
GlobalQueue.
|
|
7238
|
+
const e = GlobalQueue.be;
|
|
7239
|
+
GlobalQueue.be = t => {
|
|
7149
7240
|
for (const e of t.j) {
|
|
7150
7241
|
const t = e?.[$TARGET];
|
|
7151
7242
|
const n = t?.fam?.node;
|
|
@@ -8162,8 +8253,8 @@ class RevealController {
|
|
|
8162
8253
|
Ft: true
|
|
8163
8254
|
});
|
|
8164
8255
|
An=true;
|
|
8165
|
-
|
|
8166
|
-
|
|
8256
|
+
On=true;
|
|
8257
|
+
hn=false;
|
|
8167
8258
|
constructor(e, t) {
|
|
8168
8259
|
this._n = e;
|
|
8169
8260
|
this.Tn = t;
|
|
@@ -8221,10 +8312,10 @@ class RevealController {
|
|
|
8221
8312
|
untrack(() => this.pn());
|
|
8222
8313
|
}
|
|
8223
8314
|
pn(e, t) {
|
|
8224
|
-
if (this.
|
|
8225
|
-
this.
|
|
8315
|
+
if (this.hn) return;
|
|
8316
|
+
this.hn = true;
|
|
8226
8317
|
const n = this.An;
|
|
8227
|
-
const i = this.
|
|
8318
|
+
const i = this.On;
|
|
8228
8319
|
try {
|
|
8229
8320
|
const n = e ?? read(this.cn), i = untrack(this._n), r = i === "sequential" && !!untrack(this.Tn), o = t ?? r;
|
|
8230
8321
|
if (n) {
|
|
@@ -8276,10 +8367,10 @@ class RevealController {
|
|
|
8276
8367
|
}
|
|
8277
8368
|
} finally {
|
|
8278
8369
|
this.An = this.sn();
|
|
8279
|
-
this.
|
|
8280
|
-
this.
|
|
8370
|
+
this.On = this.fn();
|
|
8371
|
+
this.hn = false;
|
|
8281
8372
|
}
|
|
8282
|
-
if (this.dn && (n !== this.An || i !== this.
|
|
8373
|
+
if (this.dn && (n !== this.An || i !== this.On)) this.dn.pn();
|
|
8283
8374
|
}
|
|
8284
8375
|
}
|
|
8285
8376
|
|
|
@@ -8299,8 +8390,8 @@ class CollectionQueue extends Queue {
|
|
|
8299
8390
|
});
|
|
8300
8391
|
En;
|
|
8301
8392
|
Sn=false;
|
|
8302
|
-
|
|
8303
|
-
|
|
8393
|
+
vn;
|
|
8394
|
+
bn=ON_INIT;
|
|
8304
8395
|
constructor(e) {
|
|
8305
8396
|
super();
|
|
8306
8397
|
this.gn = e;
|
|
@@ -8311,16 +8402,16 @@ class CollectionQueue extends Queue {
|
|
|
8311
8402
|
}
|
|
8312
8403
|
notify(e, t, n, i) {
|
|
8313
8404
|
if (!(t & this.gn)) return super.notify(e, t, n, i);
|
|
8314
|
-
if (this.Sn && this.
|
|
8405
|
+
if (this.Sn && this.vn) {
|
|
8315
8406
|
const e = untrack(() => {
|
|
8316
8407
|
try {
|
|
8317
|
-
return this.
|
|
8408
|
+
return this.vn();
|
|
8318
8409
|
} catch {
|
|
8319
8410
|
return ON_INIT;
|
|
8320
8411
|
}
|
|
8321
8412
|
});
|
|
8322
|
-
if (e !== this.
|
|
8323
|
-
this.
|
|
8413
|
+
if (e !== this.bn) {
|
|
8414
|
+
this.bn = e;
|
|
8324
8415
|
this.Sn = false;
|
|
8325
8416
|
this.un.clear();
|
|
8326
8417
|
}
|
|
@@ -8367,9 +8458,9 @@ class CollectionQueue extends Queue {
|
|
|
8367
8458
|
}
|
|
8368
8459
|
if (!this.ln) {
|
|
8369
8460
|
setSignal(this.cn, false);
|
|
8370
|
-
if (this.
|
|
8461
|
+
if (this.vn) {
|
|
8371
8462
|
try {
|
|
8372
|
-
this.
|
|
8463
|
+
this.bn = untrack(() => this.vn());
|
|
8373
8464
|
} catch {
|
|
8374
8465
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
8375
8466
|
}
|
|
@@ -8387,7 +8478,7 @@ function createCollectionBoundary(e, t, n, i) {
|
|
|
8387
8478
|
ownedWrite: true,
|
|
8388
8479
|
Ft: true
|
|
8389
8480
|
});
|
|
8390
|
-
if (i) o.
|
|
8481
|
+
if (i) o.vn = i;
|
|
8391
8482
|
const s = o.yn = createBoundChildren(r, t, o, e);
|
|
8392
8483
|
// Prime source tracking so reveal registration sees pending sources.
|
|
8393
8484
|
untrack(() => {
|