@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.18

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.
Files changed (40) hide show
  1. package/dist/dev-shared.js +296 -191
  2. package/dist/dev.attribution.js +16 -16
  3. package/dist/dev.js +527 -311
  4. package/dist/observe/core/async.js +148 -115
  5. package/dist/observe/core/constants.js +3 -1
  6. package/dist/observe/core/core.js +27 -27
  7. package/dist/observe/core/effect.js +29 -32
  8. package/dist/observe/core/graph.js +5 -5
  9. package/dist/observe/core/owner.js +7 -7
  10. package/dist/observe/core/scheduler.js +23 -12
  11. package/dist/observe/core/verdict.js +2 -2
  12. package/dist/observe/deferred.js +16 -13
  13. package/dist/observe/from.js +248 -0
  14. package/dist/observe/index.js +2 -0
  15. package/dist/observe/store/reconcile.js +137 -121
  16. package/dist/observe/store/store.js +595 -618
  17. package/dist/observe/store/target.js +1 -5
  18. package/dist/prod/core/async.js +209 -176
  19. package/dist/prod/core/constants.js +3 -1
  20. package/dist/prod/core/core.js +33 -33
  21. package/dist/prod/core/effect.js +24 -27
  22. package/dist/prod/core/graph.js +2 -2
  23. package/dist/prod/core/lanes.js +14 -14
  24. package/dist/prod/core/scheduler.js +35 -24
  25. package/dist/prod/core/truth.js +4 -4
  26. package/dist/prod/core/verdict.js +7 -7
  27. package/dist/prod/deferred.js +17 -14
  28. package/dist/prod/from.js +248 -0
  29. package/dist/prod/index.js +2 -0
  30. package/dist/prod/store/optimistic.js +1 -1
  31. package/dist/prod/store/reconcile.js +137 -121
  32. package/dist/prod/store/store.js +94 -117
  33. package/dist/prod/store/target.js +13 -17
  34. package/dist/types/core/async.d.ts +12 -2
  35. package/dist/types/core/constants.d.ts +5 -0
  36. package/dist/types/core/core.d.ts +19 -3
  37. package/dist/types/core/scheduler.d.ts +15 -3
  38. package/dist/types/from.d.ts +47 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/package.json +1 -1
@@ -12,7 +12,7 @@ import { insertIntoHeap } from "../core/heap.js";
12
12
 
13
13
  import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, resolveTx, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
14
14
 
15
- import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants, devAssertNeverUserMutation } from "./target.js";
15
+ import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants } from "./target.js";
16
16
 
17
17
  import { optHooks, affectsHooks } from "./hooks.js";
18
18
 
