@solidjs/signals 2.0.0-beta.25 → 2.0.0-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev.js +113 -7
- package/dist/node.cjs +140 -41
- package/dist/prod/core/async.js +180 -107
- package/dist/prod/core/core.js +162 -162
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/external.js +4 -4
- 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 +38 -38
- package/dist/prod/core/owner.js +44 -44
- package/dist/prod/core/scheduler.js +94 -94
- package/dist/prod/core/verdict.js +55 -55
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +6 -6
- package/dist/prod/store/reconcile.js +1 -1
- package/dist/prod/store/store.js +58 -32
- package/dist/types/core/async.d.ts +1 -0
- package/dist/types-cjs/core/async.d.cts +1 -0
- package/package.json +1 -1
package/dist/prod/core/async.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING
|
|
1
|
+
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { untrack, context, setSignal } from "./core.js";
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ import "./invariants.js";
|
|
|
6
6
|
|
|
7
7
|
import { NotReadyError, StatusError } from "./error.js";
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { unobserved, trimStaleDeps } from "./graph.js";
|
|
10
10
|
|
|
11
11
|
import { enqueueSub } from "./heap.js";
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ import { resolveTransition, hasActiveOverride, assignOrMergeLane, resolveLane }
|
|
|
14
14
|
|
|
15
15
|
import { cleanup } from "./owner.js";
|
|
16
16
|
|
|
17
|
-
import { globalQueue, GlobalQueue, clock, schedule, flush, queuePendingNode, insertSubs } from "./scheduler.js";
|
|
17
|
+
import { globalQueue, GlobalQueue, clock, currentTransition, schedule, flush, queuePendingNode, insertSubs } from "./scheduler.js";
|
|
18
18
|
|
|
19
19
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
20
20
|
// predecessor — a singular slot promoted to a Set on the second source —
|
|
@@ -38,58 +38,94 @@ function clearPendingSources(e) {
|
|
|
38
38
|
e.oe = undefined;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function setPendingError(e, n,
|
|
41
|
+
function setPendingError(e, n, t) {
|
|
42
42
|
if (!n) {
|
|
43
43
|
e._ = null;
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
if (
|
|
47
|
-
e._ =
|
|
46
|
+
if (t instanceof NotReadyError && t.source === n) {
|
|
47
|
+
e._ = t;
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
const
|
|
51
|
-
if (!(
|
|
50
|
+
const r = e._;
|
|
51
|
+
if (!(r instanceof NotReadyError) || r.source !== n) {
|
|
52
52
|
e._ = new NotReadyError(n);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function forEachDependent(e, n) {
|
|
57
|
-
for (let
|
|
57
|
+
for (let t = e.o; t !== null; t = t.ue) n(t.le, t);
|
|
58
58
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
59
|
-
for (let
|
|
60
|
-
for (let e =
|
|
59
|
+
for (let t = e.u ?? null; t !== null; t = t.fe) {
|
|
60
|
+
for (let e = t.o; e !== null; e = e.ue) n(e.le, e);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
65
65
|
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
66
66
|
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
67
|
+
// Settle-time counterpart of unlinkSubs' last-one-out check. A lazy node that
|
|
68
|
+
// loses its last subscriber while STATUS_PENDING is exempt from autodispose
|
|
69
|
+
// (the in-flight work is an observer), so whatever CLEARS that pending state
|
|
70
|
+
// must run the release — otherwise the node stays linked and recomputes
|
|
71
|
+
// forever with zero subscribers (#2934). The node's own promise/iterator
|
|
72
|
+
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
73
|
+
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
74
|
+
function releaseIfSettledUnobserved(e) {
|
|
75
|
+
e.ae && e.T & CONFIG_AUTO_DISPOSE && !e.o && !(e.se & REACTIVE_ZOMBIE) && !(e.S & STATUS_PENDING) && unobserved(e);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
79
|
+
// sources through its own recursion (no per-node settle callback), so after
|
|
80
|
+
// the propagation completes, walk the same graph for stranded lazy nodes.
|
|
81
|
+
// Collect-then-release so unobserved() never unlinks under the walk.
|
|
82
|
+
function releaseSettledDependents(e) {
|
|
83
|
+
let n;
|
|
84
|
+
const t = new Set;
|
|
85
|
+
const visit = e => {
|
|
86
|
+
if (t.has(e)) return;
|
|
87
|
+
t.add(e);
|
|
88
|
+
if (!e.o && e.T & CONFIG_AUTO_DISPOSE) (n ??= []).push(e);
|
|
89
|
+
forEachDependent(e, visit);
|
|
90
|
+
};
|
|
91
|
+
forEachDependent(e, visit);
|
|
92
|
+
if (n) for (const e of n) releaseIfSettledUnobserved(e);
|
|
93
|
+
}
|
|
94
|
+
|
|
67
95
|
function settlePendingSource(e) {
|
|
68
96
|
let n = false;
|
|
97
|
+
let t;
|
|
69
98
|
const r = new Set;
|
|
70
99
|
// Companion updates no-op without the verdict layer (null hook).
|
|
71
|
-
const
|
|
72
|
-
const settle =
|
|
73
|
-
if (r.has(
|
|
74
|
-
r.add(
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
setPendingError(
|
|
79
|
-
|
|
100
|
+
const o = GlobalQueue.ce;
|
|
101
|
+
const settle = u => {
|
|
102
|
+
if (r.has(u) || !removePendingSource(u, e)) return;
|
|
103
|
+
r.add(u);
|
|
104
|
+
u.Se = clock;
|
|
105
|
+
const l = u.oe?.values().next().value;
|
|
106
|
+
if (l) {
|
|
107
|
+
setPendingError(u, l);
|
|
108
|
+
o !== null && o(u);
|
|
80
109
|
} else {
|
|
81
|
-
|
|
82
|
-
setPendingError(
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
enqueueSub(
|
|
110
|
+
u.S &= ~STATUS_PENDING;
|
|
111
|
+
setPendingError(u);
|
|
112
|
+
o !== null && o(u);
|
|
113
|
+
if (u.de) {
|
|
114
|
+
enqueueSub(u);
|
|
86
115
|
n = true;
|
|
87
116
|
}
|
|
88
|
-
|
|
117
|
+
u.de = false;
|
|
118
|
+
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
119
|
+
// again at release time — deferred so unobserved() can't unlink subs
|
|
120
|
+
// lists this walk is still iterating.
|
|
121
|
+
if (!u.o && u.T & CONFIG_AUTO_DISPOSE) (t ??= []).push(u);
|
|
89
122
|
}
|
|
90
|
-
forEachDependent(
|
|
123
|
+
forEachDependent(u, settle);
|
|
91
124
|
};
|
|
92
125
|
forEachDependent(e, settle);
|
|
126
|
+
// Release before the flush schedule below: unobserved() pulls the node back
|
|
127
|
+
// out of the heap, so the enqueueSub above never recomputes a released node.
|
|
128
|
+
if (t) for (const e of t) releaseIfSettledUnobserved(e);
|
|
93
129
|
if (n) schedule();
|
|
94
130
|
}
|
|
95
131
|
|
|
@@ -98,44 +134,69 @@ function isThenable(e) {
|
|
|
98
134
|
return e != null && typeof e === "object" && typeof e.then === "function";
|
|
99
135
|
}
|
|
100
136
|
|
|
101
|
-
function handleAsync(e, n,
|
|
102
|
-
let
|
|
137
|
+
function handleAsync(e, n, t) {
|
|
138
|
+
let r = false;
|
|
103
139
|
let o = false;
|
|
104
140
|
if (typeof n === "object" && n !== null) {
|
|
105
141
|
untrack(() => {
|
|
106
|
-
|
|
107
|
-
o = !
|
|
142
|
+
r = n[Symbol.asyncIterator];
|
|
143
|
+
o = !r && isThenable(n);
|
|
108
144
|
});
|
|
109
145
|
}
|
|
110
|
-
if (!o && !
|
|
146
|
+
if (!o && !r) {
|
|
111
147
|
e.Te = null;
|
|
112
148
|
return n;
|
|
113
149
|
}
|
|
114
150
|
e.Te = n;
|
|
115
151
|
let u;
|
|
116
|
-
|
|
152
|
+
// Settle-time transition re-entry. The loading rail is invisible to
|
|
153
|
+
// transactions (#2933): a boundary-caught first load never registers as an
|
|
154
|
+
// async reporter, so its settle — the boundary's fallback -> content
|
|
155
|
+
// reveal — must flow ambiently. The node can still carry a `_transition`
|
|
156
|
+
// stamp (pending-node bookkeeping rides through the stamping sites), and
|
|
157
|
+
// blindly re-entering that stamped, still-incomplete transaction stashed
|
|
158
|
+
// the reveal with it — a deadlock when the transaction's completion
|
|
159
|
+
// depended on the reveal (#2937). An ESCAPED first load did register and
|
|
160
|
+
// keeps transition scheduling; initialized (value-holding) pending settles
|
|
161
|
+
// are the transaction's reveal machinery and always re-enter.
|
|
162
|
+
const settleTransition = () => {
|
|
163
|
+
const n = resolveTransition(e);
|
|
164
|
+
if (n && e.S & STATUS_UNINITIALIZED && !currentTransition(n).Ee.has(e)) {
|
|
165
|
+
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
166
|
+
// stash-path restamp both re-enter the transaction through it.
|
|
167
|
+
e.Ie = null;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
globalQueue.initTransition(n);
|
|
171
|
+
};
|
|
172
|
+
const handleError = t => {
|
|
117
173
|
if (e.Te !== n) return;
|
|
118
|
-
|
|
174
|
+
settleTransition();
|
|
119
175
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
120
|
-
|
|
121
|
-
e
|
|
176
|
+
const r = t instanceof NotReadyError;
|
|
177
|
+
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, t);
|
|
178
|
+
e.Se = clock;
|
|
179
|
+
// A real error settles derivatively-pending dependents (notifyStatus
|
|
180
|
+
// cleared their pending sources), so stranded lazy ones release here —
|
|
181
|
+
// the error twin of settlePendingSource's release (#2934).
|
|
182
|
+
if (!r) releaseSettledDependents(e);
|
|
122
183
|
};
|
|
123
|
-
const asyncWrite = (
|
|
184
|
+
const asyncWrite = (r, o) => {
|
|
124
185
|
if (e.Te !== n) return;
|
|
125
186
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
126
187
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
127
188
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
128
189
|
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
129
|
-
|
|
190
|
+
settleTransition();
|
|
130
191
|
const u = !!(e.S & STATUS_UNINITIALIZED);
|
|
131
192
|
trimStaleDeps(e);
|
|
132
193
|
clearStatus(e);
|
|
133
194
|
const l = resolveLane(e);
|
|
134
|
-
if (l) l.
|
|
135
|
-
if (
|
|
136
|
-
r
|
|
195
|
+
if (l) l.Ne.delete(e);
|
|
196
|
+
if (t) {
|
|
197
|
+
t(r);
|
|
137
198
|
if (u) clearStatus(e, true);
|
|
138
|
-
} else if (e.
|
|
199
|
+
} else if (e.Ae !== undefined) {
|
|
139
200
|
// Optimistic node — resting OR covered by an active override — holds
|
|
140
201
|
// through the shared pending-node path, exactly like a plain async memo,
|
|
141
202
|
// so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
|
|
@@ -145,8 +206,8 @@ function handleAsync(e, n, r) {
|
|
|
145
206
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
146
207
|
// has committed by then, so corrections reveal atomically with their
|
|
147
208
|
// transition rather than escaping it.
|
|
148
|
-
if (e.
|
|
149
|
-
e.
|
|
209
|
+
if (e._e === NOT_PENDING) queuePendingNode(e);
|
|
210
|
+
e._e = r;
|
|
150
211
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
151
212
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
152
213
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -154,22 +215,22 @@ function handleAsync(e, n, r) {
|
|
|
154
215
|
// only notified when the hold is visible to them: under an active
|
|
155
216
|
// override every reader sees the override (A17), so waking subs would
|
|
156
217
|
// re-show an unchanged view — the revert is the notification point.
|
|
157
|
-
GlobalQueue.
|
|
218
|
+
GlobalQueue.De !== null && GlobalQueue.De(e, r);
|
|
158
219
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
159
|
-
e.
|
|
220
|
+
e.Se = clock;
|
|
160
221
|
} else if (l) {
|
|
161
222
|
// Route through lane's effect queue for independent flushing
|
|
162
|
-
const n = e.
|
|
163
|
-
const
|
|
223
|
+
const n = e.Pe;
|
|
224
|
+
const t = e.Ue;
|
|
164
225
|
const o = e.Re;
|
|
165
226
|
try {
|
|
166
|
-
if (!n && u || !o || !o(
|
|
167
|
-
e.
|
|
168
|
-
e.
|
|
227
|
+
if (!n && u || !o || !o(r, t)) {
|
|
228
|
+
e.Ue = r;
|
|
229
|
+
e.Se = clock;
|
|
169
230
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
170
231
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
171
232
|
// (computePendingState doesn't read _value).
|
|
172
|
-
GlobalQueue.
|
|
233
|
+
GlobalQueue.De !== null && GlobalQueue.De(e, r);
|
|
173
234
|
insertSubs(e, true);
|
|
174
235
|
}
|
|
175
236
|
} catch (n) {
|
|
@@ -181,7 +242,7 @@ function handleAsync(e, n, r) {
|
|
|
181
242
|
}
|
|
182
243
|
} else {
|
|
183
244
|
try {
|
|
184
|
-
setSignal(e, () =>
|
|
245
|
+
setSignal(e, () => r);
|
|
185
246
|
} catch (n) {
|
|
186
247
|
// Same containment as above: setSignal's comparator throw is the only
|
|
187
248
|
// pre-commit failure here, and there is no user callsite to throw to.
|
|
@@ -198,17 +259,21 @@ function handleAsync(e, n, r) {
|
|
|
198
259
|
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
199
260
|
// fetch per suspended re-read). Settling is that observer's release, so
|
|
200
261
|
// it runs the same last-one-out check the other release sites run.
|
|
262
|
+
// Returns whether the node released, so the iterator branch can stop
|
|
263
|
+
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
201
264
|
const settleAutodispose = () => {
|
|
202
265
|
if (e.T & CONFIG_AUTO_DISPOSE && !e.o && !(e.S & STATUS_PENDING)) {
|
|
203
266
|
unobserved(e);
|
|
267
|
+
return true;
|
|
204
268
|
}
|
|
269
|
+
return false;
|
|
205
270
|
};
|
|
206
271
|
if (o) {
|
|
207
|
-
let
|
|
272
|
+
let t = false, r = false, o, l = true;
|
|
208
273
|
n.then(e => {
|
|
209
274
|
if (l) {
|
|
210
275
|
u = e;
|
|
211
|
-
|
|
276
|
+
t = true;
|
|
212
277
|
} else {
|
|
213
278
|
asyncWrite(e);
|
|
214
279
|
settleAutodispose();
|
|
@@ -216,87 +281,95 @@ function handleAsync(e, n, r) {
|
|
|
216
281
|
}, e => {
|
|
217
282
|
if (l) {
|
|
218
283
|
o = e;
|
|
219
|
-
|
|
284
|
+
r = true;
|
|
220
285
|
} else {
|
|
221
286
|
handleError(e);
|
|
222
287
|
settleAutodispose();
|
|
223
288
|
}
|
|
224
289
|
});
|
|
225
290
|
l = false;
|
|
226
|
-
if (
|
|
291
|
+
if (r) {
|
|
227
292
|
// Settle through the same status path an async rejection uses, then
|
|
228
293
|
// unwind the in-progress synchronous read so the errored node isn't
|
|
229
294
|
// momentarily read as `undefined`.
|
|
230
295
|
handleError(o);
|
|
231
296
|
throw o;
|
|
232
|
-
} else if (!
|
|
297
|
+
} else if (!t) {
|
|
233
298
|
globalQueue.initTransition(resolveTransition(e));
|
|
234
299
|
throw new NotReadyError(context);
|
|
235
300
|
}
|
|
236
301
|
}
|
|
237
|
-
if (
|
|
238
|
-
const
|
|
239
|
-
let
|
|
302
|
+
if (r) {
|
|
303
|
+
const t = n[Symbol.asyncIterator]();
|
|
304
|
+
let r = false;
|
|
240
305
|
let o = false;
|
|
241
306
|
let l = true;
|
|
242
307
|
cleanup(() => {
|
|
243
308
|
if (o) return;
|
|
244
309
|
o = true;
|
|
245
310
|
try {
|
|
246
|
-
const e =
|
|
311
|
+
const e = t.return?.();
|
|
247
312
|
if (isThenable(e)) e.then(undefined, () => {});
|
|
248
313
|
} catch {}
|
|
249
314
|
});
|
|
315
|
+
// Release check before each next pull: an unobserved lazy node must tear
|
|
316
|
+
// down (its cleanup above closes the iterator) instead of pumping the
|
|
317
|
+
// stream forever with zero subscribers (#2935).
|
|
318
|
+
const iterateOrRelease = () => {
|
|
319
|
+
if (!settleAutodispose()) iterate();
|
|
320
|
+
};
|
|
250
321
|
const iterate = () => {
|
|
251
|
-
let
|
|
252
|
-
|
|
322
|
+
let s, i, f = false, a = false, c = true;
|
|
323
|
+
t.next().then(t => {
|
|
253
324
|
if (c) {
|
|
254
|
-
|
|
325
|
+
s = t;
|
|
255
326
|
f = true;
|
|
256
|
-
if (
|
|
327
|
+
if (t.done) o = true;
|
|
257
328
|
} else if (e.Te !== n) {
|
|
258
329
|
return;
|
|
259
|
-
} else if (!
|
|
260
|
-
|
|
261
|
-
asyncWrite(
|
|
330
|
+
} else if (!t.done) {
|
|
331
|
+
r = true;
|
|
332
|
+
asyncWrite(t.value, iterateOrRelease);
|
|
262
333
|
} else {
|
|
263
334
|
o = true;
|
|
264
|
-
if (
|
|
335
|
+
if (r) {
|
|
265
336
|
schedule();
|
|
266
337
|
flush();
|
|
267
338
|
} else {
|
|
268
339
|
// Empty completion settles like the immediately-done sync path.
|
|
269
340
|
asyncWrite(undefined);
|
|
270
341
|
}
|
|
342
|
+
settleAutodispose();
|
|
271
343
|
}
|
|
272
|
-
},
|
|
344
|
+
}, t => {
|
|
273
345
|
if (c) {
|
|
274
|
-
|
|
346
|
+
i = t;
|
|
275
347
|
a = true;
|
|
276
348
|
} else if (e.Te === n) {
|
|
277
349
|
o = true;
|
|
278
|
-
handleError(
|
|
350
|
+
handleError(t);
|
|
351
|
+
settleAutodispose();
|
|
279
352
|
}
|
|
280
353
|
});
|
|
281
354
|
c = false;
|
|
282
355
|
if (a) {
|
|
283
356
|
// Match the promise branch, but only rethrow during the initial read.
|
|
284
357
|
o = true;
|
|
285
|
-
handleError(
|
|
286
|
-
if (l) throw
|
|
358
|
+
handleError(i);
|
|
359
|
+
if (l) throw i;
|
|
287
360
|
return true;
|
|
288
361
|
}
|
|
289
|
-
if (f && !
|
|
290
|
-
u =
|
|
291
|
-
|
|
362
|
+
if (f && !s.done) {
|
|
363
|
+
u = s.value;
|
|
364
|
+
r = true;
|
|
292
365
|
return iterate();
|
|
293
366
|
}
|
|
294
|
-
return f &&
|
|
367
|
+
return f && s.done;
|
|
295
368
|
};
|
|
296
|
-
const
|
|
369
|
+
const s = iterate();
|
|
297
370
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
298
371
|
l = false;
|
|
299
|
-
if (!
|
|
372
|
+
if (!r && !s) {
|
|
300
373
|
globalQueue.initTransition(resolveTransition(e));
|
|
301
374
|
throw new NotReadyError(context);
|
|
302
375
|
}
|
|
@@ -306,75 +379,75 @@ function handleAsync(e, n, r) {
|
|
|
306
379
|
|
|
307
380
|
function clearStatus(e, n = false) {
|
|
308
381
|
if (e.oe) clearPendingSources(e);
|
|
309
|
-
if (e.
|
|
382
|
+
if (e.de) e.de = false;
|
|
310
383
|
// The pending window is over; its quiet classification dies with it.
|
|
311
384
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
312
385
|
// plain store to an existing slot — no shape change.)
|
|
313
|
-
e.
|
|
386
|
+
e.be = false;
|
|
314
387
|
e.S = n ? 0 : e.S & STATUS_UNINITIALIZED;
|
|
315
388
|
if (e._) setPendingError(e);
|
|
316
389
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
317
390
|
// once the verdict layer created them, which installs the hooks).
|
|
318
|
-
if (e.
|
|
319
|
-
if (e.u && GlobalQueue.
|
|
391
|
+
if (e.he || e.Ge) GlobalQueue.ce(e);
|
|
392
|
+
if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
|
|
320
393
|
if (e.i) e.i();
|
|
321
394
|
}
|
|
322
395
|
|
|
323
|
-
function notifyStatus(e, n,
|
|
396
|
+
function notifyStatus(e, n, t, r, o) {
|
|
324
397
|
// Wrap regular errors to track source node
|
|
325
|
-
if (n === STATUS_ERROR && !(
|
|
326
|
-
const u = n === STATUS_PENDING &&
|
|
398
|
+
if (n === STATUS_ERROR && !(t instanceof StatusError) && !(t instanceof NotReadyError)) t = new StatusError(e, t);
|
|
399
|
+
const u = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
|
|
327
400
|
const l = u === e;
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
if (!
|
|
401
|
+
const s = n === STATUS_PENDING && e.Ae !== undefined && !l;
|
|
402
|
+
const i = s && hasActiveOverride(e);
|
|
403
|
+
if (!r) {
|
|
331
404
|
if (n === STATUS_PENDING && u) {
|
|
332
405
|
addPendingSource(e, u);
|
|
333
406
|
e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
|
|
334
407
|
// Preserve the current source on this propagation so render-effect notification
|
|
335
408
|
// can register every distinct pending source with the transition.
|
|
336
|
-
setPendingError(e, u,
|
|
409
|
+
setPendingError(e, u, t);
|
|
337
410
|
} else {
|
|
338
411
|
clearPendingSources(e);
|
|
339
412
|
e.S = n | (n !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
|
|
340
|
-
e._ =
|
|
413
|
+
e._ = t;
|
|
341
414
|
}
|
|
342
|
-
GlobalQueue.
|
|
343
|
-
if (e.u && GlobalQueue.
|
|
415
|
+
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
416
|
+
if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
|
|
344
417
|
}
|
|
345
|
-
if (o && !
|
|
418
|
+
if (o && !r) {
|
|
346
419
|
assignOrMergeLane(e, o);
|
|
347
420
|
}
|
|
348
|
-
const f =
|
|
349
|
-
const a =
|
|
421
|
+
const f = r || i;
|
|
422
|
+
const a = r || s ? undefined : o;
|
|
350
423
|
if (e.i) {
|
|
351
|
-
if (
|
|
424
|
+
if (r && n === STATUS_PENDING) {
|
|
352
425
|
return;
|
|
353
426
|
}
|
|
354
427
|
if (f) {
|
|
355
|
-
e.i(n,
|
|
428
|
+
e.i(n, t);
|
|
356
429
|
} else {
|
|
357
430
|
e.i();
|
|
358
431
|
}
|
|
359
432
|
return;
|
|
360
433
|
}
|
|
361
|
-
forEachDependent(e, (e,
|
|
362
|
-
e.
|
|
363
|
-
if (n === STATUS_PENDING && u && !e.oe?.has(u) || n !== STATUS_PENDING && (e._ !==
|
|
434
|
+
forEachDependent(e, (e, r) => {
|
|
435
|
+
e.Se = clock;
|
|
436
|
+
if (n === STATUS_PENDING && u && !e.oe?.has(u) || n !== STATUS_PENDING && (e._ !== t || e.oe)) {
|
|
364
437
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
365
438
|
// It exists so the observer re-runs when the source settles, but it must
|
|
366
439
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
367
440
|
// read swallows those, and the async path must match. Re-run the observer
|
|
368
441
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
369
|
-
if (
|
|
442
|
+
if (r.ge && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
|
|
370
443
|
enqueueSub(e);
|
|
371
444
|
schedule();
|
|
372
445
|
return;
|
|
373
446
|
}
|
|
374
|
-
if (!f && !e.
|
|
375
|
-
notifyStatus(e, n,
|
|
447
|
+
if (!f && !e.Ie) queuePendingNode(e);
|
|
448
|
+
notifyStatus(e, n, t, f, a);
|
|
376
449
|
}
|
|
377
450
|
});
|
|
378
451
|
}
|
|
379
452
|
|
|
380
|
-
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, setPendingError, settlePendingSource };
|
|
453
|
+
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, releaseSettledDependents, setPendingError, settlePendingSource };
|