@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
|
@@ -228,4 +228,6 @@ const defaultContext = {};
|
|
|
228
228
|
* @internal
|
|
229
229
|
*/ const $REFRESH = Symbol("refresh");
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
const NewSet = Set;
|
|
232
|
+
|
|
233
|
+
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_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;
|
package/dist/prod/core/core.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { notifyStatus, releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, stageError, settlePendingSource, releaseIfSettledUnobserved, settleErroredDependents } from "./async.js";
|
|
2
2
|
|
|
3
|
-
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED, CONFIG_STAGED_ERROR, REACTIVE_ZOMBIE, REACTIVE_MISSED_WAKE, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_PROBED, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_SCREEN_READ, REACTIVE_PROBE_UNANSWERED, CAUGHT_REARMED, CONFIG_PROMOTED, CONFIG_INPUTS_PUBLISHED, CONFIG_FRESH_READ, REACTIVE_IN_HEAP_HEIGHT, CONFIG_SLOT_NODE, EFFECT_USER, STATUS_NONE } from "./constants.js";
|
|
3
|
+
import { STATUS_UNINITIALIZED, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, REACTIVE_MANUAL_WRITE, STATUS_ERROR, REACTIVE_DIRTY, CONFIG_OVERRIDE, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_SNAPSHOT_STALE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_VERDICT, STATUS_PENDING, REACTIVE_LANE_DIRTY, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_LAGS, EFFECT_RENDER, CONFIG_HELD_FRAME, EFFECT_TRACKED, CONFIG_STAGED, CONFIG_STAGED_ERROR, REACTIVE_ZOMBIE, REACTIVE_MISSED_WAKE, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_PROBED, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_SCREEN_READ, REACTIVE_PROBE_UNANSWERED, CAUGHT_REARMED, CONFIG_PROMOTED, CONFIG_INPUTS_PUBLISHED, CONFIG_FRESH_READ, REACTIVE_IN_HEAP_HEIGHT, CONFIG_SLOT_NODE, EFFECT_USER, NewSet, STATUS_NONE } from "./constants.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ import { insertIntoHeap, deleteFromHeap, insertIntoHeapHeight, enqueueSub, markN
|
|
|
10
10
|
|
|
11
11
|
import { inheritId, linkChild, disposeChildren, markDisposal } from "./owner.js";
|
|
12
12
|
|
|
13
|
-
import { schedule, externalUntrackHook, clock, txOf, flushTransaction, laneWriteHook, joinFuture, queuePendingNode, globalQueue, notifyEpoch, insertSubs, dirtyQueue, observeFlightHook,
|
|
13
|
+
import { schedule, externalUntrackHook, clock, txOf, flushTransaction, laneWriteHook, joinFuture, queuePendingNode, globalQueue, notifyEpoch, insertSubs, dirtyQueue, observeFlightHook, laneStageHook, passLane, laneReadHook, wireExternalSourceHook, bumpNotifyEpoch, setPassLane, joinPassTx, freshHook, GlobalQueue, laneOutcomeHook, passTx, holdNode, laneDirty, heldTrim, staleReader, laneSeamsHook, stagedReaders, deferZombie } from "./scheduler.js";
|
|
14
14
|
|
|
15
15
|
// The heap's per-node step. A tracked effect's heap visit is its compute
|
|
16
16
|
// phase — empty, like a user effect whose compute reads nothing — and hands
|
|
@@ -78,7 +78,7 @@ function ownerInSnapshotScope(e) {
|
|
|
78
78
|
|
|
79
79
|
function setSnapshotCapture(e) {
|
|
80
80
|
snapshotCaptureActive = e;
|
|
81
|
-
if (e && !snapshotSources) snapshotSources = new
|
|
81
|
+
if (e && !snapshotSources) snapshotSources = new NewSet;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function markSnapshotScope(e) {
|
|
@@ -199,7 +199,7 @@ function recompute(e, t = false) {
|
|
|
199
199
|
// after the new frame's first runs, and the held pass's own
|
|
200
200
|
// children die below (`disposeChildren`). The landing re-derives a
|
|
201
201
|
// fresh held frame for the reveal (`_reruns`).
|
|
202
|
-
e.
|
|
202
|
+
e.ue = NOT_PENDING;
|
|
203
203
|
if (n === EFFECT_RENDER) e.l &= ~CONFIG_HELD;
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -210,7 +210,9 @@ function recompute(e, t = false) {
|
|
|
210
210
|
// and own nothing to park.
|
|
211
211
|
if (n === EFFECT_TRACKED || e.l & CONFIG_STAGED) {
|
|
212
212
|
// A lazy node only those children read is released when this pass
|
|
213
|
-
// ends, if the pass doesn't read it again (#4142).
|
|
213
|
+
// ends, if the pass doesn't read it again (#4142). A cleanup or
|
|
214
|
+
// `unobserved` hook that throws here neither stops the pass nor skips
|
|
215
|
+
// that drain: its error is rethrown when the flush ends (owner.ts).
|
|
214
216
|
const t = deferredReleases;
|
|
215
217
|
deferReleases(o = []);
|
|
216
218
|
disposeChildren(e);
|
|
@@ -219,7 +221,7 @@ function recompute(e, t = false) {
|
|
|
219
221
|
// An error a pass staged (D-41) is replaced by this pass's answer: a
|
|
220
222
|
// value, a flight, or an error of its own (#4109, #4145).
|
|
221
223
|
if (e.l & CONFIG_STAGED_ERROR) {
|
|
222
|
-
e.
|
|
224
|
+
e.ue = NOT_PENDING;
|
|
223
225
|
e.l ^= CONFIG_STAGED_ERROR;
|
|
224
226
|
}
|
|
225
227
|
}
|
|
@@ -255,7 +257,7 @@ function recompute(e, t = false) {
|
|
|
255
257
|
e.ie = clock;
|
|
256
258
|
// The pass's previous value: its staging, else a lane node's lane value
|
|
257
259
|
// when it has one (lanes.ts), else the committed one.
|
|
258
|
-
let T = e.
|
|
260
|
+
let T = e.ue !== NOT_PENDING ? e.ue : e.l & CONFIG_OVERRIDE && e.T.v !== NOT_PENDING ? e.T.v : e.Ie;
|
|
259
261
|
let S = e.Fe;
|
|
260
262
|
let c = false;
|
|
261
263
|
// L2: did this pass read the future (REACTIVE_JOINED, set by read) — or,
|
|
@@ -305,7 +307,7 @@ function recompute(e, t = false) {
|
|
|
305
307
|
// D-41: a pass of a held node, or one that read a staging of this
|
|
306
308
|
// flush, stages its error (`stageError`).
|
|
307
309
|
if (n || !(I = stageError(e, t, true))) {
|
|
308
|
-
if (n) ext(e).
|
|
310
|
+
if (n) ext(e).se = true;
|
|
309
311
|
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t);
|
|
310
312
|
// The replacement source is fully propagated now. If no new flight
|
|
311
313
|
// re-owned self, retire the superseded flight and its dependent copies.
|
|
@@ -331,7 +333,10 @@ function recompute(e, t = false) {
|
|
|
331
333
|
// (markNode(c) in read()) marks the running node as part of ordinary
|
|
332
334
|
// bookkeeping, and those marks are correctly discarded here.
|
|
333
335
|
c = (e.R & REACTIVE_MISSED_WAKE) !== 0;
|
|
334
|
-
A
|
|
336
|
+
// A mount's staged read joins it — except a nested derivation left
|
|
337
|
+
// pending: no render effect reaches it yet, so it holds nothing and
|
|
338
|
+
// reaches no boundary (Reader, #4203). A reader that does is caught.
|
|
339
|
+
A = !!(e.R & (i && (E || n || !(e.m & STATUS_PENDING)) ? REACTIVE_JOINED | REACTIVE_STAGED_READ : REACTIVE_JOINED));
|
|
335
340
|
// A verdict reader is one for as long as it probes, or reads a memo
|
|
336
341
|
// that does (`read`): a pass that did neither (REACTIVE_PROBED, the same
|
|
337
342
|
// bit) is an ordinary derivation again.
|
|
@@ -385,7 +390,7 @@ function recompute(e, t = false) {
|
|
|
385
390
|
// publishes to — the staged `_pendingValue` when staged; a lane node's
|
|
386
391
|
// lane value (a node entering the lane this pass has none yet — its
|
|
387
392
|
// committed value, `laneStage` having voided a frame staging).
|
|
388
|
-
const o = e.
|
|
393
|
+
const o = e.ue !== NOT_PENDING ? e.ue : e.l & CONFIG_OVERRIDE && e.T.v !== NOT_PENDING ? e.T.v : e.Ie;
|
|
389
394
|
// A throwing comparator is contained inside `isSame` (A3, #2837; #4111).
|
|
390
395
|
const E = !n && l || !!e.T?.de || !isSame(e, o, T);
|
|
391
396
|
// Effects use `_equals: false` (no per-effect closure). The side effects that
|
|
@@ -398,7 +403,7 @@ function recompute(e, t = false) {
|
|
|
398
403
|
// last applied owes no run (lanes.ts).
|
|
399
404
|
!(e.R & REACTIVE_SCREEN_READ && !e.Ae && Object.is(e.ge, T)) &&
|
|
400
405
|
// A re-staging pass owes no run: the commit replays the effect (#3802).
|
|
401
|
-
e.
|
|
406
|
+
e.ue === NOT_PENDING) {
|
|
402
407
|
e.Ae = !e.T?.F;
|
|
403
408
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
404
409
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
@@ -437,8 +442,8 @@ function recompute(e, t = false) {
|
|
|
437
442
|
// effect's value slot is private: the run the lane holds is what
|
|
438
443
|
// shows it — unless the effect was born held, whose first run is the
|
|
439
444
|
// commit's (A29): it re-stages, as below.
|
|
440
|
-
if (n && e.
|
|
441
|
-
} else if (t ? !((flushTransaction !== null || passTx !== null) && (A || creatorPass(f)?.R & REACTIVE_JOINED)) : n && e.
|
|
445
|
+
if (n && e.ue === NOT_PENDING) e.Ie = T; else if (n || C.ke) e.ue = T; else e.T.v = T;
|
|
446
|
+
} else if (t ? !((flushTransaction !== null || passTx !== null) && (A || creatorPass(f)?.R & REACTIVE_JOINED)) : n && e.ue === NOT_PENDING) {
|
|
442
447
|
// A first pass publishes directly. So does an effect: its value slot
|
|
443
448
|
// is private (only its own run reads it), and the staging round-trip
|
|
444
449
|
// (queuePendingNode + commitPendingNodes) paid per effect on the
|
|
@@ -451,7 +456,7 @@ function recompute(e, t = false) {
|
|
|
451
456
|
// that separation; it cannot be skipped on any path a pull can reach.
|
|
452
457
|
e.Ie = T;
|
|
453
458
|
} else {
|
|
454
|
-
e.
|
|
459
|
+
e.ue = T;
|
|
455
460
|
// Born held: in the transaction from birth, so a read of it this
|
|
456
461
|
// tick is a read of its world (the mount-during-a-hold case), not
|
|
457
462
|
// only after the seam parks it.
|
|
@@ -527,7 +532,7 @@ function recompute(e, t = false) {
|
|
|
527
532
|
// kept at a park — one spurious recompute at most). A creation pass and a
|
|
528
533
|
// tracked effect trim now: their frames are replaceable like a direct
|
|
529
534
|
// commit, and a tracked effect's spurious run would be user-visible.
|
|
530
|
-
if (!e.T?.F && e.
|
|
535
|
+
if (!e.T?.F && e.ue === NOT_PENDING && !(n && e.Ae)) {
|
|
531
536
|
if (t || n === EFFECT_TRACKED) trimStaleDeps(e); else heldTrim(e);
|
|
532
537
|
}
|
|
533
538
|
// A staged value, a parked frame (L2: the commit retires it), or status the
|
|
@@ -535,7 +540,7 @@ function recompute(e, t = false) {
|
|
|
535
540
|
// node for this flush's commit. A first pass queues only when pending or
|
|
536
541
|
// born held: otherwise its value published directly. A queued pass's
|
|
537
542
|
// children are uncommitted (CONFIG_STAGED) until that commit.
|
|
538
|
-
if (e.
|
|
543
|
+
if (e.ue !== NOT_PENDING || e.T !== null && (e.T.Ue !== null || e.T.me !== null) || (e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0 && (!t || (e.m & STATUS_PENDING) !== 0)) {
|
|
539
544
|
e.l |= CONFIG_STAGED;
|
|
540
545
|
// Lane work is the lane's to reveal (its seam), not this flush's commit.
|
|
541
546
|
if (C === null) queuePendingNode(e);
|
|
@@ -624,7 +629,7 @@ function computed(e, t) {
|
|
|
624
629
|
// A loadingValue node is born committed: commit #0 is already in _value.
|
|
625
630
|
m: o ? 0 : STATUS_UNINITIALIZED,
|
|
626
631
|
ie: clock,
|
|
627
|
-
|
|
632
|
+
ue: NOT_PENDING,
|
|
628
633
|
Me: -1,
|
|
629
634
|
ce: o,
|
|
630
635
|
// Cold machinery (async slots) lives one hop away in the lazily-allocated extension — the core literal MUST
|
|
@@ -645,7 +650,7 @@ function computed(e, t) {
|
|
|
645
650
|
Se: null,
|
|
646
651
|
ae: null,
|
|
647
652
|
F: undefined,
|
|
648
|
-
|
|
653
|
+
se: undefined,
|
|
649
654
|
fe: undefined,
|
|
650
655
|
we: undefined,
|
|
651
656
|
Pe: undefined,
|
|
@@ -653,8 +658,8 @@ function computed(e, t) {
|
|
|
653
658
|
me: null,
|
|
654
659
|
Re: null,
|
|
655
660
|
Ve: false,
|
|
656
|
-
|
|
657
|
-
|
|
661
|
+
je: NOT_PENDING,
|
|
662
|
+
Be: -1,
|
|
658
663
|
Ee: 0,
|
|
659
664
|
v: NOT_PENDING,
|
|
660
665
|
I: 0,
|
|
@@ -682,6 +687,12 @@ function computed(e, t) {
|
|
|
682
687
|
if (t.m & STATUS_UNINITIALIZED || e.i !== EFFECT_RENDER) joinPassTx(txOf(t), !e.i && e.m & STATUS_UNINITIALIZED || freshHook?.(e));
|
|
683
688
|
}
|
|
684
689
|
|
|
690
|
+
/** `joinPass` into the hold `t` (a folded guess's: store/optimistic.ts
|
|
691
|
+
* `foldedRead`, D-34) — a reader is never a render effect there. */ function joinPassAt(e, t) {
|
|
692
|
+
e.R |= REACTIVE_JOINED;
|
|
693
|
+
joinPassTx(t, !e.i && e.m & STATUS_UNINITIALIZED || freshHook?.(e));
|
|
694
|
+
}
|
|
695
|
+
|
|
685
696
|
/** A15's stale reader (shared-hole and reveal corollaries): a render effect
|
|
686
697
|
* reading a node held by a transaction that is not the flush's. It is served
|
|
687
698
|
* the committed value — a pending one's too — publishes mainline, and is
|
|
@@ -739,7 +750,7 @@ function computed(e, t) {
|
|
|
739
750
|
|
|
740
751
|
/** The computed whose pass a creation under `owner` belongs to (a root's is
|
|
741
752
|
* its nearest computed ancestor's), or null outside every pass. */ function creatorPass(e) {
|
|
742
|
-
return e !== null && e.
|
|
753
|
+
return e !== null && e.Qe ? e.Ye : e;
|
|
743
754
|
}
|
|
744
755
|
|
|
745
756
|
/** L2 — park the previous pass's frame for this node's commit: the children
|
|
@@ -791,7 +802,7 @@ function computed(e, t) {
|
|
|
791
802
|
R: REACTIVE_LAZY,
|
|
792
803
|
m: STATUS_UNINITIALIZED,
|
|
793
804
|
ie: clock,
|
|
794
|
-
|
|
805
|
+
ue: NOT_PENDING,
|
|
795
806
|
Me: -1,
|
|
796
807
|
ce: false,
|
|
797
808
|
Ae: false,
|
|
@@ -828,7 +839,7 @@ function setEffectStatusNotify(e) {
|
|
|
828
839
|
* 0, and only effect literals carry the field) get the shared notifier.
|
|
829
840
|
* Presence doubles as the "display consumer" membership test in the status
|
|
830
841
|
* walks, exactly as the per-node field did when every effect carried one. */ function statusNotifierOf(e) {
|
|
831
|
-
return e.i ? effectStatusNotify
|
|
842
|
+
return e.i ? effectStatusNotify : null;
|
|
832
843
|
}
|
|
833
844
|
|
|
834
845
|
const lazyOptions = {
|
|
@@ -837,7 +848,7 @@ const lazyOptions = {
|
|
|
837
848
|
|
|
838
849
|
function setupComputedNode(e, t) {
|
|
839
850
|
e.We = e;
|
|
840
|
-
const n = context?.
|
|
851
|
+
const n = context?.Qe ? context.Ye : context;
|
|
841
852
|
if (context) linkChild(context, e);
|
|
842
853
|
if (n) e.Fe = n.Fe + 1;
|
|
843
854
|
wireExternalSourceHook?.(e);
|
|
@@ -863,7 +874,7 @@ function signal(e, t) {
|
|
|
863
874
|
o: null,
|
|
864
875
|
ve: null,
|
|
865
876
|
ie: clock,
|
|
866
|
-
|
|
877
|
+
ue: NOT_PENDING,
|
|
867
878
|
// Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
|
|
868
879
|
// materialize one signal per touched leaf, so signal bytes are store
|
|
869
880
|
// bytes. _time is write-only on signals (every read site is computed-
|
|
@@ -903,7 +914,7 @@ function isEqual(e, t) {
|
|
|
903
914
|
o: null,
|
|
904
915
|
ve: null,
|
|
905
916
|
ie: clock,
|
|
906
|
-
|
|
917
|
+
ue: NOT_PENDING,
|
|
907
918
|
Me: -1,
|
|
908
919
|
T: null,
|
|
909
920
|
O: n,
|
|
@@ -1033,7 +1044,7 @@ function setVerdict(e) {
|
|
|
1033
1044
|
* never the graph — A32).
|
|
1034
1045
|
* False means the reader derives from the staged value.
|
|
1035
1046
|
*/ function readerSeesCommitted(e, t) {
|
|
1036
|
-
return !t || e.
|
|
1047
|
+
return !t || e.ue === NOT_PENDING || t.l & CONFIG_CHILDREN_FORBIDDEN;
|
|
1037
1048
|
}
|
|
1038
1049
|
|
|
1039
1050
|
/** A28 — set when a node is staged (queuePendingNode) OUTSIDE a flush;
|
|
@@ -1054,11 +1065,11 @@ function markUnflushedStaged() {
|
|
|
1054
1065
|
* is unflushed. Exempt: promoted writes (A28 (4): a write issued inside a
|
|
1055
1066
|
* recompute is promoted at that recompute's end — boundary and loading
|
|
1056
1067
|
* machinery, signals declared for in-computation writes). */ function unflushedValue(e) {
|
|
1057
|
-
if (globalQueue.q || e.
|
|
1068
|
+
if (globalQueue.q || e.ue === NOT_PENDING || e.l & CONFIG_PROMOTED) return NOT_PENDING;
|
|
1058
1069
|
// A held node (L2) carries a staged value between flushes too, but it was
|
|
1059
1070
|
// flushed — and parked. Not an unflushed write — unless rewritten since:
|
|
1060
1071
|
// then the flushed staging is what the world sees until the next flush.
|
|
1061
|
-
if (e.l & CONFIG_HELD) return e.T.
|
|
1072
|
+
if (e.l & CONFIG_HELD) return e.T.Be === clock ? e.T.je : NOT_PENDING;
|
|
1062
1073
|
return e.Ie;
|
|
1063
1074
|
}
|
|
1064
1075
|
|
|
@@ -1066,9 +1077,9 @@ function markUnflushedStaged() {
|
|
|
1066
1077
|
* flush left (`_flushed`) until the flush that carries the rewrite — the
|
|
1067
1078
|
* stash is stamped with the clock, which that flush advances. */ function stashFlushed(e) {
|
|
1068
1079
|
const t = e.T;
|
|
1069
|
-
if (t.
|
|
1070
|
-
t.
|
|
1071
|
-
t.
|
|
1080
|
+
if (t.Be !== clock) {
|
|
1081
|
+
t.je = e.ue;
|
|
1082
|
+
t.Be = clock;
|
|
1072
1083
|
unflushedStaged = true;
|
|
1073
1084
|
}
|
|
1074
1085
|
}
|
|
@@ -1115,7 +1126,7 @@ function resyncUnflushedCompanions() {
|
|
|
1115
1126
|
|
|
1116
1127
|
function read(e) {
|
|
1117
1128
|
let t = context;
|
|
1118
|
-
if (t?.
|
|
1129
|
+
if (t?.Qe) t = t.Ye;
|
|
1119
1130
|
const n = e;
|
|
1120
1131
|
// CARVE 1: `owner` was `el._firewall || el` — a store leaf's status,
|
|
1121
1132
|
// height and error were read off its projection computed. (Typed loosely
|
|
@@ -1126,7 +1137,7 @@ function read(e) {
|
|
|
1126
1137
|
// The verdict windows (`latest`, `isPending`; verdict.ts): one cold path,
|
|
1127
1138
|
// off this one, present only while a window is open.
|
|
1128
1139
|
if (verdict !== null) return verdict(e, t);
|
|
1129
|
-
if (!n.X && e.T?.Pe === undefined && !snapshotCaptureActive && (!unflushedStaged || e.
|
|
1140
|
+
if (!n.X && e.T?.Pe === undefined && !snapshotCaptureActive && (!unflushedStaged || e.ue === NOT_PENDING) && // A28, see readNodeFast
|
|
1130
1141
|
!(e.l & CONFIG_OVERRIDE) && // lanes: the slow path's one arm
|
|
1131
1142
|
true) {
|
|
1132
1143
|
if (t) {
|
|
@@ -1147,11 +1158,13 @@ function read(e) {
|
|
|
1147
1158
|
}
|
|
1148
1159
|
}
|
|
1149
1160
|
// Committed visibility for untracked and children-forbidden readers.
|
|
1150
|
-
if (!t || e.
|
|
1161
|
+
if (!t || e.ue === NOT_PENDING || t.l & CONFIG_CHILDREN_FORBIDDEN) return e.Ie;
|
|
1151
1162
|
// (A plain signal is never uninitialized — the carve-out is `serve`'s.)
|
|
1152
|
-
|
|
1163
|
+
// Lane work over a folded lane (D-34), once the frame has a
|
|
1164
|
+
// transaction, reads the screen too.
|
|
1165
|
+
if ((observeFlightHook && t.l & CONFIG_VERDICT || laneStageHook && passLane?.folded) && stagedScreen(t)) return e.Ie;
|
|
1153
1166
|
stagedRead(t);
|
|
1154
|
-
return e.
|
|
1167
|
+
return e.ue;
|
|
1155
1168
|
}
|
|
1156
1169
|
// Rule 3: this read serves the committed value to a render effect outside a
|
|
1157
1170
|
// parking flush (decided after the pull below — a pull can join).
|
|
@@ -1237,7 +1250,7 @@ function read(e) {
|
|
|
1237
1250
|
const n = e.T?.Pe;
|
|
1238
1251
|
if (n !== undefined) {
|
|
1239
1252
|
const o = n === NO_SNAPSHOT ? undefined : n;
|
|
1240
|
-
const E = e.
|
|
1253
|
+
const E = e.ue !== NOT_PENDING ? e.ue : e.Ie;
|
|
1241
1254
|
if (E !== o) t.R |= REACTIVE_SNAPSHOT_STALE;
|
|
1242
1255
|
return o;
|
|
1243
1256
|
}
|
|
@@ -1274,7 +1287,7 @@ function read(e) {
|
|
|
1274
1287
|
// an untracked reader has nothing to serve and holds (A19 exception 1) — a
|
|
1275
1288
|
// bookkeeping read (`spectate`) likewise, and a children-forbidden reader
|
|
1276
1289
|
// (A32: the frame, which has nothing here).
|
|
1277
|
-
if (e.
|
|
1290
|
+
if (e.ue !== NOT_PENDING && e.m & STATUS_UNINITIALIZED && (!t || spectating || t.l & CONFIG_CHILDREN_FORBIDDEN)) throw new NotReadyError(null);
|
|
1278
1291
|
const n = t && unflushedStaged ? unflushedValue(e) : NOT_PENDING;
|
|
1279
1292
|
if (n !== NOT_PENDING) {
|
|
1280
1293
|
markLateLinker(t);
|
|
@@ -1284,13 +1297,16 @@ function read(e) {
|
|
|
1284
1297
|
if (observeFlightHook && t.l & CONFIG_VERDICT && !(e.m & STATUS_UNINITIALIZED) && stagedScreen(t)) return e.Ie;
|
|
1285
1298
|
stagedRead(t, e);
|
|
1286
1299
|
// D-41: the staged answer is an error (`stageError`).
|
|
1287
|
-
if (e.l & CONFIG_STAGED_ERROR) throw e.
|
|
1288
|
-
return e.
|
|
1300
|
+
if (e.l & CONFIG_STAGED_ERROR) throw e.ue;
|
|
1301
|
+
return e.ue;
|
|
1289
1302
|
}
|
|
1290
1303
|
|
|
1291
1304
|
/** A pass read a staging of this flush: it derives from what the flush may
|
|
1292
1305
|
* yet hold (REACTIVE_STAGED_READ — the seam decides). Lane work too (plan sec. 28, a
|
|
1293
|
-
* lane sees the screen plus its own guesses)
|
|
1306
|
+
* lane sees the screen plus its own guesses) — a folded lane's only before
|
|
1307
|
+
* the frame has a transaction (after, it reads the screen like a verdict
|
|
1308
|
+
* reader, `stagedScreen` — a list pass never pairs a held length with the
|
|
1309
|
+
* guess's rows, D-34): the staging is the screen if
|
|
1294
1310
|
* the frame commits — one pass, the common case — and a held write if it
|
|
1295
1311
|
* parks, which the seam repairs (`stagedReaders`): the pass re-derives on
|
|
1296
1312
|
* the committed world and its lane's runs wait that round, so the held
|
|
@@ -1377,7 +1393,7 @@ function read(e) {
|
|
|
1377
1393
|
|
|
1378
1394
|
function setSignal(e, t) {
|
|
1379
1395
|
if (writeHook !== null) writeHook(e);
|
|
1380
|
-
const n = e.
|
|
1396
|
+
const n = e.ue === NOT_PENDING ? e.Ie : e.ue;
|
|
1381
1397
|
if (typeof t === "function") t = t(n);
|
|
1382
1398
|
// Lanes: a write landing on a guess is its truth (A18 — an async guess's
|
|
1383
1399
|
// own landing), judged against the guess; one landing on a lane's
|
|
@@ -1404,12 +1420,12 @@ function setSignal(e, t) {
|
|
|
1404
1420
|
// pass reads a value the server never had. Store leaves written here are
|
|
1405
1421
|
// plain signals and qualify the same way.
|
|
1406
1422
|
if (snapshotCaptureActive) captureWriteSnapshot(e, n);
|
|
1407
|
-
const E = e.
|
|
1423
|
+
const E = e.ue !== NOT_PENDING;
|
|
1408
1424
|
if (!E) queuePendingNode(e);
|
|
1409
1425
|
// A28: a held node rewritten outside a flush keeps its flushed staging
|
|
1410
1426
|
// for every reader until the flush that carries the rewrite.
|
|
1411
1427
|
else if (e.l & CONFIG_HELD && !globalQueue.q) stashFlushed(e);
|
|
1412
|
-
e.
|
|
1428
|
+
e.ue = t;
|
|
1413
1429
|
if (context !== null) notePromotedWrite(e);
|
|
1414
1430
|
// _time is a computed-only slot (§12e): writing it on a signal would fork
|
|
1415
1431
|
// the lean shape. Every read site is computed-typed.
|
|
@@ -1466,7 +1482,7 @@ function setSignal(e, t) {
|
|
|
1466
1482
|
e.R = e.R & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
1467
1483
|
insertIntoHeap(e, dirtyQueue);
|
|
1468
1484
|
schedule();
|
|
1469
|
-
} else if (e.
|
|
1485
|
+
} else if (e.ue !== NOT_PENDING) e.R |= REACTIVE_MANUAL_WRITE;
|
|
1470
1486
|
return t;
|
|
1471
1487
|
}
|
|
1472
1488
|
|
|
@@ -1527,4 +1543,4 @@ function staleValues(e, t = true) {
|
|
|
1527
1543
|
}
|
|
1528
1544
|
}
|
|
1529
1545
|
|
|
1530
|
-
export { bornInto, captureWriteSnapshot, clearSnapshots, computed, context, createEffectNode, effectStatusNotify, ext, isEqual, isSame, joinPass, markLateLinker, markRefresh, markSnapshotScope, markUnflushedStaged, notePromotedWrite, prepareComputed, pullComputed, read, readerSeesCommitted, recompute, releaseSnapshotScope, resyncUnflushedCompanions, runWithOwner, serve, setEffectStatusNotify, setMemo, setSignal, setSnapshotCapture, setVerdict, setWriteHook, signal, slotSignal, snapshotCaptureActive, snapshotSources, spectating, stagedRead, stagedScreen, staleValues, stashFlushed, statusNotifierOf, tracking, unflushedStaged, unflushedValue, untrack, verdict, writeHook };
|
|
1546
|
+
export { bornInto, captureWriteSnapshot, clearSnapshots, computed, context, createEffectNode, effectStatusNotify, ext, isEqual, isSame, joinPass, joinPassAt, markLateLinker, markRefresh, markSnapshotScope, markUnflushedStaged, notePromotedWrite, prepareComputed, pullComputed, read, readerSeesCommitted, recompute, releaseSnapshotScope, resyncUnflushedCompanions, runWithOwner, serve, setEffectStatusNotify, setMemo, setSignal, setSnapshotCapture, setVerdict, setWriteHook, signal, slotSignal, snapshotCaptureActive, snapshotSources, spectating, stagedRead, stagedScreen, staleValues, stashFlushed, statusNotifierOf, tracking, unflushedStaged, unflushedValue, untrack, verdict, writeHook };
|
package/dist/prod/core/effect.js
CHANGED
|
@@ -15,42 +15,47 @@ import { globalQueue, schedule, heldRunHook, haltReactivity, GlobalQueue } from
|
|
|
15
15
|
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
|
|
16
16
|
* sources and recompute
|
|
17
17
|
*/ function effect(t, e, E, u) {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
recompute(
|
|
18
|
+
const r = !!u?.user;
|
|
19
|
+
const f = createEffectNode(t, e, E, r ? EFFECT_USER : EFFECT_RENDER, u);
|
|
20
|
+
recompute(f, true);
|
|
21
21
|
// A first pass that read a staged value was staged itself (recompute: born
|
|
22
22
|
// staged); the flush's commit replays this effect. Its first run is not this
|
|
23
23
|
// creation's (A29). A lane's node likewise: its run is the lane's, queued
|
|
24
24
|
// by the pass and released at the reveal (lanes.ts).
|
|
25
|
-
!u?.defer &&
|
|
25
|
+
!u?.defer && f.ue === NOT_PENDING && !f.T?.Re?.v && (f.i === EFFECT_USER || u?.schedule ? globalQueue.enqueue(f.i, runEffect.bind(null, f)) : runEffect(f, f.i));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function notifyEffectStatus(
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
if (E & STATUS_ERROR) {
|
|
28
|
+
function notifyEffectStatus() {
|
|
29
|
+
const t = this.m;
|
|
30
|
+
const e = this.T?.F;
|
|
31
|
+
if (t & STATUS_ERROR) {
|
|
33
32
|
globalQueue.notify(this, STATUS_PENDING, 0);
|
|
34
33
|
if (this.i === EFFECT_USER) {
|
|
35
34
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
36
35
|
// queue it like the effect function. It runs in the same imperative,
|
|
37
36
|
// writable scope and throws escalate the same way. No payload is queued — the node already carries `_statusFlags`/`_error`,
|
|
38
37
|
// and the runner dispatches on them, so a recovery before the effect
|
|
39
|
-
// phase takes the success arm instead.
|
|
40
|
-
//
|
|
41
|
-
// re-propagates unblocked at commit.
|
|
38
|
+
// phase takes the success arm instead. (Re-read: the boundary
|
|
39
|
+
// notify above can run a redraw.)
|
|
42
40
|
if (this.m & STATUS_ERROR) {
|
|
43
41
|
this.Ae = true;
|
|
44
42
|
globalQueue.enqueue(this.i, this.W ??= runEffect.bind(null, this));
|
|
45
43
|
}
|
|
46
44
|
return;
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
46
|
+
// Dev locates the halt at the node that threw: the StatusError's
|
|
47
|
+
// source, upstream of this effect when a computed failed.
|
|
48
|
+
escalate(this, unwrapStatusError(e), e, this);
|
|
52
49
|
} else if (this.i === EFFECT_RENDER) {
|
|
53
|
-
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR,
|
|
50
|
+
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR, t, e);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** An effect's error no boundary takes halts the system (boundary-or-halt):
|
|
55
|
+
* halted with `cause`, `thrown` rethrown; dev locates it at `subject`. */ function escalate(t, e, E = e, u = t) {
|
|
56
|
+
if (!globalQueue.notify(t, STATUS_ERROR, STATUS_ERROR)) {
|
|
57
|
+
haltReactivity(e);
|
|
58
|
+
throw E;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -86,10 +91,7 @@ function runEffect(t, e) {
|
|
|
86
91
|
e?.();
|
|
87
92
|
}) : console.error(e);
|
|
88
93
|
} catch (e) {
|
|
89
|
-
|
|
90
|
-
haltReactivity(e);
|
|
91
|
-
throw e;
|
|
92
|
-
}
|
|
94
|
+
escalate(t, e);
|
|
93
95
|
}
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
@@ -107,10 +109,7 @@ function runEffect(t, e) {
|
|
|
107
109
|
} catch (e) {
|
|
108
110
|
ext(t).F = new StatusError(t, e);
|
|
109
111
|
t.m |= STATUS_ERROR;
|
|
110
|
-
|
|
111
|
-
haltReactivity(e);
|
|
112
|
-
throw e;
|
|
113
|
-
}
|
|
112
|
+
escalate(t, e);
|
|
114
113
|
} finally {
|
|
115
114
|
t.ge = t.Ie;
|
|
116
115
|
t.Ae = false;
|
package/dist/prod/core/graph.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTO_DISPOSE, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_SLOT_NODE } from "./constants.js";
|
|
1
|
+
import { NewSet, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTO_DISPOSE, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_SLOT_NODE } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { deleteFromHeap } from "./heap.js";
|
|
4
4
|
|
|
5
|
-
import { disposeChildren } from "./owner.js";
|
|
5
|
+
import { disposeChildren, runCleanup } from "./owner.js";
|
|
6
6
|
|
|
7
7
|
import { bumpNotifyEpoch, dirtyQueue } from "./scheduler.js";
|
|
8
8
|
|
|
@@ -27,7 +27,9 @@ function unlinkSubs(e) {
|
|
|
27
27
|
if (o === null) {
|
|
28
28
|
// Store slot nodes dispatch to the ONE shared hook — no per-node
|
|
29
29
|
// unobserved closure, no NodeExtension to hold it.
|
|
30
|
-
|
|
30
|
+
// A user hook that throws is collected like a cleanup (owner.ts): the
|
|
31
|
+
// unlink and the teardown around it carry on.
|
|
32
|
+
if (n.l & CONFIG_SLOT_NODE) slotUnobservedHook(n); else if (n.T?.we) runCleanup(n.T.we);
|
|
31
33
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
32
34
|
// A pending node is exempt: its in-flight async work is an observer —
|
|
33
35
|
// tearing down would orphan the work and re-execute it on the next
|
|
@@ -105,7 +107,7 @@ function unobserved(e) {
|
|
|
105
107
|
* stays alive and serves its cache, uniform with observed memos) while
|
|
106
108
|
* reclamation still happens within one microtask — the enqueue site arms
|
|
107
109
|
* schedule(), so a flush is guaranteed even when no other work is queued.
|
|
108
|
-
*/ const dormantNodes = new
|
|
110
|
+
*/ const dormantNodes = new NewSet;
|
|
109
111
|
|
|
110
112
|
function sweepDormant() {
|
|
111
113
|
if (dormantNodes.size === 0) return;
|
|
@@ -141,18 +143,18 @@ function link(e, n) {
|
|
|
141
143
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
142
144
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
143
145
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
const
|
|
146
|
+
const r = e.ve;
|
|
147
|
+
if (r !== null && r.u === n && (!s || r.Te === n.Ne)) return;
|
|
148
|
+
const t = n._ = e.ve = {
|
|
147
149
|
S: e,
|
|
148
150
|
u: n,
|
|
149
151
|
G: o,
|
|
150
|
-
Xe:
|
|
152
|
+
Xe: r,
|
|
151
153
|
t: null,
|
|
152
154
|
Te: n.Ne
|
|
153
155
|
};
|
|
154
|
-
if (l !== null) l.G =
|
|
155
|
-
if (
|
|
156
|
+
if (l !== null) l.G = t; else n.C = t;
|
|
157
|
+
if (r !== null) r.t = t; else e.o = t;
|
|
156
158
|
// New subscriber edge: staged-rewrite skips (§12d) must not miss it.
|
|
157
159
|
bumpNotifyEpoch();
|
|
158
160
|
}
|
package/dist/prod/core/heap.js
CHANGED
|
@@ -16,7 +16,7 @@ import { dirtyQueue } from "./scheduler.js";
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function actualInsertIntoHeap(e, t) {
|
|
19
|
-
const E = (e._parent?.
|
|
19
|
+
const E = (e._parent?.Qe ? e._parent.Ye?.Fe : e._parent?.Fe) ?? -1;
|
|
20
20
|
if (E >= e.Fe) e.Fe = E + 1;
|
|
21
21
|
const n = e.Fe;
|
|
22
22
|
const I = t.$e[n];
|