@@ -134,7 +134,7 @@ function wrap(e, n = null, t = null, r = n?.fam ?? null) {
134
134
  const i = lookupTarget(e, r);
135
135
  if (i !== undefined) return i.px;
136
136
  const o = e[$TARGET];
137
- if (o !== undefined && o.px === e) {
137
+ if (o?.px === e) {
138
138
  // Foreign-family proxies re-wrap into THIS family (writes stay isolated);
139
139
  // same-family and plain-store proxies pass through.
140
140
  if (r === null || o.fam === r) return e;
@@ -206,7 +206,7 @@ function sameKey(e, n) {
206
206
  /** The container node's comparator: a staging is a backing (identity — a
207
207
  * pending backing is never "equal" to the committed one); a lane value is
208
208
  * an arrangement (`LaneView`), judged by the optimistic machinery. */ const containerEquals = function(e, n) {
209
- return e === n || optHooks !== null && optHooks.arrangement(this.O, e, n);
209
+ return e === n || !!optHooks?.arrangement(this.O, e, n);
210
210
  };
211
211
 
212
212
  function sameLogicalSlot(e, n, t) {
@@ -225,10 +225,10 @@ function releaseSlot(e) {
225
225
  if (n.k === e) n.k = null;
226
226
  } else if (t === $DEEP) {
227
227
  if (n.dk === e) n.dk = null;
228
- } else if (n.n !== null && n.n[t] === e) {
228
+ } else if (n.n?.[t] === e) {
229
229
  delete n.n[t];
230
230
  n.nc--;
231
- } else if (n.h !== null && n.h[t] === e) delete n.h[t];
231
+ } else if (n.h?.[t] === e) delete n.h[t];
232
232
  // The family's index keeps only targets that still carry a node.
233
233
  if (n.fam !== null && n.nc === 0 && n.k === null && n.dk === null && (n.h === null || Reflect.ownKeys(n.h).length === 0)) n.fam.live.delete(n);
234
234
  }
@@ -247,7 +247,7 @@ function releaseSlot(e) {
247
247
  // holds: its release waits for the commit that resolves it. So does a leaf of
248
248
  // a held container (#4146): a mainline write it carried is in the held
249
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;
250
+ const slotKept = e => e.ue !== NOT_PENDING || e.l & CONFIG_OVERRIDE || e.O.k?.l & CONFIG_HELD;
251
251
 
252
252
  setSlotUnobserved(e => {
253
253
  if (slotKept(e)) deferredReleases.add(e); else releaseSlot(e);
@@ -260,7 +260,7 @@ setSlotUnobserved(e => {
260
260
  * unchanged stages nothing and holds no one). */ function bornStaged(e, n, t, r) {
261
261
  if (n.xe && n.xe(n.Ie, t)) return;
262
262
  queuePendingNode(n);
263
- n.se = t;
263
+ n.ue = t;
264
264
  const i = e.k;
265
265
  if (i === null) return;
266
266
  // a node-less staging holds nothing (`stageOn`)
@@ -292,7 +292,7 @@ t = -1) {
292
292
  // receiver.
293
293
  const o = e.pb;
294
294
  const l = i = slotSignal(committed(e)[n], slotNodeEquals, e, n, t === -1 ? isOwnAccessor(o ?? e.v, n) : t === 1);
295
- if (o !== null && !l.acc) bornStaged(e, l, e.del !== null && e.del.has(n) ? undefined : o[n], n);
295
+ if (o !== null && !l.acc) bornStaged(e, l, e.del?.has(n) ? undefined : o[n], n);
296
296
  r[n] = i;
297
297
  e.nc++;
298
298
  noteNode(e, l, n);
@@ -306,7 +306,7 @@ function getHasNode(e, n) {
306
306
  if (r === undefined) {
307
307
  const i = r = slotSignal(n in committed(e), isEqual, e, n, false);
308
308
  const o = e.pb;
309
- if (o !== null) bornStaged(e, i, n in o && !(e.del !== null && e.del.has(n)), n);
309
+ if (o !== null) bornStaged(e, i, n in o && !e.del?.has(n), n);
310
310
  t[n] = r;
311
311
  noteNode(e, i, n);
312
312
  }
@@ -326,7 +326,7 @@ function getHasNode(e, n) {
326
326
  // would have read had the node been there from the write.
327
327
  if (e.pb !== null && !directCommit) {
328
328
  n.Ie = preBatch(e);
329
- n.se = e.pb;
329
+ n.ue = e.pb;
330
330
  queuePendingNode(n);
331
331
  }
332
332
  }
@@ -345,8 +345,8 @@ function getHasNode(e, n) {
345
345
  * (`storeParkHook`) — the one case the staging home exists for. */ function stageOn(e, n) {
346
346
  if (e.k === null && passLane === null && (context === null || globalQueue.q) && !deriveHolds(e)) return;
347
347
  const t = getContainerNode(e);
348
- if (t.se === NOT_PENDING) queuePendingNode(t);
349
- t.se = n;
348
+ if (t.ue === NOT_PENDING) queuePendingNode(t);
349
+ t.ue = n;
350
350
  // A28 (4): a write issued inside a pass outside a flush (a creation-time
351
351
  // derive) is promoted at the pass's end — the batch with it.
352
352
  if (context !== null) notePromotedWrite(t);
@@ -449,7 +449,7 @@ function copyOwn(e, n, t) {
449
449
  const t = Reflect.ownKeys(n);
450
450
  let r = Object.getPrototypeOf(n) === Object.prototype;
451
451
  for (const i of t) {
452
- if (lookupGetter.call(n, i) !== undefined || lookupSetter.call(n, i) !== undefined) {
452
+ if (isOwnAccessor(n, i)) {
453
453
  e.a = true;
454
454
  r = false;
455
455
  break;
@@ -479,7 +479,7 @@ const plainProto = e => {
479
479
  /** An overlay with many adds (or any delete) rebuilds the committed
480
480
  * container at flatten so its shape stays fast (#3689). */ function overlayRebuilds(e, n) {
481
481
  if (e.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
482
- if (e.del !== null && e.del.size !== 0) return true;
482
+ if (e.del?.size) return true;
483
483
  const t = e.wk;
484
484
  if (t !== null && t !== WK_ALL && t.u === undefined && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
485
485
  const r = e.v;
@@ -491,17 +491,10 @@ const plainProto = e => {
491
491
  /** Downgrade an overlay to a real clone (a consumer needs a container). */ function materializePB(e) {
492
492
  const n = e.pb;
493
493
  if (!e.ovl) return n;
494
- const t = e.sc === 2 ? wideClone(e.v, e) : cloneRaw(e.v, e);
495
- if (e.del !== null) {
496
- for (const n of e.del) delete t[n];
497
- e.kc -= e.del.size;
498
- e.del = null;
499
- }
500
- for (const r of Reflect.ownKeys(n)) e.sc === 2 ? t[r] = n[r] : copyOwn(t, n, r);
494
+ const t = overlayOnto(e, e.sc === 2 ? wideClone(e.v, e) : cloneRaw(e.v, e), n);
501
495
  e.pb = t;
502
- e.ovl = false;
503
496
  // The staging IS the pending backing: re-point the container node.
504
- if (e.k !== null && e.k.se === n) e.k.se = t;
497
+ if (e.k?.ue === n) e.k.ue = t;
505
498
  return t;
506
499
  }
507
500
 
@@ -522,7 +515,7 @@ const plainProto = e => {
522
515
  // mainline setter mid-hold publishes mainline; the held keys stay held).
523
516
  n = e.pb = cloneRaw(n, e);
524
517
  const t = e.k;
525
- if (t !== null && !(t.l & CONFIG_HELD)) t.se = n;
518
+ if (t !== null && !(t.l & CONFIG_HELD)) t.ue = n;
526
519
  } else if (n === null) {
527
520
  const t = e.v;
528
521
  if (!directCommit) queueFold(e);
@@ -546,7 +539,6 @@ const plainProto = e => {
546
539
  e.ch = false;
547
540
  if (e.u) {
548
541
  privatizeCommitted(e.u);
549
- devAssertNeverUserMutation(e.u.v);
550
542
  const t = e.u.v;
551
543
  const r = parentSlotKey(e, n);
552
544
  if (t[r] === n) t[r] = e.v;
@@ -570,17 +562,20 @@ const plainProto = e => {
570
562
  /** Overlay flatten (#3044): own keys onto the owned committed backing in
571
563
  * place — the backing keeps its identity. */ function flattenOverlay(e, n) {
572
564
  privatizeCommitted(e);
573
- const t = e.v;
574
- for (const r of Reflect.ownKeys(n)) e.sc === 2 ? t[r] = n[r] : copyOwn(t, n, r);
565
+ overlayOnto(e, e.v, n);
566
+ // the caller (`foldTarget`) closes the staging
567
+ }
568
+
569
+ /** An overlay's own keys and deletions onto `to` (the two are disjoint: a
570
+ * write un-deletes its key); the overlay is closed. */ function overlayOnto(e, n, t) {
571
+ for (const r of Reflect.ownKeys(t)) e.sc === 2 ? n[r] = t[r] : copyOwn(n, t, r);
575
572
  if (e.del !== null) {
576
- for (const n of e.del) delete t[n];
573
+ for (const t of e.del) delete n[t];
577
574
  e.kc -= e.del.size;
578
575
  e.del = null;
579
576
  }
580
- e.pb = null;
581
577
  e.ovl = false;
582
- e.wk = null;
583
- // written-keys window closes with the commit
578
+ return n;
584
579
  }
585
580
 
586
581
  /** Adoption (a setter's returned replacement; reconcile and projection
@@ -620,7 +615,7 @@ const plainProto = e => {
620
615
  e.wk = null;
621
616
  // adoption supersedes staged trap writes
622
617
  const i = n[$OWNER];
623
- if (i !== undefined && i.fam === e.fam) n[$OWNER] = e; else setLookup(n, e);
618
+ if (i?.fam === e.fam) n[$OWNER] = e; else setLookup(n, e);
624
619
  if (t && r !== n) notifyFold(e, r, n);
625
620
  }
626
621
 
@@ -697,7 +692,7 @@ let foldIndex = null;
697
692
  if (r.pb === null) continue;
698
693
  // folded already (a direct commit)
699
694
  const i = r.k;
700
- if (i !== null && i.se !== NOT_PENDING) {
695
+ if (i !== null && i.ue !== NOT_PENDING) {
701
696
  // held: commits with its hold
702
697
  foldList.push(r);
703
698
  foldOlds.push(n[t]);
@@ -721,7 +716,7 @@ let foldIndex = null;
721
716
  * marks (an ambient `affects()` over a declared reload lives to the
722
717
  * landing) read it. */ GlobalQueue.k = e => {
723
718
  const n = e.O?.fam;
724
- return n != null && n.node !== null && (n.node.m & STATUS_PENDING) !== 0;
719
+ return (n?.node?.m & STATUS_PENDING) !== 0;
725
720
  };
726
721
 
727
722
  /** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
@@ -732,7 +727,7 @@ let foldIndex = null;
732
727
  if (n.ch) {
733
728
  const t = e.ze;
734
729
  const r = n.v;
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]));
730
+ if (n.h?.[t] === e) e.Ie = untrack(() => t in r); else if (n.n?.[t] === e) e.Ie = untrack(() => unwrapValue(r[t]));
736
731
  }
737
732
  return e.Ie;
738
733
  };
@@ -768,12 +763,7 @@ function runDirect(e) {
768
763
  const t = e.k;
769
764
  const r = e.pb;
770
765
  if (r !== null) {
771
- if (r === e.v) {
772
- // An eager adoption nothing wrote after: the backing is already
773
- // the adopted object (shared ownership — never cloned).
774
- e.pb = null;
775
- e.wk = null;
776
- } else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.Pe !== n)) {
766
+ if (r === e.v) ; else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.Pe !== n)) {
777
767
  // Overlay flatten (#3044): the backing keeps its identity, so the
778
768
  // `t.v === old` gate below skips path copying (the parent slot
779
769
  // already points here) and the adopted-notify (setter
@@ -791,25 +781,21 @@ function runDirect(e) {
791
781
  if (hasOwn.call(r, n)) copyOwn(t, r, n); else delete t[n];
792
782
  }
793
783
  } else {
794
- for (const e of Reflect.ownKeys(r)) {
795
- const i = Object.getOwnPropertyDescriptor(r, e);
796
- if (i.get || i.set || !i.enumerable || !i.writable || !i.configurable) Object.defineProperty(t, e, i); else if (i.value !== n[e] || !hasOwn.call(n, e)) t[e] = i.value;
797
- }
784
+ for (const e of Reflect.ownKeys(r)) copyOwn(t, r, e);
798
785
  for (const e of Reflect.ownKeys(n)) {
799
786
  if (!hasOwn.call(r, e)) delete t[e];
800
787
  }
801
788
  }
802
- e.pb = null;
803
- e.wk = null;
804
789
  } else {
805
790
  // The clone (or adopted object) becomes the committed backing
806
791
  // (path copy below).
807
792
  e.v = e.ovl ? materializePB(e) : r;
808
793
  e.ch = e.v[$TARGET] !== undefined;
809
- e.pb = null;
810
- e.wk = null;
811
794
  }
812
- }
795
+ e.pb = null;
796
+ e.wk = null;
797
+ // the written-keys window closes with the commit
798
+ }
813
799
  if (t !== null) {
814
800
  // The node's committed value is the backing. A container nobody
815
801
  // subscribes to was a transient staging home (INTERNALS §5: an
@@ -821,7 +807,6 @@ function runDirect(e) {
821
807
  const t = parentSlotKey(e, n);
822
808
  if (e.u.v[t] === n) {
823
809
  privatizeCommitted(e.u);
824
- devAssertNeverUserMutation(e.u.v);
825
810
  e.u.v[t] = e.v;
826
811
  }
827
812
  }
@@ -906,7 +891,7 @@ function heldDerivation(e, n, t) {
906
891
  if (e?.get || e?.set || !isEqual(e?.value, r.value)) setSignal(i, () => r.value);
907
892
  continue;
908
893
  }
909
- const l = e.del !== null && e.del.has(o) ? undefined : n[o];
894
+ const l = e.del?.has(o) ? undefined : n[o];
910
895
  setSignal(i, () => l);
911
896
  if (e.fam !== null) {
912
897
  // The derive's write is a derivation; a user setter's is a proposal
@@ -924,13 +909,13 @@ function heldDerivation(e, n, t) {
924
909
  for (const r of t) {
925
910
  const t = l[r];
926
911
  if (t !== undefined) {
927
- setSignal(t, r in n && !(e.del !== null && e.del.has(r)));
912
+ setSignal(t, r in n && !e.del?.has(r));
928
913
  if (e.fam !== null) holdWithDerive(e, t);
929
914
  }
930
915
  }
931
916
  }
932
917
  if (e.dk !== null) {
933
- if (e.del !== null && e.del.size !== 0) bumpDeep(e); else for (const r of o ?? Reflect.ownKeys(n)) {
918
+ if (e.del?.size) bumpDeep(e); else for (const r of o ?? Reflect.ownKeys(n)) {
934
919
  if (r === $OWNER) continue;
935
920
  const i = n[r];
936
921
  const o = t[r];
@@ -948,7 +933,7 @@ function heldDerivation(e, n, t) {
948
933
  if (u !== null && (u.o !== null || u.l & CONFIG_OVERRIDE)) {
949
934
  let r;
950
935
  if (e.ovl) {
951
- r = e.del !== null && e.del.size !== 0;
936
+ r = !!e.del?.size;
952
937
  if (!r) {
953
938
  for (const e of Reflect.ownKeys(n)) {
954
939
  if (!hasOwn.call(t, e)) {
@@ -1094,7 +1079,7 @@ function inDraft(e) {
1094
1079
  /** A child proxy served to a draft joins the draft's scope. */ function draftServe(e, n) {
1095
1080
  if (writeScopes !== null && inDraft(e)) {
1096
1081
  const e = n?.[$TARGET];
1097
- if (e !== undefined && e.v !== undefined) writeScopes.add(scopeKey(e));
1082
+ if (e?.v !== undefined) writeScopes.add(scopeKey(e));
1098
1083
  }
1099
1084
  return n;
1100
1085
  }
@@ -1104,7 +1089,7 @@ function inDraft(e) {
1104
1089
  * "adoption is eager by contract" — and the node keeps the frame committed
1105
1090
  * readers under a hold still see), `t.v` otherwise. */ function committed(e) {
1106
1091
  const n = e.k;
1107
- if (n !== null) return n.se !== NOT_PENDING ? asBacking(n.Ie) : e.v;
1092
+ if (n !== null) return n.ue !== NOT_PENDING ? asBacking(n.Ie) : e.v;
1108
1093
  // A node-less staging (`stageOn`): the fold queue remembers the frame.
1109
1094
  return e.pb !== null ? preBatch(e) : e.v;
1110
1095
  }
@@ -1137,7 +1122,7 @@ function inDraft(e) {
1137
1122
  // sees — the lanes' values and the tick's own guesses over the truth
1138
1123
  // (#3665), never a staging awaiting its fold: the draft is born on the
1139
1124
  // read (and notified at the setter's exit like any).
1140
- if (userWrite && e.fam !== null && e.fam.opt === true && !pendingNotify.has(e) && inDraft(e)) {
1125
+ if (userWrite && e.fam?.opt === true && !pendingNotify.has(e) && inDraft(e)) {
1141
1126
  const n = ensurePB(e);
1142
1127
  pendingNotify.add(e);
1143
1128
  return n;
@@ -1170,7 +1155,7 @@ function inDraft(e) {
1170
1155
  // it).
1171
1156
  if (n !== undefined) {
1172
1157
  const t = e.n?.[n];
1173
- if (t !== undefined && t.l & CONFIG_OVERRIDE) return committed(e);
1158
+ if (t?.l & CONFIG_OVERRIDE) return committed(e);
1174
1159
  }
1175
1160
  const o = i !== null && (i.l & CONFIG_HELD) !== 0;
1176
1161
  // A held container: the hold's unit is the key (#3706). A key the HELD
@@ -1223,7 +1208,7 @@ function inDraft(e) {
1223
1208
 
1224
1209
  /** Did the HELD staging (the container node's, not a mainline layer above
1225
1210
  * it) change `key`? */ function heldKeyChanged(e, n, t = true) {
1226
- return changedBetween(e, e.k.Ie, e.k.se, n, t) && !adoptChild(e, n);
1211
+ return changedBetween(e, e.k.Ie, e.k.ue, n, t) && !adoptChild(e, n);
1227
1212
  }
1228
1213
 
1229
1214
  /** The values of a held frame, built once per frame: neither the committed
@@ -1252,23 +1237,23 @@ function rawsOf(e) {
1252
1237
  const t = e.k;
1253
1238
  const r = asBacking(t.Ie);
1254
1239
  const i = r[n];
1255
- const o = t.se[n];
1240
+ const o = t.ue[n];
1256
1241
  const l = Array.isArray(r) ? e.fam?.key : null;
1257
1242
  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 ||
1258
1243
  // A raw in both frames (the same objects swapped or reordered) is its
1259
1244
  // own row: pairing it with another would alias the two after the commit.
1260
- rawsOf(r).has(o) || rawsOf(t.se).has(i)) return false;
1245
+ rawsOf(r).has(o) || rawsOf(t.ue).has(i)) return false;
1261
1246
  // A raw-marked value wraps to itself, a proxy to its own target: neither
1262
1247
  // is a fresh target around `ov`.
1263
1248
  const u = wrap(i, e, n)[$TARGET];
1264
- if (u === undefined || u.v !== i) return false;
1249
+ if (u?.v !== i) return false;
1265
1250
  adoptPB(u, o, false);
1266
1251
  holdNode(getContainerNode(u), txOf(t));
1267
1252
  return true;
1268
1253
  }
1269
1254
 
1270
1255
  /** A family target's unheld staging, read with no pass (a handler). */ function familyAhead(e) {
1271
- return e.fam !== null && context === null && !(e.k !== null && e.k.l & CONFIG_HELD);
1256
+ return e.fam !== null && context === null && !(e.k?.l & CONFIG_HELD);
1272
1257
  }
1273
1258
 
1274
1259
  /** Did this batch change `key` — value (slot equality), presence, and (for
@@ -1288,7 +1273,7 @@ function rawsOf(e) {
1288
1273
 
1289
1274
  function changedBetween(e, n, t, r, i) {
1290
1275
  if (e.ch || t[$TARGET] !== undefined || Object.getPrototypeOf(t) !== Object.getPrototypeOf(n) || !plainProto(n)) return true;
1291
- if (e.del !== null && e.del.has(r)) return r in n;
1276
+ if (e.del?.has(r)) return r in n;
1292
1277
  const o = hasOwn.call(t, r) || e.ovl && hasOwn.call(e.v, r);
1293
1278
  if (o !== hasOwn.call(n, r)) return true;
1294
1279
  if (!o) return false;
@@ -1302,7 +1287,7 @@ function changedBetween(e, n, t, r, i) {
1302
1287
  * tracked or not, applies the hold and A28 rules a signal's read does. A
1303
1288
  * projection's unheld staging is ahead for a handler (`familyAhead`). */ function nodeValue(e, n, t) {
1304
1289
  let r = read(e);
1305
- if (e.se !== NOT_PENDING && !(e.l & CONFIG_HELD) && context === null && t.fam !== null) r = e.se;
1290
+ if (e.ue !== NOT_PENDING && !(e.l & CONFIG_HELD) && context === null && t.fam !== null) r = e.ue;
1306
1291
  return r === FORCE ? n : r;
1307
1292
  }
1308
1293
 
@@ -1395,7 +1380,7 @@ function changedBetween(e, n, t, r, i) {
1395
1380
  * classification, as core reads it — `heldNotFinal`). */ function holdWithDerive(e, n) {
1396
1381
  const t = e.fam?.node;
1397
1382
  if (t !== undefined && t !== null && !userWrite && // the derive's own write (its draft or landing), not a user setter's
1398
- t.l & CONFIG_HELD && n.se !== NOT_PENDING &&
1383
+ t.l & CONFIG_HELD && n.ue !== NOT_PENDING &&
1399
1384
  // A node carrying a guess is the lane's: its staging is the truth beneath
1400
1385
  // the guess (`setSignal` → `laneWrite`), never re-homed by the store.
1401
1386
  !(n.l & (CONFIG_HELD | CONFIG_OVERRIDE))) {
@@ -1436,7 +1421,7 @@ function changedBetween(e, n, t, r, i) {
1436
1421
  /** A read on an optimistic family that composes the lanes' values: not the
1437
1422
  * draft's (it composed already), not a derive's write-override read (the
1438
1423
  * derive composes on the truth). */ function optRead(e) {
1439
- return e.fam !== null && e.fam.opt === true && !inDraft(e) && !writeOverride;
1424
+ return e.fam?.opt === true && !inDraft(e) && !writeOverride;
1440
1425
  }
1441
1426
 
1442
1427
  /** Pollution keys are never served from the prototype (core R30). */ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
@@ -1519,7 +1504,7 @@ const traps = {
1519
1504
  const i = readSource(e, n);
1520
1505
  // Overlay delete (#3044): a prototype overlay cannot shadow a delete, so
1521
1506
  // deleted keys are tracked aside and read as absent in the pending view.
1522
- if (e.del !== null && i === e.pb && e.del.has(n)) {
1507
+ if (i === e.pb && e.del?.has(n)) {
1523
1508
  if (!inDraft(e) && getObserver() !== null) read(getNode(e, n));
1524
1509
  return undefined;
1525
1510
  }
@@ -1606,7 +1591,7 @@ const traps = {
1606
1591
  if (t !== undefined) return t;
1607
1592
  }
1608
1593
  }
1609
- return n in t && !(e.del !== null && t === e.pb && e.del.has(n));
1594
+ return n in t && !(t === e.pb && e.del?.has(n));
1610
1595
  },
1611
1596
  ownKeys(e) {
1612
1597
  if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.ro(e, undefined);
@@ -1649,14 +1634,13 @@ const traps = {
1649
1634
  },
1650
1635
  set(e, n, t) {
1651
1636
  const r = inDraft(e);
1652
- const i = !r && writeOverride;
1653
- if (!r && !i) {
1637
+ if (!r && !writeOverride) {
1654
1638
  return true;
1655
1639
  }
1656
1640
  if (n === "__proto__") return true;
1657
1641
  // pollution guard (core R30)
1658
- const o = e.s ? t : unwrapValue(t);
1659
- const l = ensurePB(e);
1642
+ const i = e.s ? t : unwrapValue(t);
1643
+ const o = ensurePB(e);
1660
1644
  // #4146 (R1: node existence is unobservable; #3706: the hold's unit is
1661
1645
  // the key): a user setter writing a key a HELD container's staging left
1662
1646
  // unchanged would write it into the held staging — read as the hold's
@@ -1668,40 +1652,32 @@ const traps = {
1668
1652
  // A34) — as it would with a reader's leaf. Kept while the container is
1669
1653
  // held (`deferredReleases`).
1670
1654
  if (userWrite && e.k?.l & CONFIG_HELD) deferredReleases.add(getNode(e, n));
1671
- if (Array.isArray(l)) {
1655
+ if (Array.isArray(o)) {
1672
1656
  touch(e, n);
1673
1657
  if (n === "length") e.wk = WK_ALL; else touch(e, "length");
1674
1658
  } else {
1675
1659
  touch(e, n);
1676
- if (!(n in l)) e.kc++;
1660
+ if (!(n in o)) e.kc++;
1677
1661
  }
1678
- if (UNSAFE_KEYS.has(n)) {
1679
- Object.defineProperty(l, n, {
1680
- value: o,
1662
+ const l = UNSAFE_KEYS.has(n);
1663
+ if (l || e.ovl && e.sc !== 2 && !hasOwn.call(o, n)) {
1664
+ Object.defineProperty(o, n, {
1665
+ value: i,
1681
1666
  writable: true,
1682
1667
  enumerable: true,
1683
1668
  configurable: true
1684
1669
  });
1685
- if (e.del !== null) e.del.delete(n);
1686
- return true;
1687
- }
1688
- if (e.ovl && e.sc !== 2 && !hasOwn.call(l, n)) {
1689
- Object.defineProperty(l, n, {
1690
- value: o,
1691
- writable: true,
1692
- enumerable: true,
1693
- configurable: true
1694
- });
1695
- } else l[n] = o;
1696
- if (e.del !== null) e.del.delete(n);
1697
- if (e.s && o !== null && typeof o === "object") markRawOne(o);
1698
- if (i) notifyWrites(e);
1699
- return true;
1670
+ } else o[n] = i;
1671
+ e.del?.delete(n);
1672
+ if (l) return true;
1673
+ if (e.s && i !== null && typeof i === "object") markRawOne(i);
1674
+ if (!r) notifyWrites(e);
1675
+ // a write-override write
1676
+ return true;
1700
1677
  },
1701
1678
  defineProperty(e, n, t) {
1702
1679
  const r = inDraft(e);
1703
- const i = !r && writeOverride;
1704
- if (!r && !i) {
1680
+ if (!r && !writeOverride) {
1705
1681
  return true;
1706
1682
  }
1707
1683
  if (n === "__proto__") return true;
@@ -1710,21 +1686,21 @@ const traps = {
1710
1686
  ...t,
1711
1687
  value: unwrapValue(t.value)
1712
1688
  };
1713
- const o = ensurePB(e);
1689
+ const i = ensurePB(e);
1714
1690
  if (e.a || !(t.enumerable && t.writable && t.configurable)) e.sc = 1;
1715
1691
  touch(e, n);
1716
- Object.defineProperty(o, n, t);
1717
- if (e.del !== null) e.del.delete(n);
1718
- if (i) notifyWrites(e);
1719
- return true;
1692
+ Object.defineProperty(i, n, t);
1693
+ e.del?.delete(n);
1694
+ if (!r) notifyWrites(e);
1695
+ // a write-override write
1696
+ return true;
1720
1697
  },
1721
1698
  deleteProperty(e, n) {
1722
1699
  const t = inDraft(e);
1723
- const r = !t && writeOverride;
1724
- if (!t && !r) {
1700
+ if (!t && !writeOverride) {
1725
1701
  return true;
1726
1702
  }
1727
- const i = ensurePB(e);
1703
+ const r = ensurePB(e);
1728
1704
  touch(e, n);
1729
1705
  // The key count (`kc`, the overlay gate and the rebuild cap) follows a
1730
1706
  // delete the way it follows an add: an own key of the draft leaving — a
@@ -1735,14 +1711,15 @@ const traps = {
1735
1711
  // one" shape drifted the count up by one per write until a three-key
1736
1712
  // object crossed the overlay threshold and paid a rebuild on every
1737
1713
  // 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--;
1714
+ const i = e.ovl && hasOwn.call(e.v, n);
1715
+ if (hasOwn.call(r, n)) {
1716
+ delete r[n];
1717
+ i || e.kc--;
1742
1718
  }
1743
- if (o) (e.del ??= new Set).add(n);
1744
- if (r) notifyWrites(e);
1745
- return true;
1719
+ if (i) (e.del ??= new Set).add(n);
1720
+ if (!t) notifyWrites(e);
1721
+ // a write-override write
1722
+ return true;
1746
1723
  }
1747
1724
  };
1748
1725
 
@@ -1824,17 +1801,17 @@ function createStore(e, n) {
1824
1801
  * replaced by reference — #2932). The list driver uses this to choose the
1825
1802
  * slot-patch channel (collected row bodies) over per-record registration. */ function storeIsShallow(e) {
1826
1803
  const n = e?.[$TARGET];
1827
- return n !== undefined && n.s === true;
1804
+ return n?.s === true;
1828
1805
  }
1829
1806
 
1830
1807
  /** True when `proxy` belongs to a projection family (S3). */ function storeHasFamily(e) {
1831
1808
  const n = e?.[$TARGET];
1832
- return n !== undefined && n.fam !== null;
1809
+ return n?.fam != null;
1833
1810
  }
1834
1811
 
1835
1812
  /** True when `proxy` belongs to an OPTIMISTIC family (S4). */ function storeHasOptimisticFamily(e) {
1836
1813
  const n = e?.[$TARGET];
1837
- return n !== undefined && n.fam?.opt === true;
1814
+ return n?.fam?.opt === true;
1838
1815
  }
1839
1816
 
1840
1817
  // ---------------------------------------------------------------------------
@@ -1844,7 +1821,7 @@ function visibleKeys(e, n) {
1844
1821
  if (e.ovl && n === e.pb) {
1845
1822
  t = Reflect.ownKeys(e.v);
1846
1823
  const r = e.del;
1847
- if (r !== null && r.size !== 0) t = t.filter(e => !r.has(e));
1824
+ if (r?.size) t = t.filter(e => !r.has(e));
1848
1825
  for (const r of Reflect.ownKeys(n)) {
1849
1826
  if (!hasOwn.call(e.v, r)) t.push(r);
1850
1827
  }
@@ -1862,7 +1839,7 @@ function visibleKeys(e, n) {
1862
1839
  function visibleDescriptor(e, n, t) {
1863
1840
  let r = Object.getOwnPropertyDescriptor(n, t);
1864
1841
  if (e.ovl && n === e.pb) {
1865
- if (e.del !== null && e.del.has(t)) return undefined;
1842
+ if (e.del?.has(t)) return undefined;
1866
1843
  if (r === undefined) r = Object.getOwnPropertyDescriptor(e.v, t);
1867
1844
  }
1868
1845
  return r;
@@ -1873,7 +1850,7 @@ function visibleDescriptor(e, n, t) {
1873
1850
  /** Tracking snapshot: subscribes every reachable record's container and deep
1874
1851
  * witness (one node per record, not one per path), then snapshots. */ function deep(e) {
1875
1852
  const n = e?.[$TARGET];
1876
- if (n === undefined || n.px !== e) return e;
1853
+ if (n?.px !== e) return e;
1877
1854
  const t = new Set;
1878
1855
  const childTarget = (e, n, t) => {
1879
1856
  let r = lookupTarget(n, e.fam);
@@ -17,31 +17,27 @@ const $OWNER = Symbol(0);
17
17
  /** raw → target for plain (family-less) stores. Family stores use their own
18
18
  * map so one raw can wrap once per family (§7b). */ const storeLookup = new WeakMap;
19
19
 
20
- function setLookup(e, o) {
21
- (o.fam?.map ?? storeLookup).set(e, o);
20
+ function setLookup(o, e) {
21
+ (e.fam?.map ?? storeLookup).set(o, e);
22
22
  }
23
23
 
24
- function isOwned(e) {
25
- return e[$OWNER] !== undefined;
24
+ function isOwned(o) {
25
+ return o[$OWNER] !== undefined;
26
26
  }
27
27
 
28
28
  /** The target wrapping `raw` in `fam` (or the plain lookup). An owned raw
29
- * answers from its stamp; a user raw from the map. */ function lookupTarget(e, o) {
30
- const t = e[$OWNER];
31
- return t !== undefined && t.fam === o ? t : (o?.map ?? storeLookup).get(e);
32
- }
33
-
34
- function devAssertNeverUserMutation(e) {
35
- return;
29
+ * answers from its stamp; a user raw from the map. */ function lookupTarget(o, e) {
30
+ const n = o[$OWNER];
31
+ return n !== undefined && n.fam === e ? n : (e?.map ?? storeLookup).get(o);
36
32
  }
37
33
 
38
34
  /** Sticky descendants flag up the parent chain (§6d): adoption descends
39
- * into a changed child pair only where a target with nodes exists below. */ function markDescendants(e) {
40
- let o = e;
41
- while (o && !o.d) {
42
- o.d = true;
43
- o = o.u;
35
+ * into a changed child pair only where a target with nodes exists below. */ function markDescendants(o) {
36
+ let e = o;
37
+ while (e && !e.d) {
38
+ e.d = true;
39
+ e = e.u;
44
40
  }
45
41
  }
46
42
 
47
- export { $OWNER, devAssertNeverUserMutation, isOwned, lookupTarget, markDescendants, setLookup, storeLookup };
43
+ export { $OWNER, isOwned, lookupTarget, markDescendants, setLookup, storeLookup };
@@ -27,12 +27,22 @@ export declare function settlePendingSource(el: Computed<any>, source?: Computed
27
27
  export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
28
28
  /** Fire and clear a node's iterator-flight cancellation hook (#3122). */
29
29
  export declare function releaseFlightTeardown(el: Computed<any>): void;
30
+ /**
31
+ * Internal (not a package export): run `fn` when the current pass's flight
32
+ * is superseded, at the same instant as the iterator close above, instead of
33
+ * when the replacing pass commits (owner cleanups wait for that). Chains onto
34
+ * the node's teardown slot; fires once with it. A no-op unless the ambient
35
+ * owner is a computed in its own pass. `consumeIterator` fills the slot
36
+ * before its first pull, so a source opened in an async generator's body
37
+ * (`for await`) composes after the generator's close.
38
+ */
39
+ export declare function onSupersede(fn: () => void): void;
30
40
  export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void, onError?: (error: unknown, pending: boolean) => void): T;
31
41
  export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
32
- export declare function notifyStatus(el: Computed<any>, status: number, error: any, blockStatus?: boolean): void;
42
+ export declare function notifyStatus(el: Computed<any>, status: number, error: any): void;
33
43
  /** The dependents' half of `notifyStatus`: `el`'s status reaches each
34
44
  * subscriber as a propagated mark (or a re-derive). On its own for a store
35
45
  * family's leaves, which are not the derive's dependents — the family
36
46
  * propagates the derive's status from each leaf to the leaf's readers
37
47
  * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */
38
- export declare function propagateStatus(el: Computed<any>, status: number, error: any, downstreamBlockStatus?: boolean): void;
48
+ export declare function propagateStatus(el: Computed<any>, status: number, error: any): void;