@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-shared.js +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
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 } 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
3
|
import { attrHooks } from "./attribution-hooks.js";
|
|
4
4
|
|
|
@@ -40,16 +40,32 @@ let endLanesHook = null;
|
|
|
40
40
|
|
|
41
41
|
let lanesBlockedHook = null;
|
|
42
42
|
|
|
43
|
-
|
|
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;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function installLaneHooks(e, o, n, l, t, s, u, i, r, a, f) {
|
|
44
58
|
laneReadHook = e;
|
|
45
|
-
laneStageHook =
|
|
46
|
-
laneOutcomeHook =
|
|
47
|
-
laneWriteHook =
|
|
48
|
-
applyGuessesHook =
|
|
59
|
+
laneStageHook = o;
|
|
60
|
+
laneOutcomeHook = n;
|
|
61
|
+
laneWriteHook = l;
|
|
62
|
+
applyGuessesHook = t;
|
|
49
63
|
laneSeamsHook = s;
|
|
50
64
|
laneCorrectionsHook = u;
|
|
51
65
|
endLanesHook = i;
|
|
52
66
|
lanesBlockedHook = r;
|
|
67
|
+
laneAdoptHook = a;
|
|
68
|
+
laneServedHook = f;
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
// Boundaries (boundaries.ts): the display consumers between an observer
|
|
@@ -75,12 +91,12 @@ let boundarySeamHook = null;
|
|
|
75
91
|
|
|
76
92
|
let heldRunHook = null;
|
|
77
93
|
|
|
78
|
-
function installBoundaryHooks(e, n,
|
|
94
|
+
function installBoundaryHooks(e, o, n, l, t) {
|
|
79
95
|
catchHook = e;
|
|
80
|
-
freshHook =
|
|
81
|
-
hiddenHook =
|
|
82
|
-
boundarySeamHook =
|
|
83
|
-
heldRunHook =
|
|
96
|
+
freshHook = o;
|
|
97
|
+
hiddenHook = n;
|
|
98
|
+
boundarySeamHook = l;
|
|
99
|
+
heldRunHook = t;
|
|
84
100
|
}
|
|
85
101
|
|
|
86
102
|
/** Store (store/store.ts): `park` — the flush parked into `t`: the store
|
|
@@ -92,9 +108,9 @@ function installBoundaryHooks(e, n, o, t, l) {
|
|
|
92
108
|
|
|
93
109
|
let storeCommitHook = null;
|
|
94
110
|
|
|
95
|
-
function installStoreHooks(e,
|
|
111
|
+
function installStoreHooks(e, o) {
|
|
96
112
|
storeParkHook = e;
|
|
97
|
-
storeCommitHook =
|
|
113
|
+
storeCommitHook = o;
|
|
98
114
|
}
|
|
99
115
|
|
|
100
116
|
/** `affects()` marks (affects.ts): the releases at a landing and at the seam
|
|
@@ -102,15 +118,19 @@ function installStoreHooks(e, n) {
|
|
|
102
118
|
|
|
103
119
|
let releaseAmbientMarksHook = null;
|
|
104
120
|
|
|
105
|
-
function installMarkHooks(e,
|
|
121
|
+
function installMarkHooks(e, o) {
|
|
106
122
|
releaseMarksHook = e;
|
|
107
|
-
releaseAmbientMarksHook =
|
|
123
|
+
releaseAmbientMarksHook = o;
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
/** Verdicts (verdict.ts). */ let observeFlightHook = null;
|
|
111
127
|
|
|
112
|
-
|
|
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) {
|
|
113
132
|
observeFlightHook = e;
|
|
133
|
+
holdWorkHook = o;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
/** External-source bridge (wired by enableExternalSource(); undefined while
|
|
@@ -118,9 +138,9 @@ function installVerdictHooks(e) {
|
|
|
118
138
|
|
|
119
139
|
let externalUntrackHook = undefined;
|
|
120
140
|
|
|
121
|
-
function setExternalHooks(e,
|
|
141
|
+
function setExternalHooks(e, o) {
|
|
122
142
|
wireExternalSourceHook = e;
|
|
123
|
-
externalUntrackHook =
|
|
143
|
+
externalUntrackHook = o;
|
|
124
144
|
}
|
|
125
145
|
|
|
126
146
|
/** Live transactions — opened, unmerged, not landed. Scanned at every seam
|
|
@@ -128,24 +148,24 @@ function setExternalHooks(e, n) {
|
|
|
128
148
|
|
|
129
149
|
/** Observe tier: this flush parked its transaction (`holdStart` fired). */ let holding = false;
|
|
130
150
|
|
|
131
|
-
/** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e,
|
|
132
|
-
const
|
|
151
|
+
/** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e, o = null) {
|
|
152
|
+
const n = {
|
|
133
153
|
tn: [],
|
|
134
154
|
un: [ [], [] ],
|
|
135
155
|
En: [],
|
|
136
|
-
|
|
137
|
-
_parent:
|
|
156
|
+
eo: null,
|
|
157
|
+
_parent: o,
|
|
138
158
|
P: e,
|
|
139
159
|
Pe: null,
|
|
140
160
|
tt: 0,
|
|
141
161
|
nt: false,
|
|
142
162
|
en: null,
|
|
143
|
-
|
|
163
|
+
Ue: false,
|
|
144
164
|
ln: false,
|
|
145
165
|
I: null
|
|
146
166
|
};
|
|
147
|
-
if (!e) transactions.push(
|
|
148
|
-
return
|
|
167
|
+
if (!e) transactions.push(n);
|
|
168
|
+
return n;
|
|
149
169
|
}
|
|
150
170
|
|
|
151
171
|
// Lanes (plan sec. 28, 2026-10-02; lanes.ts). A lane is "a new base of a transition":
|
|
@@ -175,6 +195,10 @@ function setPassLane(e) {
|
|
|
175
195
|
* schedules the seam that consumes it: membership is the tick's — the same
|
|
176
196
|
* synchronous frame — and the next tick's writes are not this one's. */ let flushTransaction = null;
|
|
177
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
|
+
|
|
178
202
|
/** The transaction the passes running OUTSIDE a flush this tick derive from
|
|
179
203
|
* (a mainline mount, a mainline re-pass): the passes' own (A29, creation-
|
|
180
204
|
* time form — "the entry is the pass's alone"): their results are staged
|
|
@@ -188,8 +212,8 @@ function setPassLane(e) {
|
|
|
188
212
|
* Cleared by the flush the join schedules, and at the end of a flush that
|
|
189
213
|
* set it. */ let passTx = null;
|
|
190
214
|
|
|
191
|
-
function joinPassTx(e,
|
|
192
|
-
if (globalQueue.
|
|
215
|
+
function joinPassTx(e, o) {
|
|
216
|
+
if (globalQueue.Y && !o || flushTransaction !== null) return joinFuture(e);
|
|
193
217
|
if (passTx === null) passTx = resolveTx(e); else merge(resolveTx(e), passTx);
|
|
194
218
|
schedule();
|
|
195
219
|
}
|
|
@@ -206,36 +230,36 @@ function joinPassTx(e, n) {
|
|
|
206
230
|
}
|
|
207
231
|
|
|
208
232
|
function resolveTx(e) {
|
|
209
|
-
while (e.
|
|
233
|
+
while (e.eo !== null) e = e.eo;
|
|
210
234
|
return e;
|
|
211
235
|
}
|
|
212
236
|
|
|
213
237
|
/** The flush joins transaction `t` — or needs one of its own (`null`: a pass
|
|
214
238
|
* went pending with nothing held). Joining a second one merges it into the
|
|
215
239
|
* flush's: the work that touched both entangles them (A15). */ function joinFuture(e) {
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
240
|
+
const o = flushTransaction;
|
|
241
|
+
if (o === null) {
|
|
218
242
|
flushTransaction = e === null ? newTransaction(false) : resolveTx(e);
|
|
219
|
-
} else if (e !== null) merge(resolveTx(e),
|
|
220
|
-
if (!globalQueue.
|
|
243
|
+
} else if (e !== null) merge(resolveTx(e), o);
|
|
244
|
+
if (!globalQueue.Y) schedule();
|
|
221
245
|
}
|
|
222
246
|
|
|
223
247
|
/** `t` merges into `f`: the work that touched both entangles them (A15).
|
|
224
248
|
* A lane never merges: it is a sub-frame, not a peer — its work is routed
|
|
225
|
-
* per pass (`passLane`). */ function merge(e,
|
|
249
|
+
* per pass (`passLane`). */ function merge(e, o) {
|
|
226
250
|
// Both ends resolved: a stale pointer to a transaction already merged
|
|
227
251
|
// into the other would close a cycle `resolveTx` never leaves.
|
|
228
252
|
e = resolveTx(e);
|
|
229
|
-
|
|
230
|
-
if (e ===
|
|
231
|
-
e.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
append(
|
|
235
|
-
append(
|
|
236
|
-
append(
|
|
237
|
-
append(
|
|
238
|
-
if (e.I !== null) append(
|
|
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);
|
|
239
263
|
transactions.splice(transactions.indexOf(e), 1);
|
|
240
264
|
}
|
|
241
265
|
|
|
@@ -257,13 +281,13 @@ function resolveTx(e) {
|
|
|
257
281
|
* in for the flight (A17: "visible until its own fetch settles"). */ function blocked(e) {
|
|
258
282
|
// The transaction being judged (a lane consulted on its behalf judges for
|
|
259
283
|
// it): a zombie whose removal it stages is moot for it alone (`onScreen`).
|
|
260
|
-
const
|
|
284
|
+
const o = judge;
|
|
261
285
|
judge ??= e;
|
|
262
286
|
// An action still running in it holds it open (action.ts). Its lanes
|
|
263
287
|
// (lanes.ts): a lane under `t` blocks it while blocked itself.
|
|
264
|
-
const
|
|
265
|
-
judge =
|
|
266
|
-
return
|
|
288
|
+
const n = e.tt !== 0 || blockedBy(e.tn, e) || !!lanesBlockedHook?.(e);
|
|
289
|
+
judge = o;
|
|
290
|
+
return n;
|
|
267
291
|
}
|
|
268
292
|
|
|
269
293
|
let judge = null;
|
|
@@ -278,28 +302,28 @@ let judge = null;
|
|
|
278
302
|
|
|
279
303
|
/** A source the pending node waits on that is `t`'s (held by it, or by no
|
|
280
304
|
* one) — not another transaction's or lane's work. Itself, when it is the
|
|
281
|
-
* source. */ function ownSource(e,
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
284
|
-
for (const e of
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
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;
|
|
287
311
|
}
|
|
288
312
|
return false;
|
|
289
313
|
}
|
|
290
314
|
|
|
291
|
-
function blockedBy(e,
|
|
292
|
-
for (let
|
|
293
|
-
const
|
|
294
|
-
if (!(
|
|
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;
|
|
295
319
|
// The frame's own pending observer (off screen: this one holds nothing;
|
|
296
320
|
// the next listed node may).
|
|
297
|
-
if (
|
|
298
|
-
if (onScreen(
|
|
321
|
+
if (t.i === EFFECT_RENDER) {
|
|
322
|
+
if (onScreen(t, judge ?? o)) return true;
|
|
299
323
|
continue;
|
|
300
324
|
}
|
|
301
|
-
for (let e =
|
|
302
|
-
const
|
|
325
|
+
for (let e = t.o; e !== null; e = e.t) {
|
|
326
|
+
const n = e.u;
|
|
303
327
|
// A frame reader: a render effect, or a stale reader of the flight
|
|
304
328
|
// (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
|
|
305
329
|
// `frameRead`): served committed instead of going pending, it derives
|
|
@@ -311,7 +335,7 @@ function blockedBy(e, n, o = false) {
|
|
|
311
335
|
// lane-membership ruling, 2026-10-05). An output that never committed
|
|
312
336
|
// shows nothing — a mount the frame has not revealed — and holds
|
|
313
337
|
// nothing.
|
|
314
|
-
if ((
|
|
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;
|
|
315
339
|
}
|
|
316
340
|
}
|
|
317
341
|
return false;
|
|
@@ -324,8 +348,8 @@ function blockedBy(e, n, o = false) {
|
|
|
324
348
|
* is visible, a lane's reveal included: only the commit that disposes it
|
|
325
349
|
* makes its say moot), and not behind a fallback (A33: a boundary showing its fallback is the display of
|
|
326
350
|
* everything under it, so a reader there is not on screen and holds
|
|
327
|
-
* nothing — boundaries.ts). */ function onScreen(e,
|
|
328
|
-
return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e,
|
|
351
|
+
* nothing — boundaries.ts). */ function onScreen(e, o) {
|
|
352
|
+
return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e, o)) && !hiddenHook?.(e);
|
|
329
353
|
}
|
|
330
354
|
|
|
331
355
|
/** A15 (#3463): a reader whose removal is staged — a zombie, parked by a
|
|
@@ -333,10 +357,10 @@ function blockedBy(e, n, o = false) {
|
|
|
333
357
|
* except the transaction staging its removal: for that one its say is moot
|
|
334
358
|
* (done, and the commit disposes it; not done, and it stays parked). The
|
|
335
359
|
* staging transaction is the one holding the pass that parked the frame:
|
|
336
|
-
* the nearest non-zombie ancestor. */ function removalStagedBy(e,
|
|
337
|
-
let
|
|
338
|
-
while (
|
|
339
|
-
return
|
|
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);
|
|
340
364
|
}
|
|
341
365
|
|
|
342
366
|
/** Unchanged passes this flush whose stale dependency tail awaits the
|
|
@@ -362,18 +386,18 @@ function deferZombie(e) {
|
|
|
362
386
|
}
|
|
363
387
|
|
|
364
388
|
/** Put a staged node in a transaction: flagged, stamped, on its landing
|
|
365
|
-
* list. */ function holdNode(e,
|
|
389
|
+
* list. */ function holdNode(e, o) {
|
|
366
390
|
e.l |= CONFIG_HELD;
|
|
367
|
-
list(e,
|
|
391
|
+
list(e, o);
|
|
368
392
|
}
|
|
369
393
|
|
|
370
394
|
/** Put a node on a transaction's list, once: a node's `_transaction` is the
|
|
371
395
|
* transaction whose `_nodes` it is on (every site that sets one does the
|
|
372
|
-
* other), so a re-pass, a re-landing or a re-staging adds nothing. */ function list(e,
|
|
373
|
-
const
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
|
|
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);
|
|
377
401
|
}
|
|
378
402
|
|
|
379
403
|
/** Hold the (uncommitted) frame under a held pass: every computed in the
|
|
@@ -388,22 +412,22 @@ function deferZombie(e) {
|
|
|
388
412
|
* and `dissolveLane` no longer finds it — a lane node with no lane, which the
|
|
389
413
|
* next read of it trips over (`laneRead` → `txOf`). Its frame is the lane's
|
|
390
414
|
* too (ruling A: a lane pass's children are the lane's), revealed and
|
|
391
|
-
* retired at the lane's seam. */ function holdFrame(e,
|
|
392
|
-
for (let
|
|
393
|
-
if (
|
|
394
|
-
if (
|
|
395
|
-
if (!(
|
|
396
|
-
|
|
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;
|
|
397
421
|
}
|
|
398
|
-
holdFrame(
|
|
422
|
+
holdFrame(n, o);
|
|
399
423
|
}
|
|
400
424
|
}
|
|
401
425
|
|
|
402
426
|
/** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
|
|
403
|
-
* what an earlier hold staged under a re-armed boundary). */ function heldUnder(e,
|
|
404
|
-
for (let
|
|
405
|
-
if ((
|
|
406
|
-
heldUnder(
|
|
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);
|
|
407
431
|
}
|
|
408
432
|
}
|
|
409
433
|
|
|
@@ -413,10 +437,10 @@ function deferZombie(e) {
|
|
|
413
437
|
}
|
|
414
438
|
|
|
415
439
|
const dirtyQueue = {
|
|
416
|
-
|
|
440
|
+
et: new Array(2e3).fill(undefined),
|
|
417
441
|
p: false,
|
|
418
442
|
Fe: 0,
|
|
419
|
-
|
|
443
|
+
Et: 0
|
|
420
444
|
};
|
|
421
445
|
|
|
422
446
|
let clock = 0;
|
|
@@ -479,7 +503,7 @@ function schedule() {
|
|
|
479
503
|
}
|
|
480
504
|
if (scheduled) return;
|
|
481
505
|
scheduled = true;
|
|
482
|
-
if (!syncDepth && !globalQueue.
|
|
506
|
+
if (!syncDepth && !globalQueue.Y) {
|
|
483
507
|
queueMicrotask(flush);
|
|
484
508
|
}
|
|
485
509
|
}
|
|
@@ -504,7 +528,7 @@ function haltReactivity(e) {
|
|
|
504
528
|
halted = true;
|
|
505
529
|
// A cleanup error collected before the halt is dropped (owner.ts).
|
|
506
530
|
rethrowCleanupError(true);
|
|
507
|
-
let
|
|
531
|
+
let o = HALTED;
|
|
508
532
|
// Surface the cause here too: callers rethrow it, but a creation-time throw
|
|
509
533
|
// unwinds through ancestor recomputes that convert it to status instead of
|
|
510
534
|
// surfacing it (#2884), so the rethrow alone cannot guarantee visibility.
|
|
@@ -514,9 +538,9 @@ function haltReactivity(e) {
|
|
|
514
538
|
// nothing an app or its telemetry can act on (#3338 — an uncaught throw
|
|
515
539
|
// during the hydration render). The rethrow may reach the top as well in
|
|
516
540
|
// the non-swallowed cases; a duplicate report beats a silent one.
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
541
|
+
const n = e !== undefined && globalThis.reportError;
|
|
542
|
+
n || e === undefined ? console.error(o) : console.error(o, e);
|
|
543
|
+
n && n(e);
|
|
520
544
|
}
|
|
521
545
|
|
|
522
546
|
/**
|
|
@@ -524,7 +548,7 @@ function haltReactivity(e) {
|
|
|
524
548
|
* error escaped from — for the REACTIVITY_HALTED message's owner path. Call
|
|
525
549
|
* sites pick it in dev builds only (`haltReactivity(e)` in production), so
|
|
526
550
|
* production keeps the one-argument halt and its bytes unchanged.
|
|
527
|
-
*/ function haltReactivityAt(e,
|
|
551
|
+
*/ function haltReactivityAt(e, o) {
|
|
528
552
|
haltReactivity(e);
|
|
529
553
|
}
|
|
530
554
|
|
|
@@ -542,10 +566,10 @@ function notifyHalted() {
|
|
|
542
566
|
|
|
543
567
|
class GlobalQueue {
|
|
544
568
|
un=[ [], [] ];
|
|
545
|
-
|
|
569
|
+
Y=false;
|
|
546
570
|
flush() {
|
|
547
|
-
if (this.
|
|
548
|
-
this.
|
|
571
|
+
if (this.Y) return;
|
|
572
|
+
this.Y = true;
|
|
549
573
|
// A28: companions of nodes written since the last flush mirror the
|
|
550
574
|
// flushed world — re-synced inside the running window (the write is
|
|
551
575
|
// "flushed" from here on).
|
|
@@ -563,14 +587,14 @@ class GlobalQueue {
|
|
|
563
587
|
clock++;
|
|
564
588
|
// A write the commit sweep staged with no subscriber to dirty is work
|
|
565
589
|
// too — the next round commits it.
|
|
566
|
-
scheduled = dirtyQueue.
|
|
590
|
+
scheduled = dirtyQueue.Et >= dirtyQueue.Fe || pendingNodes.length !== 0;
|
|
567
591
|
this.run(EFFECT_RENDER);
|
|
568
592
|
this.run(EFFECT_USER);
|
|
569
593
|
if (false && holding) ;
|
|
570
594
|
if (false && !scheduled) ;
|
|
571
595
|
if (false) ;
|
|
572
596
|
} finally {
|
|
573
|
-
this.
|
|
597
|
+
this.Y = false;
|
|
574
598
|
passTx = null;
|
|
575
599
|
}
|
|
576
600
|
}
|
|
@@ -585,7 +609,7 @@ class GlobalQueue {
|
|
|
585
609
|
// pure round — the parent's flights before the parent is judged below.
|
|
586
610
|
if (laneCorrectionsHook?.()) runHeap(dirtyQueue, GlobalQueue._e);
|
|
587
611
|
const e = flushTransaction;
|
|
588
|
-
flushTransaction = null;
|
|
612
|
+
flushTransaction = latestOpened = null;
|
|
589
613
|
// The frame's verdict is in: the guesses written since the last seam
|
|
590
614
|
// open their lane under the frame's transaction (a lane's own flush
|
|
591
615
|
// parents a nested lane to it), or are dropped — the frame commits, and
|
|
@@ -595,13 +619,13 @@ class GlobalQueue {
|
|
|
595
619
|
// A lane's own flush (its flight landing, its reveal) parks nothing: the
|
|
596
620
|
// lane's work reached it per pass; the frame's plain writes commit.
|
|
597
621
|
// (Resolved: a guess over another transaction's guess merged them.)
|
|
598
|
-
const
|
|
599
|
-
if (
|
|
622
|
+
const o = e !== null && !e.P ? resolveTx(e) : null;
|
|
623
|
+
if (o !== null) {
|
|
600
624
|
// `t._nodes` grows under the walk (holdFrame pushes); the bound is
|
|
601
625
|
// this flush's list, which does not.
|
|
602
626
|
const e = pendingNodes.length;
|
|
603
|
-
for (let
|
|
604
|
-
const e = pendingNodes[
|
|
627
|
+
for (let n = 0; n < e; n++) {
|
|
628
|
+
const e = pendingNodes[n];
|
|
605
629
|
// Already held: the pass that re-staged it joined its transaction,
|
|
606
630
|
// which is `t` (or merged into it). Lane work is the lane's (a
|
|
607
631
|
// pending mark propagated onto it queued it here too).
|
|
@@ -614,30 +638,30 @@ class GlobalQueue {
|
|
|
614
638
|
// stale stamp was the bridge that entangled unrelated updates
|
|
615
639
|
// with a never-resolving flight). Its observers are held and
|
|
616
640
|
// wait on its flight (`blocked`).
|
|
617
|
-
if (e.
|
|
641
|
+
if (e.ue === NOT_PENDING && e.m & STATUS_UNINITIALIZED && e.i !== EFFECT_RENDER) continue;
|
|
618
642
|
// A34 (2): a tick whose writes net to the committed value made no
|
|
619
643
|
// proposal (`setShow(false); setShow(true)` on a committed true) —
|
|
620
644
|
// not staged, not held, pends nothing; a later write to it is
|
|
621
645
|
// plain mainline. (A node already held stays held when written
|
|
622
646
|
// back: A34 (1).)
|
|
623
|
-
if (e.
|
|
647
|
+
if (e.ue !== NOT_PENDING && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.T?.me == null && e.T?.Le == null &&
|
|
624
648
|
// The comparator last: a pass that created children (an object
|
|
625
649
|
// owning a fresh async memo, #4111) must not have it read them.
|
|
626
650
|
// A NotReady read there is a change (`isSame`).
|
|
627
|
-
isSame(e, e.le, e.
|
|
628
|
-
e.
|
|
651
|
+
isSame(e, e.le, e.ue)) {
|
|
652
|
+
e.ue = NOT_PENDING;
|
|
629
653
|
e.l &= ~CONFIG_STAGED;
|
|
630
654
|
continue;
|
|
631
655
|
}
|
|
632
|
-
holdNode(e,
|
|
656
|
+
holdNode(e, o);
|
|
633
657
|
}
|
|
634
658
|
// A held pass's frame is held with it (ruling A, O2): the children it
|
|
635
659
|
// created are the transaction's — they compute, and a pass over them
|
|
636
660
|
// or a write that reaches them joins; they effect at the landing.
|
|
637
|
-
if (e.l & CONFIG_STAGED) holdFrame(e,
|
|
661
|
+
if (e.l & CONFIG_STAGED) holdFrame(e, o);
|
|
638
662
|
}
|
|
639
663
|
pendingNodes.length = 0;
|
|
640
|
-
storeParkHook?.(
|
|
664
|
+
storeParkHook?.(o);
|
|
641
665
|
// (This flush's runs are stashed with `t` below — after the landings,
|
|
642
666
|
// so a `t` that lands at this very seam runs them first, ahead of
|
|
643
667
|
// the runs it held from earlier flushes.)
|
|
@@ -648,10 +672,10 @@ class GlobalQueue {
|
|
|
648
672
|
// holder's verdict lane's work — before the lane seams, which reveal
|
|
649
673
|
// it (nothing commits this seam that could dispose it).
|
|
650
674
|
// (Verdict readers exist only with the verdict engine installed.)
|
|
651
|
-
const
|
|
675
|
+
const n = deferredZombies.splice(0);
|
|
652
676
|
if (observeFlightHook) {
|
|
653
|
-
|
|
654
|
-
for (let e = 0; e <
|
|
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]);
|
|
655
679
|
}
|
|
656
680
|
// The unchanged passes' tails stay linked (A30, #3469): their inputs
|
|
657
681
|
// are held, and the committed frame still derives from them — no trim.
|
|
@@ -663,8 +687,8 @@ class GlobalQueue {
|
|
|
663
687
|
// left an effect owing a run (`runEffect` trims when the run applies):
|
|
664
688
|
// `recompute`'s own gates.
|
|
665
689
|
for (let e = 0; e < heldTrims.length; e++) {
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
690
|
+
const o = heldTrims[e];
|
|
691
|
+
if (o.T?.U == null && !o.Ae) trimStaleDeps(o);
|
|
668
692
|
}
|
|
669
693
|
}
|
|
670
694
|
// The list is the flush's either way. Reset only when there is something
|
|
@@ -678,23 +702,23 @@ class GlobalQueue {
|
|
|
678
702
|
// removes its entry.
|
|
679
703
|
// This flush's own runs, the lanes' reveals, and the landings' held runs
|
|
680
704
|
// are collected apart and ordered below.
|
|
681
|
-
const
|
|
682
|
-
const
|
|
705
|
+
const n = this.un;
|
|
706
|
+
const l = [ [], [] ];
|
|
683
707
|
// The passes that read this frame's stagings as the screen read held
|
|
684
708
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
685
709
|
// world (a lane's runs wait this round).
|
|
686
710
|
if (laneSeamsHook) {
|
|
687
|
-
this.un =
|
|
688
|
-
laneSeamsHook(
|
|
711
|
+
this.un = l;
|
|
712
|
+
laneSeamsHook(o);
|
|
689
713
|
if (stagedReaders.length) stagedReaders.length = 0;
|
|
690
714
|
}
|
|
691
715
|
this.un = [ [], [] ];
|
|
692
716
|
for (let e = transactions.length - 1; e >= 0; e--) {
|
|
693
|
-
const
|
|
694
|
-
if (blocked(
|
|
717
|
+
const o = transactions[e];
|
|
718
|
+
if (blocked(o)) continue;
|
|
695
719
|
transactions.splice(e, 1);
|
|
696
|
-
endLanesHook?.(
|
|
697
|
-
land(
|
|
720
|
+
endLanesHook?.(o);
|
|
721
|
+
land(o);
|
|
698
722
|
// A landing's commits can dispose a zombie a transaction judged above
|
|
699
723
|
// was blocked on (#3463: live "until the commit that disposes it") —
|
|
700
724
|
// judge them again.
|
|
@@ -707,8 +731,8 @@ class GlobalQueue {
|
|
|
707
731
|
// parked (something async below) — the window is the frame's, the marks
|
|
708
732
|
// are its transaction's; else they release at the seam, verdict-only,
|
|
709
733
|
// nothing to show (affects.ts).
|
|
710
|
-
const
|
|
711
|
-
releaseAmbientMarksHook?.(
|
|
734
|
+
const t = o && liveTx(o);
|
|
735
|
+
releaseAmbientMarksHook?.(t);
|
|
712
736
|
// The effect phase: lane work first (displayed ahead of the frame), then
|
|
713
737
|
// this flush's runs, then the runs the landings held from earlier
|
|
714
738
|
// flushes — as one pass would have queued them (#3540: a shell
|
|
@@ -716,21 +740,21 @@ class GlobalQueue {
|
|
|
716
740
|
// write; #3528: a display-ahead swap before the count it is shown
|
|
717
741
|
// beside). A parked frame's runs wait with its transaction instead: the
|
|
718
742
|
// effect phase applies a committed frame.
|
|
719
|
-
const s =
|
|
743
|
+
const s = t !== null;
|
|
720
744
|
for (let e = 0; e < 2; e++) {
|
|
721
|
-
if (s) append(
|
|
745
|
+
if (s) append(t.un[e], n[e]);
|
|
722
746
|
// The plain flush — no reveal, no landing, not parked — has nothing to
|
|
723
747
|
// order around its own runs: they are the queue as they stand (the
|
|
724
748
|
// same array, not a copy; `run` takes it whole). Every other seam
|
|
725
749
|
// builds the ordered queue above.
|
|
726
|
-
this.un[e] = s ||
|
|
750
|
+
this.un[e] = s || l[e].length || this.un[e].length ? l[e].concat(s ? [] : n[e], this.un[e]) : n[e];
|
|
727
751
|
}
|
|
728
752
|
if (deferredZombies.length !== 0) {
|
|
729
753
|
// Survivors are the displayed frame of a held pass: they rerun for the
|
|
730
754
|
// live write, parents before children.
|
|
731
|
-
const e = deferredZombies.splice(0).sort((e,
|
|
732
|
-
for (let
|
|
733
|
-
if (!(e[
|
|
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]);
|
|
734
758
|
}
|
|
735
759
|
}
|
|
736
760
|
// Boundaries: readers that settled, landed or died this flush are
|
|
@@ -738,18 +762,18 @@ class GlobalQueue {
|
|
|
738
762
|
boundarySeamHook?.();
|
|
739
763
|
}
|
|
740
764
|
run(e) {
|
|
741
|
-
const
|
|
742
|
-
if (
|
|
765
|
+
const o = this.un[e - 1];
|
|
766
|
+
if (o.length) {
|
|
743
767
|
this.un[e - 1] = [];
|
|
744
|
-
runQueue(
|
|
768
|
+
runQueue(o, e);
|
|
745
769
|
}
|
|
746
770
|
}
|
|
747
|
-
enqueue(e,
|
|
771
|
+
enqueue(e, o, n = passLane) {
|
|
748
772
|
// Lane work's runs are the lane's: they run at its reveal, not with
|
|
749
773
|
// the frame (which may park). A lane pass that read the frame's own
|
|
750
774
|
// staging is the frame's (`recompute` passes null): its run waits with
|
|
751
775
|
// the frame.
|
|
752
|
-
if (e) (
|
|
776
|
+
if (e) (n !== null ? n : this).un[e - 1].push(o);
|
|
753
777
|
schedule();
|
|
754
778
|
}
|
|
755
779
|
/** Status reaching the root: pending is absorbed (the root mount defers —
|
|
@@ -765,10 +789,10 @@ class GlobalQueue {
|
|
|
765
789
|
*
|
|
766
790
|
* A boundary between the observer and the root (boundaries.ts) is asked
|
|
767
791
|
* first: a fallback catches what is not ready under it, and the root
|
|
768
|
-
* never hears of it. */ notify(e,
|
|
769
|
-
if (catchHook?.(e,
|
|
770
|
-
if (
|
|
771
|
-
if (
|
|
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) {
|
|
772
796
|
// A pass that went pending holds its frame: the async's own
|
|
773
797
|
// synchronous frame is not ready (A15 reveal corollary: a reveal
|
|
774
798
|
// that discovers a flight whose inputs are visible holds and joins
|
|
@@ -800,39 +824,61 @@ class GlobalQueue {
|
|
|
800
824
|
* for it is void (#3322: an effect has one value slot, and the stale pass
|
|
801
825
|
* overwrote the value that run was for) — the re-derivation's run replaces
|
|
802
826
|
* it. Truthy when an effect re-derives (`land`). */ function reruns(e) {
|
|
803
|
-
let
|
|
804
|
-
for (let
|
|
805
|
-
const
|
|
827
|
+
let o;
|
|
828
|
+
for (let n = 0; n < e.En.length; n++) {
|
|
829
|
+
const l = e.En[n];
|
|
806
830
|
// An errored reader's display is its error (D-39): the landing gives it
|
|
807
831
|
// nothing to re-derive, and a re-run would be a read that retries the
|
|
808
|
-
// errored source (#3945)
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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;
|
|
814
858
|
// Its frame is replaced by the re-derivation: a run one of its
|
|
815
859
|
// children queued this flush (re-run by the same landing) is for the
|
|
816
860
|
// frame being replaced — void too (#3404).
|
|
817
|
-
for (let e =
|
|
818
|
-
|
|
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);
|
|
819
865
|
}
|
|
820
866
|
}
|
|
821
867
|
e.En.length = 0;
|
|
822
|
-
return
|
|
868
|
+
return o;
|
|
823
869
|
}
|
|
824
870
|
|
|
825
871
|
/** The landing: the held frame becomes the frame. */ function land(e) {
|
|
826
|
-
const
|
|
872
|
+
const o = reruns(e);
|
|
827
873
|
if (releaseMarksHook && e.I !== null) releaseMarksHook(e.I);
|
|
828
874
|
// Old children die in the commits (cleanups first), then the stashed
|
|
829
875
|
// effects run ahead of this flush's own. A node a lane took over since
|
|
830
876
|
// (a guess written over the staged truth) is the lane's to land.
|
|
831
|
-
for (let
|
|
832
|
-
const
|
|
833
|
-
if (
|
|
834
|
-
|
|
835
|
-
commitPendingNode(
|
|
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);
|
|
836
882
|
}
|
|
837
883
|
// A cleanup those commits ran that wrote a node `u` still held joined
|
|
838
884
|
// `u`, which has left `transactions`: the write is this landing's, and
|
|
@@ -846,21 +892,21 @@ class GlobalQueue {
|
|
|
846
892
|
// value. Queued last in this effect phase, the release hands them to the
|
|
847
893
|
// next round's own runs, ahead of the re-derivation's: they show with it,
|
|
848
894
|
// or park with it in the hold its pending opens. The commits stand.
|
|
849
|
-
if (
|
|
895
|
+
if (o) globalQueue.un[1].push(() => releaseQueues(e)); else releaseQueues(e);
|
|
850
896
|
}
|
|
851
897
|
|
|
852
898
|
/** The held runs join this flush's effect phase after its own runs (the
|
|
853
899
|
* landing's re-passes, in height order): the frame's effects run as one
|
|
854
900
|
* pass would have queued them — a shell re-derived at the landing before a
|
|
855
901
|
* boundary swap held since the write (#3540's log order). */ function releaseQueues(e) {
|
|
856
|
-
for (let
|
|
857
|
-
append(globalQueue.un[
|
|
858
|
-
e.un[
|
|
902
|
+
for (let o = 0; o < 2; o++) {
|
|
903
|
+
append(globalQueue.un[o], e.un[o]);
|
|
904
|
+
e.un[o] = [];
|
|
859
905
|
}
|
|
860
906
|
}
|
|
861
907
|
|
|
862
|
-
/** `a.push(...b)` without the argument-count limit. */ function append(e,
|
|
863
|
-
for (let
|
|
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]);
|
|
864
910
|
}
|
|
865
911
|
|
|
866
912
|
/** Nodes staged this flush (`_pendingValue` set), committed at its end. */ const pendingNodes = [];
|
|
@@ -872,16 +918,16 @@ class GlobalQueue {
|
|
|
872
918
|
|
|
873
919
|
/** A15's stale reader: `c` was served the committed value of a node `t`
|
|
874
920
|
* holds (a render effect, a verdict reader, lane work) and is re-derived
|
|
875
|
-
* after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e,
|
|
921
|
+
* after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e, o) {
|
|
876
922
|
if (!(e.R & REACTIVE_FRAME_READ)) {
|
|
877
923
|
e.R |= REACTIVE_FRAME_READ;
|
|
878
|
-
|
|
924
|
+
o.En.push(e);
|
|
879
925
|
}
|
|
880
926
|
}
|
|
881
927
|
|
|
882
928
|
function queuePendingNode(e) {
|
|
883
929
|
pendingNodes.push(e);
|
|
884
|
-
if (!globalQueue.
|
|
930
|
+
if (!globalQueue.Y) markUnflushedStaged();
|
|
885
931
|
// A28
|
|
886
932
|
}
|
|
887
933
|
|
|
@@ -901,10 +947,10 @@ function insertSubs(e) {
|
|
|
901
947
|
// Presence bits gate the optional-slot probes (see constants.ts): one
|
|
902
948
|
// masked read of the always-present _config instead of missing-property
|
|
903
949
|
// lookups in the hottest notify loop.
|
|
904
|
-
const
|
|
905
|
-
const
|
|
906
|
-
for (let
|
|
907
|
-
const e =
|
|
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;
|
|
908
954
|
// Missed-wake latch (#3037): this write is landing while the subscriber
|
|
909
955
|
// is mid-recompute (a nested pull committing beneath its reads), and the
|
|
910
956
|
// heap refuses RECOMPUTING nodes. A gen-current link means the pass
|
|
@@ -913,8 +959,8 @@ function insertSubs(e) {
|
|
|
913
959
|
// pass either re-reads them fresh or trims them), and neither does the
|
|
914
960
|
// tail link: it is the read IN FLIGHT — read() links before it pulls, so
|
|
915
961
|
// this very commit is what that read returns.
|
|
916
|
-
if (e.R & REACTIVE_RECOMPUTING_DEPS &&
|
|
917
|
-
if (
|
|
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) {
|
|
918
964
|
e.R |= REACTIVE_SNAPSHOT_STALE;
|
|
919
965
|
continue;
|
|
920
966
|
}
|
|
@@ -929,91 +975,100 @@ function insertSubs(e) {
|
|
|
929
975
|
* inert for its pass (`recompute` seats a lane only from its own `_x`), it
|
|
930
976
|
* is a live write if the effect becomes a zombie later this flush — an
|
|
931
977
|
* on-screen reader whose removal an adopted write stages follows the lane
|
|
932
|
-
* (the lane-membership ruling, 2026-10-05; `_update`).
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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;
|
|
936
991
|
}
|
|
937
992
|
}
|
|
938
993
|
|
|
939
|
-
/** One lane, or two of one link group (#3335): one reveal unit. */ function sameLane(e,
|
|
940
|
-
return e ===
|
|
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;
|
|
941
996
|
}
|
|
942
997
|
|
|
943
998
|
function commitPendingNode(e) {
|
|
944
|
-
const
|
|
999
|
+
const o = e;
|
|
945
1000
|
// L2: the commit is where a pass, held or not, stops being uncommitted —
|
|
946
1001
|
// unless it has no answer yet. A pass still in flight (pending, nothing
|
|
947
1002
|
// staged) stays uncommitted: a re-pass disposes its children on the spot,
|
|
948
1003
|
// and the frame it parked stays the frame until a pass of this node
|
|
949
1004
|
// commits a value.
|
|
950
|
-
if (!
|
|
1005
|
+
if (!o.X) {
|
|
951
1006
|
e.l &= -385;
|
|
952
|
-
if (e.
|
|
953
|
-
e.le = e.
|
|
954
|
-
e.
|
|
1007
|
+
if (e.ue !== NOT_PENDING) {
|
|
1008
|
+
e.le = e.ue;
|
|
1009
|
+
e.ue = NOT_PENDING;
|
|
955
1010
|
}
|
|
956
1011
|
return;
|
|
957
1012
|
}
|
|
958
1013
|
// Computeds only from here (`_statusFlags` is not a signal field). A
|
|
959
1014
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
960
1015
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
961
|
-
const
|
|
962
|
-
const
|
|
1016
|
+
const n = e.ue === NOT_PENDING && (o.m & STATUS_PENDING) !== 0;
|
|
1017
|
+
const l = e.l & CONFIG_STAGED_ERROR;
|
|
963
1018
|
// An answer commits: the error it replaces leaves the display (D-41).
|
|
964
|
-
if (!
|
|
965
|
-
e.l =
|
|
1019
|
+
if (!n && o.T) o.T.Te = null;
|
|
1020
|
+
e.l = n ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
|
|
966
1021
|
// D-41: the staged answer is an error — published now, when a value would
|
|
967
1022
|
// show, through the ordinary error path (`stageError`). Its readers first
|
|
968
1023
|
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
969
1024
|
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
970
|
-
if (
|
|
971
|
-
const
|
|
972
|
-
e.
|
|
973
|
-
e.
|
|
974
|
-
notifyStatus(
|
|
975
|
-
} else if (e.
|
|
976
|
-
e.le = e.
|
|
977
|
-
e.
|
|
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;
|
|
978
1033
|
// A node born staged (recompute) initializes at this commit.
|
|
979
|
-
|
|
1034
|
+
o.m &= ~STATUS_UNINITIALIZED;
|
|
980
1035
|
// A quiet re-ask's classification survives its landing and dies with
|
|
981
1036
|
// the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
|
|
982
1037
|
// the reveal. (The sweep of a node still in flight is not a landing.)
|
|
983
1038
|
// The A28 stash goes with it.
|
|
984
|
-
if (
|
|
1039
|
+
if (o.T != null) o.T.Ve = false, o.T.je = NOT_PENDING;
|
|
985
1040
|
// An effect with a staged value was born held (L2): its first run is
|
|
986
1041
|
// this commit's, not its creation's (A29) — queue it now.
|
|
987
1042
|
if (e.i && e.i !== EFFECT_TRACKED) {
|
|
988
1043
|
e.Ae = true;
|
|
989
|
-
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.
|
|
1044
|
+
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.q.bind(null, o));
|
|
990
1045
|
}
|
|
991
1046
|
}
|
|
992
1047
|
// The committed value is the first observable answer for a loading-window
|
|
993
1048
|
// node — the window closes here, not at compute time (#2990). Unconditional
|
|
994
1049
|
// store to an always-present computed slot.
|
|
995
|
-
|
|
996
|
-
|
|
1050
|
+
o.ce = false;
|
|
1051
|
+
o.R &= ~REACTIVE_MANUAL_WRITE;
|
|
997
1052
|
// The dependencies of the pass that produced the value are the frame's now:
|
|
998
1053
|
// the previous frame's tail goes (A30, #3410; `recompute` left it for a
|
|
999
1054
|
// staged pass). Only after a clean pass: `_error` is cleared by a clean
|
|
1000
1055
|
// pass or by the node's own landing (whose pass was clean), so a set
|
|
1001
1056
|
// `_error` means the last pass threw, kept its full list, and `_depsTail`
|
|
1002
1057
|
// marks where it stopped.
|
|
1003
|
-
if (
|
|
1004
|
-
if (!(
|
|
1058
|
+
if (o.T?.U == null) trimStaleDeps(o);
|
|
1059
|
+
if (!(o.m & STATUS_PENDING)) o.m &= ~STATUS_UNINITIALIZED;
|
|
1005
1060
|
// L2: the children this commit publishes are the frame's now — the frame
|
|
1006
1061
|
// they replace, parked by the pass (`recompute`), goes.
|
|
1007
|
-
if (!
|
|
1062
|
+
if (!n && o.T != null && (o.T.me !== null || o.T.Le !== null)) GlobalQueue.Ce(o, false, true);
|
|
1008
1063
|
}
|
|
1009
1064
|
|
|
1010
1065
|
function commitPendingNodes() {
|
|
1011
1066
|
for (let e = 0; e < pendingNodes.length; e++) {
|
|
1012
|
-
const
|
|
1067
|
+
const o = pendingNodes[e];
|
|
1013
1068
|
// A node a lane pass re-staged this round is the lane's to reveal; one
|
|
1014
1069
|
// a transaction holds (born held by a mainline pass, `passTx`) is that
|
|
1015
1070
|
// transaction's to commit, at its landing.
|
|
1016
|
-
if (!(
|
|
1071
|
+
if (!(o.l & (CONFIG_OVERRIDE | CONFIG_HELD))) commitPendingNode(o);
|
|
1017
1072
|
}
|
|
1018
1073
|
pendingNodes.length = 0;
|
|
1019
1074
|
}
|
|
@@ -1038,7 +1093,7 @@ function flush(e) {
|
|
|
1038
1093
|
}
|
|
1039
1094
|
}
|
|
1040
1095
|
}
|
|
1041
|
-
if (globalQueue.
|
|
1096
|
+
if (globalQueue.Y) {
|
|
1042
1097
|
return;
|
|
1043
1098
|
}
|
|
1044
1099
|
if (halted) return;
|
|
@@ -1050,8 +1105,8 @@ function flush(e) {
|
|
|
1050
1105
|
rethrowCleanupError();
|
|
1051
1106
|
}
|
|
1052
1107
|
|
|
1053
|
-
function runQueue(e,
|
|
1054
|
-
for (let
|
|
1108
|
+
function runQueue(e, o) {
|
|
1109
|
+
for (let n = 0; n < e.length; n++) e[n](o);
|
|
1055
1110
|
}
|
|
1056
1111
|
|
|
1057
|
-
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, 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 };
|
|
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 };
|