@solidjs/signals 2.0.0-beta.23 → 2.0.0-beta.24
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 +171 -65
- package/dist/node.cjs +1116 -995
- package/dist/prod/core/core.js +14 -11
- package/dist/prod/core/error.js +9 -0
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/scheduler.js +6 -6
- package/dist/prod/core/verdict.js +1 -1
- package/dist/prod/map.js +53 -29
- package/dist/prod/store/optimistic.js +29 -27
- package/dist/prod/store/reconcile.js +92 -61
- package/dist/prod/store/store.js +142 -102
- package/dist/prod/store/utils.js +12 -0
- package/dist/types/core/error.d.ts +1 -1
- package/dist/types/store/reconcile.d.ts +17 -8
- package/dist/types-cjs/core/error.d.cts +1 -1
- package/dist/types-cjs/store/reconcile.d.cts +17 -8
- package/package.json +1 -1
package/dist/prod/core/core.js
CHANGED
|
@@ -82,7 +82,7 @@ function releaseSubtree(e) {
|
|
|
82
82
|
if (e.se & REACTIVE_SNAPSHOT_STALE) {
|
|
83
83
|
e.se &= ~REACTIVE_SNAPSHOT_STALE;
|
|
84
84
|
e.se |= REACTIVE_DIRTY;
|
|
85
|
-
if (dirtyQueue.
|
|
85
|
+
if (dirtyQueue.He > e.Fe) dirtyQueue.He = e.Fe;
|
|
86
86
|
insertIntoHeap(e, dirtyQueue);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -95,7 +95,10 @@ function clearSnapshots() {
|
|
|
95
95
|
if (snapshotSources) {
|
|
96
96
|
for (const e of snapshotSources) {
|
|
97
97
|
delete e.Ve;
|
|
98
|
-
|
|
98
|
+
// StoreNode targets share one pre-initialized hidden class (see
|
|
99
|
+
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
100
|
+
// when present so signal-node sources don't grow the field.
|
|
101
|
+
if (e[STORE_SNAPSHOT_PROPS] !== undefined) e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
99
102
|
}
|
|
100
103
|
snapshotSources = null;
|
|
101
104
|
}
|
|
@@ -131,7 +134,7 @@ function recompute(e, t = false) {
|
|
|
131
134
|
e.se = REACTIVE_RECOMPUTING_DEPS;
|
|
132
135
|
e.ce = clock;
|
|
133
136
|
let a = e.Ne === NOT_PENDING ? e.Pe : e.Ne;
|
|
134
|
-
let r = e.
|
|
137
|
+
let r = e.Fe;
|
|
135
138
|
let c = tracking;
|
|
136
139
|
let _ = currentOptimisticLane;
|
|
137
140
|
tracking = true;
|
|
@@ -252,7 +255,7 @@ function recompute(e, t = false) {
|
|
|
252
255
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
253
256
|
if (e.Ne === NOT_PENDING) queuePendingNode(e);
|
|
254
257
|
e.Ne = a;
|
|
255
|
-
} else if (e.
|
|
258
|
+
} else if (e.Fe != r) {
|
|
256
259
|
for (let t = e.o; t !== null; t = t.ue) {
|
|
257
260
|
insertIntoHeapHeight(t.le, queueFor(t.le));
|
|
258
261
|
}
|
|
@@ -301,7 +304,7 @@ function computed(e, t) {
|
|
|
301
304
|
Qe: 0,
|
|
302
305
|
ke: e,
|
|
303
306
|
Pe: undefined,
|
|
304
|
-
|
|
307
|
+
Fe: 0,
|
|
305
308
|
u: null,
|
|
306
309
|
lt: undefined,
|
|
307
310
|
ut: null,
|
|
@@ -346,7 +349,7 @@ function computed(e, t) {
|
|
|
346
349
|
Qe: 0,
|
|
347
350
|
ke: e,
|
|
348
351
|
Pe: undefined,
|
|
349
|
-
|
|
352
|
+
Fe: 0,
|
|
350
353
|
u: null,
|
|
351
354
|
lt: undefined,
|
|
352
355
|
ut: null,
|
|
@@ -397,7 +400,7 @@ function setupComputedNode(e, t) {
|
|
|
397
400
|
context.me = e;
|
|
398
401
|
}
|
|
399
402
|
}
|
|
400
|
-
if (n) e.
|
|
403
|
+
if (n) e.Fe = n.Fe + 1;
|
|
401
404
|
if (GlobalQueue.Tt !== null) GlobalQueue.Tt(e);
|
|
402
405
|
!t?.lazy && recompute(e, true);
|
|
403
406
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
@@ -520,15 +523,15 @@ function read(e) {
|
|
|
520
523
|
link(e, t, pendingCheckActive);
|
|
521
524
|
if (l.ke) {
|
|
522
525
|
const n = queueFor(e);
|
|
523
|
-
if (l.
|
|
526
|
+
if (l.Fe >= n.He) {
|
|
524
527
|
markNode(t);
|
|
525
528
|
markHeap(n);
|
|
526
529
|
updateIfNecessary(l);
|
|
527
530
|
}
|
|
528
|
-
const i = l.
|
|
531
|
+
const i = l.Fe;
|
|
529
532
|
// parent check is shallow, might need to be recursive
|
|
530
|
-
if (i >= t.
|
|
531
|
-
t.
|
|
533
|
+
if (i >= t.Fe && e.Ge !== t) {
|
|
534
|
+
t.Fe = i + 1;
|
|
532
535
|
}
|
|
533
536
|
}
|
|
534
537
|
}
|
package/dist/prod/core/error.js
CHANGED
|
@@ -25,7 +25,16 @@
|
|
|
25
25
|
class NotReadyError extends Error {
|
|
26
26
|
source;
|
|
27
27
|
constructor(r) {
|
|
28
|
+
// Control-flow throw: it happens on every read of a pending source, so in
|
|
29
|
+
// production skip V8's eager stack capture (proportional to stack depth —
|
|
30
|
+
// real cost under SSR) by zeroing the V8-specific stackTraceLimit around
|
|
31
|
+
// super(). Dev keeps the stack for debuggability; non-V8 engines (no
|
|
32
|
+
// stackTraceLimit) take the plain path.
|
|
33
|
+
const o = Error;
|
|
34
|
+
const t = o.stackTraceLimit;
|
|
35
|
+
if (t !== undefined) o.stackTraceLimit = 0;
|
|
28
36
|
super();
|
|
37
|
+
if (t !== undefined) o.stackTraceLimit = t;
|
|
29
38
|
this.source = r;
|
|
30
39
|
}
|
|
31
40
|
}
|
package/dist/prod/core/heap.js
CHANGED
|
@@ -20,14 +20,14 @@ import { zombieQueue, dirtyQueue } from "./scheduler.js";
|
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const E = queueFor(e);
|
|
23
|
-
if (E.
|
|
23
|
+
if (E.He > e.Fe) E.He = e.Fe;
|
|
24
24
|
insertIntoHeap(e, E);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function actualInsertIntoHeap(e, E) {
|
|
28
|
-
const t = (e.Ge?.ft ? e.Ge.Nt?.
|
|
29
|
-
if (t >= e.
|
|
30
|
-
const n = e.
|
|
28
|
+
const t = (e.Ge?.ft ? e.Ge.Nt?.Fe : e.Ge?.Fe) ?? -1;
|
|
29
|
+
if (t >= e.Fe) e.Fe = t + 1;
|
|
30
|
+
const n = e.Fe;
|
|
31
31
|
const I = E.eE[n];
|
|
32
32
|
if (I === undefined) E.eE[n] = e; else {
|
|
33
33
|
const E = I.ut;
|
|
@@ -66,7 +66,7 @@ function deleteFromHeap(e, E) {
|
|
|
66
66
|
const t = e.se;
|
|
67
67
|
if (!(t & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
68
68
|
e.se = t & -25;
|
|
69
|
-
const n = e.
|
|
69
|
+
const n = e.Fe;
|
|
70
70
|
if (e.ut === e) E.eE[n] = undefined; else {
|
|
71
71
|
const t = e.lt;
|
|
72
72
|
const I = E.eE[n];
|
|
@@ -106,11 +106,11 @@ function markNode(e, E = REACTIVE_DIRTY) {
|
|
|
106
106
|
|
|
107
107
|
function runHeap(e, E) {
|
|
108
108
|
e.tE = false;
|
|
109
|
-
for (e.
|
|
110
|
-
let t = e.eE[e.
|
|
109
|
+
for (e.He = 0; e.He <= e.EE; e.He++) {
|
|
110
|
+
let t = e.eE[e.He];
|
|
111
111
|
while (t !== undefined) {
|
|
112
112
|
if (t.se & REACTIVE_IN_HEAP) E(t); else adjustHeight(t, e);
|
|
113
|
-
t = e.eE[e.
|
|
113
|
+
t = e.eE[e.He];
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
e.EE = 0;
|
|
@@ -118,14 +118,14 @@ function runHeap(e, E) {
|
|
|
118
118
|
|
|
119
119
|
function adjustHeight(e, E) {
|
|
120
120
|
deleteFromHeap(e, E);
|
|
121
|
-
let t = e.
|
|
121
|
+
let t = e.Fe;
|
|
122
122
|
for (let E = e.Xe; E; E = E.et) {
|
|
123
123
|
const e = E.tt;
|
|
124
124
|
const n = e.nt || e;
|
|
125
|
-
if (n.ke && n.
|
|
125
|
+
if (n.ke && n.Fe >= t) t = n.Fe + 1;
|
|
126
126
|
}
|
|
127
|
-
if (e.
|
|
128
|
-
e.
|
|
127
|
+
if (e.Fe !== t) {
|
|
128
|
+
e.Fe = t;
|
|
129
129
|
for (let E = e.o; E !== null; E = E.ue) {
|
|
130
130
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
131
131
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
@@ -19,14 +19,14 @@ const transitions = new Set;
|
|
|
19
19
|
const dirtyQueue = {
|
|
20
20
|
eE: new Array(2e3).fill(undefined),
|
|
21
21
|
tE: false,
|
|
22
|
-
|
|
22
|
+
He: 0,
|
|
23
23
|
EE: 0
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const zombieQueue = {
|
|
27
27
|
eE: new Array(2e3).fill(undefined),
|
|
28
28
|
tE: false,
|
|
29
|
-
|
|
29
|
+
He: 0,
|
|
30
30
|
EE: 0
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -334,7 +334,7 @@ class GlobalQueue extends Queue {
|
|
|
334
334
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
335
335
|
// scheduled so the outer drain loop commits them via the plain
|
|
336
336
|
// flush path instead of leaving them until the next natural flush.
|
|
337
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
337
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.He || this.m.Qt.length > 0;
|
|
338
338
|
reassignPendingTransition(e.Qt);
|
|
339
339
|
activeTransition = null;
|
|
340
340
|
finalizePureQueue(null, true);
|
|
@@ -362,7 +362,7 @@ class GlobalQueue extends Queue {
|
|
|
362
362
|
} else {
|
|
363
363
|
if (canUseSimpleSyncFlush(this)) {
|
|
364
364
|
commitPendingNodes();
|
|
365
|
-
if (dirtyQueue.EE >= dirtyQueue.
|
|
365
|
+
if (dirtyQueue.EE >= dirtyQueue.He) {
|
|
366
366
|
runHeap(dirtyQueue, GlobalQueue.pe);
|
|
367
367
|
commitPendingNodes();
|
|
368
368
|
}
|
|
@@ -373,7 +373,7 @@ class GlobalQueue extends Queue {
|
|
|
373
373
|
}
|
|
374
374
|
clock++;
|
|
375
375
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
376
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
376
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.He;
|
|
377
377
|
// Run lane effects first (for ready lanes), then regular effects
|
|
378
378
|
activeLanes.size && GlobalQueue.In(EFFECT_RENDER);
|
|
379
379
|
this.run(EFFECT_RENDER);
|
|
@@ -527,7 +527,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
527
527
|
const i = !t;
|
|
528
528
|
if (i) commitPendingNodes();
|
|
529
529
|
if (!t && globalQueue.vt.length) checkBoundaryChildren(globalQueue);
|
|
530
|
-
const n = dirtyQueue.EE >= dirtyQueue.
|
|
530
|
+
const n = dirtyQueue.EE >= dirtyQueue.He;
|
|
531
531
|
if (n) runHeap(dirtyQueue, GlobalQueue.pe);
|
|
532
532
|
if (i) {
|
|
533
533
|
if (n) commitPendingNodes();
|
|
@@ -232,7 +232,7 @@ function getLatestValueComputed(e) {
|
|
|
232
232
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
233
233
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
234
234
|
const e = queueFor(t);
|
|
235
|
-
if (t.
|
|
235
|
+
if (t.Fe >= e.He && !(t.se & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
236
236
|
markHeap(e);
|
|
237
237
|
prepareComputed(t, true);
|
|
238
238
|
}
|
package/dist/prod/map.js
CHANGED
|
@@ -118,22 +118,29 @@ function updateKeyedMap() {
|
|
|
118
118
|
this.Mt = t.slice(0);
|
|
119
119
|
this.jt = s;
|
|
120
120
|
} else {
|
|
121
|
-
let o, c, a, f, u, p, w, l, d
|
|
122
|
-
r = this.Ut ? new Array(s) : undefined;
|
|
123
|
-
n = this.$t ? new Array(s) : undefined;
|
|
121
|
+
let o, c, a, f, u, p, w, l, d;
|
|
124
122
|
// skip common prefix
|
|
125
123
|
for (o = 0, c = Math.min(this.jt, s); o < c && (this.Mt[o] === t[o] || this.Ut && compare(this.Gt, this.Mt[o], t[o])); o++) {
|
|
126
124
|
if (this.Ut) setSignal(this.Ut[o], t[o]);
|
|
127
125
|
}
|
|
128
|
-
// common suffix
|
|
126
|
+
// skip common suffix — counted only; retained entries land in one pass
|
|
127
|
+
// at commit instead of being staged and copied twice
|
|
129
128
|
for (c = this.jt - 1, a = s - 1; c >= o && a >= o && (this.Mt[c] === t[a] || this.Ut && compare(this.Gt, this.Mt[c], t[a])); c--,
|
|
130
|
-
a--)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
a--) ;
|
|
130
|
+
// no structural change (every position matched in place at equal
|
|
131
|
+
// length — the common post-reconcile shape): keep the same mapped
|
|
132
|
+
// array identity so downstream consumers don't re-run at all
|
|
133
|
+
if (o === s && this.jt === s) {
|
|
134
|
+
this.Mt = t.slice(0);
|
|
135
|
+
return;
|
|
135
136
|
}
|
|
136
|
-
|
|
137
|
+
const O = s - this.jt;
|
|
138
|
+
const m = new Array(s);
|
|
139
|
+
const _ = new Array(s);
|
|
140
|
+
r = this.Ut ? new Array(s) : undefined;
|
|
141
|
+
n = this.$t ? new Array(s) : undefined;
|
|
142
|
+
// 0) prepare a map of all indices in the changed window of newItems,
|
|
143
|
+
// scanning backwards so we encounter them in natural order
|
|
137
144
|
p = new Map;
|
|
138
145
|
w = new Array(a + 1);
|
|
139
146
|
for (e = a; e >= o; e--) {
|
|
@@ -143,14 +150,16 @@ function updateKeyedMap() {
|
|
|
143
150
|
w[e] = i === undefined ? -1 : i;
|
|
144
151
|
p.set(u, e);
|
|
145
152
|
}
|
|
146
|
-
// 1) step through
|
|
153
|
+
// 1) step through the old changed window and see if items can be found
|
|
154
|
+
// in the new set; if so, stage them at their new positions; if not,
|
|
155
|
+
// queue them for disposal at commit
|
|
147
156
|
for (i = o; i <= c; i++) {
|
|
148
157
|
f = this.Mt[i];
|
|
149
158
|
u = this.Gt ? this.Gt(f) : f;
|
|
150
159
|
e = p.get(u);
|
|
151
160
|
if (e !== undefined && e !== -1) {
|
|
152
|
-
|
|
153
|
-
|
|
161
|
+
m[e] = this.xt[i];
|
|
162
|
+
_[e] = this.Ft[i];
|
|
154
163
|
r && (r[e] = this.Ut[i]);
|
|
155
164
|
n && (n[e] = this.$t[i]);
|
|
156
165
|
e = w[e];
|
|
@@ -159,33 +168,48 @@ function updateKeyedMap() {
|
|
|
159
168
|
}
|
|
160
169
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
161
170
|
try {
|
|
162
|
-
for (e = o; e
|
|
163
|
-
if (e
|
|
164
|
-
(d ??= []).push(
|
|
165
|
-
|
|
171
|
+
for (e = o; e <= a; e++) {
|
|
172
|
+
if (_[e] !== undefined) continue;
|
|
173
|
+
(d ??= []).push(_[e] = createOwner());
|
|
174
|
+
m[e] = runWithOwner(_[e], h);
|
|
166
175
|
}
|
|
167
176
|
} catch (t) {
|
|
168
177
|
if (d) for (i = 0; i < d.length; i++) d[i].dispose();
|
|
169
178
|
throw t;
|
|
170
179
|
}
|
|
171
|
-
// 3) commit: land
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
180
|
+
// 3) commit: land the retained prefix and suffix plus the staged window
|
|
181
|
+
// into the fresh arrays, swap them in (new identity for downstream
|
|
182
|
+
// change propagation), then dispose exited rows
|
|
183
|
+
for (i = 0; i < o; i++) {
|
|
184
|
+
m[i] = this.xt[i];
|
|
185
|
+
_[i] = this.Ft[i];
|
|
186
|
+
r && (r[i] = this.Ut[i]);
|
|
187
|
+
n && (n[i] = this.$t[i]);
|
|
188
|
+
}
|
|
189
|
+
for (e = o; e <= a; e++) {
|
|
190
|
+
if (r) setSignal(r[e], t[e]);
|
|
191
|
+
if (n) setSignal(n[e], e);
|
|
192
|
+
}
|
|
193
|
+
for (e = a + 1; e < s; e++) {
|
|
194
|
+
m[e] = this.xt[e - O];
|
|
195
|
+
_[e] = this.Ft[e - O];
|
|
175
196
|
if (r) {
|
|
176
|
-
|
|
177
|
-
setSignal(
|
|
197
|
+
r[e] = this.Ut[e - O];
|
|
198
|
+
setSignal(r[e], t[e]);
|
|
178
199
|
}
|
|
179
200
|
if (n) {
|
|
180
|
-
|
|
181
|
-
setSignal(
|
|
201
|
+
n[e] = this.$t[e - O];
|
|
202
|
+
if (O !== 0) setSignal(n[e], e);
|
|
182
203
|
}
|
|
183
204
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
205
|
+
this.xt = m;
|
|
206
|
+
this.Ft = _;
|
|
207
|
+
r && (this.Ut = r);
|
|
208
|
+
n && (this.$t = n);
|
|
209
|
+
this.jt = s;
|
|
210
|
+
// save a copy of the mapped items for the next update
|
|
188
211
|
this.Mt = t.slice(0);
|
|
212
|
+
if (l) for (i = 0; i < l.length; i++) l[i].dispose();
|
|
189
213
|
}
|
|
190
214
|
});
|
|
191
215
|
return this.xt;
|
|
@@ -16,17 +16,17 @@ import { runProjectionComputed } from "./projection.js";
|
|
|
16
16
|
|
|
17
17
|
import { storeSetter, $TARGET, STORE_OPTIMISTIC_OVERRIDE, STORE_NODE, STORE_OPTIMISTIC_OWNERS, getOverlayLayer, STORE_VALUE, $DELETED, isWrappable, wrap, visibleNodeValue, $TRACK, notifySelf, STORE_WRAP, createStoreProxy, storeTraps, STORE_LOOKUP, STORE_OPTIMISTIC, STORE_FIREWALL } from "./store.js";
|
|
18
18
|
|
|
19
|
-
function createOptimisticStore(e, t,
|
|
19
|
+
function createOptimisticStore(e, t, i) {
|
|
20
20
|
// Register clear function with scheduler; store nodes marked
|
|
21
21
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
22
22
|
// node can be created.
|
|
23
23
|
installOptimisticEngine();
|
|
24
24
|
GlobalQueue.Dt ||= clearOptimisticStores;
|
|
25
|
-
const
|
|
26
|
-
const o =
|
|
27
|
-
const n =
|
|
25
|
+
const r = typeof e === "function";
|
|
26
|
+
const o = r ? t : e;
|
|
27
|
+
const n = r ? e : undefined;
|
|
28
28
|
// Create optimistic projection store
|
|
29
|
-
const {store: c} = createOptimisticProjectionInternal(n, o,
|
|
29
|
+
const {store: c} = createOptimisticProjectionInternal(n, o, i);
|
|
30
30
|
return [ c, e => storeSetter(c, e) ];
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -35,8 +35,8 @@ function createOptimisticStore(e, t, r) {
|
|
|
35
35
|
// scheduler's flush tail carries only a size-guarded hook call. The
|
|
36
36
|
// completing transition scopes each clear to its own layer keys (#2899).
|
|
37
37
|
function clearOptimisticStores(e, t) {
|
|
38
|
-
for (const
|
|
39
|
-
const e =
|
|
38
|
+
for (const i of e) {
|
|
39
|
+
const e = i[$TARGET];
|
|
40
40
|
if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e, t);
|
|
41
41
|
}
|
|
42
42
|
e.clear();
|
|
@@ -54,9 +54,9 @@ function clearOptimisticStores(e, t) {
|
|
|
54
54
|
* fresh authoritative data) consumes everything — the correction supersedes
|
|
55
55
|
* every tentative layer.
|
|
56
56
|
*/ function clearOptimisticOverride(e, t) {
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
-
const
|
|
57
|
+
const i = e[STORE_OPTIMISTIC_OVERRIDE];
|
|
58
|
+
if (!i) return;
|
|
59
|
+
const r = e[STORE_NODE];
|
|
60
60
|
const o = e[STORE_OPTIMISTIC_OWNERS];
|
|
61
61
|
const n = t !== undefined;
|
|
62
62
|
let c = false;
|
|
@@ -66,7 +66,7 @@ function clearOptimisticStores(e, t) {
|
|
|
66
66
|
const O = projectionWriteActive;
|
|
67
67
|
setProjectionWriteActive(true);
|
|
68
68
|
try {
|
|
69
|
-
for (const O of Reflect.ownKeys(
|
|
69
|
+
for (const O of Reflect.ownKeys(i)) {
|
|
70
70
|
if (n) {
|
|
71
71
|
let e = o?.[O] ?? null;
|
|
72
72
|
// Resolve merge chains (entangled actions settle as one); path-compress
|
|
@@ -83,19 +83,19 @@ function clearOptimisticStores(e, t) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
delete
|
|
86
|
+
delete i[O];
|
|
87
87
|
if (o) delete o[O];
|
|
88
88
|
c = true;
|
|
89
|
-
const T =
|
|
89
|
+
const T = r?.[O];
|
|
90
90
|
if (T) {
|
|
91
91
|
// Clear lane association so effects go to regular queue
|
|
92
92
|
T.je = undefined;
|
|
93
93
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
94
94
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
95
95
|
const t = getOverlayLayer(e, O);
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const o = isWrappable(
|
|
96
|
+
const i = t ? t[O] : e[STORE_VALUE][O];
|
|
97
|
+
const r = i === $DELETED ? undefined : i;
|
|
98
|
+
const o = isWrappable(r) ? wrap(r, e) : r;
|
|
99
99
|
const n = visibleNodeValue(T);
|
|
100
100
|
T.Ee = NOT_PENDING;
|
|
101
101
|
T.sn = null;
|
|
@@ -108,12 +108,14 @@ function clearOptimisticStores(e, t) {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
if (!s) {
|
|
111
|
-
delete
|
|
112
|
-
delete
|
|
111
|
+
// Assignment, not delete: StoreNode targets share one pre-initialized
|
|
112
|
+
// hidden class (see createStoreProxy) and a delete would demote it.
|
|
113
|
+
e[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
114
|
+
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
113
115
|
}
|
|
114
116
|
// Notify $TRACK
|
|
115
|
-
if (c &&
|
|
116
|
-
|
|
117
|
+
if (c && r?.[$TRACK]) {
|
|
118
|
+
r[$TRACK].je = undefined;
|
|
117
119
|
notifySelf(e);
|
|
118
120
|
}
|
|
119
121
|
} finally {
|
|
@@ -121,8 +123,8 @@ function clearOptimisticStores(e, t) {
|
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
function createOptimisticProjectionInternal(e, t,
|
|
125
|
-
let
|
|
126
|
+
function createOptimisticProjectionInternal(e, t, i) {
|
|
127
|
+
let r;
|
|
126
128
|
const o = new WeakMap;
|
|
127
129
|
const wrapper = e => {
|
|
128
130
|
e[STORE_WRAP] = wrapProjection;
|
|
@@ -131,7 +133,7 @@ function createOptimisticProjectionInternal(e, t, r) {
|
|
|
131
133
|
// Mark as optimistic store
|
|
132
134
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
133
135
|
get() {
|
|
134
|
-
return
|
|
136
|
+
return r;
|
|
135
137
|
},
|
|
136
138
|
configurable: true
|
|
137
139
|
});
|
|
@@ -165,19 +167,19 @@ function createOptimisticProjectionInternal(e, t, r) {
|
|
|
165
167
|
setProjectionWriteActive(t);
|
|
166
168
|
}
|
|
167
169
|
};
|
|
168
|
-
|
|
170
|
+
r = computed(() => {
|
|
169
171
|
setProjectionWriteActive(true);
|
|
170
172
|
try {
|
|
171
|
-
runProjectionComputed(n, e,
|
|
173
|
+
runProjectionComputed(n, e, i?.key || "id", wrapCommit, clearProjectionOverride);
|
|
172
174
|
} finally {
|
|
173
175
|
setProjectionWriteActive(false);
|
|
174
176
|
}
|
|
175
177
|
}, undefined);
|
|
176
|
-
|
|
178
|
+
r.T &= ~CONFIG_AUTO_DISPOSE;
|
|
177
179
|
}
|
|
178
180
|
return {
|
|
179
181
|
store: n,
|
|
180
|
-
node:
|
|
182
|
+
node: r
|
|
181
183
|
};
|
|
182
184
|
}
|
|
183
185
|
|