@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.20
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-shared.js +6505 -0
- package/dist/dev.attribution.js +3484 -0
- package/dist/dev.js +10227 -9508
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +112 -0
- package/dist/observe/attribution.js +7 -0
- package/dist/observe/boundaries.js +696 -0
- package/dist/observe/core/action.js +182 -0
- package/dist/observe/core/async.js +824 -0
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +280 -0
- package/dist/observe/core/attribution-hooks.js +83 -0
- package/dist/observe/core/attribution-queries.js +43 -0
- package/dist/observe/core/attribution.js +3079 -0
- package/dist/observe/core/constants.js +269 -0
- package/dist/observe/core/context.js +63 -0
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +1707 -0
- package/dist/observe/core/dev.js +394 -0
- package/dist/observe/core/effect.js +193 -0
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/error.js +82 -0
- package/dist/observe/core/external.js +97 -0
- package/dist/observe/core/graph.js +162 -0
- package/dist/observe/core/heap.js +124 -0
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/invariants.js +12 -0
- package/dist/observe/core/lanes.js +972 -0
- package/dist/observe/core/owner.js +371 -0
- package/dist/observe/core/scheduler.js +1157 -0
- package/dist/observe/core/truth.js +47 -0
- package/dist/observe/core/verdict.js +470 -0
- package/dist/observe/deferred.js +186 -0
- package/dist/observe/flatten.js +79 -0
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +71 -0
- package/dist/observe/map.js +593 -0
- package/dist/observe/reveal.js +212 -0
- package/dist/observe/signals.js +717 -0
- package/dist/observe/store/affects.js +142 -0
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/hooks.js +16 -0
- package/dist/observe/store/index.js +47 -0
- package/dist/observe/store/optimistic.js +713 -0
- package/dist/observe/store/projection.js +345 -0
- package/dist/observe/store/reconcile.js +281 -0
- package/dist/observe/store/store.js +2127 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/target.js +46 -0
- package/dist/observe/store/types.js +83 -0
- package/dist/observe/store/utils.js +1063 -0
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +98 -112
- package/dist/prod/attribution.js +45 -0
- package/dist/prod/boundaries.js +578 -468
- package/dist/prod/core/action.js +92 -59
- package/dist/prod/core/async.js +522 -336
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +168 -44
- package/dist/prod/core/context.js +12 -16
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +1345 -627
- package/dist/prod/core/dev.js +123 -1
- package/dist/prod/core/effect.js +113 -80
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/error.js +18 -4
- package/dist/prod/core/external.js +6 -7
- package/dist/prod/core/graph.js +119 -72
- package/dist/prod/core/heap.js +85 -109
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/invariants.js +1 -32
- package/dist/prod/core/lanes.js +931 -132
- package/dist/prod/core/owner.js +192 -129
- package/dist/prod/core/scheduler.js +948 -642
- package/dist/prod/core/truth.js +47 -0
- package/dist/prod/core/verdict.js +409 -420
- package/dist/prod/deferred.js +184 -0
- package/dist/prod/flatten.js +77 -0
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +40 -16
- package/dist/prod/map.js +481 -211
- package/dist/prod/reveal.js +212 -0
- package/dist/prod/signals.js +401 -84
- package/dist/prod/store/affects.js +142 -0
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/hooks.js +16 -0
- package/dist/prod/store/index.js +27 -18
- package/dist/prod/store/optimistic.js +707 -0
- package/dist/prod/store/projection.js +331 -0
- package/dist/prod/store/reconcile.js +281 -0
- package/dist/prod/store/store.js +1952 -267
- package/dist/prod/store/storePath.js +1 -1
- package/dist/prod/store/target.js +43 -0
- package/dist/prod/store/types.js +83 -0
- package/dist/prod/store/utils.js +997 -138
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/affects.d.ts +12 -30
- package/dist/types/attribution.d.ts +19 -0
- package/dist/types/attribution.prod.d.ts +22 -0
- package/dist/types/boundaries.d.ts +99 -124
- package/dist/types/carved.d.ts +1 -0
- package/dist/types/core/action.d.ts +23 -9
- package/dist/types/core/async.d.ts +34 -6
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +307 -8
- package/dist/types/core/attribution-queries.d.ts +24 -0
- package/dist/types/core/attribution.d.ts +802 -72
- package/dist/types/core/constants.d.ts +195 -38
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +295 -65
- package/dist/types/core/dev.d.ts +509 -22
- package/dist/types/core/effect.d.ts +1 -1
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/error.d.ts +18 -1
- package/dist/types/core/graph.d.ts +40 -1
- package/dist/types/core/heap.d.ts +5 -5
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +11 -7
- package/dist/types/core/invariants.d.ts +1 -26
- package/dist/types/core/lanes.d.ts +74 -43
- package/dist/types/core/owner.d.ts +27 -9
- package/dist/types/core/scheduler.d.ts +353 -102
- package/dist/types/core/truth.d.ts +18 -0
- package/dist/types/core/types.d.ts +97 -71
- package/dist/types/core/verdict.d.ts +35 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/flatten.d.ts +8 -0
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +33 -7
- package/dist/types/map.d.ts +4 -2
- package/dist/types/reveal.d.ts +19 -0
- package/dist/types/signals.d.ts +196 -45
- package/dist/types/store/affects.d.ts +12 -0
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/hooks.d.ts +62 -0
- package/dist/types/store/index.d.ts +42 -15
- package/dist/types/store/optimistic.d.ts +24 -45
- package/dist/types/store/projection.d.ts +17 -68
- package/dist/types/store/reconcile.d.ts +3 -46
- package/dist/types/store/store.d.ts +133 -136
- package/dist/types/store/storePath.d.ts +1 -1
- package/dist/types/store/target.d.ts +166 -0
- package/dist/types/store/types.d.ts +105 -0
- package/dist/types/store/utils.d.ts +188 -0
- package/package.json +31 -26
- package/dist/node.cjs +0 -8745
- package/dist/prod/core/optimistic.js +0 -265
- package/dist/prod/store/next/optimistic.js +0 -385
- package/dist/prod/store/next/projection.js +0 -172
- package/dist/prod/store/next/reconcile.js +0 -331
- package/dist/prod/store/next/store.js +0 -1499
- package/dist/prod/store/next/target.js +0 -20
- package/dist/types/core/optimistic.d.ts +0 -6
- package/dist/types/store/next/optimistic.d.ts +0 -20
- package/dist/types/store/next/projection.d.ts +0 -8
- package/dist/types/store/next/reconcile.d.ts +0 -3
- package/dist/types/store/next/store.d.ts +0 -77
- package/dist/types/store/next/target.d.ts +0 -117
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -21
- package/dist/types-cjs/core/attribution-hooks.d.cts +0 -52
- package/dist/types-cjs/core/attribution.d.cts +0 -186
- package/dist/types-cjs/core/constants.d.cts +0 -97
- package/dist/types-cjs/core/context.d.cts +0 -36
- package/dist/types-cjs/core/core.d.cts +0 -163
- package/dist/types-cjs/core/dev.d.cts +0 -81
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -47
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -6
- package/dist/types-cjs/core/heap.d.cts +0 -22
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -44
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -180
- package/dist/types-cjs/core/types.d.cts +0 -192
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/signals.d.cts +0 -624
- package/dist/types-cjs/store/index.d.cts +0 -19
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
- package/dist/types-cjs/store/next/projection.d.cts +0 -8
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
- package/dist/types-cjs/store/next/store.d.cts +0 -77
- package/dist/types-cjs/store/next/target.d.cts +0 -117
- 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/types-cjs/store/store.d.cts +0 -138
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -1,476 +1,465 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { REACTIVE_PROBED, REACTIVE_WINDOW, CONFIG_VERDICT, CONFIG_ASYNC, CONFIG_CHILDREN_FORBIDDEN, CONFIG_OVERRIDE, STATUS_ERROR, CONFIG_GUESS, STATUS_PENDING, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, CONFIG_STAGED_ERROR, REACTIVE_STAGED_READ, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, CONFIG_INPUTS_PUBLISHED, REACTIVE_JOINED, REACTIVE_LANE_READ } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { context, creatorPass, tracking, creatorReads, setVerdict, verdict, prepareComputed, pullComputed, joinPass, markLateLinker, spectating, unflushedValue, bornInto } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
7
7
|
import { link } from "./graph.js";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
import "./
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* wakeSuppressedProbes): held node → the wrapper computeds that probed it.
|
|
35
|
-
* Entries die with the hold — the commit/revert snap clears them.
|
|
36
|
-
*/ const suppressedProbes = new Map;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get or create the pending signal for a node (lazy).
|
|
40
|
-
* Used by isPending() to track pending state reactively.
|
|
41
|
-
*/
|
|
42
|
-
/** #3038: register a companion-carrying firewall child on its firewall's
|
|
43
|
-
* companion set and arm the post-recompute snap (CONFIG_CHILD_COMPANIONS is
|
|
44
|
-
* the one-load gate at the call sites). The snap then iterates exactly the
|
|
45
|
-
* children someone asked verdicts of — O(companions) — never the full
|
|
46
|
-
* `_child` chain, which carries one node per materialized leaf (the
|
|
47
|
-
* O(all-leaves-ever-read)-per-update pathology). Entries are permanent like
|
|
48
|
-
* the companions themselves; a store with no leaf-level isPending()/latest()
|
|
49
|
-
* reads never allocates the set or pays the walk. */ function markFirewallChildCompanions(e) {
|
|
50
|
-
const t = e.lt;
|
|
51
|
-
if (!t) return;
|
|
52
|
-
t.T |= CONFIG_CHILD_COMPANIONS;
|
|
53
|
-
(ext(t).Nt ??= new Set).add(e);
|
|
9
|
+
import { display, verdictLane } from "./lanes.js";
|
|
10
|
+
|
|
11
|
+
import { installVerdictHooks, GlobalQueue, flushTransaction, txOf, passLane, staleReader, globalQueue, joinFuture, stagedReaders, queuePendingNode, setPassLane } from "./scheduler.js";
|
|
12
|
+
|
|
13
|
+
import { laneValueOf } from "./truth.js";
|
|
14
|
+
|
|
15
|
+
// Verdicts (plan sec. 28 replay, 2026-10-02; maintainer, 2026-10-01: verdicts are
|
|
16
|
+
// optimistic state the system supplies). `isPending(fn)` asks whether what
|
|
17
|
+
// `fn` reads is final; `latest(fn)` reads the proposal — the staged write or
|
|
18
|
+
// landing, the lane's value — instead of the screen. A verdict is a guess
|
|
19
|
+
// ("pending, until this lands"; "the proposal is the value") and its readers
|
|
20
|
+
// break out of the hold the way a lane's do: work of the holder's verdict
|
|
21
|
+
// lane (lanes.ts), shown now, re-derived at the landing, ending with it. A
|
|
22
|
+
// verdict reader is a frame reader: its plain reads of held nodes see the
|
|
23
|
+
// screen (core.ts `frameRead`), so `[isPending(x), x()]` never pairs the
|
|
24
|
+
// fresh value with pending (A10).
|
|
25
|
+
/** A verdict reader whose answer this flush could not give yet: the node it
|
|
26
|
+
* asked about is staged and not held — whether it will be is the seam's
|
|
27
|
+
* verdict. It read the staging as the screen: if the flush parks it runs
|
|
28
|
+
* again next round, as lane work that did the same does (`stagedReaders`,
|
|
29
|
+
* lanes.ts — entering the verdict lane then voids what it staged); if it
|
|
30
|
+
* commits, the answer stood. */
|
|
31
|
+
function watchVerdict(e, t = false) {
|
|
32
|
+
if (t) e.R |= REACTIVE_PROBE_UNANSWERED;
|
|
33
|
+
stagedReaders.push(e);
|
|
54
34
|
}
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
ext(e).Ge = t;
|
|
64
|
-
e.T |= CONFIG_HAS_COMPANIONS;
|
|
65
|
-
markFirewallChildCompanions(e);
|
|
66
|
-
ext(t).It = e;
|
|
67
|
-
if (computePendingState(e)) setSignal(t, true);
|
|
68
|
-
}
|
|
69
|
-
return t;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function collectPendingSources(e) {
|
|
73
|
-
if (!pendingProbe) return;
|
|
74
|
-
pendingProbe.sources.add(e);
|
|
75
|
-
const t = e.lt || e;
|
|
76
|
-
if (t !== e) pendingProbe.sources.add(t);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Adds a node to the active isPending() probe without reading it. The store's
|
|
81
|
-
* untracked-probe fallback (`witnessAffectsMark`) reaches this through
|
|
82
|
-
* `GlobalQueue._witnessAffects` — its callers guard on `pendingCheckActive`,
|
|
83
|
-
* which only flips inside `isPending()`, so the hook is always installed by
|
|
84
|
-
* the time it can fire.
|
|
85
|
-
*/ function witnessAffects(e) {
|
|
86
|
-
pendingProbe?.sources.add(e);
|
|
36
|
+
/** The reading pass is the holder's verdict lane's — unless already lane
|
|
37
|
+
* work, or already the transaction's (it derives from the future — a held
|
|
38
|
+
* node's, or the staging of a write this flush may hold — and the verdict
|
|
39
|
+
* does not rescue it: its result shows at the landing, re-derived). A lane
|
|
40
|
+
* read, for `recompute`'s tail (REACTIVE_LANE_READ). */ function route(e, t) {
|
|
41
|
+
if (!passLane && !(e.R & (REACTIVE_JOINED | REACTIVE_STAGED_READ))) setPassLane(verdictLane(t));
|
|
42
|
+
e.R |= REACTIVE_LANE_READ;
|
|
87
43
|
}
|
|
88
44
|
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (r !== null) {
|
|
117
|
-
for (let e = i.nt ?? null; e !== null; e = e.it) {
|
|
118
|
-
if (!e.me && markWalk(e.ut, t)) return true;
|
|
119
|
-
if (e === r) break;
|
|
120
|
-
}
|
|
45
|
+
/** A verdict reader served a flight's committed value (the A31 frame-reader
|
|
46
|
+
* case) still observed the flight — A15's stale reader "derives from the
|
|
47
|
+
* flight all the same": the frame holds (the flush's transaction opens if
|
|
48
|
+
* none has, as the throw would have had it), the reader is that
|
|
49
|
+
* transaction's verdict lane's (shown now, with the flight's verdict), and
|
|
50
|
+
* re-derives at the landing (REACTIVE_FRAME_READ — which is also what makes
|
|
51
|
+
* it a blocker of the hold, `blockedBy`; a probe alone is neither). The
|
|
52
|
+
* hold is on the flight: a reader served committed never goes pending, so
|
|
53
|
+
* the transaction waits on it only through the flight's node — one that
|
|
54
|
+
* went pending this flush is queued for the seam to hold; one in the air
|
|
55
|
+
* from before, held by nobody (a lane's derivation whose lane dissolved at
|
|
56
|
+
* its parent's landing with the flight still up; a flight nothing displayed,
|
|
57
|
+
* #3305), is registered by this, its first observer (A15, #3458): queued for
|
|
58
|
+
* the seam as if it had gone pending here, so the transaction has an entry
|
|
59
|
+
* for what it now shows a reader of. Held by nothing, it landed at this very
|
|
60
|
+
* seam and its `_reruns` re-derived the reader into the same observation,
|
|
61
|
+
* every flush (fuzzer F12). True when the reader is served the committed
|
|
62
|
+
* value — not over a flight committed beneath inputs already on screen (A15
|
|
63
|
+
* reveal corollary, #3305): that value would tear against them, and the
|
|
64
|
+
* reveal observes the flight. Nor for a reader born into the flight's
|
|
65
|
+
* transaction (`bornInto`, #4010): it has no screen — it waits on the flight
|
|
66
|
+
* with the rest of its frame. */ function observeFlight(e, t) {
|
|
67
|
+
if (t.l & CONFIG_INPUTS_PUBLISHED || t.l & CONFIG_HELD && bornInto(e, txOf(t))) return false;
|
|
68
|
+
if (globalQueue.Y) {
|
|
69
|
+
joinFuture(null);
|
|
70
|
+
if (!(t.l & CONFIG_HELD)) queuePendingNode(t);
|
|
71
|
+
verdictRead(e, flushTransaction, true);
|
|
121
72
|
}
|
|
122
|
-
return
|
|
73
|
+
return true;
|
|
123
74
|
}
|
|
124
75
|
|
|
125
|
-
/**
|
|
126
|
-
|
|
76
|
+
/** Verdict windows. Inside `latest(fn)` a read of a held node serves the
|
|
77
|
+
* proposal (above the async, the held write; below it, the committed value
|
|
78
|
+
* — nothing newer exists) instead of joining or throwing; inside
|
|
79
|
+
* `isPending(fn)` a read records whether what it saw is final. Either way
|
|
80
|
+
* the reader breaks out: work of the holder's verdict lane, shown now and
|
|
81
|
+
* re-derived at the landing. */ let latestActive = false;
|
|
82
|
+
|
|
83
|
+
let probing = false;
|
|
84
|
+
|
|
85
|
+
let probeFound = false;
|
|
86
|
+
|
|
87
|
+
/** A verdict read of a node a transaction (or lane) holds: the reading pass
|
|
88
|
+
* is the holder's verdict lane's and re-derives at the holder's landing
|
|
89
|
+
* (`_reruns`, as a stale reader). `isPending` flips at the landing with no
|
|
90
|
+
* value notifying anyone (a held write's commit; a held landing's): its
|
|
91
|
+
* reader re-derives there. `latest` shows the proposal that lands — a
|
|
92
|
+
* rewrite or a landing reaches its reader through the link it holds — so a
|
|
93
|
+
* re-run would only repeat the frame. */ function verdictRead(e, t, r) {
|
|
94
|
+
route(e, t);
|
|
95
|
+
if (r) staleReader(e, t); else if (probing && t.En[t.En.length - 1] !== e) t.En.push(e);
|
|
127
96
|
}
|
|
128
97
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
98
|
+
/** A verdict read of a node staged or in flight but not held yet: whether it
|
|
99
|
+
* will be is the seam's.
|
|
100
|
+
*
|
|
101
|
+
* `isPending` asks exactly that — final unless the flush parks — so its
|
|
102
|
+
* reader cannot be answered before the seam: a flush that has joined a
|
|
103
|
+
* transaction parks, and the node with it — the reader is that
|
|
104
|
+
* transaction's verdict lane's now; before anything joined, the reader
|
|
105
|
+
* watches the seam and runs again if the flush parks (a plain sync write
|
|
106
|
+
* never glitches it true).
|
|
107
|
+
*
|
|
108
|
+
* `latest` has its answer either way — the proposal — but its reader's
|
|
109
|
+
* membership is the seam's too: the frame opens no transaction for it
|
|
110
|
+
* (#4365 — one opened for the read alone made a plain read after the window
|
|
111
|
+
* take it for a hold, `stagedScreen`, and serve the screen beside the
|
|
112
|
+
* staging in a frame nothing held). The reader watches the seam like a
|
|
113
|
+
* probe before anything joined: its pass is the frame's, and runs again in
|
|
114
|
+
* the verdict lane if the flush parks. Once the flush has joined a
|
|
115
|
+
* transaction, the reader is its verdict lane's at once; a pass that also
|
|
116
|
+
* read the frame's own stagings plainly (REACTIVE_STAGED_READ) stays the
|
|
117
|
+
* frame's (`route` does not move it). */ function provisionalVerdict(e, t) {
|
|
118
|
+
if (flushTransaction) {
|
|
119
|
+
if (probing && t) probeFound = true;
|
|
120
|
+
verdictRead(e, flushTransaction);
|
|
121
|
+
if (probing && e.R & REACTIVE_STAGED_READ) watchVerdict(e);
|
|
122
|
+
return;
|
|
133
123
|
}
|
|
134
|
-
|
|
124
|
+
// Before anything joined, a staging that would not be final held has no
|
|
125
|
+
// answer yet: whatever the seam decides, the pass runs again — a later
|
|
126
|
+
// plain read of the same pass may route it into the verdict lane
|
|
127
|
+
// (`observeFlight`), which the seam must not take as this probe's answer.
|
|
128
|
+
// `latest` opens no transaction for its answer either (#4365): the plain
|
|
129
|
+
// read of a staging after it took one opened for it for a hold and paired
|
|
130
|
+
// the staging with the screen, in a frame nothing held. Its pass is the
|
|
131
|
+
// frame's — whole — and re-derives once if the flush parks (unanswered:
|
|
132
|
+
// its membership is the seam's, not the transaction it joins).
|
|
133
|
+
watchVerdict(e, !probing || t);
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
function newQuestionInFlight(e) {
|
|
145
|
-
return !!(e.S & STATUS_PENDING) && !(e.S & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function computePendingState(e) {
|
|
149
|
-
const t = e;
|
|
150
|
-
if (t.ie & REACTIVE_DISPOSED) return false;
|
|
151
|
-
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
152
|
-
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
153
|
-
// so the one walk covers direct marks, derivation, and companion chains.
|
|
154
|
-
if (markCovered(e)) return true;
|
|
155
|
-
const n = e.lt;
|
|
156
|
-
if (e.o?.It) {
|
|
157
|
-
const t = e.o?.It;
|
|
158
|
-
const n = t.lt || t;
|
|
159
|
-
return newQuestionInFlight(n);
|
|
160
|
-
}
|
|
161
|
-
if (n && e.Pe !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
162
|
-
return !!(n.ie & REACTIVE_MANUAL_WRITE) || !n.o?.Ee && !(n.S & STATUS_PENDING) || !!(n.S & STATUS_PENDING) && quietPending(n);
|
|
163
|
-
}
|
|
164
|
-
// `!comp._loading`: a hold created while the loading window is still open is
|
|
165
|
-
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
166
|
-
// rest of the window (the UNINITIALIZED check suppresses exactly this frame
|
|
167
|
-
// for windowless first loads; born-committed nodes need their own gate, #2990).
|
|
168
|
-
if (e.Pe !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ie) {
|
|
169
|
-
if (hasActiveOverride(e)) return !e.Ue || !e.Ue(e.Pe, unwrapOverride(e.o?.De));
|
|
136
|
+
/** A19 exc. 2 / A24: a flight that re-asks the question already answered
|
|
137
|
+
* (a `refresh()`, a poll) is quiet; a node pending through others is quiet
|
|
138
|
+
* when every flight it waits on is. */ function quietPending(e) {
|
|
139
|
+
const t = e.T;
|
|
140
|
+
if (!t) return false;
|
|
141
|
+
if (t.se) {
|
|
142
|
+
for (const e of t.se) if (!e.T?.Ve) return false;
|
|
170
143
|
return true;
|
|
171
144
|
}
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function syncCompanions(e, t) {
|
|
176
|
-
if (e.o?.Ge) updatePendingSignal(e);
|
|
177
|
-
if (e.o?.ge) setSignal(e.o?.ge, t);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function updatePendingSignal(e) {
|
|
181
|
-
if (e.o?.Ge) {
|
|
182
|
-
setSignal(e.o?.Ge, computePendingState(e));
|
|
183
|
-
}
|
|
184
|
-
if (e.o?.ge) updatePendingSignal(e.o?.ge);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function updateChildCompanions(e) {
|
|
188
|
-
const t = e.o?.Nt;
|
|
189
|
-
if (t === undefined) return;
|
|
190
|
-
for (const e of t) updatePendingSignal(e);
|
|
145
|
+
return t.Ve;
|
|
191
146
|
}
|
|
192
147
|
|
|
193
|
-
/**
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (e.o?.Ge || e.o?.ge) n(e);
|
|
208
|
-
for (let t = e.u; t !== null; t = t.fe) visit(t.ae);
|
|
209
|
-
for (let t = e.o?.l ?? null; t !== null; t = t.ce) {
|
|
210
|
-
visit(t);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
visit(e);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* The correction half of the provisional fresh-read suppression (see
|
|
218
|
-
* collectPending): fired from the sanctioned async-registration site
|
|
219
|
-
* (GlobalQueue.notify) when a transaction gains an in-flight async blocker.
|
|
220
|
-
* Every probe that returned "not pending" purely because it read a held
|
|
221
|
-
* value belonging to that transaction re-runs — its re-probe now sees the
|
|
222
|
-
* live blocker through heldAwaitingAsync and lands the true verdict. The
|
|
223
|
-
* wake mirrors a companion write's own notification (optimistic-dirty on the
|
|
224
|
-
* companion's lane) so the corrected verdict commits and flushes immediately
|
|
225
|
-
* instead of being held with the transaction it reports on.
|
|
226
|
-
*/ function wakeSuppressedProbes(e) {
|
|
227
|
-
if (suppressedProbes.size === 0) return;
|
|
228
|
-
let t = false;
|
|
229
|
-
for (const [n, i] of suppressedProbes) {
|
|
230
|
-
const r = n._e;
|
|
231
|
-
const s = r ? currentTransition(r) : null;
|
|
232
|
-
if (!s) {
|
|
233
|
-
suppressedProbes.delete(n);
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
if (s !== e) continue;
|
|
237
|
-
suppressedProbes.delete(n);
|
|
238
|
-
const o = n.o?.Ge?.o?.Be;
|
|
239
|
-
for (const e of i) {
|
|
240
|
-
if (e.ie & REACTIVE_DISPOSED) continue;
|
|
241
|
-
e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
242
|
-
if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.Be = undefined;
|
|
243
|
-
enqueueSub(e);
|
|
244
|
-
t = true;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
if (t) schedule();
|
|
148
|
+
/** `isPending`'s answer for a held node (A19), relative to what the reader
|
|
149
|
+
* sees — a verdict reader is a frame reader and sees the committed value: a
|
|
150
|
+
* flight still up (cause ii) is not final unless quiet; a held write or
|
|
151
|
+
* landing (staged — cause i/iii) is not final unless it answers the question
|
|
152
|
+
* already shown (a quiet re-ask, through its reveal), is the node's first
|
|
153
|
+
* landing (commit #0: loading, not pending), or the probe sits inside a
|
|
154
|
+
* `latest` window, whose view of the node IS the proposal (A10: a reader
|
|
155
|
+
* that observed the fresh value is not told it is pending; inside `latest`,
|
|
156
|
+
* `isPending` asks whether the latest view is final). A member of a held
|
|
157
|
+
* frame with neither is final. A24: pending iff a value change is in
|
|
158
|
+
* flight — a staging equal to what is displayed changes nothing when it
|
|
159
|
+
* lands: final now (maintainer, 2026-10-02). */ function heldNotFinal(e) {
|
|
160
|
+
if ((e.m & STATUS_PENDING) !== 0 && !quietPending(e)) return true;
|
|
161
|
+
return e.ue !== NOT_PENDING && !latestActive && !e.T.Ve && !(e.m & STATUS_UNINITIALIZED) && (!!e.T.Te || !e.ye || !e.ye(e.le, e.ue));
|
|
248
162
|
}
|
|
249
163
|
|
|
250
|
-
function
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if ((n.o?.De === undefined || n.o?.De === NOT_PENDING) && n.Pe === NOT_PENDING && !Object.is(n.be, e.be) && !(n.ie & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
265
|
-
n.ie |= REACTIVE_DIRTY;
|
|
266
|
-
insertIntoHeap(n, queueFor(n));
|
|
267
|
-
insertSubs(n);
|
|
268
|
-
schedule();
|
|
269
|
-
}
|
|
270
|
-
snapCompanionsToState(n);
|
|
164
|
+
/** `isPending`'s answer for an unheld node whose flight is up (cause ii). */ function pendingVerdict(e, t) {
|
|
165
|
+
if (t.m & STATUS_UNINITIALIZED) return;
|
|
166
|
+
if (probing && !quietPending(t)) probeFound = true;
|
|
167
|
+
if (e && tracking) {
|
|
168
|
+
if (t.l & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.Y) {
|
|
169
|
+
// `latest` of a flight serves the committed value, the frame's and the
|
|
170
|
+
// lane's alike (D-22): nothing is the seam's, so the reader is the
|
|
171
|
+
// verdict lane's now, as a plain read of a flight makes it
|
|
172
|
+
// (`observeFlight`). Its frame pass re-derived in the lane (R5) asked
|
|
173
|
+
// its question again (F-9, #4397). A staging's is the seam's (#4365).
|
|
174
|
+
if (!probing) joinFuture(null);
|
|
175
|
+
provisionalVerdict(e, false);
|
|
176
|
+
// decided above
|
|
177
|
+
}
|
|
271
178
|
}
|
|
272
179
|
}
|
|
273
180
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// only pushes into companions that already exist, so the first latest()
|
|
293
|
-
// read inside a held transition showed the committed value (#3041).
|
|
294
|
-
if (e.Pe !== NOT_PENDING && !hasActiveOverride(e)) setSignal(t, e.Pe);
|
|
295
|
-
setContextInternal(r);
|
|
296
|
-
setPendingCheckActive(i);
|
|
297
|
-
setLatestReadActive(n);
|
|
181
|
+
/** The pass entering a verdict window is a verdict reader (CONFIG_VERDICT):
|
|
182
|
+
* a dependency going pending re-derives it, the verdict having changed. Not
|
|
183
|
+
* an untracked window: that is a snapshot, like any untracked read (#3946 —
|
|
184
|
+
* a router's link claim probing inside the computation that creates the
|
|
185
|
+
* anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
|
|
186
|
+
const t = creatorPass(context);
|
|
187
|
+
if (t && tracking) {
|
|
188
|
+
// A pass run inside passes still running — its creator's, theirs — one
|
|
189
|
+
// of which read the future or a staging (a branch a held or staged
|
|
190
|
+
// condition opened, and whatever that branch creates) has no screen: the
|
|
191
|
+
// branch exists only in that world. It reads that world as any
|
|
192
|
+
// derivation of it does (`bornInto` once held) and stays its pass
|
|
193
|
+
// (`route`); a verdict reader from its next pass. #4341: a memo born in
|
|
194
|
+
// a newly opened <Match> read the screen, where its branch was closed.
|
|
195
|
+
// Not such a pass: a verdict reader now.
|
|
196
|
+
t.l &= ~CONFIG_ASYNC;
|
|
197
|
+
t.R |= REACTIVE_PROBED | REACTIVE_WINDOW | (creatorReads(t, 0) || (t.l |= CONFIG_VERDICT,
|
|
198
|
+
0));
|
|
298
199
|
}
|
|
299
|
-
return t;
|
|
300
200
|
}
|
|
301
201
|
|
|
302
|
-
/** The
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
202
|
+
/** The windows. `read` dispatches to `verdictValue` while one is open; each
|
|
203
|
+
* restores the dispatch it found — none inside a memo's pass a window
|
|
204
|
+
* pulled (`verdictValue`). */ function latest(e) {
|
|
205
|
+
markVerdictReader();
|
|
206
|
+
const t = latestActive, r = verdict;
|
|
207
|
+
latestActive = true;
|
|
208
|
+
setVerdict(verdictValue);
|
|
308
209
|
try {
|
|
309
|
-
|
|
310
|
-
// performs its mid-tick pull — a plain write queued between two latest()
|
|
311
|
-
// calls left a still-subscribed shadow at its previous speculative value
|
|
312
|
-
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
313
|
-
// queued staleness through the graph, then bring the shadow up to date.
|
|
314
|
-
const e = queueFor(t);
|
|
315
|
-
if (t.Le >= e.xe && !(t.ie & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
316
|
-
markHeap(e);
|
|
317
|
-
prepareComputed(t, true);
|
|
318
|
-
}
|
|
319
|
-
r = read(t);
|
|
320
|
-
} catch (t) {
|
|
321
|
-
if (t instanceof NotReadyError && (!context || !(e.S & STATUS_UNINITIALIZED))) return i;
|
|
322
|
-
throw t;
|
|
210
|
+
return e();
|
|
323
211
|
} finally {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (t.S & STATUS_PENDING) return i;
|
|
327
|
-
if (stale && currentOptimisticLane && t.o?.Be) {
|
|
328
|
-
const e = findLane(t.o?.Be);
|
|
329
|
-
const n = findLane(currentOptimisticLane);
|
|
330
|
-
if (e !== n && e.Ae.size > 0) {
|
|
331
|
-
return i;
|
|
332
|
-
}
|
|
212
|
+
latestActive = t;
|
|
213
|
+
setVerdict(r);
|
|
333
214
|
}
|
|
334
|
-
// A shadow recomputed by the pull above (not at creation) holds its fresh
|
|
335
|
-
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
336
|
-
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
337
|
-
// other transition's committed view, matching read()'s own selection.
|
|
338
|
-
if (t.Pe !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t._e && activeTransition !== t._e)) return t.Pe;
|
|
339
|
-
return r;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
343
|
-
setPendingCheckActive(false);
|
|
344
|
-
if (typeof e.Se === "function") prepareComputed(e, true);
|
|
345
|
-
const r = n.S;
|
|
346
|
-
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED) {
|
|
347
|
-
if (tracking && e !== t) link(e, t);
|
|
348
|
-
setPendingCheckActive(true);
|
|
349
|
-
throw n.o?._;
|
|
350
|
-
}
|
|
351
|
-
collectPendingSources(e);
|
|
352
|
-
if (i) collectPendingSources(i);
|
|
353
|
-
setPendingCheckActive(true);
|
|
354
215
|
}
|
|
355
216
|
|
|
356
217
|
/**
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
218
|
+
* Reports whether what `fn` reads is still waiting on an update. Read the
|
|
219
|
+
* values in question inside `fn`: the probe answers `true` while any of
|
|
220
|
+
* them depends on a change that is in flight — a write or an async source
|
|
221
|
+
* that has started producing a new value whose result has not landed yet —
|
|
222
|
+
* and `false` once the latest value is the one on screen. The answer is
|
|
223
|
+
* tracked like any read, so a memo or effect that calls `isPending` re-runs
|
|
224
|
+
* when it flips.
|
|
225
|
+
*
|
|
226
|
+
* A read that has no value yet is loading, not pending: inside `fn` it
|
|
227
|
+
* follows the surrounding `Loading` path like any other read, and the probe
|
|
228
|
+
* reports only updates to a value that already exists. A bare `refresh()`
|
|
229
|
+
* does not flip `isPending`; pair it with `affects()` to make the re-ask
|
|
230
|
+
* visible.
|
|
231
|
+
*
|
|
232
|
+
* @param fn expression to probe; read the values in question inside it
|
|
233
|
+
*
|
|
234
|
+
* @returns `true` while a read inside `fn` depends on a change that has not committed yet
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* const [query, setQuery] = createSignal("");
|
|
239
|
+
* const results = createMemo(() => searchProducts(query()));
|
|
240
|
+
* const stale = createMemo(() => isPending(results));
|
|
241
|
+
*
|
|
242
|
+
* setQuery("shoes");
|
|
243
|
+
* // stale() is true until the new results land, while results() keeps
|
|
244
|
+
* // serving the previous list — dim it instead of showing a spinner.
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @description https://v2.solidjs.com/reference/solid-js/reactivity/is-pending
|
|
248
|
+
*/ function isPending(e) {
|
|
249
|
+
markVerdictReader();
|
|
250
|
+
const t = probing;
|
|
251
|
+
const r = probeFound;
|
|
252
|
+
const i = verdict;
|
|
253
|
+
probing = true;
|
|
254
|
+
probeFound = false;
|
|
255
|
+
setVerdict(verdictValue);
|
|
256
|
+
try {
|
|
257
|
+
e();
|
|
258
|
+
return probeFound;
|
|
259
|
+
} catch (e) {
|
|
260
|
+
// A pending node is served inside the probe; what still throws is an
|
|
261
|
+
// uninitialized one — loading, not pending (A19 exc. 1) — whose NotReady
|
|
262
|
+
// propagates to boundaries from inside an owner (B5a; a component body
|
|
263
|
+
// suspends on it like any read, #2928) and is swallowed outside one. A
|
|
264
|
+
// verdict never throws anything else: a thunk that errors is simply not
|
|
265
|
+
// pending.
|
|
266
|
+
if (e instanceof NotReadyError && !probeFound && context !== null) throw e;
|
|
267
|
+
return probeFound;
|
|
268
|
+
} finally {
|
|
269
|
+
probing = t;
|
|
270
|
+
probeFound = r;
|
|
271
|
+
setVerdict(i);
|
|
369
272
|
}
|
|
370
|
-
return false;
|
|
371
273
|
}
|
|
372
274
|
|
|
373
|
-
function
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
pendingProbe.freshReads.add(e);
|
|
377
|
-
}
|
|
275
|
+
/** The staging, or the staged error thrown (D-41). */ function staged(e) {
|
|
276
|
+
if (e.l & CONFIG_STAGED_ERROR) throw e.ue;
|
|
277
|
+
return e.ue;
|
|
378
278
|
}
|
|
379
279
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const r =
|
|
384
|
-
|
|
385
|
-
|
|
280
|
+
/** `latest()` of a held node: the flushed staging — the proposal — and, for
|
|
281
|
+
* a tracked reader of a rewrite not yet flushed, the late-linker re-run in
|
|
282
|
+
* the flush that carries it. */ function heldLatest(e, t) {
|
|
283
|
+
const r = unflushedValue(e);
|
|
284
|
+
if (r === NOT_PENDING) return staged(e);
|
|
285
|
+
if (t) markLateLinker(t);
|
|
386
286
|
return r;
|
|
387
287
|
}
|
|
388
288
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
289
|
+
/** The verdict windows' read — `latest(fn)` and `isPending(fn)` — in one
|
|
290
|
+
* cold path off `read`'s. It links and pulls like a plain read, then answers
|
|
291
|
+
* for what the reader sees (a verdict reader is a frame reader):
|
|
292
|
+
* - a lane's node: the reader is the holder's verdict lane's (not the
|
|
293
|
+
* lane's — a lane blocked on its own flight would hold the reader's run,
|
|
294
|
+
* the opposite of a verdict's display-ahead). A guess is the value (A17),
|
|
295
|
+
* not final while its own question flies or a truth held beneath it
|
|
296
|
+
* differs (A24, A18 provenance). A derivation: `latest` sees the lane's
|
|
297
|
+
* latest (a landing a blocked lane holds has answered its question — the
|
|
298
|
+
* checkout's shipping text updates independently of the tax in flight),
|
|
299
|
+
* `isPending` the screen; not final while its own flight is up. A
|
|
300
|
+
* derivation's first load in flight (nothing produced yet — an async memo
|
|
301
|
+
* over a verdict memo, F-6) reads as the flight below: loading (D-22);
|
|
302
|
+
* - a held node: the reader breaks out as the holder's verdict lane's and
|
|
303
|
+
* re-derives at the landing; `latest` serves the proposal (`heldLatest`),
|
|
304
|
+
* `isPending` answers `heldNotFinal`;
|
|
305
|
+
* - a node staged this flush and not yet held: the seam's verdict
|
|
306
|
+
* (`provisionalVerdict`) — or, with a newer question already in flight
|
|
307
|
+
* (#3376, the stale first hop of a chain), its flight's;
|
|
308
|
+
* - a flight (cause ii): `isPending` records it (`pendingVerdict`), `latest`
|
|
309
|
+
* serves the committed value — below the async nothing newer exists; an
|
|
310
|
+
* uninitialized one throws NotReady: loading, not pending (A19 exc. 1);
|
|
311
|
+
* - an errored derivation throws for every reader (#2897). */ function verdictValue(e, t) {
|
|
312
|
+
const r = e;
|
|
313
|
+
const i = !!t && !(t.l & CONFIG_CHILDREN_FORBIDDEN);
|
|
314
|
+
const n = i && tracking;
|
|
315
|
+
// A31: the pulled memo's pass is its own, not the probe's — it reads
|
|
316
|
+
// outside the window, and the probe's read below answers for what the pass
|
|
317
|
+
// produced. So is a lazy or dormant memo's wake (an unowned memo with no
|
|
318
|
+
// reader left, #4366): woken inside the window, it read its sources as the
|
|
319
|
+
// probe does, the committed value under a landing. (A signal has no
|
|
320
|
+
// `_flags`: the wake is a no-op for it.)
|
|
321
|
+
setVerdict(null);
|
|
322
|
+
prepareComputed(r);
|
|
323
|
+
if (t && tracking) {
|
|
324
|
+
link(e, t);
|
|
325
|
+
if (e.X) pullComputed(r, t);
|
|
396
326
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
327
|
+
setVerdict(verdictValue);
|
|
328
|
+
// A live `affects()` mark on the node or a dependency (affects.ts): not
|
|
329
|
+
// final by declaration — the value itself is read as below. The verdict is
|
|
330
|
+
// display-ahead like any: in a transaction's flush (the declaring action's
|
|
331
|
+
// body) the reader is its verdict lane's, not a staging the frame parks.
|
|
332
|
+
if (probing && GlobalQueue.p?.(r)) {
|
|
333
|
+
probeFound = true;
|
|
334
|
+
if (n && flushTransaction) verdictRead(t, flushTransaction);
|
|
335
|
+
}
|
|
336
|
+
if (e.l & CONFIG_OVERRIDE && !(r.m & STATUS_ERROR && !(e.l & CONFIG_GUESS))) {
|
|
337
|
+
const i = txOf(e), o = (r.m & STATUS_PENDING) !== 0 && !quietPending(r), a = e.l & CONFIG_GUESS,
|
|
338
|
+
// NOT_PENDING: a node born in the lane with nothing in it yet has no
|
|
339
|
+
// value in either view — loading, not pending, and no verdict to read
|
|
340
|
+
// ahead: it is read as any uninitialized node, NotReady below (A7, A19
|
|
341
|
+
// exc. 1; #4363), its reader not moved into the verdict lane.
|
|
342
|
+
u = a ? 0 : latestActive && !o ? laneValueOf(e) : display(e);
|
|
343
|
+
if (u !== NOT_PENDING) {
|
|
344
|
+
if (n) verdictRead(t, i._parent ?? i);
|
|
345
|
+
if (a) {
|
|
346
|
+
if (probing && (o || e.ue !== NOT_PENDING && (!e.ye || !e.ye(e.T.P, e.ue)))) probeFound = true;
|
|
347
|
+
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
348
|
+
// world whole — the truth beneath each guess, else what it covered.
|
|
349
|
+
if (latestActive && i.folded) return i.folded(null, e);
|
|
350
|
+
return e.T.P;
|
|
351
|
+
}
|
|
352
|
+
// A first load in flight with nothing produced yet: loading, for
|
|
353
|
+
// `latest` (D-22) as for `isPending` (A19 exc. 1) — unless an error
|
|
354
|
+
// answered it first: its re-ask is pending, the error its display
|
|
355
|
+
// (D-41, #4375).
|
|
356
|
+
if (o && u === e.le && r.m & STATUS_UNINITIALIZED && (latestActive || !r.T.Te)) throw r.T.U;
|
|
357
|
+
if (probing && o) probeFound = true;
|
|
358
|
+
return u;
|
|
419
359
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
360
|
+
}
|
|
361
|
+
const o = (r.m & STATUS_UNINITIALIZED) !== 0;
|
|
362
|
+
if (e.l & CONFIG_HELD) {
|
|
363
|
+
if (!o) {
|
|
364
|
+
const i = txOf(e);
|
|
365
|
+
// A render effect re-run (or mounted) outside the verdict lane's flush
|
|
366
|
+
// while the lane is blocked — its display held on its own derivation
|
|
367
|
+
// in flight — is a stale reader of the lane (#3460, as `laneRead`): the
|
|
368
|
+
// committed value now, re-derived at the reveal. Not inside a probe:
|
|
369
|
+
// `isPending` is answered below either way.
|
|
370
|
+
if (n && !probing && t.i === EFFECT_RENDER && !passLane && i.Pe?.ln && flushTransaction !== i) {
|
|
371
|
+
staleReader(t, i.Pe);
|
|
372
|
+
return e.le;
|
|
430
373
|
}
|
|
374
|
+
if (n) verdictRead(t, i);
|
|
375
|
+
if (probing && heldNotFinal(r)) probeFound = true;
|
|
376
|
+
if (latestActive && e.ue !== NOT_PENDING) {
|
|
377
|
+
// An action body reading another transaction's proposal derives
|
|
378
|
+
// from it: the two settle as one (A15; posture C, 2026-09-15). An
|
|
379
|
+
// untracked read elsewhere has no transaction to entangle.
|
|
380
|
+
if (!n && flushTransaction && !globalQueue.Y) joinFuture(txOf(e));
|
|
381
|
+
return heldLatest(e, n ? t : null);
|
|
382
|
+
}
|
|
383
|
+
return e.le;
|
|
431
384
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (e instanceof NotReadyError) {
|
|
440
|
-
const t = !!(e.source?.S & STATUS_UNINITIALIZED);
|
|
441
|
-
if (i.found && !t) return true;
|
|
442
|
-
if (context && t) throw e;
|
|
385
|
+
// Born into the future: its staging is its only value. It has no
|
|
386
|
+
// committed value, so no verdict: `isPending` reads it as its read does —
|
|
387
|
+
// the owner joins the hold (held with it, or caught by a boundary that
|
|
388
|
+
// has not shown content) and answers for the commit, where it is final.
|
|
389
|
+
if (e.ue !== NOT_PENDING && !(r.m & STATUS_PENDING)) {
|
|
390
|
+
if (probing && i) joinPass(t, e);
|
|
391
|
+
return staged(e);
|
|
443
392
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
393
|
+
} else if (e.ue !== NOT_PENDING) {
|
|
394
|
+
if (r.m & STATUS_PENDING && !o) pendingVerdict(n ? t : null, r); else if (n && globalQueue.Y) provisionalVerdict(t, !latestActive && !o);
|
|
395
|
+
// Outside a flush, the staging is an unflushed write (A28): the probe
|
|
396
|
+
// answers for the flushed world, and watches the seam of the flush that
|
|
397
|
+
// carries the write — a memo of `isPending(x)` created after the write
|
|
398
|
+
// flips if that flush parks (#3078). (The write's own fan-out ran before
|
|
399
|
+
// the reader existed; nothing else would re-derive it.)
|
|
400
|
+
else if (n && probing) watchVerdict(t);
|
|
401
|
+
if (latestActive) {
|
|
402
|
+
// A28: an unflushed write is not what `latest` serves; a tracked
|
|
403
|
+
// reader derived from the flushed world runs again in the carrying
|
|
404
|
+
// flush.
|
|
405
|
+
if (globalQueue.Y) return staged(e);
|
|
406
|
+
if (t) markLateLinker(t);
|
|
407
|
+
}
|
|
408
|
+
return e.le;
|
|
409
|
+
}
|
|
410
|
+
if (r.m & STATUS_PENDING) {
|
|
411
|
+
if (!o) {
|
|
412
|
+
pendingVerdict(n ? t : null, r);
|
|
413
|
+
return e.le;
|
|
414
|
+
}
|
|
415
|
+
// As `read()`: an untracked read of a pending node still re-runs its
|
|
416
|
+
// reader when the node settles (a projection's pull reads its firewall
|
|
417
|
+
// untracked, store/store.ts).
|
|
418
|
+
if (t && !tracking && !spectating && e !== t) link(e, t);
|
|
419
|
+
throw r.T?.U;
|
|
448
420
|
}
|
|
421
|
+
if (e.X && r.m & STATUS_ERROR) throw r.T.U;
|
|
422
|
+
return e.le;
|
|
449
423
|
}
|
|
450
424
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
425
|
+
/** D-25: a node whose fetch a hold is waiting on is that hold's work, not a
|
|
426
|
+
* verdict reader — a pass that re-runs it reads plainly — and a memo's
|
|
427
|
+
* posture is what it reads: one that reads a verdict reader's value is a
|
|
428
|
+
* verdict reader itself (#4050). An async memo with no verdict window of its
|
|
429
|
+
* own (REACTIVE_WINDOW: it read a verdict memo, it called neither `latest`
|
|
430
|
+
* nor `isPending`) is a verdict reader between its flights, and the hold's
|
|
431
|
+
* work while one is up or its hold re-runs it.
|
|
432
|
+
*
|
|
433
|
+
* At a pass's head (core.ts `recompute`): a pending node's pass — its
|
|
434
|
+
* flight is the transition's own work (#3884) — and a held one's re-run of
|
|
435
|
+
* such a memo read plainly: the write that re-ran it is its hold's, and
|
|
436
|
+
* served the screen it re-asked a question it had answered (A10, #4397).
|
|
437
|
+
* Only a memo that never asked: D-25's "a verdict posture outlives the pass
|
|
438
|
+
* that asked" is a pass that called `latest`/`isPending`, which clears
|
|
439
|
+
* CONFIG_ASYNC and stays a verdict reader whoever dirties it.
|
|
440
|
+
*
|
|
441
|
+
* On `source` going pending (`propagateStatus`): such a memo waits on it
|
|
442
|
+
* like any derivation (F-9) instead of re-deriving — what it read changed
|
|
443
|
+
* no value, so its re-run re-asked the question it was answering. Unless
|
|
444
|
+
* its own flight is up outside a lane on a new question of the source's:
|
|
445
|
+
* its re-run supersedes a flight asked of a value the source has moved past
|
|
446
|
+
* (re-asked by a `refresh()`, the source's question is the same one). */ function holdWork(e, t) {
|
|
447
|
+
// CONFIG_ASYNC records an async memo with no window of its own: its last
|
|
448
|
+
// answering pass registered a flight (`handleAsync`) and called neither
|
|
449
|
+
// `latest` nor `isPending`. A window (`markVerdictReader`), a sync answer or
|
|
450
|
+
// an error clears it; a pass left pending keeps the last answer's.
|
|
451
|
+
const r = e.l & CONFIG_ASYNC;
|
|
452
|
+
return r && (!(e.m & STATUS_PENDING) || e.T.Re?.P || t.R & REACTIVE_REASK);
|
|
453
|
+
}
|
|
471
454
|
|
|
472
|
-
|
|
455
|
+
// Installed at module evaluation — present exactly when something imports
|
|
456
|
+
// `latest` or `isPending`. (`read` dispatches to `verdictValue` through
|
|
457
|
+
// `verdict`, set while a window is open.)
|
|
458
|
+
installVerdictHooks(observeFlight, holdWork);
|
|
473
459
|
|
|
474
|
-
|
|
460
|
+
/** A store read inside an untracked `isPending` probe found a live mark on
|
|
461
|
+
* a record with no node to carry it (store/affects.ts): not final. */ GlobalQueue.rt = () => {
|
|
462
|
+
if (probing) probeFound = true;
|
|
463
|
+
};
|
|
475
464
|
|
|
476
465
|
export { isPending, latest };
|