@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
package/dist/prod/core/async.js
CHANGED
|
@@ -10,7 +10,7 @@ import { enqueueSub } from "./heap.js";
|
|
|
10
10
|
|
|
11
11
|
import { cleanup } from "./owner.js";
|
|
12
12
|
|
|
13
|
-
import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush,
|
|
13
|
+
import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush, globalQueue, txOf, GlobalQueue, queuePendingNode } from "./scheduler.js";
|
|
14
14
|
|
|
15
15
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
16
16
|
// predecessor — a singular slot promoted to a Set on the second source —
|
|
@@ -42,7 +42,7 @@ function clearPendingSources(e) {
|
|
|
42
42
|
// (pending sources propagate the origin node, so this covers any depth).
|
|
43
43
|
// Also guards branch-local recovery: another dependency may still need the source.
|
|
44
44
|
function retryReaches(e, t) {
|
|
45
|
-
for (let n = e.
|
|
45
|
+
for (let n = e.p; n; n = n._) {
|
|
46
46
|
const e = n.I;
|
|
47
47
|
if (e === t || e.m?.Se?.has(t)) return true;
|
|
48
48
|
}
|
|
@@ -56,32 +56,32 @@ function retryReaches(e, t) {
|
|
|
56
56
|
* with NO read-visible pending status and no downstream propagation. Commit
|
|
57
57
|
* #0 keeps serving.
|
|
58
58
|
*/ function parkLoadingWindow(e, t) {
|
|
59
|
-
ext(e).
|
|
59
|
+
ext(e).de = true;
|
|
60
60
|
if (t.source) addPendingSource(e, t.source);
|
|
61
61
|
// A settled error is the node's answer ("the error stays the answer until
|
|
62
62
|
// this retry can actually run") — the park must not replace it: reads
|
|
63
63
|
// throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
|
|
64
64
|
// a pending-class NotReadyError from a read-invisible park (#2989).
|
|
65
|
-
if (!(e.
|
|
65
|
+
if (!(e.S & STATUS_ERROR)) setPendingError(e, t.source, t);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function setPendingError(e, t, n) {
|
|
69
69
|
if (!t) {
|
|
70
|
-
if (e.m !== null) e.m.
|
|
70
|
+
if (e.m !== null) e.m.F = null;
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
if (n instanceof NotReadyError && n.source === t) {
|
|
74
|
-
ext(e).
|
|
74
|
+
ext(e).F = n;
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
const r = e.m?.
|
|
77
|
+
const r = e.m?.F;
|
|
78
78
|
if (!(r instanceof NotReadyError) || r.source !== t) {
|
|
79
|
-
ext(e).
|
|
79
|
+
ext(e).F = new NotReadyError(t);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
function forEachDependent(e, t) {
|
|
84
|
-
for (let n = e.t; n !== null; n = n.
|
|
84
|
+
for (let n = e.t; n !== null; n = n.o) t(n.l, n);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
@@ -95,7 +95,7 @@ function forEachDependent(e, t) {
|
|
|
95
95
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
96
96
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
97
97
|
function releaseIfSettledUnobserved(e) {
|
|
98
|
-
e.
|
|
98
|
+
e.ee && e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.R & REACTIVE_ZOMBIE) && !(e.S & STATUS_PENDING) && unobserved(e);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -108,7 +108,7 @@ function releaseSettledDependents(e) {
|
|
|
108
108
|
const visit = e => {
|
|
109
109
|
if (n.has(e)) return;
|
|
110
110
|
n.add(e);
|
|
111
|
-
if (!e.t && e.
|
|
111
|
+
if (!e.t && e.i & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
|
|
112
112
|
forEachDependent(e, visit);
|
|
113
113
|
};
|
|
114
114
|
forEachDependent(e, visit);
|
|
@@ -136,7 +136,7 @@ function settleErroredDependents(e, t) {
|
|
|
136
136
|
const visit = e => {
|
|
137
137
|
if (r.has(e)) return;
|
|
138
138
|
r.add(e);
|
|
139
|
-
if (e.m?.
|
|
139
|
+
if (e.m?.F === t) {
|
|
140
140
|
enqueueSub(e);
|
|
141
141
|
n = true;
|
|
142
142
|
}
|
|
@@ -171,35 +171,35 @@ function settlePendingSource(e, t = e) {
|
|
|
171
171
|
// when the source went pending, `propagateStatus`), and a landing
|
|
172
172
|
// equal to the committed value notifies nobody — the source settling
|
|
173
173
|
// is its verdict changing: it runs again.
|
|
174
|
-
return f.
|
|
174
|
+
return f.i & CONFIG_VERDICT && enqueueSub(f);
|
|
175
175
|
o.add(f);
|
|
176
|
-
f.
|
|
176
|
+
f.Ie = clock;
|
|
177
177
|
const u = f.m?.Se?.values().next().value;
|
|
178
178
|
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
179
179
|
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
180
180
|
// otherwise): the settled error stays the answer through the settle —
|
|
181
181
|
// nulling it here would have reads throw `null` until the re-enqueued
|
|
182
182
|
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
183
|
-
const i = f.
|
|
183
|
+
const i = f.S & STATUS_ERROR;
|
|
184
184
|
if (u) {
|
|
185
185
|
if (!i) setPendingError(f, u);
|
|
186
186
|
} else {
|
|
187
|
-
f.
|
|
187
|
+
f.S &= ~STATUS_PENDING;
|
|
188
188
|
if (!i) setPendingError(f);
|
|
189
189
|
// L2: a landing resumes the transaction waiting on it (maintainer: "it
|
|
190
190
|
// resumes the sync frame") — a held reader's re-pass over the landed
|
|
191
191
|
// value is that transaction's work, and the flush that carries it
|
|
192
192
|
// parks into it.
|
|
193
|
-
if (f.
|
|
194
|
-
if (f.m?.
|
|
193
|
+
if (f.i & CONFIG_HELD) joinFuture(txOf(f));
|
|
194
|
+
if (f.m?.de) {
|
|
195
195
|
enqueueSub(f);
|
|
196
196
|
n = true;
|
|
197
197
|
}
|
|
198
|
-
if (f.m !== null) f.m.
|
|
198
|
+
if (f.m !== null) f.m.de = false;
|
|
199
199
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
200
200
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
201
201
|
// lists this walk is still iterating.
|
|
202
|
-
if (!f.t && f.
|
|
202
|
+
if (!f.t && f.i & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
|
|
203
203
|
}
|
|
204
204
|
forEachDependent(f, settle);
|
|
205
205
|
};
|
|
@@ -216,9 +216,9 @@ function isThenable(e) {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
|
|
219
|
-
const t = e.m?.
|
|
219
|
+
const t = e.m?.Ne;
|
|
220
220
|
if (t != null) {
|
|
221
|
-
e.m.
|
|
221
|
+
e.m.Ne = null;
|
|
222
222
|
t();
|
|
223
223
|
}
|
|
224
224
|
}
|
|
@@ -238,9 +238,9 @@ r) {
|
|
|
238
238
|
});
|
|
239
239
|
}
|
|
240
240
|
if (!f && !o) {
|
|
241
|
-
if (e.m !== null) e.m.
|
|
241
|
+
if (e.m !== null) e.m.Te = null;
|
|
242
242
|
// A sync landing is the first real answer for a loadingValue node.
|
|
243
|
-
e.
|
|
243
|
+
e.De = false;
|
|
244
244
|
return t;
|
|
245
245
|
}
|
|
246
246
|
// Flight replacement relies on recompute's supersede release for iterator
|
|
@@ -248,10 +248,10 @@ r) {
|
|
|
248
248
|
// self-registration — runs during a recompute of `el`, which has already
|
|
249
249
|
// fired _flightTeardown. A future non-recompute registration path must
|
|
250
250
|
// release it here before overwriting _inFlight.
|
|
251
|
-
ext(e).
|
|
251
|
+
ext(e).Te = t;
|
|
252
252
|
// The question this flight answers (A18 provenance, lanes.ts): the action
|
|
253
253
|
// whose slice asked it; mainline is always the current question.
|
|
254
|
-
e.m.
|
|
254
|
+
e.m._e = question || MAINLINE_QUESTION;
|
|
255
255
|
// The run that asked this flight read every input without throwing: an
|
|
256
256
|
// input still in flight was masked for it (an active override, A17), so
|
|
257
257
|
// pending state those inputs propagated onto the node earlier does not
|
|
@@ -261,17 +261,17 @@ r) {
|
|
|
261
261
|
e.m.Se = undefined;
|
|
262
262
|
let u;
|
|
263
263
|
const handleError = n => {
|
|
264
|
-
if (e.m?.
|
|
264
|
+
if (e.m?.Te !== t) return;
|
|
265
265
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
266
266
|
let o = n instanceof NotReadyError;
|
|
267
|
-
if (o && e.
|
|
267
|
+
if (o && e.De) {
|
|
268
268
|
// Loading window: the flight died waiting on an unready source. Keep
|
|
269
269
|
// serving commit #0 — same parking as recompute's catch for sync
|
|
270
270
|
// dependency throws. The dead flight is released so the clock-gated
|
|
271
271
|
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
272
|
-
if (e.m !== null) e.m.
|
|
272
|
+
if (e.m !== null) e.m.Te = null;
|
|
273
273
|
parkLoadingWindow(e, n);
|
|
274
|
-
e.
|
|
274
|
+
e.Ie = clock;
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
277
|
notifyStatus(e, o ? STATUS_PENDING : STATUS_ERROR, n);
|
|
@@ -279,7 +279,7 @@ r) {
|
|
|
279
279
|
// rejected flight will never settle its self entry, so transfer ownership
|
|
280
280
|
// after notifyStatus has propagated the replacement source.
|
|
281
281
|
if (o) settlePendingSource(e);
|
|
282
|
-
e.
|
|
282
|
+
e.Ie = clock;
|
|
283
283
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
284
284
|
// cleared their pending sources), so stranded lazy ones release here —
|
|
285
285
|
// the error twin of settlePendingSource's release (#2934).
|
|
@@ -287,12 +287,12 @@ r) {
|
|
|
287
287
|
r?.(n, o);
|
|
288
288
|
};
|
|
289
289
|
const asyncWrite = (r, o) => {
|
|
290
|
-
if (e.m?.
|
|
290
|
+
if (e.m?.Te !== t) return;
|
|
291
291
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
292
292
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
293
293
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
294
294
|
if (e.R & REACTIVE_DIRTY) return;
|
|
295
|
-
const f = !!(e.
|
|
295
|
+
const f = !!(e.S & STATUS_UNINITIALIZED);
|
|
296
296
|
landStatus(e);
|
|
297
297
|
if (n) {
|
|
298
298
|
try {
|
|
@@ -305,11 +305,8 @@ r) {
|
|
|
305
305
|
} else {
|
|
306
306
|
// CARVE 2: the override-covered landing (hold + A18 supersession) and the
|
|
307
307
|
// lane-routed landing (derived override, lane effect queue) went with
|
|
308
|
-
// the optimistic engine; every landing is the plain setSignal. A
|
|
309
|
-
//
|
|
310
|
-
let t = e.m.Re;
|
|
311
|
-
e.m.Re = null;
|
|
312
|
-
if (f && t && (t = liveTx(t))) holdNode(e, t);
|
|
308
|
+
// the optimistic engine; every landing is the plain setSignal. A node
|
|
309
|
+
// already held stages its answer into that hold (`setSignal`).
|
|
313
310
|
try {
|
|
314
311
|
setSignal(e, () => r);
|
|
315
312
|
} catch (t) {
|
|
@@ -323,8 +320,8 @@ r) {
|
|
|
323
320
|
// (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
|
|
324
321
|
// the window when the flush commits it, so no one-frame pulse can leak to
|
|
325
322
|
// observers between the landing and its commit (#2990).
|
|
326
|
-
if (e.
|
|
327
|
-
e.
|
|
323
|
+
if (e.Oe === NOT_PENDING) {
|
|
324
|
+
e.De = false;
|
|
328
325
|
// The landing published: the dependency tail the flight's pass left
|
|
329
326
|
// linked goes now (A30, #3410). A staged landing has not replaced the
|
|
330
327
|
// committed frame yet; `commitPendingNode` trims it.
|
|
@@ -343,7 +340,7 @@ r) {
|
|
|
343
340
|
// Returns whether the node released, so the iterator branch can stop
|
|
344
341
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
345
342
|
const settleAutodispose = () => {
|
|
346
|
-
if (e.
|
|
343
|
+
if (e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.S & STATUS_PENDING)) {
|
|
347
344
|
unobserved(e);
|
|
348
345
|
return true;
|
|
349
346
|
}
|
|
@@ -377,7 +374,7 @@ r) {
|
|
|
377
374
|
// Flight-identity cancellation (#3122): the registration above is the
|
|
378
375
|
// owner-death backstop; the teardown slot fires at the _inFlight release
|
|
379
376
|
// sites so supersede stops this stream immediately.
|
|
380
|
-
ext(e).
|
|
377
|
+
ext(e).Ne = close;
|
|
381
378
|
// Release check before each next pull: an unobserved lazy node must tear
|
|
382
379
|
// down (its close above runs via disposal, closing the iterator) instead
|
|
383
380
|
// of pumping the stream forever with zero subscribers (#2935).
|
|
@@ -392,10 +389,10 @@ r) {
|
|
|
392
389
|
// buffered (seroval's deserialized streams do), so a bare result is
|
|
393
390
|
// assimilated as an already-settled step instead of crashing on `.then`.
|
|
394
391
|
const S = o.next();
|
|
395
|
-
const
|
|
392
|
+
const E = isThenable(S) ? S : {
|
|
396
393
|
then: e => void e(S)
|
|
397
394
|
};
|
|
398
|
-
|
|
395
|
+
E.then(r => {
|
|
399
396
|
// The sync stash only serves the INITIAL drain (handleAsync's caller
|
|
400
397
|
// consumes syncValue / throws NotReady from it). A sync-settled step
|
|
401
398
|
// after an async gap — seroval buffering values between pulls, a
|
|
@@ -407,7 +404,7 @@ r) {
|
|
|
407
404
|
n = r;
|
|
408
405
|
l = true;
|
|
409
406
|
if (r.done) i = true;
|
|
410
|
-
} else if (e.m?.
|
|
407
|
+
} else if (e.m?.Te !== t) {
|
|
411
408
|
return;
|
|
412
409
|
} else if (!r.done) {
|
|
413
410
|
f = true;
|
|
@@ -427,7 +424,7 @@ r) {
|
|
|
427
424
|
if (c && s) {
|
|
428
425
|
r = n;
|
|
429
426
|
a = true;
|
|
430
|
-
} else if (e.m?.
|
|
427
|
+
} else if (e.m?.Te === t) {
|
|
431
428
|
i = true;
|
|
432
429
|
handleError(n);
|
|
433
430
|
settleAutodispose();
|
|
@@ -483,13 +480,13 @@ r) {
|
|
|
483
480
|
// have put it. Only a flight that actually flattens becomes
|
|
484
481
|
// disposal-bearing.
|
|
485
482
|
const registerDeferredClose = t => {
|
|
486
|
-
if (!e.
|
|
483
|
+
if (!e.Re) e.Re = t; else if (Array.isArray(e.Re)) e.Re.push(t); else e.Re = [ e.Re, t ];
|
|
487
484
|
};
|
|
488
485
|
t.then(r => {
|
|
489
486
|
if (f) {
|
|
490
487
|
u = r;
|
|
491
488
|
n = true;
|
|
492
|
-
} else if (e.m?.
|
|
489
|
+
} else if (e.m?.Te === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
|
|
493
490
|
asyncWrite(r);
|
|
494
491
|
settleAutodispose();
|
|
495
492
|
}
|
|
@@ -514,11 +511,11 @@ r) {
|
|
|
514
511
|
// work on a loadingValue node is loading-class (invisible to
|
|
515
512
|
// boundaries); the flight itself is already registered in _inFlight and
|
|
516
513
|
// lands through asyncWrite.
|
|
517
|
-
if (e.
|
|
514
|
+
if (e.De) return e.Ae;
|
|
518
515
|
throw new NotReadyError(context);
|
|
519
516
|
} else if (!flattenIfIterable(u)) {
|
|
520
517
|
// Synchronously-resolved promise: the first real answer landed.
|
|
521
|
-
e.
|
|
518
|
+
e.De = false;
|
|
522
519
|
}
|
|
523
520
|
// A sync-resolved promise holding an AsyncIterable flattened LIVE (we
|
|
524
521
|
// are still inside the synchronous read): full initial-drain semantics
|
|
@@ -528,21 +525,21 @@ r) {
|
|
|
528
525
|
if (i !== null) {
|
|
529
526
|
if (!i) {
|
|
530
527
|
// Loading window: serve commit #0 (see the promise branch above).
|
|
531
|
-
if (e.
|
|
528
|
+
if (e.De) return e.Ae;
|
|
532
529
|
throw new NotReadyError(context);
|
|
533
530
|
}
|
|
534
531
|
// A sync first yield (or immediate empty completion) is the first real
|
|
535
532
|
// answer; async yields clear inside asyncWrite.
|
|
536
|
-
e.
|
|
533
|
+
e.De = false;
|
|
537
534
|
}
|
|
538
535
|
return u;
|
|
539
536
|
}
|
|
540
537
|
|
|
541
538
|
function clearStatus(e, t = false) {
|
|
542
539
|
if (e.m?.Se) clearPendingSources(e);
|
|
543
|
-
if (e.m?.
|
|
544
|
-
e.
|
|
545
|
-
if (e.m?.
|
|
540
|
+
if (e.m?.de) if (e.m !== null) e.m.de = false;
|
|
541
|
+
e.S = t ? 0 : e.S & STATUS_UNINITIALIZED;
|
|
542
|
+
if (e.m?.F) setPendingError(e);
|
|
546
543
|
const n = statusNotifierOf(e);
|
|
547
544
|
if (n) n.call(e);
|
|
548
545
|
}
|
|
@@ -575,8 +572,8 @@ function clearStatus(e, t = false) {
|
|
|
575
572
|
const n = e.m?.Se;
|
|
576
573
|
// (The full clear below drops the set whether or not self was retired first.)
|
|
577
574
|
if (n && (n.delete(e), n.size)) {
|
|
578
|
-
e.m.
|
|
579
|
-
if (t) e.
|
|
575
|
+
e.m.de = false;
|
|
576
|
+
if (t) e.S = STATUS_PENDING;
|
|
580
577
|
setPendingError(e, n.values().next().value);
|
|
581
578
|
} else clearStatus(e, t);
|
|
582
579
|
}
|
|
@@ -589,14 +586,14 @@ function notifyStatus(e, t, n, r) {
|
|
|
589
586
|
{
|
|
590
587
|
if (t === STATUS_PENDING && o) {
|
|
591
588
|
addPendingSource(e, o);
|
|
592
|
-
e.
|
|
589
|
+
e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
|
|
593
590
|
// Preserve the current source on this propagation so readers park on
|
|
594
591
|
// the distinct pending source.
|
|
595
592
|
setPendingError(e, o, n);
|
|
596
593
|
} else {
|
|
597
594
|
clearPendingSources(e);
|
|
598
|
-
e.
|
|
599
|
-
ext(e).
|
|
595
|
+
e.S = t | (t !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
|
|
596
|
+
ext(e).F = n;
|
|
600
597
|
}
|
|
601
598
|
}
|
|
602
599
|
// Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
|
|
@@ -605,7 +602,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
605
602
|
// transition's to wait on — the frame it was asked in holds (A17: "a
|
|
606
603
|
// transition whose optimistic node is still pending on its own fetch is
|
|
607
604
|
// not complete"), through the node itself (`blocked`).
|
|
608
|
-
if (t === STATUS_PENDING && e.
|
|
605
|
+
if (t === STATUS_PENDING && e.i & CONFIG_GUESS) {
|
|
609
606
|
if (passLane === null) joinFuture(null);
|
|
610
607
|
return;
|
|
611
608
|
}
|
|
@@ -626,7 +623,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
626
623
|
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
|
|
627
624
|
const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
|
|
628
625
|
forEachDependent(e, (r, f) => {
|
|
629
|
-
r.
|
|
626
|
+
r.Ie = clock;
|
|
630
627
|
// A pending mark on a kept-tail link re-derives the subscriber instead of
|
|
631
628
|
// marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
|
|
632
629
|
// Past `_depsTail` lie the committed frame's deps, kept by A30 because
|
|
@@ -646,7 +643,7 @@ function notifyStatus(e, t, n, r) {
|
|
|
646
643
|
// Inheriting the error would make a probe's reader errored. A boundary's
|
|
647
644
|
// output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
|
|
648
645
|
// is its pass's call.
|
|
649
|
-
if (r.
|
|
646
|
+
if (r.i & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Pe !== r.pe) {
|
|
650
647
|
enqueueSub(r);
|
|
651
648
|
schedule();
|
|
652
649
|
return;
|
|
@@ -659,24 +656,24 @@ function notifyStatus(e, t, n, r) {
|
|
|
659
656
|
// shape: the unmount it stages makes the observer a zombie whose say is
|
|
660
657
|
// moot for this transaction, A15 #3463).
|
|
661
658
|
if (t === STATUS_PENDING && o && r.m?.Se?.has(o)) {
|
|
662
|
-
if (passLane === null && (r.
|
|
659
|
+
if (passLane === null && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.X) joinFuture(txOf(r));
|
|
663
660
|
return;
|
|
664
661
|
}
|
|
665
|
-
if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.
|
|
662
|
+
if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.F !== n || r.m?.Se)) {
|
|
666
663
|
// The marked subscriber is queued for the commit sweep so its status
|
|
667
664
|
// bookkeeping (loading window, uninitialized clear) runs with the flush
|
|
668
665
|
// — with the lane, when the pass propagating is the lane's work and
|
|
669
666
|
// the dependent's pending is the lane's own flight (`laneStage`).
|
|
670
667
|
{
|
|
671
668
|
// (No answer: a pending propagation leaves a written guess a guess.)
|
|
672
|
-
if (passLane !== null) GlobalQueue.
|
|
669
|
+
if (passLane !== null) GlobalQueue.W(r, passLane, true, e); else {
|
|
673
670
|
queuePendingNode(r);
|
|
674
671
|
// A15 (#3443): pending propagates onto a held memo without
|
|
675
672
|
// recomputing it, and the propagation itself enters the memo's
|
|
676
673
|
// transaction — the flight flows into a memo that transaction
|
|
677
674
|
// holds, so the write that started it is held with it. A render
|
|
678
675
|
// effect's membership is its pass's (`notify`), never sticky.
|
|
679
|
-
if (t === STATUS_PENDING && (r.
|
|
676
|
+
if (t === STATUS_PENDING && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.u) joinFuture(txOf(r));
|
|
680
677
|
}
|
|
681
678
|
}
|
|
682
679
|
notifyStatus(r, t, n);
|
|
@@ -97,7 +97,7 @@ const CONFIG_SYNC = 1 << 6;
|
|
|
97
97
|
// CONFIG_HELD_CHILDREN, CONFIG_INPUTS_PUBLISHED and CONFIG_ADOPTED_UNFLUSHED
|
|
98
98
|
// (transaction holds, zombies, until()'s authoritative view) went with the
|
|
99
99
|
// transactions.
|
|
100
|
-
// L2 (step 2):
|
|
100
|
+
// L2 (step 2): four bits, all maintained by the node's commit.
|
|
101
101
|
/** The node has a pass awaiting commit: its live children (and `_disposal`)
|
|
102
102
|
* are that pass's and were never shown — a re-pass tears them down on the
|
|
103
103
|
* spot, while the frame parked on `_x._pendingFirstChild` keeps waiting for
|
|
@@ -110,6 +110,11 @@ const CONFIG_SYNC = 1 << 6;
|
|
|
110
110
|
* parking flush they see the committed value and hold nothing, and are
|
|
111
111
|
* re-derived at the landing. Set at the park seam on every staged node. */ const CONFIG_HELD = 1 << 8;
|
|
112
112
|
|
|
113
|
+
/** A member of the uncommitted frame a held pass built (ruling A): set at
|
|
114
|
+
* the park seam on every computed under a staged node (`holdFrame`). Never
|
|
115
|
+
* shown, it has no screen: its reads are its transaction's, whichever flush
|
|
116
|
+
* runs it (`bornInto`, #4010). Cleared by its commit. */ const CONFIG_HELD_FRAME = 1 << 20;
|
|
117
|
+
|
|
113
118
|
/** A15's reveal corollary (#3305): a commit published this flight's inputs
|
|
114
119
|
* beneath it — the node was pending, nothing staged, when it committed — so
|
|
115
120
|
* its committed value is torn against the visible frame. A render effect
|
|
@@ -209,4 +214,4 @@ const defaultContext = {};
|
|
|
209
214
|
* @internal
|
|
210
215
|
*/ const $REFRESH = Symbol("refresh");
|
|
211
216
|
|
|
212
|
-
export { $REFRESH, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, 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_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
|
|
217
|
+
export { $REFRESH, 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_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, 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_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
|
|
@@ -30,7 +30,7 @@ import { getOwner } from "./owner.js";
|
|
|
30
30
|
throw new NoOwnerError;
|
|
31
31
|
}
|
|
32
32
|
// `undefined` alone means unset — a provided `null` is a value (no `??`).
|
|
33
|
-
let r = t.
|
|
33
|
+
let r = t.D[e.id];
|
|
34
34
|
if (r === undefined) r = e.defaultValue;
|
|
35
35
|
if (r === undefined) {
|
|
36
36
|
throw new ContextNotFoundError;
|
|
@@ -52,8 +52,8 @@ import { getOwner } from "./owner.js";
|
|
|
52
52
|
}
|
|
53
53
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
54
54
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
55
|
-
r.
|
|
56
|
-
...r.
|
|
55
|
+
r.D = {
|
|
56
|
+
...r.D,
|
|
57
57
|
[e.id]: t === undefined ? e.defaultValue : t
|
|
58
58
|
};
|
|
59
59
|
}
|