@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.4
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 +1454 -118
- package/dist/node.cjs +2709 -1396
- package/dist/prod/affects.js +13 -12
- package/dist/prod/boundaries.js +39 -34
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +48 -46
- package/dist/prod/core/core.js +99 -67
- package/dist/prod/core/effect.js +25 -28
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +85 -49
- package/dist/prod/core/heap.js +10 -10
- package/dist/prod/core/lanes.js +19 -19
- package/dist/prod/core/optimistic.js +66 -41
- package/dist/prod/core/owner.js +13 -13
- package/dist/prod/core/scheduler.js +131 -85
- package/dist/prod/core/verdict.js +36 -15
- package/dist/prod/index.js +4 -0
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/index.js +2 -0
- package/dist/prod/store/next/optimistic.js +65 -11
- package/dist/prod/store/next/patch-hooks.js +13 -0
- package/dist/prod/store/next/patch.js +614 -0
- package/dist/prod/store/next/projection.js +107 -45
- package/dist/prod/store/next/reconcile.js +307 -120
- package/dist/prod/store/next/store.js +321 -92
- package/dist/prod/store/next/target.js +13 -4
- package/dist/prod/store/store.js +5 -5
- package/dist/types/core/core.d.ts +15 -1
- package/dist/types/core/dev.d.ts +8 -0
- package/dist/types/core/graph.d.ts +22 -0
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/scheduler.d.ts +12 -0
- package/dist/types/store/index.d.ts +2 -0
- package/dist/types/store/next/patch-hooks.d.ts +41 -0
- package/dist/types/store/next/patch.d.ts +91 -0
- package/dist/types/store/next/reconcile.d.ts +14 -0
- package/dist/types/store/next/store.d.ts +30 -2
- package/dist/types/store/next/target.d.ts +58 -8
- package/dist/types-cjs/core/core.d.cts +15 -1
- package/dist/types-cjs/core/dev.d.cts +8 -0
- package/dist/types-cjs/core/graph.d.cts +22 -0
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/dist/types-cjs/core/scheduler.d.cts +12 -0
- package/dist/types-cjs/store/index.d.cts +2 -0
- package/dist/types-cjs/store/next/patch-hooks.d.cts +41 -0
- package/dist/types-cjs/store/next/patch.d.cts +91 -0
- package/dist/types-cjs/store/next/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/next/store.d.cts +30 -2
- package/dist/types-cjs/store/next/target.d.cts +58 -8
- package/package.json +14 -14
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { unwrapOverride, $REFRESH, CONFIG_OWNED_WRITE, NOT_PENDING, CONFIG_OPTIMISTIC, STATUS_UNINITIALIZED, STATUS_ERROR, CONFIG_CHILDREN_FORBIDDEN } from "../../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { setSignal, isEqual, read, pendingCheckActive, readNodeFast, READ_SLOW, signal, ext } from "../../core/core.js";
|
|
3
|
+
import { setSignal, isEqual, read, pendingCheckActive, latestReadActive, readNodeFast, READ_SLOW, signal, ext, setLatestReadActive, prepareComputed } from "../../core/core.js";
|
|
4
4
|
|
|
5
|
-
import { projectionWriteActive, setProjectionWriteActive, schedule, setStoreCommitHook } from "../../core/scheduler.js";
|
|
5
|
+
import { projectionWriteActive, setProjectionWriteActive, activeTransition, schedule, currentTransition, setStoreCommitHook } from "../../core/scheduler.js";
|
|
6
6
|
|
|
7
7
|
import { getObserver, getOwner } from "../../core/owner.js";
|
|
8
8
|
|
|
9
9
|
import { $TARGET, isWrappable, markRawIngest, $PROXY, getWriteOverride, markRawOne, witnessAffectsMark, $TRACK, affectsScopesLive, inheritAffectsMarks, $AFFECTS, rawValuesUsed, isRawValue, setNextAffectsNodeResolver } from "../store.js";
|
|
10
10
|
|
|
11
|
-
import { storeNextLookup, optHooks, ownedRaw, devAssertNeverUserMutation } from "./target.js";
|
|
11
|
+
import { storeNextLookup, optHooks, ownedRaw, markDescendants, devAssertNeverUserMutation } from "./target.js";
|
|
12
|
+
|
|
13
|
+
import { patchHooks, rowHooks } from "./patch-hooks.js";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Store rewrite — increment 2: plain deep stores with pending-backing writes.
|
|
@@ -38,8 +40,13 @@ import { storeNextLookup, optHooks, ownedRaw, devAssertNeverUserMutation } from
|
|
|
38
40
|
* headroom for future fields. The prototype is reset to `Object.prototype`
|
|
39
41
|
* so proxy-forwarded semantics (getPrototypeOf, constructor) are exactly a
|
|
40
42
|
* plain object's. Array targets keep the bare-`[]` path — they must carry
|
|
41
|
-
* the array exotic class for `Array.isArray(proxy)
|
|
42
|
-
*
|
|
43
|
+
* the array exotic class for `Array.isArray(proxy)`.
|
|
44
|
+
*
|
|
45
|
+
* ARRAY SHAPE RULE: arrays normalize their named properties to dictionary
|
|
46
|
+
* mode as the count grows (V8 13.x: counts ≡ 0 mod 3 from 18 up), so the
|
|
47
|
+
* target's named field count is capped at 20 — write-side patch-channel
|
|
48
|
+
* state lives inside the single `pc` extension (see target.ts), never as
|
|
49
|
+
* new named fields here. */
|
|
43
50
|
function TargetShape() {
|
|
44
51
|
this.v = undefined;
|
|
45
52
|
this.ch = undefined;
|
|
@@ -60,11 +67,24 @@ function TargetShape() {
|
|
|
60
67
|
this.s = undefined;
|
|
61
68
|
this.ovl = undefined;
|
|
62
69
|
this.del = undefined;
|
|
63
|
-
this.
|
|
70
|
+
this.pc = undefined;
|
|
71
|
+
this.hv = undefined;
|
|
72
|
+
this.ht = undefined;
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
TargetShape.prototype = Object.prototype;
|
|
67
76
|
|
|
77
|
+
/** Lazily allocate the patch-channel extension (one literal shape). */ function pcOf(e) {
|
|
78
|
+
return e.pc ?? (e.pc = {
|
|
79
|
+
sp: null,
|
|
80
|
+
p: null,
|
|
81
|
+
ro: null,
|
|
82
|
+
wk: null,
|
|
83
|
+
qa: null,
|
|
84
|
+
qe: null
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
68
88
|
function createTarget(e, t, n, r = t?.fam ?? null) {
|
|
69
89
|
// The proxy target carries the array exotic class when the value is an
|
|
70
90
|
// array, so Array.isArray(proxy) is true; the fields live on it directly.
|
|
@@ -81,6 +101,7 @@ function createTarget(e, t, n, r = t?.fam ?? null) {
|
|
|
81
101
|
i.h = null;
|
|
82
102
|
i.k = null;
|
|
83
103
|
i.dk = null;
|
|
104
|
+
i.pc = null;
|
|
84
105
|
i.u = t;
|
|
85
106
|
i.pk = n;
|
|
86
107
|
i.px = null;
|
|
@@ -93,7 +114,8 @@ function createTarget(e, t, n, r = t?.fam ?? null) {
|
|
|
93
114
|
i.s = false;
|
|
94
115
|
i.ovl = false;
|
|
95
116
|
i.del = null;
|
|
96
|
-
i.
|
|
117
|
+
i.hv = null;
|
|
118
|
+
i.ht = null;
|
|
97
119
|
i.px = new Proxy(i, traps);
|
|
98
120
|
// Legacy interop: shared machinery (affects walks, wrap dedupe) reads the
|
|
99
121
|
// proxy off looked-up targets as a field.
|
|
@@ -260,14 +282,6 @@ function getDeepNode(e) {
|
|
|
260
282
|
if (e.dk !== null) setSignal(e.dk, 1);
|
|
261
283
|
}
|
|
262
284
|
|
|
263
|
-
function markDescendants(e) {
|
|
264
|
-
let t = e;
|
|
265
|
-
while (t && !t.d) {
|
|
266
|
-
t.d = true;
|
|
267
|
-
t = t.u;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
285
|
// ---------------------------------------------------------------------------
|
|
272
286
|
// pending backing + fold (the single mutation point)
|
|
273
287
|
/** target → committed backing at batch start (the fold diff's old side). */ const foldOlds = new Map;
|
|
@@ -291,6 +305,12 @@ function cloneRaw(e, t) {
|
|
|
291
305
|
return Array.isArray(e) ? Object.defineProperties([], n) : Object.create(Object.getPrototypeOf(e), n);
|
|
292
306
|
}
|
|
293
307
|
|
|
308
|
+
/** Scanned plainness for patch admission (patchableRaw): runs the one-time
|
|
309
|
+
* accessor scan if it hasn't happened yet — the sticky `a` flag alone is not
|
|
310
|
+
* trustworthy before a scan (it starts false and is discovered lazily). */ function targetIsPlain(e) {
|
|
311
|
+
return e.sc ? !e.a : scanAccessorsOnce(e);
|
|
312
|
+
}
|
|
313
|
+
|
|
294
314
|
/** One-time own-accessor scan (Annex-B probes, no descriptor allocation);
|
|
295
315
|
* returns true when the container is plain data (overlay-safe). */ function scanAccessorsOnce(e) {
|
|
296
316
|
const t = e.v;
|
|
@@ -330,6 +350,7 @@ function cloneRaw(e, t) {
|
|
|
330
350
|
}
|
|
331
351
|
|
|
332
352
|
function ensurePB(e) {
|
|
353
|
+
if (activeTransition !== null) foldBatches.set(e, activeTransition);
|
|
333
354
|
let t = e.pb;
|
|
334
355
|
if (t === null) {
|
|
335
356
|
// Prototype-chain overlay (#3044): plain-data non-array containers
|
|
@@ -370,6 +391,25 @@ function ensurePB(e) {
|
|
|
370
391
|
return t;
|
|
371
392
|
}
|
|
372
393
|
|
|
394
|
+
/** Sentinel holder for `t.ht`: a latest()-pull staged this adoption outside
|
|
395
|
+
* any transition — the hold lasts until the fold commit (drainFolds). */ const PLAIN_HOLD = Symbol("plainHold");
|
|
396
|
+
|
|
397
|
+
/** True while a latest() read is pulling the projection computed up to date
|
|
398
|
+
* (see the get trap): adoptions landing during the pull are speculative
|
|
399
|
+
* against the un-flushed batch and stage a held view. (Not injectable — the
|
|
400
|
+
* derived createStore overload retains projection machinery in every store
|
|
401
|
+
* bundle, see treeshake.test.ts.) */ let latestPullActive = false;
|
|
402
|
+
|
|
403
|
+
/** Resolve the held committed view (#3074): answers the masked old backing
|
|
404
|
+
* while the hold is live, and lazily clears a hold whose transition has
|
|
405
|
+
* committed (transitions merge — resolve through currentTransition, same as
|
|
406
|
+
* foldHeld's node stamps). */ function heldMaskView(e) {
|
|
407
|
+
const t = e.ht;
|
|
408
|
+
if (t === null) return null;
|
|
409
|
+
if (t !== PLAIN_HOLD && currentTransition(t)?.fn === true) return e.ht = e.hv = null;
|
|
410
|
+
return e.hv;
|
|
411
|
+
}
|
|
412
|
+
|
|
373
413
|
/**
|
|
374
414
|
* Adoption (2026-08-16c): the incoming object becomes the committed backing
|
|
375
415
|
* IMMEDIATELY — reconcile is eagerly visible to every reader (shipped
|
|
@@ -385,6 +425,20 @@ function ensurePB(e) {
|
|
|
385
425
|
queueFold(e);
|
|
386
426
|
// records the pre-batch old before we swap
|
|
387
427
|
e.adopted = true;
|
|
428
|
+
// #3074/#3075: a projection recompute deriving from uncommitted inputs
|
|
429
|
+
// swaps the backing SPECULATIVELY — committed-visibility readers must
|
|
430
|
+
// keep the pre-hold view until the hold resolves (a source held by a
|
|
431
|
+
// live transition, or a latest()-pull ahead of the flush). Post-await
|
|
432
|
+
// landings (write-override) stay immediately visible — landed truth —
|
|
433
|
+
// and clear any hold; optimistic families ride the lane machinery.
|
|
434
|
+
if (e.fam?.opt !== true) {
|
|
435
|
+
if (getWriteOverride()) {
|
|
436
|
+
e.ht = e.hv = null;
|
|
437
|
+
} else if (activeTransition !== null || latestPullActive) {
|
|
438
|
+
if (heldMaskView(e) === null) e.hv = e.v;
|
|
439
|
+
e.ht = activeTransition ?? PLAIN_HOLD;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
388
442
|
}
|
|
389
443
|
e.pb = null;
|
|
390
444
|
// Overlay and accessor-scan state describe the OUTGOING backing — a
|
|
@@ -396,28 +450,47 @@ function ensurePB(e) {
|
|
|
396
450
|
// draft rescans once (#3044 audit follow-up).
|
|
397
451
|
e.ovl = false;
|
|
398
452
|
e.del = null;
|
|
399
|
-
e.
|
|
400
|
-
// adoption supersedes any staged trap writes
|
|
401
|
-
e.sc = false;
|
|
453
|
+
e.sc = false;
|
|
402
454
|
e.a = false;
|
|
403
|
-
e.
|
|
455
|
+
if (e.pc !== null) e.pc.wk = null;
|
|
456
|
+
// adoption supersedes staged trap writes
|
|
457
|
+
e.v = t;
|
|
404
458
|
e.ch = t[$TARGET] !== undefined;
|
|
405
459
|
(e.fam?.map ?? storeNextLookup).set(t, e);
|
|
406
460
|
}
|
|
407
461
|
|
|
462
|
+
/** Sentinel for `t.wk`: the written-keys bound is unusable this batch (an
|
|
463
|
+
* array length write implicitly deleted indices) — consumers full-scan. */ const WK_ALL = new Set;
|
|
464
|
+
|
|
465
|
+
const plainProto = e => {
|
|
466
|
+
const t = Object.getPrototypeOf(e);
|
|
467
|
+
return t === Object.prototype || t === Array.prototype || t === null;
|
|
468
|
+
};
|
|
469
|
+
|
|
408
470
|
function queueFold(e) {
|
|
409
471
|
if (foldOlds.has(e)) return;
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
472
|
+
if (!hookInstalled) {
|
|
473
|
+
hookInstalled = true;
|
|
474
|
+
setStoreCommitHook(drainFolds);
|
|
475
|
+
}
|
|
476
|
+
// Always arm — "map non-empty ⇒ drain scheduled" is NOT an invariant: a
|
|
477
|
+
// held re-queue, or an incomplete-transition flush (which skips
|
|
478
|
+
// commitPendingNodes entirely), leaves entries behind after `scheduled`
|
|
479
|
+
// was consumed. A size-gated arm then strands every LATER fold — queued
|
|
480
|
+
// silently, never drained, committed base frozen at stale state while its
|
|
481
|
+
// nodes commit (#3089). schedule() early-returns when already armed.
|
|
415
482
|
schedule();
|
|
416
|
-
// once per batch — drain clears the map
|
|
417
|
-
}
|
|
418
483
|
foldOlds.set(e, e.v);
|
|
419
484
|
}
|
|
420
485
|
|
|
486
|
+
/** Fold write-attribution (#3089): a draft written while a transition is
|
|
487
|
+
* active belongs to that transition — its fold must not commit before the
|
|
488
|
+
* transition settles. Observed keys already defer through the held check in
|
|
489
|
+
* drainFolds (their nodes carry _pendingValue); this write-time stamp is the
|
|
490
|
+
* equivalent hold for UNOBSERVED keys, which have no node to consult.
|
|
491
|
+
* Refreshed on every write; resolved through currentTransition at drain
|
|
492
|
+
* (transitions merge — same rule as heldMaskView). */ const foldBatches = new WeakMap;
|
|
493
|
+
|
|
421
494
|
/** Committed-time privatization for parent-chain slot updates (path copying). */ function privatizeCommitted(e) {
|
|
422
495
|
if (ownedRaw.has(e.v)) return;
|
|
423
496
|
const t = cloneRaw(e.v, e);
|
|
@@ -437,29 +510,52 @@ function drainFolds() {
|
|
|
437
510
|
const e = [ ...foldOlds ];
|
|
438
511
|
foldOlds.clear();
|
|
439
512
|
for (const [t, n] of e) {
|
|
513
|
+
// A latest()-pull staging holds only until the fold commit: this flush
|
|
514
|
+
// is committing the batch the pull ran ahead of. Transition holds stay —
|
|
515
|
+
// they clear when their transition is done (heldMaskView).
|
|
516
|
+
if (t.ht === PLAIN_HOLD) t.ht = t.hv = null;
|
|
517
|
+
// Eager (write-override) family folds swap pb -> v at notifyWrites'
|
|
518
|
+
// tail: by the time this drain runs they carry no pb, and their
|
|
519
|
+
// structural ops must emit at the fold-commit site below (the clone
|
|
520
|
+
// branch never sees them). Re-audit blocker 4.
|
|
521
|
+
const e = t.pb === null;
|
|
440
522
|
if (t.pb !== null) {
|
|
523
|
+
// #3089: a fold written under a still-running transition defers to
|
|
524
|
+
// that transition's settle (the write-time stamp covers unobserved
|
|
525
|
+
// keys; observed keys also hit the pending-node held check below).
|
|
526
|
+
const e = foldBatches.get(t);
|
|
527
|
+
if (e !== undefined) {
|
|
528
|
+
if (currentTransition(e).fn === false) {
|
|
529
|
+
foldOlds.set(t, n);
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
foldBatches.delete(t);
|
|
533
|
+
}
|
|
441
534
|
// Setter path: nodes were setSignal'd at setter exit (write-time
|
|
442
535
|
// notification — transitions/holds ride core machinery). Commit the
|
|
443
536
|
// backing only for keys whose nodes have committed; a still-pending
|
|
444
537
|
// node (transition-held) re-queues the target for the settling flush.
|
|
445
|
-
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
if (
|
|
538
|
+
let r = false;
|
|
539
|
+
const i = t.pb;
|
|
540
|
+
const o = t.n;
|
|
541
|
+
if (o !== null) {
|
|
449
542
|
// Only written keys can hold (their nodes took the setSignal); the
|
|
450
543
|
// wk bound keeps this O(written) — see notifyWrites. Same fallback
|
|
451
544
|
// rules as the notify (WK_ALL / accessors / non-plain prototypes).
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
545
|
+
const e = t.pc !== null ? t.pc.wk : null;
|
|
546
|
+
const n = e === null || e === WK_ALL || t.a === true ||
|
|
547
|
+
// Overlay pbs chain to the COMMITTED object (#3044) — plainness is
|
|
548
|
+
// the committed container's prototype, not the overlay's.
|
|
549
|
+
!plainProto(t.ovl ? t.v : i) ? Reflect.ownKeys(o) : e;
|
|
550
|
+
for (const e of n) {
|
|
551
|
+
const t = o[e];
|
|
552
|
+
if (t !== undefined && t.Pe !== NOT_PENDING) {
|
|
553
|
+
r = true;
|
|
458
554
|
break;
|
|
459
555
|
}
|
|
460
556
|
}
|
|
461
557
|
}
|
|
462
|
-
if (
|
|
558
|
+
if (r) {
|
|
463
559
|
foldOlds.set(t, n);
|
|
464
560
|
// re-queue: commit happens when the hold settles
|
|
465
561
|
continue;
|
|
@@ -474,30 +570,68 @@ function drainFolds() {
|
|
|
474
570
|
// — the never-mutate-user-data contract holds.
|
|
475
571
|
privatizeCommitted(t);
|
|
476
572
|
const e = t.v;
|
|
477
|
-
for (const t of Reflect.ownKeys(
|
|
478
|
-
const n = Object.getOwnPropertyDescriptor(
|
|
573
|
+
for (const t of Reflect.ownKeys(i)) {
|
|
574
|
+
const n = Object.getOwnPropertyDescriptor(i, t);
|
|
479
575
|
if (n.get || n.set || !n.enumerable || !n.writable || !n.configurable) Object.defineProperty(e, t, n); else e[t] = n.value;
|
|
480
576
|
}
|
|
481
577
|
if (t.del !== null) {
|
|
482
578
|
for (const n of t.del) delete e[n];
|
|
483
579
|
t.del = null;
|
|
484
580
|
}
|
|
485
|
-
(t.fam?.map ?? storeNextLookup).delete(
|
|
581
|
+
(t.fam?.map ?? storeNextLookup).delete(i);
|
|
486
582
|
t.pb = null;
|
|
487
583
|
t.ovl = false;
|
|
488
|
-
t.wk = null;
|
|
584
|
+
if (t.pc !== null) t.pc.wk = null;
|
|
489
585
|
// written-keys window closes with the fold commit
|
|
490
586
|
} else {
|
|
491
|
-
|
|
587
|
+
// Setter-channel structural ops: a fold that changes an array's shape
|
|
588
|
+
// (push/splice/permutation through the setter — the reconcile walk
|
|
589
|
+
// never queues here) is a structural visibility transition for any
|
|
590
|
+
// registered list driver. Identity-keyed; aligned folds emit nothing.
|
|
591
|
+
// Family targets defer to their own adoption emission (fam reconcile).
|
|
592
|
+
// Arrays always fold on this clone branch (overlay is non-array only).
|
|
593
|
+
// Family setter drafts (writable projection push/splice through the
|
|
594
|
+
// masked setter) fold on this branch too and the fold IS their
|
|
595
|
+
// visibility moment — emit unless the structure already rode another
|
|
596
|
+
// channel: adoption folds (reconcile walk emitted ops) and
|
|
597
|
+
// optimistic families (lane-timed override channel). Re-audit
|
|
598
|
+
// blocker 4.
|
|
599
|
+
if (t.pc !== null && t.pc.ro !== null && !t.adopted && t.fam?.opt !== true && Array.isArray(i) && Array.isArray(t.v)) rowHooks.emitSetterRowOps(t, t.v, i);
|
|
600
|
+
t.v = i;
|
|
492
601
|
t.ch = false;
|
|
493
602
|
// pb is always a plain clone
|
|
494
603
|
t.pb = null;
|
|
495
|
-
t.wk = null;
|
|
604
|
+
if (t.pc !== null) t.pc.wk = null;
|
|
496
605
|
// written-keys window closes with the fold commit
|
|
497
606
|
}
|
|
498
607
|
}
|
|
499
|
-
if (t.v === n)
|
|
500
|
-
|
|
608
|
+
if (t.v === n) {
|
|
609
|
+
// A no-op adoption (A -> B -> A before flush) still consumed its walk:
|
|
610
|
+
// clear the flag or every later setter row-op gate (!t.adopted) stays
|
|
611
|
+
// failed and a driven family list freezes (re-audit 5, P1-1).
|
|
612
|
+
t.adopted = false;
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
// Patch channel (fold-commit site): family targets emit HERE — the fold
|
|
616
|
+
// IS their visibility moment (held folds re-queued above emit when they
|
|
617
|
+
// actually commit) — and so do PLAIN fold-adopted targets (setter-
|
|
618
|
+
// returned root replacements, chained-store swaps: adoptions WITHOUT a
|
|
619
|
+
// reconcile walk, so no walk-site emission ever happened — re-audit 2,
|
|
620
|
+
// P1-2). Plain eager targets emitted at their walk/setter sites already.
|
|
621
|
+
if (t.pc !== null && (t.fam !== null || t.adopted)) {
|
|
622
|
+
// Structural ops for folds whose structure rode no other channel:
|
|
623
|
+
// eager-folded family SETTER drafts (write-override swaps pb -> v at
|
|
624
|
+
// notifyWrites' tail — the clone branch never sees them; adoption
|
|
625
|
+
// folds re-emitting would double the walk's ops) and PLAIN fold
|
|
626
|
+
// adoptions (no walk at all). Optimistic families ride the override
|
|
627
|
+
// channel (lane-timed ops + revert RESYNC) — never re-emit here.
|
|
628
|
+
if (t.pc.ro !== null && t.fam?.opt !== true && (t.fam !== null ? e && !t.adopted : t.adopted) && Array.isArray(t.v) && Array.isArray(n)) rowHooks.emitSetterRowOps(t, n, t.v);
|
|
629
|
+
if (t.pc.p !== null) {
|
|
630
|
+
// Accessor demotion at the fold-commit seam is DEV-ONLY (see the
|
|
631
|
+
// reconcile seam note: prod never pays per-adoption scans).
|
|
632
|
+
patchHooks.emitPatchLocal(t, t.v, n);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
501
635
|
// Path copying (CAS: see the eager-fold twin above).
|
|
502
636
|
if (t.u && t.u.v[t.pk] === n) {
|
|
503
637
|
privatizeCommitted(t.u);
|
|
@@ -518,19 +652,7 @@ function drainFolds() {
|
|
|
518
652
|
* isPending, affects, and lane machinery ride the core natively (§3's
|
|
519
653
|
* "pending home = the node when a node exists"). Unobserved keys stay in the
|
|
520
654
|
* pending backing and fold directly at commit.
|
|
521
|
-
*/
|
|
522
|
-
/** Sentinel for `t.wk`: the written-keys bound is unusable this batch (an
|
|
523
|
-
* array length write implicitly deleted indices) — consumers full-scan. */ const WK_ALL = new Set;
|
|
524
|
-
|
|
525
|
-
/** Plain-prototype check for the written-keys bound: prototype getters on
|
|
526
|
-
* class instances can derive from ANY field, so only plain-data containers
|
|
527
|
-
* may bound the notify to written keys. Overlay pbs chain to the COMMITTED
|
|
528
|
-
* object (#3044), so overlay plainness is judged on the committed proto. */ const plainProto = e => {
|
|
529
|
-
const t = Object.getPrototypeOf(e);
|
|
530
|
-
return t === Object.prototype || t === Array.prototype || t === null;
|
|
531
|
-
};
|
|
532
|
-
|
|
533
|
-
function notifyWrites(e) {
|
|
655
|
+
*/ function notifyWrites(e) {
|
|
534
656
|
let t = e.pb;
|
|
535
657
|
if (t === null) return;
|
|
536
658
|
// Optimistic channel: user writes on an optimistic family become node-level
|
|
@@ -567,9 +689,16 @@ function notifyWrites(e) {
|
|
|
567
689
|
// not a full scan). Falls back to the full node scan when the bound can't
|
|
568
690
|
// hold: no trap granularity (wk null), an array length write (WK_ALL —
|
|
569
691
|
// implicit index deletes), accessors on the record (t.a — a getter node's
|
|
570
|
-
// value can change when ANY key is written), or a non-plain prototype
|
|
571
|
-
|
|
572
|
-
|
|
692
|
+
// value can change when ANY key is written), or a non-plain prototype
|
|
693
|
+
// (class instances: prototype getters derive from arbitrary fields).
|
|
694
|
+
const i = e.pc !== null ? e.pc.wk : null;
|
|
695
|
+
// Overlay pbs chain to the COMMITTED object (#3044): a prototype-overlay
|
|
696
|
+
// draft is plain data on its own layer, but its getPrototypeOf is the
|
|
697
|
+
// committed container — judge plainness by the COMMITTED prototype or the
|
|
698
|
+
// bound never engages for overlay writes (every plain-object setter batch
|
|
699
|
+
// would full-scan: the exact selection-map workload wk exists for; jf
|
|
700
|
+
// `select` regressed 2x on this).
|
|
701
|
+
const o = i === WK_ALL || e.a === true || !plainProto(e.ovl ? e.v : t) ? null : i;
|
|
573
702
|
if (r !== null) {
|
|
574
703
|
const i = o ?? Reflect.ownKeys(r);
|
|
575
704
|
for (const o of i) {
|
|
@@ -600,12 +729,16 @@ function notifyWrites(e) {
|
|
|
600
729
|
}
|
|
601
730
|
const f = e.h;
|
|
602
731
|
if (f !== null) {
|
|
603
|
-
|
|
732
|
+
const n = o ?? Reflect.ownKeys(f);
|
|
733
|
+
for (const r of n) {
|
|
734
|
+
const n = f[r];
|
|
735
|
+
if (n !== undefined) setSignal(n, r in t && !(e.del !== null && e.del.has(r)));
|
|
736
|
+
}
|
|
604
737
|
}
|
|
605
738
|
// Deep-witness (dk): setter writes must notify a deep() subscriber even on
|
|
606
|
-
// keys with no node. O(pb keys) equality only when a witness exists.
|
|
739
|
+
// keys with no node. O(written/pb keys) equality only when a witness exists.
|
|
607
740
|
if (e.dk !== null) {
|
|
608
|
-
if (e.del !== null && e.del.size !== 0) bumpDeep(e); else for (const r of Reflect.ownKeys(t)) {
|
|
741
|
+
if (e.del !== null && e.del.size !== 0) bumpDeep(e); else for (const r of o ?? Reflect.ownKeys(t)) {
|
|
609
742
|
const i = t[r];
|
|
610
743
|
const o = n[r];
|
|
611
744
|
if (i !== null && typeof i === "object" ? !targetsEqual(o, i) : !isEqual(o, i)) {
|
|
@@ -632,6 +765,12 @@ function notifyWrites(e) {
|
|
|
632
765
|
}
|
|
633
766
|
if (r) setSignal(e.k, e => e + 1);
|
|
634
767
|
}
|
|
768
|
+
// Patch channel (setter site): a committed write transitions this record —
|
|
769
|
+
// queue its patches and bubble to ancestors (targeted nested writes must
|
|
770
|
+
// reach the row patch, §4b). One number compare when no patches exist.
|
|
771
|
+
// Family targets skip this site: their visibility moment is the FOLD
|
|
772
|
+
// commit (drainFolds emits), not the recompute/draft write.
|
|
773
|
+
if (e.fam === null && patchHooks !== null && patchHooks.hasPatches()) patchHooks.emitPatch(e, t, n);
|
|
635
774
|
// Projection backing folds split by channel (two pinned contracts):
|
|
636
775
|
// - sync-derive drafts (recompute body): NEVER eager — a downstream async
|
|
637
776
|
// hold can form LATER in the same flush and the leaf must stay at stale
|
|
@@ -643,11 +782,12 @@ function notifyWrites(e) {
|
|
|
643
782
|
// downstream consumer's own async still holds the effect-level reveal
|
|
644
783
|
// (spec-async "verdicts never inherit consumers' in-flight state").
|
|
645
784
|
if (e.fam !== null && e.pb !== null && getWriteOverride()) {
|
|
785
|
+
// Landed truth (post-await write-override): immediately visible to every
|
|
786
|
+
// reader — any staged held view is superseded.
|
|
787
|
+
if (e.ht !== null) e.ht = e.hv = null;
|
|
646
788
|
const n = e.v;
|
|
647
789
|
e.pb = null;
|
|
648
|
-
e.
|
|
649
|
-
// written-keys window closes with the eager fold
|
|
650
|
-
e.v = t;
|
|
790
|
+
e.v = t;
|
|
651
791
|
e.ch = false;
|
|
652
792
|
if (e.u && e.u.v[e.pk] === n) {
|
|
653
793
|
privatizeCommitted(e.u);
|
|
@@ -710,8 +850,8 @@ i = true) {
|
|
|
710
850
|
return;
|
|
711
851
|
}
|
|
712
852
|
const f = i?.value;
|
|
713
|
-
const
|
|
714
|
-
if (!isEqual(f,
|
|
853
|
+
const l = o?.value;
|
|
854
|
+
if (!isEqual(f, l) && !targetsEqual(f, l)) setSignal(e, typeof l === "function" ? () => l : l);
|
|
715
855
|
} else {
|
|
716
856
|
const i = n[t];
|
|
717
857
|
const o = r[t];
|
|
@@ -840,6 +980,17 @@ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
|
840
980
|
return t != null && !(t.T & CONFIG_CHILDREN_FORBIDDEN);
|
|
841
981
|
}
|
|
842
982
|
|
|
983
|
+
/** CHILDREN_FORBIDDEN execution scope (createTrackedEffect / onSettled
|
|
984
|
+
* callbacks). Distinct from context-free: these scopes get committed
|
|
985
|
+
* visibility even against a projection's authoritative-elect pending
|
|
986
|
+
* backing (#3082) — parity with signals, where core read() serves
|
|
987
|
+
* committed to them regardless of staged writes. */ function inForbiddenScope() {
|
|
988
|
+
const e = getOwner();
|
|
989
|
+
if (e === null) return false;
|
|
990
|
+
const t = e.Ct ? e.Ot : e;
|
|
991
|
+
return t != null && !!(t.T & CONFIG_CHILDREN_FORBIDDEN);
|
|
992
|
+
}
|
|
993
|
+
|
|
843
994
|
/** A pending fold is transition-held when any written node's parked value is
|
|
844
995
|
* stamped by a live transition (a plain batch parking — the lazy-recompute
|
|
845
996
|
* read case — has no transition stamp and serves fresh). */ function foldHeld(e) {
|
|
@@ -847,23 +998,33 @@ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
|
847
998
|
if (t === null) return false;
|
|
848
999
|
for (const e of Reflect.ownKeys(t)) {
|
|
849
1000
|
const n = t[e];
|
|
850
|
-
if (n.Pe !== NOT_PENDING && n._e != null && n._e.
|
|
1001
|
+
if (n.Pe !== NOT_PENDING && n._e != null && n._e.fn !== true) return true;
|
|
851
1002
|
}
|
|
852
1003
|
return false;
|
|
853
1004
|
}
|
|
854
1005
|
|
|
855
1006
|
function readSource(e) {
|
|
1007
|
+
// Held view first (#3074): an adoption staged under a live hold serves the
|
|
1008
|
+
// pre-hold committed backing to committed-visibility readers. Speculative
|
|
1009
|
+
// readers — drafts, write-override, owner-context computeds recomputing
|
|
1010
|
+
// inside the transaction, and latest() reads — see the adopted backing.
|
|
1011
|
+
if (e.ht !== null && !latestReadActive && !inDraft(e) && !getWriteOverride() && !inOwnerContext()) {
|
|
1012
|
+
const t = heldMaskView(e);
|
|
1013
|
+
if (t !== null) return t;
|
|
1014
|
+
}
|
|
856
1015
|
// Signal-parity visibility (core read(): owner-context reads serve
|
|
857
1016
|
// _pendingValue, context-free reads serve committed — effects recompute
|
|
858
1017
|
// BEFORE commitPendingNodes in the flush, so the pending view must be
|
|
859
1018
|
// servable). Drafts (setter window OR projection write-override) and
|
|
860
1019
|
// owner-context reads see the pending backing; context-free reads see
|
|
861
1020
|
// committed. Node reads apply the same rule, so both homes agree.
|
|
862
|
-
|
|
1021
|
+
if (e.pb !== null && (inDraft(e) || getWriteOverride() || inOwnerContext() ||
|
|
863
1022
|
// A projection's pending backing is authoritative-elect: serve it to
|
|
864
1023
|
// context-free readers too UNLESS a transition is holding the node
|
|
865
|
-
// commits (downstream async hold — stale committed is the contract)
|
|
866
|
-
|
|
1024
|
+
// commits (downstream async hold — stale committed is the contract)
|
|
1025
|
+
// or the reader is a CHILDREN_FORBIDDEN scope, which never observes
|
|
1026
|
+
// its own unsettled write (#3082, signal parity per #3006).
|
|
1027
|
+
e.fam !== null && !foldHeld(e) && !inForbiddenScope())) return e.pb;
|
|
867
1028
|
return e.v;
|
|
868
1029
|
}
|
|
869
1030
|
|
|
@@ -906,7 +1067,9 @@ function isOwnAccessor(e, t) {
|
|
|
906
1067
|
* reader that forced it (backing commits eagerly; node values fold at flush).
|
|
907
1068
|
* FORCE sentinels never surface (they only bump subscribers of accessor
|
|
908
1069
|
* keys, which are served by the trap, not the node). */ function nodeValue(e, t) {
|
|
909
|
-
|
|
1070
|
+
// latest() sees the in-flight parked value like an owner-context reader
|
|
1071
|
+
// does (#3075) — signal/memo parity for store-node-backed keys.
|
|
1072
|
+
const n = hasActiveOverride(e) ? unwrapOverride(e.o?.De) : e.Pe !== NOT_PENDING && (latestReadActive || inOwnerContext()) ? e.Pe : t;
|
|
910
1073
|
return n === FORCE ? t : n;
|
|
911
1074
|
}
|
|
912
1075
|
|
|
@@ -995,6 +1158,27 @@ function isOwnAccessor(e, t) {
|
|
|
995
1158
|
if (t != null && t.S & (STATUS_UNINITIALIZED | STATUS_ERROR)) read(t);
|
|
996
1159
|
}
|
|
997
1160
|
|
|
1161
|
+
/** latest() pull (#3075): bring the projection computed up to date so the
|
|
1162
|
+
* read serves the IN-FLIGHT derivation — signal/memo parity, where core
|
|
1163
|
+
* read() routes latest() through a companion that recomputes speculatively.
|
|
1164
|
+
* The latest flag is suspended for the recompute (the derive's own reads
|
|
1165
|
+
* are normal reads), and latestPullActive marks any adoption it commits as
|
|
1166
|
+
* staged (see adoptPB) — the speculative swap must not leak to
|
|
1167
|
+
* committed-visibility readers before the flush. */ function pullProjectionForLatest(e) {
|
|
1168
|
+
const t = e.fam.node;
|
|
1169
|
+
if (t == null) return;
|
|
1170
|
+
const n = latestReadActive;
|
|
1171
|
+
setLatestReadActive(false);
|
|
1172
|
+
const r = latestPullActive;
|
|
1173
|
+
latestPullActive = true;
|
|
1174
|
+
try {
|
|
1175
|
+
prepareComputed(t, true);
|
|
1176
|
+
} finally {
|
|
1177
|
+
latestPullActive = r;
|
|
1178
|
+
setLatestReadActive(n);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
998
1182
|
const traps = {
|
|
999
1183
|
get(e, t, n) {
|
|
1000
1184
|
// One typeof gates every brand-symbol compare off the hot string path
|
|
@@ -1022,6 +1206,10 @@ const traps = {
|
|
|
1022
1206
|
}
|
|
1023
1207
|
if (pendingCheckActive) witnessAffectsMark(e, t);
|
|
1024
1208
|
if (e.fam !== null && getObserver() === null && !inDraft(e)) firewallGate(e);
|
|
1209
|
+
// latest() pull (#3075): store traps never reach core read() without an
|
|
1210
|
+
// observer, so bring the projection computed up to date here — signal/
|
|
1211
|
+
// memo parity for latest() reads through a projection.
|
|
1212
|
+
if (e.fam !== null && latestReadActive && !inDraft(e) && !getWriteOverride()) pullProjectionForLatest(e);
|
|
1025
1213
|
const r = readSource(e);
|
|
1026
1214
|
// Overlay delete (#3044): a prototype overlay cannot shadow a delete, so
|
|
1027
1215
|
// deleted keys are tracked aside and read as absent in the pending view.
|
|
@@ -1216,13 +1404,14 @@ const traps = {
|
|
|
1216
1404
|
// Array length writes implicitly delete indices — the written-keys bound
|
|
1217
1405
|
// can't see them, so poison to the full scan for this batch. Index
|
|
1218
1406
|
// writes implicitly GROW length, so arrays always record it alongside.
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1407
|
+
const l = pcOf(e);
|
|
1408
|
+
if (Array.isArray(f)) {
|
|
1409
|
+
if (t === "length") l.wk = WK_ALL; else if (l.wk !== WK_ALL) {
|
|
1410
|
+
const e = l.wk ??= new Set;
|
|
1411
|
+
e.add(t);
|
|
1412
|
+
e.add("length");
|
|
1224
1413
|
}
|
|
1225
|
-
} else if (
|
|
1414
|
+
} else if (l.wk !== WK_ALL) (l.wk ??= new Set).add(t);
|
|
1226
1415
|
// Own data keys literally named "prototype"/"constructor" land as data —
|
|
1227
1416
|
// defineProperty sidesteps a proto-chain setter named the same.
|
|
1228
1417
|
if (UNSAFE_KEYS.has(t)) {
|
|
@@ -1260,7 +1449,14 @@ const traps = {
|
|
|
1260
1449
|
const i = !r && getWriteOverride();
|
|
1261
1450
|
if (!r && !i) return true;
|
|
1262
1451
|
if (t === "__proto__") return true;
|
|
1263
|
-
if (n.get || n.set)
|
|
1452
|
+
if (n.get || n.set) {
|
|
1453
|
+
e.a = true;
|
|
1454
|
+
// Accessor demotion (re-audit blocker 3): a record that acquires an
|
|
1455
|
+
// accessor after patch registration stops being patchable — pull its
|
|
1456
|
+
// patches and re-drive them as tracked effect fallbacks. Hooks are
|
|
1457
|
+
// installed whenever pc.p exists (registration installs them).
|
|
1458
|
+
if (e.pc !== null && e.pc.p !== null) patchHooks.demoteToEffects(e);
|
|
1459
|
+
}
|
|
1264
1460
|
// Unwrap before ensurePB (see the set trap: self-reference materializes).
|
|
1265
1461
|
if ("value" in n) n = {
|
|
1266
1462
|
...n,
|
|
@@ -1268,7 +1464,8 @@ const traps = {
|
|
|
1268
1464
|
};
|
|
1269
1465
|
const o = ensurePB(e);
|
|
1270
1466
|
pendingNotify.add(e);
|
|
1271
|
-
|
|
1467
|
+
const f = pcOf(e);
|
|
1468
|
+
if (f.wk !== WK_ALL) (f.wk ??= new Set).add(t);
|
|
1272
1469
|
Object.defineProperty(o, t, n);
|
|
1273
1470
|
if (e.del !== null) e.del.delete(t);
|
|
1274
1471
|
if (i) notifyWrites(e);
|
|
@@ -1280,7 +1477,8 @@ const traps = {
|
|
|
1280
1477
|
if (!n && !r) return true;
|
|
1281
1478
|
const i = ensurePB(e);
|
|
1282
1479
|
pendingNotify.add(e);
|
|
1283
|
-
|
|
1480
|
+
const o = pcOf(e);
|
|
1481
|
+
if (o.wk !== WK_ALL) (o.wk ??= new Set).add(t);
|
|
1284
1482
|
delete i[t];
|
|
1285
1483
|
// A prototype overlay cannot shadow a delete of a committed key —
|
|
1286
1484
|
// record it aside (#3044); reads/has/ownKeys/commit consult the set.
|
|
@@ -1344,8 +1542,39 @@ function createStoreNext(e, t = false) {
|
|
|
1344
1542
|
return [ n, setter ];
|
|
1345
1543
|
}
|
|
1346
1544
|
|
|
1545
|
+
/** True when `proxy` is a SHALLOW store (children served verbatim, slots
|
|
1546
|
+
* replaced by reference — #2932). The list driver uses this to choose the
|
|
1547
|
+
* slot-patch channel (collected row bodies) over per-record registration. */ function storeIsShallow(e) {
|
|
1548
|
+
const t = e?.[$TARGET];
|
|
1549
|
+
return t !== undefined && t.s === true;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/** True when `proxy` belongs to a projection/optimistic FAMILY. The list
|
|
1553
|
+
* driver must DECLINE family arrays (external audit finding): family
|
|
1554
|
+
* structural changes never emit row/slot ops (the setter channel is
|
|
1555
|
+
* fam-gated; optimistic writes ride node overrides), and the proxy identity
|
|
1556
|
+
* is stable so the each-watch cannot catch the change either — an engaged
|
|
1557
|
+
* list would freeze on optimistic/projection structural updates. Record-
|
|
1558
|
+
* level family patches are unaffected (they have their own emission). */ function storeHasFamily(e) {
|
|
1559
|
+
const t = e?.[$TARGET];
|
|
1560
|
+
return t !== undefined && t.fam !== null;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
/** True when `proxy` belongs to an OPTIMISTIC family specifically. The list
|
|
1564
|
+
* driver declines these (audit finding, narrowed): optimistic user writes
|
|
1565
|
+
* ride node-level overrides — they never enter the reconcile walk, so no
|
|
1566
|
+
* row/slot ops are emitted and an engaged list would freeze on optimistic
|
|
1567
|
+
* structural changes. PROJECTION (non-optimistic) families are drivable:
|
|
1568
|
+
* their recomputes go through the reconcile walk, whose emissions are
|
|
1569
|
+
* transition-stamped in the apply queue like any other (equivalence-matrix
|
|
1570
|
+
* gated). Re-admitting optimistic families requires a lane-timed structural
|
|
1571
|
+
* emission mirroring emitPatchOptimistic, plus revert resync. */ function storeHasOptimisticFamily(e) {
|
|
1572
|
+
const t = e?.[$TARGET];
|
|
1573
|
+
return t !== undefined && t.fam?.opt === true;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1347
1576
|
/** Tracking deep snapshot (`deep()` for next targets): subscribes to the
|
|
1348
|
-
* key-set and
|
|
1577
|
+
* key-set and deep-witness node at every reachable level, then returns the
|
|
1349
1578
|
* plain view. Shared references and cycles handled via the visited set. */ function deepNext(e) {
|
|
1350
1579
|
const t = e?.[$TARGET];
|
|
1351
1580
|
if (t === undefined || t.px !== e) return e;
|
|
@@ -1465,11 +1694,11 @@ function snapshotWalk(e, t, n) {
|
|
|
1465
1694
|
Object.defineProperty(i, o, f);
|
|
1466
1695
|
continue;
|
|
1467
1696
|
}
|
|
1468
|
-
const
|
|
1469
|
-
const
|
|
1470
|
-
if (f.enumerable && f.writable && f.configurable) i[o] =
|
|
1697
|
+
const l = f.value;
|
|
1698
|
+
const u = l !== null && typeof l === "object" ? snapshotWalk(l, t, n) : l;
|
|
1699
|
+
if (f.enumerable && f.writable && f.configurable) i[o] = u; else Object.defineProperty(i, o, {
|
|
1471
1700
|
...f,
|
|
1472
|
-
value:
|
|
1701
|
+
value: u
|
|
1473
1702
|
});
|
|
1474
1703
|
}
|
|
1475
1704
|
if (e && i.length !== r.length) i.length = r.length;
|
|
@@ -1484,16 +1713,16 @@ function snapshotWalk(e, t, n) {
|
|
|
1484
1713
|
if (!i || i.get || i.set) continue;
|
|
1485
1714
|
const o = i.value;
|
|
1486
1715
|
if (o === null || typeof o !== "object") continue;
|
|
1487
|
-
const
|
|
1488
|
-
if (
|
|
1716
|
+
const l = snapshotWalk(o, t, n);
|
|
1717
|
+
if (l !== o) {
|
|
1489
1718
|
if (f === null) {
|
|
1490
1719
|
f = Array.isArray(r) ? [ ...r ] : Object.create(Object.getPrototypeOf(r), Object.getOwnPropertyDescriptors(r));
|
|
1491
1720
|
t.set(r, f);
|
|
1492
1721
|
}
|
|
1493
|
-
f[e] =
|
|
1722
|
+
f[e] = l;
|
|
1494
1723
|
}
|
|
1495
1724
|
}
|
|
1496
1725
|
return f ?? r;
|
|
1497
1726
|
}
|
|
1498
1727
|
|
|
1499
|
-
export { adoptPB, bumpDeep, createStoreNext, deepNext, getHasNode, getKeySetNode, getNode, hasAccessorFlag, hasActiveOverride, materializePB, notifyFold, notifyFoldTail, notifyKeyDiff, notifyKeyValue, runAuthoritative, snapshotNext, storeSetterNext, targetsEqual, unwrapValue, wrapNext };
|
|
1728
|
+
export { adoptPB, bumpDeep, createStoreNext, deepNext, getHasNode, getKeySetNode, getNode, hasAccessorFlag, hasActiveOverride, materializePB, notifyFold, notifyFoldTail, notifyKeyDiff, notifyKeyValue, pcOf, runAuthoritative, snapshotNext, storeHasFamily, storeHasOptimisticFamily, storeIsShallow, storeSetterNext, targetIsPlain, targetsEqual, unwrapValue, wrapNext };
|