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