@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
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-shared.js +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CONFIG_VERDICT,
|
|
1
|
+
import { REACTIVE_PROBED, REACTIVE_WINDOW, CONFIG_VERDICT, CONFIG_ASYNC, CONFIG_CHILDREN_FORBIDDEN, CONFIG_OVERRIDE, STATUS_ERROR, CONFIG_GUESS, STATUS_PENDING, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, CONFIG_STAGED_ERROR, REACTIVE_STAGED_READ, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, CONFIG_INPUTS_PUBLISHED, REACTIVE_JOINED, REACTIVE_LANE_READ } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { context, tracking, setVerdict, verdict, pullComputed, joinPass, markLateLinker, spectating, unflushedValue, bornInto } from "./core.js";
|
|
3
|
+
import { context, creatorPass, tracking, creatorReads, setVerdict, verdict, prepareComputed, pullComputed, joinPass, markLateLinker, spectating, unflushedValue, bornInto } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import "./dev.js";
|
|
6
6
|
|
|
@@ -40,7 +40,7 @@ function watchVerdict(e, t = false) {
|
|
|
40
40
|
* node's, or the staging of a write this flush may hold — and the verdict
|
|
41
41
|
* does not rescue it: its result shows at the landing, re-derived). A lane
|
|
42
42
|
* read, for `recompute`'s tail (REACTIVE_LANE_READ). */ function route(e, t) {
|
|
43
|
-
if (passLane
|
|
43
|
+
if (!passLane && !(e.R & (REACTIVE_JOINED | REACTIVE_STAGED_READ))) setPassLane(verdictLane(t));
|
|
44
44
|
e.R |= REACTIVE_LANE_READ;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -67,7 +67,7 @@ function watchVerdict(e, t = false) {
|
|
|
67
67
|
* transaction (`bornInto`, #4010): it has no screen — it waits on the flight
|
|
68
68
|
* with the rest of its frame. */ function observeFlight(e, t) {
|
|
69
69
|
if (t.l & CONFIG_INPUTS_PUBLISHED || t.l & CONFIG_HELD && bornInto(e, txOf(t))) return false;
|
|
70
|
-
if (globalQueue.
|
|
70
|
+
if (globalQueue.Y) {
|
|
71
71
|
joinFuture(null);
|
|
72
72
|
if (!(t.l & CONFIG_HELD)) queuePendingNode(t);
|
|
73
73
|
verdictRead(e, flushTransaction, true);
|
|
@@ -92,9 +92,9 @@ let probeFound = false;
|
|
|
92
92
|
* value notifying anyone (a held write's commit; a held landing's): its
|
|
93
93
|
* reader re-derives there. `latest` shows the proposal that lands — a
|
|
94
94
|
* rewrite or a landing reaches its reader through the link it holds — so a
|
|
95
|
-
* re-run would only repeat the frame. */ function verdictRead(e, t,
|
|
95
|
+
* re-run would only repeat the frame. */ function verdictRead(e, t, r) {
|
|
96
96
|
route(e, t);
|
|
97
|
-
if (
|
|
97
|
+
if (r) staleReader(e, t); else if (probing && t.En[t.En.length - 1] !== e) t.En.push(e);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** A verdict read of a node staged or in flight but not held yet: whether it
|
|
@@ -107,39 +107,40 @@ let probeFound = false;
|
|
|
107
107
|
* watches the seam and runs again if the flush parks (a plain sync write
|
|
108
108
|
* never glitches it true).
|
|
109
109
|
*
|
|
110
|
-
* `latest` has its answer either way — the proposal —
|
|
111
|
-
* membership
|
|
112
|
-
* (
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (flushTransaction !== null) {
|
|
125
|
-
if (t) probeFound = true;
|
|
110
|
+
* `latest` has its answer either way — the proposal — but its reader's
|
|
111
|
+
* membership is the seam's too: the frame opens no transaction for it
|
|
112
|
+
* (#4365 — one opened for the read alone made a plain read after the window
|
|
113
|
+
* take it for a hold, `stagedScreen`, and serve the screen beside the
|
|
114
|
+
* staging in a frame nothing held). The reader watches the seam like a
|
|
115
|
+
* probe before anything joined: its pass is the frame's, and runs again in
|
|
116
|
+
* the verdict lane if the flush parks. Once the flush has joined a
|
|
117
|
+
* transaction, the reader is its verdict lane's at once; a pass that also
|
|
118
|
+
* read the frame's own stagings plainly (REACTIVE_STAGED_READ) stays the
|
|
119
|
+
* frame's (`route` does not move it). */ function provisionalVerdict(e, t) {
|
|
120
|
+
if (flushTransaction) {
|
|
121
|
+
if (probing && t) probeFound = true;
|
|
126
122
|
verdictRead(e, flushTransaction);
|
|
127
|
-
if (e.R & REACTIVE_STAGED_READ) watchVerdict(e);
|
|
123
|
+
if (probing && e.R & REACTIVE_STAGED_READ) watchVerdict(e);
|
|
128
124
|
return;
|
|
129
125
|
}
|
|
130
126
|
// Before anything joined, a staging that would not be final held has no
|
|
131
127
|
// answer yet: whatever the seam decides, the pass runs again — a later
|
|
132
128
|
// plain read of the same pass may route it into the verdict lane
|
|
133
129
|
// (`observeFlight`), which the seam must not take as this probe's answer.
|
|
134
|
-
|
|
130
|
+
// `latest` opens no transaction for its answer either (#4365): the plain
|
|
131
|
+
// read of a staging after it took one opened for it for a hold and paired
|
|
132
|
+
// the staging with the screen, in a frame nothing held. Its pass is the
|
|
133
|
+
// frame's — whole — and re-derives once if the flush parks (unanswered:
|
|
134
|
+
// its membership is the seam's, not the transaction it joins).
|
|
135
|
+
watchVerdict(e, !probing || t);
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
/** A19 exc. 2 / A24: a flight that re-asks the question already answered
|
|
138
139
|
* (a `refresh()`, a poll) is quiet; a node pending through others is quiet
|
|
139
140
|
* when every flight it waits on is. */ function quietPending(e) {
|
|
140
141
|
const t = e.T;
|
|
141
|
-
if (t
|
|
142
|
-
if (t.se
|
|
142
|
+
if (!t) return false;
|
|
143
|
+
if (t.se) {
|
|
143
144
|
for (const e of t.se) if (!e.T?.ut) return false;
|
|
144
145
|
return true;
|
|
145
146
|
}
|
|
@@ -159,16 +160,24 @@ let probeFound = false;
|
|
|
159
160
|
* flight — a staging equal to what is displayed changes nothing when it
|
|
160
161
|
* lands: final now (maintainer, 2026-10-02). */ function heldNotFinal(e) {
|
|
161
162
|
if ((e.m & STATUS_PENDING) !== 0 && !quietPending(e)) return true;
|
|
162
|
-
return e.
|
|
163
|
+
return e.ue !== NOT_PENDING && !latestActive && !e.T.ut && !(e.m & STATUS_UNINITIALIZED) && (!!e.T.Te || !e.je || !e.je(e.le, e.ue));
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
/** `isPending`'s answer for an unheld node whose flight is up (cause ii). */ function pendingVerdict(e, t) {
|
|
166
167
|
if (t.m & STATUS_UNINITIALIZED) return;
|
|
167
168
|
if (probing && !quietPending(t)) probeFound = true;
|
|
168
|
-
if (e
|
|
169
|
-
if (t.l & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.
|
|
169
|
+
if (e && tracking) {
|
|
170
|
+
if (t.l & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.Y) {
|
|
171
|
+
// `latest` of a flight serves the committed value, the frame's and the
|
|
172
|
+
// lane's alike (D-22): nothing is the seam's, so the reader is the
|
|
173
|
+
// verdict lane's now, as a plain read of a flight makes it
|
|
174
|
+
// (`observeFlight`). Its frame pass re-derived in the lane (R5) asked
|
|
175
|
+
// its question again (F-9, #4397). A staging's is the seam's (#4365).
|
|
176
|
+
if (!probing) joinFuture(null);
|
|
177
|
+
provisionalVerdict(e, false);
|
|
170
178
|
// decided above
|
|
171
|
-
|
|
179
|
+
}
|
|
180
|
+
}
|
|
172
181
|
}
|
|
173
182
|
|
|
174
183
|
/** The pass entering a verdict window is a verdict reader (CONFIG_VERDICT):
|
|
@@ -176,11 +185,19 @@ let probeFound = false;
|
|
|
176
185
|
* an untracked window: that is a snapshot, like any untracked read (#3946 —
|
|
177
186
|
* a router's link claim probing inside the computation that creates the
|
|
178
187
|
* anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
|
|
179
|
-
|
|
180
|
-
if (t
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
const t = creatorPass(context);
|
|
189
|
+
if (t && tracking) {
|
|
190
|
+
// A pass run inside passes still running — its creator's, theirs — one
|
|
191
|
+
// of which read the future or a staging (a branch a held or staged
|
|
192
|
+
// condition opened, and whatever that branch creates) has no screen: the
|
|
193
|
+
// branch exists only in that world. It reads that world as any
|
|
194
|
+
// derivation of it does (`bornInto` once held) and stays its pass
|
|
195
|
+
// (`route`); a verdict reader from its next pass. #4341: a memo born in
|
|
196
|
+
// a newly opened <Match> read the screen, where its branch was closed.
|
|
197
|
+
// Not such a pass: a verdict reader now.
|
|
198
|
+
t.l &= ~CONFIG_ASYNC;
|
|
199
|
+
t.R |= REACTIVE_PROBED | REACTIVE_WINDOW | (creatorReads(t, 0) || (t.l |= CONFIG_VERDICT,
|
|
200
|
+
0));
|
|
184
201
|
// Observe tier: which windows this pass entered (1 `isPending`, 2
|
|
185
202
|
// `latest`) — the hold census names the affordance (attribution.ts).
|
|
186
203
|
t.Ve = (t.Ve ?? 0) | e;
|
|
@@ -191,14 +208,14 @@ let probeFound = false;
|
|
|
191
208
|
* restores the dispatch it found — none inside a memo's pass a window
|
|
192
209
|
* pulled (`verdictValue`). */ function latest(e) {
|
|
193
210
|
markVerdictReader(2);
|
|
194
|
-
const t = latestActive,
|
|
211
|
+
const t = latestActive, r = verdict;
|
|
195
212
|
latestActive = true;
|
|
196
213
|
setVerdict(verdictValue);
|
|
197
214
|
try {
|
|
198
215
|
return e();
|
|
199
216
|
} finally {
|
|
200
217
|
latestActive = t;
|
|
201
|
-
setVerdict(
|
|
218
|
+
setVerdict(r);
|
|
202
219
|
}
|
|
203
220
|
}
|
|
204
221
|
|
|
@@ -236,8 +253,8 @@ let probeFound = false;
|
|
|
236
253
|
*/ function isPending(e) {
|
|
237
254
|
markVerdictReader(1);
|
|
238
255
|
const t = probing;
|
|
239
|
-
const
|
|
240
|
-
const
|
|
256
|
+
const r = probeFound;
|
|
257
|
+
const i = verdict;
|
|
241
258
|
probing = true;
|
|
242
259
|
probeFound = false;
|
|
243
260
|
setVerdict(verdictValue);
|
|
@@ -255,23 +272,23 @@ let probeFound = false;
|
|
|
255
272
|
return probeFound;
|
|
256
273
|
} finally {
|
|
257
274
|
probing = t;
|
|
258
|
-
probeFound =
|
|
259
|
-
setVerdict(
|
|
275
|
+
probeFound = r;
|
|
276
|
+
setVerdict(i);
|
|
260
277
|
}
|
|
261
278
|
}
|
|
262
279
|
|
|
263
280
|
/** The staging, or the staged error thrown (D-41). */ function staged(e) {
|
|
264
|
-
if (e.l & CONFIG_STAGED_ERROR) throw e.
|
|
265
|
-
return e.
|
|
281
|
+
if (e.l & CONFIG_STAGED_ERROR) throw e.ue;
|
|
282
|
+
return e.ue;
|
|
266
283
|
}
|
|
267
284
|
|
|
268
285
|
/** `latest()` of a held node: the flushed staging — the proposal — and, for
|
|
269
286
|
* a tracked reader of a rewrite not yet flushed, the late-linker re-run in
|
|
270
287
|
* the flush that carries it. */ function heldLatest(e, t) {
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
273
|
-
if (t
|
|
274
|
-
return
|
|
288
|
+
const r = unflushedValue(e);
|
|
289
|
+
if (r === NOT_PENDING) return staged(e);
|
|
290
|
+
if (t) markLateLinker(t);
|
|
291
|
+
return r;
|
|
275
292
|
}
|
|
276
293
|
|
|
277
294
|
/** The verdict windows' read — `latest(fn)` and `isPending(fn)` — in one
|
|
@@ -284,7 +301,9 @@ let probeFound = false;
|
|
|
284
301
|
* differs (A24, A18 provenance). A derivation: `latest` sees the lane's
|
|
285
302
|
* latest (a landing a blocked lane holds has answered its question — the
|
|
286
303
|
* checkout's shipping text updates independently of the tax in flight),
|
|
287
|
-
* `isPending` the screen; not final while its own flight is up
|
|
304
|
+
* `isPending` the screen; not final while its own flight is up. A
|
|
305
|
+
* derivation's first load in flight (nothing produced yet — an async memo
|
|
306
|
+
* over a verdict memo, F-6) reads as the flight below: loading (D-22);
|
|
288
307
|
* - a held node: the reader breaks out as the holder's verdict lane's and
|
|
289
308
|
* re-derives at the landing; `latest` serves the proposal (`heldLatest`),
|
|
290
309
|
* `isPending` answers `heldNotFinal`;
|
|
@@ -295,63 +314,76 @@ let probeFound = false;
|
|
|
295
314
|
* serves the committed value — below the async nothing newer exists; an
|
|
296
315
|
* uninitialized one throws NotReady: loading, not pending (A19 exc. 1);
|
|
297
316
|
* - an errored derivation throws for every reader (#2897). */ function verdictValue(e, t) {
|
|
298
|
-
const
|
|
299
|
-
const
|
|
300
|
-
const
|
|
301
|
-
|
|
317
|
+
const r = e;
|
|
318
|
+
const i = !!t && !(t.l & CONFIG_CHILDREN_FORBIDDEN);
|
|
319
|
+
const n = i && tracking;
|
|
320
|
+
// A31: the pulled memo's pass is its own, not the probe's — it reads
|
|
321
|
+
// outside the window, and the probe's read below answers for what the pass
|
|
322
|
+
// produced. So is a lazy or dormant memo's wake (an unowned memo with no
|
|
323
|
+
// reader left, #4366): woken inside the window, it read its sources as the
|
|
324
|
+
// probe does, the committed value under a landing. (A signal has no
|
|
325
|
+
// `_flags`: the wake is a no-op for it.)
|
|
326
|
+
setVerdict(null);
|
|
327
|
+
prepareComputed(r);
|
|
328
|
+
if (t && tracking) {
|
|
302
329
|
link(e, t);
|
|
303
|
-
if (
|
|
304
|
-
// A31: the pulled memo's pass is its own, not the probe's — it reads
|
|
305
|
-
// outside the window, and the probe's read below answers for what
|
|
306
|
-
// the pass produced.
|
|
307
|
-
setVerdict(null);
|
|
308
|
-
pullComputed(n, t);
|
|
309
|
-
setVerdict(verdictValue);
|
|
310
|
-
}
|
|
330
|
+
if (e.X) pullComputed(r, t);
|
|
311
331
|
}
|
|
332
|
+
setVerdict(verdictValue);
|
|
312
333
|
// A live `affects()` mark on the node or a dependency (affects.ts): not
|
|
313
334
|
// final by declaration — the value itself is read as below. The verdict is
|
|
314
335
|
// display-ahead like any: in a transaction's flush (the declaring action's
|
|
315
336
|
// body) the reader is its verdict lane's, not a staging the frame parks.
|
|
316
|
-
if (probing && GlobalQueue.p
|
|
337
|
+
if (probing && GlobalQueue.p?.(r)) {
|
|
317
338
|
probeFound = true;
|
|
318
|
-
if (
|
|
339
|
+
if (n && flushTransaction) verdictRead(t, flushTransaction);
|
|
319
340
|
}
|
|
320
|
-
if (e.l & CONFIG_OVERRIDE && !(
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
341
|
+
if (e.l & CONFIG_OVERRIDE && !(r.m & STATUS_ERROR && !(e.l & CONFIG_GUESS))) {
|
|
342
|
+
const i = txOf(e), o = (r.m & STATUS_PENDING) !== 0 && !quietPending(r), a = e.l & CONFIG_GUESS,
|
|
343
|
+
// NOT_PENDING: a node born in the lane with nothing in it yet has no
|
|
344
|
+
// value in either view — loading, not pending, and no verdict to read
|
|
345
|
+
// ahead: it is read as any uninitialized node, NotReady below (A7, A19
|
|
346
|
+
// exc. 1; #4363), its reader not moved into the verdict lane.
|
|
347
|
+
u = a ? 0 : latestActive && !o ? laneValueOf(e) : display(e);
|
|
348
|
+
if (u !== NOT_PENDING) {
|
|
349
|
+
if (n) verdictRead(t, i._parent ?? i);
|
|
350
|
+
if (a) {
|
|
351
|
+
if (probing && (o || e.ue !== NOT_PENDING && (!e.je || !e.je(e.T.V, e.ue)))) probeFound = true;
|
|
352
|
+
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
353
|
+
// world whole — the truth beneath each guess, else what it covered.
|
|
354
|
+
if (latestActive && i.folded) return i.folded(null, e);
|
|
355
|
+
return e.T.V;
|
|
356
|
+
}
|
|
357
|
+
// A first load in flight with nothing produced yet: loading, for
|
|
358
|
+
// `latest` (D-22) as for `isPending` (A19 exc. 1) — unless an error
|
|
359
|
+
// answered it first: its re-ask is pending, the error its display
|
|
360
|
+
// (D-41, #4375).
|
|
361
|
+
if (o && u === e.le && r.m & STATUS_UNINITIALIZED && (latestActive || !r.T.Te)) throw r.T.U;
|
|
362
|
+
if (probing && o) probeFound = true;
|
|
363
|
+
return u;
|
|
330
364
|
}
|
|
331
|
-
if (probing && u) probeFound = true;
|
|
332
|
-
return latestActive && !u ? laneValueOf(e) : display(e);
|
|
333
365
|
}
|
|
334
|
-
const
|
|
366
|
+
const o = (r.m & STATUS_UNINITIALIZED) !== 0;
|
|
335
367
|
if (e.l & CONFIG_HELD) {
|
|
336
|
-
if (!
|
|
337
|
-
const
|
|
368
|
+
if (!o) {
|
|
369
|
+
const i = txOf(e);
|
|
338
370
|
// A render effect re-run (or mounted) outside the verdict lane's flush
|
|
339
371
|
// while the lane is blocked — its display held on its own derivation
|
|
340
372
|
// in flight — is a stale reader of the lane (#3460, as `laneRead`): the
|
|
341
373
|
// committed value now, re-derived at the reveal. Not inside a probe:
|
|
342
374
|
// `isPending` is answered below either way.
|
|
343
|
-
if (
|
|
344
|
-
staleReader(t,
|
|
375
|
+
if (n && !probing && t.i === EFFECT_RENDER && !passLane && i.it?.ln && flushTransaction !== i) {
|
|
376
|
+
staleReader(t, i.it);
|
|
345
377
|
return e.le;
|
|
346
378
|
}
|
|
347
|
-
if (
|
|
348
|
-
if (probing && heldNotFinal(
|
|
349
|
-
if (latestActive && e.
|
|
379
|
+
if (n) verdictRead(t, i);
|
|
380
|
+
if (probing && heldNotFinal(r)) probeFound = true;
|
|
381
|
+
if (latestActive && e.ue !== NOT_PENDING) {
|
|
350
382
|
// An action body reading another transaction's proposal derives
|
|
351
383
|
// from it: the two settle as one (A15; posture C, 2026-09-15). An
|
|
352
384
|
// untracked read elsewhere has no transaction to entangle.
|
|
353
|
-
if (!
|
|
354
|
-
return heldLatest(e,
|
|
385
|
+
if (!n && flushTransaction && !globalQueue.Y) joinFuture(txOf(e));
|
|
386
|
+
return heldLatest(e, n ? t : null);
|
|
355
387
|
}
|
|
356
388
|
return e.le;
|
|
357
389
|
}
|
|
@@ -359,46 +391,76 @@ let probeFound = false;
|
|
|
359
391
|
// committed value, so no verdict: `isPending` reads it as its read does —
|
|
360
392
|
// the owner joins the hold (held with it, or caught by a boundary that
|
|
361
393
|
// has not shown content) and answers for the commit, where it is final.
|
|
362
|
-
if (e.
|
|
363
|
-
if (probing &&
|
|
394
|
+
if (e.ue !== NOT_PENDING && !(r.m & STATUS_PENDING)) {
|
|
395
|
+
if (probing && i) joinPass(t, e);
|
|
364
396
|
return staged(e);
|
|
365
397
|
}
|
|
366
|
-
} else if (e.
|
|
367
|
-
if (
|
|
398
|
+
} else if (e.ue !== NOT_PENDING) {
|
|
399
|
+
if (r.m & STATUS_PENDING && !o) pendingVerdict(n ? t : null, r); else if (n && globalQueue.Y) provisionalVerdict(t, !latestActive && !o);
|
|
368
400
|
// Outside a flush, the staging is an unflushed write (A28): the probe
|
|
369
401
|
// answers for the flushed world, and watches the seam of the flush that
|
|
370
402
|
// carries the write — a memo of `isPending(x)` created after the write
|
|
371
403
|
// flips if that flush parks (#3078). (The write's own fan-out ran before
|
|
372
404
|
// the reader existed; nothing else would re-derive it.)
|
|
373
|
-
else if (
|
|
405
|
+
else if (n && probing) watchVerdict(t);
|
|
374
406
|
if (latestActive) {
|
|
375
407
|
// A28: an unflushed write is not what `latest` serves; a tracked
|
|
376
408
|
// reader derived from the flushed world runs again in the carrying
|
|
377
409
|
// flush.
|
|
378
|
-
if (globalQueue.
|
|
379
|
-
if (t
|
|
410
|
+
if (globalQueue.Y) return staged(e);
|
|
411
|
+
if (t) markLateLinker(t);
|
|
380
412
|
}
|
|
381
413
|
return e.le;
|
|
382
414
|
}
|
|
383
|
-
if (
|
|
384
|
-
if (!
|
|
385
|
-
pendingVerdict(
|
|
415
|
+
if (r.m & STATUS_PENDING) {
|
|
416
|
+
if (!o) {
|
|
417
|
+
pendingVerdict(n ? t : null, r);
|
|
386
418
|
return e.le;
|
|
387
419
|
}
|
|
388
420
|
// As `read()`: an untracked read of a pending node still re-runs its
|
|
389
421
|
// reader when the node settles (a projection's pull reads its firewall
|
|
390
422
|
// untracked, store/store.ts).
|
|
391
|
-
if (t
|
|
392
|
-
throw
|
|
423
|
+
if (t && !tracking && !spectating && e !== t) link(e, t);
|
|
424
|
+
throw r.T?.U;
|
|
393
425
|
}
|
|
394
|
-
if (
|
|
426
|
+
if (e.X && r.m & STATUS_ERROR) throw r.T.U;
|
|
395
427
|
return e.le;
|
|
396
428
|
}
|
|
397
429
|
|
|
430
|
+
/** D-25: a node whose fetch a hold is waiting on is that hold's work, not a
|
|
431
|
+
* verdict reader — a pass that re-runs it reads plainly — and a memo's
|
|
432
|
+
* posture is what it reads: one that reads a verdict reader's value is a
|
|
433
|
+
* verdict reader itself (#4050). An async memo with no verdict window of its
|
|
434
|
+
* own (REACTIVE_WINDOW: it read a verdict memo, it called neither `latest`
|
|
435
|
+
* nor `isPending`) is a verdict reader between its flights, and the hold's
|
|
436
|
+
* work while one is up or its hold re-runs it.
|
|
437
|
+
*
|
|
438
|
+
* At a pass's head (core.ts `recompute`): a pending node's pass — its
|
|
439
|
+
* flight is the transition's own work (#3884) — and a held one's re-run of
|
|
440
|
+
* such a memo read plainly: the write that re-ran it is its hold's, and
|
|
441
|
+
* served the screen it re-asked a question it had answered (A10, #4397).
|
|
442
|
+
* Only a memo that never asked: D-25's "a verdict posture outlives the pass
|
|
443
|
+
* that asked" is a pass that called `latest`/`isPending`, which clears
|
|
444
|
+
* CONFIG_ASYNC and stays a verdict reader whoever dirties it.
|
|
445
|
+
*
|
|
446
|
+
* On `source` going pending (`propagateStatus`): such a memo waits on it
|
|
447
|
+
* like any derivation (F-9) instead of re-deriving — what it read changed
|
|
448
|
+
* no value, so its re-run re-asked the question it was answering. Unless
|
|
449
|
+
* its own flight is up outside a lane on a new question of the source's:
|
|
450
|
+
* its re-run supersedes a flight asked of a value the source has moved past
|
|
451
|
+
* (re-asked by a `refresh()`, the source's question is the same one). */ function holdWork(e, t) {
|
|
452
|
+
// CONFIG_ASYNC records an async memo with no window of its own: its last
|
|
453
|
+
// answering pass registered a flight (`handleAsync`) and called neither
|
|
454
|
+
// `latest` nor `isPending`. A window (`markVerdictReader`), a sync answer or
|
|
455
|
+
// an error clears it; a pass left pending keeps the last answer's.
|
|
456
|
+
const r = e.l & CONFIG_ASYNC;
|
|
457
|
+
return r && (!(e.m & STATUS_PENDING) || e.T.Je?.V || t.R & REACTIVE_REASK);
|
|
458
|
+
}
|
|
459
|
+
|
|
398
460
|
// Installed at module evaluation — present exactly when something imports
|
|
399
461
|
// `latest` or `isPending`. (`read` dispatches to `verdictValue` through
|
|
400
462
|
// `verdict`, set while a window is open.)
|
|
401
|
-
installVerdictHooks(observeFlight);
|
|
463
|
+
installVerdictHooks(observeFlight, holdWork);
|
|
402
464
|
|
|
403
465
|
/** A store read inside an untracked `isPending` probe found a live mark on
|
|
404
466
|
* a record with no node to carry it (store/affects.ts): not final. */ GlobalQueue.bt = () => {
|
package/dist/observe/deferred.js
CHANGED
|
@@ -123,7 +123,7 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
|
|
|
123
123
|
* does not replace (D-40) — restaged as the committed value, the hold's
|
|
124
124
|
* readers would re-derive against the old input. */ const serve = e => {
|
|
125
125
|
const r = handleAsync(t, e);
|
|
126
|
-
return t.l & CONFIG_HELD && t.
|
|
126
|
+
return t.l & CONFIG_HELD && t.ue !== NOT_PENDING ? t.ue : r;
|
|
127
127
|
};
|
|
128
128
|
const end = () => t.R & REACTIVE_DISPOSED && land(o);
|
|
129
129
|
return accessor(computed(r => {
|
package/dist/observe/index.js
CHANGED
|
@@ -26,6 +26,8 @@ import "./core/effect.js";
|
|
|
26
26
|
|
|
27
27
|
export { configureClientErrors } from "./core/error-hooks.js";
|
|
28
28
|
|
|
29
|
+
export { checkForeignOwnerless, runAsSolidCopy } from "./core/copies.js";
|
|
30
|
+
|
|
29
31
|
export { storeName } from "./store/edges.js";
|
|
30
32
|
|
|
31
33
|
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until } from "./signals.js";
|