@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,6 +1,6 @@
|
|
|
1
1
|
import { notifyStatus, releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, stageError, settlePendingSource, releaseIfSettledUnobserved, settleErroredDependents } from "./async.js";
|
|
2
2
|
|
|
3
|
-
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_PLUMBING, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED,
|
|
3
|
+
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_PLUMBING, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, CONFIG_STAGED_ERROR, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_ASYNC, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED, REACTIVE_ZOMBIE, REACTIVE_MISSED_WAKE, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_PROBED, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_SCREEN_READ, REACTIVE_PROBE_UNANSWERED, CAUGHT_REARMED, CONFIG_PROMOTED, CONFIG_INPUTS_PUBLISHED, CONFIG_FRESH_READ, REACTIVE_IN_HEAP_HEIGHT, CONFIG_SLOT_NODE, EFFECT_USER, NewSet, STATUS_NONE } from "./constants.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ import { attrHooks } from "./attribution-hooks.js";
|
|
|
14
14
|
|
|
15
15
|
import { inheritId, linkChild, disposeChildren, markDisposal } from "./owner.js";
|
|
16
16
|
|
|
17
|
-
import { schedule, externalUntrackHook, clock, txOf, flushTransaction, laneWriteHook, joinFuture, queuePendingNode, globalQueue, notifyEpoch, insertSubs, dirtyQueue, observeFlightHook, laneStageHook, passLane, laneReadHook, wireExternalSourceHook, bumpNotifyEpoch, setPassLane, joinPassTx, freshHook, GlobalQueue, laneOutcomeHook, passTx, holdNode, laneDirty, heldTrim, staleReader,
|
|
17
|
+
import { schedule, externalUntrackHook, clock, txOf, flushTransaction, laneWriteHook, joinFuture, queuePendingNode, globalQueue, notifyEpoch, insertSubs, dirtyQueue, observeFlightHook, laneStageHook, passLane, laneReadHook, wireExternalSourceHook, bumpNotifyEpoch, setPassLane, joinPassTx, freshHook, guessing, holdWorkHook, GlobalQueue, laneOutcomeHook, passTx, holdNode, laneDirty, heldTrim, staleReader, laneServedHook, latestOpened, stagedReaders, laneSeamsHook, deferZombie } from "./scheduler.js";
|
|
18
18
|
|
|
19
19
|
// The heap's per-node step. A tracked effect's heap visit is its compute
|
|
20
20
|
// phase — empty, like a user effect whose compute reads nothing — and hands
|
|
@@ -120,7 +120,7 @@ function releaseSubtree(e) {
|
|
|
120
120
|
if (e.R & REACTIVE_SNAPSHOT_STALE) {
|
|
121
121
|
e.R &= ~REACTIVE_SNAPSHOT_STALE;
|
|
122
122
|
e.R |= REACTIVE_DIRTY;
|
|
123
|
-
if (dirtyQueue.
|
|
123
|
+
if (dirtyQueue.Et > e.lt) dirtyQueue.Et = e.lt;
|
|
124
124
|
insertIntoHeap(e, dirtyQueue);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -165,14 +165,15 @@ function recompute(e, t = false) {
|
|
|
165
165
|
// Restored at the end, after this pass's staging and runs have been
|
|
166
166
|
// routed.
|
|
167
167
|
// Lanes exist only with the lane engine installed (`laneStageHook`): a
|
|
168
|
-
// bundle without it seats every pass on mainline
|
|
168
|
+
// bundle without it seats every pass on mainline (`passLane` is never set)
|
|
169
|
+
// and folds the seat, and its restores, away.
|
|
169
170
|
const s = passLane;
|
|
170
171
|
// The mount a first pass belongs to: its creator's lane, or the one its
|
|
171
172
|
// creator's own mount came from — a render effect a verdict lane's mount's
|
|
172
173
|
// content creates is that mount's too (#4166). Lanes only, like the seat.
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
|
|
174
|
+
const E = laneRoot;
|
|
175
|
+
const l = laneStageHook && (laneRoot = t && (s || E));
|
|
176
|
+
if (laneStageHook) setPassLane((e.R & REACTIVE_LANE_DIRTY || (e.l & (CONFIG_OVERRIDE | CONFIG_GUESS)) === CONFIG_OVERRIDE) && e.T?.Je?.V ? e.T.Je : // Loose `!=`: false with no creator lane (undefined == null).
|
|
176
177
|
t && s?._parent.it != s && creatorPass(context)?.R & REACTIVE_RECOMPUTING_DEPS ? s : null);
|
|
177
178
|
// Attribution hook: fired before this run touches the dep list — `_deps`
|
|
178
179
|
// still holds the previous run's links (the subscriptions that could have
|
|
@@ -184,9 +185,29 @@ function recompute(e, t = false) {
|
|
|
184
185
|
}
|
|
185
186
|
// CARVE 2: lane posture resolution (OPTIMISTIC_DIRTY, derived-override
|
|
186
187
|
// re-derivation, lane adoption through deps) went with the optimistic engine.
|
|
187
|
-
|
|
188
|
+
// An error a pass staged, which this pass replaces (`valueChanged`).
|
|
189
|
+
const r = e.l & CONFIG_STAGED_ERROR;
|
|
190
|
+
if (!t) {
|
|
188
191
|
deleteFromHeap(e, dirtyQueue);
|
|
192
|
+
// A pending flight is the transition's own work (#3884), and so is a
|
|
193
|
+
// held async memo's re-run with no verdict window of its own (D-25,
|
|
194
|
+
// `holdWork`): a pass that takes no verdict role this time. A probe on
|
|
195
|
+
// an earlier pass left CONFIG_VERDICT, and a frame read here would serve
|
|
196
|
+
// the committed screen, settle the flight and drop the hold — a
|
|
197
|
+
// superseding write's verdict would depend on that probe. Cleared for
|
|
198
|
+
// this pass, before the flight it judges by is superseded; a probe in
|
|
199
|
+
// the body re-stamps it after the plain reads. Not an effect: it has no
|
|
200
|
+
// flight of its own (its pending is a source's), and a verdict memo's
|
|
201
|
+
// change may have just made it a verdict reader (`laneDirty`). Only a
|
|
202
|
+
// build with the lane engine (`laneStageHook`; verdict.ts imports it)
|
|
203
|
+
// ever sets CONFIG_VERDICT: without it the line folds away.
|
|
204
|
+
if (laneStageHook && !n && (e.m & STATUS_PENDING || (e.l & (CONFIG_ASYNC | CONFIG_HELD)) === (CONFIG_ASYNC | CONFIG_HELD))) e.l &= ~CONFIG_VERDICT;
|
|
189
205
|
if (e.T !== null) {
|
|
206
|
+
// The seam's re-derive runs with the parked flight still current; any
|
|
207
|
+
// later pass asks its own question (`_parked`; only the lane engine
|
|
208
|
+
// parks one).
|
|
209
|
+
const t = laneStageHook && e.T.rt;
|
|
210
|
+
if (t && t !== e.T.Ee) e.T.rt = undefined;
|
|
190
211
|
e.T.Ee = null;
|
|
191
212
|
// Supersede is where an iterator flight dies (#3122): close it now.
|
|
192
213
|
// Idempotent with the cleanup-channel close.
|
|
@@ -205,13 +226,7 @@ function recompute(e, t = false) {
|
|
|
205
226
|
// A).
|
|
206
227
|
// A boundary's structure (CONFIG_FRAME) is the frame like a render
|
|
207
228
|
// effect: it publishes mainline outside its transaction's flush (#4283).
|
|
208
|
-
|
|
209
|
-
// earlier pass left CONFIG_VERDICT, and a frame read here would serve the
|
|
210
|
-
// committed screen, settle the flight and drop the hold — a superseding
|
|
211
|
-
// write's verdict would depend on that probe. Cleared for this pass; a
|
|
212
|
-
// probe in the body re-stamps it after the plain reads.
|
|
213
|
-
if (e.m & STATUS_PENDING) e.l &= ~CONFIG_VERDICT;
|
|
214
|
-
if (e.l & CONFIG_HELD) {
|
|
229
|
+
if (e.l & CONFIG_HELD) {
|
|
215
230
|
const t = txOf(e);
|
|
216
231
|
// Held by a blocked lane: the frame joins nothing — a lane never holds
|
|
217
232
|
// a sync write (#3460). The pass is the lane's if it reads the lane's
|
|
@@ -228,8 +243,12 @@ function recompute(e, t = false) {
|
|
|
228
243
|
// children die below (`disposeChildren`). The landing re-derives a
|
|
229
244
|
// fresh held frame for the reveal (`_reruns`).
|
|
230
245
|
// Not held any more, whichever frame reader it is: its readers read
|
|
231
|
-
// the value this pass publishes
|
|
232
|
-
|
|
246
|
+
// the value this pass publishes — those that read the staging it
|
|
247
|
+
// supersedes re-derive, even when it publishes the committed value
|
|
248
|
+
// back (no change to notify them by): their held runs carry the
|
|
249
|
+
// superseded frame, and the landing would apply them (#4378).
|
|
250
|
+
if (e.ue !== NOT_PENDING) insertSubs(e);
|
|
251
|
+
e.ue = NOT_PENDING;
|
|
233
252
|
e.l &= ~CONFIG_HELD;
|
|
234
253
|
}
|
|
235
254
|
}
|
|
@@ -247,35 +266,37 @@ function recompute(e, t = false) {
|
|
|
247
266
|
deferReleases(o = []);
|
|
248
267
|
disposeChildren(e);
|
|
249
268
|
deferReleases(t);
|
|
250
|
-
} else if (e.ze !== null || e.
|
|
269
|
+
} else if (e.ze !== null || e._t !== null) parkChildren(e);
|
|
251
270
|
// An error a pass staged (D-41) is replaced by this pass's answer: a
|
|
252
271
|
// value, a flight, or an error of its own (#4109, #4145).
|
|
253
272
|
if (e.l & CONFIG_STAGED_ERROR) {
|
|
254
|
-
e.
|
|
273
|
+
e.ue = NOT_PENDING;
|
|
255
274
|
e.l ^= CONFIG_STAGED_ERROR;
|
|
256
275
|
}
|
|
257
276
|
}
|
|
258
|
-
const
|
|
277
|
+
const a = !!(e.m & STATUS_UNINITIALIZED);
|
|
259
278
|
// Capture both error and pending status before the compute clears them.
|
|
260
279
|
// A conditional can drop its pending source and recover to an unchanged
|
|
261
280
|
// value, leaving blocked dependents outside that source’s settle walk.
|
|
262
|
-
const
|
|
281
|
+
const _ = e.m & STATUS_ERROR && e.T?.U;
|
|
263
282
|
const u = (e.m & STATUS_PENDING) !== 0;
|
|
264
|
-
const
|
|
283
|
+
const I = u && e.T?.se;
|
|
265
284
|
// Pending SOURCE-hood, captured before the compute clears status: a node
|
|
266
285
|
// whose own flight parked dependents self-registers in _pendingSources
|
|
267
286
|
// (notifyStatus, isSource). If this recompute supersedes that flight and
|
|
268
287
|
// settles synchronously, those dependents settle HERE — asyncWrite's
|
|
269
288
|
// settlePendingSource walk never runs for a landing that was preempted
|
|
270
289
|
// (#3181).
|
|
271
|
-
const
|
|
290
|
+
const N = e.T?.se?.has(e);
|
|
272
291
|
// D-41: this pass's error is staged, not published (`stageError`).
|
|
273
292
|
let f = false;
|
|
274
293
|
// A19 exc. 2: a `refresh()` re-asks the question already answered — quiet
|
|
275
294
|
// for the verdict — unless the question in flight is a new one, which the
|
|
276
295
|
// re-ask does not launder (a poll during a quiet confirm stays quiet).
|
|
277
|
-
|
|
278
|
-
|
|
296
|
+
// Nor a guess's new question whose answer is still held (#4336: an
|
|
297
|
+
// action's refresh after an outside input change has not committed it).
|
|
298
|
+
const T = (e.R & REACTIVE_REASK) !== 0 && !((e.m & STATUS_PENDING || guessing && e.ue !== NOT_PENDING) && e.T !== null && !e.T.ut);
|
|
299
|
+
const S = context;
|
|
279
300
|
context = e;
|
|
280
301
|
e._ = null;
|
|
281
302
|
e.Ne++;
|
|
@@ -284,20 +305,20 @@ function recompute(e, t = false) {
|
|
|
284
305
|
// live writes until the commit that disposes it, so every per-pass wipe
|
|
285
306
|
// — here, the finally below, updateIfNecessary — carries it (#3543).
|
|
286
307
|
e.R = REACTIVE_RECOMPUTING_DEPS | e.R & (REACTIVE_ZOMBIE | REACTIVE_REASK);
|
|
287
|
-
e.
|
|
308
|
+
e.ie = clock;
|
|
288
309
|
// The pass's previous value: its staging, else a lane node's lane value
|
|
289
310
|
// when it has one (lanes.ts), else the committed one.
|
|
290
|
-
let
|
|
291
|
-
let
|
|
292
|
-
let
|
|
311
|
+
let c = e.ue !== NOT_PENDING ? e.ue : e.l & CONFIG_OVERRIDE && e.T.V !== NOT_PENDING ? e.T.V : e.le;
|
|
312
|
+
let A = e.lt;
|
|
313
|
+
let R = false;
|
|
293
314
|
// L2: did this pass read the future (REACTIVE_JOINED, set by read) — or,
|
|
294
315
|
// a lane's mount, a staging of this flush (#3851, #4166)?
|
|
295
|
-
let
|
|
296
|
-
let
|
|
316
|
+
let C = false;
|
|
317
|
+
let O = tracking;
|
|
297
318
|
tracking = true;
|
|
298
319
|
try {
|
|
299
320
|
if (!false && e.l & CONFIG_SYNC) {
|
|
300
|
-
|
|
321
|
+
c = e.X(c);
|
|
301
322
|
if (e.T !== null) e.T.Ee = null;
|
|
302
323
|
e.ce = false;
|
|
303
324
|
} else {
|
|
@@ -305,12 +326,15 @@ function recompute(e, t = false) {
|
|
|
305
326
|
// (with the commit as setter): its undefined return is not a sync
|
|
306
327
|
// answer, and the outer handleAsync must not clobber the registration.
|
|
307
328
|
const t = e.T?.Ee;
|
|
308
|
-
const n = e.X(
|
|
329
|
+
const n = e.X(c);
|
|
309
330
|
const o = typeof n === "object" && n !== null;
|
|
310
331
|
const s = e.T?.Ee !== t;
|
|
311
|
-
|
|
332
|
+
c = s || !o ? n : handleAsync(e, n);
|
|
312
333
|
if (!s && !o) {
|
|
313
|
-
if (e.T !== null)
|
|
334
|
+
if (e.T !== null) {
|
|
335
|
+
e.T.Ee = null;
|
|
336
|
+
if (holdWorkHook) e.l &= ~CONFIG_ASYNC;
|
|
337
|
+
}
|
|
314
338
|
// A sync (non-object) return is the first real answer; async-shaped
|
|
315
339
|
// results clear inside handleAsync at their own landing points, and a
|
|
316
340
|
// self-registered flight clears when its own handleAsync lands.
|
|
@@ -324,6 +348,10 @@ function recompute(e, t = false) {
|
|
|
324
348
|
if (e.m !== 0 || e.T !== null) clearStatus(e, t);
|
|
325
349
|
} catch (t) {
|
|
326
350
|
const n = t instanceof NotReadyError;
|
|
351
|
+
// An error answers, and so does a loading window's unready read (D-25,
|
|
352
|
+
// verdict.ts `holdWork`): no flight is its own. A pass left pending
|
|
353
|
+
// keeps the last answer's. (Kept by the verdict engine alone.)
|
|
354
|
+
if (holdWorkHook && (!n || e.ce)) e.l &= ~CONFIG_ASYNC;
|
|
327
355
|
if (n && e.ce) {
|
|
328
356
|
// Loading window with an unready sync dependency: register for the
|
|
329
357
|
// source's settle (the settlePendingSource walk runs off
|
|
@@ -341,7 +369,7 @@ function recompute(e, t = false) {
|
|
|
341
369
|
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t);
|
|
342
370
|
// The replacement source is fully propagated now. If no new flight
|
|
343
371
|
// re-owned self, retire the superseded flight and its dependent copies.
|
|
344
|
-
if (n &&
|
|
372
|
+
if (n && N && !e.T?.Ee) settlePendingSource(e);
|
|
345
373
|
}
|
|
346
374
|
// A re-park drops what the earlier pass carried (#3456): a source this
|
|
347
375
|
// pass no longer reaches — its branch switched, or a fresh flight
|
|
@@ -352,25 +380,29 @@ function recompute(e, t = false) {
|
|
|
352
380
|
// re-park twin of the unchanged-value recovery sweep below; dependents
|
|
353
381
|
// with another path keep the source (retryReaches). A staged error
|
|
354
382
|
// answered what the pass carried: the same.
|
|
355
|
-
if ((n || f) &&
|
|
383
|
+
if ((n || f) && I) for (const t of I) if (t !== e && !e.T?.se?.has(t)) settlePendingSource(e, t);
|
|
356
384
|
}
|
|
357
385
|
} finally {
|
|
358
|
-
tracking =
|
|
359
|
-
if (laneStageHook) laneRoot =
|
|
386
|
+
tracking = O;
|
|
387
|
+
if (laneStageHook) laneRoot = E;
|
|
360
388
|
// Consume the missed-wake latch (#3037, set by insertSubs): a dep write
|
|
361
389
|
// landed beneath this pass on a link it had already validated. The wipe
|
|
362
390
|
// below must not key off DIRTY/CHECK — the read-time pull protocol
|
|
363
391
|
// (markNode(c) in read()) marks the running node as part of ordinary
|
|
364
392
|
// bookkeeping, and those marks are correctly discarded here.
|
|
365
|
-
|
|
393
|
+
R = (e.R & REACTIVE_MISSED_WAKE) !== 0;
|
|
366
394
|
// A mount's staged read joins it — except a nested derivation left
|
|
367
395
|
// pending: no render effect reaches it yet, so it holds nothing and
|
|
368
|
-
// reaches no boundary (Reader, #4203)
|
|
369
|
-
|
|
396
|
+
// reaches no boundary (Reader, #4203), whatever it read — a memo the
|
|
397
|
+
// mount bore held over the staging included, at any depth (#4340). A
|
|
398
|
+
// reader that does is caught.
|
|
399
|
+
C = !!(e.R & (l ? s || n || !(e.m & STATUS_PENDING) ? REACTIVE_JOINED | REACTIVE_STAGED_READ : 0 : REACTIVE_JOINED));
|
|
370
400
|
// A verdict reader is one for as long as it probes, or reads a memo
|
|
371
401
|
// that does (`read`): a pass that did neither (REACTIVE_PROBED, the same
|
|
372
|
-
// bit) is an ordinary derivation again.
|
|
373
|
-
|
|
402
|
+
// bit) is an ordinary derivation again. Its async posture is the
|
|
403
|
+
// verdict engine's to keep (CONFIG_ASYNC, verdict.ts `holdWork`, D-25).
|
|
404
|
+
// (Only the verdict engine probes: without it the line folds away.)
|
|
405
|
+
if (observeFlightHook) e.l = e.l & ~CONFIG_VERDICT | e.R & REACTIVE_PROBED;
|
|
374
406
|
// REACTIVE_DISPOSED survives too (#3621): the pass may have disposed its
|
|
375
407
|
// own owner (a memo calling its root's `dispose()`, a cleanup doing so
|
|
376
408
|
// #3601/#3606), and `disposeChildren` set the flag on this node
|
|
@@ -379,12 +411,12 @@ function recompute(e, t = false) {
|
|
|
379
411
|
// this pass's verdict for the landing; the next pass's wipe at the top
|
|
380
412
|
// clears it.
|
|
381
413
|
e.R = e.R & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED | REACTIVE_FRAME_READ | REACTIVE_STAGED_READ | REACTIVE_LANE_READ | REACTIVE_SCREEN_READ | REACTIVE_PROBE_UNANSWERED) | (t ? e.R & REACTIVE_SNAPSHOT_STALE : 0);
|
|
382
|
-
context =
|
|
414
|
+
context = S;
|
|
383
415
|
if (o) for (const e of o) releaseIfSettledUnobserved(e);
|
|
384
416
|
// A19 exc. 2: a pass that went pending on a `refresh()` re-asks the
|
|
385
417
|
// question already answered — quiet for the verdict; any other pending
|
|
386
418
|
// pass is a new question. Settled, there is nothing to classify.
|
|
387
|
-
if (e.T !== null) e.T.ut =
|
|
419
|
+
if (e.T !== null) e.T.ut = T && (e.m & STATUS_PENDING) !== 0;
|
|
388
420
|
}
|
|
389
421
|
// A node that died during its own pass (#3621) is dead at the end of it,
|
|
390
422
|
// and the pass is void. Its owner's teardown already unlinked its deps,
|
|
@@ -401,7 +433,7 @@ function recompute(e, t = false) {
|
|
|
401
433
|
clearDeps(e);
|
|
402
434
|
if (e.T !== null) e.T.Ee = null;
|
|
403
435
|
if (attrHooks !== null) attrHooks.recomputeEnd(e, t, false, false, false, false);
|
|
404
|
-
setPassLane(s);
|
|
436
|
+
if (laneStageHook) setPassLane(s);
|
|
405
437
|
return;
|
|
406
438
|
}
|
|
407
439
|
// The lane this pass is work of, if any: its seat (the node's, its
|
|
@@ -412,11 +444,11 @@ function recompute(e, t = false) {
|
|
|
412
444
|
let d = !laneStageHook ? null : passLane;
|
|
413
445
|
// Listed before its staging, a pending pass included (the lane's own
|
|
414
446
|
// flight is the lane's); false: the pass left the lane (lanes.ts).
|
|
415
|
-
const
|
|
447
|
+
const D = !!e.T?.U || f;
|
|
416
448
|
if (laneStageHook && d !== null) {
|
|
417
|
-
if (laneStageHook(e, d, t,
|
|
449
|
+
if (laneStageHook(e, d, t, D)) setPassLane(d); else d = null;
|
|
418
450
|
}
|
|
419
|
-
if (!
|
|
451
|
+
if (!D) {
|
|
420
452
|
// Observe-tier fan-in (HUGE_FAN_IN): the validated prefix [_deps.._depsTail]
|
|
421
453
|
// IS this pass's distinct sources — count it here rather than per link. A
|
|
422
454
|
// begin/end bracket around the pass plus a per-link increment measured
|
|
@@ -437,13 +469,17 @@ function recompute(e, t = false) {
|
|
|
437
469
|
// publishes to — the staged `_pendingValue` when staged; a lane node's
|
|
438
470
|
// lane value (a node entering the lane this pass has none yet — its
|
|
439
471
|
// committed value, `laneStage` having voided a frame staging).
|
|
440
|
-
const o = e.
|
|
472
|
+
const o = e.ue !== NOT_PENDING ? e.ue : e.l & CONFIG_OVERRIDE && e.T.V !== NOT_PENDING ? e.T.V : e.le;
|
|
441
473
|
// A throwing comparator is contained inside `isSame` (A3, #2837; #4111).
|
|
442
|
-
|
|
474
|
+
// A pass replacing an error this node staged is a new answer, even the
|
|
475
|
+
// committed value (D-41: a recovery equal to the last good value is a
|
|
476
|
+
// change): the slot it publishes to held the error, and the readers that
|
|
477
|
+
// derived from it — `latest()` throws it — re-derive (#4403).
|
|
478
|
+
const s = !n && a || !!e.T?.Te || !!r || !isSame(e, o, c);
|
|
443
479
|
// A committed derived change becomes a cause for this node's subscribers,
|
|
444
480
|
// chaining their attribution through this node to the root write.
|
|
445
481
|
if (attrHooks !== null) {
|
|
446
|
-
i = s && !e.T?.
|
|
482
|
+
i = s && !e.T?.U;
|
|
447
483
|
if (i && !n && !t) attrHooks.derivedChanged(e);
|
|
448
484
|
}
|
|
449
485
|
// Effects use `_equals: false` (no per-effect closure). The side effects that
|
|
@@ -454,16 +490,16 @@ function recompute(e, t = false) {
|
|
|
454
490
|
if (n && s &&
|
|
455
491
|
// A stale reader of a lane (REACTIVE_SCREEN_READ) that computed what it
|
|
456
492
|
// last applied owes no run (lanes.ts).
|
|
457
|
-
!(e.R & REACTIVE_SCREEN_READ && !e.Qe && Object.is(e.
|
|
493
|
+
!(e.R & REACTIVE_SCREEN_READ && !e.Qe && Object.is(e.It, c)) &&
|
|
458
494
|
// A re-staging pass owes no run: the commit replays the effect (#3802).
|
|
459
|
-
e.
|
|
460
|
-
e.Qe = !e.T?.
|
|
495
|
+
e.ue === NOT_PENDING) {
|
|
496
|
+
e.Qe = !e.T?.U;
|
|
461
497
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
462
498
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
463
499
|
// Lane work's run is the lane's (released at its reveal) — a first
|
|
464
500
|
// pass under a lane too: `effect()` skips the synchronous first run of
|
|
465
501
|
// a lane's node.
|
|
466
|
-
if (!t || d !== null) globalQueue.enqueue(n, e.W ??= GlobalQueue.
|
|
502
|
+
if (!t || d !== null) globalQueue.enqueue(n, e.W ??= GlobalQueue.q.bind(null, e), d);
|
|
467
503
|
}
|
|
468
504
|
// Lanes. A written guess's own pass from the frame: its source
|
|
469
505
|
// recomputed it — the truth (A18: "the source is whatever recomputes the
|
|
@@ -472,7 +508,7 @@ function recompute(e, t = false) {
|
|
|
472
508
|
// only a correction: an equal truth re-runs nothing (lanes.ts). (As the
|
|
473
509
|
// lane's own work the lane judged it — `laneStage`.)
|
|
474
510
|
// (The hook first: a build without lanes folds the arm away.)
|
|
475
|
-
if (laneOutcomeHook && !t && d === null && e.l & CONFIG_GUESS && laneOutcomeHook(e,
|
|
511
|
+
if (laneOutcomeHook && !t && d === null && e.l & CONFIG_GUESS && laneOutcomeHook(e, c, D)) ; else if (D) ; else if (s) {
|
|
476
512
|
// L2: a first pass is born held — staged, committed with the
|
|
477
513
|
// transaction, its effect's first run the landing's (A29; `effect()`
|
|
478
514
|
// skips the synchronous first run on a staged value) — when the flush
|
|
@@ -496,8 +532,8 @@ function recompute(e, t = false) {
|
|
|
496
532
|
// effect's value slot is private: the run the lane holds is what
|
|
497
533
|
// shows it — unless the effect was born held, whose first run is the
|
|
498
534
|
// commit's (A29): it re-stages, as below.
|
|
499
|
-
if (n && e.
|
|
500
|
-
} else if (t ? !((flushTransaction !== null || passTx !== null) && (
|
|
535
|
+
if (n && e.ue === NOT_PENDING) e.le = c; else if (n || d.Nt) e.ue = c; else e.T.V = c;
|
|
536
|
+
} else if (t ? !((flushTransaction !== null || passTx !== null) && (C || creatorPass(S)?.R & REACTIVE_JOINED)) : n && e.ue === NOT_PENDING) {
|
|
501
537
|
// A first pass publishes directly. So does an effect: its value slot
|
|
502
538
|
// is private (only its own run reads it), and the staging round-trip
|
|
503
539
|
// (queuePendingNode + commitPendingNodes) paid per effect on the
|
|
@@ -508,9 +544,13 @@ function recompute(e, t = false) {
|
|
|
508
544
|
// sources commit) must see the fresh value while PLAIN reads stay
|
|
509
545
|
// committed until flush (#3009 purity). The pending round-trip is
|
|
510
546
|
// that separation; it cannot be skipped on any path a pull can reach.
|
|
511
|
-
e.le =
|
|
547
|
+
e.le = c;
|
|
512
548
|
} else {
|
|
513
|
-
e.
|
|
549
|
+
e.ue = c;
|
|
550
|
+
// D-39: a staged recovery keeps the error it replaces the display
|
|
551
|
+
// until it commits (`commitPendingNode`), as a write over one does
|
|
552
|
+
// (`setMemo`).
|
|
553
|
+
if (_) e.T.Te = _;
|
|
514
554
|
// Born held: in the transaction from birth, so a read of it this
|
|
515
555
|
// tick is a read of its world (the mount-during-a-hold case), not
|
|
516
556
|
// only after the seam parks it.
|
|
@@ -528,7 +568,7 @@ function recompute(e, t = false) {
|
|
|
528
568
|
// #3851): the mount is part of the hold, and the boundary appears
|
|
529
569
|
// at its commit, its fallback never seen (D-13, U-3) — a `<Show>`
|
|
530
570
|
// mounting it over a landing included.
|
|
531
|
-
freshHook?.(e, !
|
|
571
|
+
freshHook?.(e, !l && flushTransaction);
|
|
532
572
|
}
|
|
533
573
|
}
|
|
534
574
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
@@ -538,7 +578,7 @@ function recompute(e, t = false) {
|
|
|
538
578
|
// Lane work re-staged: the lane's members re-derive as its work.
|
|
539
579
|
if (d !== null) laneDirty(e, d);
|
|
540
580
|
}
|
|
541
|
-
} else if (e.
|
|
581
|
+
} else if (e.lt != A) {
|
|
542
582
|
for (let t = e.o; t !== null; t = t.t) insertIntoHeapHeight(t.u, dirtyQueue);
|
|
543
583
|
}
|
|
544
584
|
// Silent recovery: errored → unchanged value fires no notification, but
|
|
@@ -546,16 +586,16 @@ function recompute(e, t = false) {
|
|
|
546
586
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
547
587
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
548
588
|
// (el._x?._error re-set), so this only runs on a genuinely clean recovery.
|
|
549
|
-
if (!s && !e.T?.
|
|
550
|
-
if (
|
|
589
|
+
if (!s && !e.T?.U) {
|
|
590
|
+
if (_) settleErroredDependents(e, _);
|
|
551
591
|
// Self-registration (this node's own superseded flight) is the #3181
|
|
552
592
|
// sweep's business below — retiring it here too would walk twice.
|
|
553
|
-
if (
|
|
593
|
+
if (I) for (const t of I) if (t !== e) settlePendingSource(e, t);
|
|
554
594
|
}
|
|
555
595
|
// #3181: a synchronous settle supersedes the old landing callback, so
|
|
556
596
|
// recompute owns its pending-source sweep. An uninitialized node without
|
|
557
597
|
// a replacement source still has no truth to reveal and must stay parked.
|
|
558
|
-
if (
|
|
598
|
+
if (N && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
|
|
559
599
|
}
|
|
560
600
|
// A first pass that went pending where the born-held arm would have held
|
|
561
601
|
// its value (it read a held node, or a verdict lane's mount read a staging,
|
|
@@ -565,7 +605,7 @@ function recompute(e, t = false) {
|
|
|
565
605
|
// hold's commit (D-12) — but the hold does not wait for it: its only
|
|
566
606
|
// readers are behind the fallback (`_hidden`; F-4, #3540). A boundary
|
|
567
607
|
// re-armed by `on` owns what it collects outright (D-14): not held.
|
|
568
|
-
if (t && d === null &&
|
|
608
|
+
if (t && d === null && C && e.m & STATUS_PENDING) {
|
|
569
609
|
const t = flushTransaction ?? passTx;
|
|
570
610
|
if (t && !t.V && freshHook?.(e) !== CAUGHT_REARMED) holdNode(e, t);
|
|
571
611
|
}
|
|
@@ -586,29 +626,29 @@ function recompute(e, t = false) {
|
|
|
586
626
|
// kept at a park — one spurious recompute at most). A creation pass and a
|
|
587
627
|
// tracked effect trim now: their frames are replaceable like a direct
|
|
588
628
|
// commit, and a tracked effect's spurious run would be user-visible.
|
|
589
|
-
if (!e.T?.
|
|
629
|
+
if (!e.T?.U && e.ue === NOT_PENDING && !(n && e.Qe)) {
|
|
590
630
|
if (t || n === EFFECT_TRACKED) trimStaleDeps(e); else heldTrim(e);
|
|
591
631
|
}
|
|
592
632
|
// Observe: the posture the run executed under — lane work (optimistic:
|
|
593
633
|
// overlay, never waste), a transaction's pass (held), or plain.
|
|
594
|
-
if (attrHooks !== null) attrHooks.recomputeEnd(e, t, i, d !== null, flushTransaction !== null || passTx !== null || (e.l & CONFIG_HELD) !== 0, e.
|
|
634
|
+
if (attrHooks !== null) attrHooks.recomputeEnd(e, t, i, d !== null, flushTransaction !== null || passTx !== null || (e.l & CONFIG_HELD) !== 0, e.ue !== NOT_PENDING);
|
|
595
635
|
// A staged value, a parked frame (L2: the commit retires it), or status the
|
|
596
636
|
// commit sweep must settle (a pending or uninitialized pass), queues the
|
|
597
637
|
// node for this flush's commit. A first pass queues only when pending or
|
|
598
638
|
// born held: otherwise its value published directly. A queued pass's
|
|
599
639
|
// children are uncommitted (CONFIG_STAGED) until that commit.
|
|
600
|
-
if (e.
|
|
640
|
+
if (e.ue !== NOT_PENDING || e.T !== null && (e.T.ft !== null || e.T.Tt !== null) || (e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0 && (!t || (e.m & STATUS_PENDING) !== 0)) {
|
|
601
641
|
e.l |= CONFIG_STAGED;
|
|
602
642
|
// Lane work is the lane's to reveal (its seam), not this flush's commit.
|
|
603
643
|
if (d === null) queuePendingNode(e);
|
|
604
644
|
}
|
|
605
|
-
setPassLane(s);
|
|
645
|
+
if (laneStageHook) setPassLane(s);
|
|
606
646
|
// Missed-wake reschedule (see the finally above): values this pass read
|
|
607
647
|
// before the nested commit are stale, so run again now that the heap will
|
|
608
648
|
// accept the node. Equality gates stop same-value landings from cascading,
|
|
609
649
|
// and a re-run only latches again if another nested commit changes a dep
|
|
610
650
|
// beneath it — convergent unless deps genuinely keep changing.
|
|
611
|
-
if (
|
|
651
|
+
if (R) {
|
|
612
652
|
enqueueSub(e);
|
|
613
653
|
schedule();
|
|
614
654
|
}
|
|
@@ -633,7 +673,7 @@ function updateIfNecessary(e) {
|
|
|
633
673
|
}
|
|
634
674
|
}
|
|
635
675
|
}
|
|
636
|
-
if (e.R & REACTIVE_DIRTY || e.T?.
|
|
676
|
+
if (e.R & REACTIVE_DIRTY || e.T?.U && e.ie < clock && !e.T?.Ee) {
|
|
637
677
|
recompute(e);
|
|
638
678
|
}
|
|
639
679
|
// The guard above refused an already-disposed node; the recompute it just
|
|
@@ -663,44 +703,44 @@ function computed(e, t) {
|
|
|
663
703
|
// plus the slots.
|
|
664
704
|
const s = {
|
|
665
705
|
id: inheritId(t, n, context),
|
|
666
|
-
l: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.
|
|
706
|
+
l: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.ae ? CONFIG_NO_SNAPSHOT : 0) | (
|
|
667
707
|
// Plumbing is an observe-tier notion (a name and records to
|
|
668
708
|
// withhold); the prod literal never carries the bit.
|
|
669
|
-
t?.
|
|
709
|
+
t?.St ? CONFIG_PLUMBING : 0) | (t?.ct ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
670
710
|
je: t?.equals ?? isEqual,
|
|
671
|
-
|
|
711
|
+
_t: null,
|
|
672
712
|
A: context?.A ?? defaultContext,
|
|
673
|
-
|
|
713
|
+
At: 0,
|
|
674
714
|
X: e,
|
|
675
715
|
le: o ? t.loadingValue : undefined,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
716
|
+
lt: 0,
|
|
717
|
+
Rt: undefined,
|
|
718
|
+
Ct: null,
|
|
679
719
|
C: null,
|
|
680
720
|
_: null,
|
|
681
721
|
Ne: 0,
|
|
682
722
|
o: null,
|
|
683
|
-
|
|
723
|
+
Ot: null,
|
|
684
724
|
_parent: context,
|
|
685
725
|
Xe: null,
|
|
686
726
|
dt: null,
|
|
687
727
|
ze: null,
|
|
688
728
|
R: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
689
729
|
m: o ? 0 : STATUS_UNINITIALIZED,
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
730
|
+
ie: clock,
|
|
731
|
+
ue: NOT_PENDING,
|
|
732
|
+
Dt: -1,
|
|
693
733
|
ce: o,
|
|
694
734
|
T: null,
|
|
695
735
|
// The slot is always present (hidden class); plumbing leaves it
|
|
696
736
|
// unset, which `ownerPath` skips.
|
|
697
|
-
_name: t?.
|
|
737
|
+
_name: t?.St ? undefined : t?.name ?? "computed",
|
|
698
738
|
_loc: t?.loc,
|
|
699
739
|
// Observe: the verdict windows this pass entered (verdict.ts) — a
|
|
700
740
|
// slot, so the stamp is never a write after construction.
|
|
701
741
|
Ve: 0
|
|
702
742
|
};
|
|
703
|
-
if (t?.unobserved) ext(s).
|
|
743
|
+
if (t?.unobserved) ext(s).Gt = t.unobserved;
|
|
704
744
|
setupComputedNode(s, t);
|
|
705
745
|
return s;
|
|
706
746
|
}
|
|
@@ -712,21 +752,21 @@ function computed(e, t) {
|
|
|
712
752
|
return e.T ??= {
|
|
713
753
|
Ee: null,
|
|
714
754
|
Se: null,
|
|
715
|
-
|
|
755
|
+
U: undefined,
|
|
716
756
|
fe: undefined,
|
|
717
757
|
se: undefined,
|
|
718
|
-
|
|
758
|
+
Gt: undefined,
|
|
719
759
|
st: undefined,
|
|
720
760
|
ft: null,
|
|
721
|
-
|
|
761
|
+
Tt: null,
|
|
722
762
|
Je: null,
|
|
723
763
|
ut: false,
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
764
|
+
Ft: NOT_PENDING,
|
|
765
|
+
ht: -1,
|
|
766
|
+
Ie: 0,
|
|
727
767
|
V: NOT_PENDING,
|
|
728
768
|
I: 0,
|
|
729
|
-
Te:
|
|
769
|
+
Te: null
|
|
730
770
|
};
|
|
731
771
|
}
|
|
732
772
|
|
|
@@ -806,6 +846,9 @@ function computed(e, t) {
|
|
|
806
846
|
// head), and the pass may then read a guess and become the lane's.
|
|
807
847
|
if (s === flushTransaction && !o && !n || bornInto(e, s)) return false;
|
|
808
848
|
staleReader(e, s);
|
|
849
|
+
// Lane work or a verdict reader no longer waits on `el`'s flight (lanes.ts
|
|
850
|
+
// `laneServed`, A15).
|
|
851
|
+
if (o || n) laneServedHook(e, t);
|
|
809
852
|
return true;
|
|
810
853
|
}
|
|
811
854
|
|
|
@@ -819,7 +862,14 @@ function computed(e, t) {
|
|
|
819
862
|
|
|
820
863
|
/** The computed whose pass a creation under `owner` belongs to (a root's is
|
|
821
864
|
* its nearest computed ancestor's), or null outside every pass. */ function creatorPass(e) {
|
|
822
|
-
return e !== null && e.Pt ? e.
|
|
865
|
+
return e !== null && e.Pt ? e.Ht : e;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/** What `born` and the passes still running around `p` read — its
|
|
869
|
+
* creator's, theirs — of the future or a staging (REACTIVE_JOINED |
|
|
870
|
+
* REACTIVE_STAGED_READ): a pass created by one that did has no screen; its
|
|
871
|
+
* branch exists only in that world (#4341). */ function creatorReads(e, t) {
|
|
872
|
+
return (e = creatorPass(e._parent))?.R & REACTIVE_RECOMPUTING_DEPS ? creatorReads(e, t | e.R) : t & (REACTIVE_JOINED | REACTIVE_STAGED_READ);
|
|
823
873
|
}
|
|
824
874
|
|
|
825
875
|
/** L2 — park the previous pass's frame for this node's commit: the children
|
|
@@ -828,11 +878,11 @@ function computed(e, t) {
|
|
|
828
878
|
* the frame that replaces them (`commitPendingNode`) or when the owner does. */ function parkChildren(e) {
|
|
829
879
|
markDisposal(e);
|
|
830
880
|
const t = ext(e);
|
|
831
|
-
t.
|
|
881
|
+
t.Tt = e._t;
|
|
832
882
|
t.ft = e.ze;
|
|
833
|
-
e.
|
|
883
|
+
e._t = null;
|
|
834
884
|
e.ze = null;
|
|
835
|
-
e.
|
|
885
|
+
e.At = 0;
|
|
836
886
|
}
|
|
837
887
|
|
|
838
888
|
/**
|
|
@@ -841,47 +891,47 @@ function computed(e, t) {
|
|
|
841
891
|
* mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
|
|
842
892
|
* the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
|
|
843
893
|
*/ function createEffectNode(e, t, n, o, s) {
|
|
844
|
-
const
|
|
894
|
+
const E = s?.transparent ?? false;
|
|
845
895
|
// Prod and observe boilerplates — see computed() for why the observe tier
|
|
846
896
|
// gets its `_name` as a literal slot rather than a write after the fact.
|
|
847
897
|
// The default label is the node kind (tracked effects relabel their computed
|
|
848
898
|
// in trackedEffect); the wrappers in signals.ts no longer spread a name into
|
|
849
899
|
// the options to get it.
|
|
850
|
-
const
|
|
851
|
-
id: inheritId(s,
|
|
900
|
+
const l = {
|
|
901
|
+
id: inheritId(s, E, context),
|
|
852
902
|
l:
|
|
853
903
|
// CONFIG_FRAME for a render effect (EFFECT_RENDER = 1; a user
|
|
854
904
|
// effect's 1 << 24 is unused).
|
|
855
|
-
o << 23 | (
|
|
905
|
+
o << 23 | (E ? CONFIG_TRANSPARENT : 0) | (s?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (s?.sync ? CONFIG_SYNC : 0) | (s?.ct ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
856
906
|
je: false,
|
|
857
|
-
|
|
907
|
+
_t: null,
|
|
858
908
|
A: context?.A ?? defaultContext,
|
|
859
|
-
|
|
909
|
+
At: 0,
|
|
860
910
|
X: e,
|
|
861
911
|
le: undefined,
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
912
|
+
lt: 0,
|
|
913
|
+
Rt: undefined,
|
|
914
|
+
Ct: null,
|
|
865
915
|
C: null,
|
|
866
916
|
_: null,
|
|
867
917
|
Ne: 0,
|
|
868
918
|
o: null,
|
|
869
|
-
|
|
919
|
+
Ot: null,
|
|
870
920
|
_parent: context,
|
|
871
921
|
Xe: null,
|
|
872
922
|
dt: null,
|
|
873
923
|
ze: null,
|
|
874
924
|
R: REACTIVE_LAZY,
|
|
875
925
|
m: STATUS_UNINITIALIZED,
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
926
|
+
ie: clock,
|
|
927
|
+
ue: NOT_PENDING,
|
|
928
|
+
Dt: -1,
|
|
879
929
|
ce: false,
|
|
880
930
|
Qe: false,
|
|
881
|
-
|
|
931
|
+
It: undefined,
|
|
882
932
|
Ge: t,
|
|
883
|
-
|
|
884
|
-
|
|
933
|
+
kt: n,
|
|
934
|
+
Vt: undefined,
|
|
885
935
|
i: o,
|
|
886
936
|
T: null,
|
|
887
937
|
_name: s?.name ?? "effect",
|
|
@@ -893,9 +943,9 @@ function computed(e, t) {
|
|
|
893
943
|
// allocation on EVERY effect at creation (an alloc + 19 field stores,
|
|
894
944
|
// +23% effect creation, caught by the creation benches). Only genuinely
|
|
895
945
|
// per-node channels (boundaries) live on _x.
|
|
896
|
-
if (s?.unobserved) ext(
|
|
897
|
-
setupComputedNode(
|
|
898
|
-
return
|
|
946
|
+
if (s?.unobserved) ext(l).Gt = s.unobserved;
|
|
947
|
+
setupComputedNode(l, lazyOptions);
|
|
948
|
+
return l;
|
|
899
949
|
}
|
|
900
950
|
|
|
901
951
|
/**
|
|
@@ -922,10 +972,10 @@ const lazyOptions = {
|
|
|
922
972
|
};
|
|
923
973
|
|
|
924
974
|
function setupComputedNode(e, t) {
|
|
925
|
-
e.
|
|
926
|
-
const n = context?.Pt ? context.
|
|
975
|
+
e.Ct = e;
|
|
976
|
+
const n = context?.Pt ? context.Ht : context;
|
|
927
977
|
if (context) linkChild(context, e);
|
|
928
|
-
if (n) e.
|
|
978
|
+
if (n) e.lt = n.lt + 1;
|
|
929
979
|
wireExternalSourceHook?.(e);
|
|
930
980
|
!t?.lazy && recompute(e, true);
|
|
931
981
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
@@ -940,19 +990,19 @@ function signal(e, t) {
|
|
|
940
990
|
// and staying null on internal signals — one shape either way).
|
|
941
991
|
const n = {
|
|
942
992
|
je: t?.equals ?? isEqual,
|
|
943
|
-
l: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.
|
|
993
|
+
l: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.ae ? CONFIG_NO_SNAPSHOT : 0),
|
|
944
994
|
le: e,
|
|
945
995
|
o: null,
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
996
|
+
Ot: null,
|
|
997
|
+
ie: clock,
|
|
998
|
+
ue: NOT_PENDING,
|
|
999
|
+
Dt: -1,
|
|
950
1000
|
T: null,
|
|
951
1001
|
_name: t?.name ?? "signal",
|
|
952
1002
|
_loc: t?.loc,
|
|
953
1003
|
H: null
|
|
954
1004
|
};
|
|
955
|
-
if (t?.unobserved) ext(n).
|
|
1005
|
+
if (t?.unobserved) ext(n).Gt = t.unobserved;
|
|
956
1006
|
if (snapshotCaptureActive && !(n.l & CONFIG_NO_SNAPSHOT)) takeSnapshot(n, e);
|
|
957
1007
|
return n;
|
|
958
1008
|
}
|
|
@@ -972,18 +1022,18 @@ function isEqual(e, t) {
|
|
|
972
1022
|
* the store's notification machinery. The observe literal adds the label
|
|
973
1023
|
* and location slots (the store relabels `store.<key>` and stamps the
|
|
974
1024
|
* store's `loc` when the engine is installed). */ function slotSignal(e, t, n, o, s) {
|
|
975
|
-
const
|
|
1025
|
+
const E = {
|
|
976
1026
|
je: t,
|
|
977
1027
|
l: CONFIG_OWNED_WRITE | CONFIG_SLOT_NODE,
|
|
978
1028
|
le: e,
|
|
979
1029
|
o: null,
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1030
|
+
Ot: null,
|
|
1031
|
+
ie: clock,
|
|
1032
|
+
ue: NOT_PENDING,
|
|
1033
|
+
Dt: -1,
|
|
984
1034
|
T: null,
|
|
985
1035
|
O: n,
|
|
986
|
-
|
|
1036
|
+
gt: o,
|
|
987
1037
|
acc: s,
|
|
988
1038
|
px: undefined,
|
|
989
1039
|
pxv: undefined,
|
|
@@ -991,7 +1041,7 @@ function isEqual(e, t) {
|
|
|
991
1041
|
_loc: undefined,
|
|
992
1042
|
H: null
|
|
993
1043
|
};
|
|
994
|
-
return
|
|
1044
|
+
return E;
|
|
995
1045
|
}
|
|
996
1046
|
|
|
997
1047
|
/**
|
|
@@ -1112,7 +1162,7 @@ function setVerdict(e) {
|
|
|
1112
1162
|
* never the graph — A32).
|
|
1113
1163
|
* False means the reader derives from the staged value.
|
|
1114
1164
|
*/ function readerSeesCommitted(e, t) {
|
|
1115
|
-
return !t || e.
|
|
1165
|
+
return !t || e.ue === NOT_PENDING || t.l & CONFIG_CHILDREN_FORBIDDEN;
|
|
1116
1166
|
}
|
|
1117
1167
|
|
|
1118
1168
|
/** A28 — set when a node is staged (queuePendingNode) OUTSIDE a flush;
|
|
@@ -1133,11 +1183,11 @@ function markUnflushedStaged() {
|
|
|
1133
1183
|
* is unflushed. Exempt: promoted writes (A28 (4): a write issued inside a
|
|
1134
1184
|
* recompute is promoted at that recompute's end — boundary and loading
|
|
1135
1185
|
* machinery, signals declared for in-computation writes). */ function unflushedValue(e) {
|
|
1136
|
-
if (globalQueue.
|
|
1186
|
+
if (globalQueue.Y || e.ue === NOT_PENDING || e.l & CONFIG_PROMOTED) return NOT_PENDING;
|
|
1137
1187
|
// A held node (L2) carries a staged value between flushes too, but it was
|
|
1138
1188
|
// flushed — and parked. Not an unflushed write — unless rewritten since:
|
|
1139
1189
|
// then the flushed staging is what the world sees until the next flush.
|
|
1140
|
-
if (e.l & CONFIG_HELD) return e.T.
|
|
1190
|
+
if (e.l & CONFIG_HELD) return e.T.ht === clock ? e.T.Ft : NOT_PENDING;
|
|
1141
1191
|
return e.le;
|
|
1142
1192
|
}
|
|
1143
1193
|
|
|
@@ -1145,9 +1195,9 @@ function markUnflushedStaged() {
|
|
|
1145
1195
|
* flush left (`_flushed`) until the flush that carries the rewrite — the
|
|
1146
1196
|
* stash is stamped with the clock, which that flush advances. */ function stashFlushed(e) {
|
|
1147
1197
|
const t = e.T;
|
|
1148
|
-
if (t.
|
|
1149
|
-
t.
|
|
1150
|
-
t.
|
|
1198
|
+
if (t.ht !== clock) {
|
|
1199
|
+
t.Ft = e.ue;
|
|
1200
|
+
t.ht = clock;
|
|
1151
1201
|
unflushedStaged = true;
|
|
1152
1202
|
}
|
|
1153
1203
|
}
|
|
@@ -1175,7 +1225,7 @@ function resyncUnflushedCompanions() {
|
|
|
1175
1225
|
/** A tracked read's pull of a computed: bring it current when the flush has
|
|
1176
1226
|
* reached its height (or the reader is a fresh-pull waiter), and sit the
|
|
1177
1227
|
* reader above it. */ function pullComputed(e, t) {
|
|
1178
|
-
if (e.
|
|
1228
|
+
if (e.lt >= dirtyQueue.Et) {
|
|
1179
1229
|
markNode(t);
|
|
1180
1230
|
markHeap(dirtyQueue);
|
|
1181
1231
|
updateIfNecessary(e);
|
|
@@ -1187,25 +1237,26 @@ function resyncUnflushedCompanions() {
|
|
|
1187
1237
|
// node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
|
|
1188
1238
|
// a dead target serves its last value, which is already quiescent.
|
|
1189
1239
|
else if (t.l & CONFIG_FRESH_READ) updateIfNecessary(e);
|
|
1190
|
-
const n = e.
|
|
1240
|
+
const n = e.lt;
|
|
1191
1241
|
// parent check is shallow, might need to be recursive
|
|
1192
|
-
if (n >= t.
|
|
1242
|
+
if (n >= t.lt && e._parent !== t) t.lt = n + 1;
|
|
1193
1243
|
}
|
|
1194
1244
|
|
|
1195
1245
|
function read(e) {
|
|
1196
1246
|
let t = context;
|
|
1197
|
-
if (t?.Pt) t = t.
|
|
1247
|
+
if (t?.Pt) t = t.Ht;
|
|
1198
1248
|
const n = e;
|
|
1199
1249
|
// CARVE 1: `owner` was `el._firewall || el` — a store leaf's status,
|
|
1200
1250
|
// height and error were read off its projection computed. (Typed loosely
|
|
1201
1251
|
// as the `||` expression was: a signal's `_statusFlags`/`_height` read as
|
|
1202
1252
|
// undefined and mask to 0 on every site below.)
|
|
1203
1253
|
const o = e;
|
|
1204
|
-
if (typeof n.X === "function") prepareComputed(e);
|
|
1205
1254
|
// The verdict windows (`latest`, `isPending`; verdict.ts): one cold path,
|
|
1206
|
-
// off this one, present only while a window is open.
|
|
1255
|
+
// off this one, present only while a window is open. It wakes a lazy or
|
|
1256
|
+
// dormant memo itself, outside the window (#4366).
|
|
1207
1257
|
if (verdict !== null) return verdict(e, t);
|
|
1208
|
-
if (
|
|
1258
|
+
if (typeof n.X === "function") prepareComputed(e);
|
|
1259
|
+
if (!n.X && e.T?.st === undefined && !snapshotCaptureActive && (!unflushedStaged || e.ue === NOT_PENDING) && // A28, see readNodeFast
|
|
1209
1260
|
!(e.l & CONFIG_OVERRIDE) && // lanes: the slow path's one arm
|
|
1210
1261
|
true) {
|
|
1211
1262
|
if (t) {
|
|
@@ -1226,13 +1277,13 @@ function read(e) {
|
|
|
1226
1277
|
}
|
|
1227
1278
|
}
|
|
1228
1279
|
// Committed visibility for untracked and children-forbidden readers.
|
|
1229
|
-
if (!t || e.
|
|
1280
|
+
if (!t || e.ue === NOT_PENDING || t.l & CONFIG_CHILDREN_FORBIDDEN) return e.le;
|
|
1230
1281
|
// (A plain signal is never uninitialized — the carve-out is `serve`'s.)
|
|
1231
1282
|
// Lane work over a folded lane (D-34), once the frame has a
|
|
1232
1283
|
// transaction, reads the screen too.
|
|
1233
1284
|
if ((observeFlightHook && t.l & CONFIG_VERDICT || laneStageHook && passLane?.folded) && stagedScreen(t)) return e.le;
|
|
1234
1285
|
stagedRead(t);
|
|
1235
|
-
return e.
|
|
1286
|
+
return e.ue;
|
|
1236
1287
|
}
|
|
1237
1288
|
// Rule 3: this read serves the committed value to a render effect outside a
|
|
1238
1289
|
// parking flush (decided after the pull below — a pull can join).
|
|
@@ -1247,7 +1298,8 @@ function read(e) {
|
|
|
1247
1298
|
// it probed inline: it reads held values as the screen and shows the
|
|
1248
1299
|
// verdict now. Not an effect: a render effect is a frame reader
|
|
1249
1300
|
// already, and a user effect's posture is its own reads'.
|
|
1250
|
-
|
|
1301
|
+
// (A verdict memo exists only with the verdict engine installed.)
|
|
1302
|
+
if (observeFlightHook && !t.i) t.R |= o.l & CONFIG_VERDICT;
|
|
1251
1303
|
}
|
|
1252
1304
|
}
|
|
1253
1305
|
// L2, as in the fast block above (tracked or not). A node born into the
|
|
@@ -1273,7 +1325,7 @@ function read(e) {
|
|
|
1273
1325
|
const n = e.T?.st;
|
|
1274
1326
|
if (n !== undefined && !(o.m & STATUS_ERROR)) {
|
|
1275
1327
|
const o = n === NO_SNAPSHOT ? undefined : n;
|
|
1276
|
-
const s = e.
|
|
1328
|
+
const s = e.ue !== NOT_PENDING ? e.ue : e.le;
|
|
1277
1329
|
if (s !== o) t.R |= REACTIVE_SNAPSHOT_STALE;
|
|
1278
1330
|
return o;
|
|
1279
1331
|
}
|
|
@@ -1292,11 +1344,12 @@ function read(e) {
|
|
|
1292
1344
|
// — unless the flight committed beneath inputs already on screen
|
|
1293
1345
|
// (`observeFlight`), or the reader was born into the flight's transaction
|
|
1294
1346
|
// (#4010): it has no screen, and waits on the flight with its frame.
|
|
1295
|
-
|
|
1347
|
+
// (A lane, and a verdict reader, exist only with their engines installed —
|
|
1348
|
+
// the verdict engine imports the lane engine: without it the test folds.)
|
|
1349
|
+
if (laneStageHook && o.m & STATUS_PENDING && !s && !(e.l & CONFIG_OVERRIDE) && !(o.m & STATUS_UNINITIALIZED)) {
|
|
1296
1350
|
// A reader with no committed value yet sees the flight pending: a
|
|
1297
1351
|
// boundary a lane mounts shows its fallback (A29's boundary exemption).
|
|
1298
|
-
|
|
1299
|
-
if (laneStageHook && passLane !== null && !(t?.m & STATUS_UNINITIALIZED)) s = true; else if (observeFlightHook && t !== null && t.l & CONFIG_VERDICT) s = observeFlightHook(t, o);
|
|
1352
|
+
if (passLane !== null && !(t?.m & STATUS_UNINITIALIZED)) s = true; else if (t !== null && t.l & CONFIG_VERDICT) s = observeFlightHook(t, o);
|
|
1300
1353
|
}
|
|
1301
1354
|
if (o.m & STATUS_PENDING && !s) {
|
|
1302
1355
|
// A reader landing on a pending node throws; an untracked read of an
|
|
@@ -1310,10 +1363,10 @@ function read(e) {
|
|
|
1310
1363
|
// the node settles — unless nobody is reading (`spectating`, #3528)
|
|
1311
1364
|
// or the reader is the node itself.
|
|
1312
1365
|
if (!tracking && !spectating && e !== t) link(e, t);
|
|
1313
|
-
throw o.T?.
|
|
1366
|
+
throw o.T?.U;
|
|
1314
1367
|
}
|
|
1315
1368
|
} else if (o.m & STATUS_UNINITIALIZED) {
|
|
1316
|
-
throw o.T?.
|
|
1369
|
+
throw o.T?.U;
|
|
1317
1370
|
}
|
|
1318
1371
|
}
|
|
1319
1372
|
// An errored derive throws for every late reader instead of silently
|
|
@@ -1322,16 +1375,24 @@ function read(e) {
|
|
|
1322
1375
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
1323
1376
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
1324
1377
|
// - owner._time < clock: only on a later cycle than the one the error was found
|
|
1325
|
-
if (tracking && o.
|
|
1378
|
+
if (tracking && o.ie < clock) {
|
|
1326
1379
|
recompute(o);
|
|
1327
1380
|
return read(e);
|
|
1328
|
-
}
|
|
1381
|
+
}
|
|
1382
|
+
// D-41: a staged error replacing the shown one is this flush's answer
|
|
1383
|
+
// (`stageError`): a reader served the staging (`serve`) throws it, as it
|
|
1384
|
+
// would read a staged value, and stages its own error with it; one
|
|
1385
|
+
// served the screen throws the shown error. Thrown the shown error, a
|
|
1386
|
+
// reader born this flush published it, and its readers' stale error
|
|
1387
|
+
// committed after the new one (#4404).
|
|
1388
|
+
if (!s && e.l & CONFIG_STAGED_ERROR) serve(e, t);
|
|
1389
|
+
throw o.T?.U;
|
|
1329
1390
|
}
|
|
1330
|
-
|
|
1331
|
-
//
|
|
1332
|
-
//
|
|
1333
|
-
if (!t
|
|
1334
|
-
const
|
|
1391
|
+
// D-41: an untracked read reads the screen, and so does a frame reader
|
|
1392
|
+
// served the committed value — `serve` hands it that value as it does an
|
|
1393
|
+
// untracked read — a shown error included (`throwShown`).
|
|
1394
|
+
if (s || !t) throwShown(e);
|
|
1395
|
+
const E = serve(e, s ? null : t);
|
|
1335
1396
|
if (!t && typeof n.X === "function" && e.l & CONFIG_AUTO_DISPOSE && !(o.m & STATUS_PENDING) && !e.o) {
|
|
1336
1397
|
// Deferred, not inline (#3078): an inline unobserved() here made untracked
|
|
1337
1398
|
// reads destructive — dispose on this read, full revival recompute on the
|
|
@@ -1342,7 +1403,13 @@ function read(e) {
|
|
|
1342
1403
|
dormantNodes.add(e);
|
|
1343
1404
|
schedule();
|
|
1344
1405
|
}
|
|
1345
|
-
return
|
|
1406
|
+
return E;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/** D-41: a reader served the screen — an untracked read, a frame reader
|
|
1410
|
+
* served the committed value, a verdict reader (`serve`) — reads a shown
|
|
1411
|
+
* error there until the answer that replaces it commits. */ function throwShown(e) {
|
|
1412
|
+
if (e.T?.Te) throw e.T.Te;
|
|
1346
1413
|
}
|
|
1347
1414
|
|
|
1348
1415
|
/**
|
|
@@ -1359,18 +1426,17 @@ function read(e) {
|
|
|
1359
1426
|
// an untracked reader has nothing to serve and holds (A19 exception 1) — a
|
|
1360
1427
|
// bookkeeping read (`spectate`) likewise, and a children-forbidden reader
|
|
1361
1428
|
// (A32: the frame, which has nothing here).
|
|
1362
|
-
if (e.
|
|
1429
|
+
if (e.ue !== NOT_PENDING && e.m & STATUS_UNINITIALIZED && (!t || spectating || t.l & CONFIG_CHILDREN_FORBIDDEN)) throw new NotReadyError(null);
|
|
1363
1430
|
const n = t && unflushedStaged ? unflushedValue(e) : NOT_PENDING;
|
|
1364
1431
|
if (n !== NOT_PENDING) {
|
|
1365
1432
|
markLateLinker(t);
|
|
1366
1433
|
return n;
|
|
1367
1434
|
}
|
|
1368
|
-
if (readerSeesCommitted(e, t)) return e.le;
|
|
1369
|
-
if (observeFlightHook && t.l & CONFIG_VERDICT && !(e.m & STATUS_UNINITIALIZED) && stagedScreen(t)) return e.le;
|
|
1435
|
+
if (readerSeesCommitted(e, t) || observeFlightHook && t.l & CONFIG_VERDICT && !(e.m & STATUS_UNINITIALIZED) && stagedScreen(t) && !throwShown(e)) return e.le;
|
|
1370
1436
|
stagedRead(t, e);
|
|
1371
1437
|
// D-41: the staged answer is an error (`stageError`).
|
|
1372
|
-
if (e.l & CONFIG_STAGED_ERROR) throw e.
|
|
1373
|
-
return e.
|
|
1438
|
+
if (e.l & CONFIG_STAGED_ERROR) throw e.ue;
|
|
1439
|
+
return e.ue;
|
|
1374
1440
|
}
|
|
1375
1441
|
|
|
1376
1442
|
/** A pass read a staging of this flush: it derives from what the flush may
|
|
@@ -1390,7 +1456,13 @@ function read(e) {
|
|
|
1390
1456
|
* round (#3969: nor does it make a later lane read a re-derive, `enterLane`). */ function stagedRead(e, t) {
|
|
1391
1457
|
if (!(t?.m & STATUS_UNINITIALIZED)) {
|
|
1392
1458
|
e.R |= REACTIVE_STAGED_READ;
|
|
1393
|
-
|
|
1459
|
+
// A verdict reader's too when it is an effect, before the frame has a
|
|
1460
|
+
// transaction (after, `stagedScreen` serves it the screen): the staging
|
|
1461
|
+
// is the frame's read, and the pass re-derives once as a verdict reader
|
|
1462
|
+
// if the flush parks (D-22; D-25: the probe decides the posture in either
|
|
1463
|
+
// read order). A memo's is the frame's derivation either way: a memo is
|
|
1464
|
+
// not a leaf (`frameRead`).
|
|
1465
|
+
if (laneSeamsHook && (passLane !== null || e.i && e.l & CONFIG_VERDICT)) stagedReaders.push(e);
|
|
1394
1466
|
}
|
|
1395
1467
|
}
|
|
1396
1468
|
|
|
@@ -1404,6 +1476,14 @@ function read(e) {
|
|
|
1404
1476
|
* its only value (A29). Nor has a reader born into the flush's transaction
|
|
1405
1477
|
* (`bornInto`, #4010): its branch exists only there. */ function stagedScreen(e) {
|
|
1406
1478
|
if (flushTransaction === null || bornInto(e, flushTransaction)) return false;
|
|
1479
|
+
// A transaction only a `latest()` read opened holds nothing: the staging
|
|
1480
|
+
// is the frame's read for a pass in the frame's seat, as it is before the
|
|
1481
|
+
// frame has one, and the seam re-derives the pass once only if the flush
|
|
1482
|
+
// parks (D-22, F-10). Lane work sees the screen (D-37). Not a pass with no
|
|
1483
|
+
// value yet: its first answer is nobody's hold (D-6) and would commit the
|
|
1484
|
+
// staging whether or not the frame parks — it reads the screen, and runs
|
|
1485
|
+
// again at the landing.
|
|
1486
|
+
if (observeFlightHook && flushTransaction === latestOpened && passLane === null && e.l & CONFIG_VERDICT && !(e.m & STATUS_UNINITIALIZED)) return !stagedReaders.push(e);
|
|
1407
1487
|
staleReader(e, flushTransaction);
|
|
1408
1488
|
return true;
|
|
1409
1489
|
}
|
|
@@ -1411,7 +1491,7 @@ function read(e) {
|
|
|
1411
1491
|
/** A28 (4) — written inside a recompute that runs OUTSIDE a flush (a
|
|
1412
1492
|
* creation-time compute): promoted at that pass's end, visible to the rest of
|
|
1413
1493
|
* the block. Cold: only contextual writes reach here. */ function notePromotedWrite(e) {
|
|
1414
|
-
if (globalQueue.
|
|
1494
|
+
if (globalQueue.Y || e.l & CONFIG_PROMOTED) return;
|
|
1415
1495
|
e.l |= CONFIG_PROMOTED;
|
|
1416
1496
|
promotedWrites.push(e);
|
|
1417
1497
|
}
|
|
@@ -1469,7 +1549,7 @@ function takeSnapshot(e, t) {
|
|
|
1469
1549
|
|
|
1470
1550
|
function setSignal(e, t) {
|
|
1471
1551
|
if (writeHook !== null) writeHook(e);
|
|
1472
|
-
const n = e.
|
|
1552
|
+
const n = e.ue === NOT_PENDING ? e.le : e.ue;
|
|
1473
1553
|
if (typeof t === "function") t = t(n);
|
|
1474
1554
|
// Lanes: a write landing on a guess is its truth (A18 — an async guess's
|
|
1475
1555
|
// own landing), judged against the guess; one landing on a lane's
|
|
@@ -1498,21 +1578,21 @@ function setSignal(e, t) {
|
|
|
1498
1578
|
// pass reads a value the server never had. Store leaves written here are
|
|
1499
1579
|
// plain signals and qualify the same way.
|
|
1500
1580
|
if (snapshotCaptureActive) captureWriteSnapshot(e, n);
|
|
1501
|
-
const s = e.
|
|
1581
|
+
const s = e.ue !== NOT_PENDING;
|
|
1502
1582
|
if (!s) queuePendingNode(e);
|
|
1503
1583
|
// A28: a held node rewritten outside a flush keeps its flushed staging
|
|
1504
1584
|
// for every reader until the flush that carries the rewrite.
|
|
1505
|
-
else if (e.l & CONFIG_HELD && !globalQueue.
|
|
1506
|
-
e.
|
|
1585
|
+
else if (e.l & CONFIG_HELD && !globalQueue.Y) stashFlushed(e);
|
|
1586
|
+
e.ue = t;
|
|
1507
1587
|
if (context !== null) notePromotedWrite(e);
|
|
1508
1588
|
// _time is a computed-only slot (§12e): writing it on a signal would fork
|
|
1509
1589
|
// the lean shape. Every read site is computed-typed.
|
|
1510
|
-
if (e.X !== undefined) e.
|
|
1590
|
+
if (e.X !== undefined) e.ie = clock;
|
|
1511
1591
|
// Staged-rewrite fast path (§12d): a re-write to a node whose subscribers
|
|
1512
1592
|
// were already walked — and where nothing has recomputed or linked since
|
|
1513
1593
|
// (epoch) — re-stages the value and stops. The walk is idempotent (subs
|
|
1514
1594
|
// marked, heap entries flag-guarded, effects queued once).
|
|
1515
|
-
if (s && e.
|
|
1595
|
+
if (s && e.Dt === notifyEpoch) return t;
|
|
1516
1596
|
insertSubs(e);
|
|
1517
1597
|
schedule();
|
|
1518
1598
|
return t;
|
|
@@ -1548,8 +1628,8 @@ function setSignal(e, t) {
|
|
|
1548
1628
|
// every later read keeps throwing the error the derivation left behind.
|
|
1549
1629
|
// The error stays the display until the write commits (D-41).
|
|
1550
1630
|
if (e.m & STATUS_ERROR) {
|
|
1551
|
-
e.T.Te = e.T.
|
|
1552
|
-
notifyStatus(e, STATUS_NONE
|
|
1631
|
+
e.T.Te = e.T.U;
|
|
1632
|
+
notifyStatus(e, STATUS_NONE);
|
|
1553
1633
|
}
|
|
1554
1634
|
t = setSignal(e, t);
|
|
1555
1635
|
// A write replaces an error a pass staged (D-41): it is a value again.
|
|
@@ -1560,7 +1640,7 @@ function setSignal(e, t) {
|
|
|
1560
1640
|
e.R = e.R & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
1561
1641
|
insertIntoHeap(e, dirtyQueue);
|
|
1562
1642
|
schedule();
|
|
1563
|
-
} else if (e.
|
|
1643
|
+
} else if (e.ue !== NOT_PENDING) e.R |= REACTIVE_MANUAL_WRITE;
|
|
1564
1644
|
return t;
|
|
1565
1645
|
}
|
|
1566
1646
|
|
|
@@ -1624,4 +1704,4 @@ function staleValues(e, t = true) {
|
|
|
1624
1704
|
}
|
|
1625
1705
|
}
|
|
1626
1706
|
|
|
1627
|
-
export { bornInto, captureWriteSnapshot, clearSnapshots, computed, context, createEffectNode, effectStatusNotify, ext, isEqual, isSame, joinPass, joinPassAt, markLateLinker, markRefresh, markSnapshotScope, markUnflushedStaged, notePromotedWrite, prepareComputed, pullComputed, read, readerSeesCommitted, recompute, releaseSnapshotScope, resyncUnflushedCompanions, runWithOwner, serve, setEffectStatusNotify, setMemo, setSignal, setSnapshotCapture, setVerdict, setWriteHook, signal, slotSignal, snapshotCaptureActive, snapshotSources, spectating, stagedRead, stagedScreen, staleValues, stashFlushed, statusNotifierOf, tracking, unflushedStaged, unflushedValue, untrack, verdict, writeHook };
|
|
1707
|
+
export { bornInto, captureWriteSnapshot, clearSnapshots, computed, context, createEffectNode, creatorPass, creatorReads, effectStatusNotify, ext, isEqual, isSame, joinPass, joinPassAt, markLateLinker, markRefresh, markSnapshotScope, markUnflushedStaged, notePromotedWrite, prepareComputed, pullComputed, read, readerSeesCommitted, recompute, releaseSnapshotScope, resyncUnflushedCompanions, runWithOwner, serve, setEffectStatusNotify, setMemo, setSignal, setSnapshotCapture, setVerdict, setWriteHook, signal, slotSignal, snapshotCaptureActive, snapshotSources, spectating, stagedRead, stagedScreen, staleValues, stashFlushed, statusNotifierOf, tracking, unflushedStaged, unflushedValue, untrack, verdict, writeHook };
|