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