@solidjs/signals 2.0.0-rc.6 → 2.0.0-rc.8
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 +5243 -0
- package/dist/dev.attribution.js +2333 -0
- package/dist/dev.js +1758 -6621
- package/dist/observe/affects.js +127 -0
- package/dist/observe/attribution.js +1 -0
- package/dist/observe/boundaries.js +586 -0
- package/dist/observe/core/action.js +167 -0
- package/dist/observe/core/async.js +736 -0
- package/dist/observe/core/attribution-hooks.js +60 -0
- package/dist/observe/core/attribution.js +2318 -0
- package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +135 -71
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1289 -0
- package/dist/observe/core/dev.js +232 -0
- package/dist/observe/core/effect.js +179 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +43 -0
- package/dist/observe/core/lanes.js +168 -0
- package/dist/observe/core/optimistic.js +438 -0
- package/dist/observe/core/owner.js +308 -0
- package/dist/observe/core/scheduler.js +1190 -0
- package/dist/observe/core/verdict.js +551 -0
- package/dist/observe/index.js +55 -0
- package/dist/observe/map.js +482 -0
- package/dist/{types-cjs/signals.d.cts → observe/signals.js} +305 -317
- package/dist/observe/store/index.js +38 -0
- package/dist/observe/store/next/optimistic.js +651 -0
- package/dist/observe/store/next/projection.js +242 -0
- package/dist/observe/store/next/reconcile.js +373 -0
- package/dist/observe/store/next/store.js +2213 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +323 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +210 -0
- package/dist/prod/attribution.js +32 -0
- package/dist/prod/boundaries.js +3 -1
- package/dist/prod/core/action.js +52 -32
- package/dist/prod/core/async.js +177 -128
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +32 -1
- package/dist/prod/core/context.js +10 -16
- package/dist/prod/core/core.js +505 -286
- package/dist/prod/core/dev.js +2 -0
- package/dist/prod/core/effect.js +72 -43
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +40 -36
- package/dist/prod/core/heap.js +50 -51
- package/dist/prod/core/lanes.js +43 -22
- package/dist/prod/core/optimistic.js +224 -80
- package/dist/prod/core/owner.js +43 -39
- package/dist/prod/core/scheduler.js +347 -232
- package/dist/prod/core/verdict.js +71 -74
- package/dist/prod/index.js +9 -5
- package/dist/prod/map.js +311 -150
- package/dist/prod/signals.js +52 -38
- package/dist/prod/store/next/optimistic.js +127 -131
- package/dist/prod/store/next/projection.js +3 -3
- package/dist/prod/store/next/reconcile.js +149 -294
- package/dist/prod/store/next/store.js +694 -380
- package/dist/prod/store/next/target.js +32 -10
- package/dist/prod/store/store.js +12 -14
- package/dist/prod/store/utils.js +36 -27
- package/dist/types/attribution.d.ts +15 -0
- package/dist/types/attribution.prod.d.ts +13 -0
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/attribution-hooks.d.ts +183 -6
- package/dist/types/core/attribution.d.ts +435 -24
- package/dist/types/core/constants.d.ts +31 -0
- package/dist/types/core/core.d.ts +19 -3
- package/dist/types/core/dev.d.ts +165 -26
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/heap.d.ts +5 -3
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +17 -0
- package/dist/types/core/scheduler.d.ts +69 -4
- package/dist/types/core/types.d.ts +29 -9
- package/dist/types/index.d.ts +9 -2
- package/dist/types/map.d.ts +2 -0
- package/dist/types/signals.d.ts +10 -0
- package/dist/types/store/index.d.ts +4 -6
- package/dist/types/store/next/optimistic.d.ts +4 -2
- package/dist/types/store/next/reconcile.d.ts +5 -12
- package/dist/types/store/next/store.d.ts +8 -9
- package/dist/types/store/next/target.d.ts +56 -55
- package/dist/types/store/store.d.ts +14 -9
- package/dist/types/store/utils.d.ts +7 -0
- package/package.json +21 -16
- package/dist/node.cjs +0 -11121
- package/dist/prod/store/next/patch-hooks.js +0 -13
- package/dist/prod/store/next/patch.js +0 -614
- package/dist/types/store/next/patch-hooks.d.ts +0 -41
- package/dist/types/store/next/patch.d.ts +0 -91
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -23
- package/dist/types-cjs/core/attribution-hooks.d.cts +0 -63
- package/dist/types-cjs/core/attribution.d.cts +0 -239
- package/dist/types-cjs/core/core.d.cts +0 -176
- package/dist/types-cjs/core/dev.d.cts +0 -95
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -56
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -28
- package/dist/types-cjs/core/heap.d.cts +0 -22
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -44
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -231
- package/dist/types-cjs/core/types.d.cts +0 -204
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/store/index.d.cts +0 -21
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -23
- package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
- package/dist/types-cjs/store/next/patch.d.cts +0 -91
- package/dist/types-cjs/store/next/projection.d.cts +0 -8
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -17
- package/dist/types-cjs/store/next/store.d.cts +0 -127
- package/dist/types-cjs/store/next/target.d.cts +0 -192
- package/dist/types-cjs/store/store.d.cts +0 -138
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
package/dist/prod/core/async.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_UNINITIALIZED, CONFIG_CHILD_COMPANIONS, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING,
|
|
1
|
+
import { STATUS_UNINITIALIZED, CONFIG_CHILD_COMPANIONS, STATUS_ERROR, STATUS_PENDING, CONFIG_INPUTS_PUBLISHED, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_DISPOSED } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { untrack, ext, statusNotifierOf, setSignal, context } from "./core.js";
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ import { hasActiveOverride, assignOrMergeLane, resolveLane, resolveTransition }
|
|
|
14
14
|
|
|
15
15
|
import { cleanup } from "./owner.js";
|
|
16
16
|
|
|
17
|
-
import { GlobalQueue, schedule, flush, queuePendingNode, insertSubs, clock, currentTransition, globalQueue } from "./scheduler.js";
|
|
17
|
+
import { GlobalQueue, schedule, flush, queuePendingNode, insertSubs, clock, waitingTransition, currentTransition, globalQueue, setOrigin, origin } from "./scheduler.js";
|
|
18
18
|
|
|
19
19
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
20
20
|
// predecessor — a singular slot promoted to a Set on the second source —
|
|
@@ -40,6 +40,19 @@ function clearPendingSources(e) {
|
|
|
40
40
|
if (e.o !== null) e.o.le = undefined;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// A rejection-pending only resolves through the settle sweep over the
|
|
44
|
+
// SOURCE's subscribers, so it is retryable iff a tracked read created that
|
|
45
|
+
// edge: a dep that IS the source, or one whose own pending chain carries it
|
|
46
|
+
// (pending sources propagate the origin node, so this covers any depth).
|
|
47
|
+
// Also guards branch-local recovery: another dependency may still need the source.
|
|
48
|
+
function retryReaches(e, n) {
|
|
49
|
+
for (let t = e.fe; t; t = t.ae) {
|
|
50
|
+
const e = t.Se.ce || t.Se;
|
|
51
|
+
if (e === n || e.o?.le?.has(n)) return true;
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
43
56
|
/**
|
|
44
57
|
* A loading-window node hit an unready source (sync throw in recompute, or a
|
|
45
58
|
* NotReadyError-rejected flight): register for the source's settle — the
|
|
@@ -47,7 +60,7 @@ function clearPendingSources(e) {
|
|
|
47
60
|
* with NO read-visible pending status, no downstream propagation, no
|
|
48
61
|
* transition, no lane registration. Commit #0 keeps serving.
|
|
49
62
|
*/ function parkLoadingWindow(e, n) {
|
|
50
|
-
ext(e).
|
|
63
|
+
ext(e).de = true;
|
|
51
64
|
if (n.source) addPendingSource(e, n.source);
|
|
52
65
|
// A settled error is the node's answer ("the error stays the answer until
|
|
53
66
|
// this retry can actually run") — the park must not replace it: reads
|
|
@@ -72,10 +85,10 @@ function setPendingError(e, n, t) {
|
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
function forEachDependent(e, n) {
|
|
75
|
-
for (let t = e.u; t !== null; t = t.
|
|
88
|
+
for (let t = e.u; t !== null; t = t.Te) n(t.Ie, t);
|
|
76
89
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
77
|
-
for (let t = e.o?.i ?? null; t !== null; t = t.
|
|
78
|
-
for (let e = t.u; e !== null; e = e.
|
|
90
|
+
for (let t = e.o?.i ?? null; t !== null; t = t.Ee) {
|
|
91
|
+
for (let e = t.u; e !== null; e = e.Te) n(e.Ie, e);
|
|
79
92
|
}
|
|
80
93
|
}
|
|
81
94
|
|
|
@@ -119,9 +132,9 @@ function releaseSettledDependents(e) {
|
|
|
119
132
|
// object identity down the whole dependent tree, and holding it is exactly
|
|
120
133
|
// the "blocked on this error" marker — re-enqueue those holders so they
|
|
121
134
|
// re-run: fresh values commit and flow, and a dependent with another
|
|
122
|
-
// still-broken source simply re-errors.
|
|
123
|
-
//
|
|
124
|
-
//
|
|
135
|
+
// still-broken source simply re-errors. Pending recovery uses
|
|
136
|
+
// settlePendingSource to clear inherited status and retry blocked readers.
|
|
137
|
+
// Walks the full dependent graph
|
|
125
138
|
// (releaseSettledDependents shape): identity holders can sit below an
|
|
126
139
|
// intermediate whose own error state has since been scrubbed or replaced
|
|
127
140
|
// (e.g. an error boundary's tree node).
|
|
@@ -141,51 +154,63 @@ function settleErroredDependents(e, n) {
|
|
|
141
154
|
if (t) schedule();
|
|
142
155
|
}
|
|
143
156
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
157
|
+
// Retire `source` from pending state along the dependent graph rooted at `el`.
|
|
158
|
+
// By default, `el` is the source whose flight settled or was superseded.
|
|
159
|
+
// With a distinct `source`, `el` is a recovered computation that dropped it:
|
|
160
|
+
// the source may still be pending, so dependents with another path to it stay pending.
|
|
161
|
+
function settlePendingSource(e, n = e) {
|
|
162
|
+
// Landing and branch recovery already cleared el's own set. Superseded
|
|
163
|
+
// re-parks can retain an abandoned self entry (source === el), which must
|
|
164
|
+
// retire in the same walk as its propagated copies.
|
|
165
|
+
removePendingSource(e, n);
|
|
166
|
+
let t = false;
|
|
167
|
+
let r;
|
|
168
|
+
const o = new Set;
|
|
152
169
|
// Companion updates no-op without the verdict layer (null hook).
|
|
153
|
-
const
|
|
154
|
-
const settle =
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
170
|
+
const i = GlobalQueue.Ne;
|
|
171
|
+
const settle = s => {
|
|
172
|
+
if (o.has(s)) return;
|
|
173
|
+
// A conditional dropped this source, but another dependency can still
|
|
174
|
+
// carry it. Only retire pending state inherited through the recovered
|
|
175
|
+
// branch. Deliberately NOT marked visited on this early return: the
|
|
176
|
+
// carrying dependency may itself be a later branch of this same walk
|
|
177
|
+
// (two unchanged memos converging), and its visit must be free to
|
|
178
|
+
// re-examine this node once that branch has retired the source.
|
|
179
|
+
if (n !== e && retryReaches(s, n)) return;
|
|
180
|
+
if (!removePendingSource(s, n)) return;
|
|
181
|
+
o.add(s);
|
|
182
|
+
s._e = clock;
|
|
183
|
+
const l = s.o?.le?.values().next().value;
|
|
159
184
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
160
185
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
161
186
|
// otherwise): the settled error stays the answer through the settle —
|
|
162
187
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
163
188
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
164
|
-
const
|
|
189
|
+
const u = s.S & STATUS_ERROR;
|
|
165
190
|
if (l) {
|
|
166
|
-
if (!
|
|
167
|
-
|
|
191
|
+
if (!u) setPendingError(s, l);
|
|
192
|
+
i?.(s);
|
|
168
193
|
} else {
|
|
169
|
-
|
|
170
|
-
if (!
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
enqueueSub(
|
|
174
|
-
|
|
194
|
+
s.S &= ~STATUS_PENDING;
|
|
195
|
+
if (!u) setPendingError(s);
|
|
196
|
+
i?.(s);
|
|
197
|
+
if (s.o?.de) {
|
|
198
|
+
enqueueSub(s);
|
|
199
|
+
t = true;
|
|
175
200
|
}
|
|
176
|
-
if (
|
|
201
|
+
if (s.o !== null) s.o.de = false;
|
|
177
202
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
178
203
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
179
204
|
// lists this walk is still iterating.
|
|
180
|
-
if (!
|
|
205
|
+
if (!s.u && s.T & CONFIG_AUTO_DISPOSE) (r ??= []).push(s);
|
|
181
206
|
}
|
|
182
|
-
forEachDependent(
|
|
207
|
+
forEachDependent(s, settle);
|
|
183
208
|
};
|
|
184
209
|
forEachDependent(e, settle);
|
|
185
210
|
// Release before the flush schedule below: unobserved() pulls the node back
|
|
186
211
|
// out of the heap, so the enqueueSub above never recomputes a released node.
|
|
187
|
-
if (
|
|
188
|
-
if (
|
|
212
|
+
if (r) for (const e of r) releaseIfSettledUnobserved(e);
|
|
213
|
+
if (t) schedule();
|
|
189
214
|
}
|
|
190
215
|
|
|
191
216
|
// Object-thenable detection (Promises/A+ shape).
|
|
@@ -194,9 +219,9 @@ function isThenable(e) {
|
|
|
194
219
|
}
|
|
195
220
|
|
|
196
221
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
|
|
197
|
-
const n = e.o?.
|
|
222
|
+
const n = e.o?.De;
|
|
198
223
|
if (n != null) {
|
|
199
|
-
e.o.
|
|
224
|
+
e.o.De = null;
|
|
200
225
|
n();
|
|
201
226
|
}
|
|
202
227
|
}
|
|
@@ -211,9 +236,9 @@ function handleAsync(e, n, t) {
|
|
|
211
236
|
});
|
|
212
237
|
}
|
|
213
238
|
if (!o && !r) {
|
|
214
|
-
if (e.o !== null) e.o.
|
|
239
|
+
if (e.o !== null) e.o.Pe = null;
|
|
215
240
|
// A sync landing is the first real answer for a loadingValue node.
|
|
216
|
-
e.
|
|
241
|
+
e.Ae = false;
|
|
217
242
|
return n;
|
|
218
243
|
}
|
|
219
244
|
// Flight replacement relies on recompute's supersede release for iterator
|
|
@@ -221,8 +246,13 @@ function handleAsync(e, n, t) {
|
|
|
221
246
|
// self-registration — runs during a recompute of `el`, which has already
|
|
222
247
|
// fired _flightTeardown. A future non-recompute registration path must
|
|
223
248
|
// release it here before overwriting _inFlight.
|
|
224
|
-
ext(e).
|
|
225
|
-
|
|
249
|
+
ext(e).Pe = n;
|
|
250
|
+
// Provenance of the question this flight asks (#3331): the action whose
|
|
251
|
+
// window is registering it, or the flight whose landing is. Its landings
|
|
252
|
+
// propagate under it (asyncWrite) so an override downstream can tell a
|
|
253
|
+
// stale answer from its own.
|
|
254
|
+
const i = origin;
|
|
255
|
+
let s;
|
|
226
256
|
// Settle-time transition re-entry. The loading rail is invisible to
|
|
227
257
|
// transactions (#2933): a boundary-caught first load never registers as an
|
|
228
258
|
// async reporter, so its settle — the boundary's fallback -> content
|
|
@@ -234,27 +264,35 @@ function handleAsync(e, n, t) {
|
|
|
234
264
|
// keeps transition scheduling; initialized (value-holding) pending settles
|
|
235
265
|
// are the transaction's reveal machinery and always re-enter.
|
|
236
266
|
const settleTransition = () => {
|
|
237
|
-
|
|
238
|
-
|
|
267
|
+
let n = resolveTransition(e);
|
|
268
|
+
// A lane-routed node's landing is revealed by its lane, ahead of the
|
|
269
|
+
// transaction that owns the lane (whose own commit is only the override's
|
|
270
|
+
// confirm/revert). Entering that owner here would fold every transaction
|
|
271
|
+
// waiting on this flight into it at the landing — a reveal that
|
|
272
|
+
// discovered the flight (#3305) would then wait on the owner's action
|
|
273
|
+
// instead of on the flight (#3334). Enter the waiter: the transaction
|
|
274
|
+
// whose blocker this landing clears.
|
|
275
|
+
if (e.o?.Oe) n = waitingTransition(e) ?? n;
|
|
276
|
+
if (n && e.S & STATUS_UNINITIALIZED && !currentTransition(n).Re.has(e)) {
|
|
239
277
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
240
278
|
// stash-path restamp both re-enter the transaction through it.
|
|
241
|
-
e.
|
|
279
|
+
e.ge = null;
|
|
242
280
|
return;
|
|
243
281
|
}
|
|
244
282
|
globalQueue.initTransition(n);
|
|
245
283
|
};
|
|
246
284
|
const handleError = t => {
|
|
247
|
-
if (e.o?.
|
|
285
|
+
if (e.o?.Pe !== n) return;
|
|
248
286
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
249
287
|
let r = t instanceof NotReadyError;
|
|
250
|
-
if (r && e.
|
|
288
|
+
if (r && e.Ae) {
|
|
251
289
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
252
290
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
253
291
|
// dependency throws. The dead flight is released so the clock-gated
|
|
254
292
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
255
|
-
if (e.o !== null) e.o.
|
|
293
|
+
if (e.o !== null) e.o.Pe = null;
|
|
256
294
|
parkLoadingWindow(e, t);
|
|
257
|
-
e.
|
|
295
|
+
e._e = clock;
|
|
258
296
|
return;
|
|
259
297
|
}
|
|
260
298
|
settleTransition();
|
|
@@ -263,36 +301,44 @@ function handleAsync(e, n, t) {
|
|
|
263
301
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
264
302
|
// after notifyStatus has propagated the replacement source.
|
|
265
303
|
if (r) settlePendingSource(e);
|
|
266
|
-
e.
|
|
304
|
+
e._e = clock;
|
|
267
305
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
268
306
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
269
307
|
// the error twin of settlePendingSource's release (#2934).
|
|
270
308
|
if (!r) releaseSettledDependents(e);
|
|
271
309
|
};
|
|
272
310
|
const asyncWrite = (r, o) => {
|
|
273
|
-
if (e.o?.
|
|
311
|
+
if (e.o?.Pe !== n) return;
|
|
274
312
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
275
313
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
276
314
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
277
315
|
if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
316
|
+
// The landing propagates under the flight's provenance (#3331) — through
|
|
317
|
+
// the flush below, which clears it.
|
|
318
|
+
setOrigin(i);
|
|
278
319
|
settleTransition();
|
|
279
|
-
const
|
|
320
|
+
const s = !!(e.S & STATUS_UNINITIALIZED);
|
|
280
321
|
// Captured before clearStatus wipes it: a quiet re-ask's landing may be
|
|
281
322
|
// transition-held below, and the displayed value keeps answering the same
|
|
282
323
|
// question until the hold commits — the classification must survive to
|
|
283
324
|
// that reveal or companion synchronization briefly classifies the held
|
|
284
325
|
// old value as pending, a one-frame pulse to direct observers (#3178).
|
|
285
326
|
// A truthy capture implies `_x` exists, so the restore writes it directly.
|
|
286
|
-
const l = e.o?.
|
|
327
|
+
const l = e.o?.Ue;
|
|
287
328
|
trimStaleDeps(e);
|
|
288
329
|
clearStatus(e);
|
|
289
|
-
if (l) e.o.
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
330
|
+
if (l) e.o.Ue = true;
|
|
331
|
+
const u = resolveLane(e);
|
|
332
|
+
if (u) u.he.delete(e);
|
|
292
333
|
if (t) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
334
|
+
try {
|
|
335
|
+
t(r);
|
|
336
|
+
} catch (e) {
|
|
337
|
+
handleError(e);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (s) clearStatus(e, true);
|
|
341
|
+
} else if (e.o?.be !== undefined) {
|
|
296
342
|
// Optimistic node — resting OR covered by an active override — holds
|
|
297
343
|
// through the shared pending-node path, exactly like a plain async memo,
|
|
298
344
|
// so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
|
|
@@ -302,8 +348,8 @@ function handleAsync(e, n, t) {
|
|
|
302
348
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
303
349
|
// has committed by then, so corrections reveal atomically with their
|
|
304
350
|
// transition rather than escaping it.
|
|
305
|
-
if (e.
|
|
306
|
-
e.
|
|
351
|
+
if (e.Ge === NOT_PENDING) queuePendingNode(e);
|
|
352
|
+
e.Ge = r;
|
|
307
353
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
308
354
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
309
355
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -311,35 +357,34 @@ function handleAsync(e, n, t) {
|
|
|
311
357
|
// only notified when the hold is visible to them: under an active
|
|
312
358
|
// override every reader sees the override (A17), so waking subs would
|
|
313
359
|
// re-show an unchanged view — the revert is the notification point.
|
|
314
|
-
|
|
360
|
+
// Under an override the landing is handed to the engine's
|
|
361
|
+
// supersedeOverride (A18 supersession, #3331): own-source truth that
|
|
362
|
+
// differs from the override ends the optimism for the graph now (plain
|
|
363
|
+
// channel, lane demoted); a matching arrival is silent except to an
|
|
364
|
+
// authoritative-view reader (until()'s predicate) waiting on exactly
|
|
365
|
+
// this staged truth (#3164 — without the wake the hold deadlocks: the
|
|
366
|
+
// landing waits on the transaction, the transaction on the action, the
|
|
367
|
+
// action on an until() never re-notified). The hook is installed with
|
|
368
|
+
// the engine, which an active override implies. The propagation runs
|
|
369
|
+
// under this flight's provenance (setOrigin above).
|
|
370
|
+
GlobalQueue.pe?.(e, r);
|
|
315
371
|
if (!hasActiveOverride(e)) {
|
|
316
372
|
insertSubs(e);
|
|
317
|
-
} else
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
// and is waiting for exactly this staged truth. Without the wake the
|
|
321
|
-
// hold deadlocks: the landing waits on the transaction, the
|
|
322
|
-
// transaction on the action, the action on an until() that was never
|
|
323
|
-
// re-notified (#3164). Same selective wake as the equal-landing
|
|
324
|
-
// branch in recompute(). Optional call: the bit implies the
|
|
325
|
-
// optimistic engine WAS consulted, but the hook only installs with
|
|
326
|
-
// it — a bare-core build must not crash here.
|
|
327
|
-
GlobalQueue.he?.(e);
|
|
328
|
-
}
|
|
329
|
-
e.Te = clock;
|
|
330
|
-
} else if (s) {
|
|
373
|
+
} else GlobalQueue.ye(e, r);
|
|
374
|
+
e._e = clock;
|
|
375
|
+
} else if (u) {
|
|
331
376
|
// Route through lane's effect queue for independent flushing
|
|
332
|
-
const n = e.
|
|
333
|
-
const t = e.
|
|
334
|
-
const o = e.
|
|
377
|
+
const n = e.Ce;
|
|
378
|
+
const t = e.me;
|
|
379
|
+
const o = e.ve;
|
|
335
380
|
try {
|
|
336
|
-
if (!n &&
|
|
337
|
-
e.
|
|
338
|
-
e.
|
|
381
|
+
if (!n && s || !o || !o(r, t)) {
|
|
382
|
+
e.me = r;
|
|
383
|
+
e._e = clock;
|
|
339
384
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
340
385
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
341
386
|
// (computePendingState doesn't read _value).
|
|
342
|
-
GlobalQueue.
|
|
387
|
+
GlobalQueue.pe?.(e, r);
|
|
343
388
|
insertSubs(e, true);
|
|
344
389
|
}
|
|
345
390
|
} catch (n) {
|
|
@@ -365,9 +410,9 @@ function handleAsync(e, n, t) {
|
|
|
365
410
|
// window when the hold commits, so no one-frame isPending pulse can leak
|
|
366
411
|
// to live observers between the landing and its commit (#2990). The
|
|
367
412
|
// quiet re-ask classification follows the same schedule (#3178).
|
|
368
|
-
if (e.
|
|
369
|
-
e.
|
|
370
|
-
if (l) e.o.
|
|
413
|
+
if (e.Ge === NOT_PENDING) {
|
|
414
|
+
e.Ae = false;
|
|
415
|
+
if (l) e.o.Ue = false;
|
|
371
416
|
}
|
|
372
417
|
settlePendingSource(e);
|
|
373
418
|
schedule();
|
|
@@ -401,12 +446,12 @@ function handleAsync(e, n, t) {
|
|
|
401
446
|
// meaningful only in the live posture.
|
|
402
447
|
const consumeIterator = (t, r) => {
|
|
403
448
|
const o = t[Symbol.asyncIterator]();
|
|
449
|
+
let i = false;
|
|
404
450
|
let l = false;
|
|
405
|
-
let s = false;
|
|
406
451
|
let u = !r;
|
|
407
452
|
const close = () => {
|
|
408
|
-
if (
|
|
409
|
-
|
|
453
|
+
if (l) return;
|
|
454
|
+
l = true;
|
|
410
455
|
try {
|
|
411
456
|
const e = o.return?.();
|
|
412
457
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
@@ -417,7 +462,7 @@ function handleAsync(e, n, t) {
|
|
|
417
462
|
// owner-death backstop, but its disposal list can be zombie-deferred
|
|
418
463
|
// until the SUPERSEDING flight settles. The teardown slot fires at the
|
|
419
464
|
// _inFlight release sites so supersede stops this stream immediately.
|
|
420
|
-
ext(e).
|
|
465
|
+
ext(e).De = close;
|
|
421
466
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
422
467
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
423
468
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
@@ -446,15 +491,15 @@ function handleAsync(e, n, t) {
|
|
|
446
491
|
if (c && u) {
|
|
447
492
|
t = r;
|
|
448
493
|
f = true;
|
|
449
|
-
if (r.done)
|
|
450
|
-
} else if (e.o?.
|
|
494
|
+
if (r.done) l = true;
|
|
495
|
+
} else if (e.o?.Pe !== n) {
|
|
451
496
|
return;
|
|
452
497
|
} else if (!r.done) {
|
|
453
|
-
|
|
498
|
+
i = true;
|
|
454
499
|
asyncWrite(r.value, iterateOrRelease);
|
|
455
500
|
} else {
|
|
456
|
-
|
|
457
|
-
if (
|
|
501
|
+
l = true;
|
|
502
|
+
if (i) {
|
|
458
503
|
schedule();
|
|
459
504
|
flush();
|
|
460
505
|
} else {
|
|
@@ -467,8 +512,8 @@ function handleAsync(e, n, t) {
|
|
|
467
512
|
if (c && u) {
|
|
468
513
|
r = t;
|
|
469
514
|
a = true;
|
|
470
|
-
} else if (e.o?.
|
|
471
|
-
|
|
515
|
+
} else if (e.o?.Pe === n) {
|
|
516
|
+
l = true;
|
|
472
517
|
handleError(t);
|
|
473
518
|
settleAutodispose();
|
|
474
519
|
}
|
|
@@ -476,14 +521,14 @@ function handleAsync(e, n, t) {
|
|
|
476
521
|
c = false;
|
|
477
522
|
if (a) {
|
|
478
523
|
// Match the promise branch, but only rethrow during the initial read.
|
|
479
|
-
|
|
524
|
+
l = true;
|
|
480
525
|
handleError(r);
|
|
481
526
|
if (u) throw r;
|
|
482
527
|
return true;
|
|
483
528
|
}
|
|
484
529
|
if (f && !t.done) {
|
|
485
|
-
|
|
486
|
-
|
|
530
|
+
s = t.value;
|
|
531
|
+
i = true;
|
|
487
532
|
return iterate();
|
|
488
533
|
}
|
|
489
534
|
return f && t.done;
|
|
@@ -491,7 +536,7 @@ function handleAsync(e, n, t) {
|
|
|
491
536
|
const f = iterate();
|
|
492
537
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
493
538
|
u = false;
|
|
494
|
-
return
|
|
539
|
+
return i || f;
|
|
495
540
|
};
|
|
496
541
|
// Landed-synchronously verdict for a LIVE iterator drain; null when no live
|
|
497
542
|
// drain ran (plain promise flight, or a deferred flatten). Drives the
|
|
@@ -515,7 +560,7 @@ function handleAsync(e, n, t) {
|
|
|
515
560
|
return true;
|
|
516
561
|
};
|
|
517
562
|
if (o) {
|
|
518
|
-
let t = false, r = false, o,
|
|
563
|
+
let t = false, r = false, o, i = true;
|
|
519
564
|
// Close registration for the flattening path. Consumption starts in a
|
|
520
565
|
// microtask where the ambient owner is gone (or worse, someone else's),
|
|
521
566
|
// so `cleanup()` can't be used — the close targets el's disposal list
|
|
@@ -527,18 +572,18 @@ function handleAsync(e, n, t) {
|
|
|
527
572
|
// becomes disposal-bearing, which is exactly the class a directly
|
|
528
573
|
// returned iterable already occupies.
|
|
529
574
|
const registerDeferredClose = n => {
|
|
530
|
-
if (!e.
|
|
575
|
+
if (!e.we) e.we = n; else if (Array.isArray(e.we)) e.we.push(n); else e.we = [ e.we, n ];
|
|
531
576
|
};
|
|
532
577
|
n.then(r => {
|
|
533
|
-
if (
|
|
534
|
-
|
|
578
|
+
if (i) {
|
|
579
|
+
s = r;
|
|
535
580
|
t = true;
|
|
536
|
-
} else if (e.o?.
|
|
581
|
+
} else if (e.o?.Pe === n && !(e.ie & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
|
|
537
582
|
asyncWrite(r);
|
|
538
583
|
settleAutodispose();
|
|
539
584
|
}
|
|
540
585
|
}, e => {
|
|
541
|
-
if (
|
|
586
|
+
if (i) {
|
|
542
587
|
o = e;
|
|
543
588
|
r = true;
|
|
544
589
|
} else {
|
|
@@ -546,7 +591,7 @@ function handleAsync(e, n, t) {
|
|
|
546
591
|
settleAutodispose();
|
|
547
592
|
}
|
|
548
593
|
});
|
|
549
|
-
|
|
594
|
+
i = false;
|
|
550
595
|
if (r) {
|
|
551
596
|
// Settle through the same status path an async rejection uses, then
|
|
552
597
|
// unwind the in-progress synchronous read so the errored node isn't
|
|
@@ -558,12 +603,12 @@ function handleAsync(e, n, t) {
|
|
|
558
603
|
// is opened — first-flight work on a loadingValue node is loading-class
|
|
559
604
|
// (invisible to boundaries and transitions); the flight itself is
|
|
560
605
|
// already registered in _inFlight and lands through asyncWrite.
|
|
561
|
-
if (e.
|
|
606
|
+
if (e.Ae) return e.me;
|
|
562
607
|
globalQueue.initTransition(resolveTransition(e));
|
|
563
608
|
throw new NotReadyError(context);
|
|
564
|
-
} else if (!flattenIfIterable(
|
|
609
|
+
} else if (!flattenIfIterable(s)) {
|
|
565
610
|
// Synchronously-resolved promise: the first real answer landed.
|
|
566
|
-
e.
|
|
611
|
+
e.Ae = false;
|
|
567
612
|
}
|
|
568
613
|
// A sync-resolved promise holding an AsyncIterable flattened LIVE (we
|
|
569
614
|
// are still inside the synchronous read): full initial-drain semantics
|
|
@@ -573,30 +618,30 @@ function handleAsync(e, n, t) {
|
|
|
573
618
|
if (l !== null) {
|
|
574
619
|
if (!l) {
|
|
575
620
|
// Loading window: serve commit #0 (see the promise branch above).
|
|
576
|
-
if (e.
|
|
621
|
+
if (e.Ae) return e.me;
|
|
577
622
|
globalQueue.initTransition(resolveTransition(e));
|
|
578
623
|
throw new NotReadyError(context);
|
|
579
624
|
}
|
|
580
625
|
// A sync first yield (or immediate empty completion) is the first real
|
|
581
626
|
// answer; async yields clear inside asyncWrite.
|
|
582
|
-
e.
|
|
627
|
+
e.Ae = false;
|
|
583
628
|
}
|
|
584
|
-
return
|
|
629
|
+
return s;
|
|
585
630
|
}
|
|
586
631
|
|
|
587
632
|
function clearStatus(e, n = false) {
|
|
588
633
|
if (e.o?.le) clearPendingSources(e);
|
|
589
|
-
if (e.o?.
|
|
634
|
+
if (e.o?.de) if (e.o !== null) e.o.de = false;
|
|
590
635
|
// The pending window is over; its quiet classification dies with it.
|
|
591
636
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
592
637
|
// plain store to an existing slot — no shape change.)
|
|
593
|
-
if (e.o !== null) e.o.
|
|
638
|
+
if (e.o !== null) e.o.Ue = false;
|
|
594
639
|
e.S = n ? 0 : e.S & STATUS_UNINITIALIZED;
|
|
595
640
|
if (e.o?._) setPendingError(e);
|
|
596
641
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
597
642
|
// once the verdict layer created them, which installs the hooks).
|
|
598
|
-
if (e.o?.
|
|
599
|
-
if (e.o?.i && e.T & CONFIG_CHILD_COMPANIONS && GlobalQueue.
|
|
643
|
+
if (e.o?.Le || e.o?.Qe) GlobalQueue.Ne(e);
|
|
644
|
+
if (e.o?.i && e.T & CONFIG_CHILD_COMPANIONS && GlobalQueue.ke !== null) GlobalQueue.ke(e);
|
|
600
645
|
const t = statusNotifierOf(e);
|
|
601
646
|
if (t) t.call(e);
|
|
602
647
|
}
|
|
@@ -605,12 +650,16 @@ function notifyStatus(e, n, t, r, o) {
|
|
|
605
650
|
// Wrap regular errors to track source node
|
|
606
651
|
if (n === STATUS_ERROR && !(t instanceof StatusError) && !(t instanceof NotReadyError)) t = new StatusError(e, t);
|
|
607
652
|
const i = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
const u =
|
|
653
|
+
const s = i === e;
|
|
654
|
+
const l = n === STATUS_PENDING && e.o?.be !== undefined && !s;
|
|
655
|
+
const u = l && hasActiveOverride(e);
|
|
611
656
|
if (!r) {
|
|
612
657
|
if (n === STATUS_PENDING && i) {
|
|
613
658
|
addPendingSource(e, i);
|
|
659
|
+
// A fresh flight from a settled state starts with its inputs unpublished
|
|
660
|
+
// (a replacement flight while still pending keeps the mark: the first
|
|
661
|
+
// flight's committed inputs are still the frame).
|
|
662
|
+
if (!(e.S & STATUS_PENDING)) e.T &= ~CONFIG_INPUTS_PUBLISHED;
|
|
614
663
|
e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
|
|
615
664
|
// Preserve the current source on this propagation so render-effect notification
|
|
616
665
|
// can register every distinct pending source with the transition.
|
|
@@ -620,14 +669,14 @@ function notifyStatus(e, n, t, r, o) {
|
|
|
620
669
|
e.S = n | (n !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
|
|
621
670
|
ext(e)._ = t;
|
|
622
671
|
}
|
|
623
|
-
GlobalQueue.
|
|
624
|
-
if (e.o?.i && e.T & CONFIG_CHILD_COMPANIONS && GlobalQueue.
|
|
672
|
+
GlobalQueue.Ne?.(e);
|
|
673
|
+
if (e.o?.i && e.T & CONFIG_CHILD_COMPANIONS && GlobalQueue.ke !== null) GlobalQueue.ke(e);
|
|
625
674
|
}
|
|
626
675
|
if (o && !r) {
|
|
627
676
|
assignOrMergeLane(e, o);
|
|
628
677
|
}
|
|
629
678
|
const f = r || u;
|
|
630
|
-
const a = r ||
|
|
679
|
+
const a = r || l ? undefined : o;
|
|
631
680
|
const c = statusNotifierOf(e);
|
|
632
681
|
if (c) {
|
|
633
682
|
if (r && n === STATUS_PENDING) {
|
|
@@ -641,19 +690,19 @@ function notifyStatus(e, n, t, r, o) {
|
|
|
641
690
|
return;
|
|
642
691
|
}
|
|
643
692
|
forEachDependent(e, (e, r) => {
|
|
644
|
-
e.
|
|
693
|
+
e._e = clock;
|
|
645
694
|
if (n === STATUS_PENDING && i && !e.o?.le?.has(i) || n !== STATUS_PENDING && (e.o?._ !== t || e.o?.le)) {
|
|
646
695
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
647
696
|
// It exists so the observer re-runs when the source settles, but it must
|
|
648
697
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
649
698
|
// read swallows those, and the async path must match. Re-run the observer
|
|
650
699
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
651
|
-
if (r.
|
|
700
|
+
if (r.je && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
|
|
652
701
|
enqueueSub(e);
|
|
653
702
|
schedule();
|
|
654
703
|
return;
|
|
655
704
|
}
|
|
656
|
-
if (!f && !e.
|
|
705
|
+
if (!f && !e.ge) queuePendingNode(e);
|
|
657
706
|
notifyStatus(e, n, t, f, a);
|
|
658
707
|
}
|
|
659
708
|
});
|