@solidjs/signals 2.0.0-rc.18 → 2.0.0-rc.19
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 +168 -88
- package/dist/dev.attribution.js +16 -13
- package/dist/dev.js +272 -129
- package/dist/observe/boundaries.js +88 -67
- package/dist/observe/core/action.js +8 -0
- package/dist/observe/core/async.js +46 -34
- package/dist/observe/core/attribution.js +30 -28
- package/dist/observe/core/constants.js +21 -1
- package/dist/observe/core/core.js +164 -136
- package/dist/observe/core/effect.js +6 -6
- package/dist/observe/core/graph.js +3 -3
- package/dist/observe/core/heap.js +5 -5
- package/dist/observe/core/lanes.js +104 -84
- package/dist/observe/core/owner.js +10 -9
- package/dist/observe/core/scheduler.js +38 -35
- package/dist/observe/core/truth.js +6 -6
- package/dist/observe/core/verdict.js +13 -13
- package/dist/observe/deferred.js +39 -40
- package/dist/observe/index.js +2 -2
- package/dist/observe/map.js +22 -22
- package/dist/observe/reveal.js +5 -5
- package/dist/observe/signals.js +57 -15
- package/dist/observe/store/affects.js +1 -1
- package/dist/observe/store/hooks.js +3 -0
- package/dist/observe/store/optimistic.js +11 -11
- package/dist/observe/store/projection.js +34 -21
- package/dist/observe/store/reconcile.js +2 -2
- package/dist/observe/store/store.js +63 -53
- package/dist/observe/store/utils.js +7 -2
- package/dist/prod/boundaries.js +153 -132
- package/dist/prod/core/action.js +8 -0
- package/dist/prod/core/async.js +55 -43
- package/dist/prod/core/constants.js +14 -1
- package/dist/prod/core/core.js +162 -134
- package/dist/prod/core/effect.js +9 -9
- package/dist/prod/core/graph.js +3 -3
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/lanes.js +98 -78
- package/dist/prod/core/owner.js +15 -14
- package/dist/prod/core/scheduler.js +43 -40
- package/dist/prod/core/truth.js +6 -6
- package/dist/prod/core/verdict.js +17 -17
- package/dist/prod/deferred.js +39 -40
- package/dist/prod/index.js +2 -2
- package/dist/prod/map.js +14 -14
- package/dist/prod/reveal.js +8 -8
- package/dist/prod/signals.js +46 -4
- package/dist/prod/store/affects.js +1 -1
- package/dist/prod/store/hooks.js +3 -0
- package/dist/prod/store/optimistic.js +16 -16
- package/dist/prod/store/projection.js +22 -9
- package/dist/prod/store/reconcile.js +2 -2
- package/dist/prod/store/store.js +262 -262
- package/dist/prod/store/utils.js +2 -0
- package/dist/types/core/action.d.ts +8 -0
- package/dist/types/core/constants.d.ts +20 -0
- package/dist/types/core/core.d.ts +14 -1
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +5 -1
- package/dist/types/core/scheduler.d.ts +2 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/signals.d.ts +37 -0
- package/dist/types/store/target.d.ts +2 -0
- package/package.json +1 -1
package/dist/prod/core/owner.js
CHANGED
|
@@ -6,7 +6,7 @@ import { unobserved, clearDeps } from "./graph.js";
|
|
|
6
6
|
|
|
7
7
|
import { deleteFromHeap } from "./heap.js";
|
|
8
8
|
|
|
9
|
-
import { globalQueue, schedule, dirtyQueue } from "./scheduler.js";
|
|
9
|
+
import { globalQueue, pendingNodes, schedule, dirtyQueue } from "./scheduler.js";
|
|
10
10
|
|
|
11
11
|
// L2 (step 2): the parked frame. A pass parks the previous frame's children
|
|
12
12
|
// and `_disposal` list on `_x._pendingFirstChild` / `_x._pendingDisposal`
|
|
@@ -16,11 +16,11 @@ import { globalQueue, schedule, dirtyQueue } from "./scheduler.js";
|
|
|
16
16
|
// key off it, and the heap defers a zombie's recompute past the seam (no
|
|
17
17
|
// second heap — the deferral list in scheduler.ts).
|
|
18
18
|
function markDisposal(e) {
|
|
19
|
-
let n = e.
|
|
19
|
+
let n = e.pe;
|
|
20
20
|
while (n) {
|
|
21
21
|
n.R |= REACTIVE_ZOMBIE;
|
|
22
22
|
markDisposal(n);
|
|
23
|
-
n = n.
|
|
23
|
+
n = n.Ge;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -72,15 +72,16 @@ function disposeChildren(e, n = false, r) {
|
|
|
72
72
|
e.R = t | REACTIVE_DISPOSED;
|
|
73
73
|
}
|
|
74
74
|
if (n && e.X) {
|
|
75
|
-
if (e.T !== null) e.T.
|
|
75
|
+
if (e.T !== null) e.T.Ee = null;
|
|
76
76
|
// A death that can unblock the future (L2, `futureBlocked`): a held
|
|
77
77
|
// flight's — a transaction's or a lane's (its `_x._transaction`) — or a
|
|
78
78
|
// stale reader's (REACTIVE_FRAME_READ — a frame that derived from one).
|
|
79
|
+
// An idle pending queue would also pin it until an unrelated flush.
|
|
79
80
|
// Nothing else re-examines a dead node, so make sure a seam comes.
|
|
80
|
-
if (e.m & STATUS_PENDING && e.T?.Re != null || t & REACTIVE_FRAME_READ) schedule();
|
|
81
|
+
if (e.m & STATUS_PENDING && e.T?.Re != null || t & REACTIVE_FRAME_READ || pendingNodes.length) schedule();
|
|
81
82
|
}
|
|
82
|
-
let l = r ? e.T.Ue : e.
|
|
83
|
-
if (r) e.T.Ue = null; else e.
|
|
83
|
+
let l = r ? e.T.Ue : e.pe;
|
|
84
|
+
if (r) e.T.Ue = null; else e.pe = null;
|
|
84
85
|
while (l) {
|
|
85
86
|
const e = l;
|
|
86
87
|
// Owner teardown is death regardless of the child's own lifecycle
|
|
@@ -110,7 +111,7 @@ function disposeChildren(e, n = false, r) {
|
|
|
110
111
|
// itself out of the detached chain, and a cleanup may then have linked
|
|
111
112
|
// it at the fresh head, which rewrote the `_nextSibling` a pre-read
|
|
112
113
|
// would still be holding.
|
|
113
|
-
l = l.
|
|
114
|
+
l = l.Ge;
|
|
114
115
|
}
|
|
115
116
|
if (!r) e.ye = 0;
|
|
116
117
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
@@ -120,8 +121,8 @@ function disposeChildren(e, n = false, r) {
|
|
|
120
121
|
// still reach later siblings.
|
|
121
122
|
if (n && !r && !(t & REACTIVE_ZOMBIE) && e._parent !== null && !(e._parent.R & REACTIVE_DISPOSED)) {
|
|
122
123
|
const n = e.Ze;
|
|
123
|
-
const r = e.
|
|
124
|
-
if (n !== null) n.
|
|
124
|
+
const r = e.Ge;
|
|
125
|
+
if (n !== null) n.Ge = r; else e._parent.pe = r;
|
|
125
126
|
if (r !== null) r.Ze = n;
|
|
126
127
|
e.Ze = null;
|
|
127
128
|
}
|
|
@@ -136,11 +137,11 @@ function disposeChildren(e, n = false, r) {
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function linkChild(e, n) {
|
|
139
|
-
const r = e.
|
|
140
|
+
const r = e.pe;
|
|
140
141
|
n.Ze = null;
|
|
141
|
-
n.
|
|
142
|
+
n.Ge = r;
|
|
142
143
|
if (r !== null) r.Ze = n;
|
|
143
|
-
e.
|
|
144
|
+
e.pe = n;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
function runDisposal(e, n) {
|
|
@@ -306,8 +307,8 @@ function disposeRootSelf(e = true) {
|
|
|
306
307
|
R: REACTIVE_NONE,
|
|
307
308
|
Qe: true,
|
|
308
309
|
Ye: n?.Qe ? n.Ye : n,
|
|
309
|
-
De: null,
|
|
310
310
|
pe: null,
|
|
311
|
+
Ge: null,
|
|
311
312
|
Ze: null,
|
|
312
313
|
He: null,
|
|
313
314
|
A: n?.A || defaultContext,
|
|
@@ -135,12 +135,12 @@ function setExternalHooks(e, n) {
|
|
|
135
135
|
En: [],
|
|
136
136
|
cn: null,
|
|
137
137
|
_parent: n,
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
P: e,
|
|
139
|
+
Pe: null,
|
|
140
140
|
tt: 0,
|
|
141
141
|
nt: false,
|
|
142
142
|
en: null,
|
|
143
|
-
|
|
143
|
+
ge: false,
|
|
144
144
|
ln: false,
|
|
145
145
|
I: null
|
|
146
146
|
};
|
|
@@ -227,7 +227,7 @@ function resolveTx(e) {
|
|
|
227
227
|
// into the other would close a cycle `resolveTx` never leaves.
|
|
228
228
|
e = resolveTx(e);
|
|
229
229
|
n = resolveTx(n);
|
|
230
|
-
if (e === n || e.
|
|
230
|
+
if (e === n || e.P || n.P) return;
|
|
231
231
|
e.cn = n;
|
|
232
232
|
n.tt += e.tt;
|
|
233
233
|
n.nt ||= e.nt;
|
|
@@ -311,7 +311,7 @@ function blockedBy(e, n, o = false) {
|
|
|
311
311
|
// lane-membership ruling, 2026-10-05). An output that never committed
|
|
312
312
|
// shows nothing — a mount the frame has not revealed — and holds
|
|
313
313
|
// nothing.
|
|
314
|
-
if ((o.i === EFFECT_RENDER && o.m & STATUS_PENDING || o.R & REACTIVE_FRAME_READ || o.l & CONFIG_REDERIVE && o.m === STATUS_PENDING) && (e.
|
|
314
|
+
if ((o.i === EFFECT_RENDER && o.m & STATUS_PENDING || o.R & REACTIVE_FRAME_READ || o.l & CONFIG_REDERIVE && o.m === STATUS_PENDING) && (e.de === o.Ne || o.T?.U != null) && !(o.R & REACTIVE_DISPOSED) && onScreen(o, judge ?? n)) return true;
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
317
|
return false;
|
|
@@ -389,8 +389,8 @@ function deferZombie(e) {
|
|
|
389
389
|
* next read of it trips over (`laneRead` → `txOf`). Its frame is the lane's
|
|
390
390
|
* too (ruling A: a lane pass's children are the lane's), revealed and
|
|
391
391
|
* retired at the lane's seam. */ function holdFrame(e, n) {
|
|
392
|
-
for (let o = e.
|
|
393
|
-
if (o.T?.Re?.
|
|
392
|
+
for (let o = e.pe; o !== null; o = o.Ge) {
|
|
393
|
+
if (o.T?.Re?.P) continue;
|
|
394
394
|
if (o.X !== undefined) {
|
|
395
395
|
if (!(o.l & CONFIG_HELD)) holdNode(o, n);
|
|
396
396
|
o.l |= CONFIG_HELD_FRAME;
|
|
@@ -401,7 +401,7 @@ function deferZombie(e) {
|
|
|
401
401
|
|
|
402
402
|
/** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
|
|
403
403
|
* what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, n, o) {
|
|
404
|
-
for (let t = e.
|
|
404
|
+
for (let t = e.pe; t !== null; t = t.Ge) {
|
|
405
405
|
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !== n) o(t);
|
|
406
406
|
heldUnder(t, n, o);
|
|
407
407
|
}
|
|
@@ -415,7 +415,7 @@ function deferZombie(e) {
|
|
|
415
415
|
const dirtyQueue = {
|
|
416
416
|
$e: new Array(2e3).fill(undefined),
|
|
417
417
|
p: false,
|
|
418
|
-
|
|
418
|
+
Fe: 0,
|
|
419
419
|
et: 0
|
|
420
420
|
};
|
|
421
421
|
|
|
@@ -497,12 +497,14 @@ function schedule() {
|
|
|
497
497
|
* hook machinery (pay-for-use).
|
|
498
498
|
*/ const ROOT_ERROR_HOOK = Symbol.for("solid-js/root-error-hook");
|
|
499
499
|
|
|
500
|
+
const HALTED = "[REACTIVITY_HALTED]";
|
|
501
|
+
|
|
500
502
|
function haltReactivity(e) {
|
|
501
503
|
if (halted) return;
|
|
502
504
|
halted = true;
|
|
503
505
|
// A cleanup error collected before the halt is dropped (owner.ts).
|
|
504
506
|
rethrowCleanupError(true);
|
|
505
|
-
let n =
|
|
507
|
+
let n = HALTED;
|
|
506
508
|
// Surface the cause here too: callers rethrow it, but a creation-time throw
|
|
507
509
|
// unwinds through ancestor recomputes that convert it to status instead of
|
|
508
510
|
// surfacing it (#2884), so the rethrow alone cannot guarantee visibility.
|
|
@@ -530,7 +532,7 @@ function haltReactivity(e) {
|
|
|
530
532
|
function notifyHalted() {
|
|
531
533
|
if (haltNotified) return;
|
|
532
534
|
haltNotified = true;
|
|
533
|
-
console.error(
|
|
535
|
+
console.error(HALTED);
|
|
534
536
|
}
|
|
535
537
|
|
|
536
538
|
/** @internal Test/dev-reload hook. Revives scheduling after a halt. */ function resetErrorHalt() {
|
|
@@ -561,7 +563,7 @@ class GlobalQueue {
|
|
|
561
563
|
clock++;
|
|
562
564
|
// A write the commit sweep staged with no subscriber to dirty is work
|
|
563
565
|
// too — the next round commits it.
|
|
564
|
-
scheduled = dirtyQueue.et >= dirtyQueue.
|
|
566
|
+
scheduled = dirtyQueue.et >= dirtyQueue.Fe || pendingNodes.length !== 0;
|
|
565
567
|
this.run(EFFECT_RENDER);
|
|
566
568
|
this.run(EFFECT_USER);
|
|
567
569
|
if (false && holding) ;
|
|
@@ -593,7 +595,7 @@ class GlobalQueue {
|
|
|
593
595
|
// A lane's own flush (its flight landing, its reveal) parks nothing: the
|
|
594
596
|
// lane's work reached it per pass; the frame's plain writes commit.
|
|
595
597
|
// (Resolved: a guess over another transaction's guess merged them.)
|
|
596
|
-
const n = e !== null && !e.
|
|
598
|
+
const n = e !== null && !e.P ? resolveTx(e) : null;
|
|
597
599
|
if (n !== null) {
|
|
598
600
|
// `t._nodes` grows under the walk (holdFrame pushes); the bound is
|
|
599
601
|
// this flush's list, which does not.
|
|
@@ -603,7 +605,7 @@ class GlobalQueue {
|
|
|
603
605
|
// Already held: the pass that re-staged it joined its transaction,
|
|
604
606
|
// which is `t` (or merged into it). Lane work is the lane's (a
|
|
605
607
|
// pending mark propagated onto it queued it here too).
|
|
606
|
-
if (!(e.l & (CONFIG_HELD | CONFIG_OVERRIDE)) && (e.T === null || e.T.Re === null || !e.T.Re.
|
|
608
|
+
if (!(e.l & (CONFIG_HELD | CONFIG_OVERRIDE)) && (e.T === null || e.T.Re === null || !e.T.Re.P)) {
|
|
607
609
|
// A loading source — pending with nothing staged and no committed
|
|
608
610
|
// value (A16, A19 exc. 1: uninitialized is loading, not pending)
|
|
609
611
|
// that is not an observer — is nobody's frame: not held. Its
|
|
@@ -612,18 +614,18 @@ class GlobalQueue {
|
|
|
612
614
|
// stale stamp was the bridge that entangled unrelated updates
|
|
613
615
|
// with a never-resolving flight). Its observers are held and
|
|
614
616
|
// wait on its flight (`blocked`).
|
|
615
|
-
if (e.
|
|
617
|
+
if (e.ie === NOT_PENDING && e.m & STATUS_UNINITIALIZED && e.i !== EFFECT_RENDER) continue;
|
|
616
618
|
// A34 (2): a tick whose writes net to the committed value made no
|
|
617
619
|
// proposal (`setShow(false); setShow(true)` on a committed true) —
|
|
618
620
|
// not staged, not held, pends nothing; a later write to it is
|
|
619
621
|
// plain mainline. (A node already held stays held when written
|
|
620
622
|
// back: A34 (1).)
|
|
621
|
-
if (e.
|
|
623
|
+
if (e.ie !== NOT_PENDING && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.T?.Ue == null && e.T?.me == null &&
|
|
622
624
|
// The comparator last: a pass that created children (an object
|
|
623
625
|
// owning a fresh async memo, #4111) must not have it read them.
|
|
624
626
|
// A NotReady read there is a change (`isSame`).
|
|
625
|
-
isSame(e, e.
|
|
626
|
-
e.
|
|
627
|
+
isSame(e, e.le, e.ie)) {
|
|
628
|
+
e.ie = NOT_PENDING;
|
|
627
629
|
e.l &= ~CONFIG_STAGED;
|
|
628
630
|
continue;
|
|
629
631
|
}
|
|
@@ -648,7 +650,7 @@ class GlobalQueue {
|
|
|
648
650
|
// (Verdict readers exist only with the verdict engine installed.)
|
|
649
651
|
const o = deferredZombies.splice(0);
|
|
650
652
|
if (observeFlightHook) {
|
|
651
|
-
o.sort((e, n) => e.
|
|
653
|
+
o.sort((e, n) => e.he - n.he);
|
|
652
654
|
for (let e = 0; e < o.length; e++) if ((o[e].R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE && o[e].l & CONFIG_VERDICT) recompute(o[e]);
|
|
653
655
|
}
|
|
654
656
|
// The unchanged passes' tails stay linked (A30, #3469): their inputs
|
|
@@ -662,7 +664,7 @@ class GlobalQueue {
|
|
|
662
664
|
// `recompute`'s own gates.
|
|
663
665
|
for (let e = 0; e < heldTrims.length; e++) {
|
|
664
666
|
const n = heldTrims[e];
|
|
665
|
-
if (n.T?.
|
|
667
|
+
if (n.T?.U == null && !n.Ae) trimStaleDeps(n);
|
|
666
668
|
}
|
|
667
669
|
}
|
|
668
670
|
// The list is the flush's either way. Reset only when there is something
|
|
@@ -677,11 +679,12 @@ class GlobalQueue {
|
|
|
677
679
|
// This flush's own runs, the lanes' reveals, and the landings' held runs
|
|
678
680
|
// are collected apart and ordered below.
|
|
679
681
|
const o = this.un;
|
|
680
|
-
const t =
|
|
682
|
+
const t = [ [], [] ];
|
|
681
683
|
// The passes that read this frame's stagings as the screen read held
|
|
682
684
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
683
685
|
// world (a lane's runs wait this round).
|
|
684
686
|
if (laneSeamsHook) {
|
|
687
|
+
this.un = t;
|
|
685
688
|
laneSeamsHook(n !== null ? stagedReaders : null);
|
|
686
689
|
if (stagedReaders.length) stagedReaders.length = 0;
|
|
687
690
|
}
|
|
@@ -725,7 +728,7 @@ class GlobalQueue {
|
|
|
725
728
|
if (deferredZombies.length !== 0) {
|
|
726
729
|
// Survivors are the displayed frame of a held pass: they rerun for the
|
|
727
730
|
// live write, parents before children.
|
|
728
|
-
const e = deferredZombies.splice(0).sort((e, n) => e.
|
|
731
|
+
const e = deferredZombies.splice(0).sort((e, n) => e.he - n.he);
|
|
729
732
|
for (let n = 0; n < e.length; n++) {
|
|
730
733
|
if (!(e[n].R & REACTIVE_DISPOSED)) recompute(e[n]);
|
|
731
734
|
}
|
|
@@ -811,7 +814,7 @@ class GlobalQueue {
|
|
|
811
814
|
// Its frame is replaced by the re-derivation: a run one of its
|
|
812
815
|
// children queued this flush (re-run by the same landing) is for the
|
|
813
816
|
// frame being replaced — void too (#3404).
|
|
814
|
-
for (let e = t.
|
|
817
|
+
for (let e = t.pe; e !== null; e = e.Ge) if (e.i) e.Ae = false;
|
|
815
818
|
enqueueSub(t);
|
|
816
819
|
}
|
|
817
820
|
}
|
|
@@ -821,7 +824,7 @@ class GlobalQueue {
|
|
|
821
824
|
|
|
822
825
|
/** The landing: the held frame becomes the frame. */ function land(e) {
|
|
823
826
|
const n = reruns(e);
|
|
824
|
-
if (e.I !== null) releaseMarksHook(e.I);
|
|
827
|
+
if (releaseMarksHook && e.I !== null) releaseMarksHook(e.I);
|
|
825
828
|
// Old children die in the commits (cleanups first), then the stashed
|
|
826
829
|
// effects run ahead of this flush's own. A node a lane took over since
|
|
827
830
|
// (a guess written over the staged truth) is the lane's to land.
|
|
@@ -899,7 +902,7 @@ function insertSubs(e) {
|
|
|
899
902
|
// masked read of the always-present _config instead of missing-property
|
|
900
903
|
// lookups in the hottest notify loop.
|
|
901
904
|
const n = e.l;
|
|
902
|
-
const o = (n & CONFIG_HAS_SNAPSHOT) !== 0 && e.T?.
|
|
905
|
+
const o = (n & CONFIG_HAS_SNAPSHOT) !== 0 && e.T?.De !== undefined;
|
|
903
906
|
for (let n = e.o; n !== null; n = n.t) {
|
|
904
907
|
const e = n.u;
|
|
905
908
|
// Missed-wake latch (#3037): this write is landing while the subscriber
|
|
@@ -910,7 +913,7 @@ function insertSubs(e) {
|
|
|
910
913
|
// pass either re-reads them fresh or trims them), and neither does the
|
|
911
914
|
// tail link: it is the read IN FLIGHT — read() links before it pulls, so
|
|
912
915
|
// this very commit is what that read returns.
|
|
913
|
-
if (e.R & REACTIVE_RECOMPUTING_DEPS && n.
|
|
916
|
+
if (e.R & REACTIVE_RECOMPUTING_DEPS && n.de === e.Ne && n !== e._) e.R |= REACTIVE_MISSED_WAKE;
|
|
914
917
|
if (o && e.l & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
915
918
|
e.R |= REACTIVE_SNAPSHOT_STALE;
|
|
916
919
|
continue;
|
|
@@ -929,7 +932,7 @@ function insertSubs(e) {
|
|
|
929
932
|
* (the lane-membership ruling, 2026-10-05; `_update`). */ function laneDirty(e, n) {
|
|
930
933
|
for (let o = e.o; o !== null; o = o.t) {
|
|
931
934
|
const e = o.u.T?.Re;
|
|
932
|
-
if (e?.
|
|
935
|
+
if (e?.P ? sameLane(e, n) : o.u.i) o.u.R |= REACTIVE_LANE_DIRTY;
|
|
933
936
|
}
|
|
934
937
|
}
|
|
935
938
|
|
|
@@ -946,32 +949,32 @@ function commitPendingNode(e) {
|
|
|
946
949
|
// commits a value.
|
|
947
950
|
if (!n.X) {
|
|
948
951
|
e.l &= -385;
|
|
949
|
-
if (e.
|
|
950
|
-
e.
|
|
951
|
-
e.
|
|
952
|
+
if (e.ie !== NOT_PENDING) {
|
|
953
|
+
e.le = e.ie;
|
|
954
|
+
e.ie = NOT_PENDING;
|
|
952
955
|
}
|
|
953
956
|
return;
|
|
954
957
|
}
|
|
955
958
|
// Computeds only from here (`_statusFlags` is not a signal field). A
|
|
956
959
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
957
960
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
958
|
-
const o = e.
|
|
961
|
+
const o = e.ie === NOT_PENDING && (n.m & STATUS_PENDING) !== 0;
|
|
959
962
|
const t = e.l & CONFIG_STAGED_ERROR;
|
|
960
963
|
// An answer commits: the error it replaces leaves the display (D-41).
|
|
961
|
-
if (!o && n.T) n.T.
|
|
964
|
+
if (!o && n.T) n.T.Ie = undefined;
|
|
962
965
|
e.l = o ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
|
|
963
966
|
// D-41: the staged answer is an error — published now, when a value would
|
|
964
967
|
// show, through the ordinary error path (`stageError`). Its readers first
|
|
965
968
|
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
966
969
|
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
967
970
|
if (t) {
|
|
968
|
-
const o = e.
|
|
969
|
-
e.
|
|
970
|
-
e.
|
|
971
|
+
const o = e.ie;
|
|
972
|
+
e.ie = NOT_PENDING;
|
|
973
|
+
e.Se = clock + 1;
|
|
971
974
|
notifyStatus(n, STATUS_ERROR, o);
|
|
972
|
-
} else if (e.
|
|
973
|
-
e.
|
|
974
|
-
e.
|
|
975
|
+
} else if (e.ie !== NOT_PENDING) {
|
|
976
|
+
e.le = e.ie;
|
|
977
|
+
e.ie = NOT_PENDING;
|
|
975
978
|
// A node born staged (recompute) initializes at this commit.
|
|
976
979
|
n.m &= ~STATUS_UNINITIALIZED;
|
|
977
980
|
// A quiet re-ask's classification survives its landing and dies with
|
|
@@ -997,7 +1000,7 @@ function commitPendingNode(e) {
|
|
|
997
1000
|
// pass or by the node's own landing (whose pass was clean), so a set
|
|
998
1001
|
// `_error` means the last pass threw, kept its full list, and `_depsTail`
|
|
999
1002
|
// marks where it stopped.
|
|
1000
|
-
if (n.T?.
|
|
1003
|
+
if (n.T?.U == null) trimStaleDeps(n);
|
|
1001
1004
|
if (!(n.m & STATUS_PENDING)) n.m &= ~STATUS_UNINITIALIZED;
|
|
1002
1005
|
// L2: the children this commit publishes are the frame's now — the frame
|
|
1003
1006
|
// they replace, parked by the pass (`recompute`), goes.
|
|
@@ -1051,4 +1054,4 @@ function runQueue(e, n) {
|
|
|
1051
1054
|
for (let o = 0; o < e.length; o++) e[o](n);
|
|
1052
1055
|
}
|
|
1053
1056
|
|
|
1054
|
-
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|
|
1057
|
+
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, pendingNodes, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|
package/dist/prod/core/truth.js
CHANGED
|
@@ -12,9 +12,9 @@ import { enqueueSub } from "./heap.js";
|
|
|
12
12
|
* staging a shown lane holds for its next reveal, else its slot; the
|
|
13
13
|
* committed value while it has none (its first lane pass in flight). */
|
|
14
14
|
function laneValueOf(r) {
|
|
15
|
-
if (!(r.l & CONFIG_GUESS) && r.
|
|
16
|
-
const t = r.T.
|
|
17
|
-
return t !== NOT_PENDING ? t : r.
|
|
15
|
+
if (!(r.l & CONFIG_GUESS) && r.ie !== NOT_PENDING) return r.ie;
|
|
16
|
+
const t = r.T.P;
|
|
17
|
+
return t !== NOT_PENDING ? t : r.le;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/** Truth readers (`until`, `refresh`; CONFIG_AUTHORITATIVE) — pay-for-use:
|
|
@@ -25,7 +25,7 @@ function laneValueOf(r) {
|
|
|
25
25
|
* value. */ function truthRead(r) {
|
|
26
26
|
if (truth(r)) return laneValueOf(r);
|
|
27
27
|
if (!(r.l & CONFIG_GUESS)) throw new NotReadyError(null);
|
|
28
|
-
return r.
|
|
28
|
+
return r.ie !== NOT_PENDING ? r.ie : r.le;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** A guess confirmed: its lane's truth readers re-read — of the lane's
|
|
@@ -36,8 +36,8 @@ function laneValueOf(r) {
|
|
|
36
36
|
/** A lane node's value is the truth when every guess beneath it is
|
|
37
37
|
* confirmed — its source staged a value equal to the guess — and nothing
|
|
38
38
|
* beneath it is held in the parent: same inputs, same value. */ function truth(r) {
|
|
39
|
-
if (r.l & CONFIG_GUESS) return r.
|
|
40
|
-
if (r.
|
|
39
|
+
if (r.l & CONFIG_GUESS) return r.ie !== NOT_PENDING && r.xe && r.xe(r.T.P, r.ie);
|
|
40
|
+
if (r.ie !== NOT_PENDING) return;
|
|
41
41
|
if (r.l & CONFIG_OVERRIDE) for (let t = r.C; t; t = t.G) if (!truth(t.S)) return;
|
|
42
42
|
return 1;
|
|
43
43
|
}
|
|
@@ -157,7 +157,7 @@ let probeFound = false;
|
|
|
157
157
|
* flight — a staging equal to what is displayed changes nothing when it
|
|
158
158
|
* lands: final now (maintainer, 2026-10-02). */ function heldNotFinal(e) {
|
|
159
159
|
if ((e.m & STATUS_PENDING) !== 0 && !quietPending(e)) return true;
|
|
160
|
-
return e.
|
|
160
|
+
return e.ie !== NOT_PENDING && !latestActive && !e.T.Ve && !(e.m & STATUS_UNINITIALIZED) && (!!e.T.Ie || !e.xe || !e.xe(e.le, e.ie));
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/** `isPending`'s answer for an unheld node whose flight is up (cause ii). */ function pendingVerdict(e, t) {
|
|
@@ -256,8 +256,8 @@ let probeFound = false;
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
/** The staging, or the staged error thrown (D-41). */ function staged(e) {
|
|
259
|
-
if (e.l & CONFIG_STAGED_ERROR) throw e.
|
|
260
|
-
return e.
|
|
259
|
+
if (e.l & CONFIG_STAGED_ERROR) throw e.ie;
|
|
260
|
+
return e.ie;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
/** `latest()` of a held node: the flushed staging — the proposal — and, for
|
|
@@ -317,11 +317,11 @@ let probeFound = false;
|
|
|
317
317
|
if (i) verdictRead(t, r._parent ?? r);
|
|
318
318
|
const u = (n.m & STATUS_PENDING) !== 0 && !quietPending(n);
|
|
319
319
|
if (e.l & CONFIG_GUESS) {
|
|
320
|
-
if (probing && (u || e.
|
|
320
|
+
if (probing && (u || e.ie !== NOT_PENDING && (!e.xe || !e.xe(e.T.P, e.ie)))) probeFound = true;
|
|
321
321
|
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
322
322
|
// world whole — the truth beneath each guess, else what it covered.
|
|
323
323
|
if (latestActive && r.folded) return r.folded(null, e);
|
|
324
|
-
return e.T.
|
|
324
|
+
return e.T.P;
|
|
325
325
|
}
|
|
326
326
|
if (probing && u) probeFound = true;
|
|
327
327
|
return latestActive && !u ? laneValueOf(e) : display(e);
|
|
@@ -335,30 +335,30 @@ let probeFound = false;
|
|
|
335
335
|
// in flight — is a stale reader of the lane (#3460, as `laneRead`): the
|
|
336
336
|
// committed value now, re-derived at the reveal. Not inside a probe:
|
|
337
337
|
// `isPending` is answered below either way.
|
|
338
|
-
if (i && !probing && t.i === EFFECT_RENDER && passLane === null && r.
|
|
339
|
-
staleReader(t, r.
|
|
340
|
-
return e.
|
|
338
|
+
if (i && !probing && t.i === EFFECT_RENDER && passLane === null && r.Pe !== null && r.Pe.ln && flushTransaction !== r) {
|
|
339
|
+
staleReader(t, r.Pe);
|
|
340
|
+
return e.le;
|
|
341
341
|
}
|
|
342
342
|
if (i) verdictRead(t, r);
|
|
343
343
|
if (probing && heldNotFinal(n)) probeFound = true;
|
|
344
|
-
if (latestActive && e.
|
|
344
|
+
if (latestActive && e.ie !== NOT_PENDING) {
|
|
345
345
|
// An action body reading another transaction's proposal derives
|
|
346
346
|
// from it: the two settle as one (A15; posture C, 2026-09-15). An
|
|
347
347
|
// untracked read elsewhere has no transaction to entangle.
|
|
348
348
|
if (!i && flushTransaction !== null && !globalQueue.q) joinFuture(txOf(e));
|
|
349
349
|
return heldLatest(e, i ? t : null);
|
|
350
350
|
}
|
|
351
|
-
return e.
|
|
351
|
+
return e.le;
|
|
352
352
|
}
|
|
353
353
|
// Born into the future: its staging is its only value. It has no
|
|
354
354
|
// committed value, so no verdict: `isPending` reads it as its read does —
|
|
355
355
|
// the owner joins the hold (held with it, or caught by a boundary that
|
|
356
356
|
// has not shown content) and answers for the commit, where it is final.
|
|
357
|
-
if (e.
|
|
357
|
+
if (e.ie !== NOT_PENDING && !(n.m & STATUS_PENDING)) {
|
|
358
358
|
if (probing && r) joinPass(t, e);
|
|
359
359
|
return staged(e);
|
|
360
360
|
}
|
|
361
|
-
} else if (e.
|
|
361
|
+
} else if (e.ie !== NOT_PENDING) {
|
|
362
362
|
if (n.m & STATUS_PENDING && !u) pendingVerdict(i ? t : null, n); else if (i && globalQueue.q) provisionalVerdict(t, !latestActive && !u);
|
|
363
363
|
// Outside a flush, the staging is an unflushed write (A28): the probe
|
|
364
364
|
// answers for the flushed world, and watches the seam of the flush that
|
|
@@ -373,21 +373,21 @@ let probeFound = false;
|
|
|
373
373
|
if (globalQueue.q) return staged(e);
|
|
374
374
|
if (t !== null) markLateLinker(t);
|
|
375
375
|
}
|
|
376
|
-
return e.
|
|
376
|
+
return e.le;
|
|
377
377
|
}
|
|
378
378
|
if (n.m & STATUS_PENDING) {
|
|
379
379
|
if (!u) {
|
|
380
380
|
pendingVerdict(i ? t : null, n);
|
|
381
|
-
return e.
|
|
381
|
+
return e.le;
|
|
382
382
|
}
|
|
383
383
|
// As `read()`: an untracked read of a pending node still re-runs its
|
|
384
384
|
// reader when the node settles (a projection's pull reads its firewall
|
|
385
385
|
// untracked, store/store.ts).
|
|
386
386
|
if (t !== null && !tracking && !spectating && e !== t) link(e, t);
|
|
387
|
-
throw n.T?.
|
|
387
|
+
throw n.T?.U;
|
|
388
388
|
}
|
|
389
|
-
if (n.X !== undefined && n.m & STATUS_ERROR) throw n.T.
|
|
390
|
-
return e.
|
|
389
|
+
if (n.X !== undefined && n.m & STATUS_ERROR) throw n.T.U;
|
|
390
|
+
return e.le;
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
// Installed at module evaluation — present exactly when something imports
|
package/dist/prod/deferred.js
CHANGED
|
@@ -121,7 +121,7 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
121
121
|
* does not replace (D-40) — restaged as the committed value, the hold's
|
|
122
122
|
* readers would re-derive against the old input. */ const serve = e => {
|
|
123
123
|
const r = handleAsync(t, e);
|
|
124
|
-
return t.l & CONFIG_HELD && t.
|
|
124
|
+
return t.l & CONFIG_HELD && t.ie !== NOT_PENDING ? t.ie : r;
|
|
125
125
|
};
|
|
126
126
|
const end = () => t.R & REACTIVE_DISPOSED && land(o);
|
|
127
127
|
return accessor(computed(r => {
|
|
@@ -133,52 +133,51 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
133
133
|
// Sticky, and read before this wrapper ever opens the window itself.
|
|
134
134
|
const n = l ||= !(t.m & STATUS_UNINITIALIZED) && !t.ce;
|
|
135
135
|
if (n) t.ce = true, t.l |= CONFIG_LAGS;
|
|
136
|
-
let s;
|
|
137
136
|
try {
|
|
138
|
-
|
|
137
|
+
const t = e(r);
|
|
138
|
+
if (n && typeof t === "object" && t !== null) {
|
|
139
|
+
if (isThenable(t)) {
|
|
140
|
+
ask(t);
|
|
141
|
+
const done = () => land(t, true);
|
|
142
|
+
t.then(done, done);
|
|
143
|
+
return serve(t);
|
|
144
|
+
}
|
|
145
|
+
const e = t[Symbol.asyncIterator];
|
|
146
|
+
if (e) {
|
|
147
|
+
// A stream's flight ends at its first yield (or its end).
|
|
148
|
+
const r = e.call(t);
|
|
149
|
+
let o = true;
|
|
150
|
+
const done = () => land(n, true);
|
|
151
|
+
const n = {
|
|
152
|
+
// Registered ahead of the engine's own reaction to the same
|
|
153
|
+
// promise, as for a plain flight: verdict and value in one flush.
|
|
154
|
+
next: e => {
|
|
155
|
+
const t = r.next(e);
|
|
156
|
+
if (o) {
|
|
157
|
+
o = false;
|
|
158
|
+
if (isThenable(t)) t.then(done, done); else done();
|
|
159
|
+
}
|
|
160
|
+
return t;
|
|
161
|
+
},
|
|
162
|
+
return: e => r.return?.(e) ?? Promise.resolve({
|
|
163
|
+
done: true,
|
|
164
|
+
value: e
|
|
165
|
+
})
|
|
166
|
+
};
|
|
167
|
+
ask(n);
|
|
168
|
+
return serve({
|
|
169
|
+
[Symbol.asyncIterator]: () => n
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
land(o);
|
|
174
|
+
return t;
|
|
139
175
|
} catch (e) {
|
|
140
176
|
// The wrapping form: an unready source parks the node in the window,
|
|
141
177
|
// and the wait is its flight until the source's settle re-runs it.
|
|
142
178
|
if (n && e instanceof NotReadyError) ask(e); else land(o);
|
|
143
179
|
throw e;
|
|
144
180
|
}
|
|
145
|
-
if (n && typeof s === "object" && s !== null) {
|
|
146
|
-
if (isThenable(s)) {
|
|
147
|
-
ask(s);
|
|
148
|
-
const done = () => land(s, true);
|
|
149
|
-
s.then(done, done);
|
|
150
|
-
return serve(s);
|
|
151
|
-
}
|
|
152
|
-
const e = s[Symbol.asyncIterator];
|
|
153
|
-
if (e) {
|
|
154
|
-
// A stream's flight ends at its first yield (or its end).
|
|
155
|
-
const r = e.call(s);
|
|
156
|
-
let t = true;
|
|
157
|
-
const done = () => land(o, true);
|
|
158
|
-
const o = {
|
|
159
|
-
// Registered ahead of the engine's own reaction to the same
|
|
160
|
-
// promise, as for a plain flight: verdict and value in one flush.
|
|
161
|
-
next: e => {
|
|
162
|
-
const o = r.next(e);
|
|
163
|
-
if (t) {
|
|
164
|
-
t = false;
|
|
165
|
-
if (isThenable(o)) o.then(done, done); else done();
|
|
166
|
-
}
|
|
167
|
-
return o;
|
|
168
|
-
},
|
|
169
|
-
return: e => r.return?.(e) ?? Promise.resolve({
|
|
170
|
-
done: true,
|
|
171
|
-
value: e
|
|
172
|
-
})
|
|
173
|
-
};
|
|
174
|
-
ask(o);
|
|
175
|
-
return serve({
|
|
176
|
-
[Symbol.asyncIterator]: () => o
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
land(o);
|
|
181
|
-
return s;
|
|
182
181
|
}, r));
|
|
183
182
|
}
|
|
184
183
|
|
package/dist/prod/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export { $REFRESH, SUPPORTS_PROXY } from "./core/constants.js";
|
|
|
18
18
|
|
|
19
19
|
export { setConsoleFooter } from "./core/dev.js";
|
|
20
20
|
|
|
21
|
-
export { ROOT_ERROR_HOOK, enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
|
|
21
|
+
export { ROOT_ERROR_HOOK, clock, enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
|
|
22
22
|
|
|
23
23
|
import "./core/effect.js";
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ export { configureClientErrors } from "./core/error-hooks.js";
|
|
|
26
26
|
|
|
27
27
|
export { storeName } from "./store/edges.js";
|
|
28
28
|
|
|
29
|
-
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until } from "./signals.js";
|
|
29
|
+
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until } from "./signals.js";
|
|
30
30
|
|
|
31
31
|
export { mapArray, repeat } from "./map.js";
|
|
32
32
|
|