@solidjs/signals 2.0.0-rc.4 → 2.0.0-rc.6
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 +1618 -232
- package/dist/node.cjs +2262 -1199
- package/dist/prod/boundaries.js +4 -1
- package/dist/prod/core/async.js +152 -101
- package/dist/prod/core/constants.js +55 -1
- package/dist/prod/core/core.js +305 -234
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/error.js +13 -1
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +32 -32
- package/dist/prod/core/optimistic.js +57 -57
- package/dist/prod/core/owner.js +34 -34
- package/dist/prod/core/scheduler.js +346 -152
- package/dist/prod/core/verdict.js +122 -65
- package/dist/prod/index.js +3 -3
- package/dist/prod/map.js +106 -106
- package/dist/prod/signals.js +321 -26
- package/dist/prod/store/next/optimistic.js +363 -151
- package/dist/prod/store/next/patch.js +6 -6
- package/dist/prod/store/next/projection.js +25 -21
- package/dist/prod/store/next/store.js +223 -113
- package/dist/prod/store/store.js +2 -2
- package/dist/types/core/async.d.ts +2 -0
- package/dist/types/core/attribution-hooks.d.ts +11 -0
- package/dist/types/core/attribution.d.ts +57 -4
- package/dist/types/core/constants.d.ts +54 -0
- package/dist/types/core/core.d.ts +19 -20
- package/dist/types/core/dev.d.ts +8 -2
- package/dist/types/core/error.d.ts +9 -0
- package/dist/types/core/index.d.ts +2 -2
- package/dist/types/core/scheduler.d.ts +39 -0
- package/dist/types/core/types.d.ts +12 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/signals.d.ts +108 -11
- package/dist/types/store/next/optimistic.d.ts +13 -10
- package/dist/types/store/next/projection.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +22 -0
- package/dist/types/store/next/target.d.ts +25 -0
- package/dist/types-cjs/core/async.d.cts +2 -0
- package/dist/types-cjs/core/attribution-hooks.d.cts +11 -0
- package/dist/types-cjs/core/attribution.d.cts +57 -4
- package/dist/types-cjs/core/constants.d.cts +54 -0
- package/dist/types-cjs/core/core.d.cts +19 -20
- package/dist/types-cjs/core/dev.d.cts +8 -2
- package/dist/types-cjs/core/error.d.cts +9 -0
- package/dist/types-cjs/core/index.d.cts +2 -2
- package/dist/types-cjs/core/scheduler.d.cts +39 -0
- package/dist/types-cjs/core/types.d.cts +12 -0
- package/dist/types-cjs/index.d.cts +3 -3
- package/dist/types-cjs/signals.d.cts +108 -11
- package/dist/types-cjs/store/next/optimistic.d.cts +13 -10
- package/dist/types-cjs/store/next/projection.d.cts +1 -1
- package/dist/types-cjs/store/next/store.d.cts +22 -0
- package/dist/types-cjs/store/next/target.d.cts +25 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NOT_PENDING, REACTIVE_DISPOSED, REACTIVE_DIRTY, REACTIVE_CHECK, unwrapOverride, REACTIVE_ZOMBIE, STATUS_UNINITIALIZED, STATUS_PENDING, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_MANUAL_WRITE, CONFIG_HAS_COMPANIONS, CONFIG_CHILD_COMPANIONS, STATUS_ERROR, REACTIVE_RECOMPUTING_DEPS } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { setSignal, prepareComputed, read, context, stale, currentOptimisticLane, tracking, ext, setLatestReadActive, setContextInternal, optimisticComputed,
|
|
3
|
+
import { setSignal, pendingCheckActive, setPendingCheckActive, prepareComputed, read, context, stale, currentOptimisticLane, tracking, ext, setLatestReadActive, setContextInternal, optimisticComputed, latestReadActive, optimisticSignal } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -47,23 +47,23 @@ let pendingProbe = null;
|
|
|
47
47
|
* O(all-leaves-ever-read)-per-update pathology). Entries are permanent like
|
|
48
48
|
* the companions themselves; a store with no leaf-level isPending()/latest()
|
|
49
49
|
* reads never allocates the set or pays the walk. */ function markFirewallChildCompanions(e) {
|
|
50
|
-
const t = e.
|
|
50
|
+
const t = e.st;
|
|
51
51
|
if (!t) return;
|
|
52
52
|
t.T |= CONFIG_CHILD_COMPANIONS;
|
|
53
|
-
(ext(t).
|
|
53
|
+
(ext(t).St ??= new Set).add(e);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function getPendingSignal(e) {
|
|
57
|
-
let t = e.o?.
|
|
57
|
+
let t = e.o?.ye;
|
|
58
58
|
if (!t) {
|
|
59
59
|
// Start false, write true if pending - ensures reversion returns to false
|
|
60
60
|
t = optimisticSignal(false, {
|
|
61
61
|
ownedWrite: true
|
|
62
62
|
});
|
|
63
|
-
ext(e).
|
|
63
|
+
ext(e).ye = t;
|
|
64
64
|
e.T |= CONFIG_HAS_COMPANIONS;
|
|
65
65
|
markFirewallChildCompanions(e);
|
|
66
|
-
ext(t).
|
|
66
|
+
ext(t).Tt = e;
|
|
67
67
|
if (computePendingState(e)) setSignal(t, true);
|
|
68
68
|
}
|
|
69
69
|
return t;
|
|
@@ -72,7 +72,7 @@ function getPendingSignal(e) {
|
|
|
72
72
|
function collectPendingSources(e) {
|
|
73
73
|
if (!pendingProbe) return;
|
|
74
74
|
pendingProbe.sources.add(e);
|
|
75
|
-
const t = e.
|
|
75
|
+
const t = e.st || e;
|
|
76
76
|
if (t !== e) pendingProbe.sources.add(t);
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -105,17 +105,17 @@ function collectPendingSources(e) {
|
|
|
105
105
|
if (e.S & STATUS_ERROR) return false;
|
|
106
106
|
if (t.has(e)) return false;
|
|
107
107
|
t.add(e);
|
|
108
|
-
const n = e.
|
|
108
|
+
const n = e.st;
|
|
109
109
|
if (n && markWalk(n, t)) return true;
|
|
110
110
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
111
111
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
112
112
|
// pass's dependency set — walking past it would read dropped deps and
|
|
113
113
|
// latch a stale verdict on the companion.
|
|
114
114
|
const i = e;
|
|
115
|
-
const r = i.ie & REACTIVE_RECOMPUTING_DEPS ? i.
|
|
115
|
+
const r = i.ie & REACTIVE_RECOMPUTING_DEPS ? i.je : undefined;
|
|
116
116
|
if (r !== null) {
|
|
117
|
-
for (let e = i.
|
|
118
|
-
if (!e.
|
|
117
|
+
for (let e = i.ut ?? null; e !== null; e = e.lt) {
|
|
118
|
+
if (!e.ve && markWalk(e.ot, t)) return true;
|
|
119
119
|
if (e === r) break;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -128,10 +128,10 @@ function collectPendingSources(e) {
|
|
|
128
128
|
|
|
129
129
|
function quietPending(e) {
|
|
130
130
|
if (e.o?.le) {
|
|
131
|
-
for (const t of e.o.le) if (!t.o?.
|
|
131
|
+
for (const t of e.o.le) if (!t.o?.De) return false;
|
|
132
132
|
return true;
|
|
133
133
|
}
|
|
134
|
-
return e.o?.
|
|
134
|
+
return e.o?.De ?? false;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
|
|
@@ -152,40 +152,44 @@ function computePendingState(e) {
|
|
|
152
152
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
153
153
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
154
154
|
if (markCovered(e)) return true;
|
|
155
|
-
const n = e.
|
|
156
|
-
if (e.o?.
|
|
157
|
-
const t = e.o?.
|
|
158
|
-
const n = t.
|
|
155
|
+
const n = e.st;
|
|
156
|
+
if (e.o?.Tt) {
|
|
157
|
+
const t = e.o?.Tt;
|
|
158
|
+
const n = t.st || t;
|
|
159
159
|
return newQuestionInFlight(n);
|
|
160
160
|
}
|
|
161
|
-
if (n && e.
|
|
162
|
-
return !!(n.ie & REACTIVE_MANUAL_WRITE) || !n.o?.
|
|
161
|
+
if (n && e.Re !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
162
|
+
return !!(n.ie & REACTIVE_MANUAL_WRITE) || !n.o?.Ie && !(n.S & STATUS_PENDING) || !!(n.S & STATUS_PENDING) && quietPending(n);
|
|
163
163
|
}
|
|
164
164
|
// `!comp._loading`: a hold created while the loading window is still open is
|
|
165
165
|
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
166
166
|
// rest of the window (the UNINITIALIZED check suppresses exactly this frame
|
|
167
167
|
// for windowless first loads; born-committed nodes need their own gate, #2990).
|
|
168
|
-
if (e.
|
|
169
|
-
if (hasActiveOverride(e)) return !e.
|
|
170
|
-
|
|
168
|
+
if (e.Re !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ne) {
|
|
169
|
+
if (hasActiveOverride(e)) return !e.pe || !e.pe(e.Re, unwrapOverride(e.o?.Pe));
|
|
170
|
+
// A quiet re-ask's held landing still answers the same question: the
|
|
171
|
+
// classification survives the landing (asyncWrite) and dies with the
|
|
172
|
+
// commit (commitPendingNode) — verdict-quiet through the reveal, like
|
|
173
|
+
// the loading window above (#3178).
|
|
174
|
+
if (!t.o?.De) return true;
|
|
171
175
|
}
|
|
172
176
|
return newQuestionInFlight(t);
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
function syncCompanions(e, t) {
|
|
176
|
-
if (e.o?.
|
|
177
|
-
if (e.o?.
|
|
180
|
+
if (e.o?.ye) updatePendingSignal(e);
|
|
181
|
+
if (e.o?.Ce) setSignal(e.o?.Ce, t);
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
function updatePendingSignal(e) {
|
|
181
|
-
if (e.o?.
|
|
182
|
-
setSignal(e.o?.
|
|
185
|
+
if (e.o?.ye) {
|
|
186
|
+
setSignal(e.o?.ye, computePendingState(e));
|
|
183
187
|
}
|
|
184
|
-
if (e.o?.
|
|
188
|
+
if (e.o?.Ce) updatePendingSignal(e.o?.Ce);
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
function updateChildCompanions(e) {
|
|
188
|
-
const t = e.o?.
|
|
192
|
+
const t = e.o?.St;
|
|
189
193
|
if (t === undefined) return;
|
|
190
194
|
for (const e of t) updatePendingSignal(e);
|
|
191
195
|
}
|
|
@@ -204,7 +208,7 @@ function updateChildCompanions(e) {
|
|
|
204
208
|
const visit = e => {
|
|
205
209
|
if (i.has(e)) return;
|
|
206
210
|
i.add(e);
|
|
207
|
-
if (e.o?.
|
|
211
|
+
if (e.o?.ye || e.o?.Ce) n(e);
|
|
208
212
|
for (let t = e.u; t !== null; t = t.ae) visit(t.ce);
|
|
209
213
|
for (let t = e.o?.i ?? null; t !== null; t = t.Se) {
|
|
210
214
|
visit(t);
|
|
@@ -227,7 +231,7 @@ function updateChildCompanions(e) {
|
|
|
227
231
|
if (suppressedProbes.size === 0) return;
|
|
228
232
|
let t = false;
|
|
229
233
|
for (const [n, i] of suppressedProbes) {
|
|
230
|
-
const r = n.
|
|
234
|
+
const r = n.Ae;
|
|
231
235
|
const s = r ? currentTransition(r) : null;
|
|
232
236
|
if (!s) {
|
|
233
237
|
suppressedProbes.delete(n);
|
|
@@ -235,11 +239,11 @@ function updateChildCompanions(e) {
|
|
|
235
239
|
}
|
|
236
240
|
if (s !== e) continue;
|
|
237
241
|
suppressedProbes.delete(n);
|
|
238
|
-
const o = n.o?.
|
|
242
|
+
const o = n.o?.ye?.o?.Je;
|
|
239
243
|
for (const e of i) {
|
|
240
244
|
if (e.ie & REACTIVE_DISPOSED) continue;
|
|
241
245
|
e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
242
|
-
if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.
|
|
246
|
+
if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.Je = undefined;
|
|
243
247
|
enqueueSub(e);
|
|
244
248
|
t = true;
|
|
245
249
|
}
|
|
@@ -249,19 +253,19 @@ function updateChildCompanions(e) {
|
|
|
249
253
|
|
|
250
254
|
function snapCompanionsToState(e) {
|
|
251
255
|
suppressedProbes.size !== 0 && suppressedProbes.delete(e);
|
|
252
|
-
const t = e.o?.
|
|
253
|
-
if (t && (t.o?.
|
|
256
|
+
const t = e.o?.ye;
|
|
257
|
+
if (t && (t.o?.Pe === undefined || t.o?.Pe === NOT_PENDING)) {
|
|
254
258
|
const n = computePendingState(e);
|
|
255
|
-
if (t.be !== n || t.
|
|
259
|
+
if (t.be !== n || t.Re !== NOT_PENDING) {
|
|
256
260
|
t.be = n;
|
|
257
|
-
t.
|
|
261
|
+
t.Re = NOT_PENDING;
|
|
258
262
|
insertSubs(t);
|
|
259
263
|
schedule();
|
|
260
264
|
}
|
|
261
265
|
}
|
|
262
|
-
const n = e.o?.
|
|
266
|
+
const n = e.o?.Ce;
|
|
263
267
|
if (n && !(n.ie & REACTIVE_DISPOSED)) {
|
|
264
|
-
if ((n.o?.
|
|
268
|
+
if ((n.o?.Pe === undefined || n.o?.Pe === NOT_PENDING) && n.Re === NOT_PENDING && !Object.is(n.be, e.be) && !(n.ie & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
265
269
|
n.ie |= REACTIVE_DIRTY;
|
|
266
270
|
insertIntoHeap(n, queueFor(n));
|
|
267
271
|
insertSubs(n);
|
|
@@ -272,7 +276,7 @@ function snapCompanionsToState(e) {
|
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
function getLatestValueComputed(e) {
|
|
275
|
-
let t = e.o?.
|
|
279
|
+
let t = e.o?.Ce;
|
|
276
280
|
// A shadow disposed while unobserved (its gated reader unmounted at a
|
|
277
281
|
// landing) is a corpse: sync writes into it equality-swallow against its
|
|
278
282
|
// frozen _value, and a later read revives it via recompute — clearing
|
|
@@ -289,16 +293,16 @@ function getLatestValueComputed(e) {
|
|
|
289
293
|
setContextInternal(null);
|
|
290
294
|
// Detach from owner so it isn't disposed with effects
|
|
291
295
|
t = optimisticComputed(() => read(e));
|
|
292
|
-
ext(e).
|
|
296
|
+
ext(e).Ce = t;
|
|
293
297
|
e.T |= CONFIG_HAS_COMPANIONS;
|
|
294
298
|
markFirewallChildCompanions(e);
|
|
295
|
-
ext(t).
|
|
299
|
+
ext(t).Tt = e;
|
|
296
300
|
// Parent-child lane relationship
|
|
297
301
|
// Backfill an in-flight write (mirrors getPendingSignal): the companion is
|
|
298
302
|
// created lazily, possibly after the write was processed — syncCompanions
|
|
299
303
|
// only pushes into companions that already exist, so the first latest()
|
|
300
304
|
// read inside a held transition showed the committed value (#3041).
|
|
301
|
-
if (e.
|
|
305
|
+
if (e.Re !== NOT_PENDING && !hasActiveOverride(e)) setSignal(t, e.Re);
|
|
302
306
|
setContextInternal(r);
|
|
303
307
|
setPendingCheckActive(i);
|
|
304
308
|
setLatestReadActive(n);
|
|
@@ -310,7 +314,7 @@ function getLatestValueComputed(e) {
|
|
|
310
314
|
const t = getLatestValueComputed(e);
|
|
311
315
|
const n = latestReadActive;
|
|
312
316
|
setLatestReadActive(false);
|
|
313
|
-
const i = e.o?.
|
|
317
|
+
const i = e.o?.Pe !== undefined && e.o?.Pe !== NOT_PENDING ? unwrapOverride(e.o?.Pe) : e.be;
|
|
314
318
|
let r;
|
|
315
319
|
try {
|
|
316
320
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -319,9 +323,24 @@ function getLatestValueComputed(e) {
|
|
|
319
323
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
320
324
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
321
325
|
const e = queueFor(t);
|
|
322
|
-
if (t.
|
|
326
|
+
if (t.Me >= e.Qe && !(t.ie & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
323
327
|
markHeap(e);
|
|
324
|
-
|
|
328
|
+
// Suspend probe collection during the pull (mirrors pendingCheckRead's
|
|
329
|
+
// prepare): a probe through latest() answers for the SHADOW — the
|
|
330
|
+
// read() dispatch collects it deliberately, so the verdict reflects
|
|
331
|
+
// async still in flight for the latest view, not the parent's held
|
|
332
|
+
// write. A stale shadow recomputing HERE ran its `read(parent)` with
|
|
333
|
+
// the probe still live and collected the parent too, so the verdict
|
|
334
|
+
// depended on whether anything had pulled the shadow current earlier
|
|
335
|
+
// in the tick (#3104: reading latest(m) flipped a later
|
|
336
|
+
// latest(() => isPending(x)) from true to false).
|
|
337
|
+
const n = pendingCheckActive;
|
|
338
|
+
setPendingCheckActive(false);
|
|
339
|
+
try {
|
|
340
|
+
prepareComputed(t, true);
|
|
341
|
+
} finally {
|
|
342
|
+
setPendingCheckActive(n);
|
|
343
|
+
}
|
|
325
344
|
}
|
|
326
345
|
r = read(t);
|
|
327
346
|
} catch (t) {
|
|
@@ -331,10 +350,10 @@ function getLatestValueComputed(e) {
|
|
|
331
350
|
setLatestReadActive(n);
|
|
332
351
|
}
|
|
333
352
|
if (t.S & STATUS_PENDING) return i;
|
|
334
|
-
if (stale && currentOptimisticLane && t.o?.
|
|
335
|
-
const e = findLane(t.o?.
|
|
353
|
+
if (stale && currentOptimisticLane && t.o?.Je) {
|
|
354
|
+
const e = findLane(t.o?.Je);
|
|
336
355
|
const n = findLane(currentOptimisticLane);
|
|
337
|
-
if (e !== n && e.
|
|
356
|
+
if (e !== n && e.Oe.size > 0) {
|
|
338
357
|
return i;
|
|
339
358
|
}
|
|
340
359
|
}
|
|
@@ -342,15 +361,41 @@ function getLatestValueComputed(e) {
|
|
|
342
361
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
343
362
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
344
363
|
// other transition's committed view, matching read()'s own selection.
|
|
345
|
-
if (t.
|
|
364
|
+
if (t.Re !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.Ae && activeTransition !== t.Ae)) return t.Re;
|
|
346
365
|
return r;
|
|
347
366
|
}
|
|
348
367
|
|
|
368
|
+
/**
|
|
369
|
+
* A latest() shadow that is uninitialized only because it was CREATED during
|
|
370
|
+
* an active flight — its parent source already has a committed value, so
|
|
371
|
+
* latest() serves that as the visible value and a tracked reader has
|
|
372
|
+
* something to pair a verdict with (#3166). Same parent resolution as
|
|
373
|
+
* computePendingState. The pending signal companion also carries
|
|
374
|
+
* `_parentSource` but is a plain signal (no `_fn`) that never goes pending,
|
|
375
|
+
* so the `_fn` check is belt-and-braces for this call site.
|
|
376
|
+
*/ function latestShadowWithInitializedParent(e) {
|
|
377
|
+
if (typeof e.oe !== "function") return false;
|
|
378
|
+
const t = e.o?.Tt;
|
|
379
|
+
if (t === undefined) return false;
|
|
380
|
+
const n = t.st || t;
|
|
381
|
+
return !(n.S & STATUS_UNINITIALIZED);
|
|
382
|
+
}
|
|
383
|
+
|
|
349
384
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
350
385
|
setPendingCheckActive(false);
|
|
351
386
|
if (typeof e.oe === "function") prepareComputed(e, true);
|
|
352
387
|
const r = n.S;
|
|
353
|
-
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED
|
|
388
|
+
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED &&
|
|
389
|
+
// The suspend-throw is for a genuinely-first-load source: the tracked
|
|
390
|
+
// reader has nothing to pair a verdict with, so it parks on the source.
|
|
391
|
+
// A latest() SHADOW created lazily mid-flight is born uninitialized even
|
|
392
|
+
// though its parent has a committed value latest() will serve — throwing
|
|
393
|
+
// here (swallowed by latestRead's fallback) dropped the shadow from the
|
|
394
|
+
// probe, so a tracked latest(isPending()) probe created during a
|
|
395
|
+
// new-question flight cached `false` for that whole flight (#3166).
|
|
396
|
+
// Defer to the PARENT's initialization state and fall through to normal
|
|
397
|
+
// collection; the plain pending throw downstream still links the reader.
|
|
398
|
+
!latestShadowWithInitializedParent(n)) {
|
|
354
399
|
if (tracking && e !== t) link(e, t);
|
|
355
400
|
setPendingCheckActive(true);
|
|
356
401
|
throw n.o?._;
|
|
@@ -368,9 +413,9 @@ function getLatestValueComputed(e) {
|
|
|
368
413
|
* reader saw is an input, and pending remains the truth for every reader
|
|
369
414
|
* (#3028).
|
|
370
415
|
*/ function heldAwaitingAsync(e) {
|
|
371
|
-
const t = e.
|
|
416
|
+
const t = e.Ae;
|
|
372
417
|
const n = t ? currentTransition(t) : activeTransition;
|
|
373
|
-
if (!n || n.
|
|
418
|
+
if (!n || n.sn) return false;
|
|
374
419
|
// A plain staged write (a signal/store leaf — no _fn) held while an action
|
|
375
420
|
// is still running is an INPUT to a computation still in flight (#3078):
|
|
376
421
|
// the pairing rule must not suppress the verdict, or a memo recomputing
|
|
@@ -385,14 +430,14 @@ function getLatestValueComputed(e) {
|
|
|
385
430
|
// action check above; the reporter scan below is for transition-held
|
|
386
431
|
// writes whose source async is still computing.
|
|
387
432
|
if (!t) return false;
|
|
388
|
-
for (const [e, t] of n.
|
|
433
|
+
for (const [e, t] of n._e) {
|
|
389
434
|
if (t.size && e.S & STATUS_PENDING && e.o?._?.source === e) return true;
|
|
390
435
|
}
|
|
391
436
|
return false;
|
|
392
437
|
}
|
|
393
438
|
|
|
394
439
|
function recordFreshRead(e, t) {
|
|
395
|
-
if (pendingProbe !== null && e.
|
|
440
|
+
if (pendingProbe !== null && e.Re !== NOT_PENDING && t === e.Re) {
|
|
396
441
|
if (heldAwaitingAsync(e)) return;
|
|
397
442
|
pendingProbe.freshReads.add(e);
|
|
398
443
|
}
|
|
@@ -400,10 +445,10 @@ function recordFreshRead(e, t) {
|
|
|
400
445
|
|
|
401
446
|
function applyReask(e, t) {
|
|
402
447
|
const n = !!(e.S & STATUS_PENDING);
|
|
403
|
-
const i = t && !(n && !e.o?.
|
|
404
|
-
const r = n && (e.o?.
|
|
448
|
+
const i = t && !(n && !e.o?.De);
|
|
449
|
+
const r = n && (e.o?.De ?? false) !== i;
|
|
405
450
|
// Allocation-free for the quiet case: false is the extension default.
|
|
406
|
-
if (i) ext(e).
|
|
451
|
+
if (i) ext(e).De = true; else if (e.o !== null) e.o.De = false;
|
|
407
452
|
return r;
|
|
408
453
|
}
|
|
409
454
|
|
|
@@ -429,6 +474,17 @@ function isPending(e) {
|
|
|
429
474
|
};
|
|
430
475
|
const collectPending = () => {
|
|
431
476
|
setPendingCheckActive(false);
|
|
477
|
+
// Companion reads are mode-neutral plumbing: under an outer latest()
|
|
478
|
+
// (isPending inside a latest window — #3104's memo shape) leaving latest
|
|
479
|
+
// mode active dispatched these reads through latestRead, which built a
|
|
480
|
+
// SHADOW OF THE PENDING SIGNAL itself. The next updatePendingSignal then
|
|
481
|
+
// wrote that companion-on-companion from inside a recompute
|
|
482
|
+
// (syncCompanions → setSignal on a shadow created without ownedWrite)
|
|
483
|
+
// and halted dev with the owned-scope write guard. The creation paths
|
|
484
|
+
// (getLatestValueComputed / getPendingSignal) already suspend both
|
|
485
|
+
// modes; this read site must too.
|
|
486
|
+
const e = latestReadActive;
|
|
487
|
+
setLatestReadActive(false);
|
|
432
488
|
try {
|
|
433
489
|
i.sources.forEach(e => {
|
|
434
490
|
if (read(getPendingSignal(e))) {
|
|
@@ -436,6 +492,7 @@ function isPending(e) {
|
|
|
436
492
|
}
|
|
437
493
|
});
|
|
438
494
|
} finally {
|
|
495
|
+
setLatestReadActive(e);
|
|
439
496
|
setPendingCheckActive(true);
|
|
440
497
|
}
|
|
441
498
|
// A "not pending" verdict that exists only because this reader saw the
|
|
@@ -472,26 +529,26 @@ function isPending(e) {
|
|
|
472
529
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
473
530
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
474
531
|
// direct calls used, so behavior is identical once this module loads.
|
|
475
|
-
GlobalQueue.
|
|
532
|
+
GlobalQueue.Ue = syncCompanions;
|
|
476
533
|
|
|
477
534
|
GlobalQueue.de = updatePendingSignal;
|
|
478
535
|
|
|
479
|
-
GlobalQueue.
|
|
536
|
+
GlobalQueue.me = updateChildCompanions;
|
|
480
537
|
|
|
481
538
|
GlobalQueue.un = snapCompanionsToState;
|
|
482
539
|
|
|
483
|
-
GlobalQueue.
|
|
540
|
+
GlobalQueue.gt = latestRead;
|
|
484
541
|
|
|
485
|
-
GlobalQueue.
|
|
542
|
+
GlobalQueue.Ht = pendingCheckRead;
|
|
486
543
|
|
|
487
|
-
GlobalQueue.
|
|
544
|
+
GlobalQueue.kt = recordFreshRead;
|
|
488
545
|
|
|
489
|
-
GlobalQueue.
|
|
546
|
+
GlobalQueue.et = applyReask;
|
|
490
547
|
|
|
491
548
|
GlobalQueue.k = repollDownstreamVerdicts;
|
|
492
549
|
|
|
493
|
-
GlobalQueue.
|
|
550
|
+
GlobalQueue.Wt = witnessAffects;
|
|
494
551
|
|
|
495
|
-
GlobalQueue.
|
|
552
|
+
GlobalQueue.zt = wakeSuppressedProbes;
|
|
496
553
|
|
|
497
554
|
export { isPending, latest };
|
package/dist/prod/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./core/error.js";
|
|
1
|
+
export { ContextNotFoundError, NoOwnerError, NotReadyError, TimeoutError } from "./core/error.js";
|
|
2
2
|
|
|
3
|
-
export { clearSnapshots, isEqual, markSnapshotScope,
|
|
3
|
+
export { clearSnapshots, isEqual, markSnapshotScope, releaseSnapshotScope, runWithOwner, setSnapshotCapture, untrack } from "./core/core.js";
|
|
4
4
|
|
|
5
5
|
export { enableExternalSource } from "./core/external.js";
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ import "./core/effect.js";
|
|
|
20
20
|
|
|
21
21
|
export { action } from "./core/action.js";
|
|
22
22
|
|
|
23
|
-
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, resolve } from "./signals.js";
|
|
23
|
+
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until } from "./signals.js";
|
|
24
24
|
|
|
25
25
|
export { affects } from "./affects.js";
|
|
26
26
|
|