@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
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 +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -69,7 +69,7 @@ function disposeChildren(e, n = false, r) {
|
|
|
69
69
|
// cleanups never run and it stays subscribed, rerunning in a torn-down
|
|
70
70
|
// tree (#3561). Death only (`self`): a re-pass leaves the frame reacting
|
|
71
71
|
// until the commit.
|
|
72
|
-
if (n && !r && e.T !== null && (e.T.ft !== null || e.T.
|
|
72
|
+
if (n && !r && e.T !== null && (e.T.ft !== null || e.T.Tt !== null)) disposeChildren(e, false, true);
|
|
73
73
|
if (n) {
|
|
74
74
|
e.R = t | REACTIVE_DISPOSED;
|
|
75
75
|
if (e._parent === null && e.Pt) unregisterRoot(e);
|
|
@@ -116,7 +116,7 @@ function disposeChildren(e, n = false, r) {
|
|
|
116
116
|
// would still be holding.
|
|
117
117
|
l = l.Xe;
|
|
118
118
|
}
|
|
119
|
-
if (!r) e.
|
|
119
|
+
if (!r) e.At = 0;
|
|
120
120
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
121
121
|
// batch dispose (parent already disposed) and for a zombie (it sits on the
|
|
122
122
|
// parent's parked frame, drained whole by the commit). We leave
|
|
@@ -132,9 +132,9 @@ function disposeChildren(e, n = false, r) {
|
|
|
132
132
|
runDisposal(e, r);
|
|
133
133
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
134
134
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
135
|
-
if (n && e.
|
|
136
|
-
const n = e.
|
|
137
|
-
e.
|
|
135
|
+
if (n && e.Vt) {
|
|
136
|
+
const n = e.Vt;
|
|
137
|
+
e.Vt = undefined;
|
|
138
138
|
runCleanup(n);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -154,9 +154,9 @@ function runDisposal(e, n) {
|
|
|
154
154
|
// walk ran every entry a second time. Detached, the re-entrant drain finds
|
|
155
155
|
// nothing. The same shape latched a throwing cleanup: the list survived the
|
|
156
156
|
// throw and every later drain re-ran and re-threw it.
|
|
157
|
-
const r = n ? e.T.
|
|
157
|
+
const r = n ? e.T.Tt : e._t;
|
|
158
158
|
if (!r) return;
|
|
159
|
-
if (n) e.T.
|
|
159
|
+
if (n) e.T.Tt = null; else e._t = null;
|
|
160
160
|
if (Array.isArray(r)) {
|
|
161
161
|
// Unwind order (#3572, restores 1.x #1562): later registrations run
|
|
162
162
|
// before earlier ones. Children have already been disposed by the caller,
|
|
@@ -173,7 +173,7 @@ function runDisposal(e, n) {
|
|
|
173
173
|
function childId(e, n) {
|
|
174
174
|
let r = e;
|
|
175
175
|
while (r.l & CONFIG_TRANSPARENT && r._parent) r = r._parent;
|
|
176
|
-
if (r.id != null) return formatId(r.id, n ? r.
|
|
176
|
+
if (r.id != null) return formatId(r.id, n ? r.At++ : r.At);
|
|
177
177
|
throw new Error("");
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -255,7 +255,7 @@ function formatId(e, n) {
|
|
|
255
255
|
* one.
|
|
256
256
|
*/ function cleanup(e, n = context) {
|
|
257
257
|
if (!n) return e;
|
|
258
|
-
if (!n.
|
|
258
|
+
if (!n._t) n._t = e; else if (Array.isArray(n._t)) n._t.push(e); else n._t = [ n._t, e ];
|
|
259
259
|
return e;
|
|
260
260
|
}
|
|
261
261
|
|
|
@@ -282,7 +282,7 @@ function disposeRootSelf(e = true) {
|
|
|
282
282
|
disposeChildren(this, e);
|
|
283
283
|
// Outside a flush the dispose call rethrows; inside one, the flush does.
|
|
284
284
|
// Kept out of `disposeChildren`, whose hot path it slows.
|
|
285
|
-
if (cleanupError && !globalQueue.
|
|
285
|
+
if (cleanupError && !globalQueue.Y) rethrowCleanupError();
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
/**
|
|
@@ -309,13 +309,13 @@ function disposeRootSelf(e = true) {
|
|
|
309
309
|
// was 12 KB and most of disposal's time (2026-10-17).
|
|
310
310
|
R: REACTIVE_NONE,
|
|
311
311
|
Pt: true,
|
|
312
|
-
|
|
312
|
+
Ht: n?.Pt ? n.Ht : n,
|
|
313
313
|
ze: null,
|
|
314
314
|
Xe: null,
|
|
315
315
|
dt: null,
|
|
316
|
-
|
|
316
|
+
_t: null,
|
|
317
317
|
A: n?.A || defaultContext,
|
|
318
|
-
|
|
318
|
+
At: 0,
|
|
319
319
|
T: null,
|
|
320
320
|
_parent: n,
|
|
321
321
|
dispose: disposeRootSelf,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EFFECT_RENDER, EFFECT_USER, CONFIG_HELD, CONFIG_OVERRIDE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, CONFIG_STAGED, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_VERDICT, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, CONFIG_HELD_FRAME, REACTIVE_LANE_DIRTY, CONFIG_STAGED_ERROR, CONFIG_INPUTS_PUBLISHED, STATUS_ERROR, EFFECT_TRACKED, REACTIVE_MANUAL_WRITE, CONFIG_GUESS, REACTIVE_FRAME_READ, CONFIG_REDERIVE } from "./constants.js";
|
|
1
|
+
import { EFFECT_RENDER, EFFECT_USER, CONFIG_HELD, CONFIG_OVERRIDE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, CONFIG_STAGED, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_VERDICT, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, CONFIG_HELD_FRAME, REACTIVE_LANE_DIRTY, CONFIG_STAGED_ERROR, CONFIG_INPUTS_PUBLISHED, STATUS_ERROR, EFFECT_TRACKED, REACTIVE_MANUAL_WRITE, CONFIG_GUESS, REACTIVE_FRAME_READ, CONFIG_REDERIVE, CONFIG_FRAME } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { attrHooks } from "./attribution-hooks.js";
|
|
4
4
|
|
|
@@ -40,7 +40,21 @@ let endLanesHook = null;
|
|
|
40
40
|
|
|
41
41
|
let lanesBlockedHook = null;
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
/** R5 (lanes.ts `laneSeams` parks a frame flight): the landing's re-derive
|
|
44
|
+
* of a reader adopts the flight instead (true: adopted, nothing to queue). */ let laneAdoptHook = null;
|
|
45
|
+
|
|
46
|
+
/** core.ts `frameRead` served lane work or a verdict reader a held node's
|
|
47
|
+
* committed value (lanes.ts `laneServed`). */ let laneServedHook = null;
|
|
48
|
+
|
|
49
|
+
/** A guess was written (lanes.ts `optimisticWrite`): the arms only a guess
|
|
50
|
+
* reaches (CONFIG_GUESS) — a build without `createOptimistic` or
|
|
51
|
+
* `createOptimisticStore` never sets it, and its bundler folds them. */ let guessing = false;
|
|
52
|
+
|
|
53
|
+
function armGuessing() {
|
|
54
|
+
guessing = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function installLaneHooks(e, o, n, t, l, s, u, r, i, a, f) {
|
|
44
58
|
laneReadHook = e;
|
|
45
59
|
laneStageHook = o;
|
|
46
60
|
laneOutcomeHook = n;
|
|
@@ -50,6 +64,8 @@ function installLaneHooks(e, o, n, t, l, s, u, r, i) {
|
|
|
50
64
|
laneCorrectionsHook = u;
|
|
51
65
|
endLanesHook = r;
|
|
52
66
|
lanesBlockedHook = i;
|
|
67
|
+
laneAdoptHook = a;
|
|
68
|
+
laneServedHook = f;
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
// Boundaries (boundaries.ts): the display consumers between an observer
|
|
@@ -109,8 +125,12 @@ function installMarkHooks(e, o) {
|
|
|
109
125
|
|
|
110
126
|
/** Verdicts (verdict.ts). */ let observeFlightHook = null;
|
|
111
127
|
|
|
112
|
-
|
|
128
|
+
/** D-25's hold work (verdict.ts `holdWork`): on `source` going pending,
|
|
129
|
+
* whether verdict reader `n` waits on it instead of re-deriving. */ let holdWorkHook = null;
|
|
130
|
+
|
|
131
|
+
function installVerdictHooks(e, o) {
|
|
113
132
|
observeFlightHook = e;
|
|
133
|
+
holdWorkHook = o;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
/** External-source bridge (wired by enableExternalSource(); undefined while
|
|
@@ -131,7 +151,7 @@ function setExternalHooks(e, o) {
|
|
|
131
151
|
/** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e, o = null) {
|
|
132
152
|
const n = {
|
|
133
153
|
Ye: [],
|
|
134
|
-
|
|
154
|
+
rn: [ [], [] ],
|
|
135
155
|
En: [],
|
|
136
156
|
eo: null,
|
|
137
157
|
_parent: o,
|
|
@@ -140,7 +160,7 @@ function setExternalHooks(e, o) {
|
|
|
140
160
|
tt: 0,
|
|
141
161
|
nt: false,
|
|
142
162
|
nn: null,
|
|
143
|
-
|
|
163
|
+
Nt: false,
|
|
144
164
|
ln: false,
|
|
145
165
|
I: null
|
|
146
166
|
};
|
|
@@ -175,6 +195,10 @@ function setPassLane(e) {
|
|
|
175
195
|
* schedules the seam that consumes it: membership is the tick's — the same
|
|
176
196
|
* synchronous frame — and the next tick's writes are not this one's. */ let flushTransaction = null;
|
|
177
197
|
|
|
198
|
+
/** The flush's transaction while only a `latest()` read of a staging opened
|
|
199
|
+
* it (verdict.ts `provisionalVerdict`): it holds nothing, and a verdict
|
|
200
|
+
* reader's plain read of a staging in it is the frame's read (D-22). */ let latestOpened = null;
|
|
201
|
+
|
|
178
202
|
/** The transaction the passes running OUTSIDE a flush this tick derive from
|
|
179
203
|
* (a mainline mount, a mainline re-pass): the passes' own (A29, creation-
|
|
180
204
|
* time form — "the entry is the pass's alone"): their results are staged
|
|
@@ -189,7 +213,7 @@ function setPassLane(e) {
|
|
|
189
213
|
* set it. */ let passTx = null;
|
|
190
214
|
|
|
191
215
|
function joinPassTx(e, o) {
|
|
192
|
-
if (globalQueue.
|
|
216
|
+
if (globalQueue.Y && !o || flushTransaction !== null) return joinFuture(e);
|
|
193
217
|
if (passTx === null) passTx = resolveTx(e); else merge(resolveTx(e), passTx);
|
|
194
218
|
schedule();
|
|
195
219
|
}
|
|
@@ -217,7 +241,7 @@ function resolveTx(e) {
|
|
|
217
241
|
if (o === null) {
|
|
218
242
|
flushTransaction = e === null ? newTransaction(false) : resolveTx(e);
|
|
219
243
|
} else if (e !== null) merge(resolveTx(e), o);
|
|
220
|
-
if (!globalQueue.
|
|
244
|
+
if (!globalQueue.Y) schedule();
|
|
221
245
|
}
|
|
222
246
|
|
|
223
247
|
/** `t` merges into `f`: the work that touched both entangles them (A15).
|
|
@@ -233,8 +257,8 @@ function resolveTx(e) {
|
|
|
233
257
|
o.tt += e.tt;
|
|
234
258
|
o.nt ||= e.nt;
|
|
235
259
|
append(o.Ye, e.Ye);
|
|
236
|
-
append(o.
|
|
237
|
-
append(o.
|
|
260
|
+
append(o.rn[0], e.rn[0]);
|
|
261
|
+
append(o.rn[1], e.rn[1]);
|
|
238
262
|
append(o.En, e.En);
|
|
239
263
|
if (e.I !== null) append(o.I ??= [], e.I);
|
|
240
264
|
transactions.splice(transactions.indexOf(e), 1);
|
|
@@ -323,7 +347,7 @@ function blockedBy(e, o, n = false) {
|
|
|
323
347
|
// lane-membership ruling, 2026-10-05). An output that never committed
|
|
324
348
|
// shows nothing — a mount the frame has not revealed — and holds
|
|
325
349
|
// nothing.
|
|
326
|
-
if ((n.i === EFFECT_RENDER && n.m & STATUS_PENDING || n.R & REACTIVE_FRAME_READ || n.l & CONFIG_REDERIVE && n.m === STATUS_PENDING) && (e.
|
|
350
|
+
if ((n.i === EFFECT_RENDER && n.m & STATUS_PENDING || n.R & REACTIVE_FRAME_READ || n.l & CONFIG_REDERIVE && n.m === STATUS_PENDING) && (e.de === n.Ne || n.T?.U != null) && !(n.R & REACTIVE_DISPOSED) && onScreen(n, judge ?? o)) return true;
|
|
327
351
|
}
|
|
328
352
|
}
|
|
329
353
|
return false;
|
|
@@ -425,10 +449,10 @@ function deferZombie(e) {
|
|
|
425
449
|
}
|
|
426
450
|
|
|
427
451
|
const dirtyQueue = {
|
|
428
|
-
|
|
452
|
+
jt: new Array(2e3).fill(undefined),
|
|
429
453
|
p: false,
|
|
430
|
-
|
|
431
|
-
|
|
454
|
+
Et: 0,
|
|
455
|
+
yt: 0
|
|
432
456
|
};
|
|
433
457
|
|
|
434
458
|
let clock = 0;
|
|
@@ -491,7 +515,7 @@ function schedule() {
|
|
|
491
515
|
}
|
|
492
516
|
if (scheduled) return;
|
|
493
517
|
scheduled = true;
|
|
494
|
-
if (!syncDepth && !globalQueue.
|
|
518
|
+
if (!syncDepth && !globalQueue.Y) {
|
|
495
519
|
queueMicrotask(flush);
|
|
496
520
|
}
|
|
497
521
|
}
|
|
@@ -553,11 +577,11 @@ function notifyHalted() {
|
|
|
553
577
|
}
|
|
554
578
|
|
|
555
579
|
class GlobalQueue {
|
|
556
|
-
|
|
557
|
-
|
|
580
|
+
rn=[ [], [] ];
|
|
581
|
+
Y=false;
|
|
558
582
|
flush() {
|
|
559
|
-
if (this.
|
|
560
|
-
this.
|
|
583
|
+
if (this.Y) return;
|
|
584
|
+
this.Y = true;
|
|
561
585
|
// A28: companions of nodes written since the last flush mirror the
|
|
562
586
|
// flushed world — re-synced inside the running window (the write is
|
|
563
587
|
// "flushed" from here on).
|
|
@@ -575,7 +599,7 @@ class GlobalQueue {
|
|
|
575
599
|
clock++;
|
|
576
600
|
// A write the commit sweep staged with no subscriber to dirty is work
|
|
577
601
|
// too — the next round commits it.
|
|
578
|
-
scheduled = dirtyQueue.
|
|
602
|
+
scheduled = dirtyQueue.yt >= dirtyQueue.Et || pendingNodes.length !== 0;
|
|
579
603
|
this.run(EFFECT_RENDER);
|
|
580
604
|
this.run(EFFECT_USER);
|
|
581
605
|
if (true && holding) {
|
|
@@ -585,7 +609,7 @@ class GlobalQueue {
|
|
|
585
609
|
if (false && !scheduled) ;
|
|
586
610
|
if (false) ;
|
|
587
611
|
} finally {
|
|
588
|
-
this.
|
|
612
|
+
this.Y = false;
|
|
589
613
|
passTx = null;
|
|
590
614
|
}
|
|
591
615
|
}
|
|
@@ -600,7 +624,7 @@ class GlobalQueue {
|
|
|
600
624
|
// pure round — the parent's flights before the parent is judged below.
|
|
601
625
|
if (laneCorrectionsHook?.()) runHeap(dirtyQueue, GlobalQueue.Ze);
|
|
602
626
|
const e = flushTransaction;
|
|
603
|
-
flushTransaction = null;
|
|
627
|
+
flushTransaction = latestOpened = null;
|
|
604
628
|
// The frame's verdict is in: the guesses written since the last seam
|
|
605
629
|
// open their lane under the frame's transaction (a lane's own flush
|
|
606
630
|
// parents a nested lane to it), or are dropped — the frame commits, and
|
|
@@ -629,18 +653,18 @@ class GlobalQueue {
|
|
|
629
653
|
// stale stamp was the bridge that entangled unrelated updates
|
|
630
654
|
// with a never-resolving flight). Its observers are held and
|
|
631
655
|
// wait on its flight (`blocked`).
|
|
632
|
-
if (e.
|
|
656
|
+
if (e.ue === NOT_PENDING && e.m & STATUS_UNINITIALIZED && e.i !== EFFECT_RENDER) continue;
|
|
633
657
|
// A34 (2): a tick whose writes net to the committed value made no
|
|
634
658
|
// proposal (`setShow(false); setShow(true)` on a committed true) —
|
|
635
659
|
// not staged, not held, pends nothing; a later write to it is
|
|
636
660
|
// plain mainline. (A node already held stays held when written
|
|
637
661
|
// back: A34 (1).)
|
|
638
|
-
if (e.
|
|
662
|
+
if (e.ue !== NOT_PENDING && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.T?.ft == null && e.T?.Tt == null &&
|
|
639
663
|
// The comparator last: a pass that created children (an object
|
|
640
664
|
// owning a fresh async memo, #4111) must not have it read them.
|
|
641
665
|
// A NotReady read there is a change (`isSame`).
|
|
642
|
-
isSame(e, e.le, e.
|
|
643
|
-
e.
|
|
666
|
+
isSame(e, e.le, e.ue)) {
|
|
667
|
+
e.ue = NOT_PENDING;
|
|
644
668
|
e.l &= ~CONFIG_STAGED;
|
|
645
669
|
continue;
|
|
646
670
|
}
|
|
@@ -665,7 +689,7 @@ class GlobalQueue {
|
|
|
665
689
|
// (Verdict readers exist only with the verdict engine installed.)
|
|
666
690
|
const n = deferredZombies.splice(0);
|
|
667
691
|
if (observeFlightHook) {
|
|
668
|
-
n.sort((e, o) => e.
|
|
692
|
+
n.sort((e, o) => e.lt - o.lt);
|
|
669
693
|
for (let e = 0; e < n.length; e++) if ((n[e].R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE && n[e].l & CONFIG_VERDICT) recompute(n[e]);
|
|
670
694
|
}
|
|
671
695
|
// The unchanged passes' tails stay linked (A30, #3469): their inputs
|
|
@@ -679,7 +703,7 @@ class GlobalQueue {
|
|
|
679
703
|
// `recompute`'s own gates.
|
|
680
704
|
for (let e = 0; e < heldTrims.length; e++) {
|
|
681
705
|
const o = heldTrims[e];
|
|
682
|
-
if (o.T?.
|
|
706
|
+
if (o.T?.U == null && !o.Qe) trimStaleDeps(o);
|
|
683
707
|
}
|
|
684
708
|
}
|
|
685
709
|
// The list is the flush's either way. Reset only when there is something
|
|
@@ -693,17 +717,17 @@ class GlobalQueue {
|
|
|
693
717
|
// removes its entry.
|
|
694
718
|
// This flush's own runs, the lanes' reveals, and the landings' held runs
|
|
695
719
|
// are collected apart and ordered below.
|
|
696
|
-
const n = this.
|
|
720
|
+
const n = this.rn;
|
|
697
721
|
const t = [ [], [] ];
|
|
698
722
|
// The passes that read this frame's stagings as the screen read held
|
|
699
723
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
700
724
|
// world (a lane's runs wait this round).
|
|
701
725
|
if (laneSeamsHook) {
|
|
702
|
-
this.
|
|
703
|
-
laneSeamsHook(o
|
|
726
|
+
this.rn = t;
|
|
727
|
+
laneSeamsHook(o);
|
|
704
728
|
if (stagedReaders.length) stagedReaders.length = 0;
|
|
705
729
|
}
|
|
706
|
-
this.
|
|
730
|
+
this.rn = [ [], [] ];
|
|
707
731
|
for (let e = transactions.length - 1; e >= 0; e--) {
|
|
708
732
|
const o = transactions[e];
|
|
709
733
|
if (blocked(o)) continue;
|
|
@@ -741,17 +765,17 @@ class GlobalQueue {
|
|
|
741
765
|
holding = true;
|
|
742
766
|
}
|
|
743
767
|
for (let e = 0; e < 2; e++) {
|
|
744
|
-
if (s) append(l.
|
|
768
|
+
if (s) append(l.rn[e], n[e]);
|
|
745
769
|
// The plain flush — no reveal, no landing, not parked — has nothing to
|
|
746
770
|
// order around its own runs: they are the queue as they stand (the
|
|
747
771
|
// same array, not a copy; `run` takes it whole). Every other seam
|
|
748
772
|
// builds the ordered queue above.
|
|
749
|
-
this.
|
|
773
|
+
this.rn[e] = s || t[e].length || this.rn[e].length ? t[e].concat(s ? [] : n[e], this.rn[e]) : n[e];
|
|
750
774
|
}
|
|
751
775
|
if (deferredZombies.length !== 0) {
|
|
752
776
|
// Survivors are the displayed frame of a held pass: they rerun for the
|
|
753
777
|
// live write, parents before children.
|
|
754
|
-
const e = deferredZombies.splice(0).sort((e, o) => e.
|
|
778
|
+
const e = deferredZombies.splice(0).sort((e, o) => e.lt - o.lt);
|
|
755
779
|
for (let o = 0; o < e.length; o++) {
|
|
756
780
|
if (!(e[o].R & REACTIVE_DISPOSED)) recompute(e[o]);
|
|
757
781
|
}
|
|
@@ -761,9 +785,9 @@ class GlobalQueue {
|
|
|
761
785
|
boundarySeamHook?.();
|
|
762
786
|
}
|
|
763
787
|
run(e) {
|
|
764
|
-
const o = this.
|
|
788
|
+
const o = this.rn[e - 1];
|
|
765
789
|
if (o.length) {
|
|
766
|
-
this.
|
|
790
|
+
this.rn[e - 1] = [];
|
|
767
791
|
runQueue(o, e);
|
|
768
792
|
}
|
|
769
793
|
}
|
|
@@ -772,7 +796,7 @@ class GlobalQueue {
|
|
|
772
796
|
// the frame (which may park). A lane pass that read the frame's own
|
|
773
797
|
// staging is the frame's (`recompute` passes null): its run waits with
|
|
774
798
|
// the frame.
|
|
775
|
-
if (e) (n !== null ? n : this).
|
|
799
|
+
if (e) (n !== null ? n : this).rn[e - 1].push(o);
|
|
776
800
|
schedule();
|
|
777
801
|
}
|
|
778
802
|
/** Status reaching the root: pending is absorbed (the root mount defers —
|
|
@@ -828,17 +852,39 @@ class GlobalQueue {
|
|
|
828
852
|
const t = e.En[n];
|
|
829
853
|
// An errored reader's display is its error (D-39): the landing gives it
|
|
830
854
|
// nothing to re-derive, and a re-run would be a read that retries the
|
|
831
|
-
// errored source (#3945)
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
855
|
+
// errored source (#3945) — unless that source is errored no longer: the
|
|
856
|
+
// reader was served a shown error the landing replaces (`throwShown`).
|
|
857
|
+
// Nor is the reader's own error: its pass threw over the committed value
|
|
858
|
+
// of what the landing carries, served as the screen (A10; a lane's node
|
|
859
|
+
// reading its parent's hold, or a pass with no value yet reading a
|
|
860
|
+
// staging, `stagedScreen`) — the landing is the new answer, and the
|
|
861
|
+
// reader re-derives on it (A15; D-39). A first load read so has no other
|
|
862
|
+
// run: its error would stay the screen (async-gen 91501 #1158, #119).
|
|
863
|
+
// A boundary's structure (its tree, its output: CONFIG_FRAME, no effect
|
|
864
|
+
// type) re-derives all the same: what it read as the screen is the
|
|
865
|
+
// content the landing replaces, and only its pass links the new content
|
|
866
|
+
// whose recovery must reach it (D-3, D-39, #4405).
|
|
867
|
+
const l = t.T?.U?.source;
|
|
868
|
+
if (t.R & REACTIVE_DISPOSED || t.m & STATUS_ERROR && (t.i || !(t.l & CONFIG_FRAME)) && l !== t && (l?.m ?? STATUS_ERROR) & STATUS_ERROR) continue;
|
|
869
|
+
if (t.R & REACTIVE_FRAME_READ || observeFlightHook && t.l & CONFIG_VERDICT) {
|
|
870
|
+
// A memo re-deriving its own error holds the release as an effect
|
|
871
|
+
// does (`land`): run first, the held runs showed that error beside a
|
|
872
|
+
// frame about to replace it (#4407; #4284: the grouping never changes
|
|
873
|
+
// the screen).
|
|
874
|
+
o ||= t.i || l === t;
|
|
875
|
+
// A lane's reveal leaves the mark to the transaction: a reader that
|
|
876
|
+
// also read a held node as committed (`staleReader`) still observes
|
|
877
|
+
// that flight until it re-runs — cleared here, the transaction landed
|
|
878
|
+
// at this seam with the flight up and voided the reveal's run (#4397).
|
|
879
|
+
if (!e.V) t.R &= ~REACTIVE_FRAME_READ;
|
|
836
880
|
t.Qe = false;
|
|
837
881
|
// Its frame is replaced by the re-derivation: a run one of its
|
|
838
882
|
// children queued this flush (re-run by the same landing) is for the
|
|
839
883
|
// frame being replaced — void too (#3404).
|
|
840
884
|
for (let e = t.ze; e !== null; e = e.Xe) if (e.i) e.Qe = false;
|
|
841
|
-
|
|
885
|
+
// A frame flight the seam parked (lanes.ts `laneSeams`, R5) asked the
|
|
886
|
+
// question this landing would: adopted, it is asked once (F-9).
|
|
887
|
+
if (!laneAdoptHook?.(t)) enqueueSub(t);
|
|
842
888
|
}
|
|
843
889
|
}
|
|
844
890
|
e.En.length = 0;
|
|
@@ -872,7 +918,7 @@ class GlobalQueue {
|
|
|
872
918
|
// value. Queued last in this effect phase, the release hands them to the
|
|
873
919
|
// next round's own runs, ahead of the re-derivation's: they show with it,
|
|
874
920
|
// or park with it in the hold its pending opens. The commits stand.
|
|
875
|
-
if (o) globalQueue.
|
|
921
|
+
if (o) globalQueue.rn[1].push(() => releaseQueues(e)); else releaseQueues(e);
|
|
876
922
|
}
|
|
877
923
|
|
|
878
924
|
/** The held runs join this flush's effect phase after its own runs (the
|
|
@@ -880,8 +926,8 @@ class GlobalQueue {
|
|
|
880
926
|
* pass would have queued them — a shell re-derived at the landing before a
|
|
881
927
|
* boundary swap held since the write (#3540's log order). */ function releaseQueues(e) {
|
|
882
928
|
for (let o = 0; o < 2; o++) {
|
|
883
|
-
append(globalQueue.
|
|
884
|
-
e.
|
|
929
|
+
append(globalQueue.rn[o], e.rn[o]);
|
|
930
|
+
e.rn[o] = [];
|
|
885
931
|
}
|
|
886
932
|
}
|
|
887
933
|
|
|
@@ -907,7 +953,7 @@ class GlobalQueue {
|
|
|
907
953
|
|
|
908
954
|
function queuePendingNode(e) {
|
|
909
955
|
pendingNodes.push(e);
|
|
910
|
-
if (!globalQueue.
|
|
956
|
+
if (!globalQueue.Y) markUnflushedStaged();
|
|
911
957
|
// A28
|
|
912
958
|
}
|
|
913
959
|
|
|
@@ -923,7 +969,7 @@ function bumpNotifyEpoch() {
|
|
|
923
969
|
function insertSubs(e) {
|
|
924
970
|
// §12d: stamp before walking — setSignal's staged-rewrite fast path skips
|
|
925
971
|
// the next walk for this node while the epoch holds (marking is idempotent).
|
|
926
|
-
e.
|
|
972
|
+
e.Dt = notifyEpoch;
|
|
927
973
|
// Presence bits gate the optional-slot probes (see constants.ts): one
|
|
928
974
|
// masked read of the always-present _config instead of missing-property
|
|
929
975
|
// lookups in the hottest notify loop.
|
|
@@ -943,7 +989,7 @@ function insertSubs(e) {
|
|
|
943
989
|
// pass either re-reads them fresh or trims them), and neither does the
|
|
944
990
|
// tail link: it is the read IN FLIGHT — read() links before it pulls, so
|
|
945
991
|
// this very commit is what that read returns.
|
|
946
|
-
if (e.R & REACTIVE_RECOMPUTING_DEPS && o.
|
|
992
|
+
if (e.R & REACTIVE_RECOMPUTING_DEPS && o.de === e.Ne && o !== e._) e.R |= REACTIVE_MISSED_WAKE;
|
|
947
993
|
if (n && e.l & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
948
994
|
e.R |= REACTIVE_SNAPSHOT_STALE;
|
|
949
995
|
continue;
|
|
@@ -960,10 +1006,19 @@ function insertSubs(e) {
|
|
|
960
1006
|
* inert for its pass (`recompute` seats a lane only from its own `_x`), it
|
|
961
1007
|
* is a live write if the effect becomes a zombie later this flush — an
|
|
962
1008
|
* on-screen reader whose removal an adopted write stages follows the lane
|
|
963
|
-
* (the lane-membership ruling, 2026-10-05; `_update`).
|
|
1009
|
+
* (the lane-membership ruling, 2026-10-05; `_update`).
|
|
1010
|
+
*
|
|
1011
|
+
* A render effect re-run by a verdict memo's change (`createMemo(() =>
|
|
1012
|
+
* latest(x))`, CONFIG_VERDICT) is the verdict reader the same read inline
|
|
1013
|
+
* makes it, for that pass (F-6; D-26 `[s(), L()]`, #4284): a frame reader
|
|
1014
|
+
* of its other reads — a staging's screen, a flight's committed value. One
|
|
1015
|
+
* an earlier propagation this flush seated in another lane leaves that
|
|
1016
|
+
* seat: its pass starts from the frame's, as the inline effect's does, and
|
|
1017
|
+
* `laneRead` re-derives it on the screen if that lane holds (`entered`). */ function laneDirty(e, o) {
|
|
964
1018
|
for (let n = e.o; n !== null; n = n.t) {
|
|
965
|
-
const
|
|
966
|
-
if (
|
|
1019
|
+
const t = n.u, l = t.T?.Je;
|
|
1020
|
+
if (t.i === EFFECT_RENDER && e.l & CONFIG_VERDICT) t.l |= CONFIG_VERDICT, t.R &= ~REACTIVE_LANE_DIRTY;
|
|
1021
|
+
if (l?.V ? sameLane(l, o) : t.i) t.R |= REACTIVE_LANE_DIRTY;
|
|
967
1022
|
}
|
|
968
1023
|
}
|
|
969
1024
|
|
|
@@ -980,44 +1035,44 @@ function commitPendingNode(e) {
|
|
|
980
1035
|
// commits a value.
|
|
981
1036
|
if (!o.X) {
|
|
982
1037
|
e.l &= -385;
|
|
983
|
-
if (e.
|
|
984
|
-
e.le = e.
|
|
985
|
-
e.
|
|
1038
|
+
if (e.ue !== NOT_PENDING) {
|
|
1039
|
+
e.le = e.ue;
|
|
1040
|
+
e.ue = NOT_PENDING;
|
|
986
1041
|
}
|
|
987
1042
|
return;
|
|
988
1043
|
}
|
|
989
1044
|
// Computeds only from here (`_statusFlags` is not a signal field). A
|
|
990
1045
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
991
1046
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
992
|
-
const n = e.
|
|
1047
|
+
const n = e.ue === NOT_PENDING && (o.m & STATUS_PENDING) !== 0;
|
|
993
1048
|
const t = e.l & CONFIG_STAGED_ERROR;
|
|
994
1049
|
// An answer commits: the error it replaces leaves the display (D-41).
|
|
995
|
-
if (!n && o.T) o.T.Te =
|
|
1050
|
+
if (!n && o.T) o.T.Te = null;
|
|
996
1051
|
e.l = n ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
|
|
997
1052
|
// D-41: the staged answer is an error — published now, when a value would
|
|
998
1053
|
// show, through the ordinary error path (`stageError`). Its readers first
|
|
999
1054
|
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
1000
1055
|
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
1001
1056
|
if (t) {
|
|
1002
|
-
const n = e.
|
|
1003
|
-
e.
|
|
1004
|
-
e.
|
|
1057
|
+
const n = e.ue;
|
|
1058
|
+
e.ue = NOT_PENDING;
|
|
1059
|
+
e.ie = clock + 1;
|
|
1005
1060
|
notifyStatus(o, STATUS_ERROR, n);
|
|
1006
|
-
} else if (e.
|
|
1007
|
-
e.le = e.
|
|
1008
|
-
e.
|
|
1061
|
+
} else if (e.ue !== NOT_PENDING) {
|
|
1062
|
+
e.le = e.ue;
|
|
1063
|
+
e.ue = NOT_PENDING;
|
|
1009
1064
|
// A node born staged (recompute) initializes at this commit.
|
|
1010
1065
|
o.m &= ~STATUS_UNINITIALIZED;
|
|
1011
1066
|
// A quiet re-ask's classification survives its landing and dies with
|
|
1012
1067
|
// the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
|
|
1013
1068
|
// the reveal. (The sweep of a node still in flight is not a landing.)
|
|
1014
1069
|
// The A28 stash goes with it.
|
|
1015
|
-
if (o.T != null) o.T.ut = false, o.T.
|
|
1070
|
+
if (o.T != null) o.T.ut = false, o.T.Ft = NOT_PENDING;
|
|
1016
1071
|
// An effect with a staged value was born held (L2): its first run is
|
|
1017
1072
|
// this commit's, not its creation's (A29) — queue it now.
|
|
1018
1073
|
if (e.i && e.i !== EFFECT_TRACKED) {
|
|
1019
1074
|
e.Qe = true;
|
|
1020
|
-
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.
|
|
1075
|
+
globalQueue.enqueue(e.i, e.W ??= GlobalQueue.q.bind(null, o));
|
|
1021
1076
|
}
|
|
1022
1077
|
}
|
|
1023
1078
|
// The committed value is the first observable answer for a loading-window
|
|
@@ -1031,11 +1086,11 @@ function commitPendingNode(e) {
|
|
|
1031
1086
|
// pass or by the node's own landing (whose pass was clean), so a set
|
|
1032
1087
|
// `_error` means the last pass threw, kept its full list, and `_depsTail`
|
|
1033
1088
|
// marks where it stopped.
|
|
1034
|
-
if (o.T?.
|
|
1089
|
+
if (o.T?.U == null) trimStaleDeps(o);
|
|
1035
1090
|
if (!(o.m & STATUS_PENDING)) o.m &= ~STATUS_UNINITIALIZED;
|
|
1036
1091
|
// L2: the children this commit publishes are the frame's now — the frame
|
|
1037
1092
|
// they replace, parked by the pass (`recompute`), goes.
|
|
1038
|
-
if (!n && o.T != null && (o.T.ft !== null || o.T.
|
|
1093
|
+
if (!n && o.T != null && (o.T.ft !== null || o.T.Tt !== null)) GlobalQueue.et(o, false, true);
|
|
1039
1094
|
}
|
|
1040
1095
|
|
|
1041
1096
|
function commitPendingNodes() {
|
|
@@ -1069,7 +1124,7 @@ function flush(e) {
|
|
|
1069
1124
|
}
|
|
1070
1125
|
}
|
|
1071
1126
|
}
|
|
1072
|
-
if (globalQueue.
|
|
1127
|
+
if (globalQueue.Y) {
|
|
1073
1128
|
return;
|
|
1074
1129
|
}
|
|
1075
1130
|
if (halted) return;
|
|
@@ -1099,4 +1154,4 @@ function runQueue(e, o) {
|
|
|
1099
1154
|
for (let n = 0; n < e.length; n++) e[n](o);
|
|
1100
1155
|
}
|
|
1101
1156
|
|
|
1102
|
-
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, blockersOf, 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 };
|
|
1157
|
+
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, armGuessing, blocked, blockersOf, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, guessing, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, holdWorkHook, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneAdoptHook, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneServedHook, laneStageHook, laneWriteHook, lanesBlockedHook, latestOpened, 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 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONFIG_GUESS, NOT_PENDING, CONFIG_AUTHORITATIVE, CONFIG_OVERRIDE } from "./constants.js";
|
|
1
|
+
import { CONFIG_GUESS, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_AUTHORITATIVE, CONFIG_OVERRIDE } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { NotReadyError } from "./error.js";
|
|
4
4
|
|
|
@@ -10,11 +10,13 @@ import { enqueueSub } from "./heap.js";
|
|
|
10
10
|
// which exists once something installs lanes (`createOptimistic`, verdicts).
|
|
11
11
|
/** A lane node's current value: its guess, or the latest it derived — the
|
|
12
12
|
* staging a shown lane holds for its next reveal, else its slot; the
|
|
13
|
-
* committed value while it has none (its first lane pass in flight)
|
|
13
|
+
* committed value while it has none (its first lane pass in flight) —
|
|
14
|
+
* NOT_PENDING for a node with no committed value either (born in the lane,
|
|
15
|
+
* uninitialized: its reads throw NotReady, A7; #4363). */
|
|
14
16
|
function laneValueOf(r) {
|
|
15
|
-
if (!(r.l & CONFIG_GUESS) && r.
|
|
17
|
+
if (!(r.l & CONFIG_GUESS) && r.ue !== NOT_PENDING) return r.ue;
|
|
16
18
|
const t = r.T.V;
|
|
17
|
-
return t !== NOT_PENDING ? t : r.le;
|
|
19
|
+
return t !== NOT_PENDING || r.m & STATUS_UNINITIALIZED ? t : r.le;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/** Truth readers (`until`, `refresh`; CONFIG_AUTHORITATIVE) — pay-for-use:
|
|
@@ -25,7 +27,7 @@ function laneValueOf(r) {
|
|
|
25
27
|
* value. */ function truthRead(r) {
|
|
26
28
|
if (truth(r)) return laneValueOf(r);
|
|
27
29
|
if (!(r.l & CONFIG_GUESS)) throw new NotReadyError(null);
|
|
28
|
-
return r.
|
|
30
|
+
return r.ue !== NOT_PENDING ? r.ue : r.le;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/** A guess confirmed: its lane's truth readers re-read — of the lane's
|
|
@@ -36,8 +38,8 @@ function laneValueOf(r) {
|
|
|
36
38
|
/** A lane node's value is the truth when every guess beneath it is
|
|
37
39
|
* confirmed — its source staged a value equal to the guess — and nothing
|
|
38
40
|
* 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.
|
|
41
|
+
if (r.l & CONFIG_GUESS) return r.ue !== NOT_PENDING && r.je && r.je(r.T.V, r.ue);
|
|
42
|
+
if (r.ue !== NOT_PENDING) return;
|
|
41
43
|
if (r.l & CONFIG_OVERRIDE) for (let t = r.C; t; t = t.G) if (!truth(t.S)) return;
|
|
42
44
|
return 1;
|
|
43
45
|
}
|