@solidjs/signals 2.0.0-rc.17 → 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 +296 -191
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +527 -311
- package/dist/observe/core/async.js +148 -115
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/core.js +27 -27
- package/dist/observe/core/effect.js +29 -32
- package/dist/observe/core/graph.js +5 -5
- package/dist/observe/core/owner.js +7 -7
- package/dist/observe/core/scheduler.js +23 -12
- package/dist/observe/core/verdict.js +2 -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/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +595 -618
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/core/async.js +209 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/core.js +33 -33
- package/dist/prod/core/effect.js +24 -27
- package/dist/prod/core/graph.js +2 -2
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/scheduler.js +35 -24
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +7 -7
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/store/optimistic.js +1 -1
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +94 -117
- 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 +19 -3
- package/dist/types/core/scheduler.d.ts +15 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -154,7 +154,7 @@ function releaseSettledDependents(e) {
|
|
|
154
154
|
// The node answered (an error ends the wait — no longer pending, nor
|
|
155
155
|
// blocked); a shown error stays its display until the commit.
|
|
156
156
|
clearPendingSources(e);
|
|
157
|
-
if (e.T) e.T.
|
|
157
|
+
if (e.T) e.T.fe = false;
|
|
158
158
|
if (!((e.m &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR)) setPendingError(e);
|
|
159
159
|
e.ue = t instanceof StatusError ? t : new StatusError(e, t);
|
|
160
160
|
e.l |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
|
|
@@ -167,7 +167,7 @@ function releaseSettledDependents(e) {
|
|
|
167
167
|
|
|
168
168
|
function settleErroredDependents(e, t) {
|
|
169
169
|
let n = false;
|
|
170
|
-
const r = new
|
|
170
|
+
const r = new NewSet;
|
|
171
171
|
const visit = e => {
|
|
172
172
|
if (r.has(e)) return;
|
|
173
173
|
r.add(e);
|
|
@@ -192,51 +192,51 @@ function settlePendingSource(e, t = e) {
|
|
|
192
192
|
removePendingSource(e, t);
|
|
193
193
|
let n = false;
|
|
194
194
|
let r;
|
|
195
|
-
const o = new
|
|
196
|
-
const settle =
|
|
197
|
-
if (o.has(
|
|
195
|
+
const o = new NewSet;
|
|
196
|
+
const settle = s => {
|
|
197
|
+
if (o.has(s) ||
|
|
198
198
|
// A conditional dropped this source, but another dependency can still
|
|
199
199
|
// carry it. Only retire pending state inherited through the recovered
|
|
200
200
|
// branch. Deliberately NOT marked visited on this early return: the
|
|
201
201
|
// carrying dependency may itself be a later branch of this same walk
|
|
202
202
|
// (two unchanged memos converging), and its visit must be free to
|
|
203
203
|
// re-examine this node once that branch has retired the source.
|
|
204
|
-
t !== e && retryReaches(
|
|
204
|
+
t !== e && retryReaches(s, t) || !removePendingSource(s, t))
|
|
205
205
|
// A19: a verdict reader holds no pending of its own (it was re-derived
|
|
206
206
|
// when the source went pending, `propagateStatus`), and a landing
|
|
207
207
|
// equal to the committed value notifies nobody — the source settling
|
|
208
208
|
// is its verdict changing: it runs again.
|
|
209
|
-
return
|
|
210
|
-
o.add(
|
|
211
|
-
|
|
212
|
-
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;
|
|
213
213
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
214
214
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
215
215
|
// otherwise): the settled error stays the answer through the settle —
|
|
216
216
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
217
217
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
218
|
-
const u =
|
|
219
|
-
if (
|
|
220
|
-
if (!u) setPendingError(
|
|
218
|
+
const u = s.m & STATUS_ERROR;
|
|
219
|
+
if (f) {
|
|
220
|
+
if (!u) setPendingError(s, f);
|
|
221
221
|
} else {
|
|
222
|
-
|
|
223
|
-
if (!u) setPendingError(
|
|
222
|
+
s.m &= ~STATUS_PENDING;
|
|
223
|
+
if (!u) setPendingError(s);
|
|
224
224
|
// L2: a landing resumes the transaction waiting on it (maintainer: "it
|
|
225
225
|
// resumes the sync frame") — a held reader's re-pass over the landed
|
|
226
226
|
// value is that transaction's work, and the flush that carries it
|
|
227
227
|
// parks into it.
|
|
228
|
-
if (
|
|
229
|
-
if (
|
|
230
|
-
enqueueSub(
|
|
228
|
+
if (s.l & CONFIG_HELD) joinFuture(txOf(s));
|
|
229
|
+
if (s.T?.fe) {
|
|
230
|
+
enqueueSub(s);
|
|
231
231
|
n = true;
|
|
232
232
|
}
|
|
233
|
-
if (
|
|
233
|
+
if (s.T !== null) s.T.fe = false;
|
|
234
234
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
235
235
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
236
236
|
// lists this walk is still iterating.
|
|
237
|
-
if (!
|
|
237
|
+
if (!s.o && s.l & CONFIG_AUTO_DISPOSE) (r ??= []).push(s);
|
|
238
238
|
}
|
|
239
|
-
forEachDependent(
|
|
239
|
+
forEachDependent(s, settle);
|
|
240
240
|
};
|
|
241
241
|
forEachDependent(e, settle);
|
|
242
242
|
// Release before the flush schedule below: unobserved() pulls the node back
|
|
@@ -258,6 +258,34 @@ function isThenable(e) {
|
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
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
|
+
|
|
261
289
|
function handleAsync(e, t, n,
|
|
262
290
|
// The flight rejected (after the node's status is set): a projection
|
|
263
291
|
// tells its leaves' readers, who are not the node's dependents
|
|
@@ -265,14 +293,14 @@ function handleAsync(e, t, n,
|
|
|
265
293
|
// pending on another source, not errored.
|
|
266
294
|
r) {
|
|
267
295
|
let o = false;
|
|
268
|
-
let
|
|
296
|
+
let s = false;
|
|
269
297
|
if (typeof t === "object" && t !== null) {
|
|
270
298
|
untrack(() => {
|
|
271
299
|
o = t[Symbol.asyncIterator];
|
|
272
|
-
|
|
300
|
+
s = !o && isThenable(t);
|
|
273
301
|
});
|
|
274
302
|
}
|
|
275
|
-
if (!
|
|
303
|
+
if (!s && !o) {
|
|
276
304
|
if (e.T !== null) e.T.Se = null;
|
|
277
305
|
// A sync landing is the first real answer for a loadingValue node.
|
|
278
306
|
e.ce = false;
|
|
@@ -293,19 +321,19 @@ r) {
|
|
|
293
321
|
// describe this answer. Drop it — the flight is the node's pending now.
|
|
294
322
|
// The landing retires only the flight's own entry (landStatus, #3373), so
|
|
295
323
|
// an entry that survived here would hold the node past its own answer.
|
|
296
|
-
e.T.
|
|
324
|
+
e.T.se = undefined;
|
|
297
325
|
// Attribution hook: a new flight is registered. Fired here (not in the
|
|
298
326
|
// branches below) so every flight shape — plain thenable, iterator, the
|
|
299
327
|
// flattened combinations — is announced exactly once, while the recompute
|
|
300
328
|
// frame that caused it is still on the engine's stack. Not inside a try
|
|
301
329
|
// (#2883 — see attribution-hooks.ts).
|
|
302
330
|
if (attrHooks !== null) attrHooks.flightStart(e, t);
|
|
303
|
-
let
|
|
331
|
+
let f;
|
|
304
332
|
const handleError = o => {
|
|
305
333
|
if (e.T?.Se !== t) return;
|
|
306
334
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
307
|
-
let
|
|
308
|
-
if (
|
|
335
|
+
let s = o instanceof NotReadyError;
|
|
336
|
+
if (s && e.ce) {
|
|
309
337
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
310
338
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
311
339
|
// dependency throws. The dead flight is released so the clock-gated
|
|
@@ -318,17 +346,24 @@ r) {
|
|
|
318
346
|
// D-41: a held node's error is staged (`stageError`). A derived store's
|
|
319
347
|
// readers learn its error through the family, not the derive's
|
|
320
348
|
// dependents: it publishes now.
|
|
321
|
-
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
|
+
}
|
|
322
357
|
// A NotReady rejection is a landing into another pending source. The
|
|
323
358
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
324
359
|
// after notifyStatus has propagated the replacement source.
|
|
325
|
-
if (
|
|
360
|
+
if (s) settlePendingSource(e);
|
|
326
361
|
e.ie = clock;
|
|
327
362
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
328
363
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
329
364
|
// the error twin of settlePendingSource's release (#2934).
|
|
330
|
-
if (!
|
|
331
|
-
r?.(o,
|
|
365
|
+
if (!s) releaseSettledDependents(e);
|
|
366
|
+
r?.(o, s);
|
|
332
367
|
};
|
|
333
368
|
const asyncWrite = (r, o) => {
|
|
334
369
|
if (e.T?.Se !== t) return;
|
|
@@ -336,7 +371,7 @@ r) {
|
|
|
336
371
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
337
372
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
338
373
|
if (e.R & REACTIVE_DIRTY) return;
|
|
339
|
-
const
|
|
374
|
+
const s = e.m & STATUS_UNINITIALIZED;
|
|
340
375
|
landStatus(e);
|
|
341
376
|
// Attribution hook: lets the engine snapshot state before the landing
|
|
342
377
|
// branches, so it can tell whether the plain path's setSignal committed a
|
|
@@ -352,7 +387,7 @@ r) {
|
|
|
352
387
|
// A store derive's landing commits through its setter: unheld, the
|
|
353
388
|
// shown error leaves now; held, at the derive's commit.
|
|
354
389
|
if (!(e.l & CONFIG_HELD)) e.T.de = undefined;
|
|
355
|
-
if (
|
|
390
|
+
if (s) landStatus(e, true);
|
|
356
391
|
// Attribution hook: this path landed through the setter (derived
|
|
357
392
|
// stores, projections), which does not go through setSignal, so the
|
|
358
393
|
// plain branch's asyncEnd never ran and the flight stayed open — the
|
|
@@ -419,7 +454,7 @@ r) {
|
|
|
419
454
|
// empty completion) — meaningful only in the live posture.
|
|
420
455
|
const consumeIterator = (n, r) => {
|
|
421
456
|
const o = n[Symbol.asyncIterator]();
|
|
422
|
-
let
|
|
457
|
+
let s = false;
|
|
423
458
|
let u = false;
|
|
424
459
|
let i = !r;
|
|
425
460
|
const close = () => {
|
|
@@ -433,7 +468,11 @@ r) {
|
|
|
433
468
|
cleanup(close, r);
|
|
434
469
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
435
470
|
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
436
|
-
// 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.
|
|
437
476
|
ext(e).ae = close;
|
|
438
477
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
439
478
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
@@ -474,11 +513,11 @@ r) {
|
|
|
474
513
|
} else if (e.T?.Se !== t) {
|
|
475
514
|
return;
|
|
476
515
|
} else if (!r.done) {
|
|
477
|
-
|
|
516
|
+
s = true;
|
|
478
517
|
asyncWrite(r.value, iterateOrRelease);
|
|
479
518
|
} else {
|
|
480
519
|
u = true;
|
|
481
|
-
if (
|
|
520
|
+
if (s) {
|
|
482
521
|
schedule();
|
|
483
522
|
flush();
|
|
484
523
|
} else {
|
|
@@ -506,8 +545,8 @@ r) {
|
|
|
506
545
|
return true;
|
|
507
546
|
}
|
|
508
547
|
if (l && !n.done) {
|
|
509
|
-
|
|
510
|
-
|
|
548
|
+
f = n.value;
|
|
549
|
+
s = true;
|
|
511
550
|
return iterate();
|
|
512
551
|
}
|
|
513
552
|
return l && n.done;
|
|
@@ -515,7 +554,7 @@ r) {
|
|
|
515
554
|
const l = iterate();
|
|
516
555
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
517
556
|
i = false;
|
|
518
|
-
return
|
|
557
|
+
return s || l;
|
|
519
558
|
};
|
|
520
559
|
// Landed-synchronously verdict for a LIVE iterator drain; null when no live
|
|
521
560
|
// drain ran (plain promise flight, or a deferred flatten). Drives the
|
|
@@ -534,16 +573,16 @@ r) {
|
|
|
534
573
|
});
|
|
535
574
|
}
|
|
536
575
|
if (!n) return false;
|
|
537
|
-
|
|
576
|
+
f = undefined;
|
|
538
577
|
const r = consumeIterator(e, t);
|
|
539
578
|
if (!t) u = r;
|
|
540
579
|
return true;
|
|
541
580
|
};
|
|
542
|
-
if (
|
|
543
|
-
let n = false, r = false, o,
|
|
581
|
+
if (s) {
|
|
582
|
+
let n = false, r = false, o, s = true;
|
|
544
583
|
t.then(r => {
|
|
545
|
-
if (
|
|
546
|
-
|
|
584
|
+
if (s) {
|
|
585
|
+
f = r;
|
|
547
586
|
n = true;
|
|
548
587
|
} else {
|
|
549
588
|
// Flattening consumes the stream as the value: each yield lands
|
|
@@ -564,7 +603,7 @@ r) {
|
|
|
564
603
|
settleAutodispose();
|
|
565
604
|
}
|
|
566
605
|
}, e => {
|
|
567
|
-
if (
|
|
606
|
+
if (s) {
|
|
568
607
|
o = e;
|
|
569
608
|
r = true;
|
|
570
609
|
} else {
|
|
@@ -572,7 +611,7 @@ r) {
|
|
|
572
611
|
settleAutodispose();
|
|
573
612
|
}
|
|
574
613
|
});
|
|
575
|
-
|
|
614
|
+
s = false;
|
|
576
615
|
if (r) {
|
|
577
616
|
// Settle through the same status path an async rejection uses, then
|
|
578
617
|
// unwind the in-progress synchronous read so the errored node isn't
|
|
@@ -580,13 +619,13 @@ r) {
|
|
|
580
619
|
handleError(o);
|
|
581
620
|
throw o;
|
|
582
621
|
} else if (!n) {
|
|
583
|
-
//
|
|
584
|
-
// work on a loadingValue node is
|
|
585
|
-
// boundaries
|
|
586
|
-
// lands through asyncWrite.
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
} 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)) {
|
|
590
629
|
// Synchronously-resolved promise: the first real answer landed.
|
|
591
630
|
e.ce = false;
|
|
592
631
|
}
|
|
@@ -597,7 +636,7 @@ r) {
|
|
|
597
636
|
if (o) flattenIfIterable(t);
|
|
598
637
|
if (u !== null) {
|
|
599
638
|
if (!u) {
|
|
600
|
-
// Loading window: serve commit #0
|
|
639
|
+
// Loading window: serve commit #0 instead of suspending.
|
|
601
640
|
if (e.ce) return e.Ie;
|
|
602
641
|
throw new NotReadyError(context);
|
|
603
642
|
}
|
|
@@ -605,12 +644,12 @@ r) {
|
|
|
605
644
|
// answer; async yields clear inside asyncWrite.
|
|
606
645
|
e.ce = false;
|
|
607
646
|
}
|
|
608
|
-
return
|
|
647
|
+
return f;
|
|
609
648
|
}
|
|
610
649
|
|
|
611
650
|
function clearStatus(e, t = false) {
|
|
612
|
-
if (e.T?.
|
|
613
|
-
if (e.T?.
|
|
651
|
+
if (e.T?.se) clearPendingSources(e);
|
|
652
|
+
if (e.T?.fe) e.T.fe = false;
|
|
614
653
|
e.m = t ? 0 : e.m & STATUS_UNINITIALIZED;
|
|
615
654
|
if (e.T?.F) setPendingError(e);
|
|
616
655
|
const n = statusNotifierOf(e);
|
|
@@ -642,34 +681,32 @@ function clearStatus(e, t = false) {
|
|
|
642
681
|
* reader thrown NotReady(self) would park on a retired entry. Companions
|
|
643
682
|
* keep their verdict (pending before and after; the write re-syncs them).
|
|
644
683
|
*/ function landStatus(e, t = false) {
|
|
645
|
-
const n = e.T?.
|
|
684
|
+
const n = e.T?.se;
|
|
646
685
|
// (The full clear below drops the set whether or not self was retired first.)
|
|
647
686
|
if (n && (n.delete(e), n.size)) {
|
|
648
|
-
e.T.
|
|
687
|
+
e.T.fe = false;
|
|
649
688
|
if (t) e.m = STATUS_PENDING;
|
|
650
689
|
setPendingError(e, n.values().next().value);
|
|
651
690
|
} else clearStatus(e, t);
|
|
652
691
|
}
|
|
653
692
|
|
|
654
|
-
function notifyStatus(e, t, n
|
|
693
|
+
function notifyStatus(e, t, n) {
|
|
655
694
|
// Wrap regular errors to track source node
|
|
656
695
|
if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
|
|
657
|
-
const
|
|
696
|
+
const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
658
697
|
// (CARVE 2: the lane assignment went with the engine.)
|
|
659
|
-
{
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
ext(e).F = n;
|
|
672
|
-
}
|
|
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;
|
|
673
710
|
}
|
|
674
711
|
// Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
|
|
675
712
|
// future value until we know otherwise"). Its own source in flight is its
|
|
@@ -681,11 +718,9 @@ function notifyStatus(e, t, n, r) {
|
|
|
681
718
|
if (passLane === null) joinFuture(null);
|
|
682
719
|
return;
|
|
683
720
|
}
|
|
684
|
-
const
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
f.call(e);
|
|
688
|
-
}
|
|
721
|
+
const o = statusNotifierOf(e);
|
|
722
|
+
if (o) {
|
|
723
|
+
o.call(e);
|
|
689
724
|
return;
|
|
690
725
|
}
|
|
691
726
|
propagateStatus(e, t, n);
|
|
@@ -695,10 +730,10 @@ function notifyStatus(e, t, n, r) {
|
|
|
695
730
|
* subscriber as a propagated mark (or a re-derive). On its own for a store
|
|
696
731
|
* family's leaves, which are not the derive's dependents — the family
|
|
697
732
|
* propagates the derive's status from each leaf to the leaf's readers
|
|
698
|
-
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n
|
|
699
|
-
const
|
|
700
|
-
forEachDependent(e, (
|
|
701
|
-
|
|
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;
|
|
702
737
|
// A pending mark on a kept-tail link re-derives the subscriber instead of
|
|
703
738
|
// marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
|
|
704
739
|
// Past `_depsTail` lie the committed frame's deps, kept by A30 because
|
|
@@ -718,8 +753,8 @@ function notifyStatus(e, t, n, r) {
|
|
|
718
753
|
// Inheriting the error would make a probe's reader errored. A boundary's
|
|
719
754
|
// output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
|
|
720
755
|
// is its pass's call.
|
|
721
|
-
if (
|
|
722
|
-
enqueueSub(
|
|
756
|
+
if (o.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && s.Te !== o.Ne) {
|
|
757
|
+
enqueueSub(o);
|
|
723
758
|
schedule();
|
|
724
759
|
return;
|
|
725
760
|
}
|
|
@@ -730,30 +765,28 @@ function notifyStatus(e, t, n, r) {
|
|
|
730
765
|
// frame still passes through — its pass is the frame's (#3372, compiled
|
|
731
766
|
// shape: the unmount it stages makes the observer a zombie whose say is
|
|
732
767
|
// moot for this transaction, A15 #3463).
|
|
733
|
-
if (t === STATUS_PENDING &&
|
|
734
|
-
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));
|
|
735
770
|
return;
|
|
736
771
|
}
|
|
737
|
-
if (t === STATUS_PENDING &&
|
|
772
|
+
if (t === STATUS_PENDING && r || t !== STATUS_PENDING && (o.T?.F !== n || o.T?.se)) {
|
|
738
773
|
// The marked subscriber is queued for the commit sweep so its status
|
|
739
774
|
// bookkeeping (loading window, uninitialized clear) runs with the flush
|
|
740
775
|
// — with the lane, when the pass propagating is the lane's work and
|
|
741
776
|
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if (t === STATUS_PENDING && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
|
|
752
|
-
}
|
|
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));
|
|
753
786
|
}
|
|
754
|
-
notifyStatus(
|
|
787
|
+
notifyStatus(o, t, n);
|
|
755
788
|
}
|
|
756
789
|
});
|
|
757
790
|
}
|
|
758
791
|
|
|
759
|
-
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 };
|