@solidjs/signals 2.0.0-rc.11 → 2.0.0-rc.14
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 +2056 -3773
- package/dist/dev.attribution.js +159 -91
- package/dist/dev.js +7263 -8384
- package/dist/observe/affects.js +125 -104
- package/dist/observe/boundaries.js +458 -665
- package/dist/observe/core/action.js +63 -66
- package/dist/observe/core/async.js +240 -383
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +271 -199
- package/dist/observe/core/constants.js +115 -178
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +840 -1428
- package/dist/observe/core/dev.js +41 -18
- package/dist/observe/core/effect.js +75 -86
- package/dist/observe/core/external.js +5 -5
- package/dist/observe/core/graph.js +61 -70
- package/dist/observe/core/heap.js +75 -98
- package/dist/observe/core/invariants.js +1 -34
- package/dist/observe/core/lanes.js +704 -181
- package/dist/observe/core/owner.js +80 -101
- package/dist/observe/core/scheduler.js +708 -1351
- package/dist/observe/core/verdict.js +302 -621
- package/dist/observe/flatten.js +79 -0
- package/dist/observe/index.js +15 -13
- package/dist/observe/map.js +232 -235
- package/dist/observe/reveal.js +212 -0
- package/dist/observe/signals.js +133 -215
- package/dist/observe/store/affects.js +135 -0
- package/dist/observe/store/index.js +29 -24
- package/dist/observe/store/optimistic.js +538 -0
- package/dist/observe/store/projection.js +302 -0
- package/dist/observe/store/reconcile.js +257 -0
- package/dist/observe/store/store.js +1945 -277
- package/dist/observe/store/storePath.js +1 -1
- package/dist/{prod/store/next → observe/store}/target.js +17 -18
- package/dist/observe/store/types.js +73 -0
- package/dist/observe/store/utils.js +1 -13
- package/dist/prod/affects.js +127 -106
- package/dist/prod/boundaries.js +442 -654
- package/dist/prod/core/action.js +71 -74
- package/dist/prod/core/async.js +307 -442
- package/dist/prod/core/constants.js +112 -177
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +852 -1448
- package/dist/prod/core/effect.js +88 -99
- package/dist/prod/core/external.js +5 -5
- package/dist/prod/core/graph.js +61 -70
- package/dist/prod/core/heap.js +75 -98
- package/dist/prod/core/invariants.js +1 -32
- package/dist/prod/core/lanes.js +666 -181
- package/dist/prod/core/owner.js +75 -96
- package/dist/prod/core/scheduler.js +677 -1332
- package/dist/prod/core/verdict.js +297 -621
- package/dist/prod/flatten.js +77 -0
- package/dist/prod/index.js +15 -13
- package/dist/prod/map.js +143 -146
- package/dist/prod/reveal.js +212 -0
- package/dist/prod/signals.js +144 -226
- package/dist/prod/store/affects.js +135 -0
- package/dist/prod/store/index.js +28 -19
- package/dist/prod/store/optimistic.js +533 -0
- package/dist/prod/store/projection.js +295 -0
- package/dist/prod/store/reconcile.js +257 -0
- package/dist/prod/store/store.js +1840 -272
- package/dist/prod/store/storePath.js +1 -1
- package/dist/{observe/store/next → prod/store}/target.js +13 -17
- package/dist/prod/store/types.js +73 -0
- package/dist/prod/store/utils.js +1 -11
- package/dist/types/affects.d.ts +11 -30
- package/dist/types/boundaries.d.ts +62 -176
- package/dist/types/carved.d.ts +1 -0
- package/dist/types/core/action.d.ts +5 -6
- package/dist/types/core/async.d.ts +10 -5
- package/dist/types/core/attribution-hooks.d.ts +48 -1
- package/dist/types/core/attribution.d.ts +29 -9
- package/dist/types/core/constants.d.ts +125 -171
- package/dist/types/core/core.d.ts +104 -264
- package/dist/types/core/dev.d.ts +60 -7
- package/dist/types/core/effect.d.ts +0 -7
- package/dist/types/core/graph.d.ts +7 -1
- package/dist/types/core/heap.d.ts +5 -7
- package/dist/types/core/index.d.ts +6 -6
- package/dist/types/core/invariants.d.ts +0 -29
- package/dist/types/core/lanes.d.ts +65 -87
- package/dist/types/core/owner.d.ts +3 -3
- package/dist/types/core/scheduler.d.ts +249 -331
- package/dist/types/core/types.d.ts +51 -85
- package/dist/types/core/verdict.d.ts +3 -0
- package/dist/types/flatten.d.ts +8 -0
- package/dist/types/index.d.ts +7 -5
- package/dist/types/reveal.d.ts +19 -0
- package/dist/types/signals.d.ts +53 -92
- package/dist/types/store/affects.d.ts +1 -0
- package/dist/types/store/index.d.ts +35 -15
- package/dist/types/store/optimistic.d.ts +23 -0
- package/dist/types/store/projection.d.ts +18 -0
- package/dist/types/store/reconcile.d.ts +3 -0
- package/dist/types/store/store.d.ts +165 -143
- package/dist/types/store/storePath.d.ts +1 -1
- package/dist/types/store/target.d.ts +151 -0
- package/dist/types/store/types.d.ts +84 -0
- package/package.json +1 -1
- package/dist/observe/core/optimistic.js +0 -669
- package/dist/observe/store/next/optimistic.js +0 -717
- package/dist/observe/store/next/projection.js +0 -266
- package/dist/observe/store/next/reconcile.js +0 -375
- package/dist/observe/store/next/store.js +0 -2480
- package/dist/prod/core/optimistic.js +0 -658
- package/dist/prod/store/next/optimistic.js +0 -710
- package/dist/prod/store/next/projection.js +0 -257
- package/dist/prod/store/next/reconcile.js +0 -373
- package/dist/prod/store/next/store.js +0 -2356
- package/dist/types/core/optimistic.d.ts +0 -6
- package/dist/types/store/next/optimistic.d.ts +0 -25
- package/dist/types/store/next/projection.d.ts +0 -27
- package/dist/types/store/next/reconcile.d.ts +0 -10
- package/dist/types/store/next/store.d.ts +0 -143
- package/dist/types/store/next/target.d.ts +0 -196
package/dist/prod/core/async.js
CHANGED
|
@@ -1,43 +1,39 @@
|
|
|
1
|
-
import { STATUS_UNINITIALIZED,
|
|
1
|
+
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, CONFIG_GUESS, CONFIG_AUTO_DISPOSE, REACTIVE_DIRTY, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_HELD, CONFIG_OVERRIDE, REACTIVE_ZOMBIE } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { untrack, ext,
|
|
3
|
+
import { untrack, ext, context, statusNotifierOf, setSignal } from "./core.js";
|
|
4
4
|
|
|
5
|
-
import "./
|
|
6
|
-
|
|
7
|
-
import { StatusError, NotReadyError } from "./error.js";
|
|
5
|
+
import { NotReadyError, StatusError } from "./error.js";
|
|
8
6
|
|
|
9
7
|
import { trimStaleDeps, unobserved } from "./graph.js";
|
|
10
8
|
|
|
11
9
|
import { enqueueSub } from "./heap.js";
|
|
12
10
|
|
|
13
|
-
import { assignOrMergeLane, resolveLane, resolveTransition } from "./lanes.js";
|
|
14
|
-
|
|
15
11
|
import { cleanup } from "./owner.js";
|
|
16
12
|
|
|
17
|
-
import {
|
|
13
|
+
import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush, liveTx, holdNode, globalQueue, txOf, GlobalQueue, queuePendingNode } from "./scheduler.js";
|
|
18
14
|
|
|
19
15
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
20
16
|
// predecessor — a singular slot promoted to a Set on the second source —
|
|
21
17
|
// created dual state whose migration invariant was easy to break: a third
|
|
22
18
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
23
19
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
24
|
-
function addPendingSource(e,
|
|
25
|
-
if (e.
|
|
26
|
-
(ext(e).
|
|
20
|
+
function addPendingSource(e, t) {
|
|
21
|
+
if (e.m?.Se?.has(t)) return false;
|
|
22
|
+
(ext(e).Se ??= new Set).add(t);
|
|
27
23
|
return true;
|
|
28
24
|
}
|
|
29
25
|
|
|
30
|
-
function removePendingSource(e,
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
33
|
-
if (!
|
|
26
|
+
function removePendingSource(e, t) {
|
|
27
|
+
const n = e.m?.Se;
|
|
28
|
+
if (!n?.delete(t)) return false;
|
|
29
|
+
if (!n.size) e.m.Se = undefined;
|
|
34
30
|
return true;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
function clearPendingSources(e) {
|
|
38
34
|
// This set is node-owned and never shared; dropping the sole reference
|
|
39
35
|
// releases the set and every entry without a redundant clear() walk.
|
|
40
|
-
if (e.
|
|
36
|
+
if (e.m !== null) e.m.Se = undefined;
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
// A rejection-pending only resolves through the settle sweep over the
|
|
@@ -45,10 +41,10 @@ function clearPendingSources(e) {
|
|
|
45
41
|
// edge: a dep that IS the source, or one whose own pending chain carries it
|
|
46
42
|
// (pending sources propagate the origin node, so this covers any depth).
|
|
47
43
|
// Also guards branch-local recovery: another dependency may still need the source.
|
|
48
|
-
function retryReaches(e,
|
|
49
|
-
for (let
|
|
50
|
-
const e =
|
|
51
|
-
if (e ===
|
|
44
|
+
function retryReaches(e, t) {
|
|
45
|
+
for (let n = e._; n; n = n.p) {
|
|
46
|
+
const e = n.I;
|
|
47
|
+
if (e === t || e.m?.Se?.has(t)) return true;
|
|
52
48
|
}
|
|
53
49
|
return false;
|
|
54
50
|
}
|
|
@@ -57,39 +53,35 @@ function retryReaches(e, n) {
|
|
|
57
53
|
* A loading-window node hit an unready source (sync throw in recompute, or a
|
|
58
54
|
* NotReadyError-rejected flight): register for the source's settle — the
|
|
59
55
|
* settlePendingSource walk runs off `_pendingSources` + `_blocked` alone —
|
|
60
|
-
* with NO read-visible pending status
|
|
61
|
-
*
|
|
62
|
-
*/ function parkLoadingWindow(e,
|
|
63
|
-
ext(e).
|
|
64
|
-
if (
|
|
56
|
+
* with NO read-visible pending status and no downstream propagation. Commit
|
|
57
|
+
* #0 keeps serving.
|
|
58
|
+
*/ function parkLoadingWindow(e, t) {
|
|
59
|
+
ext(e).Ie = true;
|
|
60
|
+
if (t.source) addPendingSource(e, t.source);
|
|
65
61
|
// A settled error is the node's answer ("the error stays the answer until
|
|
66
62
|
// this retry can actually run") — the park must not replace it: reads
|
|
67
63
|
// throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
|
|
68
64
|
// a pending-class NotReadyError from a read-invisible park (#2989).
|
|
69
|
-
if (!(e.
|
|
65
|
+
if (!(e.G & STATUS_ERROR)) setPendingError(e, t.source, t);
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
function setPendingError(e,
|
|
73
|
-
if (!
|
|
74
|
-
if (e.
|
|
68
|
+
function setPendingError(e, t, n) {
|
|
69
|
+
if (!t) {
|
|
70
|
+
if (e.m !== null) e.m.V = null;
|
|
75
71
|
return;
|
|
76
72
|
}
|
|
77
|
-
if (
|
|
78
|
-
ext(e).
|
|
73
|
+
if (n instanceof NotReadyError && n.source === t) {
|
|
74
|
+
ext(e).V = n;
|
|
79
75
|
return;
|
|
80
76
|
}
|
|
81
|
-
const r = e.
|
|
82
|
-
if (!(r instanceof NotReadyError) || r.source !==
|
|
83
|
-
ext(e).
|
|
77
|
+
const r = e.m?.V;
|
|
78
|
+
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
79
|
+
ext(e).V = new NotReadyError(t);
|
|
84
80
|
}
|
|
85
81
|
}
|
|
86
82
|
|
|
87
|
-
function forEachDependent(e,
|
|
88
|
-
for (let
|
|
89
|
-
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
90
|
-
for (let t = e.o?.i ?? null; t !== null; t = t.Ue) {
|
|
91
|
-
for (let e = t.u; e !== null; e = e.Ae) n(e.ge, e);
|
|
92
|
-
}
|
|
83
|
+
function forEachDependent(e, t) {
|
|
84
|
+
for (let n = e.t; n !== null; n = n.l) t(n.o, n);
|
|
93
85
|
}
|
|
94
86
|
|
|
95
87
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
@@ -103,7 +95,7 @@ function forEachDependent(e, n) {
|
|
|
103
95
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
104
96
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
105
97
|
function releaseIfSettledUnobserved(e) {
|
|
106
|
-
e.
|
|
98
|
+
e.re && e.u & CONFIG_AUTO_DISPOSE && !e.t && !(e.R & REACTIVE_ZOMBIE) && !(e.G & STATUS_PENDING) && unobserved(e);
|
|
107
99
|
}
|
|
108
100
|
|
|
109
101
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -111,16 +103,16 @@ function releaseIfSettledUnobserved(e) {
|
|
|
111
103
|
// the propagation completes, walk the same graph for stranded lazy nodes.
|
|
112
104
|
// Collect-then-release so unobserved() never unlinks under the walk.
|
|
113
105
|
function releaseSettledDependents(e) {
|
|
114
|
-
let
|
|
115
|
-
const
|
|
106
|
+
let t;
|
|
107
|
+
const n = new Set;
|
|
116
108
|
const visit = e => {
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
if (!e.
|
|
109
|
+
if (n.has(e)) return;
|
|
110
|
+
n.add(e);
|
|
111
|
+
if (!e.t && e.u & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
120
112
|
forEachDependent(e, visit);
|
|
121
113
|
};
|
|
122
114
|
forEachDependent(e, visit);
|
|
123
|
-
if (
|
|
115
|
+
if (t) for (const e of t) releaseIfSettledUnobserved(e);
|
|
124
116
|
}
|
|
125
117
|
|
|
126
118
|
// Error-dimension twin of settlePendingSource's blocked re-enqueue (#2949):
|
|
@@ -138,79 +130,84 @@ function releaseSettledDependents(e) {
|
|
|
138
130
|
// (releaseSettledDependents shape): identity holders can sit below an
|
|
139
131
|
// intermediate whose own error state has since been scrubbed or replaced
|
|
140
132
|
// (e.g. an error boundary's tree node).
|
|
141
|
-
function settleErroredDependents(e,
|
|
142
|
-
let
|
|
133
|
+
function settleErroredDependents(e, t) {
|
|
134
|
+
let n = false;
|
|
143
135
|
const r = new Set;
|
|
144
136
|
const visit = e => {
|
|
145
137
|
if (r.has(e)) return;
|
|
146
138
|
r.add(e);
|
|
147
|
-
if (e.
|
|
139
|
+
if (e.m?.V === t) {
|
|
148
140
|
enqueueSub(e);
|
|
149
|
-
|
|
141
|
+
n = true;
|
|
150
142
|
}
|
|
151
143
|
forEachDependent(e, visit);
|
|
152
144
|
};
|
|
153
145
|
forEachDependent(e, visit);
|
|
154
|
-
if (
|
|
146
|
+
if (n) schedule();
|
|
155
147
|
}
|
|
156
148
|
|
|
157
149
|
// Retire `source` from pending state along the dependent graph rooted at `el`.
|
|
158
150
|
// By default, `el` is the source whose flight settled or was superseded.
|
|
159
151
|
// With a distinct `source`, `el` is a recovered computation that dropped it:
|
|
160
152
|
// the source may still be pending, so dependents with another path to it stay pending.
|
|
161
|
-
function settlePendingSource(e,
|
|
153
|
+
function settlePendingSource(e, t = e) {
|
|
162
154
|
// Landing and branch recovery already cleared el's own set. Superseded
|
|
163
155
|
// re-parks can retain an abandoned self entry (source === el), which must
|
|
164
156
|
// retire in the same walk as its propagated copies.
|
|
165
|
-
removePendingSource(e,
|
|
166
|
-
let
|
|
157
|
+
removePendingSource(e, t);
|
|
158
|
+
let n = false;
|
|
167
159
|
let r;
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const settle = s => {
|
|
172
|
-
if (i.has(s)) return;
|
|
160
|
+
const o = new Set;
|
|
161
|
+
const settle = f => {
|
|
162
|
+
if (o.has(f) ||
|
|
173
163
|
// A conditional dropped this source, but another dependency can still
|
|
174
164
|
// carry it. Only retire pending state inherited through the recovered
|
|
175
165
|
// branch. Deliberately NOT marked visited on this early return: the
|
|
176
166
|
// carrying dependency may itself be a later branch of this same walk
|
|
177
167
|
// (two unchanged memos converging), and its visit must be free to
|
|
178
168
|
// re-examine this node once that branch has retired the source.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
t !== e && retryReaches(f, t) || !removePendingSource(f, t))
|
|
170
|
+
// A19: a verdict reader holds no pending of its own (it was re-derived
|
|
171
|
+
// when the source went pending, `propagateStatus`), and a landing
|
|
172
|
+
// equal to the committed value notifies nobody — the source settling
|
|
173
|
+
// is its verdict changing: it runs again.
|
|
174
|
+
return f.u & CONFIG_VERDICT && enqueueSub(f);
|
|
175
|
+
o.add(f);
|
|
176
|
+
f.Ne = clock;
|
|
177
|
+
const u = f.m?.Se?.values().next().value;
|
|
184
178
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
185
179
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
186
180
|
// otherwise): the settled error stays the answer through the settle —
|
|
187
181
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
188
182
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
189
|
-
const
|
|
183
|
+
const i = f.G & STATUS_ERROR;
|
|
190
184
|
if (u) {
|
|
191
|
-
if (!
|
|
192
|
-
o?.(s);
|
|
185
|
+
if (!i) setPendingError(f, u);
|
|
193
186
|
} else {
|
|
194
|
-
|
|
195
|
-
if (!
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
187
|
+
f.G &= ~STATUS_PENDING;
|
|
188
|
+
if (!i) setPendingError(f);
|
|
189
|
+
// L2: a landing resumes the transaction waiting on it (maintainer: "it
|
|
190
|
+
// resumes the sync frame") — a held reader's re-pass over the landed
|
|
191
|
+
// value is that transaction's work, and the flush that carries it
|
|
192
|
+
// parks into it.
|
|
193
|
+
if (f.u & CONFIG_HELD) joinFuture(txOf(f));
|
|
194
|
+
if (f.m?.Ie) {
|
|
195
|
+
enqueueSub(f);
|
|
196
|
+
n = true;
|
|
200
197
|
}
|
|
201
|
-
if (
|
|
198
|
+
if (f.m !== null) f.m.Ie = false;
|
|
202
199
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
203
200
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
204
201
|
// lists this walk is still iterating.
|
|
205
|
-
if (!
|
|
202
|
+
if (!f.t && f.u & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
|
|
206
203
|
}
|
|
207
|
-
forEachDependent(
|
|
204
|
+
forEachDependent(f, settle);
|
|
208
205
|
};
|
|
209
206
|
forEachDependent(e, settle);
|
|
210
207
|
// Release before the flush schedule below: unobserved() pulls the node back
|
|
211
208
|
// out of the heap, so the enqueueSub above never recomputes a released node.
|
|
212
209
|
if (r) for (const e of r) releaseIfSettledUnobserved(e);
|
|
213
|
-
if (
|
|
210
|
+
if (n) schedule();
|
|
214
211
|
}
|
|
215
212
|
|
|
216
213
|
// Object-thenable detection (Promises/A+ shape).
|
|
@@ -219,236 +216,124 @@ function isThenable(e) {
|
|
|
219
216
|
}
|
|
220
217
|
|
|
221
218
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
|
|
222
|
-
const
|
|
223
|
-
if (
|
|
224
|
-
e.
|
|
225
|
-
|
|
219
|
+
const t = e.m?.Te;
|
|
220
|
+
if (t != null) {
|
|
221
|
+
e.m.Te = null;
|
|
222
|
+
t();
|
|
226
223
|
}
|
|
227
224
|
}
|
|
228
225
|
|
|
229
|
-
function handleAsync(e, n,
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
226
|
+
function handleAsync(e, t, n,
|
|
227
|
+
// The flight rejected (after the node's status is set): a projection
|
|
228
|
+
// tells its leaves' readers, who are not the node's dependents
|
|
229
|
+
// (store/projection.ts). `pending`: a NotReady rejection — the node is
|
|
230
|
+
// pending on another source, not errored.
|
|
231
|
+
r) {
|
|
232
|
+
let o = false;
|
|
233
|
+
let f = false;
|
|
234
|
+
if (typeof t === "object" && t !== null) {
|
|
233
235
|
untrack(() => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
o = t[Symbol.asyncIterator];
|
|
237
|
+
f = !o && isThenable(t);
|
|
236
238
|
});
|
|
237
239
|
}
|
|
238
|
-
if (!
|
|
239
|
-
if (e.
|
|
240
|
+
if (!f && !o) {
|
|
241
|
+
if (e.m !== null) e.m.De = null;
|
|
240
242
|
// A sync landing is the first real answer for a loadingValue node.
|
|
241
|
-
e.
|
|
242
|
-
return
|
|
243
|
+
e._e = false;
|
|
244
|
+
return t;
|
|
243
245
|
}
|
|
244
246
|
// Flight replacement relies on recompute's supersede release for iterator
|
|
245
247
|
// teardown (#3122): every handleAsync call — including the projection
|
|
246
248
|
// self-registration — runs during a recompute of `el`, which has already
|
|
247
249
|
// fired _flightTeardown. A future non-recompute registration path must
|
|
248
250
|
// release it here before overwriting _inFlight.
|
|
249
|
-
ext(e).
|
|
251
|
+
ext(e).De = t;
|
|
252
|
+
// The question this flight answers (A18 provenance, lanes.ts): the action
|
|
253
|
+
// whose slice asked it; mainline is always the current question.
|
|
254
|
+
e.m.Oe = question || MAINLINE_QUESTION;
|
|
250
255
|
// The run that asked this flight read every input without throwing: an
|
|
251
256
|
// input still in flight was masked for it (an active override, A17), so
|
|
252
257
|
// pending state those inputs propagated onto the node earlier does not
|
|
253
258
|
// describe this answer. Drop it — the flight is the node's pending now.
|
|
254
259
|
// The landing retires only the flight's own entry (landStatus, #3373), so
|
|
255
260
|
// an entry that survived here would hold the node past its own answer.
|
|
256
|
-
e.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
// stale answer from its own.
|
|
261
|
-
const o = origin;
|
|
262
|
-
let s;
|
|
263
|
-
// Settle-time transition re-entry. The loading rail is invisible to
|
|
264
|
-
// transactions (#2933): a boundary-caught first load never registers as an
|
|
265
|
-
// async reporter, so its settle — the boundary's fallback -> content
|
|
266
|
-
// reveal — must flow ambiently. The node can still carry a `_transition`
|
|
267
|
-
// stamp (pending-node bookkeeping rides through the stamping sites), and
|
|
268
|
-
// blindly re-entering that stamped, still-incomplete transaction stashed
|
|
269
|
-
// the reveal with it — a deadlock when the transaction's completion
|
|
270
|
-
// depended on the reveal (#2937). An ESCAPED first load did register and
|
|
271
|
-
// keeps transition scheduling; initialized (value-holding) pending settles
|
|
272
|
-
// are the transaction's reveal machinery and always re-enter.
|
|
273
|
-
const settleTransition = () => {
|
|
274
|
-
let n = resolveTransition(e);
|
|
275
|
-
// A lane-routed node's landing is revealed by its lane, ahead of the
|
|
276
|
-
// transaction that owns the lane (whose own commit is only the override's
|
|
277
|
-
// confirm/revert). Entering that owner here would fold every transaction
|
|
278
|
-
// waiting on this flight into it at the landing — a reveal that
|
|
279
|
-
// discovered the flight (#3305) would then wait on the owner's action
|
|
280
|
-
// instead of on the flight (#3334). Enter the waiter: the transaction
|
|
281
|
-
// whose blocker this landing clears. Then every transaction waiting on
|
|
282
|
-
// the flight folds in (enterWaiting): a reveal that discovered it
|
|
283
|
-
// completes at its landing (A15) — a stampless node's fresh batch
|
|
284
|
-
// included (its flight started under a batch that committed beneath it,
|
|
285
|
-
// #3305). The fold used to happen as each stamped reader recomputed,
|
|
286
|
-
// which effects no longer do (#3407).
|
|
287
|
-
if (e.o?.me) n = waitingTransition(e) ?? n;
|
|
288
|
-
if (n && e.h & STATUS_UNINITIALIZED && !currentTransition(n).le.has(e)) {
|
|
289
|
-
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
290
|
-
// stash-path restamp both re-enter the transaction through it.
|
|
291
|
-
e.we = null;
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
globalQueue.initTransition(n);
|
|
295
|
-
enterWaiting(e);
|
|
296
|
-
};
|
|
297
|
-
const handleError = t => {
|
|
298
|
-
if (e.o?.Ce !== n) return;
|
|
261
|
+
e.m.Se = undefined;
|
|
262
|
+
let u;
|
|
263
|
+
const handleError = n => {
|
|
264
|
+
if (e.m?.De !== t) return;
|
|
299
265
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
300
|
-
let
|
|
301
|
-
if (
|
|
266
|
+
let o = n instanceof NotReadyError;
|
|
267
|
+
if (o && e._e) {
|
|
302
268
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
303
269
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
304
270
|
// dependency throws. The dead flight is released so the clock-gated
|
|
305
271
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
306
|
-
if (e.
|
|
307
|
-
parkLoadingWindow(e,
|
|
308
|
-
e.
|
|
272
|
+
if (e.m !== null) e.m.De = null;
|
|
273
|
+
parkLoadingWindow(e, n);
|
|
274
|
+
e.Ne = clock;
|
|
309
275
|
return;
|
|
310
276
|
}
|
|
311
|
-
|
|
312
|
-
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, t);
|
|
277
|
+
notifyStatus(e, o ? STATUS_PENDING : STATUS_ERROR, n);
|
|
313
278
|
// A NotReady rejection is a landing into another pending source. The
|
|
314
279
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
315
280
|
// after notifyStatus has propagated the replacement source.
|
|
316
|
-
if (
|
|
317
|
-
e.
|
|
281
|
+
if (o) settlePendingSource(e);
|
|
282
|
+
e.Ne = clock;
|
|
318
283
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
319
284
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
320
285
|
// the error twin of settlePendingSource's release (#2934).
|
|
321
|
-
if (!
|
|
286
|
+
if (!o) releaseSettledDependents(e);
|
|
287
|
+
r?.(n, o);
|
|
322
288
|
};
|
|
323
|
-
const asyncWrite = (r,
|
|
324
|
-
if (e.
|
|
289
|
+
const asyncWrite = (r, o) => {
|
|
290
|
+
if (e.m?.De !== t) return;
|
|
325
291
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
326
292
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
327
293
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
328
|
-
if (e.
|
|
329
|
-
|
|
330
|
-
// the flush below, which clears it.
|
|
331
|
-
setOrigin(o);
|
|
332
|
-
settleTransition();
|
|
333
|
-
const s = !!(e.h & STATUS_UNINITIALIZED);
|
|
334
|
-
// Captured before clearStatus wipes it: a quiet re-ask's landing may be
|
|
335
|
-
// transition-held below, and the displayed value keeps answering the same
|
|
336
|
-
// question until the hold commits — the classification must survive to
|
|
337
|
-
// that reveal or companion synchronization briefly classifies the held
|
|
338
|
-
// old value as pending, a one-frame pulse to direct observers (#3178).
|
|
339
|
-
// A truthy capture implies `_x` exists, so the restore writes it directly.
|
|
340
|
-
const u = e.o?.Le;
|
|
294
|
+
if (e.R & REACTIVE_DIRTY) return;
|
|
295
|
+
const f = !!(e.G & STATUS_UNINITIALIZED);
|
|
341
296
|
landStatus(e);
|
|
342
|
-
if (
|
|
343
|
-
const l = resolveLane(e);
|
|
344
|
-
if (l) l.Qe.delete(e);
|
|
345
|
-
if (t) {
|
|
297
|
+
if (n) {
|
|
346
298
|
try {
|
|
347
|
-
|
|
299
|
+
n(r);
|
|
348
300
|
} catch (e) {
|
|
349
301
|
handleError(e);
|
|
350
302
|
return;
|
|
351
303
|
}
|
|
352
|
-
if (
|
|
353
|
-
} else if (e.o?.Fe !== undefined && !(l && e.C & CONFIG_DERIVED_OVERRIDE)) {
|
|
354
|
-
// A derived override's landing UNDER its lane is the lane's own work
|
|
355
|
-
// (the branch below); demoted — its source superseded (A18) — the
|
|
356
|
-
// landing is the truth the correction asked for, and holds and
|
|
357
|
-
// supersedes here like the sync twin (recompute). Otherwise:
|
|
358
|
-
// Optimistic node — resting OR covered by an active override — holds
|
|
359
|
-
// through the shared pending-node path, exactly like a plain async memo,
|
|
360
|
-
// so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
|
|
361
|
-
// _value happens on this value's OWN transition schedule (A18 as
|
|
362
|
-
// re-ruled 2026-07-07: _value only changes at commit points). With an
|
|
363
|
-
// override active the hold and its eventual commit are unobservable
|
|
364
|
-
// (A17 — every reader sees the override); the revert reveals whatever
|
|
365
|
-
// has committed by then, so corrections reveal atomically with their
|
|
366
|
-
// transition rather than escaping it.
|
|
367
|
-
if (e._e === NOT_PENDING) queuePendingNode(e);
|
|
368
|
-
e._e = r;
|
|
369
|
-
// The hold is a companion-visible write like any other (A13/A19): the
|
|
370
|
-
// clearStatus() above computed its verdict before the hold existed, so
|
|
371
|
-
// isPending must re-derive (the value is not final until commit — V1)
|
|
372
|
-
// and latest() must see the fresh in-flight value (V2). Subscribers are
|
|
373
|
-
// only notified when the hold is visible to them: under an active
|
|
374
|
-
// override every reader sees the override (A17), so waking subs would
|
|
375
|
-
// re-show an unchanged view — the revert is the notification point.
|
|
376
|
-
// Under an override the landing is handed to the engine's
|
|
377
|
-
// supersedeOverride (A18 supersession, #3331): own-source truth that
|
|
378
|
-
// differs from the override ends the optimism for the graph now (plain
|
|
379
|
-
// channel, lane demoted); a matching arrival is silent except to an
|
|
380
|
-
// authoritative-view reader (until()'s predicate) waiting on exactly
|
|
381
|
-
// this staged truth (#3164 — without the wake the hold deadlocks: the
|
|
382
|
-
// landing waits on the transaction, the transaction on the action, the
|
|
383
|
-
// action on an until() never re-notified). The hook is installed with
|
|
384
|
-
// the engine, which an active override implies. The propagation runs
|
|
385
|
-
// under this flight's provenance (setOrigin above).
|
|
386
|
-
GlobalQueue.Ve?.(e, r);
|
|
387
|
-
if (!hasActiveOverride(e)) {
|
|
388
|
-
insertSubs(e);
|
|
389
|
-
} else GlobalQueue.ke(e, r);
|
|
390
|
-
e.be = clock;
|
|
391
|
-
} else if (l) {
|
|
392
|
-
// Route through lane's effect queue for independent flushing
|
|
393
|
-
const n = e.je;
|
|
394
|
-
const t = hasActiveOverride(e) ? unwrapOverride(e.o.Fe) : e.ce;
|
|
395
|
-
const i = e.xe;
|
|
396
|
-
try {
|
|
397
|
-
// `(prev, next)`, as every other commit path calls the comparator — a
|
|
398
|
-
// user comparator keyed on which side is incoming (dynamic's binding
|
|
399
|
-
// gate) reads the lane landing the same way it reads a sync commit.
|
|
400
|
-
if (!n && s || !i || !i(t, r)) {
|
|
401
|
-
// Lanes stage (#3479): a memo's landing under its lane is a derived
|
|
402
|
-
// override, as its sync pass's result is (recompute) — `_value`
|
|
403
|
-
// stays the committed truth for readers off the lane.
|
|
404
|
-
if (n) e.ce = r; else GlobalQueue.Me(e, r, l);
|
|
405
|
-
e.be = clock;
|
|
406
|
-
// The latest() shadow write gives latest() effects independent lanes; the
|
|
407
|
-
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
408
|
-
// (computePendingState doesn't read _value).
|
|
409
|
-
GlobalQueue.Ve?.(e, r);
|
|
410
|
-
insertSubs(e, true);
|
|
411
|
-
}
|
|
412
|
-
} catch (n) {
|
|
413
|
-
// A user comparator throwing during async resolution has no caller to
|
|
414
|
-
// surface to (we're in promise machinery) — route it through the node's
|
|
415
|
-
// error status so boundaries contain it instead of an unhandled
|
|
416
|
-
// rejection (#2837).
|
|
417
|
-
notifyStatus(e, STATUS_ERROR, n);
|
|
418
|
-
}
|
|
304
|
+
if (f) landStatus(e, true);
|
|
419
305
|
} else {
|
|
306
|
+
// CARVE 2: the override-covered landing (hold + A18 supersession) and the
|
|
307
|
+
// lane-routed landing (derived override, lane effect queue) went with
|
|
308
|
+
// the optimistic engine; every landing is the plain setSignal. A first
|
|
309
|
+
// answer born into a hold still live lands into it (A29, #3800).
|
|
310
|
+
let t = e.m.Re;
|
|
311
|
+
e.m.Re = null;
|
|
312
|
+
if (f && t && (t = liveTx(t))) holdNode(e, t);
|
|
420
313
|
try {
|
|
421
314
|
setSignal(e, () => r);
|
|
422
|
-
} catch (
|
|
315
|
+
} catch (t) {
|
|
423
316
|
// Same containment as above: setSignal's comparator throw is the only
|
|
424
317
|
// pre-commit failure here, and there is no user callsite to throw to.
|
|
425
|
-
notifyStatus(e, STATUS_ERROR,
|
|
318
|
+
notifyStatus(e, STATUS_ERROR, t);
|
|
426
319
|
}
|
|
427
320
|
}
|
|
428
321
|
// First real answer landing: the window closes when the answer becomes
|
|
429
|
-
// OBSERVABLE. A direct commit is observable now; a
|
|
430
|
-
// (`_pendingValue` set
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (e._e === NOT_PENDING) {
|
|
436
|
-
e.ve = false;
|
|
437
|
-
if (u) e.o.Le = false;
|
|
322
|
+
// OBSERVABLE. A direct commit is observable now; a staged write
|
|
323
|
+
// (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
|
|
324
|
+
// the window when the flush commits it, so no one-frame pulse can leak to
|
|
325
|
+
// observers between the landing and its commit (#2990).
|
|
326
|
+
if (e.Ae === NOT_PENDING) {
|
|
327
|
+
e._e = false;
|
|
438
328
|
// The landing published: the dependency tail the flight's pass left
|
|
439
|
-
// linked goes now (A30, #3410). A
|
|
440
|
-
//
|
|
441
|
-
// from the previous pass's inputs, and a mainline write to one of them
|
|
442
|
-
// must reach this node and join its hold (its stamp) instead of
|
|
443
|
-
// publishing beside the stale derivation (#3461: `b() ? b() : a()`
|
|
444
|
-
// held on `b` dropped `a` at its landing, and `A: 1` then committed
|
|
445
|
-
// beside `Selected: 0`). `commitPendingNode` trims a held landing.
|
|
329
|
+
// linked goes now (A30, #3410). A staged landing has not replaced the
|
|
330
|
+
// committed frame yet; `commitPendingNode` trims it.
|
|
446
331
|
trimStaleDeps(e);
|
|
447
332
|
}
|
|
448
333
|
settlePendingSource(e);
|
|
449
334
|
schedule();
|
|
450
335
|
flush();
|
|
451
|
-
|
|
336
|
+
o?.();
|
|
452
337
|
};
|
|
453
338
|
// A pending node's in-flight promise is an observer: `unlinkSubs` skips
|
|
454
339
|
// autodispose while STATUS_PENDING so subscriber churn can't orphan the
|
|
@@ -458,7 +343,7 @@ function handleAsync(e, n, t) {
|
|
|
458
343
|
// Returns whether the node released, so the iterator branch can stop
|
|
459
344
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
460
345
|
const settleAutodispose = () => {
|
|
461
|
-
if (e.
|
|
346
|
+
if (e.u & CONFIG_AUTO_DISPOSE && !e.t && !(e.G & STATUS_PENDING)) {
|
|
462
347
|
unobserved(e);
|
|
463
348
|
return true;
|
|
464
349
|
}
|
|
@@ -475,25 +360,24 @@ function handleAsync(e, n, t) {
|
|
|
475
360
|
// the thenable branch pre-registered while it still owned the context.
|
|
476
361
|
// Returns whether a sync answer landed (first yield or empty completion) —
|
|
477
362
|
// meaningful only in the live posture.
|
|
478
|
-
const consumeIterator = (
|
|
479
|
-
const
|
|
480
|
-
let
|
|
481
|
-
let
|
|
482
|
-
let
|
|
363
|
+
const consumeIterator = (n, r) => {
|
|
364
|
+
const o = n[Symbol.asyncIterator]();
|
|
365
|
+
let f = false;
|
|
366
|
+
let i = false;
|
|
367
|
+
let s = !r;
|
|
483
368
|
const close = () => {
|
|
484
|
-
if (
|
|
485
|
-
|
|
369
|
+
if (i) return;
|
|
370
|
+
i = true;
|
|
486
371
|
try {
|
|
487
|
-
const e =
|
|
372
|
+
const e = o.return?.();
|
|
488
373
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
489
374
|
} catch {}
|
|
490
375
|
};
|
|
491
376
|
r ? r(close) : cleanup(close);
|
|
492
377
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
493
|
-
// owner-death backstop
|
|
494
|
-
//
|
|
495
|
-
|
|
496
|
-
ext(e).ye = close;
|
|
378
|
+
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
379
|
+
// sites so supersede stops this stream immediately.
|
|
380
|
+
ext(e).Te = close;
|
|
497
381
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
498
382
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
499
383
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
@@ -501,13 +385,13 @@ function handleAsync(e, n, t) {
|
|
|
501
385
|
if (!settleAutodispose()) iterate();
|
|
502
386
|
};
|
|
503
387
|
const iterate = () => {
|
|
504
|
-
let
|
|
388
|
+
let n, r, l = false, a = false, c = true;
|
|
505
389
|
// Protocol tolerance, matching `for await`: `await` unwraps whatever
|
|
506
390
|
// next() returns — a thenable OR a bare IteratorResult. Real producers
|
|
507
391
|
// use the bare form as a promise-free fast path when a value is already
|
|
508
392
|
// buffered (seroval's deserialized streams do), so a bare result is
|
|
509
393
|
// assimilated as an already-settled step instead of crashing on `.then`.
|
|
510
|
-
const S =
|
|
394
|
+
const S = o.next();
|
|
511
395
|
const d = isThenable(S) ? S : {
|
|
512
396
|
then: e => void e(S)
|
|
513
397
|
};
|
|
@@ -519,18 +403,18 @@ function handleAsync(e, n, t) {
|
|
|
519
403
|
// stash: it must write through the async path or the value is
|
|
520
404
|
// silently dropped. (The deferred posture never has a caller, so
|
|
521
405
|
// initialRead starts false there and everything writes through.)
|
|
522
|
-
if (c &&
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (r.done)
|
|
526
|
-
} else if (e.
|
|
406
|
+
if (c && s) {
|
|
407
|
+
n = r;
|
|
408
|
+
l = true;
|
|
409
|
+
if (r.done) i = true;
|
|
410
|
+
} else if (e.m?.De !== t) {
|
|
527
411
|
return;
|
|
528
412
|
} else if (!r.done) {
|
|
529
|
-
|
|
413
|
+
f = true;
|
|
530
414
|
asyncWrite(r.value, iterateOrRelease);
|
|
531
415
|
} else {
|
|
532
|
-
|
|
533
|
-
if (
|
|
416
|
+
i = true;
|
|
417
|
+
if (f) {
|
|
534
418
|
schedule();
|
|
535
419
|
flush();
|
|
536
420
|
} else {
|
|
@@ -539,142 +423,128 @@ function handleAsync(e, n, t) {
|
|
|
539
423
|
}
|
|
540
424
|
settleAutodispose();
|
|
541
425
|
}
|
|
542
|
-
},
|
|
543
|
-
if (c &&
|
|
544
|
-
r =
|
|
426
|
+
}, n => {
|
|
427
|
+
if (c && s) {
|
|
428
|
+
r = n;
|
|
545
429
|
a = true;
|
|
546
|
-
} else if (e.
|
|
547
|
-
|
|
548
|
-
handleError(
|
|
430
|
+
} else if (e.m?.De === t) {
|
|
431
|
+
i = true;
|
|
432
|
+
handleError(n);
|
|
549
433
|
settleAutodispose();
|
|
550
434
|
}
|
|
551
435
|
});
|
|
552
436
|
c = false;
|
|
553
437
|
if (a) {
|
|
554
438
|
// Match the promise branch, but only rethrow during the initial read.
|
|
555
|
-
|
|
439
|
+
i = true;
|
|
556
440
|
handleError(r);
|
|
557
|
-
if (
|
|
441
|
+
if (s) throw r;
|
|
558
442
|
return true;
|
|
559
443
|
}
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
-
|
|
444
|
+
if (l && !n.done) {
|
|
445
|
+
u = n.value;
|
|
446
|
+
f = true;
|
|
563
447
|
return iterate();
|
|
564
448
|
}
|
|
565
|
-
return
|
|
449
|
+
return l && n.done;
|
|
566
450
|
};
|
|
567
|
-
const
|
|
451
|
+
const l = iterate();
|
|
568
452
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
569
|
-
|
|
570
|
-
return
|
|
453
|
+
s = false;
|
|
454
|
+
return f || l;
|
|
571
455
|
};
|
|
572
456
|
// Landed-synchronously verdict for a LIVE iterator drain; null when no live
|
|
573
457
|
// drain ran (plain promise flight, or a deferred flatten). Drives the
|
|
574
458
|
// shared NotReady/loading tail below.
|
|
575
|
-
let
|
|
459
|
+
let i = null;
|
|
576
460
|
// Flatten one async level: a thenable that RESOLVES to an AsyncIterable —
|
|
577
461
|
// the shape every async stub returning a stream produces — consumes as the
|
|
578
462
|
// stream itself rather than settling on the iterable object. One level
|
|
579
463
|
// only: A+ `then` already collapses nested thenables, so the resolved
|
|
580
464
|
// value is never itself a thenable.
|
|
581
|
-
const flattenIfIterable = (e,
|
|
582
|
-
let
|
|
465
|
+
const flattenIfIterable = (e, t) => {
|
|
466
|
+
let n = false;
|
|
583
467
|
if (typeof e === "object" && e !== null) {
|
|
584
468
|
untrack(() => {
|
|
585
|
-
|
|
469
|
+
n = e[Symbol.asyncIterator];
|
|
586
470
|
});
|
|
587
471
|
}
|
|
588
|
-
if (!
|
|
589
|
-
const r = consumeIterator(e,
|
|
590
|
-
if (!
|
|
472
|
+
if (!n) return false;
|
|
473
|
+
const r = consumeIterator(e, t);
|
|
474
|
+
if (!t) i = r;
|
|
591
475
|
return true;
|
|
592
476
|
};
|
|
593
|
-
if (
|
|
594
|
-
let
|
|
477
|
+
if (f) {
|
|
478
|
+
let n = false, r = false, o, f = true;
|
|
595
479
|
// Close registration for the flattening path. Consumption starts in a
|
|
596
480
|
// microtask where the ambient owner is gone (or worse, someone else's),
|
|
597
481
|
// so `cleanup()` can't be used — the close targets el's disposal list
|
|
598
482
|
// directly, exactly where a live cleanup() during this recompute would
|
|
599
|
-
// have put it.
|
|
600
|
-
//
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
// becomes disposal-bearing, which is exactly the class a directly
|
|
604
|
-
// returned iterable already occupies.
|
|
605
|
-
const registerDeferredClose = n => {
|
|
606
|
-
if (!e.qe) e.qe = n; else if (Array.isArray(e.qe)) e.qe.push(n); else e.qe = [ e.qe, n ];
|
|
483
|
+
// have put it. Only a flight that actually flattens becomes
|
|
484
|
+
// disposal-bearing.
|
|
485
|
+
const registerDeferredClose = t => {
|
|
486
|
+
if (!e.Pe) e.Pe = t; else if (Array.isArray(e.Pe)) e.Pe.push(t); else e.Pe = [ e.Pe, t ];
|
|
607
487
|
};
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
} else if (e.
|
|
488
|
+
t.then(r => {
|
|
489
|
+
if (f) {
|
|
490
|
+
u = r;
|
|
491
|
+
n = true;
|
|
492
|
+
} else if (e.m?.De === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
|
|
613
493
|
asyncWrite(r);
|
|
614
494
|
settleAutodispose();
|
|
615
495
|
}
|
|
616
496
|
}, e => {
|
|
617
|
-
if (
|
|
618
|
-
|
|
497
|
+
if (f) {
|
|
498
|
+
o = e;
|
|
619
499
|
r = true;
|
|
620
500
|
} else {
|
|
621
501
|
handleError(e);
|
|
622
502
|
settleAutodispose();
|
|
623
503
|
}
|
|
624
504
|
});
|
|
625
|
-
|
|
505
|
+
f = false;
|
|
626
506
|
if (r) {
|
|
627
507
|
// Settle through the same status path an async rejection uses, then
|
|
628
508
|
// unwind the in-progress synchronous read so the errored node isn't
|
|
629
509
|
// momentarily read as `undefined`.
|
|
630
|
-
handleError(
|
|
631
|
-
throw
|
|
632
|
-
} else if (!
|
|
633
|
-
// Loading window: serve commit #0 instead of suspending
|
|
634
|
-
//
|
|
635
|
-
//
|
|
636
|
-
//
|
|
637
|
-
if (e.
|
|
638
|
-
globalQueue.initTransition(resolveTransition(e));
|
|
510
|
+
handleError(o);
|
|
511
|
+
throw o;
|
|
512
|
+
} else if (!n) {
|
|
513
|
+
// Loading window: serve commit #0 instead of suspending — first-flight
|
|
514
|
+
// work on a loadingValue node is loading-class (invisible to
|
|
515
|
+
// boundaries); the flight itself is already registered in _inFlight and
|
|
516
|
+
// lands through asyncWrite.
|
|
517
|
+
if (e._e) return e.pe;
|
|
639
518
|
throw new NotReadyError(context);
|
|
640
|
-
} else if (!flattenIfIterable(
|
|
519
|
+
} else if (!flattenIfIterable(u)) {
|
|
641
520
|
// Synchronously-resolved promise: the first real answer landed.
|
|
642
|
-
e.
|
|
521
|
+
e._e = false;
|
|
643
522
|
}
|
|
644
523
|
// A sync-resolved promise holding an AsyncIterable flattened LIVE (we
|
|
645
524
|
// are still inside the synchronous read): full initial-drain semantics
|
|
646
525
|
// apply and the shared tail below settles the verdict.
|
|
647
526
|
}
|
|
648
|
-
if (
|
|
649
|
-
if (
|
|
650
|
-
if (!
|
|
527
|
+
if (o) flattenIfIterable(t);
|
|
528
|
+
if (i !== null) {
|
|
529
|
+
if (!i) {
|
|
651
530
|
// Loading window: serve commit #0 (see the promise branch above).
|
|
652
|
-
if (e.
|
|
653
|
-
globalQueue.initTransition(resolveTransition(e));
|
|
531
|
+
if (e._e) return e.pe;
|
|
654
532
|
throw new NotReadyError(context);
|
|
655
533
|
}
|
|
656
534
|
// A sync first yield (or immediate empty completion) is the first real
|
|
657
535
|
// answer; async yields clear inside asyncWrite.
|
|
658
|
-
e.
|
|
536
|
+
e._e = false;
|
|
659
537
|
}
|
|
660
|
-
return
|
|
538
|
+
return u;
|
|
661
539
|
}
|
|
662
540
|
|
|
663
|
-
function clearStatus(e,
|
|
664
|
-
if (e.
|
|
665
|
-
if (e.
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
e.h = n ? 0 : e.h & STATUS_UNINITIALIZED;
|
|
671
|
-
if (e.o?._) setPendingError(e);
|
|
672
|
-
// Update pending signal for isPending() reactivity (companions only exist
|
|
673
|
-
// once the verdict layer created them, which installs the hooks).
|
|
674
|
-
if (e.o?.Ze || e.o?.He) GlobalQueue.Ge(e);
|
|
675
|
-
if (e.o?.i && e.C & CONFIG_CHILD_COMPANIONS && GlobalQueue.We !== null) GlobalQueue.We(e);
|
|
676
|
-
const t = statusNotifierOf(e);
|
|
677
|
-
if (t) t.call(e);
|
|
541
|
+
function clearStatus(e, t = false) {
|
|
542
|
+
if (e.m?.Se) clearPendingSources(e);
|
|
543
|
+
if (e.m?.Ie) if (e.m !== null) e.m.Ie = false;
|
|
544
|
+
e.G = t ? 0 : e.G & STATUS_UNINITIALIZED;
|
|
545
|
+
if (e.m?.V) setPendingError(e);
|
|
546
|
+
const n = statusNotifierOf(e);
|
|
547
|
+
if (n) n.call(e);
|
|
678
548
|
}
|
|
679
549
|
|
|
680
550
|
/**
|
|
@@ -685,9 +555,8 @@ function clearStatus(e, n = false) {
|
|
|
685
555
|
* is in the air, #3373) marks `b` pending on `a` by propagation, with `b`'s
|
|
686
556
|
* flight still current: nothing superseded it (the re-ask only changed `a`'s
|
|
687
557
|
* status, not yet its value), so the landing arrives, and a full clear made
|
|
688
|
-
* `b` answer with the stale value — the
|
|
689
|
-
*
|
|
690
|
-
* derived value (`2 / 1`); `isPending(b)` read false for the gap (#3376).
|
|
558
|
+
* `b` answer with the stale value — the newer signal committed beside the
|
|
559
|
+
* older derived value (`2 / 1`) for the gap (#3376).
|
|
691
560
|
* With another source still pending the node stays derivatively pending on
|
|
692
561
|
* it; the landed value is written below (the staged answer is still the
|
|
693
562
|
* answer for the inputs it was asked with) and the input's own settle
|
|
@@ -702,121 +571,117 @@ function clearStatus(e, n = false) {
|
|
|
702
571
|
* the first landing retires UNINITIALIZED. `_error` must move off self: a
|
|
703
572
|
* reader thrown NotReady(self) would park on a retired entry. Companions
|
|
704
573
|
* keep their verdict (pending before and after; the write re-syncs them).
|
|
705
|
-
*/ function landStatus(e,
|
|
706
|
-
const
|
|
574
|
+
*/ function landStatus(e, t = false) {
|
|
575
|
+
const n = e.m?.Se;
|
|
707
576
|
// (The full clear below drops the set whether or not self was retired first.)
|
|
708
|
-
if (
|
|
709
|
-
e.
|
|
710
|
-
if (
|
|
711
|
-
setPendingError(e,
|
|
712
|
-
} else clearStatus(e,
|
|
577
|
+
if (n && (n.delete(e), n.size)) {
|
|
578
|
+
e.m.Ie = false;
|
|
579
|
+
if (t) e.G = STATUS_PENDING;
|
|
580
|
+
setPendingError(e, n.values().next().value);
|
|
581
|
+
} else clearStatus(e, t);
|
|
713
582
|
}
|
|
714
583
|
|
|
715
|
-
function notifyStatus(e,
|
|
584
|
+
function notifyStatus(e, t, n, r) {
|
|
716
585
|
// Wrap regular errors to track source node
|
|
717
|
-
if (
|
|
718
|
-
const o =
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
// derived override (#3479) is a previous speculative answer on a plain
|
|
723
|
-
// member — pending flows through it as through any memo.
|
|
724
|
-
const u = n === STATUS_PENDING && e.o?.Fe !== undefined && !(e.C & CONFIG_DERIVED_OVERRIDE) && !s;
|
|
725
|
-
const l = u && hasActiveOverride(e);
|
|
726
|
-
if (!r) {
|
|
727
|
-
// Lane before companions: the companion pokes below may create the
|
|
728
|
-
// node's pending-signal lane, whose parent is read from the node's lane
|
|
729
|
-
// at creation. Assigned after them (as it was), a node made pending by
|
|
730
|
-
// propagation before it rode the lane got a parentless companion lane,
|
|
731
|
-
// and the isPending reader that also depends on the node merged it into
|
|
732
|
-
// the held lane — the verdict then waited on the async it reports (#3379).
|
|
733
|
-
if (i) assignOrMergeLane(e, i);
|
|
734
|
-
if (n === STATUS_PENDING && o) {
|
|
586
|
+
if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
|
|
587
|
+
const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
588
|
+
// (CARVE 2: the lane assignment went with the engine.)
|
|
589
|
+
{
|
|
590
|
+
if (t === STATUS_PENDING && o) {
|
|
735
591
|
addPendingSource(e, o);
|
|
736
|
-
|
|
737
|
-
//
|
|
738
|
-
//
|
|
739
|
-
|
|
740
|
-
e.h = STATUS_PENDING | e.h & STATUS_UNINITIALIZED;
|
|
741
|
-
// Preserve the current source on this propagation so render-effect notification
|
|
742
|
-
// can register every distinct pending source with the transition.
|
|
743
|
-
setPendingError(e, o, t);
|
|
592
|
+
e.G = STATUS_PENDING | e.G & STATUS_UNINITIALIZED;
|
|
593
|
+
// Preserve the current source on this propagation so readers park on
|
|
594
|
+
// the distinct pending source.
|
|
595
|
+
setPendingError(e, o, n);
|
|
744
596
|
} else {
|
|
745
597
|
clearPendingSources(e);
|
|
746
|
-
e.
|
|
747
|
-
ext(e).
|
|
598
|
+
e.G = t | (t !== STATUS_ERROR ? e.G & STATUS_UNINITIALIZED : 0);
|
|
599
|
+
ext(e).V = n;
|
|
748
600
|
}
|
|
749
|
-
GlobalQueue.Ge?.(e);
|
|
750
|
-
if (e.o?.i && e.C & CONFIG_CHILD_COMPANIONS && GlobalQueue.We !== null) GlobalQueue.We(e);
|
|
751
601
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
if (
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
602
|
+
// Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
|
|
603
|
+
// future value until we know otherwise"). Its own source in flight is its
|
|
604
|
+
// status, not its readers': they read the guess. The flight is the parent
|
|
605
|
+
// transition's to wait on — the frame it was asked in holds (A17: "a
|
|
606
|
+
// transition whose optimistic node is still pending on its own fetch is
|
|
607
|
+
// not complete"), through the node itself (`blocked`).
|
|
608
|
+
if (t === STATUS_PENDING && e.u & CONFIG_GUESS) {
|
|
609
|
+
if (passLane === null) joinFuture(null);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const f = statusNotifierOf(e);
|
|
613
|
+
if (f) {
|
|
614
|
+
{
|
|
615
|
+
f.call(e);
|
|
763
616
|
}
|
|
764
617
|
return;
|
|
765
618
|
}
|
|
766
|
-
|
|
767
|
-
|
|
619
|
+
propagateStatus(e, t, n);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** The dependents' half of `notifyStatus`: `el`'s status reaches each
|
|
623
|
+
* subscriber as a propagated mark (or a re-derive). On its own for a store
|
|
624
|
+
* family's leaves, which are not the derive's dependents — the family
|
|
625
|
+
* propagates the derive's status from each leaf to the leaf's readers
|
|
626
|
+
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
|
|
627
|
+
const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
628
|
+
forEachDependent(e, (r, f) => {
|
|
629
|
+
r.Ne = clock;
|
|
768
630
|
// A pending mark on a kept-tail link re-derives the subscriber instead of
|
|
769
631
|
// marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
|
|
770
632
|
// Past `_depsTail` lie the committed frame's deps, kept by A30 because
|
|
771
633
|
// that frame still derives from them while the pass that dropped them is
|
|
772
|
-
//
|
|
773
|
-
//
|
|
774
|
-
//
|
|
775
|
-
//
|
|
776
|
-
// never reads — an orphaned fetch held the truth (a hide joined to a
|
|
777
|
-
// parked action, A34), and a manual flight nobody awaited held a gated
|
|
778
|
-
// reader hidden forever (fuzzer branches-1 #1105). Skipped, the committed
|
|
779
|
-
// frame published stale beside its new inputs (`query=1` beside a
|
|
780
|
-
// `selected` derived from `remote(0)`). Re-derived, the pass decides: it
|
|
781
|
-
// reads the dep and registers through its own read, or reads a held input
|
|
782
|
-
// and enters that transaction (A29), or reads neither and is done. Clears
|
|
783
|
-
// and errors still ride every link. A link inside the prefix carries the
|
|
634
|
+
// staged. A source going pending there is a question for the node's NEXT
|
|
635
|
+
// pass, not a fact about its current one. Re-derived, the pass decides:
|
|
636
|
+
// it reads the dep and registers through its own read, or reads neither
|
|
637
|
+
// and is done. Clears and errors still ride every link. A link inside the prefix carries the
|
|
784
638
|
// pass's generation (`link()`), so the test is O(1); mid-pass the prefix
|
|
785
639
|
// is what the pass has read so far, and the heap refuses a recomputing
|
|
786
640
|
// node — a dep it has yet to reach registers through its own read.
|
|
787
|
-
|
|
788
|
-
|
|
641
|
+
// A verdict reader likewise (CONFIG_VERDICT), for either status: the
|
|
642
|
+
// dependency going pending or erroring changed what `isPending`/`latest`
|
|
643
|
+
// answer, so its pass runs again — it decides, breaking out as the
|
|
644
|
+
// verdict lane's, going pending through a plain read of its own, or
|
|
645
|
+
// answering an errored source (`isPending` false; `latest` throws it).
|
|
646
|
+
// Inheriting the error would make a probe's reader errored. A boundary's
|
|
647
|
+
// output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
|
|
648
|
+
// is its pass's call.
|
|
649
|
+
if (r.u & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Ue !== r.Ge) {
|
|
650
|
+
enqueueSub(r);
|
|
789
651
|
schedule();
|
|
790
652
|
return;
|
|
791
653
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
654
|
+
// Already pending on this source (a re-ask of its flight): the status is
|
|
655
|
+
// unchanged and nothing re-notifies. The re-asking write is held with the
|
|
656
|
+
// flight the observer waits on (fuzzer #3446 P1): the propagation joins
|
|
657
|
+
// the observer's transaction. An independent render effect in the same
|
|
658
|
+
// frame still passes through — its pass is the frame's (#3372, compiled
|
|
659
|
+
// shape: the unmount it stages makes the observer a zombie whose say is
|
|
660
|
+
// moot for this transaction, A15 #3463).
|
|
661
|
+
if (t === STATUS_PENDING && o && r.m?.Se?.has(o)) {
|
|
662
|
+
if (passLane === null && (r.u & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.ee) joinFuture(txOf(r));
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.V !== n || r.m?.Se)) {
|
|
666
|
+
// The marked subscriber is queued for the commit sweep so its status
|
|
667
|
+
// bookkeeping (loading window, uninitialized clear) runs with the flush
|
|
668
|
+
// — with the lane, when the pass propagating is the lane's work and
|
|
669
|
+
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
670
|
+
{
|
|
671
|
+
// (No answer: a pending propagation leaves a written guess a guess.)
|
|
672
|
+
if (passLane !== null) GlobalQueue.M(r, passLane, true, e); else {
|
|
673
|
+
queuePendingNode(r);
|
|
674
|
+
// A15 (#3443): pending propagates onto a held memo without
|
|
675
|
+
// recomputing it, and the propagation itself enters the memo's
|
|
676
|
+
// transaction — the flight flows into a memo that transaction
|
|
677
|
+
// holds, so the write that started it is held with it. A render
|
|
678
|
+
// effect's membership is its pass's (`notify`), never sticky.
|
|
679
|
+
if (t === STATUS_PENDING && (r.u & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
|
|
680
|
+
}
|
|
802
681
|
}
|
|
803
|
-
|
|
804
|
-
// staged by it — made pending by THIS flight cannot reveal before the
|
|
805
|
-
// flight lands: the two settle as one unit (A15, a shared derivation of
|
|
806
|
-
// both — #3443). Propagation marks the held memo without recomputing it
|
|
807
|
-
// (its inputs' values are unchanged), so this is the one moment the
|
|
808
|
-
// entanglement is known; the memo's stamped re-entry at its next pass
|
|
809
|
-
// came too late — the holder's own flight landed first and revealed the
|
|
810
|
-
// inputs beside the stale sum. The stamp alone decides nothing (#3334):
|
|
811
|
-
// a node the transaction once queued but holds nothing of — a switch's
|
|
812
|
-
// shared output whose first flight the second write superseded — must
|
|
813
|
-
// not drag the older flight into the newer reveal. Effects entangle
|
|
814
|
-
// nothing (A15 shared-hole corollary): their reader registers with the
|
|
815
|
-
// flight's transaction at queue notification.
|
|
816
|
-
if (!f) e.we ? o && !e.je && (e.h & STATUS_PENDING || e._e !== NOT_PENDING) && globalQueue.initTransition(e.we) : queuePendingNode(e);
|
|
817
|
-
notifyStatus(e, n, t, f, a);
|
|
682
|
+
notifyStatus(r, t, n);
|
|
818
683
|
}
|
|
819
684
|
});
|
|
820
685
|
}
|
|
821
686
|
|
|
822
|
-
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, parkLoadingWindow, releaseFlightTeardown, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource };
|
|
687
|
+
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource };
|