@solidjs/signals 2.0.0-rc.3 → 2.0.0-rc.5
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 +2494 -271
- package/dist/node.cjs +3691 -1595
- package/dist/prod/affects.js +13 -12
- package/dist/prod/boundaries.js +43 -35
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +137 -106
- package/dist/prod/core/constants.js +55 -1
- package/dist/prod/core/core.js +354 -247
- package/dist/prod/core/effect.js +47 -50
- package/dist/prod/core/error.js +13 -1
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +88 -52
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +61 -58
- package/dist/prod/core/owner.js +38 -38
- package/dist/prod/core/scheduler.js +401 -174
- package/dist/prod/core/verdict.js +132 -65
- package/dist/prod/index.js +7 -3
- package/dist/prod/map.js +106 -106
- package/dist/prod/signals.js +253 -25
- package/dist/prod/store/index.js +2 -0
- package/dist/prod/store/next/optimistic.js +314 -121
- package/dist/prod/store/next/patch-hooks.js +13 -0
- package/dist/prod/store/next/patch.js +614 -0
- package/dist/prod/store/next/projection.js +23 -19
- package/dist/prod/store/next/reconcile.js +307 -120
- package/dist/prod/store/next/store.js +440 -117
- package/dist/prod/store/next/target.js +13 -4
- package/dist/prod/store/store.js +5 -5
- package/dist/types/core/async.d.ts +2 -0
- package/dist/types/core/attribution.d.ts +9 -4
- package/dist/types/core/constants.d.ts +54 -0
- package/dist/types/core/core.d.ts +34 -21
- package/dist/types/core/dev.d.ts +8 -0
- package/dist/types/core/error.d.ts +9 -0
- package/dist/types/core/graph.d.ts +22 -0
- package/dist/types/core/index.d.ts +2 -2
- package/dist/types/core/scheduler.d.ts +46 -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 -0
- package/dist/types/store/index.d.ts +2 -0
- package/dist/types/store/next/optimistic.d.ts +13 -10
- package/dist/types/store/next/patch-hooks.d.ts +41 -0
- package/dist/types/store/next/patch.d.ts +91 -0
- package/dist/types/store/next/projection.d.ts +1 -1
- package/dist/types/store/next/reconcile.d.ts +14 -0
- package/dist/types/store/next/store.d.ts +52 -2
- package/dist/types/store/next/target.d.ts +73 -8
- package/dist/types-cjs/core/async.d.cts +2 -0
- package/dist/types-cjs/core/attribution.d.cts +9 -4
- package/dist/types-cjs/core/constants.d.cts +54 -0
- package/dist/types-cjs/core/core.d.cts +34 -21
- package/dist/types-cjs/core/dev.d.cts +8 -0
- package/dist/types-cjs/core/error.d.cts +9 -0
- package/dist/types-cjs/core/graph.d.cts +22 -0
- package/dist/types-cjs/core/index.d.cts +2 -2
- package/dist/types-cjs/core/scheduler.d.cts +46 -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 -0
- package/dist/types-cjs/store/index.d.cts +2 -0
- package/dist/types-cjs/store/next/optimistic.d.cts +13 -10
- package/dist/types-cjs/store/next/patch-hooks.d.cts +41 -0
- package/dist/types-cjs/store/next/patch.d.cts +91 -0
- package/dist/types-cjs/store/next/projection.d.cts +1 -1
- package/dist/types-cjs/store/next/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/next/store.d.cts +52 -2
- package/dist/types-cjs/store/next/target.d.cts +73 -8
- package/package.json +2 -2
|
@@ -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?.Ge) return false;
|
|
132
132
|
return true;
|
|
133
133
|
}
|
|
134
|
-
return e.o?.
|
|
134
|
+
return e.o?.Ge ?? false;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
|
|
@@ -152,40 +152,40 @@ 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
161
|
if (n && e.Pe !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
162
|
-
return !!(n.ie & REACTIVE_MANUAL_WRITE) || !n.o?.
|
|
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.Pe !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.
|
|
169
|
-
if (hasActiveOverride(e)) return !e.
|
|
168
|
+
if (e.Pe !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ne) {
|
|
169
|
+
if (hasActiveOverride(e)) return !e.ge || !e.ge(e.Pe, unwrapOverride(e.o?.Oe));
|
|
170
170
|
return true;
|
|
171
171
|
}
|
|
172
172
|
return newQuestionInFlight(t);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
function syncCompanions(e, t) {
|
|
176
|
-
if (e.o?.
|
|
177
|
-
if (e.o?.
|
|
176
|
+
if (e.o?.ye) updatePendingSignal(e);
|
|
177
|
+
if (e.o?.Ce) setSignal(e.o?.Ce, t);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
function updatePendingSignal(e) {
|
|
181
|
-
if (e.o?.
|
|
182
|
-
setSignal(e.o?.
|
|
181
|
+
if (e.o?.ye) {
|
|
182
|
+
setSignal(e.o?.ye, computePendingState(e));
|
|
183
183
|
}
|
|
184
|
-
if (e.o?.
|
|
184
|
+
if (e.o?.Ce) updatePendingSignal(e.o?.Ce);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
function updateChildCompanions(e) {
|
|
188
|
-
const t = e.o?.
|
|
188
|
+
const t = e.o?.St;
|
|
189
189
|
if (t === undefined) return;
|
|
190
190
|
for (const e of t) updatePendingSignal(e);
|
|
191
191
|
}
|
|
@@ -204,9 +204,9 @@ function updateChildCompanions(e) {
|
|
|
204
204
|
const visit = e => {
|
|
205
205
|
if (i.has(e)) return;
|
|
206
206
|
i.add(e);
|
|
207
|
-
if (e.o?.
|
|
208
|
-
for (let t = e.u; t !== null; t = t.
|
|
209
|
-
for (let t = e.o?.
|
|
207
|
+
if (e.o?.ye || e.o?.Ce) n(e);
|
|
208
|
+
for (let t = e.u; t !== null; t = t.ae) visit(t.ce);
|
|
209
|
+
for (let t = e.o?.i ?? null; t !== null; t = t.Se) {
|
|
210
210
|
visit(t);
|
|
211
211
|
}
|
|
212
212
|
};
|
|
@@ -227,7 +227,7 @@ function updateChildCompanions(e) {
|
|
|
227
227
|
if (suppressedProbes.size === 0) return;
|
|
228
228
|
let t = false;
|
|
229
229
|
for (const [n, i] of suppressedProbes) {
|
|
230
|
-
const r = n.
|
|
230
|
+
const r = n.Ae;
|
|
231
231
|
const s = r ? currentTransition(r) : null;
|
|
232
232
|
if (!s) {
|
|
233
233
|
suppressedProbes.delete(n);
|
|
@@ -235,11 +235,11 @@ function updateChildCompanions(e) {
|
|
|
235
235
|
}
|
|
236
236
|
if (s !== e) continue;
|
|
237
237
|
suppressedProbes.delete(n);
|
|
238
|
-
const o = n.o?.
|
|
238
|
+
const o = n.o?.ye?.o?.Je;
|
|
239
239
|
for (const e of i) {
|
|
240
240
|
if (e.ie & REACTIVE_DISPOSED) continue;
|
|
241
241
|
e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
242
|
-
if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.
|
|
242
|
+
if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.Je = undefined;
|
|
243
243
|
enqueueSub(e);
|
|
244
244
|
t = true;
|
|
245
245
|
}
|
|
@@ -249,8 +249,8 @@ function updateChildCompanions(e) {
|
|
|
249
249
|
|
|
250
250
|
function snapCompanionsToState(e) {
|
|
251
251
|
suppressedProbes.size !== 0 && suppressedProbes.delete(e);
|
|
252
|
-
const t = e.o?.
|
|
253
|
-
if (t && (t.o?.
|
|
252
|
+
const t = e.o?.ye;
|
|
253
|
+
if (t && (t.o?.Oe === undefined || t.o?.Oe === NOT_PENDING)) {
|
|
254
254
|
const n = computePendingState(e);
|
|
255
255
|
if (t.be !== n || t.Pe !== NOT_PENDING) {
|
|
256
256
|
t.be = n;
|
|
@@ -259,9 +259,9 @@ function snapCompanionsToState(e) {
|
|
|
259
259
|
schedule();
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
|
-
const n = e.o?.
|
|
262
|
+
const n = e.o?.Ce;
|
|
263
263
|
if (n && !(n.ie & REACTIVE_DISPOSED)) {
|
|
264
|
-
if ((n.o?.
|
|
264
|
+
if ((n.o?.Oe === undefined || n.o?.Oe === NOT_PENDING) && n.Pe === NOT_PENDING && !Object.is(n.be, e.be) && !(n.ie & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
265
265
|
n.ie |= REACTIVE_DIRTY;
|
|
266
266
|
insertIntoHeap(n, queueFor(n));
|
|
267
267
|
insertSubs(n);
|
|
@@ -272,7 +272,7 @@ function snapCompanionsToState(e) {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
function getLatestValueComputed(e) {
|
|
275
|
-
let t = e.o?.
|
|
275
|
+
let t = e.o?.Ce;
|
|
276
276
|
// A shadow disposed while unobserved (its gated reader unmounted at a
|
|
277
277
|
// landing) is a corpse: sync writes into it equality-swallow against its
|
|
278
278
|
// frozen _value, and a later read revives it via recompute — clearing
|
|
@@ -289,10 +289,10 @@ function getLatestValueComputed(e) {
|
|
|
289
289
|
setContextInternal(null);
|
|
290
290
|
// Detach from owner so it isn't disposed with effects
|
|
291
291
|
t = optimisticComputed(() => read(e));
|
|
292
|
-
ext(e).
|
|
292
|
+
ext(e).Ce = t;
|
|
293
293
|
e.T |= CONFIG_HAS_COMPANIONS;
|
|
294
294
|
markFirewallChildCompanions(e);
|
|
295
|
-
ext(t).
|
|
295
|
+
ext(t).Tt = e;
|
|
296
296
|
// Parent-child lane relationship
|
|
297
297
|
// Backfill an in-flight write (mirrors getPendingSignal): the companion is
|
|
298
298
|
// created lazily, possibly after the write was processed — syncCompanions
|
|
@@ -310,7 +310,7 @@ function getLatestValueComputed(e) {
|
|
|
310
310
|
const t = getLatestValueComputed(e);
|
|
311
311
|
const n = latestReadActive;
|
|
312
312
|
setLatestReadActive(false);
|
|
313
|
-
const i = e.o?.
|
|
313
|
+
const i = e.o?.Oe !== undefined && e.o?.Oe !== NOT_PENDING ? unwrapOverride(e.o?.Oe) : e.be;
|
|
314
314
|
let r;
|
|
315
315
|
try {
|
|
316
316
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -319,9 +319,24 @@ function getLatestValueComputed(e) {
|
|
|
319
319
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
320
320
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
321
321
|
const e = queueFor(t);
|
|
322
|
-
if (t.
|
|
322
|
+
if (t.Me >= e.Qe && !(t.ie & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
323
323
|
markHeap(e);
|
|
324
|
-
|
|
324
|
+
// Suspend probe collection during the pull (mirrors pendingCheckRead's
|
|
325
|
+
// prepare): a probe through latest() answers for the SHADOW — the
|
|
326
|
+
// read() dispatch collects it deliberately, so the verdict reflects
|
|
327
|
+
// async still in flight for the latest view, not the parent's held
|
|
328
|
+
// write. A stale shadow recomputing HERE ran its `read(parent)` with
|
|
329
|
+
// the probe still live and collected the parent too, so the verdict
|
|
330
|
+
// depended on whether anything had pulled the shadow current earlier
|
|
331
|
+
// in the tick (#3104: reading latest(m) flipped a later
|
|
332
|
+
// latest(() => isPending(x)) from true to false).
|
|
333
|
+
const n = pendingCheckActive;
|
|
334
|
+
setPendingCheckActive(false);
|
|
335
|
+
try {
|
|
336
|
+
prepareComputed(t, true);
|
|
337
|
+
} finally {
|
|
338
|
+
setPendingCheckActive(n);
|
|
339
|
+
}
|
|
325
340
|
}
|
|
326
341
|
r = read(t);
|
|
327
342
|
} catch (t) {
|
|
@@ -331,10 +346,10 @@ function getLatestValueComputed(e) {
|
|
|
331
346
|
setLatestReadActive(n);
|
|
332
347
|
}
|
|
333
348
|
if (t.S & STATUS_PENDING) return i;
|
|
334
|
-
if (stale && currentOptimisticLane && t.o?.
|
|
335
|
-
const e = findLane(t.o?.
|
|
349
|
+
if (stale && currentOptimisticLane && t.o?.Je) {
|
|
350
|
+
const e = findLane(t.o?.Je);
|
|
336
351
|
const n = findLane(currentOptimisticLane);
|
|
337
|
-
if (e !== n && e.
|
|
352
|
+
if (e !== n && e.De.size > 0) {
|
|
338
353
|
return i;
|
|
339
354
|
}
|
|
340
355
|
}
|
|
@@ -342,15 +357,41 @@ function getLatestValueComputed(e) {
|
|
|
342
357
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
343
358
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
344
359
|
// other transition's committed view, matching read()'s own selection.
|
|
345
|
-
if (t.Pe !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.
|
|
360
|
+
if (t.Pe !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.Ae && activeTransition !== t.Ae)) return t.Pe;
|
|
346
361
|
return r;
|
|
347
362
|
}
|
|
348
363
|
|
|
364
|
+
/**
|
|
365
|
+
* A latest() shadow that is uninitialized only because it was CREATED during
|
|
366
|
+
* an active flight — its parent source already has a committed value, so
|
|
367
|
+
* latest() serves that as the visible value and a tracked reader has
|
|
368
|
+
* something to pair a verdict with (#3166). Same parent resolution as
|
|
369
|
+
* computePendingState. The pending signal companion also carries
|
|
370
|
+
* `_parentSource` but is a plain signal (no `_fn`) that never goes pending,
|
|
371
|
+
* so the `_fn` check is belt-and-braces for this call site.
|
|
372
|
+
*/ function latestShadowWithInitializedParent(e) {
|
|
373
|
+
if (typeof e.oe !== "function") return false;
|
|
374
|
+
const t = e.o?.Tt;
|
|
375
|
+
if (t === undefined) return false;
|
|
376
|
+
const n = t.st || t;
|
|
377
|
+
return !(n.S & STATUS_UNINITIALIZED);
|
|
378
|
+
}
|
|
379
|
+
|
|
349
380
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
350
381
|
setPendingCheckActive(false);
|
|
351
|
-
if (typeof e.
|
|
382
|
+
if (typeof e.oe === "function") prepareComputed(e, true);
|
|
352
383
|
const r = n.S;
|
|
353
|
-
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED
|
|
384
|
+
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED &&
|
|
385
|
+
// The suspend-throw is for a genuinely-first-load source: the tracked
|
|
386
|
+
// reader has nothing to pair a verdict with, so it parks on the source.
|
|
387
|
+
// A latest() SHADOW created lazily mid-flight is born uninitialized even
|
|
388
|
+
// though its parent has a committed value latest() will serve — throwing
|
|
389
|
+
// here (swallowed by latestRead's fallback) dropped the shadow from the
|
|
390
|
+
// probe, so a tracked latest(isPending()) probe created during a
|
|
391
|
+
// new-question flight cached `false` for that whole flight (#3166).
|
|
392
|
+
// Defer to the PARENT's initialization state and fall through to normal
|
|
393
|
+
// collection; the plain pending throw downstream still links the reader.
|
|
394
|
+
!latestShadowWithInitializedParent(n)) {
|
|
354
395
|
if (tracking && e !== t) link(e, t);
|
|
355
396
|
setPendingCheckActive(true);
|
|
356
397
|
throw n.o?._;
|
|
@@ -368,10 +409,24 @@ function getLatestValueComputed(e) {
|
|
|
368
409
|
* reader saw is an input, and pending remains the truth for every reader
|
|
369
410
|
* (#3028).
|
|
370
411
|
*/ function heldAwaitingAsync(e) {
|
|
371
|
-
const t = e.
|
|
372
|
-
const n = t ? currentTransition(t) :
|
|
373
|
-
if (!n || n.
|
|
374
|
-
|
|
412
|
+
const t = e.Ae;
|
|
413
|
+
const n = t ? currentTransition(t) : activeTransition;
|
|
414
|
+
if (!n || n.sn) return false;
|
|
415
|
+
// A plain staged write (a signal/store leaf — no _fn) held while an action
|
|
416
|
+
// is still running is an INPUT to a computation still in flight (#3078):
|
|
417
|
+
// the pairing rule must not suppress the verdict, or a memo recomputing
|
|
418
|
+
// mid-action reads the staged value, gets told "not pending", and
|
|
419
|
+
// disagrees with a direct isPending() probe for the whole action window.
|
|
420
|
+
// A computed's staged value is the opposite case — a LANDED answer
|
|
421
|
+
// awaiting reveal — where the pairing rule stands even inside an open
|
|
422
|
+
// action (#2831: a reader that saw the new value must not also see
|
|
423
|
+
// pending); still-computing answers are covered by the reporter scan.
|
|
424
|
+
if (n.ue.length && !e.oe) return true;
|
|
425
|
+
// A node not yet stamped with a transition only qualifies through the
|
|
426
|
+
// action check above; the reporter scan below is for transition-held
|
|
427
|
+
// writes whose source async is still computing.
|
|
428
|
+
if (!t) return false;
|
|
429
|
+
for (const [e, t] of n._e) {
|
|
375
430
|
if (t.size && e.S & STATUS_PENDING && e.o?._?.source === e) return true;
|
|
376
431
|
}
|
|
377
432
|
return false;
|
|
@@ -386,10 +441,10 @@ function recordFreshRead(e, t) {
|
|
|
386
441
|
|
|
387
442
|
function applyReask(e, t) {
|
|
388
443
|
const n = !!(e.S & STATUS_PENDING);
|
|
389
|
-
const i = t && !(n && !e.o?.
|
|
390
|
-
const r = n && (e.o?.
|
|
444
|
+
const i = t && !(n && !e.o?.Ge);
|
|
445
|
+
const r = n && (e.o?.Ge ?? false) !== i;
|
|
391
446
|
// Allocation-free for the quiet case: false is the extension default.
|
|
392
|
-
if (i) ext(e).
|
|
447
|
+
if (i) ext(e).Ge = true; else if (e.o !== null) e.o.Ge = false;
|
|
393
448
|
return r;
|
|
394
449
|
}
|
|
395
450
|
|
|
@@ -415,6 +470,17 @@ function isPending(e) {
|
|
|
415
470
|
};
|
|
416
471
|
const collectPending = () => {
|
|
417
472
|
setPendingCheckActive(false);
|
|
473
|
+
// Companion reads are mode-neutral plumbing: under an outer latest()
|
|
474
|
+
// (isPending inside a latest window — #3104's memo shape) leaving latest
|
|
475
|
+
// mode active dispatched these reads through latestRead, which built a
|
|
476
|
+
// SHADOW OF THE PENDING SIGNAL itself. The next updatePendingSignal then
|
|
477
|
+
// wrote that companion-on-companion from inside a recompute
|
|
478
|
+
// (syncCompanions → setSignal on a shadow created without ownedWrite)
|
|
479
|
+
// and halted dev with the owned-scope write guard. The creation paths
|
|
480
|
+
// (getLatestValueComputed / getPendingSignal) already suspend both
|
|
481
|
+
// modes; this read site must too.
|
|
482
|
+
const e = latestReadActive;
|
|
483
|
+
setLatestReadActive(false);
|
|
418
484
|
try {
|
|
419
485
|
i.sources.forEach(e => {
|
|
420
486
|
if (read(getPendingSignal(e))) {
|
|
@@ -422,6 +488,7 @@ function isPending(e) {
|
|
|
422
488
|
}
|
|
423
489
|
});
|
|
424
490
|
} finally {
|
|
491
|
+
setLatestReadActive(e);
|
|
425
492
|
setPendingCheckActive(true);
|
|
426
493
|
}
|
|
427
494
|
// A "not pending" verdict that exists only because this reader saw the
|
|
@@ -429,7 +496,7 @@ function isPending(e) {
|
|
|
429
496
|
// this flush (a downstream async pends and holds it), the suppression was
|
|
430
497
|
// wrong and the wrapper must re-ask (#3028). Remember who to wake — the
|
|
431
498
|
// async registration (GlobalQueue.notify) triggers wakeSuppressedProbes.
|
|
432
|
-
if (!i.found && i.suppressed.length && context && typeof context.
|
|
499
|
+
if (!i.found && i.suppressed.length && context && typeof context.oe === "function") {
|
|
433
500
|
for (const e of i.suppressed) {
|
|
434
501
|
let t = suppressedProbes.get(e);
|
|
435
502
|
if (!t) suppressedProbes.set(e, t = new Set);
|
|
@@ -458,26 +525,26 @@ function isPending(e) {
|
|
|
458
525
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
459
526
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
460
527
|
// direct calls used, so behavior is identical once this module loads.
|
|
461
|
-
GlobalQueue.
|
|
528
|
+
GlobalQueue.Re = syncCompanions;
|
|
462
529
|
|
|
463
530
|
GlobalQueue.de = updatePendingSignal;
|
|
464
531
|
|
|
465
|
-
GlobalQueue.
|
|
532
|
+
GlobalQueue.me = updateChildCompanions;
|
|
466
533
|
|
|
467
534
|
GlobalQueue.un = snapCompanionsToState;
|
|
468
535
|
|
|
469
|
-
GlobalQueue.
|
|
536
|
+
GlobalQueue.gt = latestRead;
|
|
470
537
|
|
|
471
|
-
GlobalQueue.
|
|
538
|
+
GlobalQueue.Ht = pendingCheckRead;
|
|
472
539
|
|
|
473
|
-
GlobalQueue.
|
|
540
|
+
GlobalQueue.kt = recordFreshRead;
|
|
474
541
|
|
|
475
|
-
GlobalQueue.
|
|
542
|
+
GlobalQueue.et = applyReask;
|
|
476
543
|
|
|
477
|
-
GlobalQueue.
|
|
544
|
+
GlobalQueue.k = repollDownstreamVerdicts;
|
|
478
545
|
|
|
479
|
-
GlobalQueue.
|
|
546
|
+
GlobalQueue.Wt = witnessAffects;
|
|
480
547
|
|
|
481
|
-
GlobalQueue.
|
|
548
|
+
GlobalQueue.zt = wakeSuppressedProbes;
|
|
482
549
|
|
|
483
550
|
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
|
|
|
@@ -38,6 +38,10 @@ export { createProjectionNext as createProjection } from "./store/next/projectio
|
|
|
38
38
|
|
|
39
39
|
export { merge, omit } from "./store/utils.js";
|
|
40
40
|
|
|
41
|
+
export { patchableRaw, registerPatch, registerRowOps, registerSlotPatchNext as registerSlotPatch } from "./store/next/patch.js";
|
|
42
|
+
|
|
43
|
+
export { storeHasFamily, storeHasOptimisticFamily, storeIsShallow } from "./store/next/store.js";
|
|
44
|
+
|
|
41
45
|
export { storePath } from "./store/storePath.js";
|
|
42
46
|
|
|
43
47
|
const DEV = undefined;
|