@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.17
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 +1719 -1603
- package/dist/dev.attribution.js +13 -13
- package/dist/dev.js +182 -45
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +26 -10
- package/dist/observe/core/effect.js +2 -0
- package/dist/observe/core/graph.js +10 -8
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +73 -47
- package/dist/observe/core/scheduler.js +189 -173
- package/dist/observe/core/verdict.js +3 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/store.js +25 -16
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +31 -15
- package/dist/prod/core/effect.js +2 -0
- package/dist/prod/core/graph.js +10 -8
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +25 -14
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +43 -27
- package/dist/prod/core/verdict.js +4 -1
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/store.js +18 -7
- package/dist/types/core/core.d.ts +10 -3
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +23 -4
- package/package.json +1 -1
|
@@ -323,6 +323,9 @@ let probeFound = false;
|
|
|
323
323
|
const u = (n.m & STATUS_PENDING) !== 0 && !quietPending(n);
|
|
324
324
|
if (e.l & CONFIG_GUESS) {
|
|
325
325
|
if (probing && (u || e.ue !== NOT_PENDING && (!e.Ye || !e.Ye(e.T.V, e.ue)))) probeFound = true;
|
|
326
|
+
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
327
|
+
// world whole — the truth beneath each guess, else what it covered.
|
|
328
|
+
if (latestActive && r.folded) return r.folded(null, e);
|
|
326
329
|
return e.T.V;
|
|
327
330
|
}
|
|
328
331
|
if (probing && u) probeFound = true;
|
package/dist/observe/map.js
CHANGED
|
@@ -305,7 +305,7 @@ function updateKeyedMap() {
|
|
|
305
305
|
this.Kt && (this.Kt = []);
|
|
306
306
|
this.xt && (this.xt = []);
|
|
307
307
|
}
|
|
308
|
-
if (this.L && !this.vt
|
|
308
|
+
if (this.L && !this.vt.length) {
|
|
309
309
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
310
310
|
// dispose it before re-creating
|
|
311
311
|
this.je[0]?.dispose();
|
|
@@ -543,7 +543,7 @@ function updateRepeat() {
|
|
|
543
543
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
544
544
|
this.$t = 0;
|
|
545
545
|
}
|
|
546
|
-
if (this.L && !this.vt
|
|
546
|
+
if (this.L && !this.vt.length) {
|
|
547
547
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
548
548
|
// dispose it before re-creating
|
|
549
549
|
this.je[0]?.dispose();
|
package/dist/observe/signals.js
CHANGED
|
@@ -296,7 +296,12 @@ function createMemo(e, t) {
|
|
|
296
296
|
o = undefined;
|
|
297
297
|
}
|
|
298
298
|
runWithOwner(n, () => {
|
|
299
|
-
effect(() =>
|
|
299
|
+
effect(() => {
|
|
300
|
+
const e = getOwner();
|
|
301
|
+
o = e;
|
|
302
|
+
c();
|
|
303
|
+
return e;
|
|
304
|
+
}, t => {
|
|
300
305
|
o = undefined;
|
|
301
306
|
r?.();
|
|
302
307
|
const n = (e.effect || e)?.();
|
|
@@ -38,8 +38,8 @@ const scopes = new Map;
|
|
|
38
38
|
function scopeOf(e, o) {
|
|
39
39
|
let n = scopes.get(e);
|
|
40
40
|
if (n === undefined) scopes.set(e, n = {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
oo: new Set,
|
|
42
|
+
no: [],
|
|
43
43
|
Vt: o
|
|
44
44
|
});
|
|
45
45
|
return n;
|
|
@@ -47,15 +47,15 @@ function scopeOf(e, o) {
|
|
|
47
47
|
|
|
48
48
|
/** The nodes an `affects(store[, key])` declaration marks (affects.ts
|
|
49
49
|
* registers each). */ function storeMarks(e, o) {
|
|
50
|
-
const n = GlobalQueue.
|
|
50
|
+
const n = GlobalQueue.so(e, o === undefined ? $AFFECTS : o);
|
|
51
51
|
const t = scopeOf(n, o);
|
|
52
52
|
if (o === undefined) {
|
|
53
53
|
const o = [ n ];
|
|
54
54
|
walk(e.px, t, o, e.fam, new Set);
|
|
55
55
|
return o;
|
|
56
56
|
}
|
|
57
|
-
t.
|
|
58
|
-
if (e.pb !== null) t.
|
|
57
|
+
t.oo.add(e.v);
|
|
58
|
+
if (e.pb !== null) t.oo.add(e.pb);
|
|
59
59
|
return [ n ];
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -63,14 +63,14 @@ function scopeOf(e, o) {
|
|
|
63
63
|
* the committed backing both, when a draft is open; an optimistic family's
|
|
64
64
|
* view), every live node under each record into `found`. Untracked by
|
|
65
65
|
* construction: raws, never traps. */ function walk(e, o, n, t, s) {
|
|
66
|
-
if (!GlobalQueue.
|
|
66
|
+
if (!GlobalQueue.fo(e)) return;
|
|
67
67
|
const f = e[$TARGET] ?? lookupTarget(e, t);
|
|
68
68
|
let r = f !== undefined ? f.pb ?? f.v : e;
|
|
69
69
|
if (s.has(r)) return;
|
|
70
70
|
s.add(r);
|
|
71
|
-
o.
|
|
71
|
+
o.oo.add(r);
|
|
72
72
|
if (f !== undefined) {
|
|
73
|
-
if (f.pb !== null) o.
|
|
73
|
+
if (f.pb !== null) o.oo.add(f.v);
|
|
74
74
|
// The writer's view: the tick's own unflushed guesses are in motion too.
|
|
75
75
|
if (f.fam?.opt === true) r = optHooks.view(f, r, true);
|
|
76
76
|
const e = f.n;
|
|
@@ -96,7 +96,7 @@ function scopeOf(e, o) {
|
|
|
96
96
|
for (const [t, s] of scopes) {
|
|
97
97
|
if (t === n || s.Vt !== undefined && s.Vt !== o) continue;
|
|
98
98
|
for (let o = e.v; ;) {
|
|
99
|
-
if (s.
|
|
99
|
+
if (s.oo.has(o)) return t;
|
|
100
100
|
const e = o?.[$TARGET];
|
|
101
101
|
if (e === undefined) break;
|
|
102
102
|
const n = e.pb ?? e.v;
|
|
@@ -112,17 +112,17 @@ function scopeOf(e, o) {
|
|
|
112
112
|
* no work. */ const hooks = {
|
|
113
113
|
// A node born on a record a live mark covers inherits it (released with
|
|
114
114
|
// the carrier's last registration).
|
|
115
|
-
|
|
115
|
+
ro(e, o, n) {
|
|
116
116
|
if (scopes.size === 0 || n === $AFFECTS) return;
|
|
117
117
|
const t = covering(e, n, o);
|
|
118
118
|
if (!t) return;
|
|
119
119
|
GlobalQueue.N(o);
|
|
120
|
-
scopes.get(t).
|
|
120
|
+
scopes.get(t).no.push(o);
|
|
121
121
|
},
|
|
122
122
|
// An untracked probe (`isPending(() => s.x)` with no observer) reading a
|
|
123
123
|
// record a live mark covers: no node carries the mark for it — the
|
|
124
124
|
// verdict is told directly.
|
|
125
|
-
|
|
125
|
+
io(e, o) {
|
|
126
126
|
if (e.n?.[$AFFECTS]?.T?.I || covering(e, o)) GlobalQueue.bt();
|
|
127
127
|
}
|
|
128
128
|
};
|
|
@@ -136,7 +136,7 @@ function scopeOf(e, o) {
|
|
|
136
136
|
const o = scopes.get(e);
|
|
137
137
|
if (o === undefined) return;
|
|
138
138
|
scopes.delete(e);
|
|
139
|
-
releaseMarksHook(o.
|
|
139
|
+
releaseMarksHook(o.no);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
export { installStoreAffects, releaseMarkScope, storeMarks };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { CONFIG_OVERRIDE,
|
|
1
|
+
import { CONFIG_OVERRIDE, CONFIG_GUESS, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { computed, ext, untrack, read, isEqual } from "../core/core.js";
|
|
3
|
+
import { computed, joinPassAt, ext, untrack, read, isEqual } from "../core/core.js";
|
|
4
4
|
|
|
5
5
|
import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
|
|
6
6
|
|
|
7
7
|
import { getOwner } from "../core/owner.js";
|
|
8
8
|
|
|
9
|
-
import { GlobalQueue, txOf,
|
|
9
|
+
import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
|
|
10
10
|
|
|
11
11
|
import { runProjectionComputed } from "./projection.js";
|
|
12
12
|
|
|
@@ -93,16 +93,16 @@ function notifyOptimisticWrites(e, n) {
|
|
|
93
93
|
// A chained draft holds the inner store's raws; a raw is the inner slot it
|
|
94
94
|
// resolves to (as a read of it serves) — the row a held write staged is
|
|
95
95
|
// the same row, not a guess over the slot (#3796).
|
|
96
|
-
const
|
|
97
|
-
const f = unwrapValue(o &&
|
|
96
|
+
const u = n[t];
|
|
97
|
+
const f = unwrapValue(o && u ? resolveChainedRaw(e, t, u) : u);
|
|
98
98
|
if (!(t in i)) {
|
|
99
99
|
guess(getNode(e, t), t, false, f);
|
|
100
100
|
guess(getHasNode(e, t), t, true, true);
|
|
101
101
|
s = true;
|
|
102
102
|
} else {
|
|
103
103
|
const n = i[t];
|
|
104
|
-
const
|
|
105
|
-
if (!isEqual(
|
|
104
|
+
const u = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
|
|
105
|
+
if (!isEqual(u, f) && !targetsEqual(u, f)) {
|
|
106
106
|
guess(getNode(e, t), t, false, f);
|
|
107
107
|
if (r) s = true;
|
|
108
108
|
}
|
|
@@ -122,29 +122,31 @@ function notifyOptimisticWrites(e, n) {
|
|
|
122
122
|
if (s) {
|
|
123
123
|
const o = r ? n.map(unwrapValue) : shallowKeys(n);
|
|
124
124
|
// The rows the setter removed from the view it saw, by key: a later
|
|
125
|
-
// re-base over another action's truth must not bring them back.
|
|
125
|
+
// re-base over another action's truth must not bring them back. A set
|
|
126
|
+
// (empty or not) marks a keyed arrangement guess (`fold`).
|
|
126
127
|
let s = null;
|
|
127
|
-
const
|
|
128
|
-
if (r &&
|
|
128
|
+
const u = e.fam.key;
|
|
129
|
+
if (r && u !== null && u !== undefined) {
|
|
130
|
+
s = new Set;
|
|
129
131
|
const e = new Set;
|
|
130
132
|
for (let n = 0; n < o.length; n++) {
|
|
131
|
-
const t = isWrappable(o[n]) ?
|
|
133
|
+
const t = isWrappable(o[n]) ? u(o[n]) : undefined;
|
|
132
134
|
if (t !== undefined) e.add(t);
|
|
133
135
|
}
|
|
134
136
|
for (let n = 0; n < i.length; n++) {
|
|
135
137
|
const t = unwrapValue(i[n]);
|
|
136
|
-
const r = isWrappable(t) ?
|
|
137
|
-
if (r !== undefined && !e.has(r))
|
|
138
|
+
const r = isWrappable(t) ? u(t) : undefined;
|
|
139
|
+
if (r !== undefined && !e.has(r)) s.add(r);
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
optimisticWrite(getContainerNode(e), new LaneView(o, t, s));
|
|
141
143
|
}
|
|
142
144
|
if (e.dk !== null) optimisticWrite(e.dk, {});
|
|
143
145
|
markOverlaid(e);
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
+
const u = optStaged.get(e);
|
|
147
|
+
if (u === undefined) return null;
|
|
146
148
|
optStaged.delete(e);
|
|
147
|
-
return
|
|
149
|
+
return u;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
/** The container comparator's lane arm (store.ts `containerEquals`): an
|
|
@@ -228,18 +230,18 @@ function arrangementEqual(e, n, t) {
|
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
for (let s = 0; s < n.length; s++) {
|
|
231
|
-
const
|
|
233
|
+
const u = n[s];
|
|
232
234
|
let f;
|
|
233
|
-
if (isWrappable(
|
|
235
|
+
if (isWrappable(u)) {
|
|
234
236
|
if (o !== null) {
|
|
235
|
-
const e = t(
|
|
237
|
+
const e = t(u);
|
|
236
238
|
if (e !== undefined) f = o.get(e);
|
|
237
239
|
} else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
|
|
238
240
|
}
|
|
239
241
|
if (f !== undefined) {
|
|
240
|
-
if (unwrapValue(f) !==
|
|
242
|
+
if (unwrapValue(f) !== u) reconcileDraft(f, u, t);
|
|
241
243
|
if (e[s] !== f) e[s] = f;
|
|
242
|
-
} else if (unwrapValue(e[s]) !==
|
|
244
|
+
} else if (unwrapValue(e[s]) !== u) e[s] = u;
|
|
243
245
|
}
|
|
244
246
|
if (e.length !== n.length) e.length = n.length;
|
|
245
247
|
return;
|
|
@@ -268,66 +270,105 @@ function arrangementEqual(e, n, t) {
|
|
|
268
270
|
* node is born for it as the lane's derivation), on `length` only when the
|
|
269
271
|
* committed length differs, and as the `LaneView`'s base for structural
|
|
270
272
|
* reads. Unkeyed families compose
|
|
271
|
-
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n) => {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (!
|
|
277
|
-
|
|
273
|
+
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n, t) => {
|
|
274
|
+
if (!t) return fold(e, n);
|
|
275
|
+
const i = e.O;
|
|
276
|
+
if (i === undefined || e.Vt !== $TRACK) return;
|
|
277
|
+
const r = e.T.V;
|
|
278
|
+
if (!(r instanceof LaneView)) return;
|
|
279
|
+
if (!Array.isArray(n) || !Array.isArray(r.rows)) {
|
|
280
|
+
r.base = n;
|
|
278
281
|
return;
|
|
279
282
|
}
|
|
280
|
-
const
|
|
281
|
-
if (
|
|
282
|
-
const
|
|
283
|
+
const o = i.fam?.key ?? null;
|
|
284
|
+
if (o === null) return;
|
|
285
|
+
const s = new Map;
|
|
283
286
|
for (let e = 0; e < n.length; e++) {
|
|
284
287
|
const t = n[e];
|
|
285
|
-
const i = isWrappable(t) ?
|
|
286
|
-
if (i !== undefined && !
|
|
288
|
+
const i = isWrappable(t) ? o(t) : undefined;
|
|
289
|
+
if (i !== undefined && !s.has(i)) s.set(i, t);
|
|
287
290
|
}
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
for (let e = 0; e <
|
|
292
|
-
const n =
|
|
293
|
-
const t = isWrappable(n) ?
|
|
294
|
-
const i = t !== undefined ?
|
|
291
|
+
const u = new Set;
|
|
292
|
+
const f = [];
|
|
293
|
+
const a = r.rows;
|
|
294
|
+
for (let e = 0; e < a.length; e++) {
|
|
295
|
+
const n = a[e];
|
|
296
|
+
const t = isWrappable(n) ? o(n) : undefined;
|
|
297
|
+
const i = t !== undefined ? s.get(t) : undefined;
|
|
295
298
|
if (i !== undefined) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
} else
|
|
299
|
+
f.push(i);
|
|
300
|
+
u.add(t);
|
|
301
|
+
} else f.push(n);
|
|
299
302
|
}
|
|
300
|
-
const
|
|
303
|
+
const l = r.removed;
|
|
301
304
|
for (let e = 0; e < n.length; e++) {
|
|
302
305
|
const t = n[e];
|
|
303
|
-
const i = isWrappable(t) ?
|
|
304
|
-
if (i !== undefined && !
|
|
306
|
+
const i = isWrappable(t) ? o(t) : undefined;
|
|
307
|
+
if (i !== undefined && !u.has(i) && (l === null || !l.has(i))) f.push(t);
|
|
305
308
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
for (let e = 0; e <
|
|
312
|
-
const n =
|
|
309
|
+
r.rows = f;
|
|
310
|
+
r.base = f;
|
|
311
|
+
const c = txOf(e);
|
|
312
|
+
const d = committed(i);
|
|
313
|
+
const p = i.n;
|
|
314
|
+
for (let e = 0; e < f.length; e++) {
|
|
315
|
+
const n = p?.[e];
|
|
313
316
|
// A slot the lane does not own shows the committed row: it becomes the
|
|
314
317
|
// lane's only where the composed row is another row (by key — the same
|
|
315
318
|
// key's new object is the same row, its target adopted it).
|
|
316
319
|
if (n === undefined) {
|
|
317
|
-
if (!sameRow(
|
|
318
|
-
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.V :
|
|
320
|
+
if (!sameRow(d[e], f[e], o)) laneSet(getNode(i, e), f[e], c);
|
|
321
|
+
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.V : d[e], f[e], o)) laneSet(n, f[e], c);
|
|
319
322
|
}
|
|
320
|
-
if (
|
|
321
|
-
for (let e =
|
|
322
|
-
const n =
|
|
323
|
+
if (p !== null) {
|
|
324
|
+
for (let e = f.length; ;e++) {
|
|
325
|
+
const n = p[e];
|
|
323
326
|
if (n === undefined) break;
|
|
324
|
-
laneSet(n, undefined,
|
|
327
|
+
laneSet(n, undefined, c);
|
|
325
328
|
}
|
|
326
|
-
const e =
|
|
327
|
-
if (e !== undefined && (e.l & CONFIG_OVERRIDE ||
|
|
329
|
+
const e = p.length;
|
|
330
|
+
if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== f.length)) laneSet(e, f.length, c);
|
|
328
331
|
}
|
|
329
332
|
};
|
|
330
333
|
|
|
334
|
+
/** D-34 for a keyed arrangement guess: rows by key, not positions. A
|
|
335
|
+
* current truth that differs folds into the hold beneath it instead of
|
|
336
|
+
* voiding the lane: the guess stays the lane's value and the screen's until
|
|
337
|
+
* the hold commits, where rows match by key, and the graph outside the lane
|
|
338
|
+
* re-derives from the truth now (`foldedRead`). A confirmation is silent
|
|
339
|
+
* (A17): only truth readers are told. True: the lane stages the truth
|
|
340
|
+
* beneath (`laneWrite`). */ function fold(e, n) {
|
|
341
|
+
const t = e.O?.k;
|
|
342
|
+
const i = txOf(e);
|
|
343
|
+
// A guess the screen never showed is void at the correction (D-34); a
|
|
344
|
+
// keyed arrangement guess's view carries its removed-keys set.
|
|
345
|
+
if (!i.It || !(t?.l & CONFIG_OVERRIDE) || !t.T.V?.removed) return false;
|
|
346
|
+
const r = e.T.V;
|
|
347
|
+
if ((!e.Ye || !e.Ye(r, n)) && !GlobalQueue.sn(r, n)) {
|
|
348
|
+
i.folded = foldedRead;
|
|
349
|
+
insertSubs(e);
|
|
350
|
+
} else GlobalQueue.tn?.(i);
|
|
351
|
+
joinFuture(resolveTx(i._parent ?? i));
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** A folded lane's guess read by a deriving pass outside the lane, tracked
|
|
356
|
+
* or not (`untrack` is about dependencies, not about which world a pass
|
|
357
|
+
* derives from), or by `latest()` (`c` null): the hold's world — the truth
|
|
358
|
+
* staged beneath the guess, else the value it covered — and the pass joins
|
|
359
|
+
* the hold. Lane passes and the screen keep the guess: held truth is masked
|
|
360
|
+
* from lane passes only (#3164). The store's own derive reconciles its
|
|
361
|
+
* landings against the arrangement the guesses made: it is the author, not
|
|
362
|
+
* a reader. */ function foldedRead(e, n) {
|
|
363
|
+
if (e !== null) {
|
|
364
|
+
if (!(n.l & CONFIG_GUESS) || passLane !== null || e.i === EFFECT_RENDER || e.l & CONFIG_CHILDREN_FORBIDDEN || n.O?.fam?.node === e) return NOT_PENDING;
|
|
365
|
+
const t = txOf(n);
|
|
366
|
+
joinPassAt(e, resolveTx(t._parent ?? t));
|
|
367
|
+
}
|
|
368
|
+
if (n.ue !== NOT_PENDING) return n.ue;
|
|
369
|
+
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.Ie;
|
|
370
|
+
}
|
|
371
|
+
|
|
331
372
|
function sameRow(e, n, t) {
|
|
332
373
|
if (e === n) return true;
|
|
333
374
|
if (!isWrappable(e) || !isWrappable(n)) return false;
|
|
@@ -521,11 +562,11 @@ i = false) {
|
|
|
521
562
|
if (s !== null) {
|
|
522
563
|
for (const e of Reflect.ownKeys(s)) {
|
|
523
564
|
const o = s[e];
|
|
524
|
-
let
|
|
525
|
-
if (o.l & CONFIG_OVERRIDE)
|
|
526
|
-
const f = !!
|
|
527
|
-
const
|
|
528
|
-
if (!f && e in
|
|
565
|
+
let u;
|
|
566
|
+
if (o.l & CONFIG_OVERRIDE) u = t(o); else if (!i || (u = pendingGuessOf(o)) === NOT_PENDING) continue;
|
|
567
|
+
const f = !!u;
|
|
568
|
+
const a = r ?? n;
|
|
569
|
+
if (!f && e in a) delete ensure()[e];
|
|
529
570
|
}
|
|
530
571
|
}
|
|
531
572
|
return r ?? n;
|
|
@@ -538,7 +579,7 @@ function createOptimisticStore(e, n, t) {
|
|
|
538
579
|
// createProjectionInternal).
|
|
539
580
|
const o = i ? n || {} : e;
|
|
540
581
|
const s = r?.key === undefined ? "id" : r.key;
|
|
541
|
-
const
|
|
582
|
+
const u = {
|
|
542
583
|
map: new WeakMap,
|
|
543
584
|
node: null,
|
|
544
585
|
live: new Set,
|
|
@@ -546,9 +587,9 @@ function createOptimisticStore(e, n, t) {
|
|
|
546
587
|
opt: true,
|
|
547
588
|
key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
|
|
548
589
|
};
|
|
549
|
-
const f = wrap(o, null, null,
|
|
590
|
+
const f = wrap(o, null, null, u);
|
|
550
591
|
nameStore(f, r?.name, r?.loc);
|
|
551
|
-
if (
|
|
592
|
+
if (u.shallow) {
|
|
552
593
|
f[$TARGET].s = true;
|
|
553
594
|
markRawIngest(o);
|
|
554
595
|
}
|
|
@@ -564,11 +605,11 @@ function createOptimisticStore(e, n, t) {
|
|
|
564
605
|
loc: r.loc
|
|
565
606
|
};
|
|
566
607
|
const i = computed(() => {
|
|
567
|
-
if (!
|
|
608
|
+
if (!u.node) u.node = getOwner();
|
|
568
609
|
runProjectionComputed(f, n, s);
|
|
569
610
|
}, t);
|
|
570
611
|
i.l &= ~CONFIG_AUTO_DISPOSE;
|
|
571
|
-
|
|
612
|
+
u.node = i;
|
|
572
613
|
}
|
|
573
614
|
return [ f, e => storeSetter(f, e) ];
|
|
574
615
|
}
|
|
@@ -14,7 +14,7 @@ import { getOwner, getObserver } from "../core/owner.js";
|
|
|
14
14
|
|
|
15
15
|
import { insertIntoHeap } from "../core/heap.js";
|
|
16
16
|
|
|
17
|
-
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
17
|
+
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, resolveTx, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
18
18
|
|
|
19
19
|
import { lookupTarget, storeOwners, setLookup, $OWNER, isOwned, markDescendants, devAssertNeverUserMutation } from "./target.js";
|
|
20
20
|
|
|
@@ -240,7 +240,7 @@ function releaseSlot(e) {
|
|
|
240
240
|
/** A node was born on `target`: a family target enters the live index. */ function noteNode(e, n, t) {
|
|
241
241
|
if (e.fam !== null) e.fam.live.add(e);
|
|
242
242
|
markDescendants(e);
|
|
243
|
-
if (affectsHooks !== null) affectsHooks.
|
|
243
|
+
if (affectsHooks !== null) affectsHooks.ro(e, n, t);
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
// Shared slot-node release handler: registered once; the core sweep
|
|
@@ -270,8 +270,13 @@ setSlotUnobserved(e => {
|
|
|
270
270
|
// a node-less staging holds nothing (`stageOn`)
|
|
271
271
|
// Held by the container's transaction only for a key the HELD staging
|
|
272
272
|
// changed — a mainline layer's change above it stages mainline. (A
|
|
273
|
-
// container carrying a guess is a lane's: the flush's park decides
|
|
274
|
-
|
|
273
|
+
// container carrying a guess is a lane's: the flush's park decides —
|
|
274
|
+
// unless a correction folded under the guess, D-34: the key is that
|
|
275
|
+
// correction's hold's.)
|
|
276
|
+
if (o.l & CONFIG_HELD && heldKeyChanged(e, r)) {
|
|
277
|
+
const e = txOf(o);
|
|
278
|
+
if (!(o.l & CONFIG_OVERRIDE) || e.folded) holdNode(n, resolveTx(e._parent ?? e));
|
|
279
|
+
}
|
|
275
280
|
// A28 (4): a batch written inside a creation-time pass is promoted — its
|
|
276
281
|
// late-materialized leaf with it.
|
|
277
282
|
if (o.l & CONFIG_PROMOTED) notePromotedWrite(n);
|
|
@@ -787,9 +792,9 @@ installStoreHooks(storePark, () => {
|
|
|
787
792
|
});
|
|
788
793
|
|
|
789
794
|
/** The store half of `affects()` (store/affects.ts) makes its marks' nodes
|
|
790
|
-
* and walks records through these: it never imports the engine. */ GlobalQueue.
|
|
795
|
+
* and walks records through these: it never imports the engine. */ GlobalQueue.so = getNode;
|
|
791
796
|
|
|
792
|
-
GlobalQueue.
|
|
797
|
+
GlobalQueue.fo = isWrappable;
|
|
793
798
|
|
|
794
799
|
/** A projection's creation run commits directly (a memo's first value is
|
|
795
800
|
* its `_value`, not a staging): the draft still writes a clone of the seed,
|
|
@@ -1578,7 +1583,7 @@ const traps = {
|
|
|
1578
1583
|
}
|
|
1579
1584
|
// (The witness before the pull: a mark on an uninitialized derived
|
|
1580
1585
|
// store is witnessed, then the pull throws — loading, declared pending.)
|
|
1581
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1586
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.io(e, n);
|
|
1582
1587
|
if (e.fam !== null) pullFamily(e);
|
|
1583
1588
|
// Hot inline case: existing PLAIN node (non-accessor) read outside any
|
|
1584
1589
|
// draft — the dbmon/uibench effect re-read shape. Core's `read()` serves
|
|
@@ -1675,7 +1680,7 @@ const traps = {
|
|
|
1675
1680
|
if (n === $OWNER || n === $RECORD) return false;
|
|
1676
1681
|
// (The witness before the pull: a mark on an uninitialized derived
|
|
1677
1682
|
// store is witnessed, then the pull throws — loading, declared pending.)
|
|
1678
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1683
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.io(e, n);
|
|
1679
1684
|
if (e.fam !== null) pullFamily(e);
|
|
1680
1685
|
const t = readSource(e, n);
|
|
1681
1686
|
// A tracked reader's presence node answers (born from the two frames;
|
|
@@ -1700,14 +1705,14 @@ const traps = {
|
|
|
1700
1705
|
return n in t && !(e.del !== null && t === e.pb && e.del.has(n));
|
|
1701
1706
|
},
|
|
1702
1707
|
ownKeys(e) {
|
|
1703
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1708
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.io(e, undefined);
|
|
1704
1709
|
if (e.fam !== null) pullFamily(e);
|
|
1705
1710
|
return visibleKeys(e, enumerationSource(e));
|
|
1706
1711
|
},
|
|
1707
1712
|
getOwnPropertyDescriptor(e, n) {
|
|
1708
1713
|
if (n === $OWNER || n === $RECORD) return undefined;
|
|
1709
1714
|
const t = getObserver();
|
|
1710
|
-
if (verdict !== null && affectsHooks !== null && t === null) affectsHooks.
|
|
1715
|
+
if (verdict !== null && affectsHooks !== null && t === null) affectsHooks.io(e, n);
|
|
1711
1716
|
if (e.fam !== null) pullFamily(e);
|
|
1712
1717
|
// An enumerator (spread, Object.entries) already holds the container
|
|
1713
1718
|
// node and reads its frame; a descriptor read on its own tracks
|
|
@@ -1741,7 +1746,9 @@ const traps = {
|
|
|
1741
1746
|
set(e, n, t) {
|
|
1742
1747
|
const r = inDraft(e);
|
|
1743
1748
|
const o = !r && writeOverride;
|
|
1744
|
-
if (!r && !o)
|
|
1749
|
+
if (!r && !o) {
|
|
1750
|
+
return true;
|
|
1751
|
+
}
|
|
1745
1752
|
if (n === "__proto__") return true;
|
|
1746
1753
|
// pollution guard (core R30)
|
|
1747
1754
|
const i = e.s ? t : unwrapValue(t);
|
|
@@ -1790,7 +1797,9 @@ const traps = {
|
|
|
1790
1797
|
defineProperty(e, n, t) {
|
|
1791
1798
|
const r = inDraft(e);
|
|
1792
1799
|
const o = !r && writeOverride;
|
|
1793
|
-
if (!r && !o)
|
|
1800
|
+
if (!r && !o) {
|
|
1801
|
+
return true;
|
|
1802
|
+
}
|
|
1794
1803
|
if (n === "__proto__") return true;
|
|
1795
1804
|
if (t.get || t.set) e.a = true;
|
|
1796
1805
|
if ("value" in t) t = {
|
|
@@ -1808,7 +1817,9 @@ const traps = {
|
|
|
1808
1817
|
deleteProperty(e, n) {
|
|
1809
1818
|
const t = inDraft(e);
|
|
1810
1819
|
const r = !t && writeOverride;
|
|
1811
|
-
if (!t && !r)
|
|
1820
|
+
if (!t && !r) {
|
|
1821
|
+
return true;
|
|
1822
|
+
}
|
|
1812
1823
|
const o = ensurePB(e);
|
|
1813
1824
|
touch(e, n);
|
|
1814
1825
|
// The key count (`kc`, the overlay gate and the rebuild cap) follows a
|
|
@@ -1903,9 +1914,7 @@ function createStore(e, n) {
|
|
|
1903
1914
|
}
|
|
1904
1915
|
{
|
|
1905
1916
|
const e = getOwner();
|
|
1906
|
-
|
|
1907
|
-
// `_owner` write itself never reaches the proxy, see storeOwners.
|
|
1908
|
-
registerGraph(r, e);
|
|
1917
|
+
registerGraph(r, e);
|
|
1909
1918
|
// Only once the engine is installed, like the node stamping it feeds: a
|
|
1910
1919
|
// WeakMap.set per fresh store is a growing ephemeron table and,
|
|
1911
1920
|
// disabled, buys nothing.
|
package/dist/prod/boundaries.js
CHANGED
|
@@ -12,7 +12,7 @@ import { enqueueSub } from "./core/heap.js";
|
|
|
12
12
|
|
|
13
13
|
import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
|
|
14
14
|
|
|
15
|
-
import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, txOf, unhold, laneStageHook, schedule, installBoundaryHooks } from "./core/scheduler.js";
|
|
15
|
+
import { globalQueue, haltReactivityAt, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, txOf, unhold, laneStageHook, schedule, installBoundaryHooks } from "./core/scheduler.js";
|
|
16
16
|
|
|
17
17
|
import { flatten } from "./flatten.js";
|
|
18
18
|
|
|
@@ -349,7 +349,7 @@ function createBoundary(e, n, r, t) {
|
|
|
349
349
|
} catch (e) {
|
|
350
350
|
if (!(e instanceof NotReadyError)) {
|
|
351
351
|
if (!globalQueue.notify(getOwner(), STATUS_ERROR, STATUS_ERROR, e)) {
|
|
352
|
-
haltReactivity(e);
|
|
352
|
+
if (false) ; else haltReactivity(e);
|
|
353
353
|
throw e;
|
|
354
354
|
}
|
|
355
355
|
return;
|
package/dist/prod/core/async.js
CHANGED
|
@@ -144,7 +144,9 @@ function releaseSettledDependents(e) {
|
|
|
144
144
|
// Staged whether or not the flush has joined a hold yet: a pass that runs
|
|
145
145
|
// before its async sibling joins is the seam's to decide, like a value
|
|
146
146
|
// (#4109). A flush that parks nothing publishes it at its commit (S-38).
|
|
147
|
-
|
|
147
|
+
// Not a projection's derive: its readers learn its error through the
|
|
148
|
+
// family, which the commit's publish never reaches (#4189).
|
|
149
|
+
if (!(e.l & CONFIG_HELD || n && e.R & REACTIVE_STAGED_READ && globalQueue.q && !e.fam) || passLane) return false;
|
|
148
150
|
// The node answered (an error ends the wait — no longer pending, nor
|
|
149
151
|
// blocked); a shown error stays its display until the commit.
|
|
150
152
|
clearPendingSources(e);
|
|
@@ -33,6 +33,8 @@ import { getOwner } from "./owner.js";
|
|
|
33
33
|
let r = t.A[e.id];
|
|
34
34
|
if (r === undefined) r = e.defaultValue;
|
|
35
35
|
if (r === undefined) {
|
|
36
|
+
// Dev names the context and why it has no value: no provider, or a
|
|
37
|
+
// provider that passed `undefined` (the key is set, to `undefined`).
|
|
36
38
|
throw new ContextNotFoundError;
|
|
37
39
|
}
|
|
38
40
|
return r;
|