@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
@@ -1,87 +1,458 @@
1
- import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, NOT_PENDING, CONFIG_HAS_COMPANIONS, EFFECT_TRACKED, CONFIG_HAS_LANE, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED } from "./constants.js";
1
+ import { EFFECT_RENDER, EFFECT_USER, CONFIG_HELD, CONFIG_OVERRIDE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, CONFIG_STAGED, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_VERDICT, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, CONFIG_HELD_FRAME, REACTIVE_LANE_DIRTY, CONFIG_STAGED_ERROR, CONFIG_INPUTS_PUBLISHED, STATUS_ERROR, EFFECT_TRACKED, REACTIVE_MANUAL_WRITE, CONFIG_GUESS, REACTIVE_FRAME_READ, CONFIG_REDERIVE, CONFIG_FRAME } from "./constants.js";
2
2
 
3
- import { currentOptimisticLane } from "./core.js";
3
+ import { attrHooks } from "./attribution-hooks.js";
4
+
5
+ import { notifyStatus } from "./async.js";
6
+
7
+ import { resyncUnflushedCompanions, isSame, recompute, markUnflushedStaged, ext } from "./core.js";
4
8
 
5
9
  import { DEV } from "./dev.js";
6
10
 
7
- import { NotReadyError } from "./error.js";
11
+ import { sweepDormant, trimStaleDeps } from "./graph.js";
8
12
 
9
- import { runHeap, deleteFromHeap, enqueueSub } from "./heap.js";
13
+ import { runHeap, enqueueSub, deleteFromHeap } from "./heap.js";
10
14
 
11
- import { activeLanes, assignOrMergeLane, findLane } from "./lanes.js";
15
+ import { devCheckQuiescent } from "./invariants.js";
12
16
 
13
- export { getOrCreateLane, hasActiveOverride, mergeLanes, resolveLane } from "./lanes.js";
17
+ import { rethrowCleanupError } from "./owner.js";
14
18
 
15
- import { devCheckFlushStart, devCheckActiveOverrides, devCensusCompanions, devCheckQuiescent } from "./invariants.js";
19
+ // Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
20
+ // bundle that never imports the installing module never assigns them — its
21
+ // minifier folds every guarded call site (and the branch behind it) away.
22
+ // Each module installs its own set at evaluation (pay-for-use).
23
+ // Lanes (lanes.ts; installed when `createOptimistic` — or verdict.ts — is
24
+ // imported; every call site is behind a bit or a `passLane` nothing else sets).
25
+ let laneReadHook = null;
16
26
 
17
- const transitions = new Set;
27
+ let laneStageHook = null;
18
28
 
19
- const dirtyQueue = {
20
- eE: new Array(2e3).fill(undefined),
21
- tE: false,
22
- xe: 0,
23
- EE: 0
24
- };
29
+ let laneOutcomeHook = null;
25
30
 
26
- const zombieQueue = {
27
- eE: new Array(2e3).fill(undefined),
28
- tE: false,
29
- xe: 0,
30
- EE: 0
31
- };
31
+ let laneWriteHook = null;
32
32
 
33
- /** runHeap callback that discards a queued zombie recompute instead of running
34
- * it: unlink pure recompute entries; strip just the recompute bit from dirtied
35
- * height-adjust entries so their height work still happens. */ function cancelZombieRecompute(e) {
36
- if (e.ie & REACTIVE_IN_HEAP_HEIGHT) e.ie &= -12; else {
37
- deleteFromHeap(e, zombieQueue);
38
- e.ie &= -4;
39
- }
33
+ let applyGuessesHook = null;
34
+
35
+ let laneSeamsHook = null;
36
+
37
+ let laneCorrectionsHook = null;
38
+
39
+ let endLanesHook = null;
40
+
41
+ let lanesBlockedHook = null;
42
+
43
+ /** R5 (lanes.ts `laneSeams` parks a frame flight): the landing's re-derive
44
+ * of a reader adopts the flight instead (true: adopted, nothing to queue). */ let laneAdoptHook = null;
45
+
46
+ /** core.ts `frameRead` served lane work or a verdict reader a held node's
47
+ * committed value (lanes.ts `laneServed`). */ let laneServedHook = null;
48
+
49
+ /** A guess was written (lanes.ts `optimisticWrite`): the arms only a guess
50
+ * reaches (CONFIG_GUESS) — a build without `createOptimistic` or
51
+ * `createOptimisticStore` never sets it, and its bundler folds them. */ let guessing = false;
52
+
53
+ function armGuessing() {
54
+ guessing = true;
40
55
  }
41
56
 
42
- let clock = 0;
57
+ function installLaneHooks(e, o, n, l, t, s, u, i, r, a, f) {
58
+ laneReadHook = e;
59
+ laneStageHook = o;
60
+ laneOutcomeHook = n;
61
+ laneWriteHook = l;
62
+ applyGuessesHook = t;
63
+ laneSeamsHook = s;
64
+ laneCorrectionsHook = u;
65
+ endLanesHook = i;
66
+ lanesBlockedHook = r;
67
+ laneAdoptHook = a;
68
+ laneServedHook = f;
69
+ }
43
70
 
44
- let activeTransition = null;
71
+ // Boundaries (boundaries.ts): the display consumers between an observer
72
+ // and the root. `catch` — status from a frame reader, nearest boundary
73
+ // first (true: caught, the root never hears of it; a clear — flags 0 —
74
+ // settles the reader there); `fresh` — a pass that read a hold (true: a
75
+ // first pass a loading boundary that has not shown content caught,
76
+ // `joinPass`; `held`: the flush's hold owns it, nothing catches it);
77
+ // `hidden` — a frame reader behind a fallback (the boundary showing it)
78
+ // is not on screen and holds nothing; `boundarySeam` — the seam's sweep (readers
79
+ // gone or settled without a pass reveal; an `on` re-arm resolves);
80
+ // `heldRun` — a queued run under a fallback-showing boundary waits for
81
+ // the reveal (true: held; the boundary re-queues it by type). The
82
+ // synchronous first render on creation builds the subtree, attached or
83
+ // not; its updates and the user effects wait.
84
+ let catchHook = null;
45
85
 
46
- let scheduled = false;
86
+ let freshHook = null;
47
87
 
48
- let halted = false;
88
+ let hiddenHook = null;
49
89
 
50
- let haltNotified = false;
90
+ let boundarySeamHook = null;
51
91
 
52
- let syncDepth = 0;
92
+ let heldRunHook = null;
93
+
94
+ function installBoundaryHooks(e, o, n, l, t) {
95
+ catchHook = e;
96
+ freshHook = o;
97
+ hiddenHook = n;
98
+ boundarySeamHook = l;
99
+ heldRunHook = t;
100
+ }
101
+
102
+ /** Store (store/store.ts): `park` — the flush parked into `t`: the store
103
+ * materializes and holds the container node of every staging that had none
104
+ * (a staging needs the node as its home only when something can read the
105
+ * frame through it; a hold can); `commit` — fold the pending backings whose
106
+ * container nodes this flush committed (the owned-raw model's one mutation
107
+ * point). */ let storeParkHook = null;
108
+
109
+ let storeCommitHook = null;
110
+
111
+ function installStoreHooks(e, o) {
112
+ storeParkHook = e;
113
+ storeCommitHook = o;
114
+ }
115
+
116
+ /** `affects()` marks (affects.ts): the releases at a landing and at the seam
117
+ * (ambient marks). */ let releaseMarksHook = null;
118
+
119
+ let releaseAmbientMarksHook = null;
120
+
121
+ function installMarkHooks(e, o) {
122
+ releaseMarksHook = e;
123
+ releaseAmbientMarksHook = o;
124
+ }
125
+
126
+ /** Verdicts (verdict.ts). */ let observeFlightHook = null;
127
+
128
+ /** D-25's hold work (verdict.ts `holdWork`): on `source` going pending,
129
+ * whether verdict reader `n` waits on it instead of re-deriving. */ let holdWorkHook = null;
130
+
131
+ function installVerdictHooks(e, o) {
132
+ observeFlightHook = e;
133
+ holdWorkHook = o;
134
+ }
135
+
136
+ /** External-source bridge (wired by enableExternalSource(); undefined while
137
+ * no config is active — including after _resetExternalSourceConfig()). */ let wireExternalSourceHook = undefined;
138
+
139
+ let externalUntrackHook = undefined;
140
+
141
+ function setExternalHooks(e, o) {
142
+ wireExternalSourceHook = e;
143
+ externalUntrackHook = o;
144
+ }
145
+
146
+ /** Live transactions — opened, unmerged, not landed. Scanned at every seam
147
+ * while non-empty; nothing on the plain path. */ const transactions = [];
148
+
149
+ /** Observe tier: this flush parked its transaction (`holdStart` fired). */ let holding = false;
150
+
151
+ /** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e, o = null) {
152
+ const n = {
153
+ tn: [],
154
+ un: [ [], [] ],
155
+ En: [],
156
+ eo: null,
157
+ _parent: o,
158
+ P: e,
159
+ Pe: null,
160
+ tt: 0,
161
+ nt: false,
162
+ en: null,
163
+ Ue: false,
164
+ ln: false,
165
+ I: null
166
+ };
167
+ if (!e) transactions.push(n);
168
+ return n;
169
+ }
170
+
171
+ // Lanes (plan sec. 28, 2026-10-02; lanes.ts). A lane is "a new base of a transition":
172
+ // the sub-frame an optimistic write opens in the transition of the frame it
173
+ // is made in. It sees the screen plus its own guesses (plan sec. 19), breaks out of
174
+ // the parent's hold — its effects run now — and holds itself if its own
175
+ // derivations hit async. It ends when the parent lands: a guess reverts to
176
+ // the truth it covered, or lands as the truth that superseded it. A frame
177
+ // that does not park has nothing to be optimistic over: the write is void.
178
+
179
+ // The seat of a pass is its node's: a node carrying a lane's value runs as
180
+ // the lane's whoever dirtied it; a derivation's tracked read of a lane's
181
+ // value moves its pass into the lane; a leaf's never does (it reads the
182
+ // screen). Lane work's values go to the lane slot, its runs to the lane's
183
+ // queues; the rest of the frame is the flush's.
184
+ /** The lane the running pass is work of; set at `recompute`'s head from the
185
+ * node, moved by a derivation's lane read, saved and restored around the
186
+ * pass. */ let passLane = null;
187
+
188
+ function setPassLane(e) {
189
+ passLane = e;
190
+ }
191
+
192
+ /** The transaction this flush parks into: set by the first join, merged
193
+ * with every further one. Consumed at the seam. A join outside a flush (a
194
+ * mount's pending observer, a write to a held node, an action opening)
195
+ * schedules the seam that consumes it: membership is the tick's — the same
196
+ * synchronous frame — and the next tick's writes are not this one's. */ let flushTransaction = null;
197
+
198
+ /** The flush's transaction while only a `latest()` read of a staging opened
199
+ * it (verdict.ts `provisionalVerdict`): it holds nothing, and a verdict
200
+ * reader's plain read of a staging in it is the frame's read (D-22). */ let latestOpened = null;
201
+
202
+ /** The transaction the passes running OUTSIDE a flush this tick derive from
203
+ * (a mainline mount, a mainline re-pass): the passes' own (A29, creation-
204
+ * time form — "the entry is the pass's alone"): their results are staged
205
+ * into it, and nothing else in the tick is — a write made after the mount
206
+ * is a mainline write, a render effect mounted beside it a stale reader.
207
+ * Inside a flush, or in a tick that already has its transaction (an
208
+ * action's body), the frame joins instead (`flushTransaction`) — except a
209
+ * first pass a loading boundary that has not shown content catches (`own`,
210
+ * A29's boundary exemption, #3540): it is the boundary's, not the tick's,
211
+ * and a flush that has joined nothing keeps it pass-scoped as outside one.
212
+ * Cleared by the flush the join schedules, and at the end of a flush that
213
+ * set it. */ let passTx = null;
214
+
215
+ function joinPassTx(e, o) {
216
+ if (globalQueue.Y && !o || flushTransaction !== null) return joinFuture(e);
217
+ if (passTx === null) passTx = resolveTx(e); else merge(resolveTx(e), passTx);
218
+ schedule();
219
+ }
220
+
221
+ /** The transaction holding a node (CONFIG_HELD set), resolved through
222
+ * merges; the path is compressed. */ function txOf(e) {
223
+ return e.T.Re = resolveTx(e.T.Re);
224
+ }
225
+
226
+ /** `t` resolved through merges while it is still parked or open; null once
227
+ * it has landed. */ function liveTx(e) {
228
+ e = resolveTx(e);
229
+ return transactions.indexOf(e) !== -1 ? e : null;
230
+ }
231
+
232
+ function resolveTx(e) {
233
+ while (e.eo !== null) e = e.eo;
234
+ return e;
235
+ }
53
236
 
54
- let projectionWriteActive = false;
237
+ /** The flush joins transaction `t` — or needs one of its own (`null`: a pass
238
+ * went pending with nothing held). Joining a second one merges it into the
239
+ * flush's: the work that touched both entangles them (A15). */ function joinFuture(e) {
240
+ const o = flushTransaction;
241
+ if (o === null) {
242
+ flushTransaction = e === null ? newTransaction(false) : resolveTx(e);
243
+ } else if (e !== null) merge(resolveTx(e), o);
244
+ if (!globalQueue.Y) schedule();
245
+ }
246
+
247
+ /** `t` merges into `f`: the work that touched both entangles them (A15).
248
+ * A lane never merges: it is a sub-frame, not a peer — its work is routed
249
+ * per pass (`passLane`). */ function merge(e, o) {
250
+ // Both ends resolved: a stale pointer to a transaction already merged
251
+ // into the other would close a cycle `resolveTx` never leaves.
252
+ e = resolveTx(e);
253
+ o = resolveTx(o);
254
+ if (e === o || e.P || o.P) return;
255
+ e.eo = o;
256
+ o.tt += e.tt;
257
+ o.nt ||= e.nt;
258
+ append(o.tn, e.tn);
259
+ append(o.un[0], e.un[0]);
260
+ append(o.un[1], e.un[1]);
261
+ append(o.En, e.En);
262
+ if (e.I !== null) append(o.I ??= [], e.I);
263
+ transactions.splice(transactions.indexOf(e), 1);
264
+ }
265
+
266
+ /** A15: a hold is a property of the async node — observed pending by a
267
+ * render reader. A transaction is blocked while a node it holds, in flight,
268
+ * has one: a pending render effect (the frame itself), or a pending held
269
+ * node a render effect reads. A stale reader served the committed value
270
+ * never went pending, but derives from the flight all the same (#3494) and
271
+ * is still linked to it; a memo between them is pending, and held, too — so
272
+ * one hop of `_subs` is the chain. Reads of the reader's LAST pass only (the
273
+ * link's generation is the pass's): a tail kept for A30 — the committed
274
+ * frame's dependency, awaiting the run that retires it — is not a read of
275
+ * the flight, and a reader that stopped reading releases it (O3, #3494).
276
+ * An errored pass (NotReady included) did not stop: it never got there, and
277
+ * its full list stands (A30) — the reads it did not reach still observe. A
278
+ * flight nobody renders holds nothing (A29). Only the nodes `t` still owns
279
+ * count: one a lane took over since is the lane's to wait on. A guess whose
280
+ * own truth is in flight blocks the lane's parent, not the lane — it stands
281
+ * in for the flight (A17: "visible until its own fetch settles"). */ function blocked(e) {
282
+ // The transaction being judged (a lane consulted on its behalf judges for
283
+ // it): a zombie whose removal it stages is moot for it alone (`onScreen`).
284
+ const o = judge;
285
+ judge ??= e;
286
+ // An action still running in it holds it open (action.ts). Its lanes
287
+ // (lanes.ts): a lane under `t` blocks it while blocked itself.
288
+ const n = e.tt !== 0 || blockedBy(e.tn, e) || !!lanesBlockedHook?.(e);
289
+ judge = o;
290
+ return n;
291
+ }
292
+
293
+ let judge = null;
55
294
 
56
- // Store property nodes that were created solely to carry a pending write (no
57
- // subscribers at write time). Swept after each flush that commits pending
58
- // values — any still without subs get disposed via their `_unobserved` hook,
59
- // releasing the slot in the parent store's node map.
60
- const transientStoreNodes = new Set;
295
+ /** `t`'s own flights only — not its lanes': a flight the frame asked for
296
+ * (a refetch, a plain load) is authoritative; a lane's derivation flight is
297
+ * not (lanes.ts, the body-end corollary). A pending reader counts only if
298
+ * one of the sources it waits on is `t`'s (a render effect marked pending
299
+ * by a lane flight, never re-run, is the lane's wait, not the frame's). */ function ownFlights(e) {
300
+ return blockedBy(e.tn, e, true);
301
+ }
61
302
 
62
- function canUseSimpleSyncFlush(e) {
63
- const t = e.k;
64
- return transitions.size === 0 && activeLanes.size === 0 && e.Qt.length === 0 && t.Ke.length === 0 && t.m.length === 0 && t.cn.size === 0 && transientStoreNodes.size === 0;
303
+ /** A source the pending node waits on that is `t`'s (held by it, or by no
304
+ * one) — not another transaction's or lane's work. Itself, when it is the
305
+ * source. */ function ownSource(e, o) {
306
+ const n = e.T?.se;
307
+ if (n === undefined) return true;
308
+ for (const e of n) {
309
+ const n = e.T?.Re;
310
+ if (n == null || resolveTx(n) === o) return true;
311
+ }
312
+ return false;
65
313
  }
66
314
 
67
- function sweepTransientStoreNodes() {
68
- if (transientStoreNodes.size === 0) return;
69
- for (const e of transientStoreNodes) {
70
- if (e.u !== null) {
71
- transientStoreNodes.delete(e);
315
+ function blockedBy(e, o, n = false) {
316
+ for (let l = 0; l < e.length; l++) {
317
+ const t = e[l];
318
+ if (!(t.m & STATUS_PENDING) || t.R & REACTIVE_DISPOSED || t.l & CONFIG_GUESS || t.T.Re !== null && txOf(t) !== o || n && !ownSource(t, o)) continue;
319
+ // The frame's own pending observer (off screen: this one holds nothing;
320
+ // the next listed node may).
321
+ if (t.i === EFFECT_RENDER) {
322
+ if (onScreen(t, judge ?? o)) return true;
72
323
  continue;
73
324
  }
74
- if (e.Pe !== NOT_PENDING) continue;
75
- if (e.o?.De !== undefined && e.o?.De !== NOT_PENDING) continue;
76
- // A live affects() mark keeps the node addressable: sweeping it would
77
- // detach the refcount from the slot (a fresh probe would upsert a new,
78
- // unmarked node for the same property).
79
- if (e.o?.t) continue;
80
- transientStoreNodes.delete(e);
81
- e.o?.ft?.();
325
+ for (let e = t.o; e !== null; e = e.t) {
326
+ const n = e.u;
327
+ // A frame reader: a render effect, or a stale reader of the flight
328
+ // (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
329
+ // `frameRead`): served committed instead of going pending, it derives
330
+ // from the flight all the same and is re-derived at the landing — the
331
+ // frame's observation survives its reader becoming a lane's (a guess
332
+ // over a held window, V5/A17). A probe alone does not hold. A
333
+ // boundary showing content forwards the pending (its output pending,
334
+ // CONFIG_REDERIVE): transparent, its readers hold through it (A33; the
335
+ // lane-membership ruling, 2026-10-05). An output that never committed
336
+ // shows nothing — a mount the frame has not revealed — and holds
337
+ // nothing.
338
+ if ((n.i === EFFECT_RENDER && n.m & STATUS_PENDING || n.R & REACTIVE_FRAME_READ || n.l & CONFIG_REDERIVE && n.m === STATUS_PENDING) && (e.Ne === n.de || n.T?.U != null) && !(n.R & REACTIVE_DISPOSED) && onScreen(n, judge ?? o)) return true;
339
+ }
340
+ }
341
+ return false;
342
+ }
343
+
344
+ /** A frame reader whose say counts for `t`'s hold — `t` the transaction
345
+ * being judged: not a zombie whose removal `t` stages (A15 #3463: a re-ask
346
+ * in the unmount frame lands its pending on the zombie it unmounts — the
347
+ * compiled <Show> of #3372; a zombie blocks every other judgment while it
348
+ * is visible, a lane's reveal included: only the commit that disposes it
349
+ * makes its say moot), and not behind a fallback (A33: a boundary showing its fallback is the display of
350
+ * everything under it, so a reader there is not on screen and holds
351
+ * nothing — boundaries.ts). */ function onScreen(e, o) {
352
+ return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e, o)) && !hiddenHook?.(e);
353
+ }
354
+
355
+ /** A15 (#3463): a reader whose removal is staged — a zombie, parked by a
356
+ * pass awaiting its commit — is still on screen and live for every hold,
357
+ * except the transaction staging its removal: for that one its say is moot
358
+ * (done, and the commit disposes it; not done, and it stays parked). The
359
+ * staging transaction is the one holding the pass that parked the frame:
360
+ * the nearest non-zombie ancestor. */ function removalStagedBy(e, o) {
361
+ let n = e;
362
+ while (n?.R & REACTIVE_ZOMBIE) n = n._parent;
363
+ return n?.l & CONFIG_HELD && n.T?.Re != null && txOf(n) === resolveTx(o);
364
+ }
365
+
366
+ /** Unchanged passes this flush whose stale dependency tail awaits the
367
+ * flush's verdict (A30, #3469): trimmed when the flush commits, kept when
368
+ * it parks — the committed frame still derives from the previous pass's
369
+ * dependencies, and a write to one of them must reach the node until a
370
+ * committing pass replaces it. */ const heldTrims = [];
371
+
372
+ function heldTrim(e) {
373
+ heldTrims.push(e);
374
+ }
375
+
376
+ /** Zombies popped from the dirty heap this flush (`deferZombie`). The seam
377
+ * decides their fate: a park cancels them (the writes that dirtied them are
378
+ * held with it); a commit runs the survivors — the ones whose owner is still
379
+ * awaiting its commit — in height order, after the commits that would have
380
+ * disposed them (#3546). No second heap: the list is the deferral. */ const deferredZombies = [];
381
+
382
+ function deferZombie(e) {
383
+ deleteFromHeap(e, dirtyQueue);
384
+ e.R &= -4;
385
+ deferredZombies.push(e);
386
+ }
387
+
388
+ /** Put a staged node in a transaction: flagged, stamped, on its landing
389
+ * list. */ function holdNode(e, o) {
390
+ e.l |= CONFIG_HELD;
391
+ list(e, o);
392
+ }
393
+
394
+ /** Put a node on a transaction's list, once: a node's `_transaction` is the
395
+ * transaction whose `_nodes` it is on (every site that sets one does the
396
+ * other), so a re-pass, a re-landing or a re-staging adds nothing. */ function list(e, o) {
397
+ const n = ext(e);
398
+ if (n.Re === o) return;
399
+ n.Re = o;
400
+ o.tn.push(e);
401
+ }
402
+
403
+ /** Hold the (uncommitted) frame under a held pass: every computed in the
404
+ * live child chain, recursively. Plain owners are walked through, not held
405
+ * — nothing reads or re-passes them. Once per park, over the parked frames
406
+ * only; recomputes pay nothing for it. A lane's node in the frame (listed on
407
+ * a lane: a verdict reader broken out of this very hold — display-ahead — or
408
+ * a derivation of a guess, CONFIG_OVERRIDE; a lane pass's effect) is the
409
+ * lane's, as the seam's own loop has it: "lane work never makes its node
410
+ * transaction work" (A15, #3698). Re-listed here it would carry the lane's
411
+ * value on the transaction's list, where the landing nulls its transaction
412
+ * and `dissolveLane` no longer finds it — a lane node with no lane, which the
413
+ * next read of it trips over (`laneRead` → `txOf`). Its frame is the lane's
414
+ * too (ruling A: a lane pass's children are the lane's), revealed and
415
+ * retired at the lane's seam. */ function holdFrame(e, o) {
416
+ for (let n = e.pe; n !== null; n = n.Ge) {
417
+ if (n.T?.Re?.P) continue;
418
+ if (n.X !== undefined) {
419
+ if (!(n.l & CONFIG_HELD)) holdNode(n, o);
420
+ n.l |= CONFIG_HELD_FRAME;
421
+ }
422
+ holdFrame(n, o);
423
+ }
424
+ }
425
+
426
+ /** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
427
+ * what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, o, n) {
428
+ for (let l = e.pe; l !== null; l = l.Ge) {
429
+ if ((l.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(l) !== o) n(l);
430
+ heldUnder(l, o, n);
82
431
  }
83
432
  }
84
433
 
434
+ /** `n` leaves the hold it was staged in: its next pass publishes mainline. */ function unhold(e) {
435
+ e.T.Re = null;
436
+ e.l &= ~CONFIG_HELD;
437
+ }
438
+
439
+ const dirtyQueue = {
440
+ et: new Array(2e3).fill(undefined),
441
+ p: false,
442
+ Fe: 0,
443
+ Et: 0
444
+ };
445
+
446
+ let clock = 0;
447
+
448
+ let scheduled = false;
449
+
450
+ let halted = false;
451
+
452
+ let haltNotified = false;
453
+
454
+ let syncDepth = 0;
455
+
85
456
  /**
86
457
  * Toggles the dev-mode "must be inside a `<Loading>` boundary" enforcement
87
458
  * window. Only `render()` calls this — wrapping the initial mount so that a
@@ -91,63 +462,40 @@ function sweepTransientStoreNodes() {
91
462
  * @internal
92
463
  */ function enforceLoadingBoundary(e) {}
93
464
 
94
- function setProjectionWriteActive(e) {
95
- projectionWriteActive = e;
465
+ // Dev-only marker for the effect half of createEffect/createRenderEffect, so
466
+ // flush() can report the no-op instead of failing silently (React parity).
467
+ /** Action bodies on the stack (action.ts): `flush()` is refused inside one —
468
+ * the body's writes are its transaction's and commit when it settles; a
469
+ * drain mid-step cannot reveal them, and dev says so. */ let actionDepth = 0;
470
+
471
+ function enterAction() {
472
+ actionDepth++;
96
473
  }
97
474
 
98
- /**
99
- * Ambient work IS a transaction: the global queue always carries one
100
- * current-transaction-shaped batch (`globalQueue._batch`). With no transition
101
- * active, registrations (pending commits, optimistic nodes, affects marks,
102
- * optimistic stores) land in a plain ambient batch that the plain flush
103
- * finalizes; when a transition initializes it adopts the ambient batch's
104
- * contents and `_batch` becomes the transition itself, so later registrations
105
- * land there directly — no per-field aliasing.
106
- */ function createBatch() {
107
- return {
108
- Te: clock,
109
- yt: [],
110
- Ne: new Map,
111
- Ke: [],
112
- m: [],
113
- cn: new Set,
114
- oe: [],
115
- bt: {
116
- Lt: [ [], [] ],
117
- Qt: []
118
- },
119
- an: false,
120
- ln: new Set
121
- };
475
+ function exitAction() {
476
+ actionDepth--;
122
477
  }
123
478
 
124
- function mergeTransitionState(e, t) {
125
- t.an = e;
126
- e.oe.push(...t.oe);
127
- for (const i of activeLanes) if (i._e === t) i._e = e;
128
- if (t.Ke.length) {
129
- // Move (don't copy): the global queue's batch may still be the outgoing
130
- // transition, and the adoption pass in initTransition would re-push its
131
- // contents into the target — duplicating every entry.
132
- e.Ke.push(...t.Ke);
133
- t.Ke.length = 0;
134
- }
135
- if (t.m.length) {
136
- // Move (don't copy): the global queue's batch may still be the outgoing
137
- // transition, and the adoption pass in initTransition would re-push its
138
- // contents into the target — double-releasing every mark.
139
- e.m.push(...t.m);
140
- t.m.length = 0;
141
- }
142
- for (const i of t.cn) e.cn.add(i);
143
- for (const [i, n] of t.Ne) {
144
- let t = e.Ne.get(i);
145
- if (!t) e.Ne.set(i, t = new Set);
146
- for (const e of n) t.add(e);
147
- }
148
- for (const i of t.ln) e.ln.add(i);
479
+ /** Provenance (A18, #3331): the question being asked — an action's
480
+ * sequence while a slice of its body and the flush that carries it run, 0
481
+ * otherwise. A guess is stamped with it (lanes.ts; a mainline guess takes a
482
+ * fresh sequence: the newest intent), a flight with the question that
483
+ * started it (async.ts; mainline is always the current question). An
484
+ * answer from an older question than the guess it lands on is stale: held
485
+ * silently, it does not move the graph. */ let question = 0;
486
+
487
+ let questions = 0;
488
+
489
+ function setQuestion(e) {
490
+ question = e;
149
491
  }
150
492
 
493
+ function nextQuestion() {
494
+ return ++questions;
495
+ }
496
+
497
+ const MAINLINE_QUESTION = 2147483647;
498
+
151
499
  function schedule() {
152
500
  if (halted) {
153
501
  notifyHalted();
@@ -155,28 +503,60 @@ function schedule() {
155
503
  }
156
504
  if (scheduled) return;
157
505
  scheduled = true;
158
- if (!syncDepth && !globalQueue.sn && !projectionWriteActive) queueMicrotask(flush);
506
+ if (!syncDepth && !globalQueue.Y) {
507
+ queueMicrotask(flush);
508
+ }
159
509
  }
160
510
 
161
511
  /**
162
512
  * Permanently halts the reactive system. Called when a user error escapes
163
513
  * every boundary — app state is undefined at that point, so scheduling stops
164
514
  * entirely rather than limping along with a half-applied update.
165
- */ function haltReactivity(e) {
515
+ */
516
+ /**
517
+ * The key a root owner carries its client error hook under (`render`'s
518
+ * `onError`) — registered, so a runtime writes it with no import of the hook
519
+ * module (core/error-hooks.ts) and no property mangling in the way. Defined
520
+ * HERE, not there: a runtime that only writes the key must not retain the
521
+ * hook machinery (pay-for-use).
522
+ */ const ROOT_ERROR_HOOK = Symbol.for("solid-js/root-error-hook");
523
+
524
+ const HALTED = "[REACTIVITY_HALTED]";
525
+
526
+ function haltReactivity(e) {
166
527
  if (halted) return;
167
528
  halted = true;
168
- let t = "[REACTIVITY_HALTED]";
169
- // Log the cause here too: callers rethrow it, but a creation-time throw
529
+ // A cleanup error collected before the halt is dropped (owner.ts).
530
+ rethrowCleanupError(true);
531
+ let o = HALTED;
532
+ // Surface the cause here too: callers rethrow it, but a creation-time throw
170
533
  // unwinds through ancestor recomputes that convert it to status instead of
171
534
  // surfacing it (#2884), so the rethrow alone cannot guarantee visibility.
172
- e === undefined ? console.error(t) : console.error(t, e);
535
+ // Where the platform has one, hand the cause to its uncaught-error channel
536
+ // (`reportError` → `error` event → window.onerror / error monitoring): a
537
+ // halt that only reaches console.error leaves a page that LOOKS alive with
538
+ // nothing an app or its telemetry can act on (#3338 — an uncaught throw
539
+ // during the hydration render). The rethrow may reach the top as well in
540
+ // the non-swallowed cases; a duplicate report beats a silent one.
541
+ const n = e !== undefined && globalThis.reportError;
542
+ n || e === undefined ? console.error(o) : console.error(o, e);
543
+ n && n(e);
544
+ }
545
+
546
+ /**
547
+ * Dev: `haltReactivity`, located at `subject` — the computation the uncaught
548
+ * error escaped from — for the REACTIVITY_HALTED message's owner path. Call
549
+ * sites pick it in dev builds only (`haltReactivity(e)` in production), so
550
+ * production keeps the one-argument halt and its bytes unchanged.
551
+ */ function haltReactivityAt(e, o) {
552
+ haltReactivity(e);
173
553
  }
174
554
 
175
555
  // Logs on the first write after a halt so a frozen interaction is traceable.
176
556
  function notifyHalted() {
177
557
  if (haltNotified) return;
178
558
  haltNotified = true;
179
- console.error("[REACTIVITY_HALTED]");
559
+ console.error(HALTED);
180
560
  }
181
561
 
182
562
  /** @internal Test/dev-reload hook. Revives scheduling after a halt. */ function resetErrorHalt() {
@@ -184,348 +564,372 @@ function notifyHalted() {
184
564
  haltNotified = false;
185
565
  }
186
566
 
187
- // Identifies one child-traversal pass in `Queue.run` so a rescan after the
188
- // child list shifts can tell "already run this pass" from "still pending".
189
- let queueRunToken = 0;
190
-
191
- class Queue {
192
- ve=null;
193
- Lt=[ [], [] ];
194
- Qt=[];
195
- Mt=0;
196
- created=clock;
197
- addChild(e) {
198
- this.Qt.push(e);
199
- e.ve = this;
200
- }
201
- removeChild(e) {
202
- const t = this.Qt.indexOf(e);
203
- if (t >= 0) {
204
- this.Qt.splice(t, 1);
205
- e.ve = null;
206
- }
207
- }
208
- notify(e, t, i, n) {
209
- if (this.ve) return this.ve.notify(e, t, i, n);
210
- return false;
211
- }
212
- run(e) {
213
- if (this.Lt[e - 1].length) {
214
- const t = this.Lt[e - 1];
215
- this.Lt[e - 1] = [];
216
- runQueue(t, e);
217
- }
218
- // Effects run here can dispose owners, and disposal removes queues from
219
- // this list — the running child itself, an earlier sibling, or several at
220
- // once. A plain index walk then skips whatever shifted into the cursor.
221
- // Stamping each child before it runs makes the pass idempotent, so a shift
222
- // can be recovered by rescanning from the front and every child still runs
223
- // exactly once. Children appended mid-pass carry a stale stamp and run,
224
- // matching the previous live-array behaviour.
225
- const t = this.Qt;
226
- const i = ++queueRunToken;
227
- for (let n = 0; n < t.length; ) {
228
- const s = t[n];
229
- if (s.Mt !== i) {
230
- s.Mt = i;
231
- s.run?.(e);
232
- if (t[n] !== s) {
233
- n = 0;
234
- continue;
235
- }
236
- }
237
- n++;
238
- }
239
- }
240
- enqueue(e, t) {
241
- if (e) {
242
- // Route to lane's effect queue if we're in an optimistic recomputation
243
- if (currentOptimisticLane) {
244
- const i = findLane(currentOptimisticLane);
245
- i.en[e - 1].push(t);
246
- } else {
247
- this.Lt[e - 1].push(t);
248
- }
249
- }
250
- schedule();
251
- }
252
- stashQueues(e) {
253
- e.Lt[0].push(...this.Lt[0]);
254
- e.Lt[1].push(...this.Lt[1]);
255
- this.Lt = [ [], [] ];
256
- for (let t = 0; t < this.Qt.length; t++) {
257
- let i = this.Qt[t];
258
- let n = e.Qt[t];
259
- if (!n) {
260
- n = {
261
- Lt: [ [], [] ],
262
- Qt: []
263
- };
264
- e.Qt[t] = n;
265
- }
266
- i.stashQueues(n);
267
- }
268
- }
269
- restoreQueues(e) {
270
- this.Lt[0].push(...e.Lt[0]);
271
- this.Lt[1].push(...e.Lt[1]);
272
- for (let t = 0; t < e.Qt.length; t++) {
273
- const i = e.Qt[t];
274
- let n = this.Qt[t];
275
- if (n) n.restoreQueues(i);
276
- }
277
- }
278
- }
279
-
280
- class GlobalQueue extends Queue {
281
- sn=false;
282
- // The current transaction-shaped batch: a plain ambient batch while no
283
- // transition is active, the active transition itself after initTransition.
284
- k=createBatch();
285
- static Ce;
286
- static Fe;
287
- static tt;
288
- static Vt=null;
289
- // Store-side hook: drops a keyless affects() mark's identity scope when the
290
- // carrier node's last registration releases (wired by store.ts, mirroring
291
- // _clearOptimisticStore).
292
- static G=null;
293
- // affects()-side hooks (wired by affects.ts, mirroring _update): the mark
294
- // engine — count/register/release — lives with the feature. Every call site
295
- // is gated by state only that module creates, so `!` invocations are safe
296
- // once the gate holds.
297
- static M=null;
298
- static h=null;
299
- static j=null;
300
- // External-source bridge (wired by enableExternalSource(); null while no
301
- // config is active — including after _resetExternalSourceConfig()).
302
- static Rt=null;
303
- static Gt=null;
304
- // Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
305
- // imported; null in apps that never use them). Call sites either guard for
306
- // null or sit behind state only the verdict layer can create (`!` is safe
307
- // there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
308
- // verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
309
- // isPending()/latest()).
310
- static Oe=null;
311
- static de=null;
312
- static ye=null;
313
- static un=null;
314
- static Pt=null;
315
- static Dt=null;
316
- static Ht=null;
317
- static Je=null;
318
- static p=null;
319
- static Bt=null;
320
- // Re-asks probes whose verdict was provisionally suppressed by a fresh read
321
- // of a held value, once the transaction gains an async blocker (#3028).
322
- static wt=null;
323
- // Optimistic-engine hooks (wired by core/optimistic.ts via
324
- // installOptimisticEngine(), called from verdict.ts / createOptimistic /
325
- // createOptimisticStore — every module that can create optimistic state).
326
- // Call sites are gated by state only the engine can create: an
327
- // `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
328
- // entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
329
- // once the gate holds.
330
- static vt=null;
331
- static fn=null;
332
- static dn=null;
333
- static En=null;
334
- static Tn=null;
335
- static Ft=null;
336
- static ht=null;
337
- static gt=null;
338
- static je=null;
339
- static $e=null;
340
- static ze=null;
341
- static Nn=null;
567
+ class GlobalQueue {
568
+ un=[ [], [] ];
569
+ Y=false;
342
570
  flush() {
343
- if (this.sn) return;
344
- // Fast drain: nothing in flight but plain pending commits — no dirty
345
- // computeds, no queued effects, no child queues, no transitions/lanes/
346
- // optimistic state. Commit and go; anything a commit hook schedules
347
- // (companion snaps, store folds notifying subs) re-arms `scheduled`
348
- // below and the outer drain loop takes the full spine next round.
349
- if (activeTransition === null && dirtyQueue.EE < dirtyQueue.xe && this.Lt[0].length === 0 && this.Lt[1].length === 0 && this.Qt.length === 0 && canUseSimpleSyncFlush(this)) {
350
- this.sn = true;
351
- try {
352
- commitPendingNodes();
353
- } finally {
354
- this.sn = false;
355
- }
356
- clock++;
357
- scheduled = dirtyQueue.EE >= dirtyQueue.xe || this.Lt[0].length !== 0 || this.Lt[1].length !== 0 || this.k.yt.length !== 0;
358
- return;
359
- }
360
- this.sn = true;
571
+ if (this.Y) return;
572
+ this.Y = true;
573
+ // A28: companions of nodes written since the last flush mirror the
574
+ // flushed world — re-synced inside the running window (the write is
575
+ // "flushed" from here on).
576
+ resyncUnflushedCompanions();
577
+ passLane = null;
578
+ passTx = null;
361
579
  try {
362
- if (false) ;
363
- runHeap(dirtyQueue, GlobalQueue.Ce);
364
- if (activeTransition) {
365
- const e = transitionComplete(activeTransition);
366
- if (!e) {
367
- const e = activeTransition;
368
- // When the parking batch IS the transition, all of its writes commit
369
- // only with it — every zombie recompute they queued would run against
370
- // a world the zombie never displays (zombies render mainline until
371
- // commit), so cancel them instead of running them. Only an ambient
372
- // batch's mainline writes (the #2916 shape below) legitimately reach
373
- // zombies here. Height-adjust entries still process normally: a
374
- // dirtied one keeps its height flag and falls through to runHeap's
375
- // adjustHeight path on the next pass of the bucket.
376
- runHeap(zombieQueue, this.k === e ? cancelZombieRecompute : GlobalQueue.Ce);
377
- // Detach: the stashed transition keeps its batch; ambient work that
378
- // follows lands in a fresh one. If the batch is already a separate
379
- // ambient one — action done() restored activeTransition without
380
- // adopting the batch, and an ordinary write landed there before
381
- // the scheduled flush (#2916) — keep it: replacing it would strand
382
- // its queued pending nodes with held _pendingValues forever.
383
- if (this.k === e) currentBatch = this.k = createBatch();
384
- // Run lane effects immediately (before stashing) - lanes with no pending async
385
- if (activeLanes.size) {
386
- GlobalQueue.Tn(EFFECT_RENDER);
387
- GlobalQueue.Tn(EFFECT_USER);
388
- }
389
- this.stashQueues(e.bt);
390
- clock++;
391
- // A kept ambient batch may hold pending nodes (#2916): stay
392
- // scheduled so the outer drain loop commits them via the plain
393
- // flush path instead of leaving them until the next natural flush.
394
- scheduled = dirtyQueue.EE >= dirtyQueue.xe || this.k.yt.length > 0;
395
- reassignPendingTransition(e.yt);
396
- activeTransition = null;
397
- finalizePureQueue(null, true);
398
- return;
399
- }
400
- const t = activeTransition;
401
- const i = this.k;
402
- i !== t && i.yt.push(...t.yt);
403
- this.restoreQueues(t.bt);
404
- transitions.delete(t);
405
- activeTransition = null;
406
- reassignPendingTransition(i.yt);
407
- finalizePureQueue(t);
408
- if (i === t) {
409
- // Drop the dead Transition wrapper but keep its (drained) containers
410
- // as the ambient batch — late registrations during finalization live
411
- // there and must survive to the next flush.
412
- const e = createBatch();
413
- e.yt = i.yt;
414
- e.Ke = i.Ke;
415
- e.m = i.m;
416
- e.cn = i.cn;
417
- currentBatch = this.k = e;
418
- }
419
- } else {
420
- if (canUseSimpleSyncFlush(this)) {
421
- commitPendingNodes();
422
- if (dirtyQueue.EE >= dirtyQueue.xe) {
423
- runHeap(dirtyQueue, GlobalQueue.Ce);
424
- commitPendingNodes();
425
- }
426
- } else {
427
- if (transitions.size) runHeap(zombieQueue, GlobalQueue.Ce);
428
- finalizePureQueue();
429
- }
430
- }
580
+ // Sweep before the heap: unobserved() pulls swept nodes out of it, so
581
+ // a dormant memo dirtied in the same tick is reclaimed instead of
582
+ // recomputed; late subscribers (an effect reading a swept memo this
583
+ // flush) revive it, which is the pay-for-use contract.
584
+ sweepDormant();
585
+ runHeap(dirtyQueue, GlobalQueue._e);
586
+ this.settle();
431
587
  clock++;
432
- // Check if finalization added items to the heap (from optimistic reversion)
433
- scheduled = dirtyQueue.EE >= dirtyQueue.xe;
434
- // Run lane effects first (for ready lanes), then regular effects
435
- activeLanes.size && GlobalQueue.Tn(EFFECT_RENDER);
588
+ // A write the commit sweep staged with no subscriber to dirty is work
589
+ // too — the next round commits it.
590
+ scheduled = dirtyQueue.Et >= dirtyQueue.Fe || pendingNodes.length !== 0;
436
591
  this.run(EFFECT_RENDER);
437
- activeLanes.size && GlobalQueue.Tn(EFFECT_USER);
438
592
  this.run(EFFECT_USER);
439
- if (false) ;
440
- if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
593
+ if (false && holding) ;
594
+ if (false && !scheduled) ;
441
595
  if (false) ;
442
596
  } finally {
443
- this.sn = false;
597
+ this.Y = false;
598
+ passTx = null;
444
599
  }
445
600
  }
446
- notify(e, t, i, n) {
447
- // Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
448
- if (t & STATUS_PENDING) {
449
- if (i & STATUS_PENDING) {
450
- const t = n !== undefined ? n : e.o?._;
451
- // A visibility-only mark notification (the affects() boundary
452
- // channel) updates display state on its way up but must be invisible
453
- // to completion accounting BY CONSTRUCTION: it never registers a
454
- // reporter and never counts toward the loading-boundary diagnostic.
455
- if (t?.i) return true;
456
- if (activeTransition && t) {
457
- const i = t.source;
458
- let n = activeTransition.Ne.get(i);
459
- if (!n) activeTransition.Ne.set(i, n = new Set);
460
- const s = n.size;
461
- n.add(e);
462
- if (n.size !== s) {
463
- schedule();
464
- GlobalQueue.wt?.(activeTransition);
601
+ /** L2 — the seam: end of the pure phase. Commit this flush's staged nodes,
602
+ * or park them with the transaction the flush joined; then land every
603
+ * transaction no frame is waiting on. The landing flush is an ordinary
604
+ * flush: the settle walk (async.ts) re-ran the parked readers in its pure
605
+ * phase, and here no flight the transaction holds has a frame deriving
606
+ * from it (`blocked`). */ settle() {
607
+ // Lanes: an ended action body judges its guesses now that their passes
608
+ // have run (lanes.ts); a correction's re-derivations run in one more
609
+ // pure round — the parent's flights before the parent is judged below.
610
+ if (laneCorrectionsHook?.()) runHeap(dirtyQueue, GlobalQueue._e);
611
+ const e = flushTransaction;
612
+ flushTransaction = latestOpened = null;
613
+ // The frame's verdict is in: the guesses written since the last seam
614
+ // open their lane under the frame's transaction (a lane's own flush
615
+ // parents a nested lane to it), or are dropped — the frame commits, and
616
+ // there is nothing to be optimistic over. Their passes run next round;
617
+ // a parent landing at this very seam ends the lane before they do.
618
+ applyGuessesHook?.(e);
619
+ // A lane's own flush (its flight landing, its reveal) parks nothing: the
620
+ // lane's work reached it per pass; the frame's plain writes commit.
621
+ // (Resolved: a guess over another transaction's guess merged them.)
622
+ const o = e !== null && !e.P ? resolveTx(e) : null;
623
+ if (o !== null) {
624
+ // `t._nodes` grows under the walk (holdFrame pushes); the bound is
625
+ // this flush's list, which does not.
626
+ const e = pendingNodes.length;
627
+ for (let n = 0; n < e; n++) {
628
+ const e = pendingNodes[n];
629
+ // Already held: the pass that re-staged it joined its transaction,
630
+ // which is `t` (or merged into it). Lane work is the lane's (a
631
+ // pending mark propagated onto it queued it here too).
632
+ if (!(e.l & (CONFIG_HELD | CONFIG_OVERRIDE)) && (e.T === null || e.T.Re === null || !e.T.Re.P)) {
633
+ // A loading source — pending with nothing staged and no committed
634
+ // value (A16, A19 exc. 1: uninitialized is loading, not pending)
635
+ // that is not an observer — is nobody's frame: not held. Its
636
+ // first landing is commit #0, not a resumption of this frame, and
637
+ // a write that reaches it later overlaps nothing (#2937: the
638
+ // stale stamp was the bridge that entangled unrelated updates
639
+ // with a never-resolving flight). Its observers are held and
640
+ // wait on its flight (`blocked`).
641
+ if (e.ue === NOT_PENDING && e.m & STATUS_UNINITIALIZED && e.i !== EFFECT_RENDER) continue;
642
+ // A34 (2): a tick whose writes net to the committed value made no
643
+ // proposal (`setShow(false); setShow(true)` on a committed true) —
644
+ // not staged, not held, pends nothing; a later write to it is
645
+ // plain mainline. (A node already held stays held when written
646
+ // back: A34 (1).)
647
+ if (e.ue !== NOT_PENDING && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.T?.me == null && e.T?.Le == null &&
648
+ // The comparator last: a pass that created children (an object
649
+ // owning a fresh async memo, #4111) must not have it read them.
650
+ // A NotReady read there is a change (`isSame`).
651
+ isSame(e, e.le, e.ue)) {
652
+ e.ue = NOT_PENDING;
653
+ e.l &= ~CONFIG_STAGED;
654
+ continue;
465
655
  }
656
+ holdNode(e, o);
466
657
  }
658
+ // A held pass's frame is held with it (ruling A, O2): the children it
659
+ // created are the transaction's — they compute, and a pass over them
660
+ // or a write that reaches them joins; they effect at the landing.
661
+ if (e.l & CONFIG_STAGED) holdFrame(e, o);
662
+ }
663
+ pendingNodes.length = 0;
664
+ storeParkHook?.(o);
665
+ // (This flush's runs are stashed with `t` below — after the landings,
666
+ // so a `t` that lands at this very seam runs them first, ahead of
667
+ // the runs it held from earlier flushes.)
668
+ // The batch joins: the writes that dirtied these are held with it — a
669
+ // zombie never displays that world. A verdict reader among them does
670
+ // (#3444: `latest()` inside a branch a held Show is removing peers
671
+ // through like the same read outside): it re-runs now, as the
672
+ // holder's verdict lane's work — before the lane seams, which reveal
673
+ // it (nothing commits this seam that could dispose it).
674
+ // (Verdict readers exist only with the verdict engine installed.)
675
+ const n = deferredZombies.splice(0);
676
+ if (observeFlightHook) {
677
+ n.sort((e, o) => e.he - o.he);
678
+ for (let e = 0; e < n.length; e++) if ((n[e].R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE && n[e].l & CONFIG_VERDICT) recompute(n[e]);
679
+ }
680
+ // The unchanged passes' tails stay linked (A30, #3469): their inputs
681
+ // are held, and the committed frame still derives from them — no trim.
682
+ } else {
683
+ commitPendingNodes();
684
+ // The flush committed: an unchanged pass's stale tail goes now. Not
685
+ // after a later pass this flush that threw (NotReady included — it
686
+ // keeps its full list, `_depsTail` marking where it stopped) or that
687
+ // left an effect owing a run (`runEffect` trims when the run applies):
688
+ // `recompute`'s own gates.
689
+ for (let e = 0; e < heldTrims.length; e++) {
690
+ const o = heldTrims[e];
691
+ if (o.T?.U == null && !o.Ae) trimStaleDeps(o);
467
692
  }
468
- return true;
469
693
  }
470
- return false;
471
- }
472
- initTransition(e) {
473
- if (e) e = currentTransition(e);
474
- if (e && e === activeTransition) return;
475
- if (!e && activeTransition && activeTransition.Te === clock) return;
476
- if (!activeTransition) {
477
- activeTransition = e ?? createBatch();
478
- } else if (e) {
479
- const t = activeTransition;
480
- mergeTransitionState(e, t);
481
- transitions.delete(t);
482
- activeTransition = e;
694
+ // The list is the flush's either way. Reset only when there is something
695
+ // to reset (`stagedReaders` below likewise): `length = 0` is a runtime
696
+ // call even on an empty array, and the plain flush — no unchanged pass,
697
+ // no lane work — has nothing in either.
698
+ if (heldTrims.length) heldTrims.length = 0;
699
+ // Lanes: a blocked one parks its frame (its own flight is up); an
700
+ // unblocked one reveals this round's work. Then land every transaction
701
+ // no frame is waiting on — its lanes end with it. Backwards: a landing
702
+ // removes its entry.
703
+ // This flush's own runs, the lanes' reveals, and the landings' held runs
704
+ // are collected apart and ordered below.
705
+ const n = this.un;
706
+ const l = [ [], [] ];
707
+ // The passes that read this frame's stagings as the screen read held
708
+ // writes if it parked: the lane seam re-derives them on the committed
709
+ // world (a lane's runs wait this round).
710
+ if (laneSeamsHook) {
711
+ this.un = l;
712
+ laneSeamsHook(o);
713
+ if (stagedReaders.length) stagedReaders.length = 0;
483
714
  }
484
- transitions.add(activeTransition);
485
- activeTransition.Te = clock;
486
- const t = this.k;
487
- if (t !== activeTransition) {
488
- // Adopt the ambient batch into the transaction, then make the
489
- // transaction the batch so later registrations land there directly.
490
- // Pending and optimistic nodes are re-stamped as the transaction's;
491
- // marks don't hijack the node's _transition — a mark on a plain signal
492
- // must not entangle unrelated writes to it; the same rule holds one hop
493
- // downstream: propagation never queues pended subscribers as pending
494
- // nodes, see propagateAffectsMark, #2893.
495
- for (let e = 0; e < t.yt.length; e++) {
496
- const i = t.yt[e];
497
- i._e = activeTransition;
498
- activeTransition.yt.push(i);
499
- }
500
- for (let e = 0; e < t.Ke.length; e++) {
501
- const i = t.Ke[e];
502
- i._e = activeTransition;
503
- activeTransition.Ke.push(i);
715
+ this.un = [ [], [] ];
716
+ for (let e = transactions.length - 1; e >= 0; e--) {
717
+ const o = transactions[e];
718
+ if (blocked(o)) continue;
719
+ transactions.splice(e, 1);
720
+ endLanesHook?.(o);
721
+ land(o);
722
+ // A landing's commits can dispose a zombie a transaction judged above
723
+ // was blocked on (#3463: live "until the commit that disposes it") —
724
+ // judge them again.
725
+ e = transactions.length;
726
+ }
727
+ // The store folds the pending backings whose container nodes committed
728
+ // — this flush's, or a landing's (store/store.ts installs it).
729
+ storeCommitHook?.();
730
+ // Marks declared outside a transaction: the flush that carried them
731
+ // parked (something async below) — the window is the frame's, the marks
732
+ // are its transaction's; else they release at the seam, verdict-only,
733
+ // nothing to show (affects.ts).
734
+ const t = o && liveTx(o);
735
+ releaseAmbientMarksHook?.(t);
736
+ // The effect phase: lane work first (displayed ahead of the frame), then
737
+ // this flush's runs, then the runs the landings held from earlier
738
+ // flushes — as one pass would have queued them (#3540: a shell
739
+ // re-derived at the landing before a boundary swap held since the
740
+ // write; #3528: a display-ahead swap before the count it is shown
741
+ // beside). A parked frame's runs wait with its transaction instead: the
742
+ // effect phase applies a committed frame.
743
+ const s = t !== null;
744
+ for (let e = 0; e < 2; e++) {
745
+ if (s) append(t.un[e], n[e]);
746
+ // The plain flush — no reveal, no landing, not parked — has nothing to
747
+ // order around its own runs: they are the queue as they stand (the
748
+ // same array, not a copy; `run` takes it whole). Every other seam
749
+ // builds the ordered queue above.
750
+ this.un[e] = s || l[e].length || this.un[e].length ? l[e].concat(s ? [] : n[e], this.un[e]) : n[e];
751
+ }
752
+ if (deferredZombies.length !== 0) {
753
+ // Survivors are the displayed frame of a held pass: they rerun for the
754
+ // live write, parents before children.
755
+ const e = deferredZombies.splice(0).sort((e, o) => e.he - o.he);
756
+ for (let o = 0; o < e.length; o++) {
757
+ if (!(e[o].R & REACTIVE_DISPOSED)) recompute(e[o]);
504
758
  }
505
- if (t.m.length) activeTransition.m.push(...t.m);
506
- for (const e of t.cn) activeTransition.cn.add(e);
507
- // Gated readers recorded against the ambient batch move with it: their
508
- // replay-at-commit now happens at the transaction's completion.
509
- if (t.ln.size) {
510
- for (const e of t.ln) activeTransition.ln.add(e);
511
- t.ln.clear();
759
+ }
760
+ // Boundaries: readers that settled, landed or died this flush are
761
+ // dropped; a fallback with none left reveals next round.
762
+ boundarySeamHook?.();
763
+ }
764
+ run(e) {
765
+ const o = this.un[e - 1];
766
+ if (o.length) {
767
+ this.un[e - 1] = [];
768
+ runQueue(o, e);
769
+ }
770
+ }
771
+ enqueue(e, o, n = passLane) {
772
+ // Lane work's runs are the lane's: they run at its reveal, not with
773
+ // the frame (which may park). A lane pass that read the frame's own
774
+ // staging is the frame's (`recompute` passes null): its run waits with
775
+ // the frame.
776
+ if (e) (n !== null ? n : this).un[e - 1].push(o);
777
+ schedule();
778
+ }
779
+ /** Status reaching the root: pending is absorbed (the root mount defers —
780
+ * dev records it for the ASYNC_OUTSIDE_LOADING_BOUNDARY FYI); an error is
781
+ * unhandled (`false` → the caller halts).
782
+ *
783
+ * L2: this is where a transaction is registered. Pending that reaches an
784
+ * observer (a render effect: the frame) is a frame that cannot show — the
785
+ * flush parks, and the transaction waits on the flight while a frame
786
+ * derives from it (`blocked`). Pending nobody observes holds nothing: a
787
+ * memo in flight that no frame reads is not a frame waiting. (Base: the
788
+ * queue's `_asyncReporters`, INV-3's one registration site.)
789
+ *
790
+ * A boundary between the observer and the root (boundaries.ts) is asked
791
+ * first: a fallback catches what is not ready under it, and the root
792
+ * never hears of it. */ notify(e, o, n, l) {
793
+ if (catchHook?.(e, n & o, l)) return true;
794
+ if (o & STATUS_PENDING) {
795
+ if (n & STATUS_PENDING) {
796
+ // A pass that went pending holds its frame: the async's own
797
+ // synchronous frame is not ready (A15 reveal corollary: a reveal
798
+ // that discovers a flight whose inputs are visible holds and joins
799
+ // it; one whose inputs are held is a stale reader and never gets
800
+ // here — `read` serves it the committed value). The frame's, not the
801
+ // observer's: a render effect belongs to whoever dirtied its pass
802
+ // (A15 shared-hole, #3407) — one held by T1 and re-run by T2's write
803
+ // pends for T2's flight, and the two stay parallel; a frame that is
804
+ // T1's already joined T1 through the write or the memo that made it
805
+ // so. Outside a flush — root setup, a mount — the frame is the
806
+ // mount's: its pending observers are one transaction, and a flight
807
+ // started in it resumes it when it lands (maintainer, #3461: "part
808
+ // of the same one"); what the mount published synchronously stays
809
+ // published. Lane work going pending holds the lane, not the frame:
810
+ // `blocked(lane)` finds it in the lane's staging ("if further async
811
+ // downstream is hit it holds like its own transition").
812
+ if (passLane === null) joinFuture(null);
512
813
  }
513
- currentBatch = this.k = activeTransition;
814
+ return true;
514
815
  }
515
- for (const e of activeLanes) {
516
- if (!e._e) e._e = activeTransition;
816
+ return false;
817
+ }
818
+ }
819
+
820
+ /** A15's stale readers: a frame whose LAST pass read a held node as
821
+ * committed re-derives on the landed world — next round, after the commits.
822
+ * One re-derived since (any later pass cleared the bit: in the transaction,
823
+ * or without the held read) owes nothing. A run this transaction stashed
824
+ * for it is void (#3322: an effect has one value slot, and the stale pass
825
+ * overwrote the value that run was for) — the re-derivation's run replaces
826
+ * it. Truthy when an effect re-derives (`land`). */ function reruns(e) {
827
+ let o;
828
+ for (let n = 0; n < e.En.length; n++) {
829
+ const l = e.En[n];
830
+ // An errored reader's display is its error (D-39): the landing gives it
831
+ // nothing to re-derive, and a re-run would be a read that retries the
832
+ // errored source (#3945) — unless that source is errored no longer: the
833
+ // reader was served a shown error the landing replaces (`throwShown`).
834
+ // Nor is the reader's own error: its pass threw over the committed value
835
+ // of what the landing carries, served as the screen (A10; a lane's node
836
+ // reading its parent's hold, or a pass with no value yet reading a
837
+ // staging, `stagedScreen`) — the landing is the new answer, and the
838
+ // reader re-derives on it (A15; D-39). A first load read so has no other
839
+ // run: its error would stay the screen (async-gen 91501 #1158, #119).
840
+ // A boundary's structure (its tree, its output: CONFIG_FRAME, no effect
841
+ // type) re-derives all the same: what it read as the screen is the
842
+ // content the landing replaces, and only its pass links the new content
843
+ // whose recovery must reach it (D-3, D-39, #4405).
844
+ const t = l.T?.U?.source;
845
+ if (l.R & REACTIVE_DISPOSED || l.m & STATUS_ERROR && (l.i || !(l.l & CONFIG_FRAME)) && t !== l && (t?.m ?? STATUS_ERROR) & STATUS_ERROR) continue;
846
+ if (l.R & REACTIVE_FRAME_READ || observeFlightHook && l.l & CONFIG_VERDICT) {
847
+ // A memo re-deriving its own error holds the release as an effect
848
+ // does (`land`): run first, the held runs showed that error beside a
849
+ // frame about to replace it (#4407; #4284: the grouping never changes
850
+ // the screen).
851
+ o ||= l.i || t === l;
852
+ // A lane's reveal leaves the mark to the transaction: a reader that
853
+ // also read a held node as committed (`staleReader`) still observes
854
+ // that flight until it re-runs — cleared here, the transaction landed
855
+ // at this seam with the flight up and voided the reveal's run (#4397).
856
+ if (!e.P) l.R &= ~REACTIVE_FRAME_READ;
857
+ l.Ae = false;
858
+ // Its frame is replaced by the re-derivation: a run one of its
859
+ // children queued this flush (re-run by the same landing) is for the
860
+ // frame being replaced — void too (#3404).
861
+ for (let e = l.pe; e !== null; e = e.Ge) if (e.i) e.Ae = false;
862
+ // A frame flight the seam parked (lanes.ts `laneSeams`, R5) asked the
863
+ // question this landing would: adopted, it is asked once (F-9).
864
+ if (!laneAdoptHook?.(l)) enqueueSub(l);
517
865
  }
518
866
  }
867
+ e.En.length = 0;
868
+ return o;
519
869
  }
520
870
 
521
- function queuePendingNode(e) {
522
- currentBatch.yt.push(e);
871
+ /** The landing: the held frame becomes the frame. */ function land(e) {
872
+ const o = reruns(e);
873
+ if (releaseMarksHook && e.I !== null) releaseMarksHook(e.I);
874
+ // Old children die in the commits (cleanups first), then the stashed
875
+ // effects run ahead of this flush's own. A node a lane took over since
876
+ // (a guess written over the staged truth) is the lane's to land.
877
+ for (let o = 0; o < e.tn.length; o++) {
878
+ const n = e.tn[o];
879
+ if (n.T.Re === null || txOf(n) !== e) continue;
880
+ n.T.Re = null;
881
+ commitPendingNode(n);
882
+ }
883
+ // A cleanup those commits ran that wrote a node `u` still held joined
884
+ // `u`, which has left `transactions`: the write is this landing's, and
885
+ // the next flush must not park in it (#4089).
886
+ if (flushTransaction === e) flushTransaction = null;
887
+ // An effect re-derives next round (`reruns`): the held runs wait for it
888
+ // (D-9, the A15 reveal corollary, #4071). Its re-derivation can discover a
889
+ // flight — a stale reader whose mainline pass stopped reading it, now
890
+ // reading the landed world — and a landing that showed its runs first
891
+ // would reveal the held write beside a frame that can only show its old
892
+ // value. Queued last in this effect phase, the release hands them to the
893
+ // next round's own runs, ahead of the re-derivation's: they show with it,
894
+ // or park with it in the hold its pending opens. The commits stand.
895
+ if (o) globalQueue.un[1].push(() => releaseQueues(e)); else releaseQueues(e);
896
+ }
897
+
898
+ /** The held runs join this flush's effect phase after its own runs (the
899
+ * landing's re-passes, in height order): the frame's effects run as one
900
+ * pass would have queued them — a shell re-derived at the landing before a
901
+ * boundary swap held since the write (#3540's log order). */ function releaseQueues(e) {
902
+ for (let o = 0; o < 2; o++) {
903
+ append(globalQueue.un[o], e.un[o]);
904
+ e.un[o] = [];
905
+ }
906
+ }
907
+
908
+ /** `a.push(...b)` without the argument-count limit. */ function append(e, o) {
909
+ for (let n = 0; n < o.length; n++) e.push(o[n]);
523
910
  }
524
911
 
525
- // Sticky: flips true on the first refresh() ever (the only setter of
526
- // REACTIVE_REASK) so the hot notification loop skips the per-subscriber flag
527
- // clear entirely in apps that never refresh.
528
- let reaskArmed = false;
912
+ /** Nodes staged this flush (`_pendingValue` set), committed at its end. */ const pendingNodes = [];
913
+
914
+ /** Passes that read a staging of this flush as the screen — lane work
915
+ * (core.ts `stagedRead`), a verdict reader before the frame's verdict
916
+ * (verdict.ts): if the frame parks they read a held write — re-derived next
917
+ * round (lanes.ts; a lane's runs wait that round). */ const stagedReaders = [];
918
+
919
+ /** A15's stale reader: `c` was served the committed value of a node `t`
920
+ * holds (a render effect, a verdict reader, lane work) and is re-derived
921
+ * after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e, o) {
922
+ if (!(e.R & REACTIVE_FRAME_READ)) {
923
+ e.R |= REACTIVE_FRAME_READ;
924
+ o.En.push(e);
925
+ }
926
+ }
927
+
928
+ function queuePendingNode(e) {
929
+ pendingNodes.push(e);
930
+ if (!globalQueue.Y) markUnflushedStaged();
931
+ // A28
932
+ }
529
933
 
530
934
  /** §12d: bumped by every recompute and every new subscriber edge. A node's
531
935
  * staged-rewrite skip is sound only while NOTHING recomputed or linked since
@@ -536,29 +940,17 @@ function bumpNotifyEpoch() {
536
940
  notifyEpoch++;
537
941
  }
538
942
 
539
- function armReaskClear() {
540
- reaskArmed = true;
541
- }
542
-
543
- function insertSubs(e, t = false) {
943
+ function insertSubs(e) {
544
944
  // §12d: stamp before walking — setSignal's staged-rewrite fast path skips
545
945
  // the next walk for this node while the epoch holds (marking is idempotent).
546
- e._t = notifyEpoch;
547
- // Get source lane: prefer node's own lane over current context
548
- // This is important for isPending signals which need their own lane to flush immediately
946
+ e.Me = notifyEpoch;
549
947
  // Presence bits gate the optional-slot probes (see constants.ts): one
550
948
  // masked read of the always-present _config instead of missing-property
551
- // lookups in the hottest notify loop. Bits are sticky — the field read
552
- // stays authoritative when a bit is set.
553
- const i = e.T;
554
- const n = (i & CONFIG_HAS_LANE ? e.o?.Be : undefined) || currentOptimisticLane;
555
- const s = (i & CONFIG_HAS_SNAPSHOT) !== 0 && e.o?.Qe !== undefined;
556
- const o = reaskArmed;
557
- for (let i = e.u; i !== null; i = i.fe) {
558
- const e = i.ae;
559
- // A value-change notification is a new question for the subscriber: any
560
- // pending re-ask mark (refresh) it carried is superseded.
561
- if (o) e.ie &= ~REACTIVE_REASK;
949
+ // lookups in the hottest notify loop.
950
+ const o = e.l;
951
+ const n = (o & CONFIG_HAS_SNAPSHOT) !== 0 && e.T?.De !== undefined;
952
+ for (let o = e.o; o !== null; o = o.t) {
953
+ const e = o.u;
562
954
  // Missed-wake latch (#3037): this write is landing while the subscriber
563
955
  // is mid-recompute (a nested pull committing beneath its reads), and the
564
956
  // heap refuses RECOMPUTING nodes. A gen-current link means the pass
@@ -567,159 +959,126 @@ function insertSubs(e, t = false) {
567
959
  // pass either re-reads them fresh or trims them), and neither does the
568
960
  // tail link: it is the read IN FLIGHT — read() links before it pulls, so
569
961
  // this very commit is what that read returns.
570
- if (e.ie & REACTIVE_RECOMPUTING_DEPS && i.ll === e.Ze && i !== e.Ye) e.ie |= REACTIVE_MISSED_WAKE;
571
- if (s && e.T & CONFIG_IN_SNAPSHOT_SCOPE) {
572
- e.ie |= REACTIVE_SNAPSHOT_STALE;
962
+ if (e.R & REACTIVE_RECOMPUTING_DEPS && o.Ne === e.de && o !== e._) e.R |= REACTIVE_MISSED_WAKE;
963
+ if (n && e.l & CONFIG_IN_SNAPSHOT_SCOPE) {
964
+ e.R |= REACTIVE_SNAPSHOT_STALE;
573
965
  continue;
574
966
  }
575
- if (t && n) {
576
- e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
577
- assignOrMergeLane(e, n);
578
- } else if (t) {
579
- e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
580
- // No source lane means reversion - clear subscriber's lane so effects go to regular queue
581
- if (e.o) e.o.Be = undefined;
582
- }
583
967
  enqueueSub(e);
584
968
  }
585
969
  }
586
970
 
971
+ /** Lane work re-staged (lanes.ts; `recompute`): the lane's members among
972
+ * its subscribers re-derive as the lane's work (REACTIVE_LANE_DIRTY), their
973
+ * runs held with it — not as stale readers republishing the committed view
974
+ * (#3460). After `insertSubs`. A render effect on no lane is marked too:
975
+ * inert for its pass (`recompute` seats a lane only from its own `_x`), it
976
+ * is a live write if the effect becomes a zombie later this flush — an
977
+ * on-screen reader whose removal an adopted write stages follows the lane
978
+ * (the lane-membership ruling, 2026-10-05; `_update`).
979
+ *
980
+ * A render effect re-run by a verdict memo's change (`createMemo(() =>
981
+ * latest(x))`, CONFIG_VERDICT) is the verdict reader the same read inline
982
+ * makes it, for that pass (F-6; D-26 `[s(), L()]`, #4284): a frame reader
983
+ * of its other reads — a staging's screen, a flight's committed value. One
984
+ * an earlier propagation this flush seated in another lane leaves that
985
+ * seat: its pass starts from the frame's, as the inline effect's does, and
986
+ * `laneRead` re-derives it on the screen if that lane holds (`entered`). */ function laneDirty(e, o) {
987
+ for (let n = e.o; n !== null; n = n.t) {
988
+ const l = n.u, t = l.T?.Re;
989
+ if (l.i === EFFECT_RENDER && e.l & CONFIG_VERDICT) l.l |= CONFIG_VERDICT, l.R &= ~REACTIVE_LANE_DIRTY;
990
+ if (t?.P ? sameLane(t, o) : l.i) l.R |= REACTIVE_LANE_DIRTY;
991
+ }
992
+ }
993
+
994
+ /** One lane, or two of one link group (#3335): one reveal unit. */ function sameLane(e, o) {
995
+ return e === o || e.en !== null && e.en === o.en;
996
+ }
997
+
587
998
  function commitPendingNode(e) {
588
- const t = e;
589
- if (!t.Se) {
590
- if (e.Pe !== NOT_PENDING) {
591
- e.be = e.Pe;
592
- e.Pe = NOT_PENDING;
999
+ const o = e;
1000
+ // L2: the commit is where a pass, held or not, stops being uncommitted —
1001
+ // unless it has no answer yet. A pass still in flight (pending, nothing
1002
+ // staged) stays uncommitted: a re-pass disposes its children on the spot,
1003
+ // and the frame it parked stays the frame until a pass of this node
1004
+ // commits a value.
1005
+ if (!o.X) {
1006
+ e.l &= -385;
1007
+ if (e.ue !== NOT_PENDING) {
1008
+ e.le = e.ue;
1009
+ e.ue = NOT_PENDING;
593
1010
  }
594
- if (e.T & CONFIG_HAS_COMPANIONS) GlobalQueue.un(e);
595
1011
  return;
596
1012
  }
597
- if (e.Pe !== NOT_PENDING) {
598
- e.be = e.Pe;
599
- e.Pe = NOT_PENDING;
600
- // Set _modified for effects, but not for tracked effects (they handle their own scheduling)
601
- if (e.Re && e.Re !== EFFECT_TRACKED) e.Xe = true;
1013
+ // Computeds only from here (`_statusFlags` is not a signal field). A
1014
+ // commit beneath a flight publishes its inputs (A15 reveal corollary,
1015
+ // #3305): a reveal of it must observe, not show the pre-flight value.
1016
+ const n = e.ue === NOT_PENDING && (o.m & STATUS_PENDING) !== 0;
1017
+ const l = e.l & CONFIG_STAGED_ERROR;
1018
+ // An answer commits: the error it replaces leaves the display (D-41).
1019
+ if (!n && o.T) o.T.Te = null;
1020
+ e.l = n ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
1021
+ // D-41: the staged answer is an error — published now, when a value would
1022
+ // show, through the ordinary error path (`stageError`). Its readers first
1023
+ // see it in the cycle after this seam: a tracked re-read there is not a
1024
+ // retry (`read`), or a boundary re-derived by it would retry it forever.
1025
+ if (l) {
1026
+ const n = e.ue;
1027
+ e.ue = NOT_PENDING;
1028
+ e.ie = clock + 1;
1029
+ notifyStatus(o, STATUS_ERROR, n);
1030
+ } else if (e.ue !== NOT_PENDING) {
1031
+ e.le = e.ue;
1032
+ e.ue = NOT_PENDING;
1033
+ // A node born staged (recompute) initializes at this commit.
1034
+ o.m &= ~STATUS_UNINITIALIZED;
1035
+ // A quiet re-ask's classification survives its landing and dies with
1036
+ // the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
1037
+ // the reveal. (The sweep of a node still in flight is not a landing.)
1038
+ // The A28 stash goes with it.
1039
+ if (o.T != null) o.T.Ve = false, o.T.je = NOT_PENDING;
1040
+ // An effect with a staged value was born held (L2): its first run is
1041
+ // this commit's, not its creation's (A29) — queue it now.
1042
+ if (e.i && e.i !== EFFECT_TRACKED) {
1043
+ e.Ae = true;
1044
+ globalQueue.enqueue(e.i, e.W ??= GlobalQueue.q.bind(null, o));
1045
+ }
602
1046
  }
603
- // The committed hold is the first observable answer for a loading-window
1047
+ // The committed value is the first observable answer for a loading-window
604
1048
  // node — the window closes here, not at compute time (#2990). Unconditional
605
1049
  // store to an always-present computed slot.
606
- t.Ie = false;
607
- t.ie &= ~REACTIVE_MANUAL_WRITE;
608
- if (!(t.S & STATUS_PENDING)) t.S &= ~STATUS_UNINITIALIZED;
609
- if (t.o != null && (t.o.qe !== null || t.o.We !== null)) GlobalQueue.Fe(t, false, true);
610
- if (e.T & CONFIG_HAS_COMPANIONS) GlobalQueue.un(e);
611
- }
612
-
613
- // Store commit hook (INTERNALS-STORE-STATE.md §3): installed by the store
614
- // module at init (same treeshakeable pattern as _resolveOptimistic /
615
- // _clearOptimisticStores). Folds committed store-node values into their
616
- // backing objects at the same moment pending values commit — the single
617
- // mutation point of the owned-raw model.
618
- let storeCommitHook = null;
619
-
620
- function setStoreCommitHook(e) {
621
- storeCommitHook = e;
1050
+ o.ce = false;
1051
+ o.R &= ~REACTIVE_MANUAL_WRITE;
1052
+ // The dependencies of the pass that produced the value are the frame's now:
1053
+ // the previous frame's tail goes (A30, #3410; `recompute` left it for a
1054
+ // staged pass). Only after a clean pass: `_error` is cleared by a clean
1055
+ // pass or by the node's own landing (whose pass was clean), so a set
1056
+ // `_error` means the last pass threw, kept its full list, and `_depsTail`
1057
+ // marks where it stopped.
1058
+ if (o.T?.U == null) trimStaleDeps(o);
1059
+ if (!(o.m & STATUS_PENDING)) o.m &= ~STATUS_UNINITIALIZED;
1060
+ // L2: the children this commit publishes are the frame's now — the frame
1061
+ // they replace, parked by the pass (`recompute`), goes.
1062
+ if (!n && o.T != null && (o.T.me !== null || o.T.Le !== null)) GlobalQueue.Ce(o, false, true);
622
1063
  }
623
1064
 
624
1065
  function commitPendingNodes() {
625
- const e = currentBatch.yt;
626
- for (let t = 0; t < e.length; t++) {
627
- commitPendingNode(e[t]);
628
- }
629
- e.length = 0;
630
- storeCommitHook?.();
631
- }
632
-
633
- function finalizePureQueue(e = null, t = false) {
634
- // For incomplete transitions, skip pending resolution and optimistic reversion
635
- // For completing transitions or no-transition, resolve pending and revert optimistic
636
- const i = !t;
637
- if (i) commitPendingNodes();
638
- if (!t && globalQueue.Qt.length) checkBoundaryChildren(globalQueue);
639
- const n = dirtyQueue.EE >= dirtyQueue.xe;
640
- if (n) runHeap(dirtyQueue, GlobalQueue.Ce);
641
- if (i) {
642
- if (n) commitPendingNodes();
643
- // The settling batch: the completing transaction's, or the ambient one.
644
- const t = e ?? globalQueue.k;
645
- // Optimistic reversion: a non-empty batch means _optimisticWrite ran,
646
- // which installed the engine's hooks.
647
- if (t.Ke.length) GlobalQueue.fn(t.Ke);
648
- // Replay entanglement: subs recorded by the read-time gate get rescheduled
649
- // so they re-run with the now-committed values visible. The ambient batch
650
- // replays too — laneReadsCommitted records readers whose committed-view
651
- // read hid a same-tick plain write that just committed above (#2963).
652
- if (t.ln.size) {
653
- for (const e of t.ln) {
654
- if (e.ie & REACTIVE_DISPOSED) continue;
655
- enqueueSub(e);
656
- }
657
- t.ln.clear();
658
- // A completing transition keeps the outer flush loop alive by itself;
659
- // the ambient batch needs the re-arm or the replay sits in the heap
660
- // until the next unrelated write.
661
- schedule();
662
- }
663
- // Declared motion ends with the transaction: settle (or plain flush end
664
- // for ambient marks) releases each registration's refcount. A non-empty
665
- // batch means registerAffectsMark ran, which installed the hook. Marks
666
- // held boundary display state through the visual channel, and their
667
- // release is the display-state update point — re-run the boundary sweep
668
- // (the earlier sweep above ran while the marks were still live).
669
- if (t.m.length) {
670
- GlobalQueue.M(t.m);
671
- if (globalQueue.Qt.length) checkBoundaryChildren(globalQueue);
672
- }
673
- // A non-empty set means trackOptimisticStore ran, which installed the
674
- // hook; the hook iterates, clears, and schedules (keeping the loop out of
675
- // core lets esbuild shake it — rollup already folds the null guard). The
676
- // completing transition scopes the clear to its own layer keys (#2899).
677
- if (t.cn.size) GlobalQueue.Vt(t.cn, e);
678
- sweepTransientStoreNodes();
679
- // Lanes only enter activeLanes through the engine's getOrCreateLane.
680
- if (activeLanes.size) GlobalQueue.En(e);
681
- }
682
- }
683
-
684
- function checkBoundaryChildren(e) {
685
- for (const t of e.Qt) {
686
- t.se?.();
687
- checkBoundaryChildren(t);
688
- }
689
- }
690
-
691
- /**
692
- * Count of live `affects()` registrations across the system (including
693
- * store-scope inherited marks). Gates the read-path mark check in `read()` so
694
- * graphs that never use the feature pay one integer compare.
695
- */ let activeAffectsMarks = 0;
696
-
697
- /**
698
- * Counter mutation seam for the mark engine in affects.ts: an imported `let`
699
- * binding is read-only, and the read-path gate above must stay a plain module
700
- * variable so `read()` pays one integer compare, not a function call.
701
- *
702
- * @internal
703
- */ function shiftAffectsMarks(e) {
704
- activeAffectsMarks += e;
705
- }
706
-
707
- function reassignPendingTransition(e) {
708
- for (let t = 0; t < e.length; t++) {
709
- e[t]._e = activeTransition;
1066
+ for (let e = 0; e < pendingNodes.length; e++) {
1067
+ const o = pendingNodes[e];
1068
+ // A node a lane pass re-staged this round is the lane's to reveal; one
1069
+ // a transaction holds (born held by a mainline pass, `passTx`) is that
1070
+ // transaction's to commit, at its landing.
1071
+ if (!(o.l & (CONFIG_OVERRIDE | CONFIG_HELD))) commitPendingNode(o);
710
1072
  }
1073
+ pendingNodes.length = 0;
711
1074
  }
712
1075
 
713
1076
  const globalQueue = new GlobalQueue;
714
1077
 
715
- // Hot-path mirror of `globalQueue._batch`: `queuePendingNode` runs once per
716
- // staged write and `commitPendingNodes` once per flush, and the extra
717
- // property hop through `_batch` was a measured instruction-count regression
718
- // (CodSpeed update1to1, PR #2905). The field stays authoritative for
719
- // cross-module readers; every `_batch` assignment updates both.
720
- let currentBatch = globalQueue.k;
721
-
722
1078
  function flush(e) {
1079
+ if (actionDepth > 0) {
1080
+ return e ? e() : undefined;
1081
+ }
723
1082
  if (e) {
724
1083
  syncDepth++;
725
1084
  try {
@@ -734,73 +1093,20 @@ function flush(e) {
734
1093
  }
735
1094
  }
736
1095
  }
737
- if (globalQueue.sn) {
1096
+ if (globalQueue.Y) {
738
1097
  return;
739
1098
  }
740
1099
  if (halted) return;
741
- // `flush()` is an explicit drain point, so it must also process an active
742
- // transition even if no microtask was scheduled for it yet.
743
- while (scheduled || activeTransition) {
1100
+ while (scheduled) {
744
1101
  globalQueue.flush();
745
1102
  }
1103
+ // A cleanup that threw during the drain, now that the drain is complete
1104
+ // (owner.ts).
1105
+ rethrowCleanupError();
746
1106
  }
747
1107
 
748
- function runQueue(e, t) {
749
- for (let i = 0; i < e.length; i++) e[i](t);
750
- }
751
-
752
- function reporterBlocksSource(e, t) {
753
- if (e.ie & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
754
- if (e.o?.le?.has(t)) return true;
755
- for (let i = e.nt; i; i = i.it) {
756
- let e = i.ut;
757
- while (e) {
758
- if (e === t || e.lt === t) return true;
759
- e = e.o?.It;
760
- }
761
- }
762
- return !!(e.S & STATUS_PENDING && e.o?._ instanceof NotReadyError && e.o?._.source === t);
763
- }
764
-
765
- function transitionComplete(e) {
766
- if (e.an) return true;
767
- if (e.oe.length) return false;
768
- let t = true;
769
- for (const [i, n] of e.Ne) {
770
- let s = false;
771
- for (const e of n) {
772
- if (reporterBlocksSource(e, i)) {
773
- s = true;
774
- break;
775
- }
776
- n.delete(e);
777
- }
778
- if (!s) e.Ne.delete(i); else if (i.S & STATUS_PENDING && i.o?._?.source === i) {
779
- t = false;
780
- break;
781
- }
782
- }
783
- // Override blockage lives with the engine (absent hook = "no optimistic
784
- // blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
785
- // no-ops when the transition holds neither, so no pre-check is needed.
786
- if (t && GlobalQueue.dn?.(e)) t = false;
787
- t && (e.an = true);
788
- return t;
789
- }
790
-
791
- function currentTransition(e) {
792
- while (e.an && typeof e.an === "object") e = e.an;
793
- return e;
794
- }
795
-
796
- function runInTransition(e, t) {
797
- const i = activeTransition;
798
- try {
799
- activeTransition = currentTransition(e);
800
- return t();
801
- } finally {
802
- activeTransition = i;
803
- }
1108
+ function runQueue(e, o) {
1109
+ for (let n = 0; n < e.length; n++) e[n](o);
804
1110
  }
805
1111
 
806
- export { GlobalQueue, Queue, activeAffectsMarks, activeLanes, activeTransition, armReaskClear, assignOrMergeLane, bumpNotifyEpoch, clock, currentTransition, dirtyQueue, enforceLoadingBoundary, finalizePureQueue, findLane, flush, globalQueue, haltReactivity, insertSubs, notifyEpoch, projectionWriteActive, queuePendingNode, reaskArmed, resetErrorHalt, runInTransition, schedule, setProjectionWriteActive, setStoreCommitHook, shiftAffectsMarks, storeCommitHook, zombieQueue };
1112
+ export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, armGuessing, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, guessing, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, holdWorkHook, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneAdoptHook, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneServedHook, laneStageHook, laneWriteHook, lanesBlockedHook, latestOpened, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, pendingNodes, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };