@solidjs/signals 2.0.0-beta.32 → 2.0.0-beta.33
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 +235 -87
- package/dist/node.cjs +758 -635
- package/dist/prod/core/async.js +108 -54
- package/dist/prod/core/core.js +241 -204
- package/dist/prod/core/effect.js +27 -27
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +32 -32
- package/dist/prod/core/heap.js +36 -36
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +53 -44
- package/dist/prod/core/scheduler.js +76 -72
- package/dist/prod/core/verdict.js +59 -48
- package/dist/prod/map.js +6 -6
- package/dist/prod/signals.js +2 -34
- package/dist/prod/store/optimistic.js +37 -32
- package/dist/prod/store/projection.js +41 -6
- package/dist/prod/store/store.js +7 -7
- package/dist/types/core/async.d.ts +9 -0
- package/dist/types/core/types.d.ts +24 -0
- package/dist/types/signals.d.ts +60 -4
- package/dist/types/store/store.d.ts +14 -0
- package/dist/types-cjs/core/async.d.cts +9 -0
- package/dist/types-cjs/core/types.d.cts +24 -0
- package/dist/types-cjs/signals.d.cts +60 -4
- package/dist/types-cjs/store/store.d.cts +14 -0
- package/package.json +1 -1
package/dist/prod/core/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { handleAsync, clearStatus, notifyStatus, settleErroredDependents } from "./async.js";
|
|
1
|
+
import { handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settleErroredDependents } from "./async.js";
|
|
2
2
|
|
|
3
3
|
import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, STATUS_PENDING, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, OVERRIDE_UNDEFINED, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, $REFRESH, REACTIVE_MANUAL_WRITE, NO_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
|
|
4
4
|
|
|
@@ -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.ve) return true;
|
|
52
|
+
e = e.ke;
|
|
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.ve = true;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function releaseSnapshotScope(e) {
|
|
67
|
-
e.
|
|
67
|
+
e.ve = 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.Fe;
|
|
74
74
|
while (t) {
|
|
75
|
-
if (t.
|
|
76
|
-
t = t.
|
|
75
|
+
if (t.ve) {
|
|
76
|
+
t = t.He;
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
|
-
if (t.
|
|
79
|
+
if (t.ce) {
|
|
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.
|
|
85
|
+
if (dirtyQueue.Ve > e.xe) dirtyQueue.Ve = e.xe;
|
|
86
86
|
insertIntoHeap(e, dirtyQueue);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
releaseSubtree(t);
|
|
90
|
-
t = t.
|
|
90
|
+
t = t.He;
|
|
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.Le;
|
|
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,24 +106,24 @@ function clearSnapshots() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
function recompute(e, t = false) {
|
|
109
|
-
const n = e.
|
|
109
|
+
const n = e.Re;
|
|
110
110
|
if (!t) {
|
|
111
|
-
if (e.
|
|
111
|
+
if (e.Ne && (!n || activeTransition) && activeTransition !== e.Ne) globalQueue.initTransition(e.Ne);
|
|
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.Ne || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Fe !== null || e.ye !== null) {
|
|
116
116
|
markDisposal(e);
|
|
117
|
-
e.
|
|
118
|
-
e.
|
|
119
|
-
e.
|
|
120
|
-
e.
|
|
117
|
+
e.Qe = e.ye;
|
|
118
|
+
e.We = e.Fe;
|
|
119
|
+
e.ye = null;
|
|
120
|
+
e.Fe = null;
|
|
121
121
|
e.qe = 0;
|
|
122
122
|
} else ;
|
|
123
123
|
}
|
|
124
124
|
let i = !!(e.se & REACTIVE_OPTIMISTIC_DIRTY);
|
|
125
|
-
const
|
|
126
|
-
const
|
|
125
|
+
const l = e._e !== undefined && e._e !== NOT_PENDING;
|
|
126
|
+
const u = !!(e.S & STATUS_UNINITIALIZED);
|
|
127
127
|
// Outgoing error, captured before the compute clears status: if this run
|
|
128
128
|
// recovers to an unchanged value, dependents still holding this object must
|
|
129
129
|
// be swept (settleErroredDependents, #2949).
|
|
@@ -131,16 +131,21 @@ function recompute(e, t = false) {
|
|
|
131
131
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
132
132
|
// the recompute wipes _flags below.
|
|
133
133
|
const s = (e.se & REACTIVE_REASK) !== 0;
|
|
134
|
-
|
|
134
|
+
// Captured before the compute clears it on a sync landing: if that landing
|
|
135
|
+
// is transition-held below, the window must stay open until the hold
|
|
136
|
+
// commits (commitPendingNode) — a closed window plus a held value reads as
|
|
137
|
+
// a pending frame to live observers of the verdict (#2990).
|
|
138
|
+
const a = e.Ee;
|
|
139
|
+
const r = context;
|
|
135
140
|
context = e;
|
|
136
|
-
e.
|
|
137
|
-
e.
|
|
141
|
+
e.Ye = null;
|
|
142
|
+
e.Ze++;
|
|
138
143
|
e.se = REACTIVE_RECOMPUTING_DEPS;
|
|
139
|
-
e.
|
|
140
|
-
let
|
|
141
|
-
let
|
|
142
|
-
let
|
|
143
|
-
let
|
|
144
|
+
e.de = clock;
|
|
145
|
+
let c = e.De === NOT_PENDING ? e.Ue : e.De;
|
|
146
|
+
let _ = e.xe;
|
|
147
|
+
let f = tracking;
|
|
148
|
+
let E = currentOptimisticLane;
|
|
144
149
|
tracking = true;
|
|
145
150
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
146
151
|
// inside a latest() read window: read() short-circuits through the
|
|
@@ -148,31 +153,32 @@ function recompute(e, t = false) {
|
|
|
148
153
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
149
154
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
150
155
|
// covers creation-time computes and flushes that run inside the window.
|
|
151
|
-
const
|
|
156
|
+
const T = latestReadActive;
|
|
152
157
|
latestReadActive = false;
|
|
153
158
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
154
159
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
155
160
|
// _optimisticWrite, so the hook is installed whenever either gate holds.
|
|
156
161
|
if (i) {
|
|
157
|
-
const t = GlobalQueue.
|
|
162
|
+
const t = GlobalQueue.je(e, true);
|
|
158
163
|
if (t) currentOptimisticLane = t;
|
|
159
|
-
} else if (activeTransition && !t && activeTransition.
|
|
164
|
+
} else if (activeTransition && !t && activeTransition.Me.length) {
|
|
160
165
|
// Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
|
|
161
166
|
// child propagates. Walk deps once and inherit the OPT lane so this node
|
|
162
167
|
// recomputes under the right posture and propagates correctly.
|
|
163
|
-
const t = GlobalQueue.
|
|
168
|
+
const t = GlobalQueue.je(e, false);
|
|
164
169
|
if (t) {
|
|
165
170
|
i = true;
|
|
166
171
|
currentOptimisticLane = t;
|
|
167
172
|
}
|
|
168
173
|
}
|
|
169
174
|
const N = n && n !== EFFECT_USER;
|
|
170
|
-
const
|
|
175
|
+
const d = stale;
|
|
171
176
|
if (N) stale = true;
|
|
172
177
|
try {
|
|
173
178
|
if (!false && e.T & CONFIG_SYNC) {
|
|
174
|
-
|
|
179
|
+
c = e.ce(c);
|
|
175
180
|
e.Te = null;
|
|
181
|
+
e.Ee = false;
|
|
176
182
|
} else {
|
|
177
183
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
178
184
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
@@ -180,42 +186,61 @@ function recompute(e, t = false) {
|
|
|
180
186
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
181
187
|
// iteration drive updates.
|
|
182
188
|
const t = e.Te;
|
|
183
|
-
const n = e.
|
|
189
|
+
const n = e.ce(c);
|
|
184
190
|
const i = typeof n === "object" && n !== null;
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
if (!
|
|
191
|
+
const l = e.Te !== t;
|
|
192
|
+
c = l || !i ? n : handleAsync(e, n);
|
|
193
|
+
if (!l && !i) {
|
|
194
|
+
e.Te = null;
|
|
195
|
+
// A sync (non-object) return is the first real answer; async-shaped
|
|
196
|
+
// results clear inside handleAsync at their own landing points, and a
|
|
197
|
+
// self-registered flight (inFlightChanged — projections) clears when
|
|
198
|
+
// its internal handleAsync lands.
|
|
199
|
+
e.Ee = false;
|
|
200
|
+
}
|
|
188
201
|
}
|
|
189
202
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
190
203
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
191
204
|
// the flags write (create or not) stores the 0 already there.
|
|
192
|
-
if (e.S !== 0 || e.i !== undefined || e._ || e.
|
|
205
|
+
if (e.S !== 0 || e.i !== undefined || e._ || e.he || e.ue || e.oe !== undefined || e.ge !== undefined || e.pe !== undefined || e.u !== null) clearStatus(e, t);
|
|
193
206
|
// _optimisticLane is only ever assigned by engine paths.
|
|
194
|
-
if (e.
|
|
207
|
+
if (e.Ke) GlobalQueue.ze(e);
|
|
195
208
|
} catch (t) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
const n = t instanceof NotReadyError;
|
|
210
|
+
if (n && e.Ee) {
|
|
211
|
+
// Loading window with an unready sync dependency: register for the
|
|
212
|
+
// source's settle (the settlePendingSource walk runs off
|
|
213
|
+
// _pendingSources + _blocked alone) but take NO read-visible pending
|
|
214
|
+
// status, no downstream propagation, no transition, no lane
|
|
215
|
+
// registration — the committed loading value keeps serving. If the
|
|
216
|
+
// node is currently errored the error stays the answer until this
|
|
217
|
+
// retry can actually run.
|
|
218
|
+
parkLoadingWindow(e, t);
|
|
219
|
+
} else {
|
|
220
|
+
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
221
|
+
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
222
|
+
if (n && currentOptimisticLane) GlobalQueue.$e(e);
|
|
223
|
+
let i = false;
|
|
224
|
+
if (n) {
|
|
225
|
+
e.ue = true;
|
|
226
|
+
if (GlobalQueue.Be !== null) i = GlobalQueue.Be(e, s);
|
|
227
|
+
}
|
|
228
|
+
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.Ke : undefined);
|
|
229
|
+
if (i) GlobalQueue.k(e);
|
|
203
230
|
}
|
|
204
|
-
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.Me : undefined);
|
|
205
|
-
if (n) GlobalQueue.k(e);
|
|
206
231
|
} finally {
|
|
207
|
-
tracking =
|
|
208
|
-
latestReadActive =
|
|
209
|
-
if (N) stale =
|
|
232
|
+
tracking = f;
|
|
233
|
+
latestReadActive = T;
|
|
234
|
+
if (N) stale = d;
|
|
210
235
|
e.se = REACTIVE_NONE | (t ? e.se & REACTIVE_SNAPSHOT_STALE : 0);
|
|
211
|
-
context =
|
|
236
|
+
context = r;
|
|
212
237
|
}
|
|
213
238
|
if (!e._) {
|
|
214
239
|
trimStaleDeps(e);
|
|
215
|
-
const s =
|
|
216
|
-
let
|
|
240
|
+
const s = l ? unwrapOverride(e._e) : e.De === NOT_PENDING ? e.Ue : e.De;
|
|
241
|
+
let r = false;
|
|
217
242
|
try {
|
|
218
|
-
|
|
243
|
+
r = !n && u || !e.be || !e.be(s, c);
|
|
219
244
|
} catch (t) {
|
|
220
245
|
// A throwing user comparator is an error of this node's computation.
|
|
221
246
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -228,50 +253,55 @@ function recompute(e, t = false) {
|
|
|
228
253
|
// its runner — happen here instead. `!create` matches the previous `initialized`
|
|
229
254
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
230
255
|
// effect() can call its runner synchronously for the first run.
|
|
231
|
-
if (n &&
|
|
232
|
-
e.
|
|
256
|
+
if (n && r) {
|
|
257
|
+
e.Je = !e._;
|
|
233
258
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
234
259
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
235
|
-
if (!t) e.C.enqueue(n, e.
|
|
260
|
+
if (!t) e.C.enqueue(n, e.Xe ??= GlobalQueue.et.bind(null, e));
|
|
236
261
|
}
|
|
237
|
-
if (e._) ; else if (
|
|
238
|
-
const
|
|
262
|
+
if (e._) ; else if (r) {
|
|
263
|
+
const u = l ? e._e : undefined;
|
|
239
264
|
if (t ||
|
|
240
265
|
// Plain sync flush (no transition on either side) commits effect
|
|
241
266
|
// values directly — the pending round-trip (queuePendingNode +
|
|
242
267
|
// commitPendingNodes) exists to sequence transition reveals, and
|
|
243
268
|
// paying it per effect on the plain path is pure overhead.
|
|
244
|
-
n && (activeTransition !== e.
|
|
245
|
-
e.
|
|
269
|
+
n && (activeTransition !== e.Ne || activeTransition === null) || i) {
|
|
270
|
+
e.Ue = c;
|
|
246
271
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
247
272
|
// override unconditionally. The direct _value commit is the lane's
|
|
248
273
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
249
274
|
// commit can't clobber the fresh value.
|
|
250
|
-
if (
|
|
251
|
-
e.
|
|
275
|
+
if (l && i) {
|
|
276
|
+
e._e = c === undefined ? OVERRIDE_UNDEFINED : c;
|
|
252
277
|
e.De = NOT_PENDING;
|
|
253
278
|
}
|
|
254
279
|
} else {
|
|
255
|
-
e.De =
|
|
280
|
+
e.De = c;
|
|
281
|
+
// A window landing that gets held re-opens the window until the hold
|
|
282
|
+
// commits — the verdict's held-value branch is window-gated (#2990).
|
|
283
|
+
if (a) e.Ee = true;
|
|
256
284
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
257
285
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
258
286
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
259
287
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
260
288
|
// pending value commits before effects run.
|
|
261
|
-
if ((activeTransition || e.
|
|
289
|
+
if ((activeTransition || e.Ne) && GlobalQueue.Pe !== null) GlobalQueue.Pe(e, c);
|
|
262
290
|
}
|
|
263
291
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
264
292
|
// subscriber-less node has nothing to notify.
|
|
265
|
-
if (e.o !== null && (!
|
|
266
|
-
} else if (
|
|
293
|
+
if (e.o !== null && (!l || i || e._e !== u)) insertSubs(e, i || l);
|
|
294
|
+
} else if (l) {
|
|
267
295
|
// Unchanged value (equals the override) recomputed while the override
|
|
268
296
|
// is active: _value may still be stale, so hold the authoritative value
|
|
269
297
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
270
298
|
if (e.De === NOT_PENDING) queuePendingNode(e);
|
|
271
|
-
e.De =
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
299
|
+
e.De = c;
|
|
300
|
+
if (a) e.Ee = true;
|
|
301
|
+
// see the held branch above (#2990)
|
|
302
|
+
} else if (e.xe != _) {
|
|
303
|
+
for (let t = e.o; t !== null; t = t.le) {
|
|
304
|
+
insertIntoHeapHeight(t.fe, queueFor(t.fe));
|
|
275
305
|
}
|
|
276
306
|
}
|
|
277
307
|
// Silent recovery: errored → unchanged value fires no notification, but
|
|
@@ -279,25 +309,25 @@ function recompute(e, t = false) {
|
|
|
279
309
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
280
310
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
281
311
|
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
282
|
-
if (o !== undefined && !
|
|
312
|
+
if (o !== undefined && !r && !e._) settleErroredDependents(e, o);
|
|
283
313
|
}
|
|
284
|
-
currentOptimisticLane =
|
|
285
|
-
const
|
|
314
|
+
currentOptimisticLane = E;
|
|
315
|
+
const I = e.De !== NOT_PENDING || e.We !== null || e.Qe !== null || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
286
316
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
287
317
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
288
318
|
// under the override (A17). Revert no longer commits anything, so an
|
|
289
319
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
290
320
|
// _transition.
|
|
291
|
-
|
|
292
|
-
e.
|
|
321
|
+
I && (!t || e.S & STATUS_PENDING) && (!e.Ne || l) && queuePendingNode(e);
|
|
322
|
+
e.Ne && n && activeTransition !== e.Ne && runInTransition(e.Ne, () => recompute(e));
|
|
293
323
|
}
|
|
294
324
|
|
|
295
325
|
function updateIfNecessary(e) {
|
|
296
326
|
if (e.se & REACTIVE_CHECK) {
|
|
297
|
-
for (let t = e.
|
|
298
|
-
const n = t.
|
|
299
|
-
const i = n.
|
|
300
|
-
if (i.
|
|
327
|
+
for (let t = e.tt; t; t = t.nt) {
|
|
328
|
+
const n = t.it;
|
|
329
|
+
const i = n.lt || n;
|
|
330
|
+
if (i.ce) {
|
|
301
331
|
updateIfNecessary(i);
|
|
302
332
|
}
|
|
303
333
|
if (e.se & REACTIVE_DIRTY) {
|
|
@@ -305,7 +335,7 @@ function updateIfNecessary(e) {
|
|
|
305
335
|
}
|
|
306
336
|
}
|
|
307
337
|
}
|
|
308
|
-
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e._ && e.
|
|
338
|
+
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e._ && e.de < clock && !e.Te) {
|
|
309
339
|
recompute(e);
|
|
310
340
|
}
|
|
311
341
|
e.se = e.se & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -313,42 +343,48 @@ function updateIfNecessary(e) {
|
|
|
313
343
|
|
|
314
344
|
function computed(e, t) {
|
|
315
345
|
const n = t?.transparent ?? false;
|
|
316
|
-
|
|
346
|
+
// `in` (not `!== undefined`): an explicit `loadingValue: undefined` on a
|
|
347
|
+
// `T | undefined` node is a real commit #0. The typeof guard tolerates
|
|
348
|
+
// non-object option values that older call shapes force through `as any`.
|
|
349
|
+
const i = t !== null && typeof t === "object" && "loadingValue" in t;
|
|
350
|
+
const l = {
|
|
317
351
|
id: inheritId(t, n, context),
|
|
318
352
|
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),
|
|
319
|
-
|
|
353
|
+
be: t?.equals != null ? t.equals : isEqual,
|
|
320
354
|
ut: t?.unobserved,
|
|
321
|
-
|
|
355
|
+
ye: null,
|
|
322
356
|
C: context?.C ?? globalQueue,
|
|
323
357
|
we: context?.we ?? defaultContext,
|
|
324
358
|
qe: 0,
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
359
|
+
ce: e,
|
|
360
|
+
Ue: i ? t.loadingValue : undefined,
|
|
361
|
+
xe: 0,
|
|
328
362
|
u: null,
|
|
329
|
-
|
|
330
|
-
ot: null,
|
|
331
|
-
et: null,
|
|
332
|
-
We: null,
|
|
333
|
-
Ye: 0,
|
|
334
|
-
o: null,
|
|
363
|
+
ot: undefined,
|
|
335
364
|
st: null,
|
|
336
|
-
|
|
337
|
-
|
|
365
|
+
tt: null,
|
|
366
|
+
Ye: null,
|
|
367
|
+
Ze: 0,
|
|
368
|
+
o: null,
|
|
338
369
|
rt: null,
|
|
339
|
-
ke:
|
|
370
|
+
ke: context,
|
|
371
|
+
He: null,
|
|
372
|
+
ct: null,
|
|
373
|
+
Fe: null,
|
|
340
374
|
se: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
341
|
-
|
|
342
|
-
|
|
375
|
+
// A loadingValue node is born committed: commit #0 is already in _value.
|
|
376
|
+
S: i ? 0 : STATUS_UNINITIALIZED,
|
|
377
|
+
de: clock,
|
|
343
378
|
De: NOT_PENDING,
|
|
344
|
-
ye: null,
|
|
345
379
|
Qe: null,
|
|
380
|
+
We: null,
|
|
346
381
|
Te: null,
|
|
347
|
-
|
|
348
|
-
|
|
382
|
+
Ne: null,
|
|
383
|
+
he: false,
|
|
384
|
+
Ee: i
|
|
349
385
|
};
|
|
350
|
-
setupComputedNode(
|
|
351
|
-
return
|
|
386
|
+
setupComputedNode(l, t);
|
|
387
|
+
return l;
|
|
352
388
|
}
|
|
353
389
|
|
|
354
390
|
/**
|
|
@@ -356,48 +392,49 @@ function computed(e, t) {
|
|
|
356
392
|
* so V8 sees the full hidden class shape at construction time. Effects always run in lazy
|
|
357
393
|
* mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
|
|
358
394
|
* the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
|
|
359
|
-
*/ function createEffectNode(e, t, n, i,
|
|
360
|
-
const o =
|
|
395
|
+
*/ function createEffectNode(e, t, n, i, l, u) {
|
|
396
|
+
const o = u?.transparent ?? false;
|
|
361
397
|
const s = {
|
|
362
|
-
id: inheritId(
|
|
363
|
-
T: (o ? CONFIG_TRANSPARENT : 0) | (
|
|
364
|
-
|
|
365
|
-
ut:
|
|
366
|
-
|
|
398
|
+
id: inheritId(u, o, context),
|
|
399
|
+
T: (o ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
400
|
+
be: false,
|
|
401
|
+
ut: u?.unobserved,
|
|
402
|
+
ye: null,
|
|
367
403
|
C: context?.C ?? globalQueue,
|
|
368
404
|
we: context?.we ?? defaultContext,
|
|
369
405
|
qe: 0,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
406
|
+
ce: e,
|
|
407
|
+
Ue: undefined,
|
|
408
|
+
xe: 0,
|
|
373
409
|
u: null,
|
|
374
|
-
|
|
375
|
-
ot: null,
|
|
376
|
-
et: null,
|
|
377
|
-
We: null,
|
|
378
|
-
Ye: 0,
|
|
379
|
-
o: null,
|
|
410
|
+
ot: undefined,
|
|
380
411
|
st: null,
|
|
381
|
-
|
|
382
|
-
|
|
412
|
+
tt: null,
|
|
413
|
+
Ye: null,
|
|
414
|
+
Ze: 0,
|
|
415
|
+
o: null,
|
|
383
416
|
rt: null,
|
|
384
|
-
ke:
|
|
417
|
+
ke: context,
|
|
418
|
+
He: null,
|
|
419
|
+
ct: null,
|
|
420
|
+
Fe: null,
|
|
385
421
|
se: REACTIVE_LAZY,
|
|
386
422
|
S: STATUS_UNINITIALIZED,
|
|
387
|
-
|
|
423
|
+
de: clock,
|
|
388
424
|
De: NOT_PENDING,
|
|
389
|
-
ye: null,
|
|
390
425
|
Qe: null,
|
|
426
|
+
We: null,
|
|
391
427
|
Te: null,
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
_t:
|
|
397
|
-
ft:
|
|
398
|
-
Et:
|
|
399
|
-
|
|
400
|
-
|
|
428
|
+
Ne: null,
|
|
429
|
+
he: false,
|
|
430
|
+
Ee: false,
|
|
431
|
+
Je: false,
|
|
432
|
+
_t: undefined,
|
|
433
|
+
ft: t,
|
|
434
|
+
Et: n,
|
|
435
|
+
Tt: undefined,
|
|
436
|
+
Re: i,
|
|
437
|
+
i: l
|
|
401
438
|
};
|
|
402
439
|
setupComputedNode(s, lazyOptions);
|
|
403
440
|
return s;
|
|
@@ -408,24 +445,24 @@ const lazyOptions = {
|
|
|
408
445
|
};
|
|
409
446
|
|
|
410
447
|
function setupComputedNode(e, t) {
|
|
411
|
-
e.
|
|
412
|
-
const n = context?.Nt ? context.
|
|
448
|
+
e.st = e;
|
|
449
|
+
const n = context?.Nt ? context.dt : context;
|
|
413
450
|
if (context) {
|
|
414
|
-
const t = context.
|
|
451
|
+
const t = context.Fe;
|
|
415
452
|
if (t === null) {
|
|
416
|
-
context.
|
|
453
|
+
context.Fe = e;
|
|
417
454
|
} else {
|
|
418
|
-
e.
|
|
419
|
-
t.
|
|
420
|
-
context.
|
|
455
|
+
e.He = t;
|
|
456
|
+
t.ct = e;
|
|
457
|
+
context.Fe = e;
|
|
421
458
|
}
|
|
422
459
|
}
|
|
423
|
-
if (n) e.
|
|
424
|
-
if (GlobalQueue.
|
|
460
|
+
if (n) e.xe = n.xe + 1;
|
|
461
|
+
if (GlobalQueue.It !== null) GlobalQueue.It(e);
|
|
425
462
|
!t?.lazy && recompute(e, true);
|
|
426
463
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
427
464
|
if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
|
|
428
|
-
e.
|
|
465
|
+
e.Le = e.Ue === undefined ? NO_SNAPSHOT : e.Ue;
|
|
429
466
|
snapshotSources.add(e);
|
|
430
467
|
}
|
|
431
468
|
}
|
|
@@ -433,20 +470,20 @@ function setupComputedNode(e, t) {
|
|
|
433
470
|
|
|
434
471
|
function signal(e, t, n = null) {
|
|
435
472
|
const i = {
|
|
436
|
-
|
|
473
|
+
be: t?.equals != null ? t.equals : isEqual,
|
|
437
474
|
T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0),
|
|
438
475
|
ut: t?.unobserved,
|
|
439
|
-
|
|
476
|
+
Ue: e,
|
|
440
477
|
o: null,
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
478
|
+
rt: null,
|
|
479
|
+
de: clock,
|
|
480
|
+
lt: n,
|
|
481
|
+
ae: n?.u || null,
|
|
445
482
|
De: NOT_PENDING
|
|
446
483
|
};
|
|
447
484
|
n && (n.u = i);
|
|
448
485
|
if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
|
|
449
|
-
i.
|
|
486
|
+
i.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
450
487
|
snapshotSources.add(i);
|
|
451
488
|
}
|
|
452
489
|
return i;
|
|
@@ -454,13 +491,13 @@ function signal(e, t, n = null) {
|
|
|
454
491
|
|
|
455
492
|
function optimisticSignal(e, t) {
|
|
456
493
|
const n = signal(e, t);
|
|
457
|
-
n.
|
|
494
|
+
n._e = NOT_PENDING;
|
|
458
495
|
return n;
|
|
459
496
|
}
|
|
460
497
|
|
|
461
498
|
function optimisticComputed(e, t) {
|
|
462
499
|
const n = computed(e, t);
|
|
463
|
-
n.
|
|
500
|
+
n._e = NOT_PENDING;
|
|
464
501
|
return n;
|
|
465
502
|
}
|
|
466
503
|
|
|
@@ -490,11 +527,11 @@ function isEqual(e, t) {
|
|
|
490
527
|
* );
|
|
491
528
|
* ```
|
|
492
529
|
*/ function untrack(e, t) {
|
|
493
|
-
if (GlobalQueue.
|
|
530
|
+
if (GlobalQueue.St === null && !tracking && true) return e();
|
|
494
531
|
const n = tracking;
|
|
495
532
|
tracking = false;
|
|
496
533
|
try {
|
|
497
|
-
if (GlobalQueue.
|
|
534
|
+
if (GlobalQueue.St !== null) return GlobalQueue.St(e);
|
|
498
535
|
return e();
|
|
499
536
|
} finally {
|
|
500
537
|
tracking = n;
|
|
@@ -530,11 +567,11 @@ function isEqual(e, t) {
|
|
|
530
567
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
531
568
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
532
569
|
*/ function readNodeFast(e) {
|
|
533
|
-
if (latestReadActive || pendingCheckActive || e.
|
|
570
|
+
if (latestReadActive || pendingCheckActive || e.ce || e.lt || e._e !== undefined || e.Le !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
534
571
|
let t = context;
|
|
535
|
-
if (t?.Nt) t = t.
|
|
572
|
+
if (t?.Nt) t = t.dt;
|
|
536
573
|
if (t && tracking) link(e, t);
|
|
537
|
-
return !t || e.De === NOT_PENDING ? e.
|
|
574
|
+
return !t || e.De === NOT_PENDING ? e.Ue : e.De;
|
|
538
575
|
}
|
|
539
576
|
|
|
540
577
|
function read(e) {
|
|
@@ -542,82 +579,82 @@ function read(e) {
|
|
|
542
579
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
543
580
|
// the _pendingSignal of _latestValueComputed (async in flight) rather
|
|
544
581
|
// than the original node (which stays "pending" while held in a transition).
|
|
545
|
-
if (latestReadActive) return GlobalQueue.
|
|
582
|
+
if (latestReadActive) return GlobalQueue.At(e);
|
|
546
583
|
let t = context;
|
|
547
|
-
if (t?.Nt) t = t.
|
|
584
|
+
if (t?.Nt) t = t.dt;
|
|
548
585
|
const n = e;
|
|
549
|
-
const i = e.
|
|
550
|
-
const
|
|
586
|
+
const i = e.lt;
|
|
587
|
+
const l = i || e;
|
|
551
588
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
552
589
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
553
590
|
// recompute don't collect into the probe.
|
|
554
591
|
if (pendingCheckActive) {
|
|
555
|
-
GlobalQueue.
|
|
556
|
-
} else if (typeof n.
|
|
592
|
+
GlobalQueue.Ct(e, t, l, i);
|
|
593
|
+
} else if (typeof n.ce === "function") {
|
|
557
594
|
prepareComputed(e, false);
|
|
558
595
|
}
|
|
559
|
-
if (!n.
|
|
596
|
+
if (!n.ce && l === e && e._e === undefined && e.Le === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
560
597
|
if (t && tracking) link(e, t);
|
|
561
|
-
return !t || e.De === NOT_PENDING ? e.
|
|
598
|
+
return !t || e.De === NOT_PENDING ? e.Ue : e.De;
|
|
562
599
|
}
|
|
563
600
|
if (t && tracking) {
|
|
564
601
|
link(e, t, pendingCheckActive);
|
|
565
|
-
if (
|
|
602
|
+
if (l.ce) {
|
|
566
603
|
const n = queueFor(e);
|
|
567
|
-
if (
|
|
604
|
+
if (l.xe >= n.Ve) {
|
|
568
605
|
markNode(t);
|
|
569
606
|
markHeap(n);
|
|
570
|
-
updateIfNecessary(
|
|
607
|
+
updateIfNecessary(l);
|
|
571
608
|
}
|
|
572
|
-
const i =
|
|
609
|
+
const i = l.xe;
|
|
573
610
|
// parent check is shallow, might need to be recursive
|
|
574
|
-
if (i >= t.
|
|
575
|
-
t.
|
|
611
|
+
if (i >= t.xe && e.ke !== t) {
|
|
612
|
+
t.xe = i + 1;
|
|
576
613
|
}
|
|
577
614
|
}
|
|
578
615
|
}
|
|
579
|
-
if (
|
|
580
|
-
if (t && !(stale &&
|
|
616
|
+
if (l.S & STATUS_PENDING) {
|
|
617
|
+
if (t && !(stale && l.Ne && activeTransition !== l.Ne)) {
|
|
581
618
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
582
619
|
// is installed): under a lane, only same-lane pending async without an
|
|
583
620
|
// active override throws.
|
|
584
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
621
|
+
if (currentOptimisticLane === null || GlobalQueue.Ot(l)) {
|
|
585
622
|
if (!tracking && e !== t) link(e, t);
|
|
586
|
-
throw
|
|
623
|
+
throw l._;
|
|
587
624
|
}
|
|
588
|
-
} else if (t &&
|
|
625
|
+
} else if (t && l !== e && l.S & STATUS_UNINITIALIZED) {
|
|
589
626
|
if (!tracking && e !== t) link(e, t);
|
|
590
|
-
throw
|
|
591
|
-
} else if (!t &&
|
|
592
|
-
throw
|
|
627
|
+
throw l._;
|
|
628
|
+
} else if (!t && l.S & STATUS_UNINITIALIZED) {
|
|
629
|
+
throw l._;
|
|
593
630
|
}
|
|
594
631
|
}
|
|
595
632
|
// `owner` is the computed itself, or the firewall behind a store node —
|
|
596
633
|
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
597
634
|
// an errored derive throws for every late reader instead of silently
|
|
598
635
|
// serving node values (the seed, or last-good data after a failed refetch).
|
|
599
|
-
if (
|
|
636
|
+
if (l.ce && l.S & STATUS_ERROR) {
|
|
600
637
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
601
638
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
602
639
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
603
640
|
// - owner._time < clock: only on a later cycle than the one the error was found
|
|
604
|
-
if (tracking && !pendingCheckActive &&
|
|
605
|
-
recompute(
|
|
641
|
+
if (tracking && !pendingCheckActive && l.de < clock) {
|
|
642
|
+
recompute(l);
|
|
606
643
|
return read(e);
|
|
607
|
-
} else throw
|
|
644
|
+
} else throw l._;
|
|
608
645
|
}
|
|
609
646
|
if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
610
|
-
const n = e.
|
|
647
|
+
const n = e.Le;
|
|
611
648
|
if (n !== undefined) {
|
|
612
649
|
const i = n === NO_SNAPSHOT ? undefined : n;
|
|
613
|
-
const
|
|
614
|
-
if (
|
|
650
|
+
const l = e.De !== NOT_PENDING ? e.De : e.Ue;
|
|
651
|
+
if (l !== i) t.se |= REACTIVE_SNAPSHOT_STALE;
|
|
615
652
|
return i;
|
|
616
653
|
}
|
|
617
654
|
}
|
|
618
|
-
if (e.
|
|
655
|
+
if (e._e !== undefined && e._e !== NOT_PENDING) {
|
|
619
656
|
// A17: the override IS the value for every reader.
|
|
620
|
-
return unwrapOverride(e.
|
|
657
|
+
return unwrapOverride(e._e);
|
|
621
658
|
}
|
|
622
659
|
// Entanglement gate: a reader recomputing under an optimistic lane that reads
|
|
623
660
|
// a pending mid-transition write sees the committed value. Projection-store
|
|
@@ -626,43 +663,43 @@ function read(e) {
|
|
|
626
663
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
627
664
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
628
665
|
// engine — a non-null lane implies it is installed.)
|
|
629
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
630
|
-
return e.
|
|
666
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Rt(e, l, t)) {
|
|
667
|
+
return e.Ue;
|
|
631
668
|
}
|
|
632
669
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
633
670
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
634
671
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
635
672
|
// (The lane-context clause lives with the engine.)
|
|
636
|
-
const
|
|
673
|
+
const u = !t || currentOptimisticLane !== null && GlobalQueue.Pt(e, l, t) || e.De === NOT_PENDING || stale && e.Ne && activeTransition !== e.Ne ? e.Ue : e.De;
|
|
637
674
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
638
675
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
639
|
-
if (pendingCheckActive) GlobalQueue.
|
|
640
|
-
if (!t &&
|
|
676
|
+
if (pendingCheckActive) GlobalQueue.ht(e, u);
|
|
677
|
+
if (!t && l === e && typeof n.ce === "function" && e.T & CONFIG_AUTO_DISPOSE && !(l.S & STATUS_PENDING) && !e.o) {
|
|
641
678
|
unobserved(e);
|
|
642
679
|
}
|
|
643
|
-
return
|
|
680
|
+
return u;
|
|
644
681
|
}
|
|
645
682
|
|
|
646
683
|
function setSignal(e, t) {
|
|
647
|
-
if (e.
|
|
684
|
+
if (e.Ne && activeTransition !== e.Ne) globalQueue.initTransition(e.Ne);
|
|
648
685
|
// The optimistic write path lives with the engine: only optimisticSignal /
|
|
649
686
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
650
687
|
// _overrideValue slot, and every module that creates one installs the
|
|
651
688
|
// engine first.
|
|
652
|
-
if (e.
|
|
653
|
-
const n = e.De === NOT_PENDING ? e.
|
|
689
|
+
if (e._e !== undefined && !projectionWriteActive) return GlobalQueue.Gt(e, t);
|
|
690
|
+
const n = e.De === NOT_PENDING ? e.Ue : e.De;
|
|
654
691
|
if (typeof t === "function") t = t(n);
|
|
655
692
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
656
693
|
// user comparator must not run against `undefined` (matches recompute).
|
|
657
|
-
const i = !!(e.S & STATUS_UNINITIALIZED) || !e.
|
|
694
|
+
const i = !!(e.S & STATUS_UNINITIALIZED) || !e.be || !e.be(n, t);
|
|
658
695
|
if (!i) return t;
|
|
659
696
|
if (e.De === NOT_PENDING) queuePendingNode(e);
|
|
660
697
|
e.De = t;
|
|
661
698
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
662
699
|
// neither companion present the call is a guaranteed no-op (companions are
|
|
663
700
|
// only ever created, never removed, and creating one installs the hook).
|
|
664
|
-
(e.
|
|
665
|
-
e.
|
|
701
|
+
(e.ge !== undefined || e.pe !== undefined) && GlobalQueue.Pe !== null && GlobalQueue.Pe(e, t);
|
|
702
|
+
e.de = clock;
|
|
666
703
|
insertSubs(e);
|
|
667
704
|
schedule();
|
|
668
705
|
return t;
|
|
@@ -759,7 +796,7 @@ function staleValues(e, t = true) {
|
|
|
759
796
|
if (!t) {
|
|
760
797
|
return;
|
|
761
798
|
}
|
|
762
|
-
if (typeof t.
|
|
799
|
+
if (typeof t.ce === "function" && !(t.se & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
763
800
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
764
801
|
// same question: mark it so the recompute classifies any resulting
|
|
765
802
|
// pending window as quiet (not pending). If the node is already dirty
|