@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-shared.js +1972 -1751
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +672 -319
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +151 -116
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +51 -35
- package/dist/observe/core/effect.js +29 -30
- package/dist/observe/core/graph.js +13 -11
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +77 -51
- package/dist/observe/core/scheduler.js +202 -175
- package/dist/observe/core/verdict.js +5 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +612 -626
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +211 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +63 -47
- package/dist/prod/core/effect.js +24 -25
- package/dist/prod/core/graph.js +12 -10
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +39 -28
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +78 -51
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +11 -8
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +109 -121
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +29 -6
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +38 -7
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ import { enqueueSub } from "./core/heap.js";
|
|
|
14
14
|
|
|
15
15
|
import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
|
|
16
16
|
|
|
17
|
-
import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, passTx, resolveTx, schedule, txOf, unhold, laneStageHook, installBoundaryHooks } from "./core/scheduler.js";
|
|
17
|
+
import { globalQueue, haltReactivityAt, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, passTx, resolveTx, schedule, txOf, unhold, laneStageHook, installBoundaryHooks } from "./core/scheduler.js";
|
|
18
18
|
|
|
19
19
|
import { attrHooks } from "./core/attribution-hooks.js";
|
|
20
20
|
|
|
@@ -353,7 +353,7 @@ function createBoundary(e, r, n, t) {
|
|
|
353
353
|
} catch (e) {
|
|
354
354
|
if (!(e instanceof NotReadyError)) {
|
|
355
355
|
if (!globalQueue.notify(getOwner(), STATUS_ERROR, STATUS_ERROR, e)) {
|
|
356
|
-
haltReactivity(e);
|
|
356
|
+
if (false) ; else haltReactivity(e);
|
|
357
357
|
throw e;
|
|
358
358
|
}
|
|
359
359
|
return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, CONFIG_GUESS, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_DIRTY, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
|
|
1
|
+
import { STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, NewSet, REACTIVE_DIRTY, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { attrHooks } from "./attribution-hooks.js";
|
|
4
4
|
|
|
5
|
-
import { ext, statusNotifierOf,
|
|
5
|
+
import { ext, statusNotifierOf, context, untrack, setSignal } from "./core.js";
|
|
6
6
|
|
|
7
7
|
import "./dev.js";
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ import { unobserved, trimStaleDeps } from "./graph.js";
|
|
|
12
12
|
|
|
13
13
|
import { enqueueSub } from "./heap.js";
|
|
14
14
|
|
|
15
|
-
import { cleanup } from "./owner.js";
|
|
15
|
+
import { disposeChildren, cleanup } from "./owner.js";
|
|
16
16
|
|
|
17
17
|
import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedule, clock, flush, freshHook, txOf, laneStageHook, queuePendingNode } from "./scheduler.js";
|
|
18
18
|
|
|
@@ -22,22 +22,22 @@ import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedul
|
|
|
22
22
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
23
23
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
24
24
|
function addPendingSource(e, t) {
|
|
25
|
-
if (e.T?.
|
|
26
|
-
(ext(e).
|
|
25
|
+
if (e.T?.se?.has(t)) return false;
|
|
26
|
+
(ext(e).se ??= new NewSet).add(t);
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function removePendingSource(e, t) {
|
|
31
|
-
const n = e.T?.
|
|
31
|
+
const n = e.T?.se;
|
|
32
32
|
if (!n?.delete(t)) return false;
|
|
33
|
-
if (!n.size) e.T.
|
|
33
|
+
if (!n.size) e.T.se = undefined;
|
|
34
34
|
return true;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function clearPendingSources(e) {
|
|
38
38
|
// This set is node-owned and never shared; dropping the sole reference
|
|
39
39
|
// releases the set and every entry without a redundant clear() walk.
|
|
40
|
-
if (e.T !== null) e.T.
|
|
40
|
+
if (e.T !== null) e.T.se = undefined;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// A rejection-pending only resolves through the settle sweep over the
|
|
@@ -48,7 +48,7 @@ function clearPendingSources(e) {
|
|
|
48
48
|
function retryReaches(e, t) {
|
|
49
49
|
for (let n = e.C; n; n = n.G) {
|
|
50
50
|
const e = n.S;
|
|
51
|
-
if (e === t || e.T?.
|
|
51
|
+
if (e === t || e.T?.se?.has(t)) return true;
|
|
52
52
|
}
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
@@ -60,7 +60,7 @@ function retryReaches(e, t) {
|
|
|
60
60
|
* with NO read-visible pending status and no downstream propagation. Commit
|
|
61
61
|
* #0 keeps serving.
|
|
62
62
|
*/ function parkLoadingWindow(e, t) {
|
|
63
|
-
ext(e).
|
|
63
|
+
ext(e).fe = true;
|
|
64
64
|
if (t.source) addPendingSource(e, t.source);
|
|
65
65
|
// A settled error is the node's answer ("the error stays the answer until
|
|
66
66
|
// this retry can actually run") — the park must not replace it: reads
|
|
@@ -108,7 +108,7 @@ function releaseIfSettledUnobserved(e) {
|
|
|
108
108
|
// Collect-then-release so unobserved() never unlinks under the walk.
|
|
109
109
|
function releaseSettledDependents(e) {
|
|
110
110
|
let t;
|
|
111
|
-
const n = new
|
|
111
|
+
const n = new NewSet;
|
|
112
112
|
const visit = e => {
|
|
113
113
|
if (n.has(e)) return;
|
|
114
114
|
n.add(e);
|
|
@@ -148,11 +148,13 @@ function releaseSettledDependents(e) {
|
|
|
148
148
|
// Staged whether or not the flush has joined a hold yet: a pass that runs
|
|
149
149
|
// before its async sibling joins is the seam's to decide, like a value
|
|
150
150
|
// (#4109). A flush that parks nothing publishes it at its commit (S-38).
|
|
151
|
-
|
|
151
|
+
// Not a projection's derive: its readers learn its error through the
|
|
152
|
+
// family, which the commit's publish never reaches (#4189).
|
|
153
|
+
if (!(e.l & CONFIG_HELD || n && e.R & REACTIVE_STAGED_READ && globalQueue.q && !e.fam) || passLane) return false;
|
|
152
154
|
// The node answered (an error ends the wait — no longer pending, nor
|
|
153
155
|
// blocked); a shown error stays its display until the commit.
|
|
154
156
|
clearPendingSources(e);
|
|
155
|
-
if (e.T) e.T.
|
|
157
|
+
if (e.T) e.T.fe = false;
|
|
156
158
|
if (!((e.m &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR)) setPendingError(e);
|
|
157
159
|
e.ue = t instanceof StatusError ? t : new StatusError(e, t);
|
|
158
160
|
e.l |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
|
|
@@ -165,7 +167,7 @@ function releaseSettledDependents(e) {
|
|
|
165
167
|
|
|
166
168
|
function settleErroredDependents(e, t) {
|
|
167
169
|
let n = false;
|
|
168
|
-
const r = new
|
|
170
|
+
const r = new NewSet;
|
|
169
171
|
const visit = e => {
|
|
170
172
|
if (r.has(e)) return;
|
|
171
173
|
r.add(e);
|
|
@@ -190,51 +192,51 @@ function settlePendingSource(e, t = e) {
|
|
|
190
192
|
removePendingSource(e, t);
|
|
191
193
|
let n = false;
|
|
192
194
|
let r;
|
|
193
|
-
const o = new
|
|
194
|
-
const settle =
|
|
195
|
-
if (o.has(
|
|
195
|
+
const o = new NewSet;
|
|
196
|
+
const settle = s => {
|
|
197
|
+
if (o.has(s) ||
|
|
196
198
|
// A conditional dropped this source, but another dependency can still
|
|
197
199
|
// carry it. Only retire pending state inherited through the recovered
|
|
198
200
|
// branch. Deliberately NOT marked visited on this early return: the
|
|
199
201
|
// carrying dependency may itself be a later branch of this same walk
|
|
200
202
|
// (two unchanged memos converging), and its visit must be free to
|
|
201
203
|
// re-examine this node once that branch has retired the source.
|
|
202
|
-
t !== e && retryReaches(
|
|
204
|
+
t !== e && retryReaches(s, t) || !removePendingSource(s, t))
|
|
203
205
|
// A19: a verdict reader holds no pending of its own (it was re-derived
|
|
204
206
|
// when the source went pending, `propagateStatus`), and a landing
|
|
205
207
|
// equal to the committed value notifies nobody — the source settling
|
|
206
208
|
// is its verdict changing: it runs again.
|
|
207
|
-
return
|
|
208
|
-
o.add(
|
|
209
|
-
|
|
210
|
-
const
|
|
209
|
+
return s.l & CONFIG_VERDICT && enqueueSub(s);
|
|
210
|
+
o.add(s);
|
|
211
|
+
s.ie = clock;
|
|
212
|
+
const f = s.T?.se?.values().next().value;
|
|
211
213
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
212
214
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
213
215
|
// otherwise): the settled error stays the answer through the settle —
|
|
214
216
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
215
217
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
216
|
-
const u =
|
|
217
|
-
if (
|
|
218
|
-
if (!u) setPendingError(
|
|
218
|
+
const u = s.m & STATUS_ERROR;
|
|
219
|
+
if (f) {
|
|
220
|
+
if (!u) setPendingError(s, f);
|
|
219
221
|
} else {
|
|
220
|
-
|
|
221
|
-
if (!u) setPendingError(
|
|
222
|
+
s.m &= ~STATUS_PENDING;
|
|
223
|
+
if (!u) setPendingError(s);
|
|
222
224
|
// L2: a landing resumes the transaction waiting on it (maintainer: "it
|
|
223
225
|
// resumes the sync frame") — a held reader's re-pass over the landed
|
|
224
226
|
// value is that transaction's work, and the flush that carries it
|
|
225
227
|
// parks into it.
|
|
226
|
-
if (
|
|
227
|
-
if (
|
|
228
|
-
enqueueSub(
|
|
228
|
+
if (s.l & CONFIG_HELD) joinFuture(txOf(s));
|
|
229
|
+
if (s.T?.fe) {
|
|
230
|
+
enqueueSub(s);
|
|
229
231
|
n = true;
|
|
230
232
|
}
|
|
231
|
-
if (
|
|
233
|
+
if (s.T !== null) s.T.fe = false;
|
|
232
234
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
233
235
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
234
236
|
// lists this walk is still iterating.
|
|
235
|
-
if (!
|
|
237
|
+
if (!s.o && s.l & CONFIG_AUTO_DISPOSE) (r ??= []).push(s);
|
|
236
238
|
}
|
|
237
|
-
forEachDependent(
|
|
239
|
+
forEachDependent(s, settle);
|
|
238
240
|
};
|
|
239
241
|
forEachDependent(e, settle);
|
|
240
242
|
// Release before the flush schedule below: unobserved() pulls the node back
|
|
@@ -256,6 +258,34 @@ function isThenable(e) {
|
|
|
256
258
|
}
|
|
257
259
|
}
|
|
258
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Internal (not a package export): run `fn` when the current pass's flight
|
|
263
|
+
* is superseded, at the same instant as the iterator close above, instead of
|
|
264
|
+
* when the replacing pass commits (owner cleanups wait for that). Chains onto
|
|
265
|
+
* the node's teardown slot; fires once with it. A no-op unless the ambient
|
|
266
|
+
* owner is a computed in its own pass. `consumeIterator` fills the slot
|
|
267
|
+
* before its first pull, so a source opened in an async generator's body
|
|
268
|
+
* (`for await`) composes after the generator's close.
|
|
269
|
+
*/ function onSupersede(e) {
|
|
270
|
+
const t = context;
|
|
271
|
+
if (t === null || t.X === undefined || !(t.R & REACTIVE_RECOMPUTING_DEPS)) return;
|
|
272
|
+
const n = t.T === null;
|
|
273
|
+
const r = ext(t);
|
|
274
|
+
// Allocating the extension mid-run turns `_x?._inFlight` from undefined into
|
|
275
|
+
// null, which recompute would read as a flight this body registered itself.
|
|
276
|
+
// Restore undefined here, so the fix costs nothing for code that never
|
|
277
|
+
// calls onSupersede.
|
|
278
|
+
if (n) r.Se = undefined;
|
|
279
|
+
const o = r.ae;
|
|
280
|
+
r.ae = o === null ? e : () => {
|
|
281
|
+
try {
|
|
282
|
+
o();
|
|
283
|
+
} finally {
|
|
284
|
+
e();
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
259
289
|
function handleAsync(e, t, n,
|
|
260
290
|
// The flight rejected (after the node's status is set): a projection
|
|
261
291
|
// tells its leaves' readers, who are not the node's dependents
|
|
@@ -263,14 +293,14 @@ function handleAsync(e, t, n,
|
|
|
263
293
|
// pending on another source, not errored.
|
|
264
294
|
r) {
|
|
265
295
|
let o = false;
|
|
266
|
-
let
|
|
296
|
+
let s = false;
|
|
267
297
|
if (typeof t === "object" && t !== null) {
|
|
268
298
|
untrack(() => {
|
|
269
299
|
o = t[Symbol.asyncIterator];
|
|
270
|
-
|
|
300
|
+
s = !o && isThenable(t);
|
|
271
301
|
});
|
|
272
302
|
}
|
|
273
|
-
if (!
|
|
303
|
+
if (!s && !o) {
|
|
274
304
|
if (e.T !== null) e.T.Se = null;
|
|
275
305
|
// A sync landing is the first real answer for a loadingValue node.
|
|
276
306
|
e.ce = false;
|
|
@@ -291,19 +321,19 @@ r) {
|
|
|
291
321
|
// describe this answer. Drop it — the flight is the node's pending now.
|
|
292
322
|
// The landing retires only the flight's own entry (landStatus, #3373), so
|
|
293
323
|
// an entry that survived here would hold the node past its own answer.
|
|
294
|
-
e.T.
|
|
324
|
+
e.T.se = undefined;
|
|
295
325
|
// Attribution hook: a new flight is registered. Fired here (not in the
|
|
296
326
|
// branches below) so every flight shape — plain thenable, iterator, the
|
|
297
327
|
// flattened combinations — is announced exactly once, while the recompute
|
|
298
328
|
// frame that caused it is still on the engine's stack. Not inside a try
|
|
299
329
|
// (#2883 — see attribution-hooks.ts).
|
|
300
330
|
if (attrHooks !== null) attrHooks.flightStart(e, t);
|
|
301
|
-
let
|
|
331
|
+
let f;
|
|
302
332
|
const handleError = o => {
|
|
303
333
|
if (e.T?.Se !== t) return;
|
|
304
334
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
305
|
-
let
|
|
306
|
-
if (
|
|
335
|
+
let s = o instanceof NotReadyError;
|
|
336
|
+
if (s && e.ce) {
|
|
307
337
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
308
338
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
309
339
|
// dependency throws. The dead flight is released so the clock-gated
|
|
@@ -316,17 +346,24 @@ r) {
|
|
|
316
346
|
// D-41: a held node's error is staged (`stageError`). A derived store's
|
|
317
347
|
// readers learn its error through the family, not the derive's
|
|
318
348
|
// dependents: it publishes now.
|
|
319
|
-
if (
|
|
349
|
+
if (s || n || !stageError(e, o)) {
|
|
350
|
+
notifyStatus(e, s ? STATUS_PENDING : STATUS_ERROR, o);
|
|
351
|
+
// The error is this pass's answer, published now: it replaces the shown
|
|
352
|
+
// frame as a value's commit would (`commitPendingNode`), so the frame
|
|
353
|
+
// the pass parked goes instead of waiting for a later success. A no-op
|
|
354
|
+
// when nothing is parked.
|
|
355
|
+
if (!s) disposeChildren(e, false, true);
|
|
356
|
+
}
|
|
320
357
|
// A NotReady rejection is a landing into another pending source. The
|
|
321
358
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
322
359
|
// after notifyStatus has propagated the replacement source.
|
|
323
|
-
if (
|
|
360
|
+
if (s) settlePendingSource(e);
|
|
324
361
|
e.ie = clock;
|
|
325
362
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
326
363
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
327
364
|
// the error twin of settlePendingSource's release (#2934).
|
|
328
|
-
if (!
|
|
329
|
-
r?.(o,
|
|
365
|
+
if (!s) releaseSettledDependents(e);
|
|
366
|
+
r?.(o, s);
|
|
330
367
|
};
|
|
331
368
|
const asyncWrite = (r, o) => {
|
|
332
369
|
if (e.T?.Se !== t) return;
|
|
@@ -334,7 +371,7 @@ r) {
|
|
|
334
371
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
335
372
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
336
373
|
if (e.R & REACTIVE_DIRTY) return;
|
|
337
|
-
const
|
|
374
|
+
const s = e.m & STATUS_UNINITIALIZED;
|
|
338
375
|
landStatus(e);
|
|
339
376
|
// Attribution hook: lets the engine snapshot state before the landing
|
|
340
377
|
// branches, so it can tell whether the plain path's setSignal committed a
|
|
@@ -350,7 +387,7 @@ r) {
|
|
|
350
387
|
// A store derive's landing commits through its setter: unheld, the
|
|
351
388
|
// shown error leaves now; held, at the derive's commit.
|
|
352
389
|
if (!(e.l & CONFIG_HELD)) e.T.de = undefined;
|
|
353
|
-
if (
|
|
390
|
+
if (s) landStatus(e, true);
|
|
354
391
|
// Attribution hook: this path landed through the setter (derived
|
|
355
392
|
// stores, projections), which does not go through setSignal, so the
|
|
356
393
|
// plain branch's asyncEnd never ran and the flight stayed open — the
|
|
@@ -417,7 +454,7 @@ r) {
|
|
|
417
454
|
// empty completion) — meaningful only in the live posture.
|
|
418
455
|
const consumeIterator = (n, r) => {
|
|
419
456
|
const o = n[Symbol.asyncIterator]();
|
|
420
|
-
let
|
|
457
|
+
let s = false;
|
|
421
458
|
let u = false;
|
|
422
459
|
let i = !r;
|
|
423
460
|
const close = () => {
|
|
@@ -431,7 +468,11 @@ r) {
|
|
|
431
468
|
cleanup(close, r);
|
|
432
469
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
433
470
|
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
434
|
-
// sites so supersede stops this stream immediately.
|
|
471
|
+
// sites so supersede stops this stream immediately. Assigned, not
|
|
472
|
+
// chained (chaining here costs every app bytes): it replaces any
|
|
473
|
+
// `onSupersede` teardown this run registered earlier, which then falls
|
|
474
|
+
// back to the owner-cleanup channel. A returned `from()` is unaffected:
|
|
475
|
+
// `close` calls its `return()`, which runs its own teardown.
|
|
435
476
|
ext(e).ae = close;
|
|
436
477
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
437
478
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
@@ -472,11 +513,11 @@ r) {
|
|
|
472
513
|
} else if (e.T?.Se !== t) {
|
|
473
514
|
return;
|
|
474
515
|
} else if (!r.done) {
|
|
475
|
-
|
|
516
|
+
s = true;
|
|
476
517
|
asyncWrite(r.value, iterateOrRelease);
|
|
477
518
|
} else {
|
|
478
519
|
u = true;
|
|
479
|
-
if (
|
|
520
|
+
if (s) {
|
|
480
521
|
schedule();
|
|
481
522
|
flush();
|
|
482
523
|
} else {
|
|
@@ -504,8 +545,8 @@ r) {
|
|
|
504
545
|
return true;
|
|
505
546
|
}
|
|
506
547
|
if (l && !n.done) {
|
|
507
|
-
|
|
508
|
-
|
|
548
|
+
f = n.value;
|
|
549
|
+
s = true;
|
|
509
550
|
return iterate();
|
|
510
551
|
}
|
|
511
552
|
return l && n.done;
|
|
@@ -513,7 +554,7 @@ r) {
|
|
|
513
554
|
const l = iterate();
|
|
514
555
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
515
556
|
i = false;
|
|
516
|
-
return
|
|
557
|
+
return s || l;
|
|
517
558
|
};
|
|
518
559
|
// Landed-synchronously verdict for a LIVE iterator drain; null when no live
|
|
519
560
|
// drain ran (plain promise flight, or a deferred flatten). Drives the
|
|
@@ -532,16 +573,16 @@ r) {
|
|
|
532
573
|
});
|
|
533
574
|
}
|
|
534
575
|
if (!n) return false;
|
|
535
|
-
|
|
576
|
+
f = undefined;
|
|
536
577
|
const r = consumeIterator(e, t);
|
|
537
578
|
if (!t) u = r;
|
|
538
579
|
return true;
|
|
539
580
|
};
|
|
540
|
-
if (
|
|
541
|
-
let n = false, r = false, o,
|
|
581
|
+
if (s) {
|
|
582
|
+
let n = false, r = false, o, s = true;
|
|
542
583
|
t.then(r => {
|
|
543
|
-
if (
|
|
544
|
-
|
|
584
|
+
if (s) {
|
|
585
|
+
f = r;
|
|
545
586
|
n = true;
|
|
546
587
|
} else {
|
|
547
588
|
// Flattening consumes the stream as the value: each yield lands
|
|
@@ -562,7 +603,7 @@ r) {
|
|
|
562
603
|
settleAutodispose();
|
|
563
604
|
}
|
|
564
605
|
}, e => {
|
|
565
|
-
if (
|
|
606
|
+
if (s) {
|
|
566
607
|
o = e;
|
|
567
608
|
r = true;
|
|
568
609
|
} else {
|
|
@@ -570,7 +611,7 @@ r) {
|
|
|
570
611
|
settleAutodispose();
|
|
571
612
|
}
|
|
572
613
|
});
|
|
573
|
-
|
|
614
|
+
s = false;
|
|
574
615
|
if (r) {
|
|
575
616
|
// Settle through the same status path an async rejection uses, then
|
|
576
617
|
// unwind the in-progress synchronous read so the errored node isn't
|
|
@@ -578,13 +619,13 @@ r) {
|
|
|
578
619
|
handleError(o);
|
|
579
620
|
throw o;
|
|
580
621
|
} else if (!n) {
|
|
581
|
-
//
|
|
582
|
-
// work on a loadingValue node is
|
|
583
|
-
// boundaries
|
|
584
|
-
// lands through asyncWrite.
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
} else if (!flattenIfIterable(
|
|
622
|
+
// Not landed: the shared tail below suspends, or — loading window —
|
|
623
|
+
// serves commit #0 (first-flight work on a loadingValue node is
|
|
624
|
+
// loading-class, invisible to boundaries; the flight itself is already
|
|
625
|
+
// registered in _inFlight and lands through asyncWrite). A promise is
|
|
626
|
+
// never an iterator, so nothing between here and there runs.
|
|
627
|
+
u = false;
|
|
628
|
+
} else if (!flattenIfIterable(f)) {
|
|
588
629
|
// Synchronously-resolved promise: the first real answer landed.
|
|
589
630
|
e.ce = false;
|
|
590
631
|
}
|
|
@@ -595,7 +636,7 @@ r) {
|
|
|
595
636
|
if (o) flattenIfIterable(t);
|
|
596
637
|
if (u !== null) {
|
|
597
638
|
if (!u) {
|
|
598
|
-
// Loading window: serve commit #0
|
|
639
|
+
// Loading window: serve commit #0 instead of suspending.
|
|
599
640
|
if (e.ce) return e.Ie;
|
|
600
641
|
throw new NotReadyError(context);
|
|
601
642
|
}
|
|
@@ -603,12 +644,12 @@ r) {
|
|
|
603
644
|
// answer; async yields clear inside asyncWrite.
|
|
604
645
|
e.ce = false;
|
|
605
646
|
}
|
|
606
|
-
return
|
|
647
|
+
return f;
|
|
607
648
|
}
|
|
608
649
|
|
|
609
650
|
function clearStatus(e, t = false) {
|
|
610
|
-
if (e.T?.
|
|
611
|
-
if (e.T?.
|
|
651
|
+
if (e.T?.se) clearPendingSources(e);
|
|
652
|
+
if (e.T?.fe) e.T.fe = false;
|
|
612
653
|
e.m = t ? 0 : e.m & STATUS_UNINITIALIZED;
|
|
613
654
|
if (e.T?.F) setPendingError(e);
|
|
614
655
|
const n = statusNotifierOf(e);
|
|
@@ -640,34 +681,32 @@ function clearStatus(e, t = false) {
|
|
|
640
681
|
* reader thrown NotReady(self) would park on a retired entry. Companions
|
|
641
682
|
* keep their verdict (pending before and after; the write re-syncs them).
|
|
642
683
|
*/ function landStatus(e, t = false) {
|
|
643
|
-
const n = e.T?.
|
|
684
|
+
const n = e.T?.se;
|
|
644
685
|
// (The full clear below drops the set whether or not self was retired first.)
|
|
645
686
|
if (n && (n.delete(e), n.size)) {
|
|
646
|
-
e.T.
|
|
687
|
+
e.T.fe = false;
|
|
647
688
|
if (t) e.m = STATUS_PENDING;
|
|
648
689
|
setPendingError(e, n.values().next().value);
|
|
649
690
|
} else clearStatus(e, t);
|
|
650
691
|
}
|
|
651
692
|
|
|
652
|
-
function notifyStatus(e, t, n
|
|
693
|
+
function notifyStatus(e, t, n) {
|
|
653
694
|
// Wrap regular errors to track source node
|
|
654
695
|
if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
|
|
655
|
-
const
|
|
696
|
+
const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
656
697
|
// (CARVE 2: the lane assignment went with the engine.)
|
|
657
|
-
{
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
ext(e).F = n;
|
|
670
|
-
}
|
|
698
|
+
if (t === STATUS_PENDING && r) {
|
|
699
|
+
// D-41: a re-ask of a shown error keeps it the display (`_shownError`).
|
|
700
|
+
if (e.m & STATUS_ERROR) e.T.de = e.T.F;
|
|
701
|
+
addPendingSource(e, r);
|
|
702
|
+
e.m = STATUS_PENDING | e.m & STATUS_UNINITIALIZED;
|
|
703
|
+
// Preserve the current source on this propagation so readers park on
|
|
704
|
+
// the distinct pending source.
|
|
705
|
+
setPendingError(e, r, n);
|
|
706
|
+
} else {
|
|
707
|
+
clearPendingSources(e);
|
|
708
|
+
e.m = t | (t !== STATUS_ERROR ? e.m & STATUS_UNINITIALIZED : 0);
|
|
709
|
+
ext(e).F = n;
|
|
671
710
|
}
|
|
672
711
|
// Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
|
|
673
712
|
// future value until we know otherwise"). Its own source in flight is its
|
|
@@ -679,11 +718,9 @@ function notifyStatus(e, t, n, r) {
|
|
|
679
718
|
if (passLane === null) joinFuture(null);
|
|
680
719
|
return;
|
|
681
720
|
}
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
|
|
685
|
-
f.call(e);
|
|
686
|
-
}
|
|
721
|
+
const o = statusNotifierOf(e);
|
|
722
|
+
if (o) {
|
|
723
|
+
o.call(e);
|
|
687
724
|
return;
|
|
688
725
|
}
|
|
689
726
|
propagateStatus(e, t, n);
|
|
@@ -693,10 +730,10 @@ function notifyStatus(e, t, n, r) {
|
|
|
693
730
|
* subscriber as a propagated mark (or a re-derive). On its own for a store
|
|
694
731
|
* family's leaves, which are not the derive's dependents — the family
|
|
695
732
|
* propagates the derive's status from each leaf to the leaf's readers
|
|
696
|
-
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n
|
|
697
|
-
const
|
|
698
|
-
forEachDependent(e, (
|
|
699
|
-
|
|
733
|
+
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n) {
|
|
734
|
+
const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
735
|
+
forEachDependent(e, (o, s) => {
|
|
736
|
+
o.ie = clock;
|
|
700
737
|
// A pending mark on a kept-tail link re-derives the subscriber instead of
|
|
701
738
|
// marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
|
|
702
739
|
// Past `_depsTail` lie the committed frame's deps, kept by A30 because
|
|
@@ -716,8 +753,8 @@ function notifyStatus(e, t, n, r) {
|
|
|
716
753
|
// Inheriting the error would make a probe's reader errored. A boundary's
|
|
717
754
|
// output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
|
|
718
755
|
// is its pass's call.
|
|
719
|
-
if (
|
|
720
|
-
enqueueSub(
|
|
756
|
+
if (o.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && s.Te !== o.Ne) {
|
|
757
|
+
enqueueSub(o);
|
|
721
758
|
schedule();
|
|
722
759
|
return;
|
|
723
760
|
}
|
|
@@ -728,30 +765,28 @@ function notifyStatus(e, t, n, r) {
|
|
|
728
765
|
// frame still passes through — its pass is the frame's (#3372, compiled
|
|
729
766
|
// shape: the unmount it stages makes the observer a zombie whose say is
|
|
730
767
|
// moot for this transaction, A15 #3463).
|
|
731
|
-
if (t === STATUS_PENDING &&
|
|
732
|
-
if (passLane === null && (
|
|
768
|
+
if (t === STATUS_PENDING && r && o.T?.se?.has(r)) {
|
|
769
|
+
if (passLane === null && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(o, r.ie === clock)) joinFuture(txOf(o));
|
|
733
770
|
return;
|
|
734
771
|
}
|
|
735
|
-
if (t === STATUS_PENDING &&
|
|
772
|
+
if (t === STATUS_PENDING && r || t !== STATUS_PENDING && (o.T?.F !== n || o.T?.se)) {
|
|
736
773
|
// The marked subscriber is queued for the commit sweep so its status
|
|
737
774
|
// bookkeeping (loading window, uninitialized clear) runs with the flush
|
|
738
775
|
// — with the lane, when the pass propagating is the lane's work and
|
|
739
776
|
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (t === STATUS_PENDING && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
|
|
750
|
-
}
|
|
777
|
+
// (No answer: a pending propagation leaves a written guess a guess.)
|
|
778
|
+
if (laneStageHook && passLane !== null) laneStageHook(o, passLane, true, e); else {
|
|
779
|
+
queuePendingNode(o);
|
|
780
|
+
// A15 (#3443): pending propagates onto a held memo without
|
|
781
|
+
// recomputing it, and the propagation itself enters the memo's
|
|
782
|
+
// transaction — the flight flows into a memo that transaction
|
|
783
|
+
// holds, so the write that started it is held with it. A render
|
|
784
|
+
// effect's membership is its pass's (`notify`), never sticky.
|
|
785
|
+
if (t === STATUS_PENDING && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !o.i) joinFuture(txOf(o));
|
|
751
786
|
}
|
|
752
|
-
notifyStatus(
|
|
787
|
+
notifyStatus(o, t, n);
|
|
753
788
|
}
|
|
754
789
|
});
|
|
755
790
|
}
|
|
756
791
|
|
|
757
|
-
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
|
|
792
|
+
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, onSupersede, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
|
|
@@ -236,4 +236,6 @@ const defaultContext = {};
|
|
|
236
236
|
* @internal
|
|
237
237
|
*/ const $REFRESH = Symbol("refresh");
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
const NewSet = Set;
|
|
240
|
+
|
|
241
|
+
export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, NewSet, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
|
|
@@ -33,6 +33,8 @@ import { getOwner } from "./owner.js";
|
|
|
33
33
|
let r = t.A[e.id];
|
|
34
34
|
if (r === undefined) r = e.defaultValue;
|
|
35
35
|
if (r === undefined) {
|
|
36
|
+
// Dev names the context and why it has no value: no provider, or a
|
|
37
|
+
// provider that passed `undefined` (the key is set, to `undefined`).
|
|
36
38
|
throw new ContextNotFoundError;
|
|
37
39
|
}
|
|
38
40
|
return r;
|