@solidjs/signals 2.0.0-rc.8 → 2.0.0-rc.9
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 +1399 -285
- package/dist/dev.attribution.js +459 -307
- package/dist/dev.js +1864 -435
- package/dist/observe/affects.js +3 -1
- package/dist/observe/attribution.js +7 -1
- package/dist/observe/boundaries.js +209 -154
- package/dist/observe/core/action.js +18 -8
- package/dist/observe/core/async.js +220 -110
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +282 -0
- package/dist/observe/core/attribution-hooks.js +23 -1
- package/dist/observe/core/attribution-queries.js +28 -0
- package/dist/observe/core/attribution.js +262 -485
- package/dist/observe/core/constants.js +34 -1
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +867 -367
- package/dist/observe/core/dev.js +78 -17
- package/dist/observe/core/effect.js +67 -51
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/external.js +4 -4
- package/dist/observe/core/graph.js +37 -37
- package/dist/observe/core/heap.js +45 -45
- package/dist/observe/core/invariants.js +2 -0
- package/dist/observe/core/lanes.js +86 -49
- package/dist/observe/core/optimistic.js +242 -95
- package/dist/observe/core/owner.js +98 -84
- package/dist/observe/core/scheduler.js +543 -305
- package/dist/observe/core/verdict.js +247 -129
- package/dist/observe/index.js +7 -3
- package/dist/observe/map.js +126 -124
- package/dist/observe/signals.js +33 -17
- package/dist/observe/store/index.js +2 -0
- package/dist/observe/store/next/optimistic.js +141 -132
- package/dist/observe/store/next/projection.js +34 -21
- package/dist/observe/store/next/reconcile.js +58 -56
- package/dist/observe/store/next/store.js +260 -146
- package/dist/observe/store/store.js +5 -3
- package/dist/observe/store/utils.js +948 -135
- package/dist/prod/attribution.js +26 -17
- package/dist/prod/boundaries.js +128 -76
- package/dist/prod/core/action.js +16 -8
- package/dist/prod/core/async.js +251 -143
- package/dist/prod/core/constants.js +34 -1
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +843 -347
- package/dist/prod/core/dev.js +17 -1
- package/dist/prod/core/effect.js +48 -34
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +37 -37
- package/dist/prod/core/heap.js +45 -45
- package/dist/prod/core/lanes.js +90 -53
- package/dist/prod/core/optimistic.js +247 -100
- package/dist/prod/core/owner.js +57 -45
- package/dist/prod/core/scheduler.js +543 -305
- package/dist/prod/core/verdict.js +245 -127
- package/dist/prod/index.js +7 -3
- package/dist/prod/map.js +112 -112
- package/dist/prod/signals.js +28 -12
- package/dist/prod/store/next/optimistic.js +135 -128
- package/dist/prod/store/next/projection.js +31 -20
- package/dist/prod/store/next/store.js +325 -252
- package/dist/prod/store/store.js +2 -2
- package/dist/prod/store/utils.js +946 -135
- package/dist/types/attribution.d.ts +7 -2
- package/dist/types/attribution.prod.d.ts +10 -1
- package/dist/types/boundaries.d.ts +10 -1
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +28 -3
- package/dist/types/core/attribution-queries.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +51 -172
- package/dist/types/core/constants.d.ts +33 -0
- package/dist/types/core/core.d.ts +186 -5
- package/dist/types/core/dev.d.ts +129 -9
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/index.d.ts +3 -1
- package/dist/types/core/invariants.d.ts +4 -0
- package/dist/types/core/lanes.d.ts +31 -4
- package/dist/types/core/scheduler.d.ts +95 -2
- package/dist/types/core/types.d.ts +3 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/signals.d.ts +8 -0
- package/dist/types/store/index.d.ts +2 -1
- package/dist/types/store/next/optimistic.d.ts +1 -1
- package/dist/types/store/next/store.d.ts +6 -5
- package/dist/types/store/next/target.d.ts +1 -1
- package/dist/types/store/utils.d.ts +177 -6
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, STATUS_UNINITIALIZED, NOT_PENDING, CONFIG_OPTIMISTIC, CONFIG_HELD_TRUTH, unwrapOverride } from "../../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { computed, setSignal, isEqual } from "../../core/core.js";
|
|
3
|
+
import { computed, hasActiveOverride, setSignal, isEqual, visibleOverride } from "../../core/core.js";
|
|
4
4
|
|
|
5
5
|
import { getOwner } from "../../core/owner.js";
|
|
6
6
|
|
|
@@ -8,6 +8,8 @@ import { activeTransition, GlobalQueue, currentTransition, globalQueue, createTr
|
|
|
8
8
|
|
|
9
9
|
import "../../core/invariants.js";
|
|
10
10
|
|
|
11
|
+
import "../../core/dev.js";
|
|
12
|
+
|
|
11
13
|
import "../../core/verdict.js";
|
|
12
14
|
|
|
13
15
|
import "../../core/effect.js";
|
|
@@ -18,7 +20,7 @@ import { $TARGET, markRawIngest, setNextOptimisticViewResolver, isWrappable, raw
|
|
|
18
20
|
|
|
19
21
|
import { runProjectionComputedNext } from "./projection.js";
|
|
20
22
|
|
|
21
|
-
import { wrapNext, runAuthoritative, storeSetterNext,
|
|
23
|
+
import { wrapNext, runAuthoritative, storeSetterNext, unwrapValue, targetsEqual, heldMaskView, getNode, getHasNode, getKeySetNode, bumpDeep, stagedTruthPB, authoritativeRead } from "./store.js";
|
|
22
24
|
|
|
23
25
|
import { sameKey } from "./reconcile.js";
|
|
24
26
|
|
|
@@ -55,7 +57,7 @@ import { setOptHooks, $OWNER, lookupTarget } from "./target.js";
|
|
|
55
57
|
* staged values to converge (normal speculation). Resolves merges first:
|
|
56
58
|
* merge unions optimistic nodes/stores into the target. */ function transitionHoldsOptimism(e) {
|
|
57
59
|
const t = currentTransition(e);
|
|
58
|
-
return t.
|
|
60
|
+
return t.yt !== true && (t.tn.length !== 0 || t.rn.size !== 0);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
let blockedInstalled = false;
|
|
@@ -72,12 +74,15 @@ function installNextBlockedHalf() {
|
|
|
72
74
|
applyTentative: applyTentative,
|
|
73
75
|
retainsOptimism: transitionHoldsOptimism
|
|
74
76
|
});
|
|
75
|
-
|
|
77
|
+
// The affects() declaration walk is a WRITER channel (A28 (5)): tagging a
|
|
78
|
+
// parent covers the record as the writer sees it, this tick's optimistic
|
|
79
|
+
// writes included — the draft view, not the reader view.
|
|
80
|
+
setNextOptimisticViewResolver((e, t) => optimisticView(e, t, true));
|
|
76
81
|
// Scheduler flush tails call _clearOptimisticStores whenever tracked
|
|
77
82
|
// stores exist; next has no layer to clear — reverts are engine-native —
|
|
78
83
|
// so the hook only empties the batch set.
|
|
79
|
-
if (!GlobalQueue.
|
|
80
|
-
GlobalQueue.
|
|
84
|
+
if (!GlobalQueue.zn) {
|
|
85
|
+
GlobalQueue.zn = e => {
|
|
81
86
|
for (const t of e) {
|
|
82
87
|
const e = t?.[$TARGET];
|
|
83
88
|
const n = e?.fam?.overlaid;
|
|
@@ -96,24 +101,24 @@ function installNextBlockedHalf() {
|
|
|
96
101
|
e.clear();
|
|
97
102
|
};
|
|
98
103
|
}
|
|
99
|
-
const e = GlobalQueue.
|
|
100
|
-
GlobalQueue.
|
|
101
|
-
for (const e of t.
|
|
104
|
+
const e = GlobalQueue.kn;
|
|
105
|
+
GlobalQueue.kn = t => {
|
|
106
|
+
for (const e of t.rn) {
|
|
102
107
|
const n = e?.[$TARGET];
|
|
103
108
|
const i = n?.fam;
|
|
104
|
-
const
|
|
109
|
+
const r = i?.node;
|
|
105
110
|
// The hold exists to keep optimistic state alive until the store's own
|
|
106
111
|
// truth lands (#2951). Once the family carries NO live overrides (a
|
|
107
112
|
// landing consumed them, or they never existed), a pending firewall is
|
|
108
113
|
// no reason to park the transaction — blocking then leaks it forever
|
|
109
114
|
// when the in-flight question is never answered (undisposed fixtures).
|
|
110
|
-
if (
|
|
115
|
+
if (r == null || !(r.S & STATUS_PENDING)) continue;
|
|
111
116
|
// Ownership is declared (#3146): only the flight's OWN transaction
|
|
112
117
|
// parks on the flight (the #2951 anchor routed the bare write there).
|
|
113
118
|
// A transaction that merely brushed the store never waits for truth
|
|
114
119
|
// it does not carry.
|
|
115
|
-
const
|
|
116
|
-
if (
|
|
120
|
+
const o = i.ft != null ? liveTransition(i.ft) : null;
|
|
121
|
+
if (o !== null && o !== currentTransition(t)) continue;
|
|
117
122
|
if (familyHasLiveOverrides(i)) return true;
|
|
118
123
|
}
|
|
119
124
|
return e(t);
|
|
@@ -128,10 +133,10 @@ function familyHasLiveOverrides(e) {
|
|
|
128
133
|
if (t === null) continue;
|
|
129
134
|
for (const e of Reflect.ownKeys(t)) {
|
|
130
135
|
const n = t[e];
|
|
131
|
-
if (n.o?.
|
|
136
|
+
if (n.o?.Ne !== undefined && n.o?.Ne !== NOT_PENDING) return true;
|
|
132
137
|
}
|
|
133
138
|
}
|
|
134
|
-
if (e.k !== null && e.k.o?.
|
|
139
|
+
if (e.k !== null && e.k.o?.Ne !== undefined && e.k.o?.Ne !== NOT_PENDING) return true;
|
|
135
140
|
}
|
|
136
141
|
t.clear();
|
|
137
142
|
// nothing live — drop the bookkeeping
|
|
@@ -144,23 +149,23 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
144
149
|
installOptimisticEngine();
|
|
145
150
|
installNextBlockedHalf();
|
|
146
151
|
const i = typeof e === "function";
|
|
147
|
-
const
|
|
148
|
-
const
|
|
152
|
+
const r = i ? n : t;
|
|
153
|
+
const o = i ? t : e;
|
|
149
154
|
const s = {
|
|
150
155
|
map: new WeakMap,
|
|
151
156
|
node: null,
|
|
152
|
-
shallow: !!
|
|
157
|
+
shallow: !!r?.shallow,
|
|
153
158
|
opt: true
|
|
154
159
|
};
|
|
155
|
-
const l = wrapNext(
|
|
160
|
+
const l = wrapNext(o, null, null, s);
|
|
156
161
|
s.px = l;
|
|
157
162
|
// Same key resolution the projection channels use ("id" default) — replay's
|
|
158
163
|
// satisfaction rule reads it off the family.
|
|
159
|
-
const u =
|
|
164
|
+
const u = r?.key === undefined ? "id" : r.key;
|
|
160
165
|
s.key = typeof u === "function" ? u : u === null ? null : e => isWrappable(e) ? e[u] : undefined;
|
|
161
166
|
if (s.shallow) {
|
|
162
167
|
l[$TARGET].s = true;
|
|
163
|
-
markRawIngest(
|
|
168
|
+
markRawIngest(o);
|
|
164
169
|
}
|
|
165
170
|
if (i) {
|
|
166
171
|
const t = e;
|
|
@@ -178,7 +183,7 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
178
183
|
if (e == null) return;
|
|
179
184
|
let t = liveTransition(e);
|
|
180
185
|
if (t === null) s.ft = t = createTransition();
|
|
181
|
-
s.node.
|
|
186
|
+
s.node.Te = t;
|
|
182
187
|
globalQueue.initTransition(t);
|
|
183
188
|
};
|
|
184
189
|
// Landing router (#3164 fold ruling): while a transaction retains
|
|
@@ -223,8 +228,8 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
223
228
|
// (#2933: the loading rail is transaction-invisible); a sync run clears
|
|
224
229
|
// the declaration.
|
|
225
230
|
const declareFlight = e => {
|
|
226
|
-
if (e.o?.
|
|
227
|
-
if (!e.
|
|
231
|
+
if (e.o?.ce == null) {
|
|
232
|
+
if (!e.Se) s.ft = null;
|
|
228
233
|
return;
|
|
229
234
|
}
|
|
230
235
|
// First flight (#3146 carve-out): nothing has ever committed, so there
|
|
@@ -236,32 +241,32 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
236
241
|
// fallback never showed and the whole page stayed blank. The loading
|
|
237
242
|
// window (#2933) already declares nothing for the same reason; once
|
|
238
243
|
// the first truth lands, every refetch flight declares as before.
|
|
239
|
-
if (e.
|
|
244
|
+
if (e.Se || e.S & STATUS_UNINITIALIZED) return;
|
|
240
245
|
let t = activeTransition;
|
|
241
246
|
if (t === null) globalQueue.initTransition(t = createTransition());
|
|
242
247
|
s.ft = t;
|
|
243
|
-
e.
|
|
244
|
-
let n = t.
|
|
245
|
-
if (n === undefined) t.
|
|
248
|
+
e.Te = t;
|
|
249
|
+
let n = t.ot.get(e);
|
|
250
|
+
if (n === undefined) t.ot.set(e, n = new Set);
|
|
246
251
|
n.add(e);
|
|
247
252
|
};
|
|
248
253
|
let n;
|
|
249
|
-
if (
|
|
254
|
+
if (r?.seedLoadingValue) n = {
|
|
250
255
|
loadingValue: undefined
|
|
251
256
|
};
|
|
252
|
-
if (
|
|
257
|
+
if (r?.name) n = {
|
|
253
258
|
...n,
|
|
254
|
-
name:
|
|
259
|
+
name: r.name
|
|
255
260
|
};
|
|
256
261
|
const i = computed(() => {
|
|
257
262
|
const e = getOwner();
|
|
258
263
|
try {
|
|
259
|
-
runAuthoritative(() => runProjectionComputedNext(l, t,
|
|
264
|
+
runAuthoritative(() => runProjectionComputedNext(l, t, r?.key === undefined ? "id" : r.key, wrapCommit, aroundDraftWrite));
|
|
260
265
|
} finally {
|
|
261
266
|
declareFlight(e);
|
|
262
267
|
}
|
|
263
268
|
}, n);
|
|
264
|
-
i.
|
|
269
|
+
i.C &= ~CONFIG_AUTO_DISPOSE;
|
|
265
270
|
s.node = i;
|
|
266
271
|
}
|
|
267
272
|
return [ l, e => {
|
|
@@ -278,8 +283,8 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
278
283
|
|
|
279
284
|
/** Resolve a retained transition through its merge chain (`_done` holds the
|
|
280
285
|
* merge target while merged, `true` once settled). Null = dead. */ function liveTransition(e) {
|
|
281
|
-
while (typeof e.
|
|
282
|
-
return e.
|
|
286
|
+
while (typeof e.yt === "object") e = e.yt;
|
|
287
|
+
return e.yt === true ? null : e;
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
/** The transaction truth landings fold into: the first live member of the
|
|
@@ -324,11 +329,11 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
324
329
|
* stay unarmed — the override is their display and its revert their
|
|
325
330
|
* notification, A17). */ function runFolded(e, t) {
|
|
326
331
|
runAsTransitionBatch(e, t);
|
|
327
|
-
const n = e.
|
|
332
|
+
const n = e.sn;
|
|
328
333
|
for (let t = 0; t < n.length; t++) {
|
|
329
334
|
const i = n[t];
|
|
330
|
-
i.
|
|
331
|
-
if (i.
|
|
335
|
+
i.Te = e;
|
|
336
|
+
if (i.C & CONFIG_OPTIMISTIC && !hasActiveOverride(i)) i.C |= CONFIG_HELD_TRUTH;
|
|
332
337
|
}
|
|
333
338
|
}
|
|
334
339
|
|
|
@@ -344,15 +349,15 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
344
349
|
if (n !== null) {
|
|
345
350
|
// Occurrence-aware key queues (parity with the adoption window):
|
|
346
351
|
// duplicate keys match per occurrence, each current row consumed once.
|
|
347
|
-
let
|
|
348
|
-
const
|
|
349
|
-
for (let t = 0; t <
|
|
352
|
+
let r = null;
|
|
353
|
+
const o = e.length;
|
|
354
|
+
for (let t = 0; t < o; t++) {
|
|
350
355
|
const i = unwrapValue(e[t]);
|
|
351
356
|
if (!isWrappable(i)) continue;
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
354
|
-
const s = (
|
|
355
|
-
if (s === undefined)
|
|
357
|
+
const o = n(i);
|
|
358
|
+
if (o === undefined) continue;
|
|
359
|
+
const s = (r ??= new Map).get(o);
|
|
360
|
+
if (s === undefined) r.set(o, [ i ]); else s.push(i);
|
|
356
361
|
}
|
|
357
362
|
// Echo adoption: an optimistic structural add whose key the landing
|
|
358
363
|
// confirms must keep its raw (and so its proxy — list drivers keep the
|
|
@@ -367,42 +372,42 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
367
372
|
for (const e of Reflect.ownKeys(s)) {
|
|
368
373
|
const t = s[e];
|
|
369
374
|
if (!hasActiveOverride(t)) continue;
|
|
370
|
-
const i = unwrapValue(unwrapOverride(t.o.
|
|
375
|
+
const i = unwrapValue(unwrapOverride(t.o.Ne));
|
|
371
376
|
if (!isWrappable(i)) continue;
|
|
372
|
-
const
|
|
373
|
-
if (
|
|
374
|
-
const l = (
|
|
375
|
-
if (l === undefined)
|
|
377
|
+
const o = n(i);
|
|
378
|
+
if (o === undefined) continue;
|
|
379
|
+
const l = (r ??= new Map).get(o);
|
|
380
|
+
if (l === undefined) r.set(o, [ i ]); else l.push(i);
|
|
376
381
|
}
|
|
377
382
|
}
|
|
378
|
-
for (let
|
|
379
|
-
const i = t[
|
|
383
|
+
for (let o = 0; o < i; o++) {
|
|
384
|
+
const i = t[o];
|
|
380
385
|
let s;
|
|
381
|
-
if (isWrappable(i) &&
|
|
386
|
+
if (isWrappable(i) && r !== null) {
|
|
382
387
|
const e = n(i);
|
|
383
388
|
if (e !== undefined) {
|
|
384
|
-
for (const [t, n] of
|
|
389
|
+
for (const [t, n] of r) {
|
|
385
390
|
if (!sameKey(t, e)) continue;
|
|
386
391
|
s = n.shift();
|
|
387
|
-
if (n.length === 0)
|
|
392
|
+
if (n.length === 0) r.delete(t);
|
|
388
393
|
break;
|
|
389
394
|
}
|
|
390
395
|
}
|
|
391
396
|
}
|
|
392
397
|
if (s !== undefined) {
|
|
393
|
-
if (unwrapValue(e[
|
|
394
|
-
stagedApply(e[
|
|
398
|
+
if (unwrapValue(e[o]) !== s) e[o] = s;
|
|
399
|
+
stagedApply(e[o], i, n);
|
|
395
400
|
} else {
|
|
396
|
-
const t = unwrapValue(e[
|
|
397
|
-
if (!isEqual(t, i) && !targetsEqual(t, i)) e[
|
|
401
|
+
const t = unwrapValue(e[o]);
|
|
402
|
+
if (!isEqual(t, i) && !targetsEqual(t, i)) e[o] = i;
|
|
398
403
|
}
|
|
399
404
|
}
|
|
400
405
|
} else {
|
|
401
|
-
for (let
|
|
402
|
-
const i = t[
|
|
403
|
-
const
|
|
404
|
-
if (
|
|
405
|
-
if (isWrappable(i) && isWrappable(
|
|
406
|
+
for (let r = 0; r < i; r++) {
|
|
407
|
+
const i = t[r];
|
|
408
|
+
const o = unwrapValue(e[r]);
|
|
409
|
+
if (o === i) continue;
|
|
410
|
+
if (isWrappable(i) && isWrappable(o) && Array.isArray(i) === Array.isArray(o)) stagedApply(e[r], i, n); else if (!isEqual(o, i) && !targetsEqual(o, i)) e[r] = i;
|
|
406
411
|
}
|
|
407
412
|
}
|
|
408
413
|
if (e.length !== i) e.length = i;
|
|
@@ -410,25 +415,25 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
410
415
|
}
|
|
411
416
|
// Object merge; also the degenerate root-kind-change shape (arrays accept
|
|
412
417
|
// keyed writes/deletes, so a wholesale restatement still lands staged).
|
|
413
|
-
for (const
|
|
414
|
-
if (i &&
|
|
415
|
-
const
|
|
416
|
-
const s = unwrapValue(e[
|
|
417
|
-
if (s ===
|
|
418
|
-
if (isWrappable(
|
|
418
|
+
for (const r of Reflect.ownKeys(t)) {
|
|
419
|
+
if (i && r === "length" || r === $OWNER) continue;
|
|
420
|
+
const o = t[r];
|
|
421
|
+
const s = unwrapValue(e[r]);
|
|
422
|
+
if (s === o) continue;
|
|
423
|
+
if (isWrappable(o) && isWrappable(s) && Array.isArray(o) === Array.isArray(s)) {
|
|
419
424
|
// Different-keyed entities never merge (tentative-channel parity):
|
|
420
425
|
// the incoming object replaces the slot wholesale.
|
|
421
426
|
if (n !== null) {
|
|
422
427
|
const t = n(s);
|
|
423
|
-
const i = n(
|
|
428
|
+
const i = n(o);
|
|
424
429
|
if (t !== undefined && i !== undefined && !sameKey(t, i)) {
|
|
425
|
-
e[
|
|
430
|
+
e[r] = o;
|
|
426
431
|
continue;
|
|
427
432
|
}
|
|
428
433
|
}
|
|
429
|
-
stagedApply(e[
|
|
430
|
-
} else if (!isEqual(s,
|
|
431
|
-
e[
|
|
434
|
+
stagedApply(e[r], o, n);
|
|
435
|
+
} else if (!isEqual(s, o) && !targetsEqual(s, o)) {
|
|
436
|
+
e[r] = o;
|
|
432
437
|
}
|
|
433
438
|
}
|
|
434
439
|
for (const n of Reflect.ownKeys(e)) {
|
|
@@ -472,46 +477,46 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
472
477
|
// churned for the life of the action and snapped back at settle (#3323).
|
|
473
478
|
const visible = (t, n) => {
|
|
474
479
|
const i = e.n?.[t];
|
|
475
|
-
return unwrapValue(i !== undefined && hasActiveOverride(i) ? unwrapOverride(i.o?.
|
|
480
|
+
return unwrapValue(i !== undefined && hasActiveOverride(i) ? unwrapOverride(i.o?.Ne) : n);
|
|
476
481
|
};
|
|
477
482
|
const visiblePresent = t => {
|
|
478
483
|
const n = e.h?.[t];
|
|
479
|
-
return n !== undefined && hasActiveOverride(n) ? !!unwrapOverride(n.o?.
|
|
484
|
+
return n !== undefined && hasActiveOverride(n) ? !!unwrapOverride(n.o?.Ne) : t in i;
|
|
480
485
|
};
|
|
481
|
-
let
|
|
482
|
-
const
|
|
486
|
+
let r = false;
|
|
487
|
+
const o = Array.isArray(t);
|
|
483
488
|
for (const n of Reflect.ownKeys(t)) {
|
|
484
|
-
if (
|
|
489
|
+
if (o && n === "length" || n === $OWNER) continue;
|
|
485
490
|
const s = unwrapValue(t[n]);
|
|
486
491
|
if (!visiblePresent(n)) {
|
|
487
492
|
// Optimistic add: value node + presence node + membership bump.
|
|
488
493
|
setSignal(getNode(e, n, i[n]), () => s);
|
|
489
494
|
setSignal(getHasNode(e, n, n in i), true);
|
|
490
|
-
|
|
495
|
+
r = true;
|
|
491
496
|
} else {
|
|
492
497
|
const t = visible(n, i[n]);
|
|
493
498
|
if (!isEqual(t, s) && !targetsEqual(t, s)) {
|
|
494
499
|
setSignal(getNode(e, n, t), () => s);
|
|
495
|
-
if (
|
|
500
|
+
if (o) r = true;
|
|
496
501
|
}
|
|
497
502
|
}
|
|
498
503
|
}
|
|
499
504
|
for (const n of Reflect.ownKeys(i)) {
|
|
500
|
-
if (
|
|
505
|
+
if (o && n === "length" || n === $OWNER) continue;
|
|
501
506
|
if (n in t || !visiblePresent(n)) continue;
|
|
502
507
|
// Optimistic delete: node reads undefined, presence flips, membership bumps.
|
|
503
508
|
setSignal(getNode(e, n, i[n]), () => undefined);
|
|
504
509
|
setSignal(getHasNode(e, n, true), false);
|
|
505
|
-
|
|
510
|
+
r = true;
|
|
506
511
|
}
|
|
507
|
-
if (
|
|
512
|
+
if (o) {
|
|
508
513
|
const n = visible("length", i.length);
|
|
509
514
|
if (n !== t.length) {
|
|
510
515
|
setSignal(getNode(e, "length", n), () => t.length);
|
|
511
|
-
|
|
516
|
+
r = true;
|
|
512
517
|
}
|
|
513
518
|
}
|
|
514
|
-
if (
|
|
519
|
+
if (r) setSignal(getKeySetNode(e), e => e + 1);
|
|
515
520
|
// Deep-witness: optimistic value writes notify deep() subscribers too
|
|
516
521
|
// (structural ones already ride the key-set bump above).
|
|
517
522
|
bumpDeep(e);
|
|
@@ -522,7 +527,7 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
522
527
|
e.pb = stagedTruthPB.get(e) ?? null;
|
|
523
528
|
if (e.pb !== null) stagedTruthPB.delete(e);
|
|
524
529
|
(e.fam.overlaid ??= new Set).add(e);
|
|
525
|
-
GlobalQueue.
|
|
530
|
+
GlobalQueue.jn?.(e.fam.px ?? e.px);
|
|
526
531
|
}
|
|
527
532
|
|
|
528
533
|
/** Optimistic-view composition for snapshot/deep (O1: snapshot is the CURRENT
|
|
@@ -530,18 +535,20 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
530
535
|
* RUL-12). Returns `src` untouched when no override is active on `t`.
|
|
531
536
|
* Authoritative-view reads (until()'s predicate) skip composition entirely:
|
|
532
537
|
* the predicate observes authoritative truth, never the caller's tentative
|
|
533
|
-
* overlay. (Write-side emission callers never run under such a compute.) */ function optimisticView(e, t) {
|
|
538
|
+
* overlay. (Write-side emission callers never run under such a compute.) */ function optimisticView(e, t, n = false) {
|
|
534
539
|
if (e.fam?.opt !== true || authoritativeRead()) return t;
|
|
535
|
-
let
|
|
536
|
-
const ensure = () =>
|
|
540
|
+
let i = null;
|
|
541
|
+
const ensure = () => i ??= Array.isArray(t) ? [ ...t ] : {
|
|
537
542
|
...t
|
|
538
543
|
};
|
|
539
|
-
const
|
|
540
|
-
if (
|
|
541
|
-
for (const e of Reflect.ownKeys(
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
544
|
+
const r = e.n;
|
|
545
|
+
if (r !== null) {
|
|
546
|
+
for (const e of Reflect.ownKeys(r)) {
|
|
547
|
+
const i = r[e];
|
|
548
|
+
// A28 (5): readers see an optimistic write once a flush carried it;
|
|
549
|
+
// the draft (writer channel) composes on it now.
|
|
550
|
+
if (!(n ? hasActiveOverride(i) : visibleOverride(i))) continue;
|
|
551
|
+
const o = unwrapOverride(i.o?.Ne);
|
|
545
552
|
if (e === "length" && Array.isArray(t)) {
|
|
546
553
|
if (t.length !== o) ensure().length = o;
|
|
547
554
|
} else if (!isEqual(t[e], o)) ensure()[e] = o;
|
|
@@ -550,21 +557,23 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
550
557
|
const o = e.h;
|
|
551
558
|
if (o !== null) {
|
|
552
559
|
for (const e of Reflect.ownKeys(o)) {
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
560
|
+
const r = o[e];
|
|
561
|
+
// A28 (5): readers see an optimistic write once a flush carried it;
|
|
562
|
+
// the draft (writer channel) composes on it now.
|
|
563
|
+
if (!(n ? hasActiveOverride(r) : visibleOverride(r))) continue;
|
|
564
|
+
const s = !!unwrapOverride(r.o?.Ne);
|
|
565
|
+
if (!s && e in (i ?? t)) delete ensure()[e];
|
|
557
566
|
}
|
|
558
567
|
}
|
|
559
|
-
return
|
|
568
|
+
return i ?? t;
|
|
560
569
|
}
|
|
561
570
|
|
|
562
571
|
function applyTentative(e, t, n) {
|
|
563
572
|
const i = e.pb ?? e.v;
|
|
564
|
-
const
|
|
565
|
-
const
|
|
573
|
+
const r = optimisticView(e, i);
|
|
574
|
+
const o = e.fam;
|
|
566
575
|
const s = Array.isArray(t);
|
|
567
|
-
if (Array.isArray(
|
|
576
|
+
if (Array.isArray(r) !== s) return;
|
|
568
577
|
// kind change at root: flat overrides below
|
|
569
578
|
const l = [];
|
|
570
579
|
let u;
|
|
@@ -578,22 +587,22 @@ function applyTentative(e, t, n) {
|
|
|
578
587
|
if (Array.isArray(e) !== Array.isArray(t)) return null;
|
|
579
588
|
if (n) {
|
|
580
589
|
const i = n(e);
|
|
581
|
-
const
|
|
590
|
+
const r = n(t);
|
|
582
591
|
// SameValueZero (re-audit 3, P1-3): parity with the plain reconcile
|
|
583
592
|
// channel — NaN keys are self-equal.
|
|
584
|
-
if (i !== undefined &&
|
|
593
|
+
if (i !== undefined && r !== undefined && !sameKey(i, r)) return null;
|
|
585
594
|
}
|
|
586
|
-
return lookupTarget(unwrapValue(e),
|
|
595
|
+
return lookupTarget(unwrapValue(e), o) ?? null;
|
|
587
596
|
};
|
|
588
597
|
if (s) {
|
|
589
|
-
const e =
|
|
598
|
+
const e = r;
|
|
590
599
|
let i = null;
|
|
591
|
-
for (let
|
|
592
|
-
const
|
|
593
|
-
if (!isWrappable(
|
|
600
|
+
for (let r = 0; r < t.length; r++) {
|
|
601
|
+
const o = t[r];
|
|
602
|
+
if (!isWrappable(o)) continue;
|
|
594
603
|
let s;
|
|
595
604
|
if (n) {
|
|
596
|
-
const t = n(
|
|
605
|
+
const t = n(o);
|
|
597
606
|
if (t !== undefined) {
|
|
598
607
|
if (i === null) {
|
|
599
608
|
// Occurrence-aware index queues (re-audit 3, P1-3): parity with
|
|
@@ -601,41 +610,41 @@ function applyTentative(e, t, n) {
|
|
|
601
610
|
// occurrence, each view row consumed once.
|
|
602
611
|
i = new Map;
|
|
603
612
|
for (let t = 0; t < e.length; t++) {
|
|
604
|
-
const
|
|
605
|
-
if (isWrappable(
|
|
606
|
-
const e = n(
|
|
613
|
+
const r = unwrapValue(e[t]);
|
|
614
|
+
if (isWrappable(r)) {
|
|
615
|
+
const e = n(r);
|
|
607
616
|
if (e === undefined) continue;
|
|
608
|
-
const
|
|
609
|
-
if (
|
|
617
|
+
const o = i.get(e);
|
|
618
|
+
if (o === undefined) i.set(e, t); else if (Array.isArray(o)) o.push(t); else i.set(e, [ o, t ]);
|
|
610
619
|
}
|
|
611
620
|
}
|
|
612
621
|
}
|
|
613
|
-
const
|
|
614
|
-
if (
|
|
615
|
-
s = unwrapValue(e[
|
|
616
|
-
if (
|
|
622
|
+
const r = i.get(t);
|
|
623
|
+
if (r === undefined) s = undefined; else if (Array.isArray(r)) {
|
|
624
|
+
s = unwrapValue(e[r.shift()]);
|
|
625
|
+
if (r.length === 1) i.set(t, r[0]);
|
|
617
626
|
} else {
|
|
618
|
-
s = unwrapValue(e[
|
|
627
|
+
s = unwrapValue(e[r]);
|
|
619
628
|
i.delete(t);
|
|
620
629
|
}
|
|
621
|
-
} else s = unwrapValue(e[
|
|
622
|
-
} else s = unwrapValue(e[
|
|
623
|
-
const a = match(s,
|
|
630
|
+
} else s = unwrapValue(e[r]);
|
|
631
|
+
} else s = unwrapValue(e[r]);
|
|
632
|
+
const a = match(s, o);
|
|
624
633
|
if (a !== null) {
|
|
625
634
|
// Keep the existing row in the slot (identity preserved); recurse.
|
|
626
|
-
u[
|
|
627
|
-
l.push([ a,
|
|
635
|
+
u[r] = unwrapValue(s);
|
|
636
|
+
l.push([ a, o ]);
|
|
628
637
|
}
|
|
629
638
|
}
|
|
630
639
|
} else {
|
|
631
640
|
for (const e of Reflect.ownKeys(t)) {
|
|
632
641
|
if (e === $OWNER) continue;
|
|
633
|
-
const n = unwrapValue(
|
|
642
|
+
const n = unwrapValue(r[e]);
|
|
634
643
|
const i = t[e];
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
644
|
+
const o = match(n, i);
|
|
645
|
+
if (o !== null) {
|
|
637
646
|
u[e] = n;
|
|
638
|
-
l.push([
|
|
647
|
+
l.push([ o, i ]);
|
|
639
648
|
}
|
|
640
649
|
}
|
|
641
650
|
}
|