@solidjs/signals 2.0.0-rc.6 → 2.0.0-rc.7
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.js +2033 -1291
- package/dist/node.cjs +1821 -2401
- package/dist/node.dev.cjs +13724 -0
- package/dist/prod/boundaries.js +3 -1
- package/dist/prod/core/async.js +6 -1
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/context.js +10 -16
- package/dist/prod/core/core.js +215 -139
- package/dist/prod/core/dev.js +2 -0
- package/dist/prod/core/effect.js +37 -28
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +35 -31
- package/dist/prod/core/heap.js +34 -40
- package/dist/prod/core/lanes.js +41 -27
- package/dist/prod/core/optimistic.js +42 -32
- package/dist/prod/core/owner.js +32 -32
- package/dist/prod/core/scheduler.js +140 -154
- package/dist/prod/core/verdict.js +31 -34
- package/dist/prod/index.js +0 -2
- package/dist/prod/map.js +104 -94
- package/dist/prod/signals.js +51 -34
- package/dist/prod/store/next/optimistic.js +153 -172
- package/dist/prod/store/next/reconcile.js +140 -288
- package/dist/prod/store/next/store.js +307 -237
- package/dist/prod/store/store.js +2 -2
- package/dist/types/core/attribution-hooks.d.ts +64 -0
- package/dist/types/core/attribution.d.ts +265 -9
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/core.d.ts +12 -3
- package/dist/types/core/dev.d.ts +49 -8
- package/dist/types/core/heap.d.ts +5 -3
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +9 -4
- package/dist/types/signals.d.ts +10 -0
- package/dist/types/store/index.d.ts +3 -6
- package/dist/types/store/next/optimistic.d.ts +4 -2
- package/dist/types/store/next/reconcile.d.ts +5 -12
- package/dist/types/store/next/store.d.ts +3 -9
- package/dist/types/store/next/target.d.ts +20 -46
- package/dist/types/store/store.d.ts +14 -9
- package/dist/types-cjs/core/attribution-hooks.d.cts +64 -0
- package/dist/types-cjs/core/attribution.d.cts +265 -9
- package/dist/types-cjs/core/constants.d.cts +8 -0
- package/dist/types-cjs/core/core.d.cts +12 -3
- package/dist/types-cjs/core/dev.d.cts +49 -8
- package/dist/types-cjs/core/heap.d.cts +5 -3
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/dist/types-cjs/core/lanes.d.cts +10 -0
- package/dist/types-cjs/core/scheduler.d.cts +9 -4
- package/dist/types-cjs/signals.d.cts +10 -0
- package/dist/types-cjs/store/index.d.cts +3 -6
- package/dist/types-cjs/store/next/optimistic.d.cts +4 -2
- package/dist/types-cjs/store/next/reconcile.d.cts +5 -12
- package/dist/types-cjs/store/next/store.d.cts +3 -9
- package/dist/types-cjs/store/next/target.d.cts +20 -46
- package/dist/types-cjs/store/store.d.cts +14 -9
- package/package.json +3 -2
- package/dist/prod/store/next/patch-hooks.js +0 -13
- package/dist/prod/store/next/patch.js +0 -614
- package/dist/types/store/next/patch-hooks.d.ts +0 -41
- package/dist/types/store/next/patch.d.ts +0 -91
- package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
- package/dist/types-cjs/store/next/patch.d.cts +0 -91
|
@@ -6,7 +6,7 @@ import { NotReadyError } from "./error.js";
|
|
|
6
6
|
|
|
7
7
|
import "./invariants.js";
|
|
8
8
|
|
|
9
|
-
import { resolveTransition, getOrCreateLane, hasActiveOverride, activeLanes, signalLanes, findLane, resolveLane, assignOrMergeLane } from "./lanes.js";
|
|
9
|
+
import { resolveTransition, getOrCreateLane, hasActiveOverride, activeLanes, signalLanes, laneHeld, findLane, resolveLane, assignOrMergeLane } from "./lanes.js";
|
|
10
10
|
|
|
11
11
|
import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule } from "./scheduler.js";
|
|
12
12
|
|
|
@@ -48,13 +48,13 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
48
48
|
// No revert target is stashed: while the override is active every reader
|
|
49
49
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
50
50
|
// reverting is just dropping the override — _value is already correct.
|
|
51
|
-
else globalQueue.m.
|
|
51
|
+
else globalQueue.m.Xe.push(e);
|
|
52
52
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
53
53
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
54
54
|
// which a shared subscriber can merge across transactions (#2912).
|
|
55
|
-
ext(e).
|
|
56
|
-
const
|
|
57
|
-
ext(e)
|
|
55
|
+
ext(e).Tt = activeTransition;
|
|
56
|
+
const r = getOrCreateLane(e);
|
|
57
|
+
ext(e).$e = r;
|
|
58
58
|
e.T |= CONFIG_HAS_LANE;
|
|
59
59
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
60
60
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
@@ -75,8 +75,8 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
75
75
|
* while one of its optimistic nodes holds an active override that is still
|
|
76
76
|
* pending on real (non-affects-sentinel) async.
|
|
77
77
|
*/ function transitionBlocked(e) {
|
|
78
|
-
for (let n = 0; n < e.
|
|
79
|
-
const t = e.
|
|
78
|
+
for (let n = 0; n < e.Xe.length; n++) {
|
|
79
|
+
const t = e.Xe[n];
|
|
80
80
|
if (hasActiveOverride(t) && "S" in t && t.S & STATUS_PENDING && t.o?._ instanceof NotReadyError) {
|
|
81
81
|
return true;
|
|
82
82
|
}
|
|
@@ -91,7 +91,7 @@ function resolveOptimisticNodes(e) {
|
|
|
91
91
|
const n = e.length;
|
|
92
92
|
for (let t = 0; t < n; t++) {
|
|
93
93
|
const n = e[t];
|
|
94
|
-
if (n.o !== null) n.o
|
|
94
|
+
if (n.o !== null) n.o.$e = undefined;
|
|
95
95
|
// Revert is a pure drop: there is no revert target to commit —
|
|
96
96
|
// override-covered authoritative values hold in _pendingValue and
|
|
97
97
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
@@ -100,7 +100,7 @@ function resolveOptimisticNodes(e) {
|
|
|
100
100
|
ext(n).Pe = NOT_PENDING;
|
|
101
101
|
if (i !== NOT_PENDING && n.be !== unwrapOverride(i)) insertSubs(n, true);
|
|
102
102
|
n.Ae = null;
|
|
103
|
-
if (n.o !== null) n.o.
|
|
103
|
+
if (n.o !== null) n.o.Tt = null;
|
|
104
104
|
}
|
|
105
105
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
106
106
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
@@ -108,7 +108,7 @@ function resolveOptimisticNodes(e) {
|
|
|
108
108
|
for (let t = 0; t < n; t++) {
|
|
109
109
|
const n = e[t];
|
|
110
110
|
if (n.o?.ye || n.o?.Ce) GlobalQueue.un(n);
|
|
111
|
-
const i = n.o?.
|
|
111
|
+
const i = n.o?.St;
|
|
112
112
|
if (i && (i.o?.ye === n || i.o?.Ce === n)) GlobalQueue.un(i);
|
|
113
113
|
}
|
|
114
114
|
e.splice(0, n);
|
|
@@ -119,10 +119,11 @@ function runQueue(e, n) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
* Run effects from all lanes that are ready (no pending async
|
|
122
|
+
* Run effects from all lanes that are ready (no OBSERVED pending async — see
|
|
123
|
+
* laneHeld).
|
|
123
124
|
*/ function runLaneEffects(e) {
|
|
124
125
|
for (const n of activeLanes) {
|
|
125
|
-
if (n.rn || n
|
|
126
|
+
if (n.rn || laneHeld(n)) continue;
|
|
126
127
|
const t = n.tn[e - 1];
|
|
127
128
|
if (t.length) {
|
|
128
129
|
n.tn[e - 1] = [];
|
|
@@ -142,7 +143,7 @@ function cleanupCompletedLanes(e) {
|
|
|
142
143
|
if (n.tn[0].length) runQueue(n.tn[0], EFFECT_RENDER);
|
|
143
144
|
if (n.tn[1].length) runQueue(n.tn[1], EFFECT_USER);
|
|
144
145
|
}
|
|
145
|
-
if (n.nn.o
|
|
146
|
+
if (n.nn.o?.$e === n) if (n.nn.o !== null) n.nn.o.$e = undefined;
|
|
146
147
|
n.Oe.clear();
|
|
147
148
|
n.tn[0].length = 0;
|
|
148
149
|
n.tn[1].length = 0;
|
|
@@ -152,10 +153,18 @@ function cleanupCompletedLanes(e) {
|
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
/** read()'s per-lane suspension test (pending-throw path, lane context). */ function laneSuspends(e) {
|
|
156
|
+
// An UNINITIALIZED async source suspends regardless of lane (#3276): a
|
|
157
|
+
// lane mismatch preserves an already-committed stale value, but a source
|
|
158
|
+
// with no committed truth has nothing to serve — the cross-lane read
|
|
159
|
+
// surfaced a fabricated `undefined` where latest() itself suspends
|
|
160
|
+
// (latestRead rethrows NotReady for tracked uninitialized reads). Lives
|
|
161
|
+
// here rather than read()'s throw path so the floor bundles don't pay:
|
|
162
|
+
// this is only reachable under a lane, which implies the engine.
|
|
163
|
+
if (e.S & STATUS_UNINITIALIZED) return true;
|
|
155
164
|
// Per-lane suspension: only throw if in same lane as pending async
|
|
156
165
|
// AND the node doesn't have an active override (overrides are the visible value,
|
|
157
166
|
// downstream in the lane should read the override, not throw)
|
|
158
|
-
|
|
167
|
+
const n = e.o?.$e;
|
|
159
168
|
if (!n) return false;
|
|
160
169
|
return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
|
|
161
170
|
}
|
|
@@ -176,7 +185,7 @@ function cleanupCompletedLanes(e) {
|
|
|
176
185
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
177
186
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
178
187
|
*/ function laneReadsCommitted(e, n, t) {
|
|
179
|
-
if (e.o?.Pe !== undefined || !!e.o
|
|
188
|
+
if (e.o?.Pe !== undefined || !!e.o?.$e || !!(n.S & STATUS_PENDING)) {
|
|
180
189
|
// The committed view hides a staged in-flight value that will promote
|
|
181
190
|
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
182
191
|
// signals for replay at commit; async memos are excluded from it by the
|
|
@@ -188,7 +197,7 @@ function cleanupCompletedLanes(e) {
|
|
|
188
197
|
if (e.Re !== NOT_PENDING) (activeTransition ?? globalQueue.m).cn.add(t);
|
|
189
198
|
return true;
|
|
190
199
|
}
|
|
191
|
-
if (n === e && stale && t.o?.
|
|
200
|
+
if (n === e && stale && t.o?.St !== e) {
|
|
192
201
|
// The committed view can hide a staged write (a lane member — even just
|
|
193
202
|
// an isPending companion flip — puts the reader "under a lane"). The
|
|
194
203
|
// staged value commits with no re-delivery (commitPendingNode never
|
|
@@ -223,14 +232,14 @@ function cleanupCompletedLanes(e) {
|
|
|
223
232
|
// recompute() runs plain: the value stages and commits with the flush.
|
|
224
233
|
// (el's own override slot excludes companions themselves; a lane merged
|
|
225
234
|
// into a real optimistic lane resolves to a non-companion source.)
|
|
226
|
-
if (!globalQueue.fn && !activeTransition && !n.Ae && n.nn.o?.
|
|
227
|
-
if (e.o !== null) e.o
|
|
235
|
+
if (!globalQueue.fn && !activeTransition && !n.Ae && n.nn.o?.St !== undefined && e.o?.Pe === undefined) {
|
|
236
|
+
if (e.o !== null) e.o.$e = undefined;
|
|
228
237
|
return false;
|
|
229
238
|
}
|
|
230
239
|
return n;
|
|
231
240
|
}
|
|
232
|
-
for (let n = e.
|
|
233
|
-
const t = n.
|
|
241
|
+
for (let n = e.lt; n; n = n.ot) {
|
|
242
|
+
const t = n.st;
|
|
234
243
|
if (t.ie & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
235
244
|
const n = resolveLane(t);
|
|
236
245
|
if (n) {
|
|
@@ -243,13 +252,15 @@ function cleanupCompletedLanes(e) {
|
|
|
243
252
|
return null;
|
|
244
253
|
}
|
|
245
254
|
|
|
246
|
-
/** recompute()'s catch path:
|
|
255
|
+
/** recompute()'s catch path: record the pending async as the current lane's
|
|
256
|
+
* (ownership — laneHeld decides the hold). The lane source's isPending
|
|
257
|
+
* companion is NOT refreshed here: its verdict never read _pendingAsync, and
|
|
258
|
+
* the source's own write/commit/settlement paths keep it current. */ function laneAsyncPending(e) {
|
|
247
259
|
const n = findLane(currentOptimisticLane);
|
|
248
260
|
if (n.nn !== e) {
|
|
249
261
|
n.Oe.add(e);
|
|
250
|
-
ext(e)
|
|
262
|
+
ext(e).$e = n;
|
|
251
263
|
e.T |= CONFIG_HAS_LANE;
|
|
252
|
-
GlobalQueue.de !== null && GlobalQueue.de(n.nn);
|
|
253
264
|
}
|
|
254
265
|
}
|
|
255
266
|
|
|
@@ -257,7 +268,6 @@ function cleanupCompletedLanes(e) {
|
|
|
257
268
|
const n = resolveLane(e);
|
|
258
269
|
if (n) {
|
|
259
270
|
n.Oe.delete(e);
|
|
260
|
-
GlobalQueue.de !== null && GlobalQueue.de(n.nn);
|
|
261
271
|
}
|
|
262
272
|
}
|
|
263
273
|
|
|
@@ -272,18 +282,18 @@ function trackOptimisticStore(e) {
|
|
|
272
282
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
273
283
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
274
284
|
*/ function installOptimisticEngine() {
|
|
275
|
-
if (GlobalQueue.
|
|
276
|
-
GlobalQueue.
|
|
285
|
+
if (GlobalQueue.yt !== null) return;
|
|
286
|
+
GlobalQueue.yt = optimisticWrite;
|
|
277
287
|
GlobalQueue.Tn = resolveOptimisticNodes;
|
|
278
288
|
GlobalQueue.dn = transitionBlocked;
|
|
279
289
|
GlobalQueue.In = cleanupCompletedLanes;
|
|
280
290
|
GlobalQueue.Nn = runLaneEffects;
|
|
281
|
-
GlobalQueue.
|
|
282
|
-
GlobalQueue.
|
|
283
|
-
GlobalQueue.
|
|
284
|
-
GlobalQueue.
|
|
285
|
-
GlobalQueue
|
|
286
|
-
GlobalQueue.
|
|
291
|
+
GlobalQueue.Ut = gatedRead;
|
|
292
|
+
GlobalQueue.kt = laneSuspends;
|
|
293
|
+
GlobalQueue.xt = laneReadsCommitted;
|
|
294
|
+
GlobalQueue.Je = recomputeLane;
|
|
295
|
+
GlobalQueue.tt = laneAsyncPending;
|
|
296
|
+
GlobalQueue.et = laneAsyncSettled;
|
|
287
297
|
GlobalQueue._n = trackOptimisticStore;
|
|
288
298
|
}
|
|
289
299
|
|
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.Qe;
|
|
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.We;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -55,9 +55,9 @@ function disposeChildren(e, t = false, n) {
|
|
|
55
55
|
if (t.o?.ye || t.o?.Ce) GlobalQueue.un(t);
|
|
56
56
|
}
|
|
57
57
|
if (t && e.oe && e.o !== null) e.o.Ie = null;
|
|
58
|
-
let o = n ? e.o?.
|
|
58
|
+
let o = n ? e.o?.Ke ?? null : e.Qe;
|
|
59
59
|
while (o) {
|
|
60
|
-
const e = o.
|
|
60
|
+
const e = o.We;
|
|
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.Ke = null;
|
|
84
84
|
} else {
|
|
85
|
-
e.
|
|
86
|
-
e.
|
|
85
|
+
e.Qe = null;
|
|
86
|
+
e.je = 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.Le !== null && !(e.Le.ie & REACTIVE_DISPOSED)) {
|
|
93
|
+
const t = e.It;
|
|
94
|
+
const n = e.We;
|
|
95
|
+
if (t !== null) t.We = n; else e.Le.Qe = n;
|
|
96
|
+
if (n !== null) n.It = t;
|
|
97
|
+
e.It = 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.Gt) {
|
|
103
|
+
const t = e.Gt;
|
|
104
|
+
e.Gt = 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?.Ze : e.Ge;
|
|
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.
|
|
121
|
+
if (e.o !== null) e.o.Ze = null;
|
|
122
122
|
} else e.Ge = 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.Le) n = n.Le;
|
|
128
|
+
if (n.id != null) return formatId(n.id, t ? n.je++ : n.je);
|
|
129
129
|
throw new Error("");
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -246,27 +246,27 @@ function disposeRootSelf(e = true) {
|
|
|
246
246
|
const i = {
|
|
247
247
|
id: inheritId(e, n, t),
|
|
248
248
|
T: n ? CONFIG_TRANSPARENT : 0,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
Dt: true,
|
|
250
|
+
Pt: t?.Dt ? t.Pt : t,
|
|
251
|
+
Qe: null,
|
|
252
|
+
We: null,
|
|
253
|
+
It: null,
|
|
254
254
|
Ge: null,
|
|
255
255
|
C: t?.C ?? globalQueue,
|
|
256
256
|
we: t?.we || defaultContext,
|
|
257
|
-
|
|
257
|
+
je: 0,
|
|
258
258
|
o: null,
|
|
259
|
-
|
|
259
|
+
Le: t,
|
|
260
260
|
dispose: disposeRootSelf
|
|
261
261
|
};
|
|
262
262
|
if (t) {
|
|
263
|
-
const e = t.
|
|
263
|
+
const e = t.Qe;
|
|
264
264
|
if (e === null) {
|
|
265
|
-
t.
|
|
265
|
+
t.Qe = i;
|
|
266
266
|
} else {
|
|
267
|
-
i.
|
|
268
|
-
e.
|
|
269
|
-
t.
|
|
267
|
+
i.We = e;
|
|
268
|
+
e.It = i;
|
|
269
|
+
t.Qe = i;
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
return i;
|