@solidjs/signals 2.0.0-beta.24 → 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 +577 -87
- package/dist/node.cjs +1120 -683
- package/dist/prod/core/async.js +180 -107
- package/dist/prod/core/core.js +214 -180
- package/dist/prod/core/effect.js +19 -19
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +25 -25
- package/dist/prod/core/heap.js +23 -23
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +42 -40
- package/dist/prod/core/owner.js +41 -41
- package/dist/prod/core/scheduler.js +90 -90
- package/dist/prod/core/verdict.js +54 -54
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +18 -11
- package/dist/prod/store/projection.js +25 -18
- package/dist/prod/store/reconcile.js +405 -211
- package/dist/prod/store/store.js +225 -105
- package/dist/prod/store/utils.js +22 -22
- package/dist/types/core/async.d.ts +1 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/store/optimistic.d.ts +1 -1
- package/dist/types/store/store.d.ts +20 -2
- package/dist/types-cjs/core/async.d.cts +1 -0
- package/dist/types-cjs/core/core.d.cts +15 -0
- package/dist/types-cjs/store/optimistic.d.cts +1 -1
- package/dist/types-cjs/store/store.d.cts +20 -2
- package/package.json +1 -1
package/dist/prod/core/core.js
CHANGED
|
@@ -48,8 +48,8 @@ let snapshotSources = null;
|
|
|
48
48
|
|
|
49
49
|
function ownerInSnapshotScope(e) {
|
|
50
50
|
while (e) {
|
|
51
|
-
if (e.
|
|
52
|
-
e = e.
|
|
51
|
+
if (e.me) return true;
|
|
52
|
+
e = e.ve;
|
|
53
53
|
}
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
@@ -60,41 +60,41 @@ function setSnapshotCapture(e) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function markSnapshotScope(e) {
|
|
63
|
-
e.
|
|
63
|
+
e.me = true;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function releaseSnapshotScope(e) {
|
|
67
|
-
e.
|
|
67
|
+
e.me = false;
|
|
68
68
|
releaseSubtree(e);
|
|
69
69
|
schedule();
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function releaseSubtree(e) {
|
|
73
|
-
let t = e.
|
|
73
|
+
let t = e.ke;
|
|
74
74
|
while (t) {
|
|
75
|
-
if (t.
|
|
76
|
-
t = t.
|
|
75
|
+
if (t.me) {
|
|
76
|
+
t = t.Fe;
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
|
-
if (t.
|
|
79
|
+
if (t.ae) {
|
|
80
80
|
const e = t;
|
|
81
81
|
e.T &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
82
82
|
if (e.se & REACTIVE_SNAPSHOT_STALE) {
|
|
83
83
|
e.se &= ~REACTIVE_SNAPSHOT_STALE;
|
|
84
84
|
e.se |= REACTIVE_DIRTY;
|
|
85
|
-
if (dirtyQueue.He > e.
|
|
85
|
+
if (dirtyQueue.He > e.Ve) dirtyQueue.He = e.Ve;
|
|
86
86
|
insertIntoHeap(e, dirtyQueue);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
releaseSubtree(t);
|
|
90
|
-
t = t.
|
|
90
|
+
t = t.Fe;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function clearSnapshots() {
|
|
95
95
|
if (snapshotSources) {
|
|
96
96
|
for (const e of snapshotSources) {
|
|
97
|
-
delete e.
|
|
97
|
+
delete e.xe;
|
|
98
98
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
99
99
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
100
100
|
// when present so signal-node sources don't grow the field.
|
|
@@ -106,35 +106,35 @@ function clearSnapshots() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function recompute(e, t = false) {
|
|
109
|
-
const n = e.
|
|
109
|
+
const n = e.Pe;
|
|
110
110
|
if (!t) {
|
|
111
|
-
if (e.
|
|
111
|
+
if (e.Ie && (!n || activeTransition) && activeTransition !== e.Ie) globalQueue.initTransition(e.Ie);
|
|
112
112
|
deleteFromHeap(e, queueFor(e));
|
|
113
113
|
e.Te = null;
|
|
114
114
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
115
|
-
if (e.
|
|
115
|
+
if (e.Ie || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ke !== null || e.Le !== null) {
|
|
116
116
|
markDisposal(e);
|
|
117
|
-
e.ye = e.
|
|
118
|
-
e.
|
|
119
|
-
e.
|
|
120
|
-
e.
|
|
121
|
-
e.
|
|
117
|
+
e.ye = e.Le;
|
|
118
|
+
e.Qe = e.ke;
|
|
119
|
+
e.Le = null;
|
|
120
|
+
e.ke = null;
|
|
121
|
+
e.qe = 0;
|
|
122
122
|
} else ;
|
|
123
123
|
}
|
|
124
124
|
let i = !!(e.se & REACTIVE_OPTIMISTIC_DIRTY);
|
|
125
|
-
const
|
|
126
|
-
const
|
|
125
|
+
const u = e.Ae !== undefined && e.Ae !== NOT_PENDING;
|
|
126
|
+
const l = !!(e.S & STATUS_UNINITIALIZED);
|
|
127
127
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
128
128
|
// the recompute wipes _flags below.
|
|
129
129
|
const o = (e.se & REACTIVE_REASK) !== 0;
|
|
130
130
|
const s = context;
|
|
131
131
|
context = e;
|
|
132
|
-
e.
|
|
132
|
+
e.We = null;
|
|
133
133
|
e.Ye++;
|
|
134
134
|
e.se = REACTIVE_RECOMPUTING_DEPS;
|
|
135
|
-
e.
|
|
136
|
-
let a = e.
|
|
137
|
-
let r = e.
|
|
135
|
+
e.Se = clock;
|
|
136
|
+
let a = e._e === NOT_PENDING ? e.Ue : e._e;
|
|
137
|
+
let r = e.Ve;
|
|
138
138
|
let c = tracking;
|
|
139
139
|
let _ = currentOptimisticLane;
|
|
140
140
|
tracking = true;
|
|
@@ -144,30 +144,30 @@ function recompute(e, t = false) {
|
|
|
144
144
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
145
145
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
146
146
|
// covers creation-time computes and flushes that run inside the window.
|
|
147
|
-
const
|
|
147
|
+
const f = latestReadActive;
|
|
148
148
|
latestReadActive = false;
|
|
149
149
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
150
150
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
151
151
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
152
152
|
if (i) {
|
|
153
|
-
const t = GlobalQueue.
|
|
153
|
+
const t = GlobalQueue.Ze(e, true);
|
|
154
154
|
if (t) currentOptimisticLane = t;
|
|
155
|
-
} else if (activeTransition && !t && activeTransition.
|
|
155
|
+
} else if (activeTransition && !t && activeTransition.je.length) {
|
|
156
156
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
157
157
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
158
158
|
// recomputes under the right posture and propagates correctly.
|
|
159
|
-
const t = GlobalQueue.
|
|
159
|
+
const t = GlobalQueue.Ze(e, false);
|
|
160
160
|
if (t) {
|
|
161
161
|
i = true;
|
|
162
162
|
currentOptimisticLane = t;
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
const
|
|
165
|
+
const E = n && n !== EFFECT_USER;
|
|
166
166
|
const N = stale;
|
|
167
|
-
if (
|
|
167
|
+
if (E) stale = true;
|
|
168
168
|
try {
|
|
169
169
|
if (!false && e.T & CONFIG_SYNC) {
|
|
170
|
-
a = e.
|
|
170
|
+
a = e.ae(a);
|
|
171
171
|
e.Te = null;
|
|
172
172
|
} else {
|
|
173
173
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
@@ -176,39 +176,42 @@ function recompute(e, t = false) {
|
|
|
176
176
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
177
177
|
// iteration drive updates.
|
|
178
178
|
const t = e.Te;
|
|
179
|
-
const n = e.
|
|
179
|
+
const n = e.ae(a);
|
|
180
180
|
const i = typeof n === "object" && n !== null;
|
|
181
|
-
const
|
|
182
|
-
a =
|
|
183
|
-
if (!
|
|
181
|
+
const u = e.Te !== t;
|
|
182
|
+
a = u || !i ? n : handleAsync(e, n);
|
|
183
|
+
if (!u && !i) e.Te = null;
|
|
184
184
|
}
|
|
185
|
-
clearStatus
|
|
185
|
+
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
186
|
+
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
187
|
+
// the flags write (create or not) stores the 0 already there.
|
|
188
|
+
if (e.S !== 0 || e.i !== undefined || e._ || e.be || e.de || e.oe !== undefined || e.he !== undefined || e.Ge !== undefined || e.u !== null) clearStatus(e, t);
|
|
186
189
|
// _optimisticLane is only ever assigned by engine paths.
|
|
187
|
-
if (e.
|
|
190
|
+
if (e.Me) GlobalQueue.Ke(e);
|
|
188
191
|
} catch (t) {
|
|
189
192
|
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
190
193
|
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
191
|
-
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.
|
|
194
|
+
if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.ze(e);
|
|
192
195
|
let n = false;
|
|
193
196
|
if (t instanceof NotReadyError) {
|
|
194
|
-
e.
|
|
195
|
-
if (GlobalQueue
|
|
197
|
+
e.de = true;
|
|
198
|
+
if (GlobalQueue.$e !== null) n = GlobalQueue.$e(e, o);
|
|
196
199
|
}
|
|
197
|
-
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.
|
|
200
|
+
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.Me : undefined);
|
|
198
201
|
if (n) GlobalQueue.k(e);
|
|
199
202
|
} finally {
|
|
200
203
|
tracking = c;
|
|
201
|
-
latestReadActive =
|
|
202
|
-
if (
|
|
204
|
+
latestReadActive = f;
|
|
205
|
+
if (E) stale = N;
|
|
203
206
|
e.se = REACTIVE_NONE | (t ? e.se & REACTIVE_SNAPSHOT_STALE : 0);
|
|
204
207
|
context = s;
|
|
205
208
|
}
|
|
206
209
|
if (!e._) {
|
|
207
210
|
trimStaleDeps(e);
|
|
208
|
-
const o =
|
|
211
|
+
const o = u ? unwrapOverride(e.Ae) : e._e === NOT_PENDING ? e.Ue : e._e;
|
|
209
212
|
let s = false;
|
|
210
213
|
try {
|
|
211
|
-
s = !n &&
|
|
214
|
+
s = !n && l || !e.Re || !e.Re(o, a);
|
|
212
215
|
} catch (t) {
|
|
213
216
|
// A throwing user comparator is an error of this node's computation.
|
|
214
217
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -222,62 +225,69 @@ function recompute(e, t = false) {
|
|
|
222
225
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
223
226
|
// effect() can call its runner synchronously for the first run.
|
|
224
227
|
if (n && s) {
|
|
225
|
-
e
|
|
228
|
+
e.Be = !e._;
|
|
226
229
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
227
230
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
228
|
-
if (!t) e.C.enqueue(n, e.
|
|
231
|
+
if (!t) e.C.enqueue(n, e.Je ??= GlobalQueue.Xe.bind(null, e));
|
|
229
232
|
}
|
|
230
233
|
if (e._) ; else if (s) {
|
|
231
|
-
const
|
|
232
|
-
if (t ||
|
|
233
|
-
|
|
234
|
+
const l = u ? e.Ae : undefined;
|
|
235
|
+
if (t ||
|
|
236
|
+
// Plain sync flush (no transition on either side) commits effect
|
|
237
|
+
// values directly — the pending round-trip (queuePendingNode +
|
|
238
|
+
// commitPendingNodes) exists to sequence transition reveals, and
|
|
239
|
+
// paying it per effect on the plain path is pure overhead.
|
|
240
|
+
n && (activeTransition !== e.Ie || activeTransition === null) || i) {
|
|
241
|
+
e.Ue = a;
|
|
234
242
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
235
243
|
// override unconditionally. The direct _value commit is the lane's
|
|
236
244
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
237
245
|
// commit can't clobber the fresh value.
|
|
238
|
-
if (
|
|
239
|
-
e.
|
|
240
|
-
e.
|
|
246
|
+
if (u && i) {
|
|
247
|
+
e.Ae = a === undefined ? OVERRIDE_UNDEFINED : a;
|
|
248
|
+
e._e = NOT_PENDING;
|
|
241
249
|
}
|
|
242
250
|
} else {
|
|
243
|
-
e.
|
|
251
|
+
e._e = a;
|
|
244
252
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
245
253
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
246
254
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
247
255
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
248
256
|
// pending value commits before effects run.
|
|
249
|
-
if ((activeTransition || e.
|
|
257
|
+
if ((activeTransition || e.Ie) && GlobalQueue.De !== null) GlobalQueue.De(e, a);
|
|
250
258
|
}
|
|
251
|
-
|
|
252
|
-
|
|
259
|
+
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
260
|
+
// subscriber-less node has nothing to notify.
|
|
261
|
+
if (e.o !== null && (!u || i || e.Ae !== l)) insertSubs(e, i || u);
|
|
262
|
+
} else if (u) {
|
|
253
263
|
// Unchanged value (equals the override) recomputed while the override
|
|
254
264
|
// is active: _value may still be stale, so hold the authoritative value
|
|
255
265
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
256
|
-
if (e.
|
|
257
|
-
e.
|
|
258
|
-
} else if (e.
|
|
266
|
+
if (e._e === NOT_PENDING) queuePendingNode(e);
|
|
267
|
+
e._e = a;
|
|
268
|
+
} else if (e.Ve != r) {
|
|
259
269
|
for (let t = e.o; t !== null; t = t.ue) {
|
|
260
270
|
insertIntoHeapHeight(t.le, queueFor(t.le));
|
|
261
271
|
}
|
|
262
272
|
}
|
|
263
273
|
}
|
|
264
274
|
currentOptimisticLane = _;
|
|
265
|
-
const T = e.
|
|
275
|
+
const T = e._e !== NOT_PENDING || e.Qe !== null || e.ye !== null || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
266
276
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
267
277
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
268
278
|
// under the override (A17). Revert no longer commits anything, so an
|
|
269
279
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
270
280
|
// _transition.
|
|
271
|
-
T && (!t || e.S & STATUS_PENDING) && (!e.
|
|
272
|
-
e.
|
|
281
|
+
T && (!t || e.S & STATUS_PENDING) && (!e.Ie || u) && queuePendingNode(e);
|
|
282
|
+
e.Ie && n && activeTransition !== e.Ie && runInTransition(e.Ie, () => recompute(e));
|
|
273
283
|
}
|
|
274
284
|
|
|
275
285
|
function updateIfNecessary(e) {
|
|
276
286
|
if (e.se & REACTIVE_CHECK) {
|
|
277
|
-
for (let t = e.
|
|
278
|
-
const n = t.
|
|
279
|
-
const i = n.
|
|
280
|
-
if (i.
|
|
287
|
+
for (let t = e.et; t; t = t.tt) {
|
|
288
|
+
const n = t.nt;
|
|
289
|
+
const i = n.it || n;
|
|
290
|
+
if (i.ae) {
|
|
281
291
|
updateIfNecessary(i);
|
|
282
292
|
}
|
|
283
293
|
if (e.se & REACTIVE_DIRTY) {
|
|
@@ -285,7 +295,7 @@ function updateIfNecessary(e) {
|
|
|
285
295
|
}
|
|
286
296
|
}
|
|
287
297
|
}
|
|
288
|
-
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e._ && e.
|
|
298
|
+
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e._ && e.Se < clock && !e.Te) {
|
|
289
299
|
recompute(e);
|
|
290
300
|
}
|
|
291
301
|
e.se = e.se & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -297,35 +307,35 @@ function computed(e, t) {
|
|
|
297
307
|
id: inheritId(t, n, context),
|
|
298
308
|
T: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
299
309
|
Re: t?.equals != null ? t.equals : isEqual,
|
|
300
|
-
|
|
301
|
-
|
|
310
|
+
ut: t?.unobserved,
|
|
311
|
+
Le: null,
|
|
302
312
|
C: context?.C ?? globalQueue,
|
|
303
313
|
we: context?.we ?? defaultContext,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
314
|
+
qe: 0,
|
|
315
|
+
ae: e,
|
|
316
|
+
Ue: undefined,
|
|
317
|
+
Ve: 0,
|
|
308
318
|
u: null,
|
|
309
319
|
lt: undefined,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
320
|
+
ot: null,
|
|
321
|
+
et: null,
|
|
322
|
+
We: null,
|
|
313
323
|
Ye: 0,
|
|
314
324
|
o: null,
|
|
315
|
-
ot: null,
|
|
316
|
-
Ge: context,
|
|
317
|
-
ve: null,
|
|
318
325
|
st: null,
|
|
319
|
-
|
|
326
|
+
ve: context,
|
|
327
|
+
Fe: null,
|
|
328
|
+
rt: null,
|
|
329
|
+
ke: null,
|
|
320
330
|
se: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
321
331
|
S: STATUS_UNINITIALIZED,
|
|
322
|
-
|
|
323
|
-
|
|
332
|
+
Se: clock,
|
|
333
|
+
_e: NOT_PENDING,
|
|
324
334
|
ye: null,
|
|
325
|
-
|
|
335
|
+
Qe: null,
|
|
326
336
|
Te: null,
|
|
327
|
-
|
|
328
|
-
|
|
337
|
+
Ie: null,
|
|
338
|
+
be: false
|
|
329
339
|
};
|
|
330
340
|
setupComputedNode(i, t);
|
|
331
341
|
return i;
|
|
@@ -336,48 +346,48 @@ function computed(e, t) {
|
|
|
336
346
|
* so V8 sees the full hidden class shape at construction time. Effects always run in lazy
|
|
337
347
|
* mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
|
|
338
348
|
* the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
|
|
339
|
-
*/ function createEffectNode(e, t, n, i,
|
|
340
|
-
const o =
|
|
349
|
+
*/ function createEffectNode(e, t, n, i, u, l) {
|
|
350
|
+
const o = l?.transparent ?? false;
|
|
341
351
|
const s = {
|
|
342
|
-
id: inheritId(
|
|
343
|
-
T: (o ? CONFIG_TRANSPARENT : 0) | (
|
|
352
|
+
id: inheritId(l, o, context),
|
|
353
|
+
T: (o ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
344
354
|
Re: false,
|
|
345
|
-
|
|
346
|
-
|
|
355
|
+
ut: l?.unobserved,
|
|
356
|
+
Le: null,
|
|
347
357
|
C: context?.C ?? globalQueue,
|
|
348
358
|
we: context?.we ?? defaultContext,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
359
|
+
qe: 0,
|
|
360
|
+
ae: e,
|
|
361
|
+
Ue: undefined,
|
|
362
|
+
Ve: 0,
|
|
353
363
|
u: null,
|
|
354
364
|
lt: undefined,
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
365
|
+
ot: null,
|
|
366
|
+
et: null,
|
|
367
|
+
We: null,
|
|
358
368
|
Ye: 0,
|
|
359
369
|
o: null,
|
|
360
|
-
ot: null,
|
|
361
|
-
Ge: context,
|
|
362
|
-
ve: null,
|
|
363
370
|
st: null,
|
|
364
|
-
|
|
371
|
+
ve: context,
|
|
372
|
+
Fe: null,
|
|
373
|
+
rt: null,
|
|
374
|
+
ke: null,
|
|
365
375
|
se: REACTIVE_LAZY,
|
|
366
376
|
S: STATUS_UNINITIALIZED,
|
|
367
|
-
|
|
368
|
-
|
|
377
|
+
Se: clock,
|
|
378
|
+
_e: NOT_PENDING,
|
|
369
379
|
ye: null,
|
|
370
|
-
|
|
380
|
+
Qe: null,
|
|
371
381
|
Te: null,
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
382
|
+
Ie: null,
|
|
383
|
+
be: false,
|
|
384
|
+
Be: false,
|
|
385
|
+
ct: undefined,
|
|
386
|
+
_t: t,
|
|
387
|
+
ft: n,
|
|
378
388
|
Et: undefined,
|
|
379
|
-
|
|
380
|
-
i:
|
|
389
|
+
Pe: i,
|
|
390
|
+
i: u
|
|
381
391
|
};
|
|
382
392
|
setupComputedNode(s, lazyOptions);
|
|
383
393
|
return s;
|
|
@@ -388,24 +398,24 @@ const lazyOptions = {
|
|
|
388
398
|
};
|
|
389
399
|
|
|
390
400
|
function setupComputedNode(e, t) {
|
|
391
|
-
e.
|
|
392
|
-
const n = context?.
|
|
401
|
+
e.ot = e;
|
|
402
|
+
const n = context?.Nt ? context.Tt : context;
|
|
393
403
|
if (context) {
|
|
394
|
-
const t = context.
|
|
404
|
+
const t = context.ke;
|
|
395
405
|
if (t === null) {
|
|
396
|
-
context.
|
|
406
|
+
context.ke = e;
|
|
397
407
|
} else {
|
|
398
|
-
e.
|
|
399
|
-
t.
|
|
400
|
-
context.
|
|
408
|
+
e.Fe = t;
|
|
409
|
+
t.rt = e;
|
|
410
|
+
context.ke = e;
|
|
401
411
|
}
|
|
402
412
|
}
|
|
403
|
-
if (n) e.
|
|
404
|
-
if (GlobalQueue.
|
|
413
|
+
if (n) e.Ve = n.Ve + 1;
|
|
414
|
+
if (GlobalQueue.It !== null) GlobalQueue.It(e);
|
|
405
415
|
!t?.lazy && recompute(e, true);
|
|
406
416
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
407
417
|
if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
|
|
408
|
-
e.
|
|
418
|
+
e.xe = e.Ue === undefined ? NO_SNAPSHOT : e.Ue;
|
|
409
419
|
snapshotSources.add(e);
|
|
410
420
|
}
|
|
411
421
|
}
|
|
@@ -415,18 +425,18 @@ function signal(e, t, n = null) {
|
|
|
415
425
|
const i = {
|
|
416
426
|
Re: t?.equals != null ? t.equals : isEqual,
|
|
417
427
|
T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0),
|
|
418
|
-
|
|
419
|
-
|
|
428
|
+
ut: t?.unobserved,
|
|
429
|
+
Ue: e,
|
|
420
430
|
o: null,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
431
|
+
st: null,
|
|
432
|
+
Se: clock,
|
|
433
|
+
it: n,
|
|
424
434
|
fe: n?.u || null,
|
|
425
|
-
|
|
435
|
+
_e: NOT_PENDING
|
|
426
436
|
};
|
|
427
437
|
n && (n.u = i);
|
|
428
438
|
if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
|
|
429
|
-
i.
|
|
439
|
+
i.xe = e === undefined ? NO_SNAPSHOT : e;
|
|
430
440
|
snapshotSources.add(i);
|
|
431
441
|
}
|
|
432
442
|
return i;
|
|
@@ -434,13 +444,13 @@ function signal(e, t, n = null) {
|
|
|
434
444
|
|
|
435
445
|
function optimisticSignal(e, t) {
|
|
436
446
|
const n = signal(e, t);
|
|
437
|
-
n.
|
|
447
|
+
n.Ae = NOT_PENDING;
|
|
438
448
|
return n;
|
|
439
449
|
}
|
|
440
450
|
|
|
441
451
|
function optimisticComputed(e, t) {
|
|
442
452
|
const n = computed(e, t);
|
|
443
|
-
n.
|
|
453
|
+
n.Ae = NOT_PENDING;
|
|
444
454
|
return n;
|
|
445
455
|
}
|
|
446
456
|
|
|
@@ -470,11 +480,11 @@ function isEqual(e, t) {
|
|
|
470
480
|
* );
|
|
471
481
|
* ```
|
|
472
482
|
*/ function untrack(e, t) {
|
|
473
|
-
if (GlobalQueue.
|
|
483
|
+
if (GlobalQueue.dt === null && !tracking && true) return e();
|
|
474
484
|
const n = tracking;
|
|
475
485
|
tracking = false;
|
|
476
486
|
try {
|
|
477
|
-
if (GlobalQueue.
|
|
487
|
+
if (GlobalQueue.dt !== null) return GlobalQueue.dt(e);
|
|
478
488
|
return e();
|
|
479
489
|
} finally {
|
|
480
490
|
tracking = n;
|
|
@@ -496,6 +506,27 @@ function isEqual(e, t) {
|
|
|
496
506
|
}
|
|
497
507
|
}
|
|
498
508
|
|
|
509
|
+
/**
|
|
510
|
+
* Sentinel returned by readNodeFast when the plain-signal fast path does not
|
|
511
|
+
* apply and the caller must fall back to the full read().
|
|
512
|
+
*/ const READ_SLOW = Symbol("read-slow");
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* read()'s plain-signal fast path as a standalone entry for hot callers
|
|
516
|
+
* (store traps). Safe to substitute for read() only because the bail
|
|
517
|
+
* conditions mirror read()'s prelude and fast-path guard exactly: the
|
|
518
|
+
* latestRead and pendingCheck windows run side-effectful hooks before the
|
|
519
|
+
* fast path, `_fn` nodes need prepareComputed, and firewall / override /
|
|
520
|
+
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
521
|
+
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
522
|
+
*/ function readNodeFast(e) {
|
|
523
|
+
if (latestReadActive || pendingCheckActive || e.ae || e.it || e.Ae !== undefined || e.xe !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
524
|
+
let t = context;
|
|
525
|
+
if (t?.Nt) t = t.Tt;
|
|
526
|
+
if (t && tracking) link(e, t);
|
|
527
|
+
return !t || e._e === NOT_PENDING ? e.Ue : e._e;
|
|
528
|
+
}
|
|
529
|
+
|
|
499
530
|
function read(e) {
|
|
500
531
|
// Handle latest() mode: read from _latestValueComputed
|
|
501
532
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
@@ -503,76 +534,76 @@ function read(e) {
|
|
|
503
534
|
// than the original node (which stays "pending" while held in a transition).
|
|
504
535
|
if (latestReadActive) return GlobalQueue.St(e);
|
|
505
536
|
let t = context;
|
|
506
|
-
if (t?.
|
|
537
|
+
if (t?.Nt) t = t.Tt;
|
|
507
538
|
const n = e;
|
|
508
|
-
const i = e.
|
|
509
|
-
const
|
|
539
|
+
const i = e.it;
|
|
540
|
+
const u = i || e;
|
|
510
541
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
511
542
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
512
543
|
// recompute don't collect into the probe.
|
|
513
544
|
if (pendingCheckActive) {
|
|
514
|
-
GlobalQueue.
|
|
515
|
-
} else if (typeof n.
|
|
545
|
+
GlobalQueue.At(e, t, u, i);
|
|
546
|
+
} else if (typeof n.ae === "function") {
|
|
516
547
|
prepareComputed(e, false);
|
|
517
548
|
}
|
|
518
|
-
if (!n.
|
|
549
|
+
if (!n.ae && u === e && e.Ae === undefined && e.xe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
519
550
|
if (t && tracking) link(e, t);
|
|
520
|
-
return !t || e.
|
|
551
|
+
return !t || e._e === NOT_PENDING ? e.Ue : e._e;
|
|
521
552
|
}
|
|
522
553
|
if (t && tracking) {
|
|
523
554
|
link(e, t, pendingCheckActive);
|
|
524
|
-
if (
|
|
555
|
+
if (u.ae) {
|
|
525
556
|
const n = queueFor(e);
|
|
526
|
-
if (
|
|
557
|
+
if (u.Ve >= n.He) {
|
|
527
558
|
markNode(t);
|
|
528
559
|
markHeap(n);
|
|
529
|
-
updateIfNecessary(
|
|
560
|
+
updateIfNecessary(u);
|
|
530
561
|
}
|
|
531
|
-
const i =
|
|
562
|
+
const i = u.Ve;
|
|
532
563
|
// parent check is shallow, might need to be recursive
|
|
533
|
-
if (i >= t.
|
|
534
|
-
t.
|
|
564
|
+
if (i >= t.Ve && e.ve !== t) {
|
|
565
|
+
t.Ve = i + 1;
|
|
535
566
|
}
|
|
536
567
|
}
|
|
537
568
|
}
|
|
538
|
-
if (
|
|
539
|
-
if (t && !(stale &&
|
|
569
|
+
if (u.S & STATUS_PENDING) {
|
|
570
|
+
if (t && !(stale && u.Ie && activeTransition !== u.Ie)) {
|
|
540
571
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
541
572
|
// is installed): under a lane, only same-lane pending async without an
|
|
542
573
|
// active override throws.
|
|
543
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
574
|
+
if (currentOptimisticLane === null || GlobalQueue.Ct(u)) {
|
|
544
575
|
if (!tracking && e !== t) link(e, t);
|
|
545
|
-
throw
|
|
576
|
+
throw u._;
|
|
546
577
|
}
|
|
547
|
-
} else if (t &&
|
|
578
|
+
} else if (t && u !== e && u.S & STATUS_UNINITIALIZED) {
|
|
548
579
|
if (!tracking && e !== t) link(e, t);
|
|
549
|
-
throw
|
|
550
|
-
} else if (!t &&
|
|
551
|
-
throw
|
|
580
|
+
throw u._;
|
|
581
|
+
} else if (!t && u.S & STATUS_UNINITIALIZED) {
|
|
582
|
+
throw u._;
|
|
552
583
|
}
|
|
553
584
|
}
|
|
554
|
-
if (e.
|
|
585
|
+
if (e.ae && e.S & STATUS_ERROR) {
|
|
555
586
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
556
587
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
557
588
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
558
589
|
// - el._time < clock: only on a later cycle than the one the error was found
|
|
559
|
-
if (tracking && !pendingCheckActive && e.
|
|
590
|
+
if (tracking && !pendingCheckActive && e.Se < clock) {
|
|
560
591
|
recompute(e);
|
|
561
592
|
return read(e);
|
|
562
593
|
} else throw e._;
|
|
563
594
|
}
|
|
564
595
|
if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
565
|
-
const n = e.
|
|
596
|
+
const n = e.xe;
|
|
566
597
|
if (n !== undefined) {
|
|
567
598
|
const i = n === NO_SNAPSHOT ? undefined : n;
|
|
568
|
-
const
|
|
569
|
-
if (
|
|
599
|
+
const u = e._e !== NOT_PENDING ? e._e : e.Ue;
|
|
600
|
+
if (u !== i) t.se |= REACTIVE_SNAPSHOT_STALE;
|
|
570
601
|
return i;
|
|
571
602
|
}
|
|
572
603
|
}
|
|
573
|
-
if (e.
|
|
604
|
+
if (e.Ae !== undefined && e.Ae !== NOT_PENDING) {
|
|
574
605
|
// A17: the override IS the value for every reader.
|
|
575
|
-
return unwrapOverride(e.
|
|
606
|
+
return unwrapOverride(e.Ae);
|
|
576
607
|
}
|
|
577
608
|
// Entanglement gate: a reader recomputing under an optimistic lane that reads
|
|
578
609
|
// a pending mid-transition write sees the committed value. Projection-store
|
|
@@ -581,40 +612,43 @@ function read(e) {
|
|
|
581
612
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
582
613
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
583
614
|
// engine — a non-null lane implies it is installed.)
|
|
584
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
585
|
-
return e.
|
|
615
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ot(e, u, t)) {
|
|
616
|
+
return e.Ue;
|
|
586
617
|
}
|
|
587
618
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
588
619
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
589
620
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
590
621
|
// (The lane-context clause lives with the engine.)
|
|
591
|
-
const
|
|
622
|
+
const l = !t || currentOptimisticLane !== null && GlobalQueue.Rt(e, u, t) || e._e === NOT_PENDING || stale && e.Ie && activeTransition !== e.Ie ? e.Ue : e._e;
|
|
592
623
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
593
624
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
594
|
-
if (pendingCheckActive) GlobalQueue.
|
|
595
|
-
if (!t &&
|
|
625
|
+
if (pendingCheckActive) GlobalQueue.Pt(e, l);
|
|
626
|
+
if (!t && u === e && typeof n.ae === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.o) {
|
|
596
627
|
unobserved(e);
|
|
597
628
|
}
|
|
598
|
-
return
|
|
629
|
+
return l;
|
|
599
630
|
}
|
|
600
631
|
|
|
601
632
|
function setSignal(e, t) {
|
|
602
|
-
if (e.
|
|
633
|
+
if (e.Ie && activeTransition !== e.Ie) globalQueue.initTransition(e.Ie);
|
|
603
634
|
// The optimistic write path lives with the engine: only optimisticSignal /
|
|
604
635
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
605
636
|
// _overrideValue slot, and every module that creates one installs the
|
|
606
637
|
// engine first.
|
|
607
|
-
if (e.
|
|
608
|
-
const n = e.
|
|
638
|
+
if (e.Ae !== undefined && !projectionWriteActive) return GlobalQueue.ht(e, t);
|
|
639
|
+
const n = e._e === NOT_PENDING ? e.Ue : e._e;
|
|
609
640
|
if (typeof t === "function") t = t(n);
|
|
610
641
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
611
642
|
// user comparator must not run against `undefined` (matches recompute).
|
|
612
643
|
const i = !!(e.S & STATUS_UNINITIALIZED) || !e.Re || !e.Re(n, t);
|
|
613
644
|
if (!i) return t;
|
|
614
|
-
if (e.
|
|
615
|
-
e.
|
|
616
|
-
|
|
617
|
-
|
|
645
|
+
if (e._e === NOT_PENDING) queuePendingNode(e);
|
|
646
|
+
e._e = t;
|
|
647
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
648
|
+
// neither companion present the call is a guaranteed no-op (companions are
|
|
649
|
+
// only ever created, never removed, and creating one installs the hook).
|
|
650
|
+
(e.he !== undefined || e.Ge !== undefined) && GlobalQueue.De !== null && GlobalQueue.De(e, t);
|
|
651
|
+
e.Se = clock;
|
|
618
652
|
insertSubs(e);
|
|
619
653
|
schedule();
|
|
620
654
|
return t;
|
|
@@ -628,7 +662,7 @@ function setSignal(e, t) {
|
|
|
628
662
|
* cleanup point.
|
|
629
663
|
*/ function suppressComputedRecompute(e) {
|
|
630
664
|
deleteFromHeap(e, queueFor(e));
|
|
631
|
-
if (!(e.se & REACTIVE_MANUAL_WRITE) && e.
|
|
665
|
+
if (!(e.se & REACTIVE_MANUAL_WRITE) && e._e === NOT_PENDING) {
|
|
632
666
|
queuePendingNode(e);
|
|
633
667
|
schedule();
|
|
634
668
|
}
|
|
@@ -711,7 +745,7 @@ function staleValues(e, t = true) {
|
|
|
711
745
|
if (!t) {
|
|
712
746
|
return;
|
|
713
747
|
}
|
|
714
|
-
if (typeof t.
|
|
748
|
+
if (typeof t.ae === "function" && !(t.se & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
715
749
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
716
750
|
// same question: mark it so the recompute classifies any resulting
|
|
717
751
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -729,4 +763,4 @@ function staleValues(e, t = true) {
|
|
|
729
763
|
}
|
|
730
764
|
}
|
|
731
765
|
|
|
732
|
-
export { clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, suppressComputedRecompute, tracking, untrack };
|
|
766
|
+
export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, suppressComputedRecompute, tracking, untrack };
|