@solidjs/signals 2.0.0-beta.25 → 2.0.0-beta.26
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 +113 -7
- package/dist/node.cjs +140 -41
- package/dist/prod/core/async.js +180 -107
- package/dist/prod/core/core.js +162 -162
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +28 -28
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +38 -38
- package/dist/prod/core/owner.js +44 -44
- package/dist/prod/core/scheduler.js +94 -94
- package/dist/prod/core/verdict.js +55 -55
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +6 -6
- package/dist/prod/store/reconcile.js +1 -1
- package/dist/prod/store/store.js +58 -32
- package/dist/types/core/async.d.ts +1 -0
- package/dist/types-cjs/core/async.d.cts +1 -0
- package/package.json +1 -1
|
@@ -24,8 +24,8 @@ 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 t = e.
|
|
28
|
-
const i = t ? unwrapOverride(e.
|
|
27
|
+
const t = e.Ae !== NOT_PENDING;
|
|
28
|
+
const i = t ? unwrapOverride(e.Ae) : e.Ue;
|
|
29
29
|
if (typeof n === "function") n = n(i);
|
|
30
30
|
const u = !!(e.S & STATUS_UNINITIALIZED) || !e.Re || !e.Re(i, n);
|
|
31
31
|
if (!u) {
|
|
@@ -41,21 +41,21 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
41
41
|
// No revert target is stashed: while the override is active every reader
|
|
42
42
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
43
43
|
// reverting is just dropping the override — _value is already correct.
|
|
44
|
-
else globalQueue.m.
|
|
44
|
+
else globalQueue.m.je.push(e);
|
|
45
45
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
46
46
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
47
47
|
// which a shared subscriber can merge across transactions (#2912).
|
|
48
48
|
e.sn = activeTransition;
|
|
49
49
|
const o = getOrCreateLane(e);
|
|
50
|
-
e.
|
|
50
|
+
e.Me = o;
|
|
51
51
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
52
52
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
53
53
|
// writes off the optimistic path into permanent commits (#2898).
|
|
54
|
-
e.
|
|
54
|
+
e.Ae = n === undefined ? OVERRIDE_UNDEFINED : n;
|
|
55
55
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
56
56
|
// neither companion present the call is a guaranteed no-op.
|
|
57
|
-
(e.
|
|
58
|
-
e.
|
|
57
|
+
(e.he !== undefined || e.Ge !== undefined) && GlobalQueue.De !== null && GlobalQueue.De(e, n);
|
|
58
|
+
e.Se = clock;
|
|
59
59
|
insertSubs(e, true);
|
|
60
60
|
schedule();
|
|
61
61
|
return n;
|
|
@@ -66,8 +66,8 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
66
66
|
* while one of its optimistic nodes holds an active override that is still
|
|
67
67
|
* pending on real (non-affects-sentinel) async.
|
|
68
68
|
*/ function transitionBlocked(e) {
|
|
69
|
-
for (let n = 0; n < e.
|
|
70
|
-
const t = e.
|
|
69
|
+
for (let n = 0; n < e.je.length; n++) {
|
|
70
|
+
const t = e.je[n];
|
|
71
71
|
if (hasActiveOverride(t) && "S" in t && t.S & STATUS_PENDING && t._ instanceof NotReadyError) {
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
@@ -82,15 +82,15 @@ function resolveOptimisticNodes(e) {
|
|
|
82
82
|
const n = e.length;
|
|
83
83
|
for (let t = 0; t < n; t++) {
|
|
84
84
|
const n = e[t];
|
|
85
|
-
n.
|
|
85
|
+
n.Me = undefined;
|
|
86
86
|
// Revert is a pure drop: there is no revert target to commit —
|
|
87
87
|
// override-covered authoritative values hold in _pendingValue and
|
|
88
88
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
89
89
|
if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
|
|
90
|
-
const i = n.
|
|
91
|
-
n.
|
|
92
|
-
if (i !== NOT_PENDING && n.
|
|
93
|
-
n.
|
|
90
|
+
const i = n.Ae;
|
|
91
|
+
n.Ae = NOT_PENDING;
|
|
92
|
+
if (i !== NOT_PENDING && n.Ue !== unwrapOverride(i)) insertSubs(n, true);
|
|
93
|
+
n.Ie = null;
|
|
94
94
|
n.sn = null;
|
|
95
95
|
}
|
|
96
96
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
@@ -98,9 +98,9 @@ function resolveOptimisticNodes(e) {
|
|
|
98
98
|
// transition that produced them (A19 — pending is a property of the data).
|
|
99
99
|
for (let t = 0; t < n; t++) {
|
|
100
100
|
const n = e[t];
|
|
101
|
-
if (n.
|
|
101
|
+
if (n.he || n.Ge) GlobalQueue.un(n);
|
|
102
102
|
const i = n.nn;
|
|
103
|
-
if (i && (i.
|
|
103
|
+
if (i && (i.he === n || i.Ge === n)) GlobalQueue.un(i);
|
|
104
104
|
}
|
|
105
105
|
e.splice(0, n);
|
|
106
106
|
}
|
|
@@ -113,7 +113,7 @@ function runQueue(e, n) {
|
|
|
113
113
|
* Run effects from all lanes that are ready (no pending async).
|
|
114
114
|
*/ function runLaneEffects(e) {
|
|
115
115
|
for (const n of activeLanes) {
|
|
116
|
-
if (n.tn || n.
|
|
116
|
+
if (n.tn || n.Ne.size > 0) continue;
|
|
117
117
|
const t = n.rn[e - 1];
|
|
118
118
|
if (t.length) {
|
|
119
119
|
n.rn[e - 1] = [];
|
|
@@ -124,14 +124,14 @@ function runQueue(e, n) {
|
|
|
124
124
|
|
|
125
125
|
function cleanupCompletedLanes(e) {
|
|
126
126
|
for (const n of activeLanes) {
|
|
127
|
-
const t = e ? n.
|
|
127
|
+
const t = e ? n.Ie === e : !n.Ie;
|
|
128
128
|
if (!t) continue;
|
|
129
129
|
if (!n.tn) {
|
|
130
130
|
if (n.rn[0].length) runQueue(n.rn[0], EFFECT_RENDER);
|
|
131
131
|
if (n.rn[1].length) runQueue(n.rn[1], EFFECT_USER);
|
|
132
132
|
}
|
|
133
|
-
if (n.en.
|
|
134
|
-
n.
|
|
133
|
+
if (n.en.Me === n) n.en.Me = undefined;
|
|
134
|
+
n.Ne.clear();
|
|
135
135
|
n.rn[0].length = 0;
|
|
136
136
|
n.rn[1].length = 0;
|
|
137
137
|
activeLanes.delete(n);
|
|
@@ -143,7 +143,7 @@ function cleanupCompletedLanes(e) {
|
|
|
143
143
|
// Per-lane suspension: only throw if in same lane as pending async
|
|
144
144
|
// AND the node doesn't have an active override (overrides are the visible value,
|
|
145
145
|
// downstream in the lane should read the override, not throw)
|
|
146
|
-
const n = e.
|
|
146
|
+
const n = e.Me;
|
|
147
147
|
if (!n) return false;
|
|
148
148
|
return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
|
|
149
149
|
}
|
|
@@ -153,7 +153,7 @@ function cleanupCompletedLanes(e) {
|
|
|
153
153
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
154
154
|
* is recorded for replay at commit.
|
|
155
155
|
*/ function gatedRead(e, n, t) {
|
|
156
|
-
if (latestReadActive || e.
|
|
156
|
+
if (latestReadActive || e._e === NOT_PENDING || e.ae || n !== e && !(n.se & REACTIVE_MANUAL_WRITE)) {
|
|
157
157
|
return false;
|
|
158
158
|
}
|
|
159
159
|
activeTransition.ln.add(t);
|
|
@@ -164,7 +164,7 @@ function cleanupCompletedLanes(e) {
|
|
|
164
164
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
165
165
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
166
166
|
*/ function laneReadsCommitted(e, n, t) {
|
|
167
|
-
return e.
|
|
167
|
+
return e.Ae !== undefined || !!e.Me || n === e && stale && t.nn !== e || !!(n.S & STATUS_PENDING);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
@@ -173,8 +173,8 @@ function cleanupCompletedLanes(e) {
|
|
|
173
173
|
* can run before its OPT-dirty child propagates).
|
|
174
174
|
*/ function recomputeLane(e, n) {
|
|
175
175
|
if (n) return resolveLane(e) ?? null;
|
|
176
|
-
for (let n = e.
|
|
177
|
-
const t = n.
|
|
176
|
+
for (let n = e.et; n; n = n.tt) {
|
|
177
|
+
const t = n.nt;
|
|
178
178
|
if (t.se & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
179
179
|
const n = resolveLane(t);
|
|
180
180
|
if (n) {
|
|
@@ -190,17 +190,17 @@ function cleanupCompletedLanes(e) {
|
|
|
190
190
|
/** recompute()'s catch path: track pending async in the current lane. */ function laneAsyncPending(e) {
|
|
191
191
|
const n = findLane(currentOptimisticLane);
|
|
192
192
|
if (n.en !== e) {
|
|
193
|
-
n.
|
|
194
|
-
e.
|
|
195
|
-
GlobalQueue.
|
|
193
|
+
n.Ne.add(e);
|
|
194
|
+
e.Me = n;
|
|
195
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(n.en);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/** recompute()'s success path: the node's async settled, clear it from its lane. */ function laneAsyncSettled(e) {
|
|
200
200
|
const n = resolveLane(e);
|
|
201
201
|
if (n) {
|
|
202
|
-
n.
|
|
203
|
-
GlobalQueue.
|
|
202
|
+
n.Ne.delete(e);
|
|
203
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(n.en);
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
@@ -215,18 +215,18 @@ function trackOptimisticStore(e) {
|
|
|
215
215
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
216
216
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
217
217
|
*/ function installOptimisticEngine() {
|
|
218
|
-
if (GlobalQueue.
|
|
219
|
-
GlobalQueue.
|
|
218
|
+
if (GlobalQueue.ht !== null) return;
|
|
219
|
+
GlobalQueue.ht = optimisticWrite;
|
|
220
220
|
GlobalQueue.En = resolveOptimisticNodes;
|
|
221
221
|
GlobalQueue.dn = transitionBlocked;
|
|
222
222
|
GlobalQueue.Tn = cleanupCompletedLanes;
|
|
223
223
|
GlobalQueue.In = runLaneEffects;
|
|
224
|
-
GlobalQueue.
|
|
225
|
-
GlobalQueue.
|
|
226
|
-
GlobalQueue.
|
|
227
|
-
GlobalQueue.
|
|
228
|
-
GlobalQueue.
|
|
229
|
-
GlobalQueue.
|
|
224
|
+
GlobalQueue.Ot = gatedRead;
|
|
225
|
+
GlobalQueue.Ct = laneSuspends;
|
|
226
|
+
GlobalQueue.Rt = laneReadsCommitted;
|
|
227
|
+
GlobalQueue.Ze = recomputeLane;
|
|
228
|
+
GlobalQueue.ze = laneAsyncPending;
|
|
229
|
+
GlobalQueue.Ke = laneAsyncSettled;
|
|
230
230
|
GlobalQueue.Nn = trackOptimisticStore;
|
|
231
231
|
}
|
|
232
232
|
|
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 n = e.
|
|
15
|
+
let n = e.ke;
|
|
16
16
|
while (n) {
|
|
17
17
|
const e = n.se;
|
|
18
18
|
n.se = e | REACTIVE_ZOMBIE;
|
|
@@ -26,17 +26,17 @@ function markDisposal(e) {
|
|
|
26
26
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(n, zombieQueue); else insertIntoHeapHeight(n, zombieQueue);
|
|
27
27
|
}
|
|
28
28
|
markDisposal(n);
|
|
29
|
-
n = n.
|
|
29
|
+
n = n.Fe;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function dispose(e) {
|
|
34
|
-
let n = e.
|
|
34
|
+
let n = e.et;
|
|
35
35
|
while (n !== null) {
|
|
36
36
|
n = unlinkSubs(n);
|
|
37
37
|
}
|
|
38
|
-
e.
|
|
39
|
-
e.
|
|
38
|
+
e.et = null;
|
|
39
|
+
e.We = null;
|
|
40
40
|
disposeChildren(e, true);
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -51,54 +51,54 @@ function disposeChildren(e, n = false, t) {
|
|
|
51
51
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
52
52
|
// false, and notifies subscribers still watching the companion.
|
|
53
53
|
const n = e;
|
|
54
|
-
if (n.
|
|
54
|
+
if (n.he || n.Ge) GlobalQueue.un(n);
|
|
55
55
|
}
|
|
56
|
-
if (n && e.
|
|
57
|
-
let l = t ? e.
|
|
56
|
+
if (n && e.ae) e.Te = null;
|
|
57
|
+
let l = t ? e.Qe : e.ke;
|
|
58
58
|
while (l) {
|
|
59
|
-
const e = l.
|
|
60
|
-
if (l.
|
|
59
|
+
const e = l.Fe;
|
|
60
|
+
if (l.et) {
|
|
61
61
|
const e = l;
|
|
62
62
|
deleteFromHeap(e, queueFor(e));
|
|
63
|
-
let n = e.
|
|
63
|
+
let n = e.et;
|
|
64
64
|
do {
|
|
65
65
|
n = unlinkSubs(n);
|
|
66
66
|
} while (n !== null);
|
|
67
|
-
e.
|
|
68
|
-
e.
|
|
67
|
+
e.et = null;
|
|
68
|
+
e.We = null;
|
|
69
69
|
}
|
|
70
70
|
disposeChildren(l, true);
|
|
71
71
|
l = e;
|
|
72
72
|
}
|
|
73
73
|
if (t) {
|
|
74
|
-
e.
|
|
74
|
+
e.Qe = null;
|
|
75
75
|
} else {
|
|
76
|
-
e.
|
|
77
|
-
e.
|
|
76
|
+
e.ke = null;
|
|
77
|
+
e.qe = 0;
|
|
78
78
|
}
|
|
79
79
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
80
80
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
81
81
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
82
82
|
// walks that already advanced past us still reach later siblings.
|
|
83
|
-
if (n && !t && !(i & REACTIVE_ZOMBIE) && e.
|
|
84
|
-
const n = e.
|
|
85
|
-
const t = e.
|
|
86
|
-
if (n !== null) n.
|
|
87
|
-
if (t !== null) t.
|
|
88
|
-
e.
|
|
83
|
+
if (n && !t && !(i & REACTIVE_ZOMBIE) && e.ve !== null && !(e.ve.se & REACTIVE_DISPOSED)) {
|
|
84
|
+
const n = e.rt;
|
|
85
|
+
const t = e.Fe;
|
|
86
|
+
if (n !== null) n.Fe = t; else e.ve.ke = t;
|
|
87
|
+
if (t !== null) t.rt = n;
|
|
88
|
+
e.rt = null;
|
|
89
89
|
}
|
|
90
90
|
runDisposal(e, t);
|
|
91
91
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
92
92
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
93
|
-
if (n && e.
|
|
94
|
-
const n = e.
|
|
95
|
-
e.
|
|
93
|
+
if (n && e.Et) {
|
|
94
|
+
const n = e.Et;
|
|
95
|
+
e.Et = undefined;
|
|
96
96
|
n();
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
function runDisposal(e, n) {
|
|
101
|
-
let t = n ? e.
|
|
101
|
+
let t = n ? e.ye : e.Le;
|
|
102
102
|
if (!t) return;
|
|
103
103
|
if (Array.isArray(t)) {
|
|
104
104
|
for (let e = 0; e < t.length; e++) {
|
|
@@ -108,13 +108,13 @@ function runDisposal(e, n) {
|
|
|
108
108
|
} else {
|
|
109
109
|
t.call(t);
|
|
110
110
|
}
|
|
111
|
-
n ? e.
|
|
111
|
+
n ? e.ye = null : e.Le = null;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
function childId(e, n) {
|
|
115
115
|
let t = e;
|
|
116
|
-
while (t.T & CONFIG_TRANSPARENT && t.
|
|
117
|
-
if (t.id != null) return formatId(t.id, n ? t.
|
|
116
|
+
while (t.T & CONFIG_TRANSPARENT && t.ve) t = t.ve;
|
|
117
|
+
if (t.id != null) return formatId(t.id, n ? t.qe++ : t.qe);
|
|
118
118
|
throw new Error("");
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -195,7 +195,7 @@ function formatId(e, n) {
|
|
|
195
195
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
196
196
|
*/ function cleanup(e) {
|
|
197
197
|
if (!context) return e;
|
|
198
|
-
if (!context.
|
|
198
|
+
if (!context.Le) context.Le = e; else if (Array.isArray(context.Le)) context.Le.push(e); else context.Le = [ context.Le, e ];
|
|
199
199
|
return e;
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -235,28 +235,28 @@ function disposeRootSelf(e = true) {
|
|
|
235
235
|
const i = {
|
|
236
236
|
id: inheritId(e, t, n),
|
|
237
237
|
T: t ? CONFIG_TRANSPARENT : 0,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
238
|
+
Nt: true,
|
|
239
|
+
Tt: n?.Nt ? n.Tt : n,
|
|
240
|
+
ke: null,
|
|
241
|
+
Fe: null,
|
|
242
|
+
rt: null,
|
|
243
|
+
Le: null,
|
|
244
244
|
C: n?.C ?? globalQueue,
|
|
245
245
|
we: n?.we || defaultContext,
|
|
246
|
-
|
|
247
|
-
Le: null,
|
|
246
|
+
qe: 0,
|
|
248
247
|
ye: null,
|
|
249
|
-
|
|
248
|
+
Qe: null,
|
|
249
|
+
ve: n,
|
|
250
250
|
dispose: disposeRootSelf
|
|
251
251
|
};
|
|
252
252
|
if (n) {
|
|
253
|
-
const e = n.
|
|
253
|
+
const e = n.ke;
|
|
254
254
|
if (e === null) {
|
|
255
|
-
n.
|
|
255
|
+
n.ke = i;
|
|
256
256
|
} else {
|
|
257
|
-
i.
|
|
258
|
-
e.
|
|
259
|
-
n.
|
|
257
|
+
i.Fe = e;
|
|
258
|
+
e.rt = i;
|
|
259
|
+
n.ke = i;
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
return i;
|