@solidjs/signals 2.0.0-rc.15 → 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 +2268 -1734
- package/dist/dev.attribution.js +75 -52
- package/dist/dev.js +1348 -658
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +22 -73
- package/dist/observe/boundaries.js +192 -190
- package/dist/observe/core/async.js +177 -131
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +176 -159
- package/dist/observe/core/constants.js +17 -3
- package/dist/observe/core/context.js +5 -3
- package/dist/observe/core/core.js +520 -364
- package/dist/observe/core/dev.js +66 -38
- package/dist/observe/core/effect.js +50 -48
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +60 -44
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +238 -260
- package/dist/observe/core/owner.js +117 -79
- package/dist/observe/core/scheduler.js +381 -217
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +91 -50
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +345 -260
- package/dist/observe/reveal.js +76 -76
- package/dist/observe/signals.js +47 -31
- package/dist/observe/store/affects.js +18 -18
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/optimistic.js +146 -100
- package/dist/observe/store/projection.js +68 -55
- package/dist/observe/store/store.js +180 -118
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +23 -72
- package/dist/prod/boundaries.js +156 -154
- package/dist/prod/core/async.js +173 -127
- package/dist/prod/core/constants.js +17 -3
- package/dist/prod/core/context.js +5 -3
- package/dist/prod/core/core.js +495 -343
- package/dist/prod/core/effect.js +70 -68
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +60 -44
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +230 -252
- package/dist/prod/core/owner.js +114 -77
- package/dist/prod/core/scheduler.js +327 -163
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +90 -49
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +360 -275
- package/dist/prod/reveal.js +76 -76
- package/dist/prod/signals.js +42 -26
- package/dist/prod/store/affects.js +6 -6
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/optimistic.js +143 -98
- package/dist/prod/store/projection.js +25 -19
- package/dist/prod/store/store.js +157 -100
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +1 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/constants.d.ts +13 -1
- package/dist/types/core/core.d.ts +54 -5
- package/dist/types/core/dev.d.ts +51 -13
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/graph.d.ts +11 -0
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +2 -14
- package/dist/types/core/owner.d.ts +9 -3
- package/dist/types/core/scheduler.d.ts +70 -32
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -0
- package/dist/types/core/verdict.d.ts +32 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/map.d.ts +2 -2
- package/dist/types/signals.d.ts +28 -7
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/index.d.ts +10 -3
- package/dist/types/store/optimistic.d.ts +3 -2
- package/dist/types/store/projection.d.ts +4 -3
- package/dist/types/store/store.d.ts +1 -1
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/prod/store/store.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { CONFIG_MANUAL_WRITE, CONFIG_OVERRIDE, CONFIG_HELD, $REFRESH, NOT_PENDING, STATUS_PENDING, STATUS_ERROR, EFFECT_RENDER, REACTIVE_RECOMPUTING_DEPS, REACTIVE_STAGED_READ, CONFIG_VERDICT, CONFIG_CHILDREN_FORBIDDEN, CONFIG_PROMOTED, REACTIVE_DIRTY, REACTIVE_CHECK } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { setSignal, isEqual, read, verdict, snapshotCaptureActive, captureWriteSnapshot, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
3
|
+
import { writeHook, setSignal, isEqual, read, verdict, snapshotCaptureActive, captureWriteSnapshot, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
4
|
+
|
|
5
|
+
import { signalHook } from "../core/identities.js";
|
|
4
6
|
|
|
5
7
|
import { setSlotUnobserved } from "../core/graph.js";
|
|
6
8
|
|
|
@@ -8,7 +10,7 @@ import { getObserver } from "../core/owner.js";
|
|
|
8
10
|
|
|
9
11
|
import { insertIntoHeap } from "../core/heap.js";
|
|
10
12
|
|
|
11
|
-
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, GlobalQueue, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
13
|
+
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, resolveTx, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
12
14
|
|
|
13
15
|
import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants, devAssertNeverUserMutation } from "./target.js";
|
|
14
16
|
|
|
@@ -166,7 +168,7 @@ function wrap(e, n = null, t = null, r = n?.fam ?? null) {
|
|
|
166
168
|
// adoption swap raw identity without changing the logical value — only
|
|
167
169
|
// changed leaves notify, R9).
|
|
168
170
|
const slotNodeEquals = function(e, n) {
|
|
169
|
-
return isEqual(e, n) || sameLogicalSlot(this.
|
|
171
|
+
return isEqual(e, n) || sameLogicalSlot(this.O, e, n);
|
|
170
172
|
};
|
|
171
173
|
|
|
172
174
|
/** The deep witness: the store decides when it notifies. */ const never = false;
|
|
@@ -204,7 +206,7 @@ function sameKey(e, n) {
|
|
|
204
206
|
/** The container node's comparator: a staging is a backing (identity — a
|
|
205
207
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
206
208
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */ const containerEquals = function(e, n) {
|
|
207
|
-
return e === n || optHooks !== null && optHooks.arrangement(this.
|
|
209
|
+
return e === n || optHooks !== null && optHooks.arrangement(this.O, e, n);
|
|
208
210
|
};
|
|
209
211
|
|
|
210
212
|
function sameLogicalSlot(e, n, t) {
|
|
@@ -217,8 +219,8 @@ function sameLogicalSlot(e, n, t) {
|
|
|
217
219
|
* released at the commit that resolves it (`drainFolds`). */ const deferredReleases = new Set;
|
|
218
220
|
|
|
219
221
|
function releaseSlot(e) {
|
|
220
|
-
const n = e.
|
|
221
|
-
const t = e.
|
|
222
|
+
const n = e.O;
|
|
223
|
+
const t = e.ze;
|
|
222
224
|
if (t === $TRACK) {
|
|
223
225
|
if (n.k === e) n.k = null;
|
|
224
226
|
} else if (t === $DEEP) {
|
|
@@ -241,10 +243,14 @@ function releaseSlot(e) {
|
|
|
241
243
|
// dispatches CONFIG_SLOT_NODE nodes here (graph.ts) instead of holding a
|
|
242
244
|
// per-node closure in a per-node NodeExtension. A dropped node is
|
|
243
245
|
// unreachable through the store — a fresh read makes a fresh node.
|
|
246
|
+
// A staged write — or a lane's value (a guess, S4) — is state only the node
|
|
247
|
+
// holds: its release waits for the commit that resolves it. So does a leaf of
|
|
248
|
+
// a held container (#4146): a mainline write it carried is in the held
|
|
249
|
+
// staging too, where it would read as the hold's until the landing.
|
|
250
|
+
const slotKept = e => e.se !== NOT_PENDING || e.l & CONFIG_OVERRIDE || e.O.k?.l & CONFIG_HELD;
|
|
251
|
+
|
|
244
252
|
setSlotUnobserved(e => {
|
|
245
|
-
|
|
246
|
-
// node holds: defer the release to the commit that resolves it.
|
|
247
|
-
if (e.Oe !== NOT_PENDING || e.i & CONFIG_OVERRIDE) deferredReleases.add(e); else releaseSlot(e);
|
|
253
|
+
if (slotKept(e)) deferredReleases.add(e); else releaseSlot(e);
|
|
248
254
|
});
|
|
249
255
|
|
|
250
256
|
/** A node born while its container has a staging is born from the two
|
|
@@ -252,19 +258,24 @@ setSlotUnobserved(e => {
|
|
|
252
258
|
* pending one — and held by the container's transaction when the container
|
|
253
259
|
* is held (#3706: the unit of the hold is the key — a key the batch left
|
|
254
260
|
* unchanged stages nothing and holds no one). */ function bornStaged(e, n, t, r) {
|
|
255
|
-
if (n.
|
|
261
|
+
if (n.xe && n.xe(n.Ie, t)) return;
|
|
256
262
|
queuePendingNode(n);
|
|
257
|
-
n.
|
|
263
|
+
n.se = t;
|
|
258
264
|
const i = e.k;
|
|
259
265
|
if (i === null) return;
|
|
260
266
|
// a node-less staging holds nothing (`stageOn`)
|
|
261
267
|
// Held by the container's transaction only for a key the HELD staging
|
|
262
268
|
// changed — a mainline layer's change above it stages mainline. (A
|
|
263
|
-
// container carrying a guess is a lane's: the flush's park decides
|
|
264
|
-
|
|
269
|
+
// container carrying a guess is a lane's: the flush's park decides —
|
|
270
|
+
// unless a correction folded under the guess, D-34: the key is that
|
|
271
|
+
// correction's hold's.)
|
|
272
|
+
if (i.l & CONFIG_HELD && heldKeyChanged(e, r)) {
|
|
273
|
+
const e = txOf(i);
|
|
274
|
+
if (!(i.l & CONFIG_OVERRIDE) || e.folded) holdNode(n, resolveTx(e._parent ?? e));
|
|
275
|
+
}
|
|
265
276
|
// A28 (4): a batch written inside a creation-time pass is promoted — its
|
|
266
277
|
// late-materialized leaf with it.
|
|
267
|
-
if (i.
|
|
278
|
+
if (i.l & CONFIG_PROMOTED) notePromotedWrite(n);
|
|
268
279
|
}
|
|
269
280
|
|
|
270
281
|
function getNode(e, n,
|
|
@@ -314,8 +325,8 @@ function getHasNode(e, n) {
|
|
|
314
325
|
// pending backing staged — so whoever asked for it reads the frame it
|
|
315
326
|
// would have read had the node been there from the write.
|
|
316
327
|
if (e.pb !== null && !directCommit) {
|
|
317
|
-
n.
|
|
318
|
-
n.
|
|
328
|
+
n.Ie = preBatch(e);
|
|
329
|
+
n.se = e.pb;
|
|
319
330
|
queuePendingNode(n);
|
|
320
331
|
}
|
|
321
332
|
}
|
|
@@ -331,11 +342,11 @@ function getHasNode(e, n) {
|
|
|
331
342
|
* staging: nothing allocates, nothing is swept at the commit (dbmon's tick
|
|
332
343
|
* re-created, queued, swept and dropped ~7000 container nodes). If the
|
|
333
344
|
* flush parks, the seam materializes and holds the node then
|
|
334
|
-
* (`
|
|
335
|
-
if (e.k === null && passLane === null && (context === null || globalQueue.
|
|
345
|
+
* (`storeParkHook`) — the one case the staging home exists for. */ function stageOn(e, n) {
|
|
346
|
+
if (e.k === null && passLane === null && (context === null || globalQueue.q) && !deriveHolds(e)) return;
|
|
336
347
|
const t = getContainerNode(e);
|
|
337
|
-
if (t.
|
|
338
|
-
t.
|
|
348
|
+
if (t.se === NOT_PENDING) queuePendingNode(t);
|
|
349
|
+
t.se = n;
|
|
339
350
|
// A28 (4): a write issued inside a pass outside a flush (a creation-time
|
|
340
351
|
// derive) is promoted at the pass's end — the batch with it.
|
|
341
352
|
if (context !== null) notePromotedWrite(t);
|
|
@@ -345,10 +356,10 @@ function getHasNode(e, n) {
|
|
|
345
356
|
/** The projection's derive is held by a transaction and this is its own
|
|
346
357
|
* write (not a user setter's): the staging is the derive's (`holdWithDerive`). */ function deriveHolds(e) {
|
|
347
358
|
const n = e.fam?.node;
|
|
348
|
-
return n != null && !userWrite && (n.
|
|
359
|
+
return n != null && !userWrite && (n.l & CONFIG_HELD) !== 0;
|
|
349
360
|
}
|
|
350
361
|
|
|
351
|
-
|
|
362
|
+
const storePark = e => {
|
|
352
363
|
for (let n = 0; n < foldList.length; n++) {
|
|
353
364
|
const t = foldList[n];
|
|
354
365
|
if (t.k === null && t.pb !== null) holdNode(getContainerNode(t), e);
|
|
@@ -376,9 +387,9 @@ function bumpDeep(e) {
|
|
|
376
387
|
// on the guess (`laneWrite` → `supersede`, judged by `containerEquals`);
|
|
377
388
|
// otherwise the structural readers are walked (the staging is already on
|
|
378
389
|
// the node; the comparator is the store's, done).
|
|
379
|
-
if (e.
|
|
380
|
-
if (e.
|
|
381
|
-
if (snapshotCaptureActive) captureWriteSnapshot(e, e.
|
|
390
|
+
if (e.l & CONFIG_OVERRIDE) setSignal(e, n); else {
|
|
391
|
+
if (e.l & CONFIG_HELD) joinFuture(txOf(e));
|
|
392
|
+
if (snapshotCaptureActive) captureWriteSnapshot(e, e.Ie);
|
|
382
393
|
insertSubs(e);
|
|
383
394
|
schedule();
|
|
384
395
|
}
|
|
@@ -470,7 +481,7 @@ const plainProto = e => {
|
|
|
470
481
|
if (e.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
|
|
471
482
|
if (e.del !== null && e.del.size !== 0) return true;
|
|
472
483
|
const t = e.wk;
|
|
473
|
-
if (t !== null && t !== WK_ALL && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
|
|
484
|
+
if (t !== null && t !== WK_ALL && t.u === undefined && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
|
|
474
485
|
const r = e.v;
|
|
475
486
|
let i = 0;
|
|
476
487
|
for (const e of Reflect.ownKeys(n)) if (!hasOwn.call(r, e) && ++i > OVERLAY_REBUILD_MIN_ADDS) return true;
|
|
@@ -490,7 +501,7 @@ const plainProto = e => {
|
|
|
490
501
|
e.pb = t;
|
|
491
502
|
e.ovl = false;
|
|
492
503
|
// The staging IS the pending backing: re-point the container node.
|
|
493
|
-
if (e.k !== null && e.k.
|
|
504
|
+
if (e.k !== null && e.k.se === n) e.k.se = t;
|
|
494
505
|
return t;
|
|
495
506
|
}
|
|
496
507
|
|
|
@@ -511,7 +522,7 @@ const plainProto = e => {
|
|
|
511
522
|
// mainline setter mid-hold publishes mainline; the held keys stay held).
|
|
512
523
|
n = e.pb = cloneRaw(n, e);
|
|
513
524
|
const t = e.k;
|
|
514
|
-
if (t !== null && !(t.
|
|
525
|
+
if (t !== null && !(t.l & CONFIG_HELD)) t.se = n;
|
|
515
526
|
} else if (n === null) {
|
|
516
527
|
const t = e.v;
|
|
517
528
|
if (!directCommit) queueFold(e);
|
|
@@ -590,7 +601,7 @@ const plainProto = e => {
|
|
|
590
601
|
} else r = e.v;
|
|
591
602
|
if (directCommit) {
|
|
592
603
|
e.pb = null;
|
|
593
|
-
if (e.k !== null) e.k.
|
|
604
|
+
if (e.k !== null) e.k.Ie = n;
|
|
594
605
|
} else {
|
|
595
606
|
// Eager (INTERNALS §3): the backing swaps now — handlers read the
|
|
596
607
|
// adopted object before the flush — while the container node, when
|
|
@@ -686,7 +697,7 @@ let foldIndex = null;
|
|
|
686
697
|
if (r.pb === null) continue;
|
|
687
698
|
// folded already (a direct commit)
|
|
688
699
|
const i = r.k;
|
|
689
|
-
if (i !== null && i.
|
|
700
|
+
if (i !== null && i.se !== NOT_PENDING) {
|
|
690
701
|
// held: commits with its hold
|
|
691
702
|
foldList.push(r);
|
|
692
703
|
foldOlds.push(n[t]);
|
|
@@ -697,7 +708,7 @@ let foldIndex = null;
|
|
|
697
708
|
}
|
|
698
709
|
if (deferredReleases.size !== 0) {
|
|
699
710
|
for (const e of deferredReleases) {
|
|
700
|
-
if (e.
|
|
711
|
+
if (e.o === null && !slotKept(e)) {
|
|
701
712
|
deferredReleases.delete(e);
|
|
702
713
|
releaseSlot(e);
|
|
703
714
|
}
|
|
@@ -708,28 +719,28 @@ let foldIndex = null;
|
|
|
708
719
|
/** Core asks: is a slot node's truth in flight? Its family's derive is —
|
|
709
720
|
* lanes (A17, #2864: a guess mid-refetch stands in for the flight) and
|
|
710
721
|
* marks (an ambient `affects()` over a declared reload lives to the
|
|
711
|
-
* landing) read it. */ GlobalQueue.
|
|
712
|
-
const n = e.
|
|
713
|
-
return n != null && n.node !== null && (n.node.
|
|
722
|
+
* landing) read it. */ GlobalQueue.k = e => {
|
|
723
|
+
const n = e.O?.fam;
|
|
724
|
+
return n != null && n.node !== null && (n.node.m & STATUS_PENDING) !== 0;
|
|
714
725
|
};
|
|
715
726
|
|
|
716
727
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
717
728
|
* A chained link's committed value is the inner store's at the last
|
|
718
729
|
* read-through — refreshed here, since a guess served the reads since
|
|
719
|
-
* (#3672: the revert compares against the base's live value). */ GlobalQueue.
|
|
720
|
-
const n = e.
|
|
730
|
+
* (#3672: the revert compares against the base's live value). */ GlobalQueue.fn = e => {
|
|
731
|
+
const n = e.O;
|
|
721
732
|
if (n.ch) {
|
|
722
|
-
const t = e.
|
|
733
|
+
const t = e.ze;
|
|
723
734
|
const r = n.v;
|
|
724
|
-
if (n.h !== null && n.h[t] === e) e.
|
|
735
|
+
if (n.h !== null && n.h[t] === e) e.Ie = untrack(() => t in r); else if (n.n !== null && n.n[t] === e) e.Ie = untrack(() => unwrapValue(r[t]));
|
|
725
736
|
}
|
|
726
|
-
return e.
|
|
737
|
+
return e.Ie;
|
|
727
738
|
};
|
|
728
739
|
|
|
729
|
-
|
|
740
|
+
installStoreHooks(storePark, () => {
|
|
730
741
|
drainFolds();
|
|
731
742
|
optHooks?.sweep();
|
|
732
|
-
};
|
|
743
|
+
});
|
|
733
744
|
|
|
734
745
|
/** The store half of `affects()` (store/affects.ts) makes its marks' nodes
|
|
735
746
|
* and walks records through these: it never imports the engine. */ GlobalQueue.no = getNode;
|
|
@@ -762,7 +773,7 @@ function runDirect(e) {
|
|
|
762
773
|
// the adopted object (shared ownership — never cloned).
|
|
763
774
|
e.pb = null;
|
|
764
775
|
e.wk = null;
|
|
765
|
-
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.
|
|
776
|
+
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.Pe !== n)) {
|
|
766
777
|
// Overlay flatten (#3044): the backing keeps its identity, so the
|
|
767
778
|
// `t.v === old` gate below skips path copying (the parent slot
|
|
768
779
|
// already points here) and the adopted-notify (setter
|
|
@@ -776,8 +787,8 @@ function runDirect(e) {
|
|
|
776
787
|
const t = e.v;
|
|
777
788
|
const i = e.wk;
|
|
778
789
|
if (i !== null && i !== WK_ALL) {
|
|
779
|
-
for (
|
|
780
|
-
if (hasOwn.call(r,
|
|
790
|
+
for (let e = i; e !== undefined; e = e.u) for (const n of e) {
|
|
791
|
+
if (hasOwn.call(r, n)) copyOwn(t, r, n); else delete t[n];
|
|
781
792
|
}
|
|
782
793
|
} else {
|
|
783
794
|
for (const e of Reflect.ownKeys(r)) {
|
|
@@ -804,7 +815,7 @@ function runDirect(e) {
|
|
|
804
815
|
// subscribes to was a transient staging home (INTERNALS §5: an
|
|
805
816
|
// observer-less write holds a transient record until the fold,
|
|
806
817
|
// discarded with it) — gone with the batch.
|
|
807
|
-
if (t.
|
|
818
|
+
if (t.o === null) e.k = null; else if (t.Ie instanceof LaneView) t.Ie.base = e.v; else t.Ie = e.v;
|
|
808
819
|
}
|
|
809
820
|
if (e.v !== n && e.u) {
|
|
810
821
|
const t = parentSlotKey(e, n);
|
|
@@ -831,9 +842,9 @@ function runDirect(e) {
|
|
|
831
842
|
|
|
832
843
|
function heldDerivation(e, n, t) {
|
|
833
844
|
if (e.fam === null || !userWrite) return false;
|
|
834
|
-
if (n !== undefined) return (n.
|
|
845
|
+
if (n !== undefined) return (n.l & (CONFIG_HELD | CONFIG_MANUAL_WRITE)) === CONFIG_HELD && txOf(n) !== flushTransaction;
|
|
835
846
|
const r = e.k;
|
|
836
|
-
return r !== null && (r.
|
|
847
|
+
return r !== null && (r.l & CONFIG_HELD) !== 0 && txOf(r) !== flushTransaction && heldKeyChanged(e, t);
|
|
837
848
|
}
|
|
838
849
|
|
|
839
850
|
/** Setter exit: one node write per changed observed key (the leaves stage
|
|
@@ -863,7 +874,10 @@ function heldDerivation(e, n, t) {
|
|
|
863
874
|
// value can change when ANY key is written), or a non-plain prototype
|
|
864
875
|
// (class instances: prototype getters derive from arbitrary fields).
|
|
865
876
|
// Overlay pbs chain to the COMMITTED object (#3044) — plainness is the
|
|
866
|
-
// committed container's prototype, not the overlay's.
|
|
877
|
+
// committed container's prototype, not the overlay's. THIS setter's keys
|
|
878
|
+
// only (D-8, #3743): a key an earlier setter of the batch wrote and this
|
|
879
|
+
// one did not is no second proposal — its node was told then, and telling
|
|
880
|
+
// a held node its unchanged value again would join this tick to the hold.
|
|
867
881
|
const i = e.wk;
|
|
868
882
|
const o = i === WK_ALL || e.a === true || !plainProto(e.ovl ? e.v : n) ? null : i;
|
|
869
883
|
if (e.fam !== null && !heldDerivationHit && o !== null) for (const n of o) if (heldDerivation(e, r?.[n], n)) {
|
|
@@ -898,9 +912,9 @@ function heldDerivation(e, n, t) {
|
|
|
898
912
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
899
913
|
// (A34 (3)'s discriminator).
|
|
900
914
|
if (!userWrite) {
|
|
901
|
-
i.
|
|
915
|
+
i.l &= ~CONFIG_MANUAL_WRITE;
|
|
902
916
|
holdWithDerive(e, i);
|
|
903
|
-
} else i.
|
|
917
|
+
} else i.l |= CONFIG_MANUAL_WRITE;
|
|
904
918
|
}
|
|
905
919
|
}
|
|
906
920
|
}
|
|
@@ -931,7 +945,7 @@ function heldDerivation(e, n, t) {
|
|
|
931
945
|
// container carrying an arrangement guess is told whether or not anyone
|
|
932
946
|
// subscribes: the write is a landing on the guess (`notifyContainer`).
|
|
933
947
|
const u = e.k;
|
|
934
|
-
if (u !== null && (u.
|
|
948
|
+
if (u !== null && (u.o !== null || u.l & CONFIG_OVERRIDE)) {
|
|
935
949
|
let r;
|
|
936
950
|
if (e.ovl) {
|
|
937
951
|
r = e.del !== null && e.del.size !== 0;
|
|
@@ -1033,7 +1047,7 @@ function hasAccessorFlag(e) {
|
|
|
1033
1047
|
for (const i of Reflect.ownKeys(r)) if (e || i in n !== i in t) setSignal(r[i], i in t);
|
|
1034
1048
|
}
|
|
1035
1049
|
const i = e.k;
|
|
1036
|
-
if (i !== null && (i.
|
|
1050
|
+
if (i !== null && (i.o !== null || i.l & CONFIG_OVERRIDE)) {
|
|
1037
1051
|
const e = Array.isArray(t) && Array.isArray(n) ? arrayStructureChanged(n, t) : membershipChanged(n, t);
|
|
1038
1052
|
if (e) notifyContainer(i, t);
|
|
1039
1053
|
}
|
|
@@ -1090,7 +1104,7 @@ function inDraft(e) {
|
|
|
1090
1104
|
* "adoption is eager by contract" — and the node keeps the frame committed
|
|
1091
1105
|
* readers under a hold still see), `t.v` otherwise. */ function committed(e) {
|
|
1092
1106
|
const n = e.k;
|
|
1093
|
-
if (n !== null) return n.
|
|
1107
|
+
if (n !== null) return n.se !== NOT_PENDING ? asBacking(n.Ie) : e.v;
|
|
1094
1108
|
// A node-less staging (`stageOn`): the fold queue remembers the frame.
|
|
1095
1109
|
return e.pb !== null ? preBatch(e) : e.v;
|
|
1096
1110
|
}
|
|
@@ -1102,8 +1116,8 @@ function inDraft(e) {
|
|
|
1102
1116
|
* committed frame. */ function stagingReader() {
|
|
1103
1117
|
let e = context;
|
|
1104
1118
|
if (e === null) return null;
|
|
1105
|
-
if (e
|
|
1106
|
-
return e === null || e.
|
|
1119
|
+
if (e.Qe) e = e.Ye ?? null;
|
|
1120
|
+
return e === null || e.l & CONFIG_CHILDREN_FORBIDDEN ? null : e;
|
|
1107
1121
|
}
|
|
1108
1122
|
|
|
1109
1123
|
/** The backing a read serves (RUL-1, signal parity): the draft and the write
|
|
@@ -1141,10 +1155,10 @@ function inDraft(e) {
|
|
|
1141
1155
|
if (writeOverride && !userWrite) {
|
|
1142
1156
|
const t = n !== undefined ? e.n?.[n] : undefined;
|
|
1143
1157
|
if (t !== undefined) {
|
|
1144
|
-
if ((t.
|
|
1158
|
+
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) joinPassTx(txOf(t));
|
|
1145
1159
|
} else {
|
|
1146
1160
|
const t = e.k;
|
|
1147
|
-
if (t !== null && (t.
|
|
1161
|
+
if (t !== null && (t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && (n === undefined || heldKeyChanged(e, n))) joinPassTx(txOf(t));
|
|
1148
1162
|
}
|
|
1149
1163
|
}
|
|
1150
1164
|
return r;
|
|
@@ -1156,9 +1170,9 @@ function inDraft(e) {
|
|
|
1156
1170
|
// it).
|
|
1157
1171
|
if (n !== undefined) {
|
|
1158
1172
|
const t = e.n?.[n];
|
|
1159
|
-
if (t !== undefined && t.
|
|
1173
|
+
if (t !== undefined && t.l & CONFIG_OVERRIDE) return committed(e);
|
|
1160
1174
|
}
|
|
1161
|
-
const o = i !== null && (i.
|
|
1175
|
+
const o = i !== null && (i.l & CONFIG_HELD) !== 0;
|
|
1162
1176
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
1163
1177
|
// staging left unchanged reads the ambient view — a mainline layer's
|
|
1164
1178
|
// write above the hold publishes mainline (#3688, #3612); a key it
|
|
@@ -1176,7 +1190,7 @@ function inDraft(e) {
|
|
|
1176
1190
|
// probe) judges the container like any node — for a key the batch
|
|
1177
1191
|
// changed; an unchanged key is committed and final (A22: pending is per
|
|
1178
1192
|
// key). A held container's committed frame is the node's.
|
|
1179
|
-
if (verdict === null || !o && n !== undefined && !keyChanged(e, n, t)) return o ? asBacking(i.
|
|
1193
|
+
if (verdict === null || !o && n !== undefined && !keyChanged(e, n, t)) return o ? asBacking(i.Ie) : e.v;
|
|
1180
1194
|
return i === null ? committed(e) : asBacking(read(i));
|
|
1181
1195
|
}
|
|
1182
1196
|
// A pass reading a key the batch left unchanged: the same value in both
|
|
@@ -1193,13 +1207,13 @@ function inDraft(e) {
|
|
|
1193
1207
|
// frames, a changed one is what the mark already stands for. The
|
|
1194
1208
|
// per-key question is asked once per pass, not once per key (a
|
|
1195
1209
|
// `mapArray` over 1k shifted rows asked it 1k times).
|
|
1196
|
-
if (l.R & REACTIVE_STAGED_READ && !(l.
|
|
1210
|
+
if (l.R & REACTIVE_STAGED_READ && !(l.l & (CONFIG_VERDICT | CONFIG_CHILDREN_FORBIDDEN))) return r;
|
|
1197
1211
|
if (n !== undefined && !keyChanged(e, n, t)) return committed(e);
|
|
1198
1212
|
// A node-less staging (`stageOn`): what `read()` of its node would do
|
|
1199
1213
|
// for this pass — a verdict reader sees the screen, any other derives
|
|
1200
1214
|
// from the staging and is marked as having read it.
|
|
1201
1215
|
if (i === null) {
|
|
1202
|
-
if (l.
|
|
1216
|
+
if (l.l & CONFIG_VERDICT && stagedScreen(l)) return committed(e);
|
|
1203
1217
|
stagedRead(l);
|
|
1204
1218
|
return r;
|
|
1205
1219
|
}
|
|
@@ -1209,7 +1223,7 @@ function inDraft(e) {
|
|
|
1209
1223
|
|
|
1210
1224
|
/** Did the HELD staging (the container node's, not a mainline layer above
|
|
1211
1225
|
* it) change `key`? */ function heldKeyChanged(e, n, t = true) {
|
|
1212
|
-
return changedBetween(e, e.k.
|
|
1226
|
+
return changedBetween(e, e.k.Ie, e.k.se, n, t) && !adoptChild(e, n);
|
|
1213
1227
|
}
|
|
1214
1228
|
|
|
1215
1229
|
/** The values of a held frame, built once per frame: neither the committed
|
|
@@ -1236,14 +1250,14 @@ function rawsOf(e) {
|
|
|
1236
1250
|
* `version` holds. A record's keys pair by name; an array's by the family's
|
|
1237
1251
|
* key — without a family the pairing is not known here and the hold stands. */ function adoptChild(e, n) {
|
|
1238
1252
|
const t = e.k;
|
|
1239
|
-
const r = asBacking(t.
|
|
1253
|
+
const r = asBacking(t.Ie);
|
|
1240
1254
|
const i = r[n];
|
|
1241
|
-
const o = t.
|
|
1255
|
+
const o = t.se[n];
|
|
1242
1256
|
const l = Array.isArray(r) ? e.fam?.key : null;
|
|
1243
1257
|
if (e.s || l === undefined || !sameRow(i, o, l) || !isWrappable(i) || !isWrappable(o) || Array.isArray(i) !== Array.isArray(o) || lookupTarget(i, e.fam) !== undefined || lookupTarget(o, e.fam) !== undefined ||
|
|
1244
1258
|
// A raw in both frames (the same objects swapped or reordered) is its
|
|
1245
1259
|
// own row: pairing it with another would alias the two after the commit.
|
|
1246
|
-
rawsOf(r).has(o) || rawsOf(t.
|
|
1260
|
+
rawsOf(r).has(o) || rawsOf(t.se).has(i)) return false;
|
|
1247
1261
|
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
1248
1262
|
// is a fresh target around `ov`.
|
|
1249
1263
|
const u = wrap(i, e, n)[$TARGET];
|
|
@@ -1254,7 +1268,7 @@ function rawsOf(e) {
|
|
|
1254
1268
|
}
|
|
1255
1269
|
|
|
1256
1270
|
/** A family target's unheld staging, read with no pass (a handler). */ function familyAhead(e) {
|
|
1257
|
-
return e.fam !== null && context === null && !(e.k !== null && e.k.
|
|
1271
|
+
return e.fam !== null && context === null && !(e.k !== null && e.k.l & CONFIG_HELD);
|
|
1258
1272
|
}
|
|
1259
1273
|
|
|
1260
1274
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
@@ -1288,7 +1302,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1288
1302
|
* tracked or not, applies the hold and A28 rules a signal's read does. A
|
|
1289
1303
|
* projection's unheld staging is ahead for a handler (`familyAhead`). */ function nodeValue(e, n, t) {
|
|
1290
1304
|
let r = read(e);
|
|
1291
|
-
if (e.
|
|
1305
|
+
if (e.se !== NOT_PENDING && !(e.l & CONFIG_HELD) && context === null && t.fam !== null) r = e.se;
|
|
1292
1306
|
return r === FORCE ? n : r;
|
|
1293
1307
|
}
|
|
1294
1308
|
|
|
@@ -1308,8 +1322,8 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1308
1322
|
if (l) {
|
|
1309
1323
|
// The link's committed value follows the inner store's (what a lane
|
|
1310
1324
|
// over it covers — its reveal and revert compare against it, S4).
|
|
1311
|
-
i.
|
|
1312
|
-
if (i.
|
|
1325
|
+
i.Ie = t;
|
|
1326
|
+
if (i.l & CONFIG_OVERRIDE) u = n;
|
|
1313
1327
|
} else u = n;
|
|
1314
1328
|
}
|
|
1315
1329
|
}
|
|
@@ -1330,7 +1344,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1330
1344
|
}
|
|
1331
1345
|
|
|
1332
1346
|
/** Is `n` among `c`'s dependencies (any pass's — a kept tail included)? */ function linkedTo(e, n) {
|
|
1333
|
-
for (let t = e.
|
|
1347
|
+
for (let t = e.C; t !== null; t = t.G) if (t.S === n) return true;
|
|
1334
1348
|
return false;
|
|
1335
1349
|
}
|
|
1336
1350
|
|
|
@@ -1349,7 +1363,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1349
1363
|
// reader of a memo would — linked, so it re-runs at the landing (the
|
|
1350
1364
|
// next settled pass pulls without linking and the stale link trims), a
|
|
1351
1365
|
// verdict reader registered, a tracked pass suspended.
|
|
1352
|
-
if (n.
|
|
1366
|
+
if (n.m & (STATUS_PENDING | STATUS_ERROR)) {
|
|
1353
1367
|
// A render effect outside the flight's own flush is the frame, not a
|
|
1354
1368
|
// derivation: it keeps what it shows and learns of the landing from the
|
|
1355
1369
|
// leaves the landing changes (unchanged leaves say nothing — it is not a
|
|
@@ -1360,7 +1374,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1360
1374
|
// release the hold with the flight still up. An errored derive has no
|
|
1361
1375
|
// landing to learn of: the error is what the frame shows.
|
|
1362
1376
|
const t = context;
|
|
1363
|
-
if (t !== null && t.
|
|
1377
|
+
if (t !== null && t.i === EFFECT_RENDER && !(n.m & STATUS_ERROR) && n.l & CONFIG_HELD && flushTransaction !== txOf(n) && !linkedTo(t, n)) return;
|
|
1364
1378
|
// An optimistic family carrying guesses that stand in for the flight
|
|
1365
1379
|
// (A17): the guesses are the display — a reader is served the leaves
|
|
1366
1380
|
// (committed plus the guesses) and does not suspend on the derive; a
|
|
@@ -1368,7 +1382,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1368
1382
|
// up). The family's, not the target's: the edit stands in for the one
|
|
1369
1383
|
// flight the family has.
|
|
1370
1384
|
const r = e.fam.overlaid;
|
|
1371
|
-
if (verdict === null && n.
|
|
1385
|
+
if (verdict === null && n.m & STATUS_PENDING && r !== undefined && r.size !== 0) return;
|
|
1372
1386
|
read(n);
|
|
1373
1387
|
} else untrack(() => read(n));
|
|
1374
1388
|
}
|
|
@@ -1381,12 +1395,12 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1381
1395
|
* classification, as core reads it — `heldNotFinal`). */ function holdWithDerive(e, n) {
|
|
1382
1396
|
const t = e.fam?.node;
|
|
1383
1397
|
if (t !== undefined && t !== null && !userWrite && // the derive's own write (its draft or landing), not a user setter's
|
|
1384
|
-
t.
|
|
1398
|
+
t.l & CONFIG_HELD && n.se !== NOT_PENDING &&
|
|
1385
1399
|
// A node carrying a guess is the lane's: its staging is the truth beneath
|
|
1386
1400
|
// the guess (`setSignal` → `laneWrite`), never re-homed by the store.
|
|
1387
|
-
!(n.
|
|
1401
|
+
!(n.l & (CONFIG_HELD | CONFIG_OVERRIDE))) {
|
|
1388
1402
|
holdNode(n, txOf(t));
|
|
1389
|
-
n.
|
|
1403
|
+
n.T.Ve = t.T.Ve;
|
|
1390
1404
|
}
|
|
1391
1405
|
}
|
|
1392
1406
|
|
|
@@ -1429,6 +1443,22 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1429
1443
|
|
|
1430
1444
|
// ---------------------------------------------------------------------------
|
|
1431
1445
|
// traps
|
|
1446
|
+
/** A trap write: the target is told at the setter's exit, the key recorded
|
|
1447
|
+
* in this setter's `wk`. A setter's first write to a target still staged by
|
|
1448
|
+
* an earlier setter of the batch opens a set of its own (the notify visits
|
|
1449
|
+
* it, D-8) and chains the earlier one behind for the fold's union. */ function touch(e, n) {
|
|
1450
|
+
let t = e.wk;
|
|
1451
|
+
if (!pendingNotify.has(e)) {
|
|
1452
|
+
pendingNotify.add(e);
|
|
1453
|
+
if (t !== null && t !== WK_ALL) {
|
|
1454
|
+
t = new Set;
|
|
1455
|
+
t.u = e.wk;
|
|
1456
|
+
e.wk = t;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if (t !== WK_ALL) (e.wk ??= new Set).add(n);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1432
1462
|
const traps = {
|
|
1433
1463
|
get(e, n, t) {
|
|
1434
1464
|
// One typeof gates every brand-symbol compare off the hot string path.
|
|
@@ -1472,7 +1502,7 @@ const traps = {
|
|
|
1472
1502
|
const r = e.n?.[n];
|
|
1473
1503
|
if (writeScopes === null && !writeOverride) {
|
|
1474
1504
|
const t = r;
|
|
1475
|
-
if (t !== undefined && t.acc !== true && (!e.ch || t.
|
|
1505
|
+
if (t !== undefined && t.acc !== true && (!e.ch || t.l & CONFIG_OVERRIDE)) {
|
|
1476
1506
|
const r = nodeValue(t, undefined, e);
|
|
1477
1507
|
if (r === null || typeof r !== "object") return r;
|
|
1478
1508
|
if (e.s) return serveShallow(e, n, r);
|
|
@@ -1567,9 +1597,9 @@ const traps = {
|
|
|
1567
1597
|
const i = read(r);
|
|
1568
1598
|
if (!e.ch || t !== e.v) return !!i;
|
|
1569
1599
|
const o = n in t;
|
|
1570
|
-
r.
|
|
1600
|
+
r.Ie = o;
|
|
1571
1601
|
// the link follows the inner store (S4)
|
|
1572
|
-
if (r.
|
|
1602
|
+
if (r.l & CONFIG_OVERRIDE) return !!i;
|
|
1573
1603
|
return o;
|
|
1574
1604
|
} else if (optRead(e)) {
|
|
1575
1605
|
const t = optHooks.has(e, n);
|
|
@@ -1604,7 +1634,7 @@ const traps = {
|
|
|
1604
1634
|
const t = getHasNode(e, n);
|
|
1605
1635
|
const r = read(t);
|
|
1606
1636
|
o = readSource(e, n, true);
|
|
1607
|
-
if (!r && (!e.ch || t.
|
|
1637
|
+
if (!r && (!e.ch || t.l & CONFIG_OVERRIDE || !(n in o))) return undefined;
|
|
1608
1638
|
} else o = readSource(e, n, true);
|
|
1609
1639
|
let l;
|
|
1610
1640
|
if (!i && optRead(e)) {
|
|
@@ -1620,20 +1650,29 @@ const traps = {
|
|
|
1620
1650
|
set(e, n, t) {
|
|
1621
1651
|
const r = inDraft(e);
|
|
1622
1652
|
const i = !r && writeOverride;
|
|
1623
|
-
if (!r && !i)
|
|
1653
|
+
if (!r && !i) {
|
|
1654
|
+
return true;
|
|
1655
|
+
}
|
|
1624
1656
|
if (n === "__proto__") return true;
|
|
1625
1657
|
// pollution guard (core R30)
|
|
1626
1658
|
const o = e.s ? t : unwrapValue(t);
|
|
1627
1659
|
const l = ensurePB(e);
|
|
1628
|
-
|
|
1660
|
+
// #4146 (R1: node existence is unobservable; #3706: the hold's unit is
|
|
1661
|
+
// the key): a user setter writing a key a HELD container's staging left
|
|
1662
|
+
// unchanged would write it into the held staging — read as the hold's
|
|
1663
|
+
// until its landing, while the same key with a leaf (a live reader)
|
|
1664
|
+
// publishes at the flush. The key gets its leaf first, born from the two
|
|
1665
|
+
// frames (`bornStaged`: a key the hold left unchanged — or added — is
|
|
1666
|
+
// unstaged and held by no one; a key the hold changed is born held, A34
|
|
1667
|
+
// (1)), and the write stages on it (A28; a write by the holder joins it,
|
|
1668
|
+
// A34) — as it would with a reader's leaf. Kept while the container is
|
|
1669
|
+
// held (`deferredReleases`).
|
|
1670
|
+
if (userWrite && e.k?.l & CONFIG_HELD) deferredReleases.add(getNode(e, n));
|
|
1629
1671
|
if (Array.isArray(l)) {
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
t.add(n);
|
|
1633
|
-
t.add("length");
|
|
1634
|
-
}
|
|
1672
|
+
touch(e, n);
|
|
1673
|
+
if (n === "length") e.wk = WK_ALL; else touch(e, "length");
|
|
1635
1674
|
} else {
|
|
1636
|
-
|
|
1675
|
+
touch(e, n);
|
|
1637
1676
|
if (!(n in l)) e.kc++;
|
|
1638
1677
|
}
|
|
1639
1678
|
if (UNSAFE_KEYS.has(n)) {
|
|
@@ -1662,7 +1701,9 @@ const traps = {
|
|
|
1662
1701
|
defineProperty(e, n, t) {
|
|
1663
1702
|
const r = inDraft(e);
|
|
1664
1703
|
const i = !r && writeOverride;
|
|
1665
|
-
if (!r && !i)
|
|
1704
|
+
if (!r && !i) {
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1666
1707
|
if (n === "__proto__") return true;
|
|
1667
1708
|
if (t.get || t.set) e.a = true;
|
|
1668
1709
|
if ("value" in t) t = {
|
|
@@ -1671,8 +1712,7 @@ const traps = {
|
|
|
1671
1712
|
};
|
|
1672
1713
|
const o = ensurePB(e);
|
|
1673
1714
|
if (e.a || !(t.enumerable && t.writable && t.configurable)) e.sc = 1;
|
|
1674
|
-
|
|
1675
|
-
if (e.wk !== WK_ALL) (e.wk ??= new Set).add(n);
|
|
1715
|
+
touch(e, n);
|
|
1676
1716
|
Object.defineProperty(o, n, t);
|
|
1677
1717
|
if (e.del !== null) e.del.delete(n);
|
|
1678
1718
|
if (i) notifyWrites(e);
|
|
@@ -1681,12 +1721,26 @@ const traps = {
|
|
|
1681
1721
|
deleteProperty(e, n) {
|
|
1682
1722
|
const t = inDraft(e);
|
|
1683
1723
|
const r = !t && writeOverride;
|
|
1684
|
-
if (!t && !r)
|
|
1724
|
+
if (!t && !r) {
|
|
1725
|
+
return true;
|
|
1726
|
+
}
|
|
1685
1727
|
const i = ensurePB(e);
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
delete
|
|
1689
|
-
|
|
1728
|
+
touch(e, n);
|
|
1729
|
+
// The key count (`kc`, the overlay gate and the rebuild cap) follows a
|
|
1730
|
+
// delete the way it follows an add: an own key of the draft leaving — a
|
|
1731
|
+
// clone's key, or an overlay's own add — is one fewer now. An overlay's
|
|
1732
|
+
// override of a committed key is the exception: the committed key's
|
|
1733
|
+
// deletion is recorded in `del` and counted at the rebuild, as before.
|
|
1734
|
+
// Without the decrement the natural "delete the old key, set the new
|
|
1735
|
+
// one" shape drifted the count up by one per write until a three-key
|
|
1736
|
+
// object crossed the overlay threshold and paid a rebuild on every
|
|
1737
|
+
// commit after.
|
|
1738
|
+
const o = e.ovl && hasOwn.call(e.v, n);
|
|
1739
|
+
if (hasOwn.call(i, n)) {
|
|
1740
|
+
delete i[n];
|
|
1741
|
+
o || e.kc--;
|
|
1742
|
+
}
|
|
1743
|
+
if (o) (e.del ??= new Set).add(n);
|
|
1690
1744
|
if (r) notifyWrites(e);
|
|
1691
1745
|
return true;
|
|
1692
1746
|
}
|
|
@@ -1697,11 +1751,12 @@ const traps = {
|
|
|
1697
1751
|
* to the key's presence node or a later add never re-runs it. */ function observerHoldsContainer(e, n) {
|
|
1698
1752
|
const t = e.k;
|
|
1699
1753
|
if (t === null) return false;
|
|
1700
|
-
const r = t.
|
|
1701
|
-
return r !== null && r.
|
|
1754
|
+
const r = t.ve;
|
|
1755
|
+
return r !== null && r.u === n && (!(n.R & REACTIVE_RECOMPUTING_DEPS) || r.Te === n.Ne);
|
|
1702
1756
|
}
|
|
1703
1757
|
|
|
1704
1758
|
function storeSetter(e, n, t = true) {
|
|
1759
|
+
if (writeHook !== null) writeHook(e);
|
|
1705
1760
|
const r = e[$TARGET];
|
|
1706
1761
|
const i = writeScopes;
|
|
1707
1762
|
writeScopes = new Set;
|
|
@@ -1755,6 +1810,8 @@ function storeSetter(e, n, t = true) {
|
|
|
1755
1810
|
function createStore(e, n) {
|
|
1756
1811
|
const t = n?.shallow === true;
|
|
1757
1812
|
const r = wrap(e);
|
|
1813
|
+
// Dependency edges (store/edges.ts): the root is named like a plain signal.
|
|
1814
|
+
if (signalHook !== null) signalHook(r[$TARGET]);
|
|
1758
1815
|
if (t) {
|
|
1759
1816
|
r[$TARGET].s = true;
|
|
1760
1817
|
markRawIngest(e);
|
|
@@ -1885,7 +1942,7 @@ function snapshotWalk(e, n, t) {
|
|
|
1885
1942
|
// R27: a snapshot sees the batch's pending backing — a held one (another
|
|
1886
1943
|
// transaction's future) only from its own draft.
|
|
1887
1944
|
let o = i.v;
|
|
1888
|
-
if (i.pb !== null && (inDraft(i) || writeOverride || i.k === null || !(i.k.
|
|
1945
|
+
if (i.pb !== null && (inDraft(i) || writeOverride || i.k === null || !(i.k.l & CONFIG_HELD))) {
|
|
1889
1946
|
if (i.ovl) materializePB(i);
|
|
1890
1947
|
o = i.pb;
|
|
1891
1948
|
}
|