@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15
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 +248 -189
- package/dist/dev.attribution.js +124 -41
- package/dist/dev.js +553 -322
- package/dist/observe/affects.js +34 -31
- package/dist/observe/boundaries.js +166 -132
- package/dist/observe/core/async.js +90 -83
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +281 -197
- package/dist/observe/core/constants.js +7 -2
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +277 -245
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +21 -21
- package/dist/observe/core/external.js +2 -2
- package/dist/observe/core/graph.js +25 -25
- package/dist/observe/core/heap.js +9 -9
- package/dist/observe/core/lanes.js +206 -160
- package/dist/observe/core/owner.js +27 -27
- package/dist/observe/core/scheduler.js +92 -86
- package/dist/observe/core/verdict.js +66 -54
- package/dist/observe/map.js +35 -35
- package/dist/observe/reveal.js +24 -24
- package/dist/observe/signals.js +38 -28
- package/dist/observe/store/affects.js +75 -68
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +67 -34
- package/dist/observe/store/projection.js +37 -31
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +128 -85
- package/dist/prod/affects.js +34 -31
- package/dist/prod/boundaries.js +143 -109
- package/dist/prod/core/async.js +64 -67
- package/dist/prod/core/constants.js +7 -2
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +302 -270
- package/dist/prod/core/effect.js +38 -38
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +257 -211
- package/dist/prod/core/owner.js +39 -39
- package/dist/prod/core/scheduler.js +125 -119
- package/dist/prod/core/verdict.js +70 -58
- package/dist/prod/map.js +73 -73
- package/dist/prod/reveal.js +38 -38
- package/dist/prod/signals.js +30 -20
- package/dist/prod/store/affects.js +75 -68
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +114 -81
- package/dist/prod/store/projection.js +30 -24
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +136 -93
- package/dist/types/boundaries.d.ts +4 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +33 -3
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +12 -6
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/store/affects.d.ts +11 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +0 -1
- package/dist/types/store/store.d.ts +3 -38
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ import { enqueueSub } from "./heap.js";
|
|
|
14
14
|
|
|
15
15
|
import { cleanup } from "./owner.js";
|
|
16
16
|
|
|
17
|
-
import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush,
|
|
17
|
+
import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush, globalQueue, txOf, GlobalQueue, queuePendingNode } 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 —
|
|
@@ -46,7 +46,7 @@ function clearPendingSources(e) {
|
|
|
46
46
|
// (pending sources propagate the origin node, so this covers any depth).
|
|
47
47
|
// Also guards branch-local recovery: another dependency may still need the source.
|
|
48
48
|
function retryReaches(e, t) {
|
|
49
|
-
for (let n = e.
|
|
49
|
+
for (let n = e.G; n; n = n._) {
|
|
50
50
|
const e = n.I;
|
|
51
51
|
if (e === t || e.m?.Se?.has(t)) return true;
|
|
52
52
|
}
|
|
@@ -60,32 +60,32 @@ 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).de = 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
|
|
67
67
|
// throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
|
|
68
68
|
// a pending-class NotReadyError from a read-invisible park (#2989).
|
|
69
|
-
if (!(e.
|
|
69
|
+
if (!(e.S & STATUS_ERROR)) setPendingError(e, t.source, t);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function setPendingError(e, t, n) {
|
|
73
73
|
if (!t) {
|
|
74
|
-
if (e.m !== null) e.m.
|
|
74
|
+
if (e.m !== null) e.m.F = null;
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
if (n instanceof NotReadyError && n.source === t) {
|
|
78
|
-
ext(e).
|
|
78
|
+
ext(e).F = n;
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
|
-
const r = e.m?.
|
|
81
|
+
const r = e.m?.F;
|
|
82
82
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
83
|
-
ext(e).
|
|
83
|
+
ext(e).F = new NotReadyError(t);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
function forEachDependent(e, t) {
|
|
88
|
-
for (let n = e.t; n !== null; n = n.
|
|
88
|
+
for (let n = e.t; n !== null; n = n.o) t(n.l, n);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
@@ -99,7 +99,7 @@ function forEachDependent(e, t) {
|
|
|
99
99
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
100
100
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
101
101
|
function releaseIfSettledUnobserved(e) {
|
|
102
|
-
e.
|
|
102
|
+
e.ee && e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.R & REACTIVE_ZOMBIE) && !(e.S & STATUS_PENDING) && unobserved(e);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -112,7 +112,7 @@ function releaseSettledDependents(e) {
|
|
|
112
112
|
const visit = e => {
|
|
113
113
|
if (n.has(e)) return;
|
|
114
114
|
n.add(e);
|
|
115
|
-
if (!e.t && e.
|
|
115
|
+
if (!e.t && e.i & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
116
116
|
forEachDependent(e, visit);
|
|
117
117
|
};
|
|
118
118
|
forEachDependent(e, visit);
|
|
@@ -140,7 +140,7 @@ function settleErroredDependents(e, t) {
|
|
|
140
140
|
const visit = e => {
|
|
141
141
|
if (r.has(e)) return;
|
|
142
142
|
r.add(e);
|
|
143
|
-
if (e.m?.
|
|
143
|
+
if (e.m?.F === t) {
|
|
144
144
|
enqueueSub(e);
|
|
145
145
|
n = true;
|
|
146
146
|
}
|
|
@@ -175,35 +175,35 @@ function settlePendingSource(e, t = e) {
|
|
|
175
175
|
// when the source went pending, `propagateStatus`), and a landing
|
|
176
176
|
// equal to the committed value notifies nobody — the source settling
|
|
177
177
|
// is its verdict changing: it runs again.
|
|
178
|
-
return f.
|
|
178
|
+
return f.i & CONFIG_VERDICT && enqueueSub(f);
|
|
179
179
|
o.add(f);
|
|
180
|
-
f.
|
|
180
|
+
f.Ie = clock;
|
|
181
181
|
const u = f.m?.Se?.values().next().value;
|
|
182
182
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
183
183
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
184
184
|
// otherwise): the settled error stays the answer through the settle —
|
|
185
185
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
186
186
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
187
|
-
const
|
|
187
|
+
const s = f.S & STATUS_ERROR;
|
|
188
188
|
if (u) {
|
|
189
|
-
if (!
|
|
189
|
+
if (!s) setPendingError(f, u);
|
|
190
190
|
} else {
|
|
191
|
-
f.
|
|
192
|
-
if (!
|
|
191
|
+
f.S &= ~STATUS_PENDING;
|
|
192
|
+
if (!s) setPendingError(f);
|
|
193
193
|
// L2: a landing resumes the transaction waiting on it (maintainer: "it
|
|
194
194
|
// resumes the sync frame") — a held reader's re-pass over the landed
|
|
195
195
|
// value is that transaction's work, and the flush that carries it
|
|
196
196
|
// parks into it.
|
|
197
|
-
if (f.
|
|
198
|
-
if (f.m?.
|
|
197
|
+
if (f.i & CONFIG_HELD) joinFuture(txOf(f));
|
|
198
|
+
if (f.m?.de) {
|
|
199
199
|
enqueueSub(f);
|
|
200
200
|
n = true;
|
|
201
201
|
}
|
|
202
|
-
if (f.m !== null) f.m.
|
|
202
|
+
if (f.m !== null) f.m.de = false;
|
|
203
203
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
204
204
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
205
205
|
// lists this walk is still iterating.
|
|
206
|
-
if (!f.t && f.
|
|
206
|
+
if (!f.t && f.i & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
|
|
207
207
|
}
|
|
208
208
|
forEachDependent(f, settle);
|
|
209
209
|
};
|
|
@@ -220,9 +220,9 @@ function isThenable(e) {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
|
|
223
|
-
const t = e.m?.
|
|
223
|
+
const t = e.m?.Ne;
|
|
224
224
|
if (t != null) {
|
|
225
|
-
e.m.
|
|
225
|
+
e.m.Ne = null;
|
|
226
226
|
t();
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -242,9 +242,9 @@ r) {
|
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
244
|
if (!f && !o) {
|
|
245
|
-
if (e.m !== null) e.m.
|
|
245
|
+
if (e.m !== null) e.m.Te = null;
|
|
246
246
|
// A sync landing is the first real answer for a loadingValue node.
|
|
247
|
-
e.
|
|
247
|
+
e.De = false;
|
|
248
248
|
return t;
|
|
249
249
|
}
|
|
250
250
|
// Flight replacement relies on recompute's supersede release for iterator
|
|
@@ -252,10 +252,10 @@ r) {
|
|
|
252
252
|
// self-registration — runs during a recompute of `el`, which has already
|
|
253
253
|
// fired _flightTeardown. A future non-recompute registration path must
|
|
254
254
|
// release it here before overwriting _inFlight.
|
|
255
|
-
ext(e).
|
|
255
|
+
ext(e).Te = t;
|
|
256
256
|
// The question this flight answers (A18 provenance, lanes.ts): the action
|
|
257
257
|
// whose slice asked it; mainline is always the current question.
|
|
258
|
-
e.m.
|
|
258
|
+
e.m._e = question || MAINLINE_QUESTION;
|
|
259
259
|
// The run that asked this flight read every input without throwing: an
|
|
260
260
|
// input still in flight was masked for it (an active override, A17), so
|
|
261
261
|
// pending state those inputs propagated onto the node earlier does not
|
|
@@ -271,17 +271,17 @@ r) {
|
|
|
271
271
|
if (attrHooks !== null) attrHooks.flightStart(e, t);
|
|
272
272
|
let u;
|
|
273
273
|
const handleError = n => {
|
|
274
|
-
if (e.m?.
|
|
274
|
+
if (e.m?.Te !== t) return;
|
|
275
275
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
276
276
|
let o = n instanceof NotReadyError;
|
|
277
|
-
if (o && e.
|
|
277
|
+
if (o && e.De) {
|
|
278
278
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
279
279
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
280
280
|
// dependency throws. The dead flight is released so the clock-gated
|
|
281
281
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
282
|
-
if (e.m !== null) e.m.
|
|
282
|
+
if (e.m !== null) e.m.Te = null;
|
|
283
283
|
parkLoadingWindow(e, n);
|
|
284
|
-
e.
|
|
284
|
+
e.Ie = clock;
|
|
285
285
|
return;
|
|
286
286
|
}
|
|
287
287
|
notifyStatus(e, o ? STATUS_PENDING : STATUS_ERROR, n);
|
|
@@ -289,7 +289,7 @@ r) {
|
|
|
289
289
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
290
290
|
// after notifyStatus has propagated the replacement source.
|
|
291
291
|
if (o) settlePendingSource(e);
|
|
292
|
-
e.
|
|
292
|
+
e.Ie = clock;
|
|
293
293
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
294
294
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
295
295
|
// the error twin of settlePendingSource's release (#2934).
|
|
@@ -297,12 +297,12 @@ r) {
|
|
|
297
297
|
r?.(n, o);
|
|
298
298
|
};
|
|
299
299
|
const asyncWrite = (r, o) => {
|
|
300
|
-
if (e.m?.
|
|
300
|
+
if (e.m?.Te !== t) return;
|
|
301
301
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
302
302
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
303
303
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
304
304
|
if (e.R & REACTIVE_DIRTY) return;
|
|
305
|
-
const f = !!(e.
|
|
305
|
+
const f = !!(e.S & STATUS_UNINITIALIZED);
|
|
306
306
|
landStatus(e);
|
|
307
307
|
// Attribution hook: lets the engine snapshot state before the landing
|
|
308
308
|
// branches, so it can tell whether the plain path's setSignal committed a
|
|
@@ -316,14 +316,21 @@ r) {
|
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
318
|
if (f) landStatus(e, true);
|
|
319
|
+
// Attribution hook: this path landed through the setter (derived
|
|
320
|
+
// stores, projections), which does not go through setSignal, so the
|
|
321
|
+
// plain branch's asyncEnd never ran and the flight stayed open — the
|
|
322
|
+
// next flight counted a committed answer as abandoned (#3947).
|
|
323
|
+
// direct=true: asyncEnd finalizes either way and stamps an async write
|
|
324
|
+
// only if the commit moved `_value`/`_time` or parked `_pendingValue`.
|
|
325
|
+
// A store setter does not move this node's `_value`, so no stamp is
|
|
326
|
+
// recorded and waterfall chaining through derived stores stays
|
|
327
|
+
// unmeasured. Outside the try (#2883 — see attribution-hooks.ts).
|
|
328
|
+
if (attrHooks !== null) attrHooks.asyncEnd(e, undefined, r, true);
|
|
319
329
|
} else {
|
|
320
330
|
// CARVE 2: the override-covered landing (hold + A18 supersession) and the
|
|
321
331
|
// lane-routed landing (derived override, lane effect queue) went with
|
|
322
|
-
// the optimistic engine; every landing is the plain setSignal. A
|
|
323
|
-
//
|
|
324
|
-
let t = e.m.Re;
|
|
325
|
-
e.m.Re = null;
|
|
326
|
-
if (f && t && (t = liveTx(t))) holdNode(e, t);
|
|
332
|
+
// the optimistic engine; every landing is the plain setSignal. A node
|
|
333
|
+
// already held stages its answer into that hold (`setSignal`).
|
|
327
334
|
try {
|
|
328
335
|
setSignal(e, () => r);
|
|
329
336
|
} catch (t) {
|
|
@@ -342,8 +349,8 @@ r) {
|
|
|
342
349
|
// (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
|
|
343
350
|
// the window when the flush commits it, so no one-frame pulse can leak to
|
|
344
351
|
// observers between the landing and its commit (#2990).
|
|
345
|
-
if (e.
|
|
346
|
-
e.
|
|
352
|
+
if (e.Oe === NOT_PENDING) {
|
|
353
|
+
e.De = false;
|
|
347
354
|
// The landing published: the dependency tail the flight's pass left
|
|
348
355
|
// linked goes now (A30, #3410). A staged landing has not replaced the
|
|
349
356
|
// committed frame yet; `commitPendingNode` trims it.
|
|
@@ -362,7 +369,7 @@ r) {
|
|
|
362
369
|
// Returns whether the node released, so the iterator branch can stop
|
|
363
370
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
364
371
|
const settleAutodispose = () => {
|
|
365
|
-
if (e.
|
|
372
|
+
if (e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.S & STATUS_PENDING)) {
|
|
366
373
|
unobserved(e);
|
|
367
374
|
return true;
|
|
368
375
|
}
|
|
@@ -382,11 +389,11 @@ r) {
|
|
|
382
389
|
const consumeIterator = (n, r) => {
|
|
383
390
|
const o = n[Symbol.asyncIterator]();
|
|
384
391
|
let f = false;
|
|
385
|
-
let
|
|
386
|
-
let
|
|
392
|
+
let s = false;
|
|
393
|
+
let i = !r;
|
|
387
394
|
const close = () => {
|
|
388
|
-
if (
|
|
389
|
-
|
|
395
|
+
if (s) return;
|
|
396
|
+
s = true;
|
|
390
397
|
try {
|
|
391
398
|
const e = o.return?.();
|
|
392
399
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
@@ -396,7 +403,7 @@ r) {
|
|
|
396
403
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
397
404
|
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
398
405
|
// sites so supersede stops this stream immediately.
|
|
399
|
-
ext(e).
|
|
406
|
+
ext(e).Ne = close;
|
|
400
407
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
401
408
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
402
409
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
@@ -422,17 +429,17 @@ r) {
|
|
|
422
429
|
// stash: it must write through the async path or the value is
|
|
423
430
|
// silently dropped. (The deferred posture never has a caller, so
|
|
424
431
|
// initialRead starts false there and everything writes through.)
|
|
425
|
-
if (c &&
|
|
432
|
+
if (c && i) {
|
|
426
433
|
n = r;
|
|
427
434
|
l = true;
|
|
428
|
-
if (r.done)
|
|
429
|
-
} else if (e.m?.
|
|
435
|
+
if (r.done) s = true;
|
|
436
|
+
} else if (e.m?.Te !== t) {
|
|
430
437
|
return;
|
|
431
438
|
} else if (!r.done) {
|
|
432
439
|
f = true;
|
|
433
440
|
asyncWrite(r.value, iterateOrRelease);
|
|
434
441
|
} else {
|
|
435
|
-
|
|
442
|
+
s = true;
|
|
436
443
|
if (f) {
|
|
437
444
|
schedule();
|
|
438
445
|
flush();
|
|
@@ -443,11 +450,11 @@ r) {
|
|
|
443
450
|
settleAutodispose();
|
|
444
451
|
}
|
|
445
452
|
}, n => {
|
|
446
|
-
if (c &&
|
|
453
|
+
if (c && i) {
|
|
447
454
|
r = n;
|
|
448
455
|
a = true;
|
|
449
|
-
} else if (e.m?.
|
|
450
|
-
|
|
456
|
+
} else if (e.m?.Te === t) {
|
|
457
|
+
s = true;
|
|
451
458
|
handleError(n);
|
|
452
459
|
settleAutodispose();
|
|
453
460
|
}
|
|
@@ -455,9 +462,9 @@ r) {
|
|
|
455
462
|
c = false;
|
|
456
463
|
if (a) {
|
|
457
464
|
// Match the promise branch, but only rethrow during the initial read.
|
|
458
|
-
|
|
465
|
+
s = true;
|
|
459
466
|
handleError(r);
|
|
460
|
-
if (
|
|
467
|
+
if (i) throw r;
|
|
461
468
|
return true;
|
|
462
469
|
}
|
|
463
470
|
if (l && !n.done) {
|
|
@@ -469,13 +476,13 @@ r) {
|
|
|
469
476
|
};
|
|
470
477
|
const l = iterate();
|
|
471
478
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
472
|
-
|
|
479
|
+
i = false;
|
|
473
480
|
return f || l;
|
|
474
481
|
};
|
|
475
482
|
// Landed-synchronously verdict for a LIVE iterator drain; null when no live
|
|
476
483
|
// drain ran (plain promise flight, or a deferred flatten). Drives the
|
|
477
484
|
// shared NotReady/loading tail below.
|
|
478
|
-
let
|
|
485
|
+
let s = null;
|
|
479
486
|
// Flatten one async level: a thenable that RESOLVES to an AsyncIterable —
|
|
480
487
|
// the shape every async stub returning a stream produces — consumes as the
|
|
481
488
|
// stream itself rather than settling on the iterable object. One level
|
|
@@ -490,7 +497,7 @@ r) {
|
|
|
490
497
|
}
|
|
491
498
|
if (!n) return false;
|
|
492
499
|
const r = consumeIterator(e, t);
|
|
493
|
-
if (!t)
|
|
500
|
+
if (!t) s = r;
|
|
494
501
|
return true;
|
|
495
502
|
};
|
|
496
503
|
if (f) {
|
|
@@ -502,13 +509,13 @@ r) {
|
|
|
502
509
|
// have put it. Only a flight that actually flattens becomes
|
|
503
510
|
// disposal-bearing.
|
|
504
511
|
const registerDeferredClose = t => {
|
|
505
|
-
if (!e.
|
|
512
|
+
if (!e.Re) e.Re = t; else if (Array.isArray(e.Re)) e.Re.push(t); else e.Re = [ e.Re, t ];
|
|
506
513
|
};
|
|
507
514
|
t.then(r => {
|
|
508
515
|
if (f) {
|
|
509
516
|
u = r;
|
|
510
517
|
n = true;
|
|
511
|
-
} else if (e.m?.
|
|
518
|
+
} else if (e.m?.Te === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
|
|
512
519
|
asyncWrite(r);
|
|
513
520
|
settleAutodispose();
|
|
514
521
|
}
|
|
@@ -533,35 +540,35 @@ r) {
|
|
|
533
540
|
// work on a loadingValue node is loading-class (invisible to
|
|
534
541
|
// boundaries); the flight itself is already registered in _inFlight and
|
|
535
542
|
// lands through asyncWrite.
|
|
536
|
-
if (e.
|
|
543
|
+
if (e.De) return e.Ae;
|
|
537
544
|
throw new NotReadyError(context);
|
|
538
545
|
} else if (!flattenIfIterable(u)) {
|
|
539
546
|
// Synchronously-resolved promise: the first real answer landed.
|
|
540
|
-
e.
|
|
547
|
+
e.De = false;
|
|
541
548
|
}
|
|
542
549
|
// A sync-resolved promise holding an AsyncIterable flattened LIVE (we
|
|
543
550
|
// are still inside the synchronous read): full initial-drain semantics
|
|
544
551
|
// apply and the shared tail below settles the verdict.
|
|
545
552
|
}
|
|
546
553
|
if (o) flattenIfIterable(t);
|
|
547
|
-
if (
|
|
548
|
-
if (!
|
|
554
|
+
if (s !== null) {
|
|
555
|
+
if (!s) {
|
|
549
556
|
// Loading window: serve commit #0 (see the promise branch above).
|
|
550
|
-
if (e.
|
|
557
|
+
if (e.De) return e.Ae;
|
|
551
558
|
throw new NotReadyError(context);
|
|
552
559
|
}
|
|
553
560
|
// A sync first yield (or immediate empty completion) is the first real
|
|
554
561
|
// answer; async yields clear inside asyncWrite.
|
|
555
|
-
e.
|
|
562
|
+
e.De = false;
|
|
556
563
|
}
|
|
557
564
|
return u;
|
|
558
565
|
}
|
|
559
566
|
|
|
560
567
|
function clearStatus(e, t = false) {
|
|
561
568
|
if (e.m?.Se) clearPendingSources(e);
|
|
562
|
-
if (e.m?.
|
|
563
|
-
e.
|
|
564
|
-
if (e.m?.
|
|
569
|
+
if (e.m?.de) if (e.m !== null) e.m.de = false;
|
|
570
|
+
e.S = t ? 0 : e.S & STATUS_UNINITIALIZED;
|
|
571
|
+
if (e.m?.F) setPendingError(e);
|
|
565
572
|
const n = statusNotifierOf(e);
|
|
566
573
|
if (n) n.call(e);
|
|
567
574
|
}
|
|
@@ -594,8 +601,8 @@ function clearStatus(e, t = false) {
|
|
|
594
601
|
const n = e.m?.Se;
|
|
595
602
|
// (The full clear below drops the set whether or not self was retired first.)
|
|
596
603
|
if (n && (n.delete(e), n.size)) {
|
|
597
|
-
e.m.
|
|
598
|
-
if (t) e.
|
|
604
|
+
e.m.de = false;
|
|
605
|
+
if (t) e.S = STATUS_PENDING;
|
|
599
606
|
setPendingError(e, n.values().next().value);
|
|
600
607
|
} else clearStatus(e, t);
|
|
601
608
|
}
|
|
@@ -608,14 +615,14 @@ function notifyStatus(e, t, n, r) {
|
|
|
608
615
|
{
|
|
609
616
|
if (t === STATUS_PENDING && o) {
|
|
610
617
|
addPendingSource(e, o);
|
|
611
|
-
e.
|
|
618
|
+
e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
|
|
612
619
|
// Preserve the current source on this propagation so readers park on
|
|
613
620
|
// the distinct pending source.
|
|
614
621
|
setPendingError(e, o, n);
|
|
615
622
|
} else {
|
|
616
623
|
clearPendingSources(e);
|
|
617
|
-
e.
|
|
618
|
-
ext(e).
|
|
624
|
+
e.S = t | (t !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
|
|
625
|
+
ext(e).F = n;
|
|
619
626
|
}
|
|
620
627
|
}
|
|
621
628
|
// Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
|
|
@@ -624,7 +631,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
624
631
|
// transition's to wait on — the frame it was asked in holds (A17: "a
|
|
625
632
|
// transition whose optimistic node is still pending on its own fetch is
|
|
626
633
|
// not complete"), through the node itself (`blocked`).
|
|
627
|
-
if (t === STATUS_PENDING && e.
|
|
634
|
+
if (t === STATUS_PENDING && e.i & CONFIG_GUESS) {
|
|
628
635
|
if (passLane === null) joinFuture(null);
|
|
629
636
|
return;
|
|
630
637
|
}
|
|
@@ -645,7 +652,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
645
652
|
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
|
|
646
653
|
const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
647
654
|
forEachDependent(e, (r, f) => {
|
|
648
|
-
r.
|
|
655
|
+
r.Ie = clock;
|
|
649
656
|
// A pending mark on a kept-tail link re-derives the subscriber instead of
|
|
650
657
|
// marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
|
|
651
658
|
// Past `_depsTail` lie the committed frame's deps, kept by A30 because
|
|
@@ -665,7 +672,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
665
672
|
// Inheriting the error would make a probe's reader errored. A boundary's
|
|
666
673
|
// output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
|
|
667
674
|
// is its pass's call.
|
|
668
|
-
if (r.
|
|
675
|
+
if (r.i & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Pe !== r.pe) {
|
|
669
676
|
enqueueSub(r);
|
|
670
677
|
schedule();
|
|
671
678
|
return;
|
|
@@ -678,24 +685,24 @@ function notifyStatus(e, t, n, r) {
|
|
|
678
685
|
// shape: the unmount it stages makes the observer a zombie whose say is
|
|
679
686
|
// moot for this transaction, A15 #3463).
|
|
680
687
|
if (t === STATUS_PENDING && o && r.m?.Se?.has(o)) {
|
|
681
|
-
if (passLane === null && (r.
|
|
688
|
+
if (passLane === null && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.X) joinFuture(txOf(r));
|
|
682
689
|
return;
|
|
683
690
|
}
|
|
684
|
-
if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.
|
|
691
|
+
if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.F !== n || r.m?.Se)) {
|
|
685
692
|
// The marked subscriber is queued for the commit sweep so its status
|
|
686
693
|
// bookkeeping (loading window, uninitialized clear) runs with the flush
|
|
687
694
|
// — with the lane, when the pass propagating is the lane's work and
|
|
688
695
|
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
689
696
|
{
|
|
690
697
|
// (No answer: a pending propagation leaves a written guess a guess.)
|
|
691
|
-
if (passLane !== null) GlobalQueue.
|
|
698
|
+
if (passLane !== null) GlobalQueue.W(r, passLane, true, e); else {
|
|
692
699
|
queuePendingNode(r);
|
|
693
700
|
// A15 (#3443): pending propagates onto a held memo without
|
|
694
701
|
// recomputing it, and the propagation itself enters the memo's
|
|
695
702
|
// transaction — the flight flows into a memo that transaction
|
|
696
703
|
// holds, so the write that started it is held with it. A render
|
|
697
704
|
// effect's membership is its pass's (`notify`), never sticky.
|
|
698
|
-
if (t === STATUS_PENDING && (r.
|
|
705
|
+
if (t === STATUS_PENDING && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.u) joinFuture(txOf(r));
|
|
699
706
|
}
|
|
700
707
|
}
|
|
701
708
|
notifyStatus(r, t, n);
|
|
@@ -36,7 +36,7 @@ import { $REFRESH } from "./constants.js";
|
|
|
36
36
|
*/ function subscriptions(n) {
|
|
37
37
|
const t = nodeOf(n);
|
|
38
38
|
const o = [];
|
|
39
|
-
for (let n = t?.
|
|
39
|
+
for (let n = t?.G ?? null; n !== null; n = n._) o.push(nodeName(n.I));
|
|
40
40
|
return o;
|
|
41
41
|
}
|
|
42
42
|
|