@solidjs/signals 2.0.0-rc.7 → 2.0.0-rc.8
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 +5243 -0
- package/dist/dev.attribution.js +2333 -0
- package/dist/dev.js +1229 -6834
- package/dist/observe/affects.js +127 -0
- package/dist/observe/attribution.js +1 -0
- package/dist/observe/boundaries.js +586 -0
- package/dist/observe/core/action.js +167 -0
- package/dist/observe/core/async.js +736 -0
- package/dist/observe/core/attribution-hooks.js +60 -0
- package/dist/observe/core/attribution.js +2318 -0
- package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +129 -73
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1289 -0
- package/dist/observe/core/dev.js +232 -0
- package/dist/observe/core/effect.js +179 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +43 -0
- package/dist/observe/core/lanes.js +168 -0
- package/dist/observe/core/optimistic.js +438 -0
- package/dist/observe/core/owner.js +308 -0
- package/dist/observe/core/scheduler.js +1190 -0
- package/dist/observe/core/verdict.js +551 -0
- package/dist/observe/index.js +55 -0
- package/dist/observe/map.js +482 -0
- package/dist/{types-cjs/signals.d.cts → observe/signals.js} +295 -317
- package/dist/observe/store/index.js +38 -0
- package/dist/observe/store/next/optimistic.js +651 -0
- package/dist/observe/store/next/projection.js +242 -0
- package/dist/observe/store/next/reconcile.js +373 -0
- package/dist/observe/store/next/store.js +2213 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +323 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +210 -0
- package/dist/prod/attribution.js +32 -0
- package/dist/prod/core/action.js +52 -32
- package/dist/prod/core/async.js +171 -127
- package/dist/prod/core/constants.js +24 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +434 -291
- package/dist/prod/core/effect.js +54 -34
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +32 -32
- package/dist/prod/core/heap.js +49 -44
- package/dist/prod/core/lanes.js +45 -38
- package/dist/prod/core/optimistic.js +207 -73
- package/dist/prod/core/owner.js +43 -39
- package/dist/prod/core/scheduler.js +319 -190
- package/dist/prod/core/verdict.js +67 -67
- package/dist/prod/index.js +9 -3
- package/dist/prod/map.js +292 -141
- package/dist/prod/signals.js +7 -10
- package/dist/prod/store/next/optimistic.js +140 -125
- package/dist/prod/store/next/projection.js +3 -3
- package/dist/prod/store/next/reconcile.js +87 -84
- package/dist/prod/store/next/store.js +524 -280
- package/dist/prod/store/next/target.js +32 -10
- package/dist/prod/store/store.js +12 -14
- package/dist/prod/store/utils.js +36 -27
- package/dist/types/attribution.d.ts +15 -0
- package/dist/types/attribution.prod.d.ts +13 -0
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/attribution-hooks.d.ts +119 -6
- package/dist/types/core/attribution.d.ts +208 -53
- package/dist/types/core/constants.d.ts +23 -0
- package/dist/types/core/core.d.ts +7 -0
- package/dist/types/core/dev.d.ts +124 -26
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +60 -0
- package/dist/types/core/types.d.ts +29 -9
- package/dist/types/index.d.ts +9 -2
- package/dist/types/map.d.ts +2 -0
- package/dist/types/store/index.d.ts +1 -0
- package/dist/types/store/next/store.d.ts +5 -0
- package/dist/types/store/next/target.d.ts +36 -9
- package/dist/types/store/utils.d.ts +7 -0
- package/package.json +21 -17
- package/dist/node.cjs +0 -10541
- package/dist/node.dev.cjs +0 -13724
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -23
- package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
- package/dist/types-cjs/core/attribution.d.cts +0 -495
- package/dist/types-cjs/core/core.d.cts +0 -185
- package/dist/types-cjs/core/dev.d.cts +0 -136
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -56
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -28
- package/dist/types-cjs/core/heap.d.cts +0 -24
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -54
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -236
- package/dist/types-cjs/core/types.d.cts +0 -204
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/store/index.d.cts +0 -18
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
- package/dist/types-cjs/store/next/projection.d.cts +0 -8
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
- package/dist/types-cjs/store/next/store.d.cts +0 -121
- package/dist/types-cjs/store/next/target.d.cts +0 -166
- package/dist/types-cjs/store/store.d.cts +0 -143
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_HAS_LANE, OVERRIDE_UNDEFINED, STATUS_PENDING, EFFECT_RENDER, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, EFFECT_USER } from "./constants.js";
|
|
1
|
+
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_HAS_LANE, OVERRIDE_UNDEFINED, STATUS_PENDING, CONFIG_OVERRIDE_SUPERSEDED, EFFECT_RENDER, CONFIG_AUTHORITATIVE_OBSERVED, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, LANE_RUN, EFFECT_USER } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { ext, latestReadActive, currentOptimisticLane
|
|
3
|
+
import { ext, stale, latestReadActive, currentOptimisticLane } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ import "./invariants.js";
|
|
|
8
8
|
|
|
9
9
|
import { resolveTransition, getOrCreateLane, hasActiveOverride, activeLanes, signalLanes, laneHeld, findLane, resolveLane, assignOrMergeLane } from "./lanes.js";
|
|
10
10
|
|
|
11
|
-
import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule } from "./scheduler.js";
|
|
11
|
+
import { GlobalQueue, activeTransition, globalQueue, origin, clock, insertSubs, schedule, queuePendingNode } from "./scheduler.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* The optimistic write engine, moved out of core.ts/scheduler.ts. Everything
|
|
@@ -24,9 +24,9 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
24
24
|
* once the gate holds — the same late-binding contract as verdict.ts.
|
|
25
25
|
*/
|
|
26
26
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, n) {
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
if (typeof n === "function") n = n(
|
|
27
|
+
const i = e.o?.be !== NOT_PENDING;
|
|
28
|
+
const t = i ? unwrapOverride(e.o?.be) : e.me;
|
|
29
|
+
if (typeof n === "function") n = n(t);
|
|
30
30
|
const u = !!(e.S & STATUS_UNINITIALIZED) ||
|
|
31
31
|
// A dirty node's _value is stale (its queued recompute hasn't run — e.g.
|
|
32
32
|
// a latest() shadow marked by the previous landing's companion snap), so
|
|
@@ -34,36 +34,47 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
34
34
|
// push returning the shadow to that stale value was dropped, the snap
|
|
35
35
|
// recompute then committed the parent's old value, and the banner showed
|
|
36
36
|
// the previous transition's target (#3041 follow-up).
|
|
37
|
-
!!((e.ie ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.
|
|
37
|
+
!!((e.ie ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.ve || !e.ve(t, n);
|
|
38
38
|
if (!u) {
|
|
39
39
|
// Same-value write with an active override still entangles the current
|
|
40
|
-
// action's transition — the hold must outlast all overlapping actions
|
|
41
|
-
|
|
40
|
+
// action's transition — the hold must outlast all overlapping actions —
|
|
41
|
+
// and renews the override's PROVENANCE: the newer action re-asks the
|
|
42
|
+
// question, so an older action's answer arriving later is stale to it
|
|
43
|
+
// too (#3331; a same-value re-prediction otherwise let the first
|
|
44
|
+
// action's slow source supersede and restart the downstream flight).
|
|
45
|
+
if (i) {
|
|
42
46
|
const n = resolveTransition(e);
|
|
43
47
|
if (n && activeTransition !== n) globalQueue.initTransition(n);
|
|
48
|
+
if (origin > e.o.Rt) e.o.Rt = origin;
|
|
44
49
|
}
|
|
45
50
|
return n;
|
|
46
51
|
}
|
|
47
|
-
if (
|
|
52
|
+
if (i) globalQueue.initTransition(resolveTransition(e));
|
|
48
53
|
// No revert target is stashed: while the override is active every reader
|
|
49
54
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
50
55
|
// reverting is just dropping the override — _value is already correct.
|
|
51
|
-
else globalQueue.m.
|
|
56
|
+
else globalQueue.m.it.push(e);
|
|
52
57
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
53
58
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
54
59
|
// which a shared subscriber can merge across transactions (#2912).
|
|
55
|
-
ext(e).
|
|
60
|
+
ext(e).Ot = activeTransition;
|
|
61
|
+
ext(e).It = clock;
|
|
62
|
+
// Provenance: the action asking. An answer an OLDER action's flight brings
|
|
63
|
+
// back is a stale question and holds silently to commit (#3331).
|
|
64
|
+
ext(e).Rt = origin;
|
|
56
65
|
const r = getOrCreateLane(e);
|
|
57
|
-
ext(e)
|
|
58
|
-
|
|
66
|
+
ext(e).Oe = r;
|
|
67
|
+
// A fresh override re-masks: whatever truth is staged, this write is the
|
|
68
|
+
// value for the graph again until the source answers it (#3331).
|
|
69
|
+
e.T = (e.T | CONFIG_HAS_LANE) & ~CONFIG_OVERRIDE_SUPERSEDED;
|
|
59
70
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
60
71
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
61
72
|
// writes off the optimistic path into permanent commits (#2898).
|
|
62
|
-
ext(e).
|
|
73
|
+
ext(e).be = n === undefined ? OVERRIDE_UNDEFINED : n;
|
|
63
74
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
64
75
|
// neither companion present the call is a guaranteed no-op.
|
|
65
|
-
(e.o?.
|
|
66
|
-
if (e.oe !== undefined) e.
|
|
76
|
+
(e.o?.Le !== undefined || e.o?.Qe !== undefined) && GlobalQueue.pe !== null && GlobalQueue.pe(e, n);
|
|
77
|
+
if (e.oe !== undefined) e._e = clock;
|
|
67
78
|
// §12e: computed-only slot
|
|
68
79
|
insertSubs(e, true);
|
|
69
80
|
schedule();
|
|
@@ -75,9 +86,9 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
75
86
|
* while one of its optimistic nodes holds an active override that is still
|
|
76
87
|
* pending on real (non-affects-sentinel) async.
|
|
77
88
|
*/ function transitionBlocked(e) {
|
|
78
|
-
for (let n = 0; n < e.
|
|
79
|
-
const
|
|
80
|
-
if (hasActiveOverride(
|
|
89
|
+
for (let n = 0; n < e.it.length; n++) {
|
|
90
|
+
const i = e.it[n];
|
|
91
|
+
if (hasActiveOverride(i) && "S" in i && i.S & STATUS_PENDING && i.o?._ instanceof NotReadyError) {
|
|
81
92
|
return true;
|
|
82
93
|
}
|
|
83
94
|
}
|
|
@@ -89,33 +100,134 @@ function resolveOptimisticNodes(e) {
|
|
|
89
100
|
// notifications) may push fresh optimistic nodes; only this batch settles
|
|
90
101
|
// now, so iterate a fixed window and splice it out at the end.
|
|
91
102
|
const n = e.length;
|
|
92
|
-
for (let
|
|
93
|
-
const n = e[
|
|
94
|
-
if (n.o !== null) n.o
|
|
103
|
+
for (let i = 0; i < n; i++) {
|
|
104
|
+
const n = e[i];
|
|
105
|
+
if (n.o !== null) n.o.Oe = undefined;
|
|
95
106
|
// Revert is a pure drop: there is no revert target to commit —
|
|
96
107
|
// override-covered authoritative values hold in _pendingValue and
|
|
97
108
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
98
109
|
if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
|
|
99
|
-
const
|
|
100
|
-
ext(n).
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
const t = n.o?.be;
|
|
111
|
+
ext(n).be = NOT_PENDING;
|
|
112
|
+
// A superseded override's subscribers already re-derived from the truth
|
|
113
|
+
// when it arrived (#3331) — the drop changes nothing they read. Everyone
|
|
114
|
+
// else learns of the correction here: this drop IS their notification.
|
|
115
|
+
const u = (n.T & CONFIG_OVERRIDE_SUPERSEDED) !== 0;
|
|
116
|
+
n.T &= ~CONFIG_OVERRIDE_SUPERSEDED;
|
|
117
|
+
if (!u && t !== NOT_PENDING && n.me !== unwrapOverride(t)) insertSubs(n, true);
|
|
118
|
+
n.ge = null;
|
|
119
|
+
if (n.o !== null) n.o.Ot = null;
|
|
104
120
|
}
|
|
105
121
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
106
122
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
107
123
|
// transition that produced them (A19 — pending is a property of the data).
|
|
108
|
-
for (let
|
|
109
|
-
const n = e[
|
|
110
|
-
if (n.o?.
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
124
|
+
for (let i = 0; i < n; i++) {
|
|
125
|
+
const n = e[i];
|
|
126
|
+
if (n.o?.Le || n.o?.Qe) GlobalQueue.un(n);
|
|
127
|
+
const t = n.o?.Gt;
|
|
128
|
+
if (t && (t.o?.Le === n || t.o?.Qe === n)) GlobalQueue.un(t);
|
|
113
129
|
}
|
|
114
130
|
e.splice(0, n);
|
|
115
131
|
}
|
|
116
132
|
|
|
133
|
+
/**
|
|
134
|
+
* A18 supersession (#3331): the node's own source arrived with a value that
|
|
135
|
+
* differs from its active override. "Knowing otherwise" ends the optimism for
|
|
136
|
+
* the graph at once: the override stays only as the DISPLAYED value (untracked
|
|
137
|
+
* reads, the applied frame) until the owning transaction commits, while
|
|
138
|
+
* tracked readers see the staged truth and re-derive from it as that
|
|
139
|
+
* transaction's held work — so async downstream restarts now, not at the
|
|
140
|
+
* revert (no waterfall).
|
|
141
|
+
*
|
|
142
|
+
* The lane's job for this node is over: a lane applies an optimistic view
|
|
143
|
+
* ahead of its transaction, and there is no optimistic view left — the
|
|
144
|
+
* corrected cascade is plain transaction-held work (staged memos, effect runs
|
|
145
|
+
* in the stashable queues). Demote the node and every cascade member that
|
|
146
|
+
* rides this lane; the caller then notifies on the plain channel. Runners the
|
|
147
|
+
* lane still holds for demoted effects (the optimistic frame that never got to
|
|
148
|
+
* apply) defer to the regular queue in runEffect. In a lane merged with a
|
|
149
|
+
* still-optimistic source, members shared with that source lose their lane
|
|
150
|
+
* too and simply wait for the transaction — less optimistic, never torn.
|
|
151
|
+
*
|
|
152
|
+
* A later arrival EQUAL to the override (an earlier action's answer superseded
|
|
153
|
+
* this one's; now this one's answer confirms it) ends the supersession: the
|
|
154
|
+
* graph re-derives from the override, which is the truth again. Notifies the
|
|
155
|
+
* subscribers in both cases. A plain matching confirmation (no supersession
|
|
156
|
+
* in force) is A17-silent for ordinary subscribers and wakes only an
|
|
157
|
+
* authoritative-view reader (until()'s predicate, refresh()'s waiter) that
|
|
158
|
+
* observed this node past its override — "authoritative arrival equal to the
|
|
159
|
+
* override" is exactly the acknowledgment it waits for (#3164, #3303). The
|
|
160
|
+
* wake hook is installed by the setters of that bit; optional here because
|
|
161
|
+
* the bit only implies the optimistic engine was consulted.
|
|
162
|
+
*/ function supersedeOverride(e, n) {
|
|
163
|
+
const i = !e.ve || !e.ve(n, unwrapOverride(e.o.be));
|
|
164
|
+
if (!i) {
|
|
165
|
+
if (!(e.T & CONFIG_OVERRIDE_SUPERSEDED)) {
|
|
166
|
+
if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.Qt?.(e);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
e.T &= ~CONFIG_OVERRIDE_SUPERSEDED;
|
|
170
|
+
} else {
|
|
171
|
+
// Provenance (#3331): an answer brought back by an OLDER action than the
|
|
172
|
+
// one that wrote this override answers a question the user has since
|
|
173
|
+
// changed. It is staged like any other landing and reveals if it is
|
|
174
|
+
// still the truth when the transaction commits, but it does not move the
|
|
175
|
+
// graph now — a slow source must not leak back in over a newer intent.
|
|
176
|
+
// 0 is mainline (no action): always the current question.
|
|
177
|
+
if (origin && origin < e.o.Rt) return;
|
|
178
|
+
e.T |= CONFIG_OVERRIDE_SUPERSEDED;
|
|
179
|
+
const n = e.o?.Oe;
|
|
180
|
+
if (n) {
|
|
181
|
+
const i = findLane(n);
|
|
182
|
+
const t = [ e ];
|
|
183
|
+
while (t.length) {
|
|
184
|
+
const e = t.pop();
|
|
185
|
+
const n = e.o?.Oe;
|
|
186
|
+
if (!n || findLane(n) !== i) continue;
|
|
187
|
+
e.o.Oe = undefined;
|
|
188
|
+
i.he.delete(e);
|
|
189
|
+
for (let n = e.u; n !== null; n = n.Te) t.push(n.Ie);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
insertSubs(e);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** read()'s value for a tracked reader of a superseded node: the truth —
|
|
197
|
+
* staged, or already committed (a mainline landing commits at the head of
|
|
198
|
+
* its flush, ahead of the heap run, and the override drops only at the
|
|
199
|
+
* batch's end; in between the graph must not fall back to the override it
|
|
200
|
+
* has left) — or the displayed override for a stale (render) reader of some
|
|
201
|
+
* OTHER transaction, the same visibility a foreign transaction's staged
|
|
202
|
+
* write has. */ function supersededRead(e) {
|
|
203
|
+
if (stale && e.ge && activeTransition !== e.ge) return unwrapOverride(e.o?.be);
|
|
204
|
+
return e.Ge !== NOT_PENDING ? e.Ge : e.me;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* An authoritative store landing on an override-covered node — a derived
|
|
209
|
+
* optimistic store's own truth arriving over a tentative edit through the
|
|
210
|
+
* projection-write channel (setSignal under projectionWriteActive). The
|
|
211
|
+
* store twin of asyncWrite's override branch: the truth stages for its
|
|
212
|
+
* transaction's commit whatever its relation to the committed value (a
|
|
213
|
+
* landing equal to committed still differs from the override), companions
|
|
214
|
+
* learn of it, and supersedeOverride decides the rest — A18 supersession with
|
|
215
|
+
* action provenance, or an A17-silent confirmation (#3331). Before this the
|
|
216
|
+
* landing took setSignal's plain path: a differing truth staged silently
|
|
217
|
+
* under the override and the graph never moved until the commit.
|
|
218
|
+
*/ function landOnOverride(e, n) {
|
|
219
|
+
const i = e.Ge === NOT_PENDING ? e.me : e.Ge;
|
|
220
|
+
if (typeof n === "function") n = n(i);
|
|
221
|
+
if (e.Ge === NOT_PENDING) queuePendingNode(e);
|
|
222
|
+
e.Ge = n;
|
|
223
|
+
GlobalQueue.pe?.(e, n);
|
|
224
|
+
supersedeOverride(e, n);
|
|
225
|
+
schedule();
|
|
226
|
+
return n;
|
|
227
|
+
}
|
|
228
|
+
|
|
117
229
|
function runQueue(e, n) {
|
|
118
|
-
for (let
|
|
230
|
+
for (let i = 0; i < e.length; i++) e[i](n | LANE_RUN);
|
|
119
231
|
}
|
|
120
232
|
|
|
121
233
|
/**
|
|
@@ -124,10 +236,10 @@ function runQueue(e, n) {
|
|
|
124
236
|
*/ function runLaneEffects(e) {
|
|
125
237
|
for (const n of activeLanes) {
|
|
126
238
|
if (n.rn || laneHeld(n)) continue;
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
239
|
+
const i = n.tn[e - 1];
|
|
240
|
+
if (i.length) {
|
|
129
241
|
n.tn[e - 1] = [];
|
|
130
|
-
runQueue(
|
|
242
|
+
runQueue(i, e);
|
|
131
243
|
}
|
|
132
244
|
}
|
|
133
245
|
// Optimistic patch applications ride the same visibility slot as lane
|
|
@@ -137,14 +249,14 @@ function runQueue(e, n) {
|
|
|
137
249
|
|
|
138
250
|
function cleanupCompletedLanes(e) {
|
|
139
251
|
for (const n of activeLanes) {
|
|
140
|
-
const
|
|
141
|
-
if (!
|
|
252
|
+
const i = e ? n.ge === e : !n.ge;
|
|
253
|
+
if (!i) continue;
|
|
142
254
|
if (!n.rn) {
|
|
143
255
|
if (n.tn[0].length) runQueue(n.tn[0], EFFECT_RENDER);
|
|
144
256
|
if (n.tn[1].length) runQueue(n.tn[1], EFFECT_USER);
|
|
145
257
|
}
|
|
146
|
-
if (n.nn.o
|
|
147
|
-
n.
|
|
258
|
+
if (n.nn.o?.Oe === n) if (n.nn.o !== null) n.nn.o.Oe = undefined;
|
|
259
|
+
n.he.clear();
|
|
148
260
|
n.tn[0].length = 0;
|
|
149
261
|
n.tn[1].length = 0;
|
|
150
262
|
activeLanes.delete(n);
|
|
@@ -164,28 +276,40 @@ function cleanupCompletedLanes(e) {
|
|
|
164
276
|
// Per-lane suspension: only throw if in same lane as pending async
|
|
165
277
|
// AND the node doesn't have an active override (overrides are the visible value,
|
|
166
278
|
// downstream in the lane should read the override, not throw)
|
|
167
|
-
const n = e.o
|
|
279
|
+
const n = e.o?.Oe;
|
|
168
280
|
if (!n) return false;
|
|
169
281
|
return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
|
|
170
282
|
}
|
|
171
283
|
|
|
284
|
+
/**
|
|
285
|
+
* read()'s reveal carve-out asks whether a pending node is routed through a
|
|
286
|
+
* LIVE lane: a lane-derived flight's inputs are already revealed through the
|
|
287
|
+
* lane (the override, or latest()'s fresh value), so a stale reader of another
|
|
288
|
+
* transaction must hold on the flight rather than show the node's committed
|
|
289
|
+
* value beside them (#3334). Exact, not sticky: `resolveLane` clears a lane
|
|
290
|
+
* reference the engine has since retired, so a node that was once lane-routed
|
|
291
|
+
* and is now pending under a plain hold is judged by that hold alone.
|
|
292
|
+
*/ function laneLive(e) {
|
|
293
|
+
return resolveLane(e) !== undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
172
296
|
/**
|
|
173
297
|
* read()'s entanglement gate: a reader recomputing under an optimistic lane
|
|
174
298
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
175
299
|
* is recorded for replay at commit.
|
|
176
|
-
*/ function gatedRead(e, n,
|
|
177
|
-
if (latestReadActive || e.
|
|
300
|
+
*/ function gatedRead(e, n, i) {
|
|
301
|
+
if (latestReadActive || e.Ge === NOT_PENDING || e.oe || n !== e && !(n.ie & REACTIVE_MANUAL_WRITE)) {
|
|
178
302
|
return false;
|
|
179
303
|
}
|
|
180
|
-
activeTransition.
|
|
304
|
+
activeTransition.lt.add(i);
|
|
181
305
|
return true;
|
|
182
306
|
}
|
|
183
307
|
|
|
184
308
|
/**
|
|
185
309
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
186
310
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
187
|
-
*/ function laneReadsCommitted(e, n,
|
|
188
|
-
if (e.o?.
|
|
311
|
+
*/ function laneReadsCommitted(e, n, i) {
|
|
312
|
+
if (e.o?.be !== undefined || !!e.o?.Oe || !!(n.S & STATUS_PENDING)) {
|
|
189
313
|
// The committed view hides a staged in-flight value that will promote
|
|
190
314
|
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
191
315
|
// signals for replay at commit; async memos are excluded from it by the
|
|
@@ -193,11 +317,17 @@ function cleanupCompletedLanes(e) {
|
|
|
193
317
|
// already settled (laneAsyncSettled keeps _optimisticLane) served its
|
|
194
318
|
// committed value to a reader that never re-ran after the landing, so a
|
|
195
319
|
// pending-gated branch stayed one value behind permanently (#3041
|
|
196
|
-
// follow-up). Record the reader under the same replay contract
|
|
197
|
-
|
|
320
|
+
// follow-up). Record the reader under the same replay contract — when
|
|
321
|
+
// the commit will actually change what it read: a staged value equal to
|
|
322
|
+
// the committed one (a lane recompute already published it, INV-11)
|
|
323
|
+
// promotes to the same view, and a replay would only re-run effects
|
|
324
|
+
// against an unchanged frame (#3330). An override-covered node's revert
|
|
325
|
+
// notifies its own subscribers when the truth differs (resolveOptimistic
|
|
326
|
+
// Nodes), so the reader is recorded only for the staged-vs-committed gap.
|
|
327
|
+
if (e.Ge !== NOT_PENDING && e.Ge !== e.me) (activeTransition ?? globalQueue.m).lt.add(i);
|
|
198
328
|
return true;
|
|
199
329
|
}
|
|
200
|
-
if (n === e && stale &&
|
|
330
|
+
if (n === e && stale && i.o?.Gt !== e) {
|
|
201
331
|
// The committed view can hide a staged write (a lane member — even just
|
|
202
332
|
// an isPending companion flip — puts the reader "under a lane"). The
|
|
203
333
|
// staged value commits with no re-delivery (commitPendingNode never
|
|
@@ -209,7 +339,7 @@ function cleanupCompletedLanes(e) {
|
|
|
209
339
|
// into the transaction (#3041 follow-up: a pending-gated branch that
|
|
210
340
|
// first read its async source during the landing flush stayed one value
|
|
211
341
|
// behind permanently); with none, into the ambient batch.
|
|
212
|
-
if (e.
|
|
342
|
+
if (e.Ge !== NOT_PENDING) (activeTransition ?? globalQueue.m).lt.add(i);
|
|
213
343
|
return true;
|
|
214
344
|
}
|
|
215
345
|
return false;
|
|
@@ -232,16 +362,16 @@ function cleanupCompletedLanes(e) {
|
|
|
232
362
|
// recompute() runs plain: the value stages and commits with the flush.
|
|
233
363
|
// (el's own override slot excludes companions themselves; a lane merged
|
|
234
364
|
// into a real optimistic lane resolves to a non-companion source.)
|
|
235
|
-
if (!globalQueue.
|
|
236
|
-
if (e.o !== null) e.o
|
|
365
|
+
if (!globalQueue.sn && !activeTransition && !n.ge && n.nn.o?.Gt !== undefined && e.o?.be === undefined) {
|
|
366
|
+
if (e.o !== null) e.o.Oe = undefined;
|
|
237
367
|
return false;
|
|
238
368
|
}
|
|
239
369
|
return n;
|
|
240
370
|
}
|
|
241
|
-
for (let n = e.
|
|
242
|
-
const
|
|
243
|
-
if (
|
|
244
|
-
const n = resolveLane(
|
|
371
|
+
for (let n = e.fe; n; n = n.ae) {
|
|
372
|
+
const i = n.Se;
|
|
373
|
+
if (i.ie & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
374
|
+
const n = resolveLane(i);
|
|
245
375
|
if (n) {
|
|
246
376
|
e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
247
377
|
assignOrMergeLane(e, n);
|
|
@@ -258,8 +388,8 @@ function cleanupCompletedLanes(e) {
|
|
|
258
388
|
* the source's own write/commit/settlement paths keep it current. */ function laneAsyncPending(e) {
|
|
259
389
|
const n = findLane(currentOptimisticLane);
|
|
260
390
|
if (n.nn !== e) {
|
|
261
|
-
n.
|
|
262
|
-
ext(e)
|
|
391
|
+
n.he.add(e);
|
|
392
|
+
ext(e).Oe = n;
|
|
263
393
|
e.T |= CONFIG_HAS_LANE;
|
|
264
394
|
}
|
|
265
395
|
}
|
|
@@ -267,7 +397,7 @@ function cleanupCompletedLanes(e) {
|
|
|
267
397
|
/** recompute()'s success path: the node's async settled, clear it from its lane. */ function laneAsyncSettled(e) {
|
|
268
398
|
const n = resolveLane(e);
|
|
269
399
|
if (n) {
|
|
270
|
-
n.
|
|
400
|
+
n.he.delete(e);
|
|
271
401
|
}
|
|
272
402
|
}
|
|
273
403
|
|
|
@@ -282,19 +412,23 @@ function trackOptimisticStore(e) {
|
|
|
282
412
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
283
413
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
284
414
|
*/ function installOptimisticEngine() {
|
|
285
|
-
if (GlobalQueue.
|
|
286
|
-
GlobalQueue.
|
|
287
|
-
GlobalQueue.
|
|
288
|
-
GlobalQueue.
|
|
289
|
-
GlobalQueue.
|
|
290
|
-
GlobalQueue.
|
|
291
|
-
GlobalQueue.
|
|
292
|
-
GlobalQueue.
|
|
293
|
-
GlobalQueue.
|
|
294
|
-
GlobalQueue.
|
|
295
|
-
GlobalQueue.
|
|
296
|
-
GlobalQueue.
|
|
297
|
-
GlobalQueue.
|
|
415
|
+
if (GlobalQueue.Bt !== null) return;
|
|
416
|
+
GlobalQueue.Bt = optimisticWrite;
|
|
417
|
+
GlobalQueue.fn = resolveOptimisticNodes;
|
|
418
|
+
GlobalQueue.cn = transitionBlocked;
|
|
419
|
+
GlobalQueue.dn = cleanupCompletedLanes;
|
|
420
|
+
GlobalQueue.In = runLaneEffects;
|
|
421
|
+
GlobalQueue.ye = supersedeOverride;
|
|
422
|
+
GlobalQueue.Yt = supersededRead;
|
|
423
|
+
GlobalQueue.zt = landOnOverride;
|
|
424
|
+
GlobalQueue.Zt = gatedRead;
|
|
425
|
+
GlobalQueue.qt = laneSuspends;
|
|
426
|
+
GlobalQueue.Mt = laneLive;
|
|
427
|
+
GlobalQueue.Kt = laneReadsCommitted;
|
|
428
|
+
GlobalQueue.nt = recomputeLane;
|
|
429
|
+
GlobalQueue.ot = laneAsyncPending;
|
|
430
|
+
GlobalQueue.ut = laneAsyncSettled;
|
|
431
|
+
GlobalQueue.Nn = trackOptimisticStore;
|
|
298
432
|
}
|
|
299
433
|
|
|
300
434
|
export { installOptimisticEngine };
|
package/dist/prod/core/owner.js
CHANGED
|
@@ -12,7 +12,7 @@ const PENDING_OWNER = {};
|
|
|
12
12
|
|
|
13
13
|
// Dummy owner to trigger store's read() path
|
|
14
14
|
function markDisposal(e) {
|
|
15
|
-
let t = e.
|
|
15
|
+
let t = e.Ye;
|
|
16
16
|
while (t) {
|
|
17
17
|
const e = t.ie;
|
|
18
18
|
t.ie = e | REACTIVE_ZOMBIE;
|
|
@@ -26,7 +26,7 @@ function markDisposal(e) {
|
|
|
26
26
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
27
27
|
}
|
|
28
28
|
markDisposal(t);
|
|
29
|
-
t = t.
|
|
29
|
+
t = t.Ze;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -52,12 +52,12 @@ function disposeChildren(e, t = false, n) {
|
|
|
52
52
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
53
53
|
// false, and notifies subscribers still watching the companion.
|
|
54
54
|
const t = e;
|
|
55
|
-
if (t.o?.
|
|
55
|
+
if (t.o?.Le || t.o?.Qe) GlobalQueue.un(t);
|
|
56
56
|
}
|
|
57
|
-
if (t && e.oe && e.o !== null) e.o.
|
|
58
|
-
let o = n ? e.o?.
|
|
57
|
+
if (t && e.oe && e.o !== null) e.o.Pe = null;
|
|
58
|
+
let o = n ? e.o?.Xe ?? null : e.Ye;
|
|
59
59
|
while (o) {
|
|
60
|
-
const e = o.
|
|
60
|
+
const e = o.Ze;
|
|
61
61
|
const t = o;
|
|
62
62
|
// Owner teardown is death regardless of the child's own lifecycle
|
|
63
63
|
// (#3024): strip AUTO_DISPOSE so a post-disposal read freezes at the
|
|
@@ -80,34 +80,34 @@ function disposeChildren(e, t = false, n) {
|
|
|
80
80
|
o = e;
|
|
81
81
|
}
|
|
82
82
|
if (n) {
|
|
83
|
-
if (e.o !== null) e.o.
|
|
83
|
+
if (e.o !== null) e.o.Xe = null;
|
|
84
84
|
} else {
|
|
85
|
-
e.
|
|
86
|
-
e
|
|
85
|
+
e.Ye = null;
|
|
86
|
+
e.$e = 0;
|
|
87
87
|
}
|
|
88
88
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
89
89
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
90
90
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
91
91
|
// walks that already advanced past us still reach later siblings.
|
|
92
|
-
if (t && !n && !(i & REACTIVE_ZOMBIE) && e.
|
|
93
|
-
const t = e.
|
|
94
|
-
const n = e.
|
|
95
|
-
if (t !== null) t.
|
|
96
|
-
if (n !== null) n.
|
|
97
|
-
e.
|
|
92
|
+
if (t && !n && !(i & REACTIVE_ZOMBIE) && e.qe !== null && !(e.qe.ie & REACTIVE_DISPOSED)) {
|
|
93
|
+
const t = e.St;
|
|
94
|
+
const n = e.Ze;
|
|
95
|
+
if (t !== null) t.Ze = n; else e.qe.Ye = n;
|
|
96
|
+
if (n !== null) n.St = t;
|
|
97
|
+
e.St = null;
|
|
98
98
|
}
|
|
99
99
|
runDisposal(e, n);
|
|
100
100
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
101
101
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
102
|
-
if (t && e.
|
|
103
|
-
const t = e.
|
|
104
|
-
e.
|
|
102
|
+
if (t && e.Ht) {
|
|
103
|
+
const t = e.Ht;
|
|
104
|
+
e.Ht = undefined;
|
|
105
105
|
t();
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
function runDisposal(e, t) {
|
|
110
|
-
let n = t ? e.o?.
|
|
110
|
+
let n = t ? e.o?.Je : e.we;
|
|
111
111
|
if (!n) return;
|
|
112
112
|
if (Array.isArray(n)) {
|
|
113
113
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -118,14 +118,14 @@ function runDisposal(e, t) {
|
|
|
118
118
|
n.call(n);
|
|
119
119
|
}
|
|
120
120
|
if (t) {
|
|
121
|
-
if (e.o !== null) e.o.
|
|
122
|
-
} else e.
|
|
121
|
+
if (e.o !== null) e.o.Je = null;
|
|
122
|
+
} else e.we = null;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function childId(e, t) {
|
|
126
126
|
let n = e;
|
|
127
|
-
while (n.T & CONFIG_TRANSPARENT && n.
|
|
128
|
-
if (n.id != null) return formatId(n.id, t ? n
|
|
127
|
+
while (n.T & CONFIG_TRANSPARENT && n.qe) n = n.qe;
|
|
128
|
+
if (n.id != null) return formatId(n.id, t ? n.$e++ : n.$e);
|
|
129
129
|
throw new Error("");
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -206,7 +206,7 @@ function formatId(e, t) {
|
|
|
206
206
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
207
207
|
*/ function cleanup(e) {
|
|
208
208
|
if (!context) return e;
|
|
209
|
-
if (!context.
|
|
209
|
+
if (!context.we) context.we = e; else if (Array.isArray(context.we)) context.we.push(e); else context.we = [ context.we, e ];
|
|
210
210
|
return e;
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -243,30 +243,34 @@ function disposeRootSelf(e = true) {
|
|
|
243
243
|
*/ function createOwner(e) {
|
|
244
244
|
const t = context;
|
|
245
245
|
const n = e?.transparent ?? false;
|
|
246
|
-
|
|
246
|
+
// Prod and observe boilerplates (see core.ts computed()). The observe
|
|
247
|
+
// literal carries the `_name` slot the rendering layer fills with the
|
|
248
|
+
// component label (`owner._name = "<App>"`) — a slot, so labelling a root
|
|
249
|
+
// is a plain store rather than a shape fork between labelled and plain roots.
|
|
250
|
+
const i = {
|
|
247
251
|
id: inheritId(e, n, t),
|
|
248
252
|
T: n ? CONFIG_TRANSPARENT : 0,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
gt: true,
|
|
254
|
+
bt: t?.gt ? t.bt : t,
|
|
255
|
+
Ye: null,
|
|
256
|
+
Ze: null,
|
|
257
|
+
St: null,
|
|
258
|
+
we: null,
|
|
255
259
|
C: t?.C ?? globalQueue,
|
|
256
|
-
|
|
257
|
-
|
|
260
|
+
xe: t?.xe || defaultContext,
|
|
261
|
+
$e: 0,
|
|
258
262
|
o: null,
|
|
259
|
-
|
|
263
|
+
qe: t,
|
|
260
264
|
dispose: disposeRootSelf
|
|
261
265
|
};
|
|
262
266
|
if (t) {
|
|
263
|
-
const e = t.
|
|
267
|
+
const e = t.Ye;
|
|
264
268
|
if (e === null) {
|
|
265
|
-
t.
|
|
269
|
+
t.Ye = i;
|
|
266
270
|
} else {
|
|
267
|
-
i.
|
|
268
|
-
e.
|
|
269
|
-
t.
|
|
271
|
+
i.Ze = e;
|
|
272
|
+
e.St = i;
|
|
273
|
+
t.Ye = i;
|
|
270
274
|
}
|
|
271
275
|
}
|
|
272
276
|
return i;
|