@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.18
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 +1972 -1751
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +672 -319
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +151 -116
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +51 -35
- package/dist/observe/core/effect.js +29 -30
- package/dist/observe/core/graph.js +13 -11
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +77 -51
- package/dist/observe/core/scheduler.js +202 -175
- package/dist/observe/core/verdict.js +5 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +612 -626
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +211 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +63 -47
- package/dist/prod/core/effect.js +24 -25
- package/dist/prod/core/graph.js +12 -10
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +39 -28
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +78 -51
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +11 -8
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +109 -121
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +29 -6
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +38 -7
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ import { runHeap, enqueueSub, deleteFromHeap } from "./heap.js";
|
|
|
14
14
|
|
|
15
15
|
import { devCheckQuiescent } from "./invariants.js";
|
|
16
16
|
|
|
17
|
+
import { rethrowCleanupError } from "./owner.js";
|
|
18
|
+
|
|
17
19
|
// Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
|
|
18
20
|
// bundle that never imports the installing module never assigns them — its
|
|
19
21
|
// minifier folds every guarded call site (and the branch behind it) away.
|
|
@@ -38,16 +40,16 @@ let endLanesHook = null;
|
|
|
38
40
|
|
|
39
41
|
let lanesBlockedHook = null;
|
|
40
42
|
|
|
41
|
-
function installLaneHooks(e,
|
|
43
|
+
function installLaneHooks(e, o, n, t, l, s, u, r, i) {
|
|
42
44
|
laneReadHook = e;
|
|
43
|
-
laneStageHook =
|
|
44
|
-
laneOutcomeHook =
|
|
45
|
+
laneStageHook = o;
|
|
46
|
+
laneOutcomeHook = n;
|
|
45
47
|
laneWriteHook = t;
|
|
46
48
|
applyGuessesHook = l;
|
|
47
49
|
laneSeamsHook = s;
|
|
48
50
|
laneCorrectionsHook = u;
|
|
49
|
-
endLanesHook =
|
|
50
|
-
lanesBlockedHook =
|
|
51
|
+
endLanesHook = r;
|
|
52
|
+
lanesBlockedHook = i;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
// Boundaries (boundaries.ts): the display consumers between an observer
|
|
@@ -73,10 +75,10 @@ let boundarySeamHook = null;
|
|
|
73
75
|
|
|
74
76
|
let heldRunHook = null;
|
|
75
77
|
|
|
76
|
-
function installBoundaryHooks(e,
|
|
78
|
+
function installBoundaryHooks(e, o, n, t, l) {
|
|
77
79
|
catchHook = e;
|
|
78
|
-
freshHook =
|
|
79
|
-
hiddenHook =
|
|
80
|
+
freshHook = o;
|
|
81
|
+
hiddenHook = n;
|
|
80
82
|
boundarySeamHook = t;
|
|
81
83
|
heldRunHook = l;
|
|
82
84
|
}
|
|
@@ -90,9 +92,9 @@ function installBoundaryHooks(e, n, o, t, l) {
|
|
|
90
92
|
|
|
91
93
|
let storeCommitHook = null;
|
|
92
94
|
|
|
93
|
-
function installStoreHooks(e,
|
|
95
|
+
function installStoreHooks(e, o) {
|
|
94
96
|
storeParkHook = e;
|
|
95
|
-
storeCommitHook =
|
|
97
|
+
storeCommitHook = o;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
/** `affects()` marks (affects.ts): the releases at a landing and at the seam
|
|
@@ -100,9 +102,9 @@ function installStoreHooks(e, n) {
|
|
|
100
102
|
|
|
101
103
|
let releaseAmbientMarksHook = null;
|
|
102
104
|
|
|
103
|
-
function installMarkHooks(e,
|
|
105
|
+
function installMarkHooks(e, o) {
|
|
104
106
|
releaseMarksHook = e;
|
|
105
|
-
releaseAmbientMarksHook =
|
|
107
|
+
releaseAmbientMarksHook = o;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/** Verdicts (verdict.ts). */ let observeFlightHook = null;
|
|
@@ -116,9 +118,9 @@ function installVerdictHooks(e) {
|
|
|
116
118
|
|
|
117
119
|
let externalUntrackHook = undefined;
|
|
118
120
|
|
|
119
|
-
function setExternalHooks(e,
|
|
121
|
+
function setExternalHooks(e, o) {
|
|
120
122
|
wireExternalSourceHook = e;
|
|
121
|
-
externalUntrackHook =
|
|
123
|
+
externalUntrackHook = o;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/** Live transactions — opened, unmerged, not landed. Scanned at every seam
|
|
@@ -126,13 +128,13 @@ function setExternalHooks(e, n) {
|
|
|
126
128
|
|
|
127
129
|
/** Observe tier: this flush parked its transaction (`holdStart` fired). */ let holding = false;
|
|
128
130
|
|
|
129
|
-
/** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e,
|
|
130
|
-
const
|
|
131
|
+
/** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e, o = null) {
|
|
132
|
+
const n = {
|
|
131
133
|
je: [],
|
|
132
134
|
un: [ [], [] ],
|
|
133
135
|
En: [],
|
|
134
|
-
|
|
135
|
-
_parent:
|
|
136
|
+
eo: null,
|
|
137
|
+
_parent: o,
|
|
136
138
|
V: e,
|
|
137
139
|
it: null,
|
|
138
140
|
tt: 0,
|
|
@@ -142,8 +144,8 @@ function setExternalHooks(e, n) {
|
|
|
142
144
|
ln: false,
|
|
143
145
|
I: null
|
|
144
146
|
};
|
|
145
|
-
if (!e) transactions.push(
|
|
146
|
-
return
|
|
147
|
+
if (!e) transactions.push(n);
|
|
148
|
+
return n;
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
// Lanes (plan sec. 28, 2026-10-02; lanes.ts). A lane is "a new base of a transition":
|
|
@@ -186,8 +188,8 @@ function setPassLane(e) {
|
|
|
186
188
|
* Cleared by the flush the join schedules, and at the end of a flush that
|
|
187
189
|
* set it. */ let passTx = null;
|
|
188
190
|
|
|
189
|
-
function joinPassTx(e,
|
|
190
|
-
if (globalQueue.q && !
|
|
191
|
+
function joinPassTx(e, o) {
|
|
192
|
+
if (globalQueue.q && !o || flushTransaction !== null) return joinFuture(e);
|
|
191
193
|
if (passTx === null) passTx = resolveTx(e); else merge(resolveTx(e), passTx);
|
|
192
194
|
schedule();
|
|
193
195
|
}
|
|
@@ -204,37 +206,37 @@ function joinPassTx(e, n) {
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
function resolveTx(e) {
|
|
207
|
-
while (e.
|
|
209
|
+
while (e.eo !== null) e = e.eo;
|
|
208
210
|
return e;
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
/** The flush joins transaction `t` — or needs one of its own (`null`: a pass
|
|
212
214
|
* went pending with nothing held). Joining a second one merges it into the
|
|
213
215
|
* flush's: the work that touched both entangles them (A15). */ function joinFuture(e) {
|
|
214
|
-
const
|
|
215
|
-
if (
|
|
216
|
+
const o = flushTransaction;
|
|
217
|
+
if (o === null) {
|
|
216
218
|
flushTransaction = e === null ? newTransaction(false) : resolveTx(e);
|
|
217
|
-
} else if (e !== null) merge(resolveTx(e),
|
|
219
|
+
} else if (e !== null) merge(resolveTx(e), o);
|
|
218
220
|
if (!globalQueue.q) schedule();
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
/** `t` merges into `f`: the work that touched both entangles them (A15).
|
|
222
224
|
* A lane never merges: it is a sub-frame, not a peer — its work is routed
|
|
223
|
-
* per pass (`passLane`). */ function merge(e,
|
|
225
|
+
* per pass (`passLane`). */ function merge(e, o) {
|
|
224
226
|
// Both ends resolved: a stale pointer to a transaction already merged
|
|
225
227
|
// into the other would close a cycle `resolveTx` never leaves.
|
|
226
228
|
e = resolveTx(e);
|
|
227
|
-
|
|
228
|
-
if (e ===
|
|
229
|
-
if (attrHooks !== null) attrHooks.transitionMerged(
|
|
230
|
-
e.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
append(
|
|
234
|
-
append(
|
|
235
|
-
append(
|
|
236
|
-
append(
|
|
237
|
-
if (e.I !== null) append(
|
|
229
|
+
o = resolveTx(o);
|
|
230
|
+
if (e === o || e.V || o.V) return;
|
|
231
|
+
if (attrHooks !== null) attrHooks.transitionMerged(o, e);
|
|
232
|
+
e.eo = o;
|
|
233
|
+
o.tt += e.tt;
|
|
234
|
+
o.nt ||= e.nt;
|
|
235
|
+
append(o.je, e.je);
|
|
236
|
+
append(o.un[0], e.un[0]);
|
|
237
|
+
append(o.un[1], e.un[1]);
|
|
238
|
+
append(o.En, e.En);
|
|
239
|
+
if (e.I !== null) append(o.I ??= [], e.I);
|
|
238
240
|
transactions.splice(transactions.indexOf(e), 1);
|
|
239
241
|
}
|
|
240
242
|
|
|
@@ -256,13 +258,13 @@ function resolveTx(e) {
|
|
|
256
258
|
* in for the flight (A17: "visible until its own fetch settles"). */ function blocked(e) {
|
|
257
259
|
// The transaction being judged (a lane consulted on its behalf judges for
|
|
258
260
|
// it): a zombie whose removal it stages is moot for it alone (`onScreen`).
|
|
259
|
-
const
|
|
261
|
+
const o = judge;
|
|
260
262
|
judge ??= e;
|
|
261
263
|
// An action still running in it holds it open (action.ts). Its lanes
|
|
262
264
|
// (lanes.ts): a lane under `t` blocks it while blocked itself.
|
|
263
|
-
const
|
|
264
|
-
judge =
|
|
265
|
-
return
|
|
265
|
+
const n = e.tt !== 0 || blockedBy(e.je, e) || !!lanesBlockedHook?.(e);
|
|
266
|
+
judge = o;
|
|
267
|
+
return n;
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
let judge = null;
|
|
@@ -270,12 +272,12 @@ let judge = null;
|
|
|
270
272
|
/** Observe tier: the flights `t` waits on — its pending held sources a
|
|
271
273
|
* frame reader observes (`blockedBy`'s predicate, collected; the readers
|
|
272
274
|
* themselves are not sources). */ function blockersOf(e) {
|
|
273
|
-
const
|
|
274
|
-
for (let
|
|
275
|
-
const t = e.je[
|
|
276
|
-
if (!t.i && t.m & STATUS_PENDING && !(t.R & REACTIVE_DISPOSED) && (t.T.Je === null || txOf(t) === e) && blockedBy([ t ], e))
|
|
275
|
+
const o = [];
|
|
276
|
+
for (let n = 0; n < e.je.length; n++) {
|
|
277
|
+
const t = e.je[n];
|
|
278
|
+
if (!t.i && t.m & STATUS_PENDING && !(t.R & REACTIVE_DISPOSED) && (t.T.Je === null || txOf(t) === e) && blockedBy([ t ], e)) o.push(t);
|
|
277
279
|
}
|
|
278
|
-
return
|
|
280
|
+
return o;
|
|
279
281
|
}
|
|
280
282
|
|
|
281
283
|
/** `t`'s own flights only — not its lanes': a flight the frame asked for
|
|
@@ -288,28 +290,28 @@ let judge = null;
|
|
|
288
290
|
|
|
289
291
|
/** A source the pending node waits on that is `t`'s (held by it, or by no
|
|
290
292
|
* one) — not another transaction's or lane's work. Itself, when it is the
|
|
291
|
-
* source. */ function ownSource(e,
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
294
|
-
for (const e of
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
293
|
+
* source. */ function ownSource(e, o) {
|
|
294
|
+
const n = e.T?.se;
|
|
295
|
+
if (n === undefined) return true;
|
|
296
|
+
for (const e of n) {
|
|
297
|
+
const n = e.T?.Je;
|
|
298
|
+
if (n == null || resolveTx(n) === o) return true;
|
|
297
299
|
}
|
|
298
300
|
return false;
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
function blockedBy(e,
|
|
303
|
+
function blockedBy(e, o, n = false) {
|
|
302
304
|
for (let t = 0; t < e.length; t++) {
|
|
303
305
|
const l = e[t];
|
|
304
|
-
if (!(l.m & STATUS_PENDING) || l.R & REACTIVE_DISPOSED || l.l & CONFIG_GUESS || l.T.Je !== null && txOf(l) !==
|
|
306
|
+
if (!(l.m & STATUS_PENDING) || l.R & REACTIVE_DISPOSED || l.l & CONFIG_GUESS || l.T.Je !== null && txOf(l) !== o || n && !ownSource(l, o)) continue;
|
|
305
307
|
// The frame's own pending observer (off screen: this one holds nothing;
|
|
306
308
|
// the next listed node may).
|
|
307
309
|
if (l.i === EFFECT_RENDER) {
|
|
308
|
-
if (onScreen(l, judge ??
|
|
310
|
+
if (onScreen(l, judge ?? o)) return true;
|
|
309
311
|
continue;
|
|
310
312
|
}
|
|
311
313
|
for (let e = l.o; e !== null; e = e.t) {
|
|
312
|
-
const
|
|
314
|
+
const n = e.u;
|
|
313
315
|
// A frame reader: a render effect, or a stale reader of the flight
|
|
314
316
|
// (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
|
|
315
317
|
// `frameRead`): served committed instead of going pending, it derives
|
|
@@ -321,7 +323,7 @@ function blockedBy(e, n, o = false) {
|
|
|
321
323
|
// lane-membership ruling, 2026-10-05). An output that never committed
|
|
322
324
|
// shows nothing — a mount the frame has not revealed — and holds
|
|
323
325
|
// nothing.
|
|
324
|
-
if ((
|
|
326
|
+
if ((n.i === EFFECT_RENDER && n.m & STATUS_PENDING || n.R & REACTIVE_FRAME_READ || n.l & CONFIG_REDERIVE && n.m === STATUS_PENDING) && (e.Te === n.Ne || n.T?.F != null) && !(n.R & REACTIVE_DISPOSED) && onScreen(n, judge ?? o)) return true;
|
|
325
327
|
}
|
|
326
328
|
}
|
|
327
329
|
return false;
|
|
@@ -334,8 +336,8 @@ function blockedBy(e, n, o = false) {
|
|
|
334
336
|
* is visible, a lane's reveal included: only the commit that disposes it
|
|
335
337
|
* makes its say moot), and not behind a fallback (A33: a boundary showing its fallback is the display of
|
|
336
338
|
* everything under it, so a reader there is not on screen and holds
|
|
337
|
-
* nothing — boundaries.ts). */ function onScreen(e,
|
|
338
|
-
return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e,
|
|
339
|
+
* nothing — boundaries.ts). */ function onScreen(e, o) {
|
|
340
|
+
return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e, o)) && !hiddenHook?.(e);
|
|
339
341
|
}
|
|
340
342
|
|
|
341
343
|
/** A15 (#3463): a reader whose removal is staged — a zombie, parked by a
|
|
@@ -343,10 +345,10 @@ function blockedBy(e, n, o = false) {
|
|
|
343
345
|
* except the transaction staging its removal: for that one its say is moot
|
|
344
346
|
* (done, and the commit disposes it; not done, and it stays parked). The
|
|
345
347
|
* staging transaction is the one holding the pass that parked the frame:
|
|
346
|
-
* the nearest non-zombie ancestor. */ function removalStagedBy(e,
|
|
347
|
-
let
|
|
348
|
-
while (
|
|
349
|
-
return
|
|
348
|
+
* the nearest non-zombie ancestor. */ function removalStagedBy(e, o) {
|
|
349
|
+
let n = e;
|
|
350
|
+
while (n?.R & REACTIVE_ZOMBIE) n = n._parent;
|
|
351
|
+
return n?.l & CONFIG_HELD && n.T?.Je != null && txOf(n) === resolveTx(o);
|
|
350
352
|
}
|
|
351
353
|
|
|
352
354
|
/** Unchanged passes this flush whose stale dependency tail awaits the
|
|
@@ -372,18 +374,18 @@ function deferZombie(e) {
|
|
|
372
374
|
}
|
|
373
375
|
|
|
374
376
|
/** Put a staged node in a transaction: flagged, stamped, on its landing
|
|
375
|
-
* list. */ function holdNode(e,
|
|
377
|
+
* list. */ function holdNode(e, o) {
|
|
376
378
|
e.l |= CONFIG_HELD;
|
|
377
|
-
list(e,
|
|
379
|
+
list(e, o);
|
|
378
380
|
}
|
|
379
381
|
|
|
380
382
|
/** Put a node on a transaction's list, once: a node's `_transaction` is the
|
|
381
383
|
* transaction whose `_nodes` it is on (every site that sets one does the
|
|
382
|
-
* other), so a re-pass, a re-landing or a re-staging adds nothing. */ function list(e,
|
|
383
|
-
const
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
|
|
384
|
+
* other), so a re-pass, a re-landing or a re-staging adds nothing. */ function list(e, o) {
|
|
385
|
+
const n = ext(e);
|
|
386
|
+
if (n.Je === o) return;
|
|
387
|
+
n.Je = o;
|
|
388
|
+
o.je.push(e);
|
|
387
389
|
}
|
|
388
390
|
|
|
389
391
|
/** Hold the (uncommitted) frame under a held pass: every computed in the
|
|
@@ -398,22 +400,22 @@ function deferZombie(e) {
|
|
|
398
400
|
* and `dissolveLane` no longer finds it — a lane node with no lane, which the
|
|
399
401
|
* next read of it trips over (`laneRead` → `txOf`). Its frame is the lane's
|
|
400
402
|
* too (ruling A: a lane pass's children are the lane's), revealed and
|
|
401
|
-
* retired at the lane's seam. */ function holdFrame(e,
|
|
402
|
-
for (let
|
|
403
|
-
if (
|
|
404
|
-
if (
|
|
405
|
-
if (!(
|
|
406
|
-
|
|
403
|
+
* retired at the lane's seam. */ function holdFrame(e, o) {
|
|
404
|
+
for (let n = e.ze; n !== null; n = n.Xe) {
|
|
405
|
+
if (n.T?.Je?.V) continue;
|
|
406
|
+
if (n.X !== undefined) {
|
|
407
|
+
if (!(n.l & CONFIG_HELD)) holdNode(n, o);
|
|
408
|
+
n.l |= CONFIG_HELD_FRAME;
|
|
407
409
|
}
|
|
408
|
-
holdFrame(
|
|
410
|
+
holdFrame(n, o);
|
|
409
411
|
}
|
|
410
412
|
}
|
|
411
413
|
|
|
412
414
|
/** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
|
|
413
|
-
* what an earlier hold staged under a re-armed boundary). */ function heldUnder(e,
|
|
415
|
+
* what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, o, n) {
|
|
414
416
|
for (let t = e.ze; t !== null; t = t.Xe) {
|
|
415
|
-
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !==
|
|
416
|
-
heldUnder(t,
|
|
417
|
+
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !== o) n(t);
|
|
418
|
+
heldUnder(t, o, n);
|
|
417
419
|
}
|
|
418
420
|
}
|
|
419
421
|
|
|
@@ -510,7 +512,9 @@ function schedule() {
|
|
|
510
512
|
function haltReactivity(e) {
|
|
511
513
|
if (halted) return;
|
|
512
514
|
halted = true;
|
|
513
|
-
|
|
515
|
+
// A cleanup error collected before the halt is dropped (owner.ts).
|
|
516
|
+
rethrowCleanupError(true);
|
|
517
|
+
let o = "[REACTIVITY_HALTED]";
|
|
514
518
|
// Surface the cause here too: callers rethrow it, but a creation-time throw
|
|
515
519
|
// unwinds through ancestor recomputes that convert it to status instead of
|
|
516
520
|
// surfacing it (#2884), so the rethrow alone cannot guarantee visibility.
|
|
@@ -520,9 +524,18 @@ function haltReactivity(e) {
|
|
|
520
524
|
// nothing an app or its telemetry can act on (#3338 — an uncaught throw
|
|
521
525
|
// during the hydration render). The rethrow may reach the top as well in
|
|
522
526
|
// the non-swallowed cases; a duplicate report beats a silent one.
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
527
|
+
const n = e !== undefined && globalThis.reportError;
|
|
528
|
+
n || e === undefined ? console.error(o) : console.error(o, e);
|
|
529
|
+
n && n(e);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Dev: `haltReactivity`, located at `subject` — the computation the uncaught
|
|
534
|
+
* error escaped from — for the REACTIVITY_HALTED message's owner path. Call
|
|
535
|
+
* sites pick it in dev builds only (`haltReactivity(e)` in production), so
|
|
536
|
+
* production keeps the one-argument halt and its bytes unchanged.
|
|
537
|
+
*/ function haltReactivityAt(e, o) {
|
|
538
|
+
haltReactivity(e);
|
|
526
539
|
}
|
|
527
540
|
|
|
528
541
|
// Logs on the first write after a halt so a frozen interaction is traceable.
|
|
@@ -595,13 +608,13 @@ class GlobalQueue {
|
|
|
595
608
|
// A lane's own flush (its flight landing, its reveal) parks nothing: the
|
|
596
609
|
// lane's work reached it per pass; the frame's plain writes commit.
|
|
597
610
|
// (Resolved: a guess over another transaction's guess merged them.)
|
|
598
|
-
const
|
|
599
|
-
if (
|
|
611
|
+
const o = e !== null && !e.V ? resolveTx(e) : null;
|
|
612
|
+
if (o !== null) {
|
|
600
613
|
// `t._nodes` grows under the walk (holdFrame pushes); the bound is
|
|
601
614
|
// this flush's list, which does not.
|
|
602
615
|
const e = pendingNodes.length;
|
|
603
|
-
for (let
|
|
604
|
-
const e = pendingNodes[
|
|
616
|
+
for (let n = 0; n < e; n++) {
|
|
617
|
+
const e = pendingNodes[n];
|
|
605
618
|
// Already held: the pass that re-staged it joined its transaction,
|
|
606
619
|
// which is `t` (or merged into it). Lane work is the lane's (a
|
|
607
620
|
// pending mark propagated onto it queued it here too).
|
|
@@ -629,15 +642,15 @@ class GlobalQueue {
|
|
|
629
642
|
e.l &= ~CONFIG_STAGED;
|
|
630
643
|
continue;
|
|
631
644
|
}
|
|
632
|
-
holdNode(e,
|
|
645
|
+
holdNode(e, o);
|
|
633
646
|
}
|
|
634
647
|
// A held pass's frame is held with it (ruling A, O2): the children it
|
|
635
648
|
// created are the transaction's — they compute, and a pass over them
|
|
636
649
|
// or a write that reaches them joins; they effect at the landing.
|
|
637
|
-
if (e.l & CONFIG_STAGED) holdFrame(e,
|
|
650
|
+
if (e.l & CONFIG_STAGED) holdFrame(e, o);
|
|
638
651
|
}
|
|
639
652
|
pendingNodes.length = 0;
|
|
640
|
-
storeParkHook?.(
|
|
653
|
+
storeParkHook?.(o);
|
|
641
654
|
// (This flush's runs are stashed with `t` below — after the landings,
|
|
642
655
|
// so a `t` that lands at this very seam runs them first, ahead of
|
|
643
656
|
// the runs it held from earlier flushes.)
|
|
@@ -648,10 +661,10 @@ class GlobalQueue {
|
|
|
648
661
|
// holder's verdict lane's work — before the lane seams, which reveal
|
|
649
662
|
// it (nothing commits this seam that could dispose it).
|
|
650
663
|
// (Verdict readers exist only with the verdict engine installed.)
|
|
651
|
-
const
|
|
664
|
+
const n = deferredZombies.splice(0);
|
|
652
665
|
if (observeFlightHook) {
|
|
653
|
-
|
|
654
|
-
for (let e = 0; e <
|
|
666
|
+
n.sort((e, o) => e.Et - o.Et);
|
|
667
|
+
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
668
|
}
|
|
656
669
|
// The unchanged passes' tails stay linked (A30, #3469): their inputs
|
|
657
670
|
// are held, and the committed frame still derives from them — no trim.
|
|
@@ -663,8 +676,8 @@ class GlobalQueue {
|
|
|
663
676
|
// left an effect owing a run (`runEffect` trims when the run applies):
|
|
664
677
|
// `recompute`'s own gates.
|
|
665
678
|
for (let e = 0; e < heldTrims.length; e++) {
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
679
|
+
const o = heldTrims[e];
|
|
680
|
+
if (o.T?.F == null && !o.Qe) trimStaleDeps(o);
|
|
668
681
|
}
|
|
669
682
|
}
|
|
670
683
|
// The list is the flush's either way. Reset only when there is something
|
|
@@ -678,22 +691,22 @@ class GlobalQueue {
|
|
|
678
691
|
// removes its entry.
|
|
679
692
|
// This flush's own runs, the lanes' reveals, and the landings' held runs
|
|
680
693
|
// are collected apart and ordered below.
|
|
681
|
-
const
|
|
694
|
+
const n = this.un;
|
|
682
695
|
const t = this.un = [ [], [] ];
|
|
683
696
|
// The passes that read this frame's stagings as the screen read held
|
|
684
697
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
685
698
|
// world (a lane's runs wait this round).
|
|
686
699
|
if (laneSeamsHook) {
|
|
687
|
-
laneSeamsHook(
|
|
700
|
+
laneSeamsHook(o !== null ? stagedReaders : null);
|
|
688
701
|
if (stagedReaders.length) stagedReaders.length = 0;
|
|
689
702
|
}
|
|
690
703
|
this.un = [ [], [] ];
|
|
691
704
|
for (let e = transactions.length - 1; e >= 0; e--) {
|
|
692
|
-
const
|
|
693
|
-
if (blocked(
|
|
705
|
+
const o = transactions[e];
|
|
706
|
+
if (blocked(o)) continue;
|
|
694
707
|
transactions.splice(e, 1);
|
|
695
|
-
endLanesHook?.(
|
|
696
|
-
land(
|
|
708
|
+
endLanesHook?.(o);
|
|
709
|
+
land(o);
|
|
697
710
|
// A landing's commits can dispose a zombie a transaction judged above
|
|
698
711
|
// was blocked on (#3463: live "until the commit that disposes it") —
|
|
699
712
|
// judge them again.
|
|
@@ -706,7 +719,7 @@ class GlobalQueue {
|
|
|
706
719
|
// parked (something async below) — the window is the frame's, the marks
|
|
707
720
|
// are its transaction's; else they release at the seam, verdict-only,
|
|
708
721
|
// nothing to show (affects.ts).
|
|
709
|
-
const l =
|
|
722
|
+
const l = o && liveTx(o);
|
|
710
723
|
releaseAmbientMarksHook?.(l);
|
|
711
724
|
// The effect phase: lane work first (displayed ahead of the frame), then
|
|
712
725
|
// this flush's runs, then the runs the landings held from earlier
|
|
@@ -725,19 +738,19 @@ class GlobalQueue {
|
|
|
725
738
|
holding = true;
|
|
726
739
|
}
|
|
727
740
|
for (let e = 0; e < 2; e++) {
|
|
728
|
-
if (s) append(l.un[e],
|
|
741
|
+
if (s) append(l.un[e], n[e]);
|
|
729
742
|
// The plain flush — no reveal, no landing, not parked — has nothing to
|
|
730
743
|
// order around its own runs: they are the queue as they stand (the
|
|
731
744
|
// same array, not a copy; `run` takes it whole). Every other seam
|
|
732
745
|
// builds the ordered queue above.
|
|
733
|
-
this.un[e] = s || t[e].length || this.un[e].length ? t[e].concat(s ? [] :
|
|
746
|
+
this.un[e] = s || t[e].length || this.un[e].length ? t[e].concat(s ? [] : n[e], this.un[e]) : n[e];
|
|
734
747
|
}
|
|
735
748
|
if (deferredZombies.length !== 0) {
|
|
736
749
|
// Survivors are the displayed frame of a held pass: they rerun for the
|
|
737
750
|
// live write, parents before children.
|
|
738
|
-
const e = deferredZombies.splice(0).sort((e,
|
|
739
|
-
for (let
|
|
740
|
-
if (!(e[
|
|
751
|
+
const e = deferredZombies.splice(0).sort((e, o) => e.Et - o.Et);
|
|
752
|
+
for (let o = 0; o < e.length; o++) {
|
|
753
|
+
if (!(e[o].R & REACTIVE_DISPOSED)) recompute(e[o]);
|
|
741
754
|
}
|
|
742
755
|
}
|
|
743
756
|
// Boundaries: readers that settled, landed or died this flush are
|
|
@@ -745,18 +758,18 @@ class GlobalQueue {
|
|
|
745
758
|
boundarySeamHook?.();
|
|
746
759
|
}
|
|
747
760
|
run(e) {
|
|
748
|
-
const
|
|
749
|
-
if (
|
|
761
|
+
const o = this.un[e - 1];
|
|
762
|
+
if (o.length) {
|
|
750
763
|
this.un[e - 1] = [];
|
|
751
|
-
runQueue(
|
|
764
|
+
runQueue(o, e);
|
|
752
765
|
}
|
|
753
766
|
}
|
|
754
|
-
enqueue(e,
|
|
767
|
+
enqueue(e, o, n = passLane) {
|
|
755
768
|
// Lane work's runs are the lane's: they run at its reveal, not with
|
|
756
769
|
// the frame (which may park). A lane pass that read the frame's own
|
|
757
770
|
// staging is the frame's (`recompute` passes null): its run waits with
|
|
758
771
|
// the frame.
|
|
759
|
-
if (e) (
|
|
772
|
+
if (e) (n !== null ? n : this).un[e - 1].push(o);
|
|
760
773
|
schedule();
|
|
761
774
|
}
|
|
762
775
|
/** Status reaching the root: pending is absorbed (the root mount defers —
|
|
@@ -772,10 +785,10 @@ class GlobalQueue {
|
|
|
772
785
|
*
|
|
773
786
|
* A boundary between the observer and the root (boundaries.ts) is asked
|
|
774
787
|
* first: a fallback catches what is not ready under it, and the root
|
|
775
|
-
* never hears of it. */ notify(e,
|
|
776
|
-
if (catchHook?.(e,
|
|
777
|
-
if (
|
|
778
|
-
if (
|
|
788
|
+
* never hears of it. */ notify(e, o, n, t) {
|
|
789
|
+
if (catchHook?.(e, n & o, t)) return true;
|
|
790
|
+
if (o & STATUS_PENDING) {
|
|
791
|
+
if (n & STATUS_PENDING) {
|
|
779
792
|
// A pass that went pending holds its frame: the async's own
|
|
780
793
|
// synchronous frame is not ready (A15 reveal corollary: a reveal
|
|
781
794
|
// that discovers a flight whose inputs are visible holds and joins
|
|
@@ -806,60 +819,71 @@ class GlobalQueue {
|
|
|
806
819
|
* or without the held read) owes nothing. A run this transaction stashed
|
|
807
820
|
* for it is void (#3322: an effect has one value slot, and the stale pass
|
|
808
821
|
* overwrote the value that run was for) — the re-derivation's run replaces
|
|
809
|
-
* it. */ function reruns(e) {
|
|
822
|
+
* it. Truthy when an effect re-derives (`land`). */ function reruns(e) {
|
|
823
|
+
let o;
|
|
810
824
|
for (let n = 0; n < e.En.length; n++) {
|
|
811
|
-
const
|
|
825
|
+
const t = e.En[n];
|
|
812
826
|
// An errored reader's display is its error (D-39): the landing gives it
|
|
813
827
|
// nothing to re-derive, and a re-run would be a read that retries the
|
|
814
828
|
// errored source (#3945).
|
|
815
|
-
if (
|
|
816
|
-
if (
|
|
817
|
-
o
|
|
818
|
-
|
|
829
|
+
if (t.R & REACTIVE_DISPOSED || t.m & STATUS_ERROR) continue;
|
|
830
|
+
if (t.R & REACTIVE_FRAME_READ || t.l & CONFIG_VERDICT) {
|
|
831
|
+
o ||= t.i;
|
|
832
|
+
t.R &= ~REACTIVE_FRAME_READ;
|
|
833
|
+
t.Qe = false;
|
|
819
834
|
// Its frame is replaced by the re-derivation: a run one of its
|
|
820
835
|
// children queued this flush (re-run by the same landing) is for the
|
|
821
836
|
// frame being replaced — void too (#3404).
|
|
822
|
-
for (let e =
|
|
823
|
-
enqueueSub(
|
|
837
|
+
for (let e = t.ze; e !== null; e = e.Xe) if (e.i) e.Qe = false;
|
|
838
|
+
enqueueSub(t);
|
|
824
839
|
}
|
|
825
840
|
}
|
|
826
841
|
e.En.length = 0;
|
|
842
|
+
return o;
|
|
827
843
|
}
|
|
828
844
|
|
|
829
845
|
/** The landing: the held frame becomes the frame. */ function land(e) {
|
|
830
846
|
// Attribution hook: judged complete — its held writes commit next
|
|
831
847
|
// (`_nodes` still lists them).
|
|
832
848
|
if (attrHooks !== null) attrHooks.transitionSettled(e);
|
|
833
|
-
reruns(e);
|
|
849
|
+
const o = reruns(e);
|
|
834
850
|
if (e.I !== null) releaseMarksHook(e.I);
|
|
835
851
|
// Old children die in the commits (cleanups first), then the stashed
|
|
836
852
|
// effects run ahead of this flush's own. A node a lane took over since
|
|
837
853
|
// (a guess written over the staged truth) is the lane's to land.
|
|
838
|
-
for (let
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
841
|
-
|
|
842
|
-
commitPendingNode(
|
|
854
|
+
for (let o = 0; o < e.je.length; o++) {
|
|
855
|
+
const n = e.je[o];
|
|
856
|
+
if (n.T.Je === null || txOf(n) !== e) continue;
|
|
857
|
+
n.T.Je = null;
|
|
858
|
+
commitPendingNode(n);
|
|
843
859
|
}
|
|
844
860
|
// A cleanup those commits ran that wrote a node `u` still held joined
|
|
845
861
|
// `u`, which has left `transactions`: the write is this landing's, and
|
|
846
862
|
// the next flush must not park in it (#4089).
|
|
847
863
|
if (flushTransaction === e) flushTransaction = null;
|
|
848
|
-
|
|
864
|
+
// An effect re-derives next round (`reruns`): the held runs wait for it
|
|
865
|
+
// (D-9, the A15 reveal corollary, #4071). Its re-derivation can discover a
|
|
866
|
+
// flight — a stale reader whose mainline pass stopped reading it, now
|
|
867
|
+
// reading the landed world — and a landing that showed its runs first
|
|
868
|
+
// would reveal the held write beside a frame that can only show its old
|
|
869
|
+
// value. Queued last in this effect phase, the release hands them to the
|
|
870
|
+
// next round's own runs, ahead of the re-derivation's: they show with it,
|
|
871
|
+
// or park with it in the hold its pending opens. The commits stand.
|
|
872
|
+
if (o) globalQueue.un[1].push(() => releaseQueues(e)); else releaseQueues(e);
|
|
849
873
|
}
|
|
850
874
|
|
|
851
875
|
/** The held runs join this flush's effect phase after its own runs (the
|
|
852
876
|
* landing's re-passes, in height order): the frame's effects run as one
|
|
853
877
|
* pass would have queued them — a shell re-derived at the landing before a
|
|
854
878
|
* boundary swap held since the write (#3540's log order). */ function releaseQueues(e) {
|
|
855
|
-
for (let
|
|
856
|
-
append(globalQueue.un[
|
|
857
|
-
e.un[
|
|
879
|
+
for (let o = 0; o < 2; o++) {
|
|
880
|
+
append(globalQueue.un[o], e.un[o]);
|
|
881
|
+
e.un[o] = [];
|
|
858
882
|
}
|
|
859
883
|
}
|
|
860
884
|
|
|
861
|
-
/** `a.push(...b)` without the argument-count limit. */ function append(e,
|
|
862
|
-
for (let
|
|
885
|
+
/** `a.push(...b)` without the argument-count limit. */ function append(e, o) {
|
|
886
|
+
for (let n = 0; n < o.length; n++) e.push(o[n]);
|
|
863
887
|
}
|
|
864
888
|
|
|
865
889
|
/** Nodes staged this flush (`_pendingValue` set), committed at its end. */ const pendingNodes = [];
|
|
@@ -871,10 +895,10 @@ class GlobalQueue {
|
|
|
871
895
|
|
|
872
896
|
/** A15's stale reader: `c` was served the committed value of a node `t`
|
|
873
897
|
* holds (a render effect, a verdict reader, lane work) and is re-derived
|
|
874
|
-
* after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e,
|
|
898
|
+
* after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e, o) {
|
|
875
899
|
if (!(e.R & REACTIVE_FRAME_READ)) {
|
|
876
900
|
e.R |= REACTIVE_FRAME_READ;
|
|
877
|
-
|
|
901
|
+
o.En.push(e);
|
|
878
902
|
}
|
|
879
903
|
}
|
|
880
904
|
|
|
@@ -900,13 +924,13 @@ function insertSubs(e) {
|
|
|
900
924
|
// Presence bits gate the optional-slot probes (see constants.ts): one
|
|
901
925
|
// masked read of the always-present _config instead of missing-property
|
|
902
926
|
// lookups in the hottest notify loop.
|
|
903
|
-
const
|
|
904
|
-
const
|
|
927
|
+
const o = e.l;
|
|
928
|
+
const n = (o & CONFIG_HAS_SNAPSHOT) !== 0 && e.T?.lt !== undefined;
|
|
905
929
|
// Observe-tier fan-out: this walk visits every subscriber edge anyway, so
|
|
906
930
|
// the graph-size count is one local increment here and no field anywhere.
|
|
907
931
|
let t = 0;
|
|
908
|
-
for (let
|
|
909
|
-
const e =
|
|
932
|
+
for (let o = e.o; o !== null; o = o.t) {
|
|
933
|
+
const e = o.u;
|
|
910
934
|
t++;
|
|
911
935
|
// Missed-wake latch (#3037): this write is landing while the subscriber
|
|
912
936
|
// is mid-recompute (a nested pull committing beneath its reads), and the
|
|
@@ -916,8 +940,8 @@ function insertSubs(e) {
|
|
|
916
940
|
// pass either re-reads them fresh or trims them), and neither does the
|
|
917
941
|
// tail link: it is the read IN FLIGHT — read() links before it pulls, so
|
|
918
942
|
// this very commit is what that read returns.
|
|
919
|
-
if (e.R & REACTIVE_RECOMPUTING_DEPS &&
|
|
920
|
-
if (
|
|
943
|
+
if (e.R & REACTIVE_RECOMPUTING_DEPS && o.Te === e.Ne && o !== e._) e.R |= REACTIVE_MISSED_WAKE;
|
|
944
|
+
if (n && e.l & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
921
945
|
e.R |= REACTIVE_SNAPSHOT_STALE;
|
|
922
946
|
continue;
|
|
923
947
|
}
|
|
@@ -933,25 +957,25 @@ function insertSubs(e) {
|
|
|
933
957
|
* inert for its pass (`recompute` seats a lane only from its own `_x`), it
|
|
934
958
|
* is a live write if the effect becomes a zombie later this flush — an
|
|
935
959
|
* on-screen reader whose removal an adopted write stages follows the lane
|
|
936
|
-
* (the lane-membership ruling, 2026-10-05; `_update`). */ function laneDirty(e,
|
|
937
|
-
for (let
|
|
938
|
-
const e =
|
|
939
|
-
if (e?.V ? sameLane(e,
|
|
960
|
+
* (the lane-membership ruling, 2026-10-05; `_update`). */ function laneDirty(e, o) {
|
|
961
|
+
for (let n = e.o; n !== null; n = n.t) {
|
|
962
|
+
const e = n.u.T?.Je;
|
|
963
|
+
if (e?.V ? sameLane(e, o) : n.u.i) n.u.R |= REACTIVE_LANE_DIRTY;
|
|
940
964
|
}
|
|
941
965
|
}
|
|
942
966
|
|
|
943
|
-
/** One lane, or two of one link group (#3335): one reveal unit. */ function sameLane(e,
|
|
944
|
-
return e ===
|
|
967
|
+
/** One lane, or two of one link group (#3335): one reveal unit. */ function sameLane(e, o) {
|
|
968
|
+
return e === o || e.nn !== null && e.nn === o.nn;
|
|
945
969
|
}
|
|
946
970
|
|
|
947
971
|
function commitPendingNode(e) {
|
|
948
|
-
const
|
|
972
|
+
const o = e;
|
|
949
973
|
// L2: the commit is where a pass, held or not, stops being uncommitted —
|
|
950
974
|
// unless it has no answer yet. A pass still in flight (pending, nothing
|
|
951
975
|
// staged) stays uncommitted: a re-pass disposes its children on the spot,
|
|
952
976
|
// and the frame it parked stays the frame until a pass of this node
|
|
953
977
|
// commits a value.
|
|
954
|
-
if (!
|
|
978
|
+
if (!o.X) {
|
|
955
979
|
e.l &= -385;
|
|
956
980
|
if (e.ue !== NOT_PENDING) {
|
|
957
981
|
e.Ie = e.ue;
|
|
@@ -962,62 +986,62 @@ function commitPendingNode(e) {
|
|
|
962
986
|
// Computeds only from here (`_statusFlags` is not a signal field). A
|
|
963
987
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
964
988
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
965
|
-
const
|
|
989
|
+
const n = e.ue === NOT_PENDING && (o.m & STATUS_PENDING) !== 0;
|
|
966
990
|
const t = e.l & CONFIG_STAGED_ERROR;
|
|
967
991
|
// An answer commits: the error it replaces leaves the display (D-41).
|
|
968
|
-
if (!
|
|
969
|
-
e.l =
|
|
992
|
+
if (!n && o.T) o.T.de = undefined;
|
|
993
|
+
e.l = n ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
|
|
970
994
|
// D-41: the staged answer is an error — published now, when a value would
|
|
971
995
|
// show, through the ordinary error path (`stageError`). Its readers first
|
|
972
996
|
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
973
997
|
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
974
998
|
if (t) {
|
|
975
|
-
const
|
|
999
|
+
const n = e.ue;
|
|
976
1000
|
e.ue = NOT_PENDING;
|
|
977
1001
|
e.ie = clock + 1;
|
|
978
|
-
notifyStatus(
|
|
1002
|
+
notifyStatus(o, STATUS_ERROR, n);
|
|
979
1003
|
} else if (e.ue !== NOT_PENDING) {
|
|
980
1004
|
e.Ie = e.ue;
|
|
981
1005
|
e.ue = NOT_PENDING;
|
|
982
1006
|
// A node born staged (recompute) initializes at this commit.
|
|
983
|
-
|
|
1007
|
+
o.m &= ~STATUS_UNINITIALIZED;
|
|
984
1008
|
// A quiet re-ask's classification survives its landing and dies with
|
|
985
1009
|
// the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
|
|
986
1010
|
// the reveal. (The sweep of a node still in flight is not a landing.)
|
|
987
1011
|
// The A28 stash goes with it.
|
|
988
|
-
if (
|
|
1012
|
+
if (o.T != null) o.T.ut = false, o.T.Gt = NOT_PENDING;
|
|
989
1013
|
// An effect with a staged value was born held (L2): its first run is
|
|
990
1014
|
// this commit's, not its creation's (A29) — queue it now.
|
|
991
1015
|
if (e.i && e.i !== EFFECT_TRACKED) {
|
|
992
1016
|
e.Qe = true;
|
|
993
|
-
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.K.bind(null,
|
|
1017
|
+
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.K.bind(null, o));
|
|
994
1018
|
}
|
|
995
1019
|
}
|
|
996
1020
|
// The committed value is the first observable answer for a loading-window
|
|
997
1021
|
// node — the window closes here, not at compute time (#2990). Unconditional
|
|
998
1022
|
// store to an always-present computed slot.
|
|
999
|
-
|
|
1000
|
-
|
|
1023
|
+
o.ce = false;
|
|
1024
|
+
o.R &= ~REACTIVE_MANUAL_WRITE;
|
|
1001
1025
|
// The dependencies of the pass that produced the value are the frame's now:
|
|
1002
1026
|
// the previous frame's tail goes (A30, #3410; `recompute` left it for a
|
|
1003
1027
|
// staged pass). Only after a clean pass: `_error` is cleared by a clean
|
|
1004
1028
|
// pass or by the node's own landing (whose pass was clean), so a set
|
|
1005
1029
|
// `_error` means the last pass threw, kept its full list, and `_depsTail`
|
|
1006
1030
|
// marks where it stopped.
|
|
1007
|
-
if (
|
|
1008
|
-
if (!(
|
|
1031
|
+
if (o.T?.F == null) trimStaleDeps(o);
|
|
1032
|
+
if (!(o.m & STATUS_PENDING)) o.m &= ~STATUS_UNINITIALIZED;
|
|
1009
1033
|
// L2: the children this commit publishes are the frame's now — the frame
|
|
1010
1034
|
// they replace, parked by the pass (`recompute`), goes.
|
|
1011
|
-
if (!
|
|
1035
|
+
if (!n && o.T != null && (o.T.Nt !== null || o.T.ft !== null)) GlobalQueue.et(o, false, true);
|
|
1012
1036
|
}
|
|
1013
1037
|
|
|
1014
1038
|
function commitPendingNodes() {
|
|
1015
1039
|
for (let e = 0; e < pendingNodes.length; e++) {
|
|
1016
|
-
const
|
|
1040
|
+
const o = pendingNodes[e];
|
|
1017
1041
|
// A node a lane pass re-staged this round is the lane's to reveal; one
|
|
1018
1042
|
// a transaction holds (born held by a mainline pass, `passTx`) is that
|
|
1019
1043
|
// transaction's to commit, at its landing.
|
|
1020
|
-
if (!(
|
|
1044
|
+
if (!(o.l & (CONFIG_OVERRIDE | CONFIG_HELD))) commitPendingNode(o);
|
|
1021
1045
|
}
|
|
1022
1046
|
pendingNodes.length = 0;
|
|
1023
1047
|
}
|
|
@@ -1049,24 +1073,27 @@ function flush(e) {
|
|
|
1049
1073
|
// Attribution: whether this call drained anything, so `flushEnd` fires once
|
|
1050
1074
|
// per real drain and never for a no-op call. The declaration is dead in
|
|
1051
1075
|
// prod (its only write is behind true) and rollup drops it.
|
|
1052
|
-
let
|
|
1076
|
+
let o = false;
|
|
1053
1077
|
// The drain's opening instant, under the loop's own condition so it fires
|
|
1054
1078
|
// exactly when `flushEnd` below will. Outside every try (see the rule in
|
|
1055
1079
|
// attribution-hooks.ts).
|
|
1056
1080
|
if (attrHooks !== null && scheduled) attrHooks.flushStart();
|
|
1057
1081
|
while (scheduled) {
|
|
1058
1082
|
globalQueue.flush();
|
|
1059
|
-
|
|
1083
|
+
o = true;
|
|
1060
1084
|
}
|
|
1061
1085
|
// Outside every try in this function (see the rule in attribution-hooks.ts):
|
|
1062
1086
|
// the drain loop above is the one place all scheduled work funnels through,
|
|
1063
1087
|
// so this is the "committed and effects ran" instant for everything the
|
|
1064
1088
|
// loop processed.
|
|
1065
|
-
if (
|
|
1089
|
+
if (o && attrHooks !== null) attrHooks.flushEnd();
|
|
1090
|
+
// A cleanup that threw during the drain, now that the drain is complete
|
|
1091
|
+
// (owner.ts).
|
|
1092
|
+
rethrowCleanupError();
|
|
1066
1093
|
}
|
|
1067
1094
|
|
|
1068
|
-
function runQueue(e,
|
|
1069
|
-
for (let
|
|
1095
|
+
function runQueue(e, o) {
|
|
1096
|
+
for (let n = 0; n < e.length; n++) e[n](o);
|
|
1070
1097
|
}
|
|
1071
1098
|
|
|
1072
|
-
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, blockersOf, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, 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, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|
|
1099
|
+
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, blockersOf, 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, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|