@solidjs/signals 2.0.0-rc.15 → 2.0.0-rc.16
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 +785 -367
- package/dist/dev.attribution.js +75 -52
- package/dist/dev.js +1120 -567
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +22 -73
- package/dist/observe/boundaries.js +191 -189
- package/dist/observe/core/async.js +175 -131
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +176 -159
- package/dist/observe/core/constants.js +17 -3
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +503 -363
- package/dist/observe/core/dev.js +66 -38
- package/dist/observe/core/effect.js +48 -48
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +57 -43
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +226 -259
- package/dist/observe/core/owner.js +62 -50
- package/dist/observe/core/scheduler.js +319 -171
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +88 -50
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +345 -260
- package/dist/observe/reveal.js +76 -76
- package/dist/observe/signals.js +41 -30
- package/dist/observe/store/affects.js +6 -6
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/optimistic.js +41 -36
- package/dist/observe/store/projection.js +68 -55
- package/dist/observe/store/store.js +157 -104
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +23 -72
- package/dist/prod/boundaries.js +155 -153
- package/dist/prod/core/async.js +171 -127
- package/dist/prod/core/constants.js +17 -3
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +478 -342
- package/dist/prod/core/effect.js +68 -68
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +57 -43
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +217 -250
- package/dist/prod/core/owner.js +62 -51
- package/dist/prod/core/scheduler.js +310 -162
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +87 -49
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +360 -275
- package/dist/prod/reveal.js +76 -76
- package/dist/prod/signals.js +41 -30
- package/dist/prod/store/affects.js +6 -6
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/optimistic.js +37 -33
- package/dist/prod/store/projection.js +25 -19
- package/dist/prod/store/store.js +142 -96
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +1 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/constants.d.ts +13 -1
- package/dist/types/core/core.d.ts +44 -2
- package/dist/types/core/dev.d.ts +43 -13
- package/dist/types/core/graph.d.ts +11 -0
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +2 -14
- package/dist/types/core/owner.d.ts +5 -3
- package/dist/types/core/scheduler.d.ts +47 -28
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -0
- package/dist/types/core/verdict.d.ts +32 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/map.d.ts +2 -2
- package/dist/types/signals.d.ts +28 -7
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/index.d.ts +10 -3
- package/dist/types/store/optimistic.d.ts +3 -2
- package/dist/types/store/projection.d.ts +4 -3
- package/dist/types/store/store.d.ts +1 -1
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/dev-shared.js
CHANGED
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
class NotReadyError extends Error {
|
|
26
|
-
source;
|
|
27
26
|
constructor(source) {
|
|
28
27
|
super();
|
|
29
28
|
this.source = source;
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
31
|
class StatusError extends Error {
|
|
33
|
-
source;
|
|
34
32
|
constructor(source, original) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
// Best-effort message: formatting must never replace the original (#4112).
|
|
34
|
+
try {
|
|
35
|
+
var message = String(original instanceof Error ? original.message : original);
|
|
36
|
+
} catch {}
|
|
37
|
+
super(message, { cause: original });
|
|
38
38
|
this.source = source;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -191,6 +191,9 @@ const CONFIG_SLOT_NODE = 1 << 12;
|
|
|
191
191
|
* leaf twin of REACTIVE_MANUAL_WRITE). Set by the user setter, cleared by
|
|
192
192
|
* the derive's own write to the key. */
|
|
193
193
|
const CONFIG_MANUAL_WRITE = 1 << 18;
|
|
194
|
+
/** D-41: the staged value in `_pendingValue` is an error — an
|
|
195
|
+
* answer of the held frame, published at its landing like a value. */
|
|
196
|
+
const CONFIG_STAGED_ERROR = 1 << 21;
|
|
194
197
|
/** Lanes — the node carries a written guess (`optimisticWrite`): its own
|
|
195
198
|
* source recomputing it, or a plain write landing on it, is the truth
|
|
196
199
|
* (`supersede`). A lane's derived staging is not. */
|
|
@@ -199,15 +202,21 @@ const CONFIG_GUESS = 1 << 13;
|
|
|
199
202
|
* pending is a question for its next pass — the verdict changed — so the
|
|
200
203
|
* propagation re-derives it instead of marking it pending (as a kept-tail
|
|
201
204
|
* link does, A30). Set at the window, never cleared: a reader that stopped
|
|
202
|
-
* asking re-derives once and goes pending through its own read.
|
|
203
|
-
|
|
205
|
+
* asking re-derives once and goes pending through its own read. The same
|
|
206
|
+
* bit as REACTIVE_PROBED: a pass's probe (or a read of a verdict memo,
|
|
207
|
+
* core.ts `read`) carries into the config at its end without a shift. */
|
|
208
|
+
const CONFIG_VERDICT = 1 << 15;
|
|
204
209
|
/** A dependency's status is a question for this node's pass, not a fact
|
|
205
210
|
* about its current one: the propagation re-derives it instead of marking
|
|
206
211
|
* it, for errors as for pending (as CONFIG_VERDICT). A boundary's output
|
|
207
212
|
* (show the content, or the fallback) and its `on` node (boundaries.ts); a
|
|
208
213
|
* promise over an expression (`resolve`/`until`, signals.ts: the pass reads
|
|
209
214
|
* the error and rejects, or re-asks a pending source). */
|
|
210
|
-
const CONFIG_REDERIVE = 1 <<
|
|
215
|
+
const CONFIG_REDERIVE = 1 << 14;
|
|
216
|
+
/** An answered `createDeferred` node (deferred.ts): held because a
|
|
217
|
+
* downstream hold staged its landing, its re-pass is a lagging question,
|
|
218
|
+
* not an answer, and joins no transaction (D-40). */
|
|
219
|
+
const CONFIG_LAGS = 1 << 19;
|
|
211
220
|
/** The reader wants the truth, not the lane's guess (`until`, signals.ts):
|
|
212
221
|
* a read of displayed optimism serves the base the guess covers, makes the
|
|
213
222
|
* pass no lane's, and the truth landing wakes it even when it confirms the
|
|
@@ -259,9 +268,13 @@ const CONFIG_WIDE = 1 << 26;
|
|
|
259
268
|
* creation by dev builds only (the observe artifact mangles the option name,
|
|
260
269
|
* as it does `_wide`). */
|
|
261
270
|
const CONFIG_SUPERSEDES = 1 << 27;
|
|
271
|
+
const STATUS_NONE = 0;
|
|
262
272
|
const STATUS_PENDING = 1 << 0;
|
|
263
273
|
const STATUS_ERROR = 1 << 1;
|
|
264
274
|
const STATUS_UNINITIALIZED = 1 << 2;
|
|
275
|
+
/** `catchHook`'s answer when the catcher is a boundary re-armed by
|
|
276
|
+
* `on` (truthy, as any catch): what it collects is its own, not the hold's. */
|
|
277
|
+
const CAUGHT_REARMED = 2;
|
|
265
278
|
const EFFECT_RENDER = 1;
|
|
266
279
|
const EFFECT_USER = 2;
|
|
267
280
|
const EFFECT_TRACKED = 3;
|
|
@@ -410,13 +423,21 @@ const diagnostics = {
|
|
|
410
423
|
};
|
|
411
424
|
}
|
|
412
425
|
};
|
|
426
|
+
// Flight identity → earliest declared start (see `AttributionSlot.markFlight`).
|
|
427
|
+
// Weak: a stamp must not keep a settled promise alive.
|
|
428
|
+
const flightOrigins = new WeakMap();
|
|
413
429
|
const attributionSlot = {
|
|
414
430
|
get installed() {
|
|
415
431
|
return attrHooks;
|
|
416
432
|
},
|
|
417
433
|
withInteraction,
|
|
418
434
|
withOrigin,
|
|
419
|
-
currentOrigin
|
|
435
|
+
currentOrigin,
|
|
436
|
+
markFlight(flight, startedAt = performance.now()) {
|
|
437
|
+
// Earliest wins (`undefined <= n` is false: the first mark always lands).
|
|
438
|
+
if (!(flightOrigins.get(flight) <= startedAt)) flightOrigins.set(flight, startedAt);
|
|
439
|
+
},
|
|
440
|
+
flightOrigin: flight => flightOrigins.get(flight)
|
|
420
441
|
};
|
|
421
442
|
const RECORDS = Symbol.for("@solidjs/signals/observe/records");
|
|
422
443
|
function recordsChannel() {
|
|
@@ -518,10 +539,11 @@ function isSuppressed(entry) {
|
|
|
518
539
|
return suppressedEvents.has(entry);
|
|
519
540
|
}
|
|
520
541
|
// The repair guide: the `reactivity-diagnostics` skill `solid-js` ships,
|
|
521
|
-
// one
|
|
522
|
-
//
|
|
523
|
-
|
|
524
|
-
|
|
542
|
+
// one page per code on the docs site. The slug is the code lowercased with
|
|
543
|
+
// `_` → `-` (`STRICT_READ_UNTRACKED` → `strict-read-untracked`). The host
|
|
544
|
+
// flips to docs.solidjs.com at stable (one search-and-replace, with the JSDoc
|
|
545
|
+
// links).
|
|
546
|
+
const GUIDE_URL = "https://v2.solidjs.com/reference/solid-js/diagnostics/";
|
|
525
547
|
const DEV = {
|
|
526
548
|
hooks,
|
|
527
549
|
getChildren,
|
|
@@ -531,7 +553,7 @@ const DEV = {
|
|
|
531
553
|
getObservers,
|
|
532
554
|
report: reportDiagnostic,
|
|
533
555
|
guideUrl(code) {
|
|
534
|
-
return
|
|
556
|
+
return GUIDE_URL + code.toLowerCase().replace(/_/g, "-");
|
|
535
557
|
}
|
|
536
558
|
};
|
|
537
559
|
/**
|
|
@@ -570,15 +592,29 @@ function ownerPath(subject) {
|
|
|
570
592
|
}
|
|
571
593
|
return path.length ? path.reverse() : undefined;
|
|
572
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* The innermost source location on the subject's chain: the subject's own
|
|
597
|
+
* `_loc` (a signal or computation created with `{ loc }`), else the first
|
|
598
|
+
* `_loc` up the owners — a signal hops to its registering owner, then
|
|
599
|
+
* `_parent` upward (a component root carries its JSX site). The same walk
|
|
600
|
+
* `ownerPath` makes; `undefined` when nothing on the chain was located.
|
|
601
|
+
*/
|
|
602
|
+
function locationOf(subject) {
|
|
603
|
+
// Owners have a `_parent` key (null on a root); a signal has none and hops
|
|
604
|
+
// to its registering `_owner` instead.
|
|
605
|
+
for (let node = subject; node; node = node._parent !== undefined ? node._parent : node._owner)
|
|
606
|
+
if (node._loc) return node._loc;
|
|
607
|
+
return undefined;
|
|
608
|
+
}
|
|
573
609
|
/**
|
|
574
610
|
* Records a diagnostic on the structured channel (listeners, captures) and
|
|
575
611
|
* returns the entry. `subject` locates it: the current reactive `context` by
|
|
576
612
|
* default (right for the synchronous rule checks — they fire inside the
|
|
577
613
|
* scope that misbehaved); pass the node for scheduler-time findings whose
|
|
578
614
|
* ambient context is the flush, or `null` for events that have no location
|
|
579
|
-
* by nature. An `ownerPath` already on the event wins over the
|
|
580
|
-
* (hosts whose owners are not signals' owners compute their
|
|
581
|
-
* output is a separate, dev-tier step — see `reportDiagnostic`.
|
|
615
|
+
* by nature. An `ownerPath` (or `loc`) already on the event wins over the
|
|
616
|
+
* subject walk (hosts whose owners are not signals' owners compute their
|
|
617
|
+
* own). Console output is a separate, dev-tier step — see `reportDiagnostic`.
|
|
582
618
|
*/
|
|
583
619
|
function emitDiagnostic(event, subject = context) {
|
|
584
620
|
const entry = {
|
|
@@ -595,6 +631,10 @@ function emitDiagnostic(event, subject = context) {
|
|
|
595
631
|
const path = ownerPath(subject);
|
|
596
632
|
if (path) entry.ownerPath = path;
|
|
597
633
|
}
|
|
634
|
+
if (entry.loc === undefined) {
|
|
635
|
+
const loc = locationOf(subject);
|
|
636
|
+
if (loc !== undefined) entry.loc = loc;
|
|
637
|
+
}
|
|
598
638
|
const live = subject ?? undefined;
|
|
599
639
|
if (live !== undefined) eventSubjects.set(entry, live);
|
|
600
640
|
for (const listener of diagnosticListeners) listener(entry, live);
|
|
@@ -631,12 +671,31 @@ function takeFooter(entry) {
|
|
|
631
671
|
* `reportDiagnostic(emitDiagnostic(…))`. Weak, keyed by the entry.
|
|
632
672
|
*/
|
|
633
673
|
const eventSubjects = new WeakMap();
|
|
674
|
+
/**
|
|
675
|
+
* The `at` line of a console report: the event's `loc` as the compiler wrote
|
|
676
|
+
* it (`src/App.tsx:18:3`), or — in a browser, where a dev server serves the
|
|
677
|
+
* project root at `location.origin` — `http://localhost:5173/src/App.tsx:18:3`,
|
|
678
|
+
* which Chrome and Firefox link to the Sources panel. A path that leaves the
|
|
679
|
+
* root (`../`) or is absolute is not under the origin and prints as-is.
|
|
680
|
+
*/
|
|
681
|
+
function locationLine(loc) {
|
|
682
|
+
if (
|
|
683
|
+
typeof document !== "undefined" &&
|
|
684
|
+
typeof location !== "undefined" &&
|
|
685
|
+
!loc.startsWith("..") &&
|
|
686
|
+
!loc.startsWith("/")
|
|
687
|
+
)
|
|
688
|
+
return `${location.origin}/${loc}`;
|
|
689
|
+
return loc;
|
|
690
|
+
}
|
|
634
691
|
/**
|
|
635
692
|
* The console face of a diagnostic — ONE entry per finding: the message, the
|
|
636
693
|
* owner path (`in <App> › <TodoRow> › effect`) so a human can locate it, the
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
694
|
+
* source location (`at src/App.tsx:18:3` — see `locationLine`) when a node on
|
|
695
|
+
* the chain was compiled with one, the once-per-code footer as trailing
|
|
696
|
+
* lines, and — when the subject is a binding effect the rendering runtime
|
|
697
|
+
* tagged — the element it writes, as a second console argument (hover
|
|
698
|
+
* highlights it, click jumps to Elements).
|
|
640
699
|
* Severity picks the console method. Call sites report the entry
|
|
641
700
|
* `emitDiagnostic` returned so the structured and console channels never
|
|
642
701
|
* disagree. Dev-tier: in an observe build this is a no-op, so wiring paths
|
|
@@ -647,6 +706,7 @@ function reportDiagnostic(entry) {
|
|
|
647
706
|
if (suppressedEvents.has(entry)) return;
|
|
648
707
|
let text = entry.message;
|
|
649
708
|
if (entry.ownerPath) text += `\n in ${entry.ownerPath.join(" › ")}`;
|
|
709
|
+
if (entry.loc) text += `\n at ${locationLine(entry.loc)}`;
|
|
650
710
|
const footer = takeFooter(entry);
|
|
651
711
|
if (footer) text += `\n${footer}`;
|
|
652
712
|
const element = eventSubjects.get(entry)?._devElement;
|
|
@@ -1052,6 +1112,101 @@ function devCheckQuiescent(isQueuedForCommit) {
|
|
|
1052
1112
|
return;
|
|
1053
1113
|
}
|
|
1054
1114
|
|
|
1115
|
+
// Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
|
|
1116
|
+
// bundle that never imports the installing module never assigns them — its
|
|
1117
|
+
// minifier folds every guarded call site (and the branch behind it) away.
|
|
1118
|
+
// Each module installs its own set at evaluation (pay-for-use).
|
|
1119
|
+
//
|
|
1120
|
+
// Lanes (lanes.ts; installed when `createOptimistic` — or verdict.ts — is
|
|
1121
|
+
// imported; every call site is behind a bit or a `passLane` nothing else sets).
|
|
1122
|
+
let laneReadHook = null;
|
|
1123
|
+
let laneStageHook = null;
|
|
1124
|
+
let laneOutcomeHook = null;
|
|
1125
|
+
let laneWriteHook = null;
|
|
1126
|
+
let applyGuessesHook = null;
|
|
1127
|
+
let laneSeamsHook = null;
|
|
1128
|
+
let laneCorrectionsHook = null;
|
|
1129
|
+
let endLanesHook = null;
|
|
1130
|
+
let lanesBlockedHook = null;
|
|
1131
|
+
function installLaneHooks(
|
|
1132
|
+
read,
|
|
1133
|
+
stage,
|
|
1134
|
+
outcome,
|
|
1135
|
+
write,
|
|
1136
|
+
applyGuesses,
|
|
1137
|
+
seams,
|
|
1138
|
+
corrections,
|
|
1139
|
+
end,
|
|
1140
|
+
blocked
|
|
1141
|
+
) {
|
|
1142
|
+
laneReadHook = read;
|
|
1143
|
+
laneStageHook = stage;
|
|
1144
|
+
laneOutcomeHook = outcome;
|
|
1145
|
+
laneWriteHook = write;
|
|
1146
|
+
applyGuessesHook = applyGuesses;
|
|
1147
|
+
laneSeamsHook = seams;
|
|
1148
|
+
laneCorrectionsHook = corrections;
|
|
1149
|
+
endLanesHook = end;
|
|
1150
|
+
lanesBlockedHook = blocked;
|
|
1151
|
+
}
|
|
1152
|
+
// Boundaries (boundaries.ts): the display consumers between an observer
|
|
1153
|
+
// and the root. `catch` — status from a frame reader, nearest boundary
|
|
1154
|
+
// first (true: caught, the root never hears of it; a clear — flags 0 —
|
|
1155
|
+
// settles the reader there); `fresh` — a pass that read a hold (true: a
|
|
1156
|
+
// first pass a loading boundary that has not shown content caught,
|
|
1157
|
+
// `joinPass`; `held`: the flush's hold owns it, nothing catches it);
|
|
1158
|
+
// `hidden` — a frame reader behind a fallback (the boundary showing it)
|
|
1159
|
+
// is not on screen and holds nothing; `boundarySeam` — the seam's sweep (readers
|
|
1160
|
+
// gone or settled without a pass reveal; an `on` re-arm resolves);
|
|
1161
|
+
// `heldRun` — a queued run under a fallback-showing boundary waits for
|
|
1162
|
+
// the reveal (true: held; the boundary re-queues it by type). The
|
|
1163
|
+
// synchronous first render on creation builds the subtree, attached or
|
|
1164
|
+
// not; its updates and the user effects wait.
|
|
1165
|
+
let catchHook = null;
|
|
1166
|
+
let freshHook = null;
|
|
1167
|
+
let hiddenHook = null;
|
|
1168
|
+
let boundarySeamHook = null;
|
|
1169
|
+
let heldRunHook = null;
|
|
1170
|
+
function installBoundaryHooks(caught, fresh, hidden, seam, heldRun) {
|
|
1171
|
+
catchHook = caught;
|
|
1172
|
+
freshHook = fresh;
|
|
1173
|
+
hiddenHook = hidden;
|
|
1174
|
+
boundarySeamHook = seam;
|
|
1175
|
+
heldRunHook = heldRun;
|
|
1176
|
+
}
|
|
1177
|
+
/** Store (store/store.ts): `park` — the flush parked into `t`: the store
|
|
1178
|
+
* materializes and holds the container node of every staging that had none
|
|
1179
|
+
* (a staging needs the node as its home only when something can read the
|
|
1180
|
+
* frame through it; a hold can); `commit` — fold the pending backings whose
|
|
1181
|
+
* container nodes this flush committed (the owned-raw model's one mutation
|
|
1182
|
+
* point). */
|
|
1183
|
+
let storeParkHook = null;
|
|
1184
|
+
let storeCommitHook = null;
|
|
1185
|
+
function installStoreHooks(park, commit) {
|
|
1186
|
+
storeParkHook = park;
|
|
1187
|
+
storeCommitHook = commit;
|
|
1188
|
+
}
|
|
1189
|
+
/** `affects()` marks (affects.ts): the releases at a landing and at the seam
|
|
1190
|
+
* (ambient marks). */
|
|
1191
|
+
let releaseMarksHook = null;
|
|
1192
|
+
let releaseAmbientMarksHook = null;
|
|
1193
|
+
function installMarkHooks(release, releaseAmbient) {
|
|
1194
|
+
releaseMarksHook = release;
|
|
1195
|
+
releaseAmbientMarksHook = releaseAmbient;
|
|
1196
|
+
}
|
|
1197
|
+
/** Verdicts (verdict.ts). */
|
|
1198
|
+
let observeFlightHook = null;
|
|
1199
|
+
function installVerdictHooks(observeFlight) {
|
|
1200
|
+
observeFlightHook = observeFlight;
|
|
1201
|
+
}
|
|
1202
|
+
/** External-source bridge (wired by enableExternalSource(); undefined while
|
|
1203
|
+
* no config is active — including after _resetExternalSourceConfig()). */
|
|
1204
|
+
let wireExternalSourceHook = undefined;
|
|
1205
|
+
let externalUntrackHook = undefined;
|
|
1206
|
+
function setExternalHooks(wire, untrack) {
|
|
1207
|
+
wireExternalSourceHook = wire;
|
|
1208
|
+
externalUntrackHook = untrack;
|
|
1209
|
+
}
|
|
1055
1210
|
/** Live transactions — opened, unmerged, not landed. Scanned at every seam
|
|
1056
1211
|
* while non-empty; nothing on the plain path. */
|
|
1057
1212
|
const transactions = [];
|
|
@@ -1190,10 +1345,7 @@ function blocked(t) {
|
|
|
1190
1345
|
judge ??= t;
|
|
1191
1346
|
// An action still running in it holds it open (action.ts). Its lanes
|
|
1192
1347
|
// (lanes.ts): a lane under `t` blocks it while blocked itself.
|
|
1193
|
-
const r =
|
|
1194
|
-
t._open !== 0 ||
|
|
1195
|
-
blockedBy(t._nodes, t) ||
|
|
1196
|
-
(!!GlobalQueue._lanesBlocked && GlobalQueue._lanesBlocked(t));
|
|
1348
|
+
const r = t._open !== 0 || blockedBy(t._nodes, t) || !!lanesBlockedHook?.(t);
|
|
1197
1349
|
judge = prev;
|
|
1198
1350
|
return r;
|
|
1199
1351
|
}
|
|
@@ -1288,10 +1440,7 @@ function blockedBy(nodes, owner, own = false) {
|
|
|
1288
1440
|
* everything under it, so a reader there is not on screen and holds
|
|
1289
1441
|
* nothing — boundaries.ts). */
|
|
1290
1442
|
function onScreen(r, t) {
|
|
1291
|
-
return (
|
|
1292
|
-
!(r._flags & REACTIVE_ZOMBIE && removalStagedBy(r, t)) &&
|
|
1293
|
-
!(GlobalQueue._hidden && GlobalQueue._hidden(r))
|
|
1294
|
-
);
|
|
1443
|
+
return !(r._flags & REACTIVE_ZOMBIE && removalStagedBy(r, t)) && !hiddenHook?.(r);
|
|
1295
1444
|
}
|
|
1296
1445
|
/** A15 (#3463): a reader whose removal is staged — a zombie, parked by a
|
|
1297
1446
|
* pass awaiting its commit — is still on screen and live for every hold,
|
|
@@ -1301,13 +1450,8 @@ function onScreen(r, t) {
|
|
|
1301
1450
|
* the nearest non-zombie ancestor. */
|
|
1302
1451
|
function removalStagedBy(r, t) {
|
|
1303
1452
|
let o = r;
|
|
1304
|
-
while (o
|
|
1305
|
-
return (
|
|
1306
|
-
o !== null &&
|
|
1307
|
-
(o._config & CONFIG_HELD) !== 0 &&
|
|
1308
|
-
o._x?._transaction != null &&
|
|
1309
|
-
txOf(o) === resolveTx(t)
|
|
1310
|
-
);
|
|
1453
|
+
while (o?._flags & REACTIVE_ZOMBIE) o = o._parent;
|
|
1454
|
+
return o?._config & CONFIG_HELD && o._x?._transaction != null && txOf(o) === resolveTx(t);
|
|
1311
1455
|
}
|
|
1312
1456
|
/** Unchanged passes this flush whose stale dependency tail awaits the
|
|
1313
1457
|
* flush's verdict (A30, #3469): trimmed when the flush commits, kept when
|
|
@@ -1367,6 +1511,19 @@ function holdFrame(owner, t) {
|
|
|
1367
1511
|
holdFrame(c, t);
|
|
1368
1512
|
}
|
|
1369
1513
|
}
|
|
1514
|
+
/** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
|
|
1515
|
+
* what an earlier hold staged under a re-armed boundary). */
|
|
1516
|
+
function heldUnder(owner, t, fn) {
|
|
1517
|
+
for (let c = owner._firstChild; c !== null; c = c._nextSibling) {
|
|
1518
|
+
if ((c._config & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(c) !== t) fn(c);
|
|
1519
|
+
heldUnder(c, t, fn);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
/** `n` leaves the hold it was staged in: its next pass publishes mainline. */
|
|
1523
|
+
function unhold(n) {
|
|
1524
|
+
n._x._transaction = null;
|
|
1525
|
+
n._config &= ~CONFIG_HELD;
|
|
1526
|
+
}
|
|
1370
1527
|
const dirtyQueue = {
|
|
1371
1528
|
_heap: new Array(2000).fill(undefined),
|
|
1372
1529
|
_marked: false,
|
|
@@ -1559,7 +1716,7 @@ class GlobalQueue {
|
|
|
1559
1716
|
// Lanes: an ended action body judges its guesses now that their passes
|
|
1560
1717
|
// have run (lanes.ts); a correction's re-derivations run in one more
|
|
1561
1718
|
// pure round — the parent's flights before the parent is judged below.
|
|
1562
|
-
if (
|
|
1719
|
+
if (laneCorrectionsHook?.()) runHeap(dirtyQueue, GlobalQueue._update);
|
|
1563
1720
|
const joined = flushTransaction;
|
|
1564
1721
|
flushTransaction = null;
|
|
1565
1722
|
// The frame's verdict is in: the guesses written since the last seam
|
|
@@ -1567,7 +1724,7 @@ class GlobalQueue {
|
|
|
1567
1724
|
// parents a nested lane to it), or are dropped — the frame commits, and
|
|
1568
1725
|
// there is nothing to be optimistic over. Their passes run next round;
|
|
1569
1726
|
// a parent landing at this very seam ends the lane before they do.
|
|
1570
|
-
|
|
1727
|
+
applyGuessesHook?.(joined);
|
|
1571
1728
|
// A lane's own flush (its flight landing, its reveal) parks nothing: the
|
|
1572
1729
|
// lane's work reached it per pass; the frame's plain writes commit.
|
|
1573
1730
|
// (Resolved: a guess over another transaction's guess merged them.)
|
|
@@ -1607,10 +1764,12 @@ class GlobalQueue {
|
|
|
1607
1764
|
if (
|
|
1608
1765
|
n._pendingValue !== NOT_PENDING &&
|
|
1609
1766
|
!(n._statusFlags & (STATUS_PENDING | STATUS_UNINITIALIZED)) &&
|
|
1610
|
-
n._equals &&
|
|
1611
|
-
n._equals(n._value, n._pendingValue) &&
|
|
1612
1767
|
n._x?._pendingFirstChild == null &&
|
|
1613
|
-
n._x?._pendingDisposal == null
|
|
1768
|
+
n._x?._pendingDisposal == null &&
|
|
1769
|
+
// The comparator last: a pass that created children (an object
|
|
1770
|
+
// owning a fresh async memo, #4111) must not have it read them.
|
|
1771
|
+
// A NotReady read there is a change (`isSame`).
|
|
1772
|
+
isSame(n, n._value, n._pendingValue)
|
|
1614
1773
|
) {
|
|
1615
1774
|
n._pendingValue = NOT_PENDING;
|
|
1616
1775
|
n._config &= ~CONFIG_STAGED;
|
|
@@ -1624,7 +1783,7 @@ class GlobalQueue {
|
|
|
1624
1783
|
if (n._config & CONFIG_STAGED) holdFrame(n, t);
|
|
1625
1784
|
}
|
|
1626
1785
|
pendingNodes.length = 0;
|
|
1627
|
-
|
|
1786
|
+
storeParkHook?.(t);
|
|
1628
1787
|
// (This flush's runs are stashed with `t` below — after the landings,
|
|
1629
1788
|
// so a `t` that lands at this very seam runs them first, ahead of
|
|
1630
1789
|
// the runs it held from earlier flushes.)
|
|
@@ -1634,13 +1793,17 @@ class GlobalQueue {
|
|
|
1634
1793
|
// through like the same read outside): it re-runs now, as the
|
|
1635
1794
|
// holder's verdict lane's work — before the lane seams, which reveal
|
|
1636
1795
|
// it (nothing commits this seam that could dispose it).
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1796
|
+
// (Verdict readers exist only with the verdict engine installed.)
|
|
1797
|
+
const zombies = deferredZombies.splice(0);
|
|
1798
|
+
if (observeFlightHook) {
|
|
1799
|
+
zombies.sort((a, b) => a._height - b._height);
|
|
1800
|
+
for (let i = 0; i < zombies.length; i++)
|
|
1801
|
+
if (
|
|
1802
|
+
(zombies[i]._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE &&
|
|
1803
|
+
zombies[i]._config & CONFIG_VERDICT
|
|
1804
|
+
)
|
|
1805
|
+
recompute(zombies[i]);
|
|
1806
|
+
}
|
|
1644
1807
|
// The unchanged passes' tails stay linked (A30, #3469): their inputs
|
|
1645
1808
|
// are held, and the committed frame still derives from them — no trim.
|
|
1646
1809
|
} else {
|
|
@@ -1671,14 +1834,16 @@ class GlobalQueue {
|
|
|
1671
1834
|
// The passes that read this frame's stagings as the screen read held
|
|
1672
1835
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
1673
1836
|
// world (a lane's runs wait this round).
|
|
1674
|
-
|
|
1675
|
-
|
|
1837
|
+
if (laneSeamsHook) {
|
|
1838
|
+
laneSeamsHook(t !== null ? stagedReaders : null);
|
|
1839
|
+
if (stagedReaders.length) stagedReaders.length = 0;
|
|
1840
|
+
}
|
|
1676
1841
|
this._queues = [[], []];
|
|
1677
1842
|
for (let k = transactions.length - 1; k >= 0; k--) {
|
|
1678
1843
|
const u = transactions[k];
|
|
1679
1844
|
if (blocked(u)) continue;
|
|
1680
1845
|
transactions.splice(k, 1);
|
|
1681
|
-
|
|
1846
|
+
endLanesHook?.(u);
|
|
1682
1847
|
land(u);
|
|
1683
1848
|
// A landing's commits can dispose a zombie a transaction judged above
|
|
1684
1849
|
// was blocked on (#3463: live "until the commit that disposes it") —
|
|
@@ -1687,13 +1852,13 @@ class GlobalQueue {
|
|
|
1687
1852
|
}
|
|
1688
1853
|
// The store folds the pending backings whose container nodes committed
|
|
1689
1854
|
// — this flush's, or a landing's (store/store.ts installs it).
|
|
1690
|
-
|
|
1855
|
+
storeCommitHook?.();
|
|
1691
1856
|
// Marks declared outside a transaction: the flush that carried them
|
|
1692
1857
|
// parked (something async below) — the window is the frame's, the marks
|
|
1693
1858
|
// are its transaction's; else they release at the seam, verdict-only,
|
|
1694
1859
|
// nothing to show (affects.ts).
|
|
1695
1860
|
const live = t && liveTx(t);
|
|
1696
|
-
|
|
1861
|
+
releaseAmbientMarksHook?.(live);
|
|
1697
1862
|
// The effect phase: lane work first (displayed ahead of the frame), then
|
|
1698
1863
|
// this flush's runs, then the runs the landings held from earlier
|
|
1699
1864
|
// flushes — as one pass would have queued them (#3540: a shell
|
|
@@ -1731,7 +1896,7 @@ class GlobalQueue {
|
|
|
1731
1896
|
}
|
|
1732
1897
|
// Boundaries: readers that settled, landed or died this flush are
|
|
1733
1898
|
// dropped; a fallback with none left reveals next round.
|
|
1734
|
-
|
|
1899
|
+
boundarySeamHook?.();
|
|
1735
1900
|
}
|
|
1736
1901
|
run(type) {
|
|
1737
1902
|
const effects = this._queues[type - 1];
|
|
@@ -1763,7 +1928,7 @@ class GlobalQueue {
|
|
|
1763
1928
|
* first: a fallback catches what is not ready under it, and the root
|
|
1764
1929
|
* never hears of it. */
|
|
1765
1930
|
notify(node, mask, flags, error) {
|
|
1766
|
-
if (
|
|
1931
|
+
if (catchHook?.(node, flags & mask, error)) return true;
|
|
1767
1932
|
if (mask & STATUS_PENDING) {
|
|
1768
1933
|
if (flags & STATUS_PENDING) {
|
|
1769
1934
|
if (_enforceLoadingBoundary) _hitUnhandledAsync = true;
|
|
@@ -1822,7 +1987,7 @@ function land(u) {
|
|
|
1822
1987
|
// (`_nodes` still lists them).
|
|
1823
1988
|
if (attrHooks !== null) attrHooks.transitionSettled(u);
|
|
1824
1989
|
reruns(u);
|
|
1825
|
-
if (u._marks !== null)
|
|
1990
|
+
if (u._marks !== null) releaseMarksHook(u._marks);
|
|
1826
1991
|
// Old children die in the commits (cleanups first), then the stashed
|
|
1827
1992
|
// effects run ahead of this flush's own. A node a lane took over since
|
|
1828
1993
|
// (a guess written over the staged truth) is the lane's to land.
|
|
@@ -1832,6 +1997,10 @@ function land(u) {
|
|
|
1832
1997
|
n._x._transaction = null;
|
|
1833
1998
|
commitPendingNode(n);
|
|
1834
1999
|
}
|
|
2000
|
+
// A cleanup those commits ran that wrote a node `u` still held joined
|
|
2001
|
+
// `u`, which has left `transactions`: the write is this landing's, and
|
|
2002
|
+
// the next flush must not park in it (#4089).
|
|
2003
|
+
if (flushTransaction === u) flushTransaction = null;
|
|
1835
2004
|
releaseQueues(u);
|
|
1836
2005
|
}
|
|
1837
2006
|
/** The held runs join this flush's effect phase after its own runs (the
|
|
@@ -1951,8 +2120,20 @@ function commitPendingNode(n) {
|
|
|
1951
2120
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
1952
2121
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
1953
2122
|
const inFlight = n._pendingValue === NOT_PENDING && (c._statusFlags & STATUS_PENDING) !== 0;
|
|
1954
|
-
|
|
1955
|
-
|
|
2123
|
+
const err = n._config & CONFIG_STAGED_ERROR;
|
|
2124
|
+
// An answer commits: the error it replaces leaves the display (D-41).
|
|
2125
|
+
if (!inFlight && c._x) c._x._shownError = undefined;
|
|
2126
|
+
n._config = inFlight ? (n._config & -1048833) | CONFIG_INPUTS_PUBLISHED : n._config & -3147137;
|
|
2127
|
+
// D-41: the staged answer is an error — published now, when a value would
|
|
2128
|
+
// show, through the ordinary error path (`stageError`). Its readers first
|
|
2129
|
+
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
2130
|
+
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
2131
|
+
if (err) {
|
|
2132
|
+
const e = n._pendingValue;
|
|
2133
|
+
n._pendingValue = NOT_PENDING;
|
|
2134
|
+
n._time = clock + 1;
|
|
2135
|
+
notifyStatus(c, STATUS_ERROR, e);
|
|
2136
|
+
} else if (n._pendingValue !== NOT_PENDING) {
|
|
1956
2137
|
n._value = n._pendingValue;
|
|
1957
2138
|
n._pendingValue = NOT_PENDING;
|
|
1958
2139
|
// A node born staged (recompute) initializes at this commit.
|
|
@@ -2443,13 +2624,15 @@ function getOwner() {
|
|
|
2443
2624
|
/**
|
|
2444
2625
|
* Low-level: registers `fn` as a disposal callback on the current owner.
|
|
2445
2626
|
* Most code should use `onCleanup()` from `solid-js`, which adds dev-mode
|
|
2446
|
-
* checks. `cleanup()` is the unchecked primitive used by internals
|
|
2627
|
+
* checks. `cleanup()` is the unchecked primitive used by internals; `owner`
|
|
2628
|
+
* (internal) targets a specific owner's disposal list instead of the ambient
|
|
2629
|
+
* one.
|
|
2447
2630
|
*/
|
|
2448
|
-
function cleanup(fn) {
|
|
2449
|
-
if (!
|
|
2450
|
-
if (!
|
|
2451
|
-
else if (Array.isArray(
|
|
2452
|
-
else
|
|
2631
|
+
function cleanup(fn, owner = context) {
|
|
2632
|
+
if (!owner) return fn;
|
|
2633
|
+
if (!owner._disposal) owner._disposal = fn;
|
|
2634
|
+
else if (Array.isArray(owner._disposal)) owner._disposal.push(fn);
|
|
2635
|
+
else owner._disposal = [owner._disposal, fn];
|
|
2453
2636
|
return fn;
|
|
2454
2637
|
}
|
|
2455
2638
|
/**
|
|
@@ -2486,12 +2669,18 @@ function createOwner(options) {
|
|
|
2486
2669
|
const parent = context;
|
|
2487
2670
|
const transparent = options?.transparent ?? false;
|
|
2488
2671
|
// Prod and observe boilerplates (see core.ts computed()). The observe
|
|
2489
|
-
// literal carries the `_name`
|
|
2490
|
-
// component label (`owner._name = "<App>"
|
|
2491
|
-
//
|
|
2672
|
+
// literal carries the `_name` and `_loc` slots the rendering layer fills
|
|
2673
|
+
// with the component label and JSX site (`owner._name = "<App>"`,
|
|
2674
|
+
// `owner._loc = "src/App.tsx:3:5"`) — slots, so labelling a root is a
|
|
2675
|
+
// plain store rather than a shape fork between labelled and plain roots.
|
|
2492
2676
|
const owner = {
|
|
2493
2677
|
id: inheritId(options, transparent, parent),
|
|
2494
2678
|
_config: transparent ? CONFIG_TRANSPARENT : 0,
|
|
2679
|
+
// Present from birth: disposeChildren marks death here on roots too, and
|
|
2680
|
+
// a first store of a missing property is a shape transition plus a
|
|
2681
|
+
// properties-store allocation per root — on a 100×4 table teardown that
|
|
2682
|
+
// was 12 KB and most of disposal's time (2026-10-17).
|
|
2683
|
+
_flags: REACTIVE_NONE,
|
|
2495
2684
|
_root: true,
|
|
2496
2685
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
2497
2686
|
_firstChild: null,
|
|
@@ -2503,7 +2692,8 @@ function createOwner(options) {
|
|
|
2503
2692
|
_x: null,
|
|
2504
2693
|
_parent: parent,
|
|
2505
2694
|
dispose: disposeRootSelf,
|
|
2506
|
-
_name: undefined
|
|
2695
|
+
_name: undefined,
|
|
2696
|
+
_loc: undefined
|
|
2507
2697
|
};
|
|
2508
2698
|
if (parent && parent._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
2509
2699
|
emitDiagnostic({
|
|
@@ -2555,11 +2745,14 @@ function createOwner(options) {
|
|
|
2555
2745
|
* const detached = runWithOwner(null, () => createRoot(d => d));
|
|
2556
2746
|
* ```
|
|
2557
2747
|
*
|
|
2558
|
-
* @description https://
|
|
2748
|
+
* @description https://v2.solidjs.com/reference/solid-js/advanced/owner-introspection/create-root
|
|
2559
2749
|
*/
|
|
2560
2750
|
function createRoot(init, options) {
|
|
2561
2751
|
const owner = createOwner(options);
|
|
2562
|
-
|
|
2752
|
+
// A bound function, not an arrow: an arrow would share this scope, which
|
|
2753
|
+
// holds `init`, so keeping `dispose` would keep `init` and all it closes
|
|
2754
|
+
// over alive (#4095).
|
|
2755
|
+
return runWithOwner(owner, () => init(disposeRootSelf.bind(owner, true)));
|
|
2563
2756
|
}
|
|
2564
2757
|
|
|
2565
2758
|
/** The store's shared slot-node release handler (store/store.ts installs it
|
|
@@ -2592,12 +2785,14 @@ function unlinkSubs(link) {
|
|
|
2592
2785
|
// read. The settle path runs this same last-one-out check when that
|
|
2593
2786
|
// observer releases (the untracked-read dormancy sweep guards on
|
|
2594
2787
|
// pending identically).
|
|
2788
|
+
// During a pass's teardown of its unfinished frame, the release waits
|
|
2789
|
+
// for the pass to end (`deferredReleases`, #4142).
|
|
2595
2790
|
const c = dep;
|
|
2596
2791
|
c._fn &&
|
|
2597
2792
|
c._config & CONFIG_AUTO_DISPOSE &&
|
|
2598
2793
|
!(c._flags & REACTIVE_ZOMBIE) &&
|
|
2599
2794
|
!(c._statusFlags & STATUS_PENDING) &&
|
|
2600
|
-
unobserved(c);
|
|
2795
|
+
(deferredReleases ? deferredReleases.push(c) : unobserved(c));
|
|
2601
2796
|
}
|
|
2602
2797
|
}
|
|
2603
2798
|
return nextDep;
|
|
@@ -2626,6 +2821,17 @@ function clearDeps(el) {
|
|
|
2626
2821
|
el._deps = null;
|
|
2627
2822
|
el._depsTail = null;
|
|
2628
2823
|
}
|
|
2824
|
+
/**
|
|
2825
|
+
* Last-one-out releases held back while a pass tears down the frame of an
|
|
2826
|
+
* earlier pass that never committed (#4142). The pass is about to rebuild
|
|
2827
|
+
* the same children, which read the same lazy nodes again. Released on the
|
|
2828
|
+
* spot, a lazy async memo whose only reader was the old frame's child memo
|
|
2829
|
+
* was torn down, re-ran on the new child's read, went pending, and the cycle
|
|
2830
|
+
* repeated forever. `recompute` collects them around that teardown and
|
|
2831
|
+
* releases what is still unobserved when the pass ends.
|
|
2832
|
+
*/
|
|
2833
|
+
let deferredReleases = null;
|
|
2834
|
+
const deferReleases = list => (deferredReleases = list);
|
|
2629
2835
|
function unobserved(el) {
|
|
2630
2836
|
deleteFromHeap(el, dirtyQueue);
|
|
2631
2837
|
clearDeps(el);
|
|
@@ -2827,6 +3033,43 @@ function releaseSettledDependents(el) {
|
|
|
2827
3033
|
// (releaseSettledDependents shape): identity holders can sit below an
|
|
2828
3034
|
// intermediate whose own error state has since been scrubbed or replaced
|
|
2829
3035
|
// (e.g. an error boundary's tree node).
|
|
3036
|
+
/** D-41: an error a pass of a held node found is an answer of
|
|
3037
|
+
* that frame — it ends the wait like a value and shows when a value would.
|
|
3038
|
+
* Staged like one: `_pendingValue` carries it (CONFIG_STAGED_ERROR), readers
|
|
3039
|
+
* in the hold derive from it (`serve` throws it), and the commit publishes
|
|
3040
|
+
* it through the ordinary error path (`commitPendingNode` → `notifyStatus`),
|
|
3041
|
+
* dependents included. Not for a lane pass, nor a node with no shown value
|
|
3042
|
+
* (born held — its error has no frame to wait behind): those publish now,
|
|
3043
|
+
* as before. Returns whether the error was staged. */
|
|
3044
|
+
function stageError(el, error, inPass) {
|
|
3045
|
+
// Held, or — for a pass's own throw — derived from a staging of a flush
|
|
3046
|
+
// (REACTIVE_STAGED_READ is this pass's; a landing after the pass cannot
|
|
3047
|
+
// read it, the flush it read a staging of has committed or parked since).
|
|
3048
|
+
// Staged whether or not the flush has joined a hold yet: a pass that runs
|
|
3049
|
+
// before its async sibling joins is the seam's to decide, like a value
|
|
3050
|
+
// (#4109). A flush that parks nothing publishes it at its commit (S-38).
|
|
3051
|
+
if (
|
|
3052
|
+
!(
|
|
3053
|
+
el._config & CONFIG_HELD ||
|
|
3054
|
+
(inPass && el._flags & REACTIVE_STAGED_READ && globalQueue._running)
|
|
3055
|
+
) ||
|
|
3056
|
+
passLane
|
|
3057
|
+
)
|
|
3058
|
+
return false;
|
|
3059
|
+
// The node answered (an error ends the wait — no longer pending, nor
|
|
3060
|
+
// blocked); a shown error stays its display until the commit.
|
|
3061
|
+
clearPendingSources(el);
|
|
3062
|
+
if (el._x) el._x._blocked = false;
|
|
3063
|
+
if (!((el._statusFlags &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR))
|
|
3064
|
+
setPendingError(el);
|
|
3065
|
+
el._pendingValue = error instanceof StatusError ? error : new StatusError(el, error);
|
|
3066
|
+
el._config |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
|
|
3067
|
+
// Readers parked on the flight re-run and derive from the staging; the
|
|
3068
|
+
// verdict readers the walk wakes need a flush (#4106).
|
|
3069
|
+
settlePendingSource(el);
|
|
3070
|
+
schedule();
|
|
3071
|
+
return true;
|
|
3072
|
+
}
|
|
2830
3073
|
function settleErroredDependents(el, error) {
|
|
2831
3074
|
let scheduled = false;
|
|
2832
3075
|
const visited = new Set();
|
|
@@ -3073,7 +3316,11 @@ function handleAsync(
|
|
|
3073
3316
|
el._time = clock;
|
|
3074
3317
|
return;
|
|
3075
3318
|
}
|
|
3076
|
-
|
|
3319
|
+
// D-41: a held node's error is staged (`stageError`). A derived store's
|
|
3320
|
+
// readers learn its error through the family, not the derive's
|
|
3321
|
+
// dependents: it publishes now.
|
|
3322
|
+
if (stillPending || setter || !stageError(el, error))
|
|
3323
|
+
notifyStatus(el, stillPending ? STATUS_PENDING : STATUS_ERROR, error);
|
|
3077
3324
|
// A NotReady rejection is a landing into another pending source. The
|
|
3078
3325
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
3079
3326
|
// after notifyStatus has propagated the replacement source.
|
|
@@ -3091,7 +3338,7 @@ function handleAsync(
|
|
|
3091
3338
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
3092
3339
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
3093
3340
|
if (el._flags & REACTIVE_DIRTY) return;
|
|
3094
|
-
const wasUninitialized =
|
|
3341
|
+
const wasUninitialized = el._statusFlags & STATUS_UNINITIALIZED;
|
|
3095
3342
|
landStatus(el);
|
|
3096
3343
|
// Attribution hook: lets the engine snapshot state before the landing
|
|
3097
3344
|
// branches, so it can tell whether the plain path's setSignal committed a
|
|
@@ -3104,6 +3351,9 @@ function handleAsync(
|
|
|
3104
3351
|
handleError(error);
|
|
3105
3352
|
return;
|
|
3106
3353
|
}
|
|
3354
|
+
// A store derive's landing commits through its setter: unheld, the
|
|
3355
|
+
// shown error leaves now; held, at the derive's commit.
|
|
3356
|
+
if (!(el._config & CONFIG_HELD)) el._x._shownError = undefined;
|
|
3107
3357
|
if (wasUninitialized) landStatus(el, true);
|
|
3108
3358
|
// Attribution hook: this path landed through the setter (derived
|
|
3109
3359
|
// stores, projections), which does not go through setSignal, so the
|
|
@@ -3119,14 +3369,9 @@ function handleAsync(
|
|
|
3119
3369
|
// CARVE 2: the override-covered landing (hold + A18 supersession) and the
|
|
3120
3370
|
// lane-routed landing (derived override, lane effect queue) went with
|
|
3121
3371
|
// the optimistic engine; every landing is the plain setSignal. A node
|
|
3122
|
-
// already held stages its answer into that hold (`setSignal`).
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
} catch (e) {
|
|
3126
|
-
// Same containment as above: setSignal's comparator throw is the only
|
|
3127
|
-
// pre-commit failure here, and there is no user callsite to throw to.
|
|
3128
|
-
notifyStatus(el, STATUS_ERROR, e);
|
|
3129
|
-
}
|
|
3372
|
+
// already held stages its answer into that hold (`setSignal`). Its
|
|
3373
|
+
// comparator throw is contained there (`isSame`, A3).
|
|
3374
|
+
setSignal(el, () => value);
|
|
3130
3375
|
// Attribution hook: this path landed through setSignal, whose write
|
|
3131
3376
|
// hook already saw any committed change — direct=false lets the engine
|
|
3132
3377
|
// reclassify that write as an async landing iff it actually committed.
|
|
@@ -3171,15 +3416,14 @@ function handleAsync(
|
|
|
3171
3416
|
// close registration uses the ambient owner; and DEFERRED (the flattening
|
|
3172
3417
|
// path — a thenable resolved to an iterable in a later microtask), where
|
|
3173
3418
|
// there is no caller to serve and no ambient owner: sync-settled steps
|
|
3174
|
-
// write through asyncWrite, and close registration
|
|
3175
|
-
//
|
|
3176
|
-
//
|
|
3177
|
-
|
|
3178
|
-
const consumeIterator = (source, registerClose) => {
|
|
3419
|
+
// write through asyncWrite, and close registration targets `owner` (el
|
|
3420
|
+
// itself) directly. Returns whether a sync answer landed (first yield or
|
|
3421
|
+
// empty completion) — meaningful only in the live posture.
|
|
3422
|
+
const consumeIterator = (source, owner) => {
|
|
3179
3423
|
const it = source[Symbol.asyncIterator]();
|
|
3180
3424
|
let hadValue = false;
|
|
3181
3425
|
let completed = false;
|
|
3182
|
-
let initialRead = !
|
|
3426
|
+
let initialRead = !owner;
|
|
3183
3427
|
const close = () => {
|
|
3184
3428
|
if (completed) return;
|
|
3185
3429
|
completed = true;
|
|
@@ -3188,7 +3432,7 @@ function handleAsync(
|
|
|
3188
3432
|
if (isThenable(returned)) returned.then(undefined, () => {});
|
|
3189
3433
|
} catch {}
|
|
3190
3434
|
};
|
|
3191
|
-
|
|
3435
|
+
cleanup(close, owner);
|
|
3192
3436
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
3193
3437
|
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
3194
3438
|
// sites so supersede stops this stream immediately.
|
|
@@ -3196,8 +3440,15 @@ function handleAsync(
|
|
|
3196
3440
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
3197
3441
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
3198
3442
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
3443
|
+
// Later pulls run from an async continuation with no compute catch above
|
|
3444
|
+
// them: a throw invoking the protocol (next(), the step's then) settles
|
|
3445
|
+
// as this flight's error instead of escaping as a rejection (#4112).
|
|
3199
3446
|
const iterateOrRelease = () => {
|
|
3200
|
-
|
|
3447
|
+
try {
|
|
3448
|
+
if (!settleAutodispose()) iterate();
|
|
3449
|
+
} catch (e) {
|
|
3450
|
+
handleError(e);
|
|
3451
|
+
}
|
|
3201
3452
|
};
|
|
3202
3453
|
const iterate = () => {
|
|
3203
3454
|
let syncResult,
|
|
@@ -3282,7 +3533,7 @@ function handleAsync(
|
|
|
3282
3533
|
// stream itself rather than settling on the iterable object. One level
|
|
3283
3534
|
// only: A+ `then` already collapses nested thenables, so the resolved
|
|
3284
3535
|
// value is never itself a thenable.
|
|
3285
|
-
const flattenIfIterable = (value,
|
|
3536
|
+
const flattenIfIterable = (value, owner) => {
|
|
3286
3537
|
let innerIterator = false;
|
|
3287
3538
|
if (typeof value === "object" && value !== null) {
|
|
3288
3539
|
untrack(() => {
|
|
@@ -3290,8 +3541,9 @@ function handleAsync(
|
|
|
3290
3541
|
});
|
|
3291
3542
|
}
|
|
3292
3543
|
if (!innerIterator) return false;
|
|
3293
|
-
|
|
3294
|
-
|
|
3544
|
+
syncValue = undefined;
|
|
3545
|
+
const landed = consumeIterator(value, owner);
|
|
3546
|
+
if (!owner) liveLanded = landed;
|
|
3295
3547
|
return true;
|
|
3296
3548
|
};
|
|
3297
3549
|
if (thenable) {
|
|
@@ -3299,29 +3551,32 @@ function handleAsync(
|
|
|
3299
3551
|
rejected = false,
|
|
3300
3552
|
syncError,
|
|
3301
3553
|
isSync = true;
|
|
3302
|
-
// Close registration for the flattening path. Consumption starts in a
|
|
3303
|
-
// microtask where the ambient owner is gone (or worse, someone else's),
|
|
3304
|
-
// so `cleanup()` can't be used — the close targets el's disposal list
|
|
3305
|
-
// directly, exactly where a live cleanup() during this recompute would
|
|
3306
|
-
// have put it. Only a flight that actually flattens becomes
|
|
3307
|
-
// disposal-bearing.
|
|
3308
|
-
const registerDeferredClose = fn => {
|
|
3309
|
-
if (!el._disposal) el._disposal = fn;
|
|
3310
|
-
else if (Array.isArray(el._disposal)) el._disposal.push(fn);
|
|
3311
|
-
else el._disposal = [el._disposal, fn];
|
|
3312
|
-
};
|
|
3313
3554
|
watchAsyncTail(el, result).then(
|
|
3314
3555
|
v => {
|
|
3315
3556
|
if (isSync) {
|
|
3316
3557
|
syncValue = v;
|
|
3317
3558
|
resolved = true;
|
|
3318
|
-
} else
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3559
|
+
} else {
|
|
3560
|
+
// Flattening consumes the stream as the value: each yield lands
|
|
3561
|
+
// through asyncWrite under this flight's identity; the first one
|
|
3562
|
+
// clears pending exactly like a plain promise resolution would.
|
|
3563
|
+
// Disposed nodes never start a pump (their disposal list already
|
|
3564
|
+
// ran, so nothing could close the iterator). Consumption starts in
|
|
3565
|
+
// a microtask where the ambient owner is gone, so the close
|
|
3566
|
+
// registers on el's own disposal list. Iterator setup here has no
|
|
3567
|
+
// compute catch above it: a protocol throw settles as this
|
|
3568
|
+
// flight's error (#4112).
|
|
3569
|
+
try {
|
|
3570
|
+
if (
|
|
3571
|
+
el._x?._inFlight === result &&
|
|
3572
|
+
!(el._flags & REACTIVE_DISPOSED) &&
|
|
3573
|
+
flattenIfIterable(v, el)
|
|
3574
|
+
)
|
|
3575
|
+
return;
|
|
3576
|
+
asyncWrite(v);
|
|
3577
|
+
} catch (e) {
|
|
3578
|
+
handleError(e);
|
|
3579
|
+
}
|
|
3325
3580
|
settleAutodispose();
|
|
3326
3581
|
}
|
|
3327
3582
|
},
|
|
@@ -3425,6 +3680,8 @@ function notifyStatus(el, status, error, blockStatus) {
|
|
|
3425
3680
|
// (CARVE 2: the lane assignment went with the engine.)
|
|
3426
3681
|
{
|
|
3427
3682
|
if (status === STATUS_PENDING && pendingSource) {
|
|
3683
|
+
// D-41: a re-ask of a shown error keeps it the display (`_shownError`).
|
|
3684
|
+
if (el._statusFlags & STATUS_ERROR) el._x._shownError = el._x._error;
|
|
3428
3685
|
addPendingSource(el, pendingSource);
|
|
3429
3686
|
el._statusFlags = STATUS_PENDING | (el._statusFlags & STATUS_UNINITIALIZED);
|
|
3430
3687
|
// Preserve the current source on this propagation so readers park on
|
|
@@ -3504,7 +3761,8 @@ function propagateStatus(el, status, error, downstreamBlockStatus) {
|
|
|
3504
3761
|
if (
|
|
3505
3762
|
passLane === null &&
|
|
3506
3763
|
(sub._config & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD &&
|
|
3507
|
-
globalQueue._running
|
|
3764
|
+
globalQueue._running &&
|
|
3765
|
+
!freshHook?.(sub, pendingSource._time === clock)
|
|
3508
3766
|
)
|
|
3509
3767
|
joinFuture(txOf(sub));
|
|
3510
3768
|
return;
|
|
@@ -3519,7 +3777,7 @@ function propagateStatus(el, status, error, downstreamBlockStatus) {
|
|
|
3519
3777
|
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
3520
3778
|
{
|
|
3521
3779
|
// (No answer: a pending propagation leaves a written guess a guess.)
|
|
3522
|
-
if (passLane !== null)
|
|
3780
|
+
if (laneStageHook && passLane !== null) laneStageHook(sub, passLane, true, el);
|
|
3523
3781
|
else {
|
|
3524
3782
|
queuePendingNode(sub);
|
|
3525
3783
|
// A15 (#3443): pending propagates onto a held memo without
|
|
@@ -3561,8 +3819,29 @@ GlobalQueue._update = el => {
|
|
|
3561
3819
|
// (REACTIVE_LANE_DIRTY — a lane shows ahead of any park): it runs now, as
|
|
3562
3820
|
// the lane's work, for the reveal this seam (#3463).
|
|
3563
3821
|
else if (el._flags & REACTIVE_ZOMBIE && !(el._flags & REACTIVE_LANE_DIRTY)) deferZombie(el);
|
|
3564
|
-
|
|
3822
|
+
// A lane frame's member (parked by a lane pass, #3698) follows mainline
|
|
3823
|
+
// writes only: a lane's dirty on it is cancelled — the lane's apply retires
|
|
3824
|
+
// it, and the pass that replaced it already decided what that screen shows
|
|
3825
|
+
// (#4137: a `<Show>` branch withdrawn by its own lane re-ran on a falsy
|
|
3826
|
+
// condition).
|
|
3827
|
+
// (Lanes exist only with the lane engine installed: folded away without.)
|
|
3828
|
+
else if (laneStageHook && el._flags & REACTIVE_ZOMBIE && laneFrameMember(el)) {
|
|
3829
|
+
deleteFromHeap(el, dirtyQueue);
|
|
3830
|
+
el._flags &= -65540;
|
|
3831
|
+
} else recompute(el);
|
|
3565
3832
|
};
|
|
3833
|
+
/** The zombie's frame was parked by lane work: the nearest non-zombie owner
|
|
3834
|
+
* (the one whose pass parked it) carries a lane's derived value — or, an
|
|
3835
|
+
* effect (no lane value: `laneStage`), is listed in a lane (an `insert()`
|
|
3836
|
+
* hole's render effect). */
|
|
3837
|
+
function laneFrameMember(el) {
|
|
3838
|
+
let o = el._parent;
|
|
3839
|
+
while (o._flags & REACTIVE_ZOMBIE) o = o._parent;
|
|
3840
|
+
return (
|
|
3841
|
+
(o._config & (CONFIG_OVERRIDE | CONFIG_GUESS)) === CONFIG_OVERRIDE ||
|
|
3842
|
+
(o._type && o._x?._transaction?._lane)
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3566
3845
|
GlobalQueue._dispose = disposeChildren;
|
|
3567
3846
|
const PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE =
|
|
3568
3847
|
"[PRIMITIVE_IN_FORBIDDEN_SCOPE] Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled";
|
|
@@ -3597,6 +3876,10 @@ const REACTIVE_WRITE_IN_OWNED_SCOPE_REFRESH_MESSAGE =
|
|
|
3597
3876
|
let tracking = false;
|
|
3598
3877
|
let context = null;
|
|
3599
3878
|
let snapshotCaptureActive = false;
|
|
3879
|
+
/** The lane at the root of the running chain of first passes: the lane whose
|
|
3880
|
+
* pass created the chain's first node (a mount), inherited by every first
|
|
3881
|
+
* pass nested under it, whose seats are mainline (`recompute`, #4166). */
|
|
3882
|
+
let laneRoot;
|
|
3600
3883
|
let snapshotSources = null;
|
|
3601
3884
|
function ownerInSnapshotScope(owner) {
|
|
3602
3885
|
while (owner) {
|
|
@@ -3656,6 +3939,7 @@ function recompute(el, create = false) {
|
|
|
3656
3939
|
// §12d: any recompute can clean a marked subscriber — invalidate skips.
|
|
3657
3940
|
bumpNotifyEpoch();
|
|
3658
3941
|
const isEffect = el._type;
|
|
3942
|
+
let released;
|
|
3659
3943
|
// Lanes (plan sec. 28): the seat of a pass is its node's. A node carrying a lane's
|
|
3660
3944
|
// derived value runs as the lane's whoever dirtied it — a sync write, a
|
|
3661
3945
|
// boundary reset, a frame rerun — so its children and its result are the
|
|
@@ -3671,18 +3955,27 @@ function recompute(el, create = false) {
|
|
|
3671
3955
|
// derivation's pass into the lane (`read`); a leaf's never moves.
|
|
3672
3956
|
// Restored at the end, after this pass's staging and runs have been
|
|
3673
3957
|
// routed.
|
|
3958
|
+
// Lanes exist only with the lane engine installed (`laneStageHook`): a
|
|
3959
|
+
// bundle without it seats every pass on mainline, and folds the seat away.
|
|
3674
3960
|
const prevLane = passLane;
|
|
3961
|
+
// The mount a first pass belongs to: its creator's lane, or the one its
|
|
3962
|
+
// creator's own mount came from — a render effect a verdict lane's mount's
|
|
3963
|
+
// content creates is that mount's too (#4166). Lanes only, like the seat.
|
|
3964
|
+
const prevMount = laneRoot;
|
|
3965
|
+
const mount = laneStageHook && (laneRoot = create && (prevLane || prevMount));
|
|
3675
3966
|
setPassLane(
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
el.
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3967
|
+
!laneStageHook
|
|
3968
|
+
? null
|
|
3969
|
+
: (el._flags & REACTIVE_LANE_DIRTY ||
|
|
3970
|
+
(el._config & (CONFIG_OVERRIDE | CONFIG_GUESS)) === CONFIG_OVERRIDE) &&
|
|
3971
|
+
el._x?._transaction?._lane
|
|
3972
|
+
? el._x._transaction
|
|
3973
|
+
: // Loose `!=`: false with no creator lane (undefined == null).
|
|
3974
|
+
create &&
|
|
3975
|
+
prevLane?._parent._verdict != prevLane &&
|
|
3976
|
+
creatorPass(context)?._flags & REACTIVE_RECOMPUTING_DEPS
|
|
3977
|
+
? prevLane
|
|
3978
|
+
: null
|
|
3686
3979
|
);
|
|
3687
3980
|
// Attribution hook: fired before this run touches the dep list — `_deps`
|
|
3688
3981
|
// still holds the previous run's links (the subscriptions that could have
|
|
@@ -3724,8 +4017,11 @@ function recompute(el, create = false) {
|
|
|
3724
4017
|
// Held by a blocked lane: the frame joins nothing — a lane never holds
|
|
3725
4018
|
// a sync write (#3460). The pass is the lane's if it reads the lane's
|
|
3726
4019
|
// world (`read`), and has left it otherwise.
|
|
3727
|
-
|
|
3728
|
-
|
|
4020
|
+
// An answered deferred node's re-pass is a lagging question (D-40):
|
|
4021
|
+
// it joins nothing, so the write that reached it commits mainline.
|
|
4022
|
+
if (tx._lane || el._config & CONFIG_LAGS);
|
|
4023
|
+
else if (isEffect !== EFFECT_RENDER && !(el._config & CONFIG_VERDICT))
|
|
4024
|
+
joinPassTx(tx, freshHook?.(el, el._statusFlags & STATUS_UNINITIALIZED));
|
|
3729
4025
|
else if (
|
|
3730
4026
|
tx !== flushTransaction &&
|
|
3731
4027
|
!(el._statusFlags & STATUS_UNINITIALIZED || el._config & CONFIG_HELD_FRAME)
|
|
@@ -3745,8 +4041,20 @@ function recompute(el, create = false) {
|
|
|
3745
4041
|
// frame parked before it stays parked. Otherwise they ARE the frame:
|
|
3746
4042
|
// park them until this pass commits. Tracked effects run after the seam
|
|
3747
4043
|
// and own nothing to park.
|
|
3748
|
-
if (isEffect === EFFECT_TRACKED || el._config & CONFIG_STAGED)
|
|
3749
|
-
|
|
4044
|
+
if (isEffect === EFFECT_TRACKED || el._config & CONFIG_STAGED) {
|
|
4045
|
+
// A lazy node only those children read is released when this pass
|
|
4046
|
+
// ends, if the pass doesn't read it again (#4142).
|
|
4047
|
+
const prev = deferredReleases;
|
|
4048
|
+
deferReleases((released = []));
|
|
4049
|
+
disposeChildren(el);
|
|
4050
|
+
deferReleases(prev);
|
|
4051
|
+
} else if (el._firstChild !== null || el._disposal !== null) parkChildren(el);
|
|
4052
|
+
// An error a pass staged (D-41) is replaced by this pass's answer: a
|
|
4053
|
+
// value, a flight, or an error of its own (#4109, #4145).
|
|
4054
|
+
if (el._config & CONFIG_STAGED_ERROR) {
|
|
4055
|
+
el._pendingValue = NOT_PENDING;
|
|
4056
|
+
el._config ^= CONFIG_STAGED_ERROR;
|
|
4057
|
+
}
|
|
3750
4058
|
clearSignals(el);
|
|
3751
4059
|
}
|
|
3752
4060
|
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
@@ -3763,6 +4071,8 @@ function recompute(el, create = false) {
|
|
|
3763
4071
|
// settlePendingSource walk never runs for a landing that was preempted
|
|
3764
4072
|
// (#3181).
|
|
3765
4073
|
const wasPendingSource = el._x?._pendingSources?.has(el);
|
|
4074
|
+
// D-41: this pass's error is staged, not published (`stageError`).
|
|
4075
|
+
let stagedErr = false;
|
|
3766
4076
|
// A19 exc. 2: a `refresh()` re-asks the question already answered — quiet
|
|
3767
4077
|
// for the verdict — unless the question in flight is a new one, which the
|
|
3768
4078
|
// re-ask does not launder (a poll during a quiet confirm stays quiet).
|
|
@@ -3777,7 +4087,7 @@ function recompute(el, create = false) {
|
|
|
3777
4087
|
// frame, and the splice/reawaken paths key off it. A zombie reruns for
|
|
3778
4088
|
// live writes until the commit that disposes it, so every per-pass wipe
|
|
3779
4089
|
// — here, the finally below, updateIfNecessary — carries it (#3543).
|
|
3780
|
-
el._flags = REACTIVE_RECOMPUTING_DEPS | (el._flags & REACTIVE_ZOMBIE);
|
|
4090
|
+
el._flags = REACTIVE_RECOMPUTING_DEPS | (el._flags & (REACTIVE_ZOMBIE | REACTIVE_REASK));
|
|
3781
4091
|
el._time = clock;
|
|
3782
4092
|
// The pass's previous value: its staging, else a lane node's lane value
|
|
3783
4093
|
// when it has one (lanes.ts), else the committed one.
|
|
@@ -3789,7 +4099,8 @@ function recompute(el, create = false) {
|
|
|
3789
4099
|
: el._value;
|
|
3790
4100
|
let oldHeight = el._height;
|
|
3791
4101
|
let missedWake = false;
|
|
3792
|
-
// L2: did this pass read the future (REACTIVE_JOINED, set by read)
|
|
4102
|
+
// L2: did this pass read the future (REACTIVE_JOINED, set by read) — or,
|
|
4103
|
+
// a lane's mount, a staging of this flush (#3851, #4166)?
|
|
3793
4104
|
let joined = false;
|
|
3794
4105
|
let prevTracking = tracking;
|
|
3795
4106
|
let prevStrictRead = false;
|
|
@@ -3834,11 +4145,15 @@ function recompute(el, create = false) {
|
|
|
3834
4145
|
// retry can actually run.
|
|
3835
4146
|
parkLoadingWindow(el, e);
|
|
3836
4147
|
} else {
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
4148
|
+
// D-41: a pass of a held node, or one that read a staging of this
|
|
4149
|
+
// flush, stages its error (`stageError`).
|
|
4150
|
+
if (notReady || !(stagedErr = stageError(el, e, true))) {
|
|
4151
|
+
if (notReady) ext(el)._blocked = true;
|
|
4152
|
+
notifyStatus(el, notReady ? STATUS_PENDING : STATUS_ERROR, e);
|
|
4153
|
+
// The replacement source is fully propagated now. If no new flight
|
|
4154
|
+
// re-owned self, retire the superseded flight and its dependent copies.
|
|
4155
|
+
if (notReady && wasPendingSource && !el._x?._inFlight) settlePendingSource(el);
|
|
4156
|
+
}
|
|
3842
4157
|
// A re-park drops what the earlier pass carried (#3456): a source this
|
|
3843
4158
|
// pass no longer reaches — its branch switched, or a fresh flight
|
|
3844
4159
|
// replaced the inputs' pending with its own — stays copied onto
|
|
@@ -3846,14 +4161,16 @@ function recompute(el, create = false) {
|
|
|
3846
4161
|
// stops at this node (nothing left to retire) before it finds them. A
|
|
3847
4162
|
// dependent then waits forever on a flight it has no path to. The
|
|
3848
4163
|
// re-park twin of the unchanged-value recovery sweep below; dependents
|
|
3849
|
-
// with another path keep the source (retryReaches).
|
|
3850
|
-
|
|
4164
|
+
// with another path keep the source (retryReaches). A staged error
|
|
4165
|
+
// answered what the pass carried: the same.
|
|
4166
|
+
if ((notReady || stagedErr) && outgoingPendingSources)
|
|
3851
4167
|
for (const source of outgoingPendingSources)
|
|
3852
4168
|
if (source !== el && !el._x?._pendingSources?.has(source))
|
|
3853
4169
|
settlePendingSource(el, source);
|
|
3854
4170
|
}
|
|
3855
4171
|
} finally {
|
|
3856
4172
|
tracking = prevTracking;
|
|
4173
|
+
if (laneStageHook) laneRoot = prevMount;
|
|
3857
4174
|
strictRead = prevStrictRead;
|
|
3858
4175
|
// Consume the missed-wake latch (#3037, set by insertSubs): a dep write
|
|
3859
4176
|
// landed beneath this pass on a link it had already validated. The wipe
|
|
@@ -3861,10 +4178,11 @@ function recompute(el, create = false) {
|
|
|
3861
4178
|
// (markNode(c) in read()) marks the running node as part of ordinary
|
|
3862
4179
|
// bookkeeping, and those marks are correctly discarded here.
|
|
3863
4180
|
missedWake = (el._flags & REACTIVE_MISSED_WAKE) !== 0;
|
|
3864
|
-
joined = (el._flags & REACTIVE_JOINED
|
|
3865
|
-
// A verdict reader is one for as long as it probes
|
|
3866
|
-
//
|
|
3867
|
-
|
|
4181
|
+
joined = !!(el._flags & (mount ? REACTIVE_JOINED | REACTIVE_STAGED_READ : REACTIVE_JOINED));
|
|
4182
|
+
// A verdict reader is one for as long as it probes, or reads a memo
|
|
4183
|
+
// that does (`read`): a pass that did neither (REACTIVE_PROBED, the same
|
|
4184
|
+
// bit) is an ordinary derivation again.
|
|
4185
|
+
el._config = (el._config & ~CONFIG_VERDICT) | (el._flags & REACTIVE_PROBED);
|
|
3868
4186
|
// REACTIVE_DISPOSED survives too (#3621): the pass may have disposed its
|
|
3869
4187
|
// own owner (a memo calling its root's `dispose()`, a cleanup doing so
|
|
3870
4188
|
// #3601/#3606), and `disposeChildren` set the flag on this node
|
|
@@ -3883,6 +4201,7 @@ function recompute(el, create = false) {
|
|
|
3883
4201
|
REACTIVE_PROBE_UNANSWERED)) |
|
|
3884
4202
|
(create ? el._flags & REACTIVE_SNAPSHOT_STALE : 0);
|
|
3885
4203
|
context = oldcontext;
|
|
4204
|
+
if (released) for (const node of released) releaseIfSettledUnobserved(node);
|
|
3886
4205
|
// A19 exc. 2: a pass that went pending on a `refresh()` re-asks the
|
|
3887
4206
|
// question already answered — quiet for the verdict; any other pending
|
|
3888
4207
|
// pass is a new question. Settled, there is nothing to classify.
|
|
@@ -3911,15 +4230,15 @@ function recompute(el, create = false) {
|
|
|
3911
4230
|
// seat that read none of the lane's world has left it: its result is the
|
|
3912
4231
|
// frame's (a derivation whose branch no longer reaches the guess). A
|
|
3913
4232
|
// guess is written, not derived — it never leaves this way.
|
|
3914
|
-
let lane = passLane;
|
|
4233
|
+
let lane = !laneStageHook ? null : passLane;
|
|
3915
4234
|
// Listed before its staging, a pending pass included (the lane's own
|
|
3916
4235
|
// flight is the lane's); false: the pass left the lane (lanes.ts).
|
|
3917
|
-
const errored = !!el._x?._error;
|
|
3918
|
-
if (lane !== null) {
|
|
3919
|
-
if (
|
|
4236
|
+
const errored = !!el._x?._error || stagedErr;
|
|
4237
|
+
if (laneStageHook && lane !== null) {
|
|
4238
|
+
if (laneStageHook(el, lane, create, errored)) setPassLane(lane);
|
|
3920
4239
|
else lane = null;
|
|
3921
4240
|
}
|
|
3922
|
-
if (!
|
|
4241
|
+
if (!errored) {
|
|
3923
4242
|
// Observe-tier fan-in (HUGE_FAN_IN): the validated prefix [_deps.._depsTail]
|
|
3924
4243
|
// IS this pass's distinct sources — count it here rather than per link. A
|
|
3925
4244
|
// begin/end bracket around the pass plus a per-link increment measured
|
|
@@ -3946,17 +4265,9 @@ function recompute(el, create = false) {
|
|
|
3946
4265
|
: el._config & CONFIG_OVERRIDE && el._x._lane !== NOT_PENDING
|
|
3947
4266
|
? el._x._lane
|
|
3948
4267
|
: el._value;
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
(!isEffect && wasUninitialized) || !el._equals || !el._equals(compareValue, value);
|
|
3953
|
-
} catch (e) {
|
|
3954
|
-
// A throwing user comparator is an error of this node's computation.
|
|
3955
|
-
// Route it through the same status path as a compute-phase throw so
|
|
3956
|
-
// error boundaries contain it; otherwise it unwinds the scheduler
|
|
3957
|
-
// flush, bypassing every boundary and wedging the queue (#2837).
|
|
3958
|
-
notifyStatus(el, STATUS_ERROR, e);
|
|
3959
|
-
}
|
|
4268
|
+
// A throwing comparator is contained inside `isSame` (A3, #2837; #4111).
|
|
4269
|
+
const valueChanged =
|
|
4270
|
+
(!isEffect && wasUninitialized) || !!el._x?._shownError || !isSame(el, compareValue, value);
|
|
3960
4271
|
// A committed derived change becomes a cause for this node's subscribers,
|
|
3961
4272
|
// chaining their attribution through this node to the root write.
|
|
3962
4273
|
if (attrHooks !== null) {
|
|
@@ -4000,7 +4311,7 @@ function recompute(el, create = false) {
|
|
|
4000
4311
|
!create &&
|
|
4001
4312
|
lane === null &&
|
|
4002
4313
|
el._config & CONFIG_GUESS &&
|
|
4003
|
-
|
|
4314
|
+
laneOutcomeHook(el, value, errored)
|
|
4004
4315
|
);
|
|
4005
4316
|
else if (errored);
|
|
4006
4317
|
else if (valueChanged) {
|
|
@@ -4034,9 +4345,7 @@ function recompute(el, create = false) {
|
|
|
4034
4345
|
create
|
|
4035
4346
|
? !(
|
|
4036
4347
|
(flushTransaction !== null || passTx !== null) &&
|
|
4037
|
-
(joined ||
|
|
4038
|
-
(prevLane && el._flags & REACTIVE_STAGED_READ) ||
|
|
4039
|
-
(creatorPass(oldcontext)?._flags ?? 0) & REACTIVE_JOINED)
|
|
4348
|
+
(joined || creatorPass(oldcontext)?._flags & REACTIVE_JOINED)
|
|
4040
4349
|
)
|
|
4041
4350
|
: isEffect && el._pendingValue === NOT_PENDING
|
|
4042
4351
|
) {
|
|
@@ -4065,8 +4374,12 @@ function recompute(el, create = false) {
|
|
|
4065
4374
|
el._statusFlags |= STATUS_UNINITIALIZED;
|
|
4066
4375
|
// A boundary that has not shown content catches it: its fallback
|
|
4067
4376
|
// waits for the commit (#3540). (The pass's own status clear above
|
|
4068
|
-
// dropped what the read recorded.)
|
|
4069
|
-
|
|
4377
|
+
// dropped what the read recorded.) Not when the flush has joined
|
|
4378
|
+
// the hold and the pass is its own (not a verdict lane's mount,
|
|
4379
|
+
// #3851): the mount is part of the hold, and the boundary appears
|
|
4380
|
+
// at its commit, its fallback never seen (D-13, U-3) — a `<Show>`
|
|
4381
|
+
// mounting it over a landing included.
|
|
4382
|
+
freshHook?.(el, !mount && flushTransaction);
|
|
4070
4383
|
}
|
|
4071
4384
|
}
|
|
4072
4385
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
@@ -4101,16 +4414,14 @@ function recompute(el, create = false) {
|
|
|
4101
4414
|
// A first pass that went pending where the born-held arm would have held
|
|
4102
4415
|
// its value (it read a held node, or a verdict lane's mount read a staging,
|
|
4103
4416
|
// #3851) is held like it: its answer is the hold's, and the hold waits
|
|
4104
|
-
// for it (A29, #3800)
|
|
4105
|
-
//
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
el._statusFlags & STATUS_PENDING
|
|
4111
|
-
) {
|
|
4417
|
+
// for it (A29, #3800). A boundary that has not shown content catches it
|
|
4418
|
+
// and it is held all the same — its answer reveals no earlier than the
|
|
4419
|
+
// hold's commit (D-12) — but the hold does not wait for it: its only
|
|
4420
|
+
// readers are behind the fallback (`_hidden`; F-4, #3540). A boundary
|
|
4421
|
+
// re-armed by `on` owns what it collects outright (D-14): not held.
|
|
4422
|
+
if (create && lane === null && joined && el._statusFlags & STATUS_PENDING) {
|
|
4112
4423
|
const t = flushTransaction ?? passTx;
|
|
4113
|
-
if (t
|
|
4424
|
+
if (t && !t._lane && freshHook?.(el) !== CAUGHT_REARMED) holdNode(el, t);
|
|
4114
4425
|
}
|
|
4115
4426
|
// Dependencies are the committed frame's until it is replaced (A30, #3410):
|
|
4116
4427
|
// a pass that staged its value leaves the previous pass's tail linked for
|
|
@@ -4222,12 +4533,12 @@ function computed(fn, options) {
|
|
|
4222
4533
|
const loading = options !== null && typeof options === "object" && "loadingValue" in options;
|
|
4223
4534
|
// Two literals, one per tier, selected at build time (the observe flag is
|
|
4224
4535
|
// a literal after replacement; the untaken branch is dead code). The observe
|
|
4225
|
-
// literal is the prod literal plus its `_name`
|
|
4226
|
-
// boilerplate, because a post-construction `self._name = …` forces a
|
|
4536
|
+
// literal is the prod literal plus its `_name` and `_loc` slots — slots in
|
|
4537
|
+
// the boilerplate, because a post-construction `self._name = …` forces a
|
|
4227
4538
|
// hidden-class transition and an out-of-object property store on EVERY node
|
|
4228
4539
|
// (measured: the whole of the observe tier's creation overhead). Keep the
|
|
4229
4540
|
// two in sync — the dist artifact test pins observe's key set to prod's
|
|
4230
|
-
// plus
|
|
4541
|
+
// plus the slots.
|
|
4231
4542
|
const self = {
|
|
4232
4543
|
id: inheritId(options, transparent, context),
|
|
4233
4544
|
_config:
|
|
@@ -4269,6 +4580,7 @@ function computed(fn, options) {
|
|
|
4269
4580
|
// The slot is always present (hidden class); plumbing leaves it
|
|
4270
4581
|
// unset, which `ownerPath` skips.
|
|
4271
4582
|
_name: options?._plumbing ? undefined : (options?.name ?? "computed"),
|
|
4583
|
+
_loc: options?.loc,
|
|
4272
4584
|
// Observe: the verdict windows this pass entered (verdict.ts) — a
|
|
4273
4585
|
// slot, so the stamp is never a write after construction.
|
|
4274
4586
|
_devWindows: 0
|
|
@@ -4300,7 +4612,8 @@ function ext(el) {
|
|
|
4300
4612
|
_flushedAt: -1,
|
|
4301
4613
|
_q: 0,
|
|
4302
4614
|
_lane: NOT_PENDING,
|
|
4303
|
-
_marks: 0
|
|
4615
|
+
_marks: 0,
|
|
4616
|
+
_shownError: undefined
|
|
4304
4617
|
});
|
|
4305
4618
|
}
|
|
4306
4619
|
/** A tracked read of a held node (the reader derives from its transaction's
|
|
@@ -4322,10 +4635,7 @@ function joinPass(c, el) {
|
|
|
4322
4635
|
// the reader's position, not where the memo was created). Its catch, if
|
|
4323
4636
|
// any, is at its staging.
|
|
4324
4637
|
if (el._statusFlags & STATUS_UNINITIALIZED || c._type !== EFFECT_RENDER)
|
|
4325
|
-
joinPassTx(
|
|
4326
|
-
txOf(el),
|
|
4327
|
-
(!c._type && c._statusFlags & STATUS_UNINITIALIZED) || GlobalQueue._fresh?.(c)
|
|
4328
|
-
);
|
|
4638
|
+
joinPassTx(txOf(el), (!c._type && c._statusFlags & STATUS_UNINITIALIZED) || freshHook?.(c));
|
|
4329
4639
|
}
|
|
4330
4640
|
/** A15's stale reader (shared-hole and reveal corollaries): a render effect
|
|
4331
4641
|
* reading a node held by a transaction that is not the flush's. It is served
|
|
@@ -4362,10 +4672,11 @@ function frameRead(c, el) {
|
|
|
4362
4672
|
// read the screen. Lane work with no committed value yet reads a flight
|
|
4363
4673
|
// as a mount's memo does: it enters, and the boundary it mounts catches
|
|
4364
4674
|
// the pending (#3540).
|
|
4365
|
-
|
|
4675
|
+
// (Verdict readers and lanes exist only with their engines installed.)
|
|
4676
|
+
const verdict = observeFlightHook && c._config & CONFIG_VERDICT;
|
|
4677
|
+
const lane = laneStageHook && passLane !== null;
|
|
4366
4678
|
if (
|
|
4367
|
-
(
|
|
4368
|
-
(c._statusFlags & STATUS_UNINITIALIZED && el._statusFlags & STATUS_PENDING)) &&
|
|
4679
|
+
(!lane || (c._statusFlags & STATUS_UNINITIALIZED && el._statusFlags & STATUS_PENDING)) &&
|
|
4369
4680
|
!verdict &&
|
|
4370
4681
|
(c._type !== EFFECT_RENDER || el._config & CONFIG_INPUTS_PUBLISHED)
|
|
4371
4682
|
)
|
|
@@ -4374,7 +4685,7 @@ function frameRead(c, el) {
|
|
|
4374
4685
|
// Lane work and verdict readers are never the transaction's pass, whichever
|
|
4375
4686
|
// flush runs it: a node T holds re-enters T when it re-runs (`recompute`'s
|
|
4376
4687
|
// head), and the pass may then read a guess and become the lane's.
|
|
4377
|
-
if ((t === flushTransaction &&
|
|
4688
|
+
if ((t === flushTransaction && !lane && !verdict) || bornInto(c, t)) return false;
|
|
4378
4689
|
staleReader(c, t);
|
|
4379
4690
|
return true;
|
|
4380
4691
|
}
|
|
@@ -4461,6 +4772,7 @@ function createEffectNode(fn, effectFn, errorFn, type, options) {
|
|
|
4461
4772
|
_type: type,
|
|
4462
4773
|
_x: null,
|
|
4463
4774
|
_name: options?.name ?? "effect",
|
|
4775
|
+
_loc: options?.loc,
|
|
4464
4776
|
_devWindows: 0
|
|
4465
4777
|
};
|
|
4466
4778
|
// Effects dispatch status through the SHARED notifier (statusNotifierOf,
|
|
@@ -4512,7 +4824,7 @@ function setupComputedNode(self, options) {
|
|
|
4512
4824
|
if (context) linkChild(context, self);
|
|
4513
4825
|
DEV.hooks.onOwner?.(self);
|
|
4514
4826
|
if (parent) self._height = parent._height + 1;
|
|
4515
|
-
|
|
4827
|
+
wireExternalSourceHook?.(self);
|
|
4516
4828
|
!options?.lazy && recompute(self, true);
|
|
4517
4829
|
if (snapshotCaptureActive && !options?.lazy) {
|
|
4518
4830
|
if (!(self._statusFlags & STATUS_PENDING) && !(self._config & CONFIG_NO_SNAPSHOT)) {
|
|
@@ -4524,7 +4836,7 @@ function setupComputedNode(self, options) {
|
|
|
4524
4836
|
}
|
|
4525
4837
|
function signal(v, options) {
|
|
4526
4838
|
// Prod and observe boilerplates — see computed(). The observe literal adds
|
|
4527
|
-
// `_name` and `_owner` (the creating owner, stamped by registerGraph for
|
|
4839
|
+
// `_name`, `_loc` and `_owner` (the creating owner, stamped by registerGraph for
|
|
4528
4840
|
// createSignal nodes so ownerPath can locate signal subjects; null here,
|
|
4529
4841
|
// and staying null on internal signals — one shape either way).
|
|
4530
4842
|
const s = {
|
|
@@ -4540,6 +4852,7 @@ function signal(v, options) {
|
|
|
4540
4852
|
_notifiedAt: -1,
|
|
4541
4853
|
_x: null,
|
|
4542
4854
|
_name: options?.name ?? "signal",
|
|
4855
|
+
_loc: options?.loc,
|
|
4543
4856
|
_owner: null
|
|
4544
4857
|
};
|
|
4545
4858
|
s._internal = false;
|
|
@@ -4563,7 +4876,8 @@ function isEqual(a, b) {
|
|
|
4563
4876
|
* object, no NodeExtension, no post-construction expandos. `ownedWrite` is
|
|
4564
4877
|
* baked in: the setter carries the owned-scope guard; node-level writes are
|
|
4565
4878
|
* the store's notification machinery. The observe literal adds the label
|
|
4566
|
-
*
|
|
4879
|
+
* and location slots (the store relabels `store.<key>` and stamps the
|
|
4880
|
+
* store's `loc` when the engine is installed). */
|
|
4567
4881
|
function slotSignal(v, equals, host, key, acc) {
|
|
4568
4882
|
const s = {
|
|
4569
4883
|
_equals: equals,
|
|
@@ -4581,6 +4895,7 @@ function slotSignal(v, equals, host, key, acc) {
|
|
|
4581
4895
|
px: undefined,
|
|
4582
4896
|
pxv: undefined,
|
|
4583
4897
|
_name: "signal",
|
|
4898
|
+
_loc: undefined,
|
|
4584
4899
|
_owner: null
|
|
4585
4900
|
};
|
|
4586
4901
|
s._internal = false;
|
|
@@ -4617,7 +4932,11 @@ function exitCallback() {
|
|
|
4617
4932
|
}
|
|
4618
4933
|
/**
|
|
4619
4934
|
* Dev-only: > 0 while owner teardown runs cleanups (`_disposal` entries and
|
|
4620
|
-
* effect-returned cleanups — owner.ts), for the same reason.
|
|
4935
|
+
* effect-returned cleanups — owner.ts), for the same reason. The owned-scope
|
|
4936
|
+
* write guard (setSignal, markRefresh, the store setter) stands down here
|
|
4937
|
+
* too: a cleanup is teardown, not part of whichever computation is disposing
|
|
4938
|
+
* its owner (a list pass removing a row, a branch switching away), so its
|
|
4939
|
+
* writes are imperative like an effect callback's (#4165). Kept apart from
|
|
4621
4940
|
* `callbackDepth` because its sites cannot use try/finally (the frame would
|
|
4622
4941
|
* survive into prod): a throwing cleanup leaves it raised, and dev.ts resets
|
|
4623
4942
|
* it on the next microtask, which teardown — synchronous — never spans.
|
|
@@ -4644,6 +4963,16 @@ function setStrictRead(v) {
|
|
|
4644
4963
|
* Use `untrack` inside a memo or effect when you need to read a signal once
|
|
4645
4964
|
* without making the surrounding computation depend on its future changes.
|
|
4646
4965
|
*
|
|
4966
|
+
* `untrack` stops dependency tracking, not async settlement. Reading an
|
|
4967
|
+
* uninitialized async source still suspends the owning computation; it runs
|
|
4968
|
+
* again when that source first resolves. Afterward, the untracked read is a
|
|
4969
|
+
* snapshot and does not subscribe the computation to later changes.
|
|
4970
|
+
*
|
|
4971
|
+
* If the first read must return immediately, give the async source a
|
|
4972
|
+
* `loadingValue` before reading it with `untrack`. `isPending` and `latest`
|
|
4973
|
+
* inspect updates to an existing value; neither supplies a missing initial
|
|
4974
|
+
* value.
|
|
4975
|
+
*
|
|
4647
4976
|
* Pass a `strictReadLabel` string to enable a dev-mode warning: any reactive
|
|
4648
4977
|
* read inside `fn` that isn't inside a nested tracking scope will log a
|
|
4649
4978
|
* warning naming the label.
|
|
@@ -4657,17 +4986,12 @@ function setStrictRead(v) {
|
|
|
4657
4986
|
* log(snapshot);
|
|
4658
4987
|
* }
|
|
4659
4988
|
* );
|
|
4989
|
+
*
|
|
4990
|
+
* const color = createMemo<string>(() => fetchColor(), { loadingValue: "gray" });
|
|
4991
|
+
* const initialColor = untrack(color); // "gray" while the fetch is unresolved
|
|
4660
4992
|
* ```
|
|
4661
4993
|
*/
|
|
4662
4994
|
function untrack(fn, strictReadLabel) {
|
|
4663
|
-
if (
|
|
4664
|
-
GlobalQueue._externalUntrack === null &&
|
|
4665
|
-
!tracking &&
|
|
4666
|
-
!strictRead &&
|
|
4667
|
-
!strictReadLabel &&
|
|
4668
|
-
asyncTailFlights === 0
|
|
4669
|
-
)
|
|
4670
|
-
return fn();
|
|
4671
4995
|
const prevTracking = tracking;
|
|
4672
4996
|
const prevStrictRead = strictRead;
|
|
4673
4997
|
tracking = false;
|
|
@@ -4676,7 +5000,7 @@ function untrack(fn, strictReadLabel) {
|
|
|
4676
5000
|
untrackDepth++;
|
|
4677
5001
|
}
|
|
4678
5002
|
try {
|
|
4679
|
-
if (
|
|
5003
|
+
if (externalUntrackHook) return externalUntrackHook(fn);
|
|
4680
5004
|
return fn();
|
|
4681
5005
|
} finally {
|
|
4682
5006
|
tracking = prevTracking;
|
|
@@ -4748,7 +5072,7 @@ function prepareComputed(comp, refresh) {
|
|
|
4748
5072
|
* False means the reader derives from the staged value.
|
|
4749
5073
|
*/
|
|
4750
5074
|
function readerSeesCommitted(el, c) {
|
|
4751
|
-
return
|
|
5075
|
+
return !c || el._pendingValue === NOT_PENDING || c._config & CONFIG_CHILDREN_FORBIDDEN;
|
|
4752
5076
|
}
|
|
4753
5077
|
/** A28 — set when a node is staged (queuePendingNode) OUTSIDE a flush;
|
|
4754
5078
|
* cleared when the next flush begins. The read sites test this one module
|
|
@@ -4827,6 +5151,7 @@ function pullComputed(owner, c) {
|
|
|
4827
5151
|
if (height >= c._height && owner._parent !== c) c._height = height + 1;
|
|
4828
5152
|
}
|
|
4829
5153
|
function read(el) {
|
|
5154
|
+
DEV.hooks.onRead?.(el);
|
|
4830
5155
|
if (asyncTailFlights !== 0 && !tracking && untrackDepth === 0)
|
|
4831
5156
|
checkPostAwaitRead(
|
|
4832
5157
|
el,
|
|
@@ -4877,7 +5202,7 @@ function read(el) {
|
|
|
4877
5202
|
if (!c || el._pendingValue === NOT_PENDING || c._config & CONFIG_CHILDREN_FORBIDDEN)
|
|
4878
5203
|
return el._value;
|
|
4879
5204
|
// (A plain signal is never uninitialized — the carve-out is `serve`'s.)
|
|
4880
|
-
if (c._config & CONFIG_VERDICT && stagedScreen(c)) return el._value;
|
|
5205
|
+
if (observeFlightHook && c._config & CONFIG_VERDICT && stagedScreen(c)) return el._value;
|
|
4881
5206
|
stagedRead(c);
|
|
4882
5207
|
return el._pendingValue;
|
|
4883
5208
|
}
|
|
@@ -4893,7 +5218,15 @@ function read(el) {
|
|
|
4893
5218
|
if (c) {
|
|
4894
5219
|
if (tracking) {
|
|
4895
5220
|
link(el, c);
|
|
4896
|
-
if (owner._fn)
|
|
5221
|
+
if (owner._fn) {
|
|
5222
|
+
pullComputed(owner, c);
|
|
5223
|
+
// F-6 (#4050): a memo over a verdict reader's value derives from a
|
|
5224
|
+
// display-ahead read — a verdict reader from this pass's end, as if
|
|
5225
|
+
// it probed inline: it reads held values as the screen and shows the
|
|
5226
|
+
// verdict now. Not an effect: a render effect is a frame reader
|
|
5227
|
+
// already, and a user effect's posture is its own reads'.
|
|
5228
|
+
if (!c._type) c._flags |= owner._config & CONFIG_VERDICT;
|
|
5229
|
+
}
|
|
4897
5230
|
}
|
|
4898
5231
|
// L2, as in the fast block above (tracked or not). A node born into the
|
|
4899
5232
|
// future (uninitialized) has no committed value: every reader derives
|
|
@@ -4910,8 +5243,9 @@ function read(el) {
|
|
|
4910
5243
|
}
|
|
4911
5244
|
// Lanes: a lane's node (after the pull — the node is current). NOT_PENDING
|
|
4912
5245
|
// falls through: lane work's read of a pending member throws like any.
|
|
4913
|
-
|
|
4914
|
-
|
|
5246
|
+
// (CONFIG_OVERRIDE is the lane engine's: no engine, no lane's node.)
|
|
5247
|
+
if (laneReadHook && el._config & CONFIG_OVERRIDE) {
|
|
5248
|
+
const v = laneReadHook(c, el);
|
|
4915
5249
|
if (v !== NOT_PENDING) return v;
|
|
4916
5250
|
}
|
|
4917
5251
|
// A stale reader of a held flight (rule 3, A15's reveal corollary) is served
|
|
@@ -4936,9 +5270,11 @@ function read(el) {
|
|
|
4936
5270
|
) {
|
|
4937
5271
|
// A reader with no committed value yet sees the flight pending: a
|
|
4938
5272
|
// boundary a lane mounts shows its fallback (A29's boundary exemption).
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
committed =
|
|
5273
|
+
// (A lane, and a verdict reader, exist only with their engines installed.)
|
|
5274
|
+
if (laneStageHook && passLane !== null && !(c?._statusFlags & STATUS_UNINITIALIZED))
|
|
5275
|
+
committed = true;
|
|
5276
|
+
else if (observeFlightHook && c !== null && c._config & CONFIG_VERDICT)
|
|
5277
|
+
committed = observeFlightHook(c, owner);
|
|
4942
5278
|
}
|
|
4943
5279
|
if (owner._statusFlags & STATUS_PENDING && !committed) {
|
|
4944
5280
|
// A reader landing on a pending node throws; an untracked read of an
|
|
@@ -5007,6 +5343,9 @@ function read(el) {
|
|
|
5007
5343
|
}
|
|
5008
5344
|
}
|
|
5009
5345
|
if (committed) return el._value;
|
|
5346
|
+
// D-41: an untracked read reads the screen, and a shown error is on it
|
|
5347
|
+
// until the answer that replaces it commits.
|
|
5348
|
+
if (!c && el._x?._shownError) throw el._x._shownError;
|
|
5010
5349
|
const value = serve(el, c);
|
|
5011
5350
|
if (
|
|
5012
5351
|
!c &&
|
|
@@ -5053,9 +5392,16 @@ function serve(el, c) {
|
|
|
5053
5392
|
return u;
|
|
5054
5393
|
}
|
|
5055
5394
|
if (readerSeesCommitted(el, c)) return el._value;
|
|
5056
|
-
if (
|
|
5395
|
+
if (
|
|
5396
|
+
observeFlightHook &&
|
|
5397
|
+
c._config & CONFIG_VERDICT &&
|
|
5398
|
+
!(el._statusFlags & STATUS_UNINITIALIZED) &&
|
|
5399
|
+
stagedScreen(c)
|
|
5400
|
+
)
|
|
5057
5401
|
return el._value;
|
|
5058
5402
|
stagedRead(c, el);
|
|
5403
|
+
// D-41: the staged answer is an error (`stageError`).
|
|
5404
|
+
if (el._config & CONFIG_STAGED_ERROR) throw el._pendingValue;
|
|
5059
5405
|
return el._pendingValue;
|
|
5060
5406
|
}
|
|
5061
5407
|
/** A pass read a staging of this flush: it derives from what the flush may
|
|
@@ -5073,7 +5419,7 @@ function serve(el, c) {
|
|
|
5073
5419
|
function stagedRead(c, el) {
|
|
5074
5420
|
if (!(el?._statusFlags & STATUS_UNINITIALIZED)) {
|
|
5075
5421
|
c._flags |= REACTIVE_STAGED_READ;
|
|
5076
|
-
if (passLane !== null) stagedReaders.push(c);
|
|
5422
|
+
if (laneSeamsHook && passLane !== null) stagedReaders.push(c);
|
|
5077
5423
|
}
|
|
5078
5424
|
}
|
|
5079
5425
|
/** A10 for a staged node: a verdict reader (the pass entered a window) that
|
|
@@ -5123,11 +5469,46 @@ function captureWriteSnapshot(el, current) {
|
|
|
5123
5469
|
el._config |= CONFIG_HAS_SNAPSHOT;
|
|
5124
5470
|
snapshotSources.add(el);
|
|
5125
5471
|
}
|
|
5472
|
+
/**
|
|
5473
|
+
* A callback run before every signal or store write lands, while set, with
|
|
5474
|
+
* the written signal or the store proxy whose setter runs. The
|
|
5475
|
+
* server-components client sets it while slot occurrences are left
|
|
5476
|
+
* unmounted after hydration (deferred hydration): a write may be one an
|
|
5477
|
+
* unmounted component would have observed, so the client mounts what is
|
|
5478
|
+
* left before the write applies, and clears the hook. `null` otherwise.
|
|
5479
|
+
*/
|
|
5480
|
+
let writeHook = null;
|
|
5481
|
+
/** @internal */
|
|
5482
|
+
function setWriteHook(hook) {
|
|
5483
|
+
writeHook = hook;
|
|
5484
|
+
}
|
|
5485
|
+
/**
|
|
5486
|
+
* `el`'s comparator verdict (`_equals`), the one guarded call for recompute,
|
|
5487
|
+
* setSignal (user setters and async landings) and the seam's
|
|
5488
|
+
* staged-equals-committed check.
|
|
5489
|
+
* - A comparator that read an unresolved async source has not shown the
|
|
5490
|
+
* values equal (#4111): falsy, a change, whose readers suspend in their own
|
|
5491
|
+
* tracked context.
|
|
5492
|
+
* - Any other throw is an error of `el`'s computation (A3, #2837): routed
|
|
5493
|
+
* through the status path so error boundaries contain it, instead of
|
|
5494
|
+
* unwinding a flush or a setter; answered "same" so nothing commits.
|
|
5495
|
+
* @internal
|
|
5496
|
+
*/
|
|
5497
|
+
function isSame(el, a, b) {
|
|
5498
|
+
if (el._equals === isEqual) return a === b;
|
|
5499
|
+
try {
|
|
5500
|
+
return el._equals && el._equals(a, b);
|
|
5501
|
+
} catch (e) {
|
|
5502
|
+
if (!(e instanceof NotReadyError)) return (notifyStatus(el, STATUS_ERROR, e), true);
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5126
5505
|
function setSignal(el, v) {
|
|
5506
|
+
if (writeHook !== null) writeHook(el);
|
|
5127
5507
|
if (
|
|
5128
5508
|
!(el._config & CONFIG_OWNED_WRITE) &&
|
|
5129
5509
|
!(context && context._config & CONFIG_CHILDREN_FORBIDDEN) &&
|
|
5130
|
-
context
|
|
5510
|
+
context &&
|
|
5511
|
+
!disposalDepth
|
|
5131
5512
|
) {
|
|
5132
5513
|
emitDiagnostic({
|
|
5133
5514
|
code: "REACTIVE_WRITE_IN_OWNED_SCOPE",
|
|
@@ -5146,7 +5527,7 @@ function setSignal(el, v) {
|
|
|
5146
5527
|
// Lanes: a write landing on a guess is its truth (A18 — an async guess's
|
|
5147
5528
|
// own landing), judged against the guess; one landing on a lane's
|
|
5148
5529
|
// derivation (its flight) is the lane's staging (lanes.ts).
|
|
5149
|
-
if (el._config & CONFIG_OVERRIDE) return
|
|
5530
|
+
if (laneWriteHook && el._config & CONFIG_OVERRIDE) return laneWriteHook(el, v);
|
|
5150
5531
|
// L2 (T4) / A34 (1): a write to a node whose staged state is held is a
|
|
5151
5532
|
// second proposal for the slot — the same value again or another — and
|
|
5152
5533
|
// the two cannot finish at different times: the writer's tick joins the
|
|
@@ -5154,8 +5535,12 @@ function setSignal(el, v) {
|
|
|
5154
5535
|
if (el._config & CONFIG_HELD) joinFuture(txOf(el));
|
|
5155
5536
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
5156
5537
|
// user comparator must not run against `undefined` (matches recompute).
|
|
5538
|
+
// D-41: a write over a shown error is a change whatever the last good
|
|
5539
|
+
// value was — the error leaves at its commit (`commitPendingNode`).
|
|
5157
5540
|
const valueChanged =
|
|
5158
|
-
!!(el._statusFlags & STATUS_UNINITIALIZED) ||
|
|
5541
|
+
!!(el._statusFlags & STATUS_UNINITIALIZED) ||
|
|
5542
|
+
!!el._x?._shownError ||
|
|
5543
|
+
!isSame(el, currentValue, v);
|
|
5159
5544
|
if (!valueChanged) return v;
|
|
5160
5545
|
// Attribution hook: this committed write is where a re-run chain begins.
|
|
5161
5546
|
if (attrHooks !== null) attrHooks.write(el, currentValue, v);
|
|
@@ -5213,8 +5598,21 @@ function setMemo(el, v) {
|
|
|
5213
5598
|
!(el._flags & REACTIVE_MANUAL_WRITE) &&
|
|
5214
5599
|
txOf(el) !== flushTransaction;
|
|
5215
5600
|
// The writer read the committed frame; its updater composes on it.
|
|
5216
|
-
if (held && typeof v === "function")
|
|
5217
|
-
|
|
5601
|
+
if (held && typeof v === "function") {
|
|
5602
|
+
const value = v(el._value);
|
|
5603
|
+
v = () => value;
|
|
5604
|
+
}
|
|
5605
|
+
// #4110: the write replaces a failed derivation's outcome. It lands without
|
|
5606
|
+
// re-running `_fn`, and nothing else clears STATUS_ERROR, so without this
|
|
5607
|
+
// every later read keeps throwing the error the derivation left behind.
|
|
5608
|
+
// The error stays the display until the write commits (D-41).
|
|
5609
|
+
if (el._statusFlags & STATUS_ERROR) {
|
|
5610
|
+
el._x._shownError = el._x._error;
|
|
5611
|
+
notifyStatus(el, STATUS_NONE, undefined);
|
|
5612
|
+
}
|
|
5613
|
+
v = setSignal(el, v);
|
|
5614
|
+
// A write replaces an error a pass staged (D-41): it is a value again.
|
|
5615
|
+
el._config &= ~CONFIG_STAGED_ERROR;
|
|
5218
5616
|
if (held) {
|
|
5219
5617
|
// The one write that re-runs: the staging it replaced was derived from
|
|
5220
5618
|
// inputs the writer never saw, so the hold re-derives over the write.
|
|
@@ -5222,7 +5620,7 @@ function setMemo(el, v) {
|
|
|
5222
5620
|
insertIntoHeap(el, dirtyQueue);
|
|
5223
5621
|
schedule();
|
|
5224
5622
|
} else if (el._pendingValue !== NOT_PENDING) el._flags |= REACTIVE_MANUAL_WRITE;
|
|
5225
|
-
return
|
|
5623
|
+
return v;
|
|
5226
5624
|
}
|
|
5227
5625
|
/**
|
|
5228
5626
|
* Executes `fn` with the given `owner` set as the current owner. Any reactive
|
|
@@ -5289,7 +5687,8 @@ function markRefresh(node) {
|
|
|
5289
5687
|
if (
|
|
5290
5688
|
context &&
|
|
5291
5689
|
!((node._config ?? 0) & CONFIG_OWNED_WRITE) &&
|
|
5292
|
-
!(context._config & CONFIG_CHILDREN_FORBIDDEN)
|
|
5690
|
+
!(context._config & CONFIG_CHILDREN_FORBIDDEN) &&
|
|
5691
|
+
!disposalDepth
|
|
5293
5692
|
) {
|
|
5294
5693
|
emitDiagnostic({
|
|
5295
5694
|
code: "REACTIVE_WRITE_IN_OWNED_SCOPE",
|
|
@@ -5323,175 +5722,194 @@ function markRefresh(node) {
|
|
|
5323
5722
|
}
|
|
5324
5723
|
|
|
5325
5724
|
export {
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5725
|
+
setPassLane as $,
|
|
5726
|
+
tracking as A,
|
|
5727
|
+
CONFIG_CHILDREN_FORBIDDEN as B,
|
|
5329
5728
|
CONFIG_GUESS as C,
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5729
|
+
passLane as D,
|
|
5730
|
+
STATUS_PENDING as E,
|
|
5731
|
+
EFFECT_RENDER as F,
|
|
5333
5732
|
GlobalQueue as G,
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5733
|
+
sameLane as H,
|
|
5734
|
+
flushTransaction as I,
|
|
5735
|
+
REACTIVE_SCREEN_READ as J,
|
|
5736
|
+
REACTIVE_FRAME_READ as K,
|
|
5737
|
+
attrHooks as L,
|
|
5738
|
+
commitPendingNode as M,
|
|
5340
5739
|
NOT_PENDING as N,
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5740
|
+
REACTIVE_IN_HEAP as O,
|
|
5741
|
+
REACTIVE_DIRTY as P,
|
|
5742
|
+
REACTIVE_CHECK as Q,
|
|
5344
5743
|
REACTIVE_DISPOSED as R,
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5744
|
+
STATUS_UNINITIALIZED as S,
|
|
5745
|
+
CONFIG_INPUTS_PUBLISHED as T,
|
|
5746
|
+
releaseQueues as U,
|
|
5747
|
+
CONFIG_SLOT_NODE as V,
|
|
5349
5748
|
holdNode as W,
|
|
5350
5749
|
joinFuture as X,
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5750
|
+
reruns as Y,
|
|
5751
|
+
CONFIG_STAGED as Z,
|
|
5752
|
+
merge as _,
|
|
5753
|
+
NotReadyError as a,
|
|
5754
|
+
setMemo as a$,
|
|
5755
|
+
REACTIVE_JOINED as a0,
|
|
5756
|
+
REACTIVE_STAGED_READ as a1,
|
|
5757
|
+
stagedRead as a2,
|
|
5758
|
+
setVerdict as a3,
|
|
5759
|
+
context as a4,
|
|
5760
|
+
installVerdictHooks as a5,
|
|
5761
|
+
REACTIVE_PROBED as a6,
|
|
5363
5762
|
verdict as a7,
|
|
5364
5763
|
link as a8,
|
|
5365
5764
|
pullComputed as a9,
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5765
|
+
cleanup as aA,
|
|
5766
|
+
read as aB,
|
|
5767
|
+
DEV as aC,
|
|
5768
|
+
CONFIG_TRANSPARENT as aD,
|
|
5769
|
+
NoOwnerError as aE,
|
|
5770
|
+
ContextNotFoundError as aF,
|
|
5771
|
+
createEffectNode as aG,
|
|
5772
|
+
recompute as aH,
|
|
5773
|
+
EFFECT_USER as aI,
|
|
5774
|
+
reportDiagnostic as aJ,
|
|
5775
|
+
computed as aK,
|
|
5776
|
+
staleValues as aL,
|
|
5777
|
+
CONFIG_AUTO_DISPOSE as aM,
|
|
5778
|
+
EFFECT_TRACKED as aN,
|
|
5779
|
+
heldRunHook as aO,
|
|
5780
|
+
unwrapStatusError as aP,
|
|
5781
|
+
haltReactivity as aQ,
|
|
5782
|
+
setStrictRead as aR,
|
|
5783
|
+
StatusError as aS,
|
|
5784
|
+
trimStaleDeps as aT,
|
|
5785
|
+
setTrackedQueueCallback as aU,
|
|
5786
|
+
setEffectStatusNotify as aV,
|
|
5787
|
+
_hitUnhandledAsync as aW,
|
|
5788
|
+
resetUnhandledAsync as aX,
|
|
5789
|
+
ROOT_ERROR_HOOK as aY,
|
|
5790
|
+
registerGraph as aZ,
|
|
5791
|
+
runWithOwner as a_,
|
|
5393
5792
|
strictRead as aa,
|
|
5394
5793
|
warnStrictReadUntracked as ab,
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5794
|
+
staleReader as ac,
|
|
5795
|
+
globalQueue as ad,
|
|
5796
|
+
joinPass as ae,
|
|
5797
|
+
markLateLinker as af,
|
|
5798
|
+
spectating as ag,
|
|
5799
|
+
unflushedValue as ah,
|
|
5800
|
+
CONFIG_STAGED_ERROR as ai,
|
|
5801
|
+
stagedReaders as aj,
|
|
5802
|
+
bornInto as ak,
|
|
5803
|
+
enterAction as al,
|
|
5804
|
+
setEffectCallback as am,
|
|
5805
|
+
exitAction as an,
|
|
5806
|
+
isThenable as ao,
|
|
5807
|
+
actionDepth as ap,
|
|
5808
|
+
flush as aq,
|
|
5809
|
+
setQuestion as ar,
|
|
5810
|
+
emitDiagnostic as as,
|
|
5811
|
+
enterCallback as at,
|
|
5812
|
+
exitCallback as au,
|
|
5813
|
+
getOwner as av,
|
|
5814
|
+
inEffectCallback as aw,
|
|
5815
|
+
setExternalHooks as ax,
|
|
5816
|
+
signal as ay,
|
|
5817
|
+
setSignal as az,
|
|
5818
|
+
CONFIG_AUTHORITATIVE as b,
|
|
5819
|
+
isSuppressed as b$,
|
|
5820
|
+
$REFRESH as b0,
|
|
5821
|
+
markRefresh as b1,
|
|
5822
|
+
createRoot as b2,
|
|
5823
|
+
getObserver as b3,
|
|
5824
|
+
dispose as b4,
|
|
5825
|
+
TimeoutError as b5,
|
|
5826
|
+
untrack as b6,
|
|
5827
|
+
dirtyQueue as b7,
|
|
5828
|
+
CONFIG_REDERIVE as b8,
|
|
5829
|
+
passTx as b9,
|
|
5830
|
+
settlePendingSource as bA,
|
|
5831
|
+
notifyEpoch as bB,
|
|
5832
|
+
SUPPORTS_PROXY as bC,
|
|
5833
|
+
releaseMarksHook as bD,
|
|
5834
|
+
installMarkHooks as bE,
|
|
5835
|
+
CONFIG_LAGS as bF,
|
|
5836
|
+
REACTIVE_REASK as bG,
|
|
5837
|
+
heldUnder as bH,
|
|
5838
|
+
unhold as bI,
|
|
5839
|
+
laneStageHook as bJ,
|
|
5840
|
+
REACTIVE_ZOMBIE as bK,
|
|
5841
|
+
installBoundaryHooks as bL,
|
|
5842
|
+
CAUGHT_REARMED as bM,
|
|
5843
|
+
OBSERVE as bN,
|
|
5844
|
+
clearSnapshots as bO,
|
|
5845
|
+
enforceLoadingBoundary as bP,
|
|
5846
|
+
getNextChildId as bQ,
|
|
5847
|
+
markSnapshotScope as bR,
|
|
5848
|
+
peekNextChildId as bS,
|
|
5849
|
+
releaseSnapshotScope as bT,
|
|
5850
|
+
resetErrorHalt as bU,
|
|
5851
|
+
setConsoleFooter as bV,
|
|
5852
|
+
setSnapshotCapture as bW,
|
|
5853
|
+
setWriteHook as bX,
|
|
5854
|
+
setAttributionHooks as bY,
|
|
5855
|
+
liveRootOwners as bZ,
|
|
5856
|
+
ownerPath as b_,
|
|
5857
|
+
CONFIG_FRESH_READ as ba,
|
|
5858
|
+
createOwner as bb,
|
|
5859
|
+
writeHook as bc,
|
|
5860
|
+
REACTIVE_WRITE_IN_OWNED_SCOPE_SIGNAL_MESSAGE as bd,
|
|
5861
|
+
ownedScopeWriteMessage as be,
|
|
5862
|
+
isEqual as bf,
|
|
5863
|
+
CONFIG_MANUAL_WRITE as bg,
|
|
5864
|
+
snapshotCaptureActive as bh,
|
|
5865
|
+
captureWriteSnapshot as bi,
|
|
5866
|
+
notePromotedWrite as bj,
|
|
5867
|
+
slotSignal as bk,
|
|
5868
|
+
stagedScreen as bl,
|
|
5869
|
+
CONFIG_PROMOTED as bm,
|
|
5870
|
+
setSlotUnobserved as bn,
|
|
5871
|
+
installStoreHooks as bo,
|
|
5872
|
+
joinPassTx as bp,
|
|
5873
|
+
asyncTailFlights as bq,
|
|
5874
|
+
untrackDepth as br,
|
|
5875
|
+
checkPostAwaitRead as bs,
|
|
5876
|
+
disposalDepth as bt,
|
|
5877
|
+
insertIntoHeap as bu,
|
|
5878
|
+
isDisposed as bv,
|
|
5879
|
+
handleAsync as bw,
|
|
5880
|
+
addPendingSource as bx,
|
|
5881
|
+
propagateStatus as by,
|
|
5882
|
+
forEachDependent as bz,
|
|
5883
|
+
CONFIG_OVERRIDE as c,
|
|
5884
|
+
blockersOf as c0,
|
|
5885
|
+
CONFIG_PLUMBING as c1,
|
|
5886
|
+
anyExcluded as c2,
|
|
5887
|
+
isExcluded as c3,
|
|
5888
|
+
CONFIG_WIDE as c4,
|
|
5889
|
+
GRAPH_SIZE_WARN_AT as c5,
|
|
5890
|
+
noteFanOut as c6,
|
|
5891
|
+
CONFIG_SUPERSEDES as c7,
|
|
5892
|
+
newTransaction as d,
|
|
5893
|
+
enqueueSub as e,
|
|
5894
|
+
CONFIG_VERDICT as f,
|
|
5895
|
+
REACTIVE_PROBE_UNANSWERED as g,
|
|
5896
|
+
blocked as h,
|
|
5897
|
+
installLaneHooks as i,
|
|
5898
|
+
REACTIVE_LANE_DIRTY as j,
|
|
5481
5899
|
CONFIG_HELD as k,
|
|
5482
|
-
|
|
5483
|
-
|
|
5900
|
+
clock as l,
|
|
5901
|
+
insertSubs as m,
|
|
5484
5902
|
nextQuestion as n,
|
|
5485
|
-
|
|
5486
|
-
|
|
5903
|
+
ownFlights as o,
|
|
5904
|
+
laneDirty as p,
|
|
5487
5905
|
question as q,
|
|
5488
5906
|
resolveTx as r,
|
|
5489
5907
|
schedule as s,
|
|
5490
5908
|
txOf as t,
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5909
|
+
REACTIVE_LANE_READ as u,
|
|
5910
|
+
ext as v,
|
|
5911
|
+
REACTIVE_RECOMPUTING_DEPS as w,
|
|
5912
|
+
queuePendingNode as x,
|
|
5913
|
+
list as y,
|
|
5914
|
+
STATUS_ERROR as z
|
|
5497
5915
|
};
|