@solidjs/signals 2.0.0-beta.16 → 2.0.0-beta.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.
package/dist/dev.js CHANGED
@@ -12,6 +12,9 @@ class StatusError extends Error {
12
12
  this.source = source;
13
13
  }
14
14
  }
15
+ function unwrapStatusError(error) {
16
+ return error instanceof StatusError ? error.cause : error;
17
+ }
15
18
  class NoOwnerError extends Error {
16
19
  constructor() {
17
20
  super("Context can only be accessed under a reactive root.");
@@ -36,6 +39,7 @@ const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
36
39
  const REACTIVE_SNAPSHOT_STALE = 1 << 8;
37
40
  const REACTIVE_LAZY = 1 << 9;
38
41
  const REACTIVE_MANUAL_WRITE = 1 << 10;
42
+ const REACTIVE_REASK = 1 << 11;
39
43
  const CONFIG_OWNED_WRITE = 1 << 0;
40
44
  const CONFIG_NO_SNAPSHOT = 1 << 1;
41
45
  const CONFIG_TRANSPARENT = 1 << 2;
@@ -253,6 +257,7 @@ function canUseSimpleSyncFlush(queue) {
253
257
  activeLanes.size === 0 &&
254
258
  queue._children.length === 0 &&
255
259
  queue._optimisticNodes.length === 0 &&
260
+ queue._affectsNodes.length === 0 &&
256
261
  queue._optimisticStores.size === 0 &&
257
262
  transientStoreNodes.size === 0
258
263
  );
@@ -266,6 +271,7 @@ function sweepTransientStoreNodes() {
266
271
  }
267
272
  if (node._pendingValue !== NOT_PENDING) continue;
268
273
  if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
274
+ if (node._affectsCount) continue;
269
275
  transientStoreNodes.delete(node);
270
276
  node._unobserved?.();
271
277
  }
@@ -316,6 +322,10 @@ function mergeTransitionState(target, outgoing) {
316
322
  target._actions.push(...outgoing._actions);
317
323
  for (const lane of activeLanes) if (lane._transition === outgoing) lane._transition = target;
318
324
  target._optimisticNodes.push(...outgoing._optimisticNodes);
325
+ if (outgoing._affectsNodes.length) {
326
+ target._affectsNodes.push(...outgoing._affectsNodes);
327
+ outgoing._affectsNodes.length = 0;
328
+ }
319
329
  for (const store of outgoing._optimisticStores) target._optimisticStores.add(store);
320
330
  for (const [source, reporters] of outgoing._asyncReporters) {
321
331
  let targetReporters = target._asyncReporters.get(source);
@@ -466,11 +476,15 @@ class GlobalQueue extends Queue {
466
476
  _pendingNode = null;
467
477
  _pendingNodes = [];
468
478
  _optimisticNodes = [];
479
+ _affectsNodes = [];
469
480
  _optimisticStores = new Set();
470
481
  static _update;
471
482
  static _dispose;
472
483
  static _runEffect;
473
484
  static _clearOptimisticStore = null;
485
+ static _releaseAffectsScope = null;
486
+ static _propagateAffects = null;
487
+ static _settleAffects = null;
474
488
  flush() {
475
489
  if (this._running) return;
476
490
  this._running = true;
@@ -485,6 +499,7 @@ class GlobalQueue extends Queue {
485
499
  this._pendingNode = null;
486
500
  this._pendingNodes = [];
487
501
  this._optimisticNodes = [];
502
+ this._affectsNodes = [];
488
503
  this._optimisticStores = new Set();
489
504
  runLaneEffects(EFFECT_RENDER);
490
505
  runLaneEffects(EFFECT_USER);
@@ -590,6 +605,7 @@ class GlobalQueue extends Queue {
590
605
  _pendingNodes: [],
591
606
  _asyncReporters: createAsyncReporters(),
592
607
  _optimisticNodes: [],
608
+ _affectsNodes: [],
593
609
  _optimisticStores: new Set(),
594
610
  _actions: [],
595
611
  _queueStash: { _queues: [[], []], _children: [] },
@@ -625,6 +641,10 @@ class GlobalQueue extends Queue {
625
641
  }
626
642
  this._optimisticNodes = activeTransition._optimisticNodes;
627
643
  }
644
+ if (this._affectsNodes !== activeTransition._affectsNodes) {
645
+ activeTransition._affectsNodes.push(...this._affectsNodes);
646
+ this._affectsNodes = activeTransition._affectsNodes;
647
+ }
628
648
  for (const lane of activeLanes) {
629
649
  if (!lane._transition) lane._transition = activeTransition;
630
650
  }
@@ -649,10 +669,16 @@ function queuePendingNode(node) {
649
669
  }
650
670
  globalQueue._pendingNodes.push(node);
651
671
  }
672
+ let reaskArmed = false;
673
+ function armReaskClear() {
674
+ reaskArmed = true;
675
+ }
652
676
  function insertSubs(node, optimistic = false) {
653
677
  const sourceLane = node._optimisticLane || currentOptimisticLane;
654
678
  const hasSnapshot = node._snapshotValue !== undefined;
679
+ const clearReask = reaskArmed;
655
680
  for (let s = node._subs; s !== null; s = s._nextSub) {
681
+ if (clearReask) s._sub._flags &= ~REACTIVE_REASK;
656
682
  if (hasSnapshot && s._sub._config & CONFIG_IN_SNAPSHOT_SCOPE) {
657
683
  s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
658
684
  continue;
@@ -736,6 +762,9 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
736
762
  }
737
763
  completingTransition._gatedSubs.clear();
738
764
  }
765
+ releaseAffectsMarks(
766
+ completingTransition ? completingTransition._affectsNodes : globalQueue._affectsNodes
767
+ );
739
768
  const optimisticStores = completingTransition
740
769
  ? completingTransition._optimisticStores
741
770
  : globalQueue._optimisticStores;
@@ -760,6 +789,32 @@ function trackOptimisticStore(store) {
760
789
  globalQueue._optimisticStores.add(store);
761
790
  schedule();
762
791
  }
792
+ let activeAffectsMarks = 0;
793
+ function markAffects(node) {
794
+ node._affectsCount = (node._affectsCount || 0) + 1;
795
+ activeAffectsMarks++;
796
+ if (node._affectsCount === 1) updatePendingSignal(node);
797
+ }
798
+ function registerAffectsMark(node) {
799
+ markAffects(node);
800
+ globalQueue._affectsNodes.push(node);
801
+ GlobalQueue._propagateAffects?.(node);
802
+ schedule();
803
+ }
804
+ function releaseAffectsMark(node) {
805
+ activeAffectsMarks--;
806
+ node._affectsCount--;
807
+ if (!node._affectsCount) {
808
+ GlobalQueue._settleAffects?.(node);
809
+ snapCompanionsToState(node);
810
+ GlobalQueue._releaseAffectsScope?.(node);
811
+ }
812
+ }
813
+ function releaseAffectsMarks(nodes) {
814
+ if (!nodes.length) return;
815
+ for (let i = 0; i < nodes.length; i++) releaseAffectsMark(nodes[i]);
816
+ nodes.length = 0;
817
+ }
763
818
  function reassignPendingTransition(pendingNodes) {
764
819
  for (let i = 0; i < pendingNodes.length; i++) {
765
820
  pendingNodes[i]._transition = activeTransition;
@@ -839,7 +894,8 @@ function transitionComplete(transition) {
839
894
  hasActiveOverride(node) &&
840
895
  "_statusFlags" in node &&
841
896
  node._statusFlags & STATUS_PENDING &&
842
- node._error instanceof NotReadyError
897
+ node._error instanceof NotReadyError &&
898
+ !node._error.source?._affectsFor
843
899
  ) {
844
900
  done = false;
845
901
  break;
@@ -1276,7 +1332,7 @@ function setPendingError(el, source, error) {
1276
1332
  }
1277
1333
  function forEachDependent(el, fn) {
1278
1334
  for (let s = el._subs; s !== null; s = s._nextSub) fn(s._sub, s);
1279
- for (let child = el._child; child !== null; child = child._nextChild) {
1335
+ for (let child = el._child ?? null; child !== null; child = child._nextChild) {
1280
1336
  for (let s = child._subs; s !== null; s = s._nextSub) fn(s._sub, s);
1281
1337
  }
1282
1338
  }
@@ -1293,21 +1349,22 @@ function enqueueForRerun(node) {
1293
1349
  insertIntoHeap(node, queue);
1294
1350
  }
1295
1351
  }
1296
- function settlePendingSource(el) {
1352
+ function settlePendingSource(el, source = el, snap = false) {
1297
1353
  let scheduled = false;
1298
1354
  const visited = new Set();
1355
+ const updateCompanions = snap ? snapCompanionsToState : updatePendingSignal;
1299
1356
  const settle = node => {
1300
- if (visited.has(node) || !removePendingSource(node, el)) return;
1357
+ if (visited.has(node) || !removePendingSource(node, source)) return;
1301
1358
  visited.add(node);
1302
1359
  node._time = clock;
1303
- const source = node._pendingSource ?? node._pendingSources?.values().next().value;
1304
- if (source) {
1305
- setPendingError(node, source);
1306
- updatePendingSignal(node);
1360
+ const remaining = node._pendingSource ?? node._pendingSources?.values().next().value;
1361
+ if (remaining) {
1362
+ setPendingError(node, remaining);
1363
+ updateCompanions(node);
1307
1364
  } else {
1308
1365
  node._statusFlags &= ~STATUS_PENDING;
1309
1366
  setPendingError(node);
1310
- updatePendingSignal(node);
1367
+ updateCompanions(node);
1311
1368
  if (node._blocked) {
1312
1369
  enqueueForRerun(node);
1313
1370
  scheduled = true;
@@ -1433,8 +1490,9 @@ function handleAsync(el, result, setter) {
1433
1490
  }
1434
1491
  if (iterator) {
1435
1492
  const it = result[Symbol.asyncIterator]();
1436
- let hadSyncValue = false;
1493
+ let hadValue = false;
1437
1494
  let completed = false;
1495
+ let initialRead = true;
1438
1496
  cleanup(() => {
1439
1497
  if (completed) return;
1440
1498
  completed = true;
@@ -1445,7 +1503,9 @@ function handleAsync(el, result, setter) {
1445
1503
  });
1446
1504
  const iterate = () => {
1447
1505
  let syncResult,
1506
+ syncError,
1448
1507
  resolved = false,
1508
+ rejected = false,
1449
1509
  isSync = true;
1450
1510
  it.next().then(
1451
1511
  r => {
@@ -1455,30 +1515,46 @@ function handleAsync(el, result, setter) {
1455
1515
  if (r.done) completed = true;
1456
1516
  } else if (el._inFlight !== result) {
1457
1517
  return;
1458
- } else if (!r.done) asyncWrite(r.value, iterate);
1459
- else {
1518
+ } else if (!r.done) {
1519
+ hadValue = true;
1520
+ asyncWrite(r.value, iterate);
1521
+ } else {
1460
1522
  completed = true;
1461
- schedule();
1462
- flush();
1523
+ if (hadValue) {
1524
+ schedule();
1525
+ flush();
1526
+ } else {
1527
+ asyncWrite(undefined);
1528
+ }
1463
1529
  }
1464
1530
  },
1465
1531
  e => {
1466
- if (!isSync && el._inFlight === result) {
1532
+ if (isSync) {
1533
+ syncError = e;
1534
+ rejected = true;
1535
+ } else if (el._inFlight === result) {
1467
1536
  completed = true;
1468
1537
  handleError(e);
1469
1538
  }
1470
1539
  }
1471
1540
  );
1472
1541
  isSync = false;
1542
+ if (rejected) {
1543
+ completed = true;
1544
+ handleError(syncError);
1545
+ if (initialRead) throw syncError;
1546
+ return true;
1547
+ }
1473
1548
  if (resolved && !syncResult.done) {
1474
1549
  syncValue = syncResult.value;
1475
- hadSyncValue = true;
1550
+ hadValue = true;
1476
1551
  return iterate();
1477
1552
  }
1478
1553
  return resolved && syncResult.done;
1479
1554
  };
1480
1555
  const immediatelyDone = iterate();
1481
- if (!hadSyncValue && !immediatelyDone) {
1556
+ initialRead = false;
1557
+ if (!hadValue && !immediatelyDone) {
1482
1558
  globalQueue.initTransition(resolveTransition(el));
1483
1559
  throw new NotReadyError(context);
1484
1560
  }
@@ -1488,6 +1564,7 @@ function handleAsync(el, result, setter) {
1488
1564
  function clearStatus(el, clearUninitialized = false) {
1489
1565
  if (el._pendingSource || el._pendingSources) clearPendingSources(el);
1490
1566
  if (el._blocked) el._blocked = false;
1567
+ el._reask = false;
1491
1568
  el._statusFlags = clearUninitialized ? 0 : el._statusFlags & STATUS_UNINITIALIZED;
1492
1569
  if (el._error) setPendingError(el);
1493
1570
  if (el._pendingSignal || el._latestValueComputed) updatePendingSignal(el);
@@ -1557,6 +1634,48 @@ function notifyStatus(el, status, error, blockStatus, lane) {
1557
1634
  }
1558
1635
  });
1559
1636
  }
1637
+ function getAffectsSentinel(node) {
1638
+ return (node._affectsSentinel ??= {
1639
+ _name: "affects-sentinel",
1640
+ _affectsFor: node,
1641
+ _flags: 0,
1642
+ _statusFlags: 0,
1643
+ _reask: false,
1644
+ _error: undefined,
1645
+ _subs: null,
1646
+ _deps: null
1647
+ });
1648
+ }
1649
+ function propagateAffectsMark(node) {
1650
+ if (!node._subs && !node._child) return;
1651
+ const sentinel = getAffectsSentinel(node);
1652
+ const error = new NotReadyError(sentinel);
1653
+ forEachDependent(node, sub => {
1654
+ if (sub._pendingSource !== sentinel && !sub._pendingSources?.has(sentinel)) {
1655
+ if (!sub._transition) queuePendingNode(sub);
1656
+ notifyStatus(sub, STATUS_PENDING, error);
1657
+ }
1658
+ });
1659
+ }
1660
+ function applyAffectsReads(el, sources) {
1661
+ let applied = false;
1662
+ for (let i = 0; i < sources.length; i++) {
1663
+ const src = sources[i];
1664
+ if (!src._affectsCount) continue;
1665
+ const sentinel = getAffectsSentinel(src);
1666
+ if (addPendingSource(el, sentinel)) {
1667
+ el._statusFlags |= STATUS_PENDING;
1668
+ setPendingError(el, sentinel);
1669
+ applied = true;
1670
+ }
1671
+ }
1672
+ if (applied) updatePendingSignal(el);
1673
+ }
1674
+ GlobalQueue._propagateAffects = propagateAffectsMark;
1675
+ GlobalQueue._settleAffects = node => {
1676
+ const sentinel = node._affectsSentinel;
1677
+ if (sentinel) settlePendingSource(node, sentinel, true);
1678
+ };
1560
1679
  let externalSourceConfig = null;
1561
1680
  function enableExternalSource(config) {
1562
1681
  const { factory: factory, untrack: untrackFn = fn => fn() } = config;
@@ -1597,6 +1716,7 @@ let latestReadActive = false;
1597
1716
  let context = null;
1598
1717
  let currentOptimisticLane = null;
1599
1718
  let pendingProbe = null;
1719
+ let affectsReads = null;
1600
1720
  let snapshotCaptureActive = false;
1601
1721
  let snapshotSources = null;
1602
1722
  function ownerInSnapshotScope(owner) {
@@ -1669,8 +1789,9 @@ function recompute(el, create = false) {
1669
1789
  }
1670
1790
  let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
1671
1791
  const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
1672
- !!(el._statusFlags & STATUS_PENDING);
1792
+ const wasPending = !!(el._statusFlags & STATUS_PENDING);
1673
1793
  const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
1794
+ const isReask = !!(el._flags & REACTIVE_REASK) && !(wasPending && !el._reask);
1674
1795
  const oldcontext = context;
1675
1796
  context = el;
1676
1797
  el._depsTail = null;
@@ -1680,6 +1801,9 @@ function recompute(el, create = false) {
1680
1801
  let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
1681
1802
  let oldHeight = el._height;
1682
1803
  let prevTracking = tracking;
1804
+ const prevAffectsReads = affectsReads;
1805
+ affectsReads = null;
1806
+ let markedReads = null;
1683
1807
  let prevLane = currentOptimisticLane;
1684
1808
  let prevStrictRead = false;
1685
1809
  {
@@ -1735,7 +1859,12 @@ function recompute(el, create = false) {
1735
1859
  updatePendingSignal(lane._source);
1736
1860
  }
1737
1861
  }
1738
- if (e instanceof NotReadyError) el._blocked = true;
1862
+ let reaskChanged = false;
1863
+ if (e instanceof NotReadyError) {
1864
+ el._blocked = true;
1865
+ reaskChanged = wasPending && el._reask !== isReask;
1866
+ el._reask = isReask;
1867
+ }
1739
1868
  notifyStatus(
1740
1869
  el,
1741
1870
  e instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR,
@@ -1743,12 +1872,15 @@ function recompute(el, create = false) {
1743
1872
  undefined,
1744
1873
  e instanceof NotReadyError ? el._optimisticLane : undefined
1745
1874
  );
1875
+ if (reaskChanged) repollDownstreamVerdicts(el);
1746
1876
  } finally {
1747
1877
  tracking = prevTracking;
1748
1878
  strictRead = prevStrictRead;
1749
1879
  if (isStaleEffect) stale = prevStale;
1750
1880
  el._flags = REACTIVE_NONE | (create ? el._flags & REACTIVE_SNAPSHOT_STALE : 0);
1751
1881
  context = oldcontext;
1882
+ markedReads = affectsReads;
1883
+ affectsReads = prevAffectsReads;
1752
1884
  }
1753
1885
  if (!el._error) {
1754
1886
  trimStaleDeps(el);
@@ -1794,6 +1926,7 @@ function recompute(el, create = false) {
1794
1926
  }
1795
1927
  }
1796
1928
  currentOptimisticLane = prevLane;
1929
+ if (markedReads) applyAffectsReads(el, markedReads);
1797
1930
  const needsPendingCommit =
1798
1931
  el._pendingValue !== NOT_PENDING ||
1799
1932
  el._pendingFirstChild !== null ||
@@ -1870,7 +2003,8 @@ function computed(fn, options) {
1870
2003
  _pendingDisposal: null,
1871
2004
  _pendingFirstChild: null,
1872
2005
  _inFlight: null,
1873
- _transition: null
2006
+ _transition: null,
2007
+ _reask: false
1874
2008
  };
1875
2009
  self._name = options?.name ?? "computed";
1876
2010
  setupComputedNode(self, options);
@@ -1916,6 +2050,7 @@ function createEffectNode(fn, effectFn, errorFn, type, notifyStatus, options) {
1916
2050
  _pendingFirstChild: null,
1917
2051
  _inFlight: null,
1918
2052
  _transition: null,
2053
+ _reask: false,
1919
2054
  _modified: false,
1920
2055
  _prevValue: undefined,
1921
2056
  _effectFn: effectFn,
@@ -2105,7 +2240,11 @@ function read(el) {
2105
2240
  !snapshotCaptureActive &&
2106
2241
  !strictRead
2107
2242
  ) {
2108
- if (c && tracking) link(el, c);
2243
+ if (c && tracking) {
2244
+ link(el, c);
2245
+ if (activeAffectsMarks !== 0 && el._affectsCount && !pendingCheckActive)
2246
+ (affectsReads ??= []).push(el);
2247
+ }
2109
2248
  return !c || el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
2110
2249
  }
2111
2250
  if (strictRead && owner._statusFlags & STATUS_PENDING) {
@@ -2126,6 +2265,8 @@ function read(el) {
2126
2265
  }
2127
2266
  if (c && tracking) {
2128
2267
  link(el, c, pendingCheckActive);
2268
+ if (activeAffectsMarks !== 0 && el._affectsCount && !pendingCheckActive)
2269
+ (affectsReads ??= []).push(el);
2129
2270
  if (owner._fn) {
2130
2271
  const isZombie = el._flags & REACTIVE_ZOMBIE;
2131
2272
  if (owner._height >= (isZombie ? zombieQueue._min : dirtyQueue._min)) {
@@ -2360,29 +2501,48 @@ function collectPendingSources(el) {
2360
2501
  const owner = el._firewall || el;
2361
2502
  if (owner !== el) pendingProbe.sources.add(owner);
2362
2503
  }
2504
+ function witnessAffects(node) {
2505
+ pendingProbe?.sources.add(node);
2506
+ }
2507
+ function quietPending(el) {
2508
+ if (el._pendingSources) {
2509
+ for (const source of el._pendingSources) if (!source._reask) return false;
2510
+ return true;
2511
+ }
2512
+ if (el._pendingSource) return el._pendingSource._reask;
2513
+ return el._reask;
2514
+ }
2515
+ function newQuestionInFlight(comp) {
2516
+ return (
2517
+ !!(comp._statusFlags & STATUS_PENDING) &&
2518
+ !(comp._statusFlags & STATUS_UNINITIALIZED) &&
2519
+ !quietPending(comp)
2520
+ );
2521
+ }
2363
2522
  function computePendingState(el) {
2364
2523
  const comp = el;
2365
2524
  if (comp._flags & REACTIVE_DISPOSED) return false;
2525
+ if (el._affectsCount) return true;
2366
2526
  const firewall = el._firewall;
2367
- if ((firewall || comp)._optimisticMask) return false;
2368
2527
  if (el._parentSource) {
2369
2528
  const parentNode = el._parentSource;
2370
- if (hasActiveOverride(parentNode)) return false;
2529
+ if (parentNode._affectsCount) return true;
2371
2530
  const parent = parentNode._firewall || parentNode;
2372
- if (parent._optimisticMask) return false;
2373
- return !!(
2374
- parent._statusFlags & STATUS_PENDING && !(parent._statusFlags & STATUS_UNINITIALIZED)
2375
- );
2531
+ return newQuestionInFlight(parent);
2376
2532
  }
2377
- if (hasActiveOverride(el)) return false;
2378
- if (firewall && el._pendingValue !== NOT_PENDING) {
2533
+ if (firewall && el._pendingValue !== NOT_PENDING && !hasActiveOverride(el)) {
2379
2534
  return (
2380
2535
  !!(firewall._flags & REACTIVE_MANUAL_WRITE) ||
2381
- (!firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING))
2536
+ (!firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING)) ||
2537
+ (!!(firewall._statusFlags & STATUS_PENDING) && quietPending(firewall))
2382
2538
  );
2383
2539
  }
2384
- if (el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED)) return true;
2385
- return !!(comp._statusFlags & STATUS_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED));
2540
+ if (el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED)) {
2541
+ if (hasActiveOverride(el))
2542
+ return !el._equals || !el._equals(el._pendingValue, el._overrideValue);
2543
+ return true;
2544
+ }
2545
+ return newQuestionInFlight(comp);
2386
2546
  }
2387
2547
  function syncCompanions(el, value) {
2388
2548
  if (el._pendingSignal) updatePendingSignal(el);
@@ -2399,6 +2559,19 @@ function updateChildCompanions(el) {
2399
2559
  if (child._pendingSignal || child._latestValueComputed) updatePendingSignal(child);
2400
2560
  }
2401
2561
  }
2562
+ function repollDownstreamVerdicts(el) {
2563
+ const visited = new Set();
2564
+ const visit = node => {
2565
+ if (visited.has(node)) return;
2566
+ visited.add(node);
2567
+ if (node._pendingSignal || node._latestValueComputed) updatePendingSignal(node);
2568
+ for (let s = node._subs; s !== null; s = s._nextSub) visit(s._sub);
2569
+ for (let child = node._child ?? null; child !== null; child = child._nextChild) {
2570
+ visit(child);
2571
+ }
2572
+ };
2573
+ visit(el);
2574
+ }
2402
2575
  function snapCompanionsToState(owner) {
2403
2576
  const sig = owner._pendingSignal;
2404
2577
  if (sig && (sig._overrideValue === undefined || sig._overrideValue === NOT_PENDING)) {
@@ -2486,8 +2659,9 @@ function isPending(fn) {
2486
2659
  } catch (e) {
2487
2660
  collectPending();
2488
2661
  if (e instanceof NotReadyError) {
2489
- if (probe.found && !(e.source?._statusFlags & STATUS_UNINITIALIZED)) return true;
2490
- if (context) throw e;
2662
+ const uninitialized = !!(e.source?._statusFlags & STATUS_UNINITIALIZED);
2663
+ if (probe.found && !uninitialized) return true;
2664
+ if (context && uninitialized) throw e;
2491
2665
  }
2492
2666
  return probe.found;
2493
2667
  } finally {
@@ -2532,6 +2706,10 @@ function refresh(target) {
2532
2706
  typeof node._fn === "function" &&
2533
2707
  !(node._flags & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))
2534
2708
  ) {
2709
+ if (!(node._flags & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
2710
+ node._flags |= REACTIVE_REASK;
2711
+ armReaskClear();
2712
+ }
2535
2713
  node._flags = (node._flags & ~REACTIVE_CHECK) | REACTIVE_DIRTY;
2536
2714
  insertIntoHeap(node, node._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
2537
2715
  schedule();
@@ -2632,8 +2810,7 @@ function notifyEffectStatus(status, error) {
2632
2810
  function runEffect(node) {
2633
2811
  if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
2634
2812
  if (node._statusFlags & STATUS_ERROR && node._type === EFFECT_USER) {
2635
- const err =
2636
- node._error instanceof StatusError ? (node._error.cause ?? node._error) : node._error;
2813
+ const err = unwrapStatusError(node._error);
2637
2814
  node._prevValue = node._value;
2638
2815
  node._modified = false;
2639
2816
  try {
@@ -2739,6 +2916,9 @@ function trackedEffect(fn, options) {
2739
2916
  console.warn(message);
2740
2917
  }
2741
2918
  }
2919
+ const ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE =
2920
+ "[ACTION_CALLED_IN_OWNED_SCOPE] Calling an action inside an owned scope (component, computation) is not allowed. " +
2921
+ "Call it from an event handler or another imperative scope.";
2742
2922
  function restoreTransition(transition, fn) {
2743
2923
  globalQueue.initTransition(transition);
2744
2924
  const result = fn();
@@ -2746,28 +2926,42 @@ function restoreTransition(transition, fn) {
2746
2926
  return result;
2747
2927
  }
2748
2928
  function action(genFn) {
2749
- return (...args) =>
2750
- new Promise((resolve, reject) => {
2929
+ return (...args) => {
2930
+ {
2931
+ const owner = getOwner();
2932
+ if (owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)) {
2933
+ emitDiagnostic({
2934
+ code: "ACTION_CALLED_IN_OWNED_SCOPE",
2935
+ kind: "write",
2936
+ severity: "error",
2937
+ message: ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE,
2938
+ ownerId: owner.id,
2939
+ ownerName: owner._name
2940
+ });
2941
+ throw new Error(ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE);
2942
+ }
2943
+ }
2944
+ return new Promise((resolve, reject) => {
2751
2945
  const it = genFn(...args);
2752
2946
  globalQueue.initTransition();
2753
2947
  let ctx = activeTransition;
2754
2948
  ctx._actions.push(it);
2755
- const done = (v, e) => {
2949
+ const done = (v, e, failed = false) => {
2756
2950
  ctx = currentTransition(ctx);
2757
2951
  const i = ctx._actions.indexOf(it);
2758
2952
  if (i >= 0) ctx._actions.splice(i, 1);
2759
2953
  setActiveTransition(ctx);
2760
2954
  schedule();
2761
- e ? reject(e) : resolve(v);
2955
+ failed ? reject(e) : resolve(v);
2762
2956
  };
2763
2957
  const step = (v, err) => {
2764
2958
  let r;
2765
2959
  try {
2766
2960
  r = err ? it.throw(v) : it.next(v);
2767
2961
  } catch (e) {
2768
- return done(undefined, e);
2962
+ return done(undefined, e, true);
2769
2963
  }
2770
- if (isThenable(r)) return void r.then(run, e => done(undefined, e));
2964
+ if (isThenable(r)) return void r.then(run, e => done(undefined, e, true));
2771
2965
  run(r);
2772
2966
  };
2773
2967
  const run = r => {
@@ -2781,6 +2975,7 @@ function action(genFn) {
2781
2975
  };
2782
2976
  step();
2783
2977
  });
2978
+ };
2784
2979
  }
2785
2980
  function onCleanup(fn) {
2786
2981
  {
@@ -2859,11 +3054,17 @@ function createReaction(effectFn, options) {
2859
3054
  let cl = undefined;
2860
3055
  cleanup(() => cl?.());
2861
3056
  const owner = getOwner();
3057
+ let arm;
2862
3058
  return tracking => {
3059
+ if (arm) {
3060
+ dispose(arm);
3061
+ arm = undefined;
3062
+ }
2863
3063
  runWithOwner(owner, () => {
2864
3064
  effect(
2865
- () => (tracking(), getOwner()),
3065
+ () => (tracking(), (arm = getOwner())),
2866
3066
  node => {
3067
+ arm = undefined;
2867
3068
  cl?.();
2868
3069
  const cleanup = (effectFn.effect || effectFn)?.();
2869
3070
  if (true && cleanup !== undefined && typeof cleanup !== "function") {
@@ -3406,7 +3607,8 @@ function createWriteTraps(isActive, onDraftWrite) {
3406
3607
  const $TRACK = Symbol("STORE_TRACK"),
3407
3608
  $TARGET = Symbol("STORE_TARGET"),
3408
3609
  $PROXY = Symbol("STORE_PROXY"),
3409
- $DELETED = Symbol("STORE_DELETED");
3610
+ $DELETED = Symbol("STORE_DELETED"),
3611
+ $AFFECTS = Symbol("STORE_AFFECTS");
3410
3612
  const STORE_VALUE = "v",
3411
3613
  STORE_OVERRIDE = "o",
3412
3614
  STORE_OPTIMISTIC_OVERRIDE = "x",
@@ -3416,8 +3618,7 @@ const STORE_VALUE = "v",
3416
3618
  STORE_WRAP = "w",
3417
3619
  STORE_LOOKUP = "l",
3418
3620
  STORE_FIREWALL = "f",
3419
- STORE_OPTIMISTIC = "p",
3420
- STORE_MASKED = "m";
3621
+ STORE_OPTIMISTIC = "p";
3421
3622
  const STORE_SELF_PENDING = Symbol("STORE_SELF_PENDING");
3422
3623
  function createStoreProxy(value, traps = storeTraps, extend) {
3423
3624
  let newTarget;
@@ -3513,7 +3714,7 @@ function getNodes(target, type) {
3513
3714
  if (!nodes) target[type] = nodes = Object.create(null);
3514
3715
  return nodes;
3515
3716
  }
3516
- function getNode(nodes, property, value, firewall, equals = isEqual, optimistic, snapshotProps) {
3717
+ function getNode(target, nodes, property, value, equals = isEqual, snapshotProps) {
3517
3718
  if (nodes[property]) return nodes[property];
3518
3719
  const s = signal(
3519
3720
  value,
@@ -3525,12 +3726,13 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
3525
3726
  if (
3526
3727
  typeof property === "symbol" &&
3527
3728
  property !== $TRACK &&
3729
+ property !== $AFFECTS &&
3528
3730
  symbolKeyedRecords.has(nodes)
3529
3731
  ) {
3530
3732
  const syms = Object.getOwnPropertySymbols(nodes);
3531
3733
  let hasUserSymbol = false;
3532
3734
  for (let i = 0, len = syms.length; i < len; i++) {
3533
- if (syms[i] !== $TRACK) {
3735
+ if (syms[i] !== $TRACK && syms[i] !== $AFFECTS) {
3534
3736
  hasUserSymbol = true;
3535
3737
  break;
3536
3738
  }
@@ -3540,9 +3742,9 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
3540
3742
  }
3541
3743
  }
3542
3744
  },
3543
- firewall
3745
+ target[STORE_FIREWALL]
3544
3746
  );
3545
- if (optimistic) {
3747
+ if (target[STORE_OPTIMISTIC]) {
3546
3748
  s._overrideValue = NOT_PENDING;
3547
3749
  }
3548
3750
  if (snapshotProps && property in snapshotProps) {
@@ -3550,21 +3752,99 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
3550
3752
  s._snapshotValue = sv === undefined ? NO_SNAPSHOT : sv;
3551
3753
  snapshotSources?.add(s);
3552
3754
  }
3553
- if (typeof property === "symbol" && property !== $TRACK) symbolKeyedRecords.add(nodes);
3755
+ if (typeof property === "symbol" && property !== $TRACK && property !== $AFFECTS)
3756
+ symbolKeyedRecords.add(nodes);
3757
+ if (property !== $AFFECTS && affectsScopes.size) inheritAffectsMarks(s, target[STORE_VALUE]);
3554
3758
  return (nodes[property] = s);
3555
3759
  }
3760
+ function inheritAffectsMarks(node, raw) {
3761
+ for (const [carrier, entry] of affectsScopes) {
3762
+ if (carrier._affectsCount && entry.scope.has(raw)) {
3763
+ markAffects(node);
3764
+ entry.inherited.push(node);
3765
+ }
3766
+ }
3767
+ }
3768
+ const affectsScopes = new Map();
3769
+ function walkAffectsScope(value, entry, found, lookup, visited) {
3770
+ if (!isWrappable(value)) return;
3771
+ const target = value[$TARGET] || (lookup ?? storeLookup).get(value)?.[$TARGET];
3772
+ const raw = target ? target[STORE_VALUE] : value;
3773
+ if (visited.has(raw)) return;
3774
+ visited.add(raw);
3775
+ entry.scope.add(raw);
3776
+ let override;
3777
+ if (target) {
3778
+ collectRecordNodes(target[STORE_NODE], found);
3779
+ collectRecordNodes(target[STORE_HAS], found);
3780
+ override = mergedOverlay(target);
3781
+ lookup = target[STORE_LOOKUP] ?? lookup;
3782
+ }
3783
+ if (Array.isArray(raw)) {
3784
+ const len = override?.length ?? raw.length;
3785
+ for (let i = 0; i < len; i++) {
3786
+ const v = override && i in override ? override[i] : raw[i];
3787
+ if (v !== $DELETED) walkAffectsScope(v, entry, found, lookup, visited);
3788
+ }
3789
+ } else {
3790
+ const keys = getKeys(raw, override);
3791
+ for (let i = 0, l = keys.length; i < l; i++) {
3792
+ const desc = getPropertyDescriptor(raw, override, keys[i]);
3793
+ if (!desc || desc.get) continue;
3794
+ walkAffectsScope(desc.value, entry, found, lookup, visited);
3795
+ }
3796
+ }
3797
+ }
3798
+ function collectRecordNodes(nodes, found) {
3799
+ if (!nodes) return;
3800
+ for (const key of Object.keys(nodes)) found.push(nodes[key]);
3801
+ const syms = Object.getOwnPropertySymbols(nodes);
3802
+ for (let i = 0, l = syms.length; i < l; i++) {
3803
+ if (syms[i] !== $AFFECTS) found.push(nodes[syms[i]]);
3804
+ }
3805
+ }
3806
+ function witnessAffectsMark(target) {
3807
+ const own = target[STORE_NODE]?.[$AFFECTS];
3808
+ if (own?._affectsCount) witnessAffects(own);
3809
+ if (affectsScopes.size) {
3810
+ const raw = target[STORE_VALUE];
3811
+ for (const [carrier, entry] of affectsScopes) {
3812
+ if (carrier !== own && carrier._affectsCount && entry.scope.has(raw)) witnessAffects(carrier);
3813
+ }
3814
+ }
3815
+ }
3816
+ function getStoreAffectsNodes(target, key) {
3817
+ const nodes = getNodes(target, STORE_NODE);
3818
+ if (key === undefined) {
3819
+ const carrier = getNode(target, nodes, $AFFECTS, undefined, false);
3820
+ GlobalQueue._releaseAffectsScope ||= node => {
3821
+ const entry = affectsScopes.get(node);
3822
+ if (!entry) return;
3823
+ affectsScopes.delete(node);
3824
+ for (let i = 0; i < entry.inherited.length; i++) releaseAffectsMark(entry.inherited[i]);
3825
+ };
3826
+ let entry = affectsScopes.get(carrier);
3827
+ if (!entry) affectsScopes.set(carrier, (entry = { scope: new Set(), inherited: [] }));
3828
+ const result = [carrier];
3829
+ walkAffectsScope(target[$PROXY], entry, result, target[STORE_LOOKUP], new Set());
3830
+ return result;
3831
+ }
3832
+ if (nodes[key]) return [nodes[key]];
3833
+ const layer = getOverlayLayer(target, key);
3834
+ const raw = layer ? layer[key] : target[STORE_VALUE][key];
3835
+ const prev = raw === $DELETED ? undefined : raw;
3836
+ return [upsertStoreNode(target, nodes, key, prev, target[STORE_SNAPSHOT_PROPS])];
3837
+ }
3556
3838
  function trackSelf(target, symbol = $TRACK) {
3557
- getObserver() &&
3558
- read(
3559
- getNode(
3560
- getNodes(target, STORE_NODE),
3561
- symbol,
3562
- undefined,
3563
- target[STORE_FIREWALL],
3564
- false,
3565
- target[STORE_OPTIMISTIC]
3566
- )
3567
- );
3839
+ if (!getObserver()) return;
3840
+ read(getNode(target, getNodes(target, STORE_NODE), symbol, undefined, false));
3841
+ if (
3842
+ symbol === $TRACK &&
3843
+ !target[STORE_OVERRIDE] &&
3844
+ !target[STORE_OPTIMISTIC_OVERRIDE] &&
3845
+ target[STORE_VALUE][$TARGET]
3846
+ )
3847
+ target[STORE_VALUE][$TRACK];
3568
3848
  }
3569
3849
  function notifySelf(target) {
3570
3850
  const node = target[STORE_NODE]?.[$TRACK];
@@ -3574,6 +3854,11 @@ function notifySelf(target) {
3574
3854
  target[STORE_OPTIMISTIC] && !projectionWriteActive ? STORE_SELF_PENDING : undefined
3575
3855
  );
3576
3856
  }
3857
+ function mergedOverlay(target) {
3858
+ const override = target[STORE_OVERRIDE];
3859
+ const opt = target[STORE_OPTIMISTIC_OVERRIDE];
3860
+ return override && opt ? { ...override, ...opt } : (opt ?? override);
3861
+ }
3577
3862
  function getKeys(source, override, enumerable = true) {
3578
3863
  const baseKeys = source[$TARGET]
3579
3864
  ? untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)))
@@ -3602,17 +3887,6 @@ function getPropertyDescriptor(source, override, property) {
3602
3887
  }
3603
3888
  return Reflect.getOwnPropertyDescriptor(source, property);
3604
3889
  }
3605
- function maskStoreTarget(target, on) {
3606
- const firewall = target[STORE_FIREWALL];
3607
- if (!firewall) return;
3608
- if (!!target[STORE_MASKED] === on) return;
3609
- target[STORE_MASKED] = on;
3610
- const count = (firewall._optimisticMask = (firewall._optimisticMask || 0) + (on ? 1 : -1));
3611
- if ((on && count === 1) || (!on && count === 0)) {
3612
- updatePendingSignal(firewall);
3613
- updateChildCompanions(firewall);
3614
- }
3615
- }
3616
3890
  function prepareStoreWrite(target, store, property) {
3617
3891
  if (target[STORE_OPTIMISTIC]) {
3618
3892
  const firewall = target[STORE_FIREWALL];
@@ -3642,21 +3916,12 @@ function prepareStoreWrite(target, store, property) {
3642
3916
  function armOptimisticStoreWrite(target, store) {
3643
3917
  if (target[STORE_OPTIMISTIC] && !projectionWriteActive) {
3644
3918
  trackOptimisticStore(store);
3645
- maskStoreTarget(target, true);
3646
3919
  }
3647
3920
  }
3648
3921
  function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
3649
3922
  if (nodes[property]) return nodes[property];
3650
3923
  const initial = isWrappable(prev) ? wrap(prev, target) : prev;
3651
- const node = getNode(
3652
- nodes,
3653
- property,
3654
- initial,
3655
- target[STORE_FIREWALL],
3656
- isEqual,
3657
- target[STORE_OPTIMISTIC],
3658
- snapshotProps
3659
- );
3924
+ const node = getNode(target, nodes, property, initial, isEqual, snapshotProps);
3660
3925
  registerTransientStoreNode(node);
3661
3926
  return node;
3662
3927
  }
@@ -3699,6 +3964,7 @@ const storeTraps = {
3699
3964
  if (property === $TARGET) return target;
3700
3965
  if (property === $PROXY) return receiver;
3701
3966
  if (property === $REFRESH) return target[STORE_FIREWALL];
3967
+ if (pendingCheckActive) witnessAffectsMark(target);
3702
3968
  if (property === $TRACK) {
3703
3969
  trackSelf(target);
3704
3970
  return receiver;
@@ -3720,7 +3986,7 @@ const storeTraps = {
3720
3986
  !selfRead &&
3721
3987
  !writeOnly(receiver)
3722
3988
  ) {
3723
- return read(getNode(nodes, property, undefined, target[STORE_FIREWALL]));
3989
+ return read(getNode(target, nodes, property, undefined));
3724
3990
  }
3725
3991
  const overlay = getOverlayLayer(target, property);
3726
3992
  const overridden = !!overlay;
@@ -3768,12 +4034,11 @@ const storeTraps = {
3768
4034
  } else if (getObserver() && !selfRead) {
3769
4035
  return read(
3770
4036
  getNode(
4037
+ target,
3771
4038
  nodes,
3772
4039
  property,
3773
4040
  isWrappable(value) ? wrap(value, target) : value,
3774
- target[STORE_FIREWALL],
3775
4041
  isEqual,
3776
- target[STORE_OPTIMISTIC],
3777
4042
  target[STORE_SNAPSHOT_PROPS]
3778
4043
  )
3779
4044
  );
@@ -3797,15 +4062,14 @@ const storeTraps = {
3797
4062
  },
3798
4063
  has(target, property) {
3799
4064
  if (property === $PROXY || property === $TRACK || property === "__proto__") return true;
4065
+ if (pendingCheckActive) witnessAffectsMark(target);
3800
4066
  const hasLayer = getOverlayLayer(target, property);
3801
4067
  const has = hasLayer ? hasLayer[property] !== $DELETED : property in target[STORE_VALUE];
3802
4068
  if (writeOnly(target[$PROXY]) || getObserver() === target[STORE_FIREWALL]) return has;
3803
4069
  const nodes = getNodes(target, STORE_HAS);
3804
4070
  if (nodes[property]) return read(nodes[property]);
3805
4071
  if (getObserver()) {
3806
- return read(
3807
- getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
3808
- );
4072
+ return read(getNode(target, nodes, property, has));
3809
4073
  }
3810
4074
  return has;
3811
4075
  },
@@ -3825,9 +4089,14 @@ const storeTraps = {
3825
4089
  ? prevLayer[property] !== $DELETED
3826
4090
  : property in target[STORE_VALUE];
3827
4091
  const value = unwrapStoreValue(rawValue);
4092
+ const index = typeof property === "string" ? Number(property) : -1;
3828
4093
  const isArrayIndexWrite =
3829
- Array.isArray(state) && property !== "length" && typeof property !== "symbol";
3830
- const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
4094
+ Array.isArray(state) &&
4095
+ Number.isInteger(index) &&
4096
+ index >= 0 &&
4097
+ index < 4294967295 &&
4098
+ String(index) === property;
4099
+ const nextIndex = isArrayIndexWrite ? index + 1 : 0;
3831
4100
  const len = isArrayIndexWrite && (getOverlayLayer(target, "length") ?? state).length;
3832
4101
  const nextLength = isArrayIndexWrite && nextIndex > len ? nextIndex : undefined;
3833
4102
  if (prev === value && nextLength === undefined) return true;
@@ -3930,6 +4199,7 @@ const storeTraps = {
3930
4199
  return true;
3931
4200
  },
3932
4201
  ownKeys(target) {
4202
+ if (pendingCheckActive) witnessAffectsMark(target);
3933
4203
  if (getObserver() !== target[STORE_FIREWALL]) trackSelf(target);
3934
4204
  let keys = getKeys(target[STORE_VALUE], target[STORE_OVERRIDE], false);
3935
4205
  if (target[STORE_OPTIMISTIC_OVERRIDE]) {
@@ -4013,6 +4283,58 @@ function createStore(first, second, options) {
4013
4283
  : fn => storeSetter(wrappedStore, fn)
4014
4284
  ];
4015
4285
  }
4286
+ function affects(target, key) {
4287
+ if (arguments.length > 2) {
4288
+ const message =
4289
+ "[INVALID_AFFECTS_TARGET] affects() takes a single optional key — extra keys are " +
4290
+ "not a path. Mark each slot with its own affects(record, key) call, or pass the " +
4291
+ 'nested record itself: affects(state.user, "name").';
4292
+ emitDiagnostic({
4293
+ code: "INVALID_AFFECTS_TARGET",
4294
+ kind: "write",
4295
+ severity: "error",
4296
+ message: message
4297
+ });
4298
+ throw new Error(message);
4299
+ }
4300
+ const storeTarget = target?.[$TARGET];
4301
+ if (storeTarget) {
4302
+ const nodes = getStoreAffectsNodes(storeTarget, key);
4303
+ for (let i = 0; i < nodes.length; i++) registerAffectsMark(nodes[i]);
4304
+ return;
4305
+ }
4306
+ const node = target?.[$REFRESH];
4307
+ if (node) {
4308
+ if (key !== undefined) {
4309
+ const message =
4310
+ "[INVALID_AFFECTS_TARGET] affects() keys are only valid on store targets. " +
4311
+ "An accessor is a single slot — pass it alone, or target the store record that owns the property.";
4312
+ emitDiagnostic({
4313
+ code: "INVALID_AFFECTS_TARGET",
4314
+ kind: "write",
4315
+ severity: "error",
4316
+ message: message,
4317
+ nodeName: node._name
4318
+ });
4319
+ throw new Error(message);
4320
+ }
4321
+ registerAffectsMark(node);
4322
+ return;
4323
+ }
4324
+ {
4325
+ const message =
4326
+ "[INVALID_AFFECTS_TARGET] affects() expects a Solid source accessor or a store node. " +
4327
+ "Pass the store proxy (optionally with a property key) or the original accessor, " +
4328
+ "not a wrapper function or an already-read value.";
4329
+ emitDiagnostic({
4330
+ code: "INVALID_AFFECTS_TARGET",
4331
+ kind: "write",
4332
+ severity: "error",
4333
+ message: message
4334
+ });
4335
+ throw new Error(message);
4336
+ }
4337
+ }
4016
4338
  function createOptimisticStore(first, second, options) {
4017
4339
  GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
4018
4340
  const derived = typeof first === "function";
@@ -4023,15 +4345,12 @@ function createOptimisticStore(first, second, options) {
4023
4345
  }
4024
4346
  function clearOptimisticStore(store) {
4025
4347
  const target = store[$TARGET];
4026
- if (!target) return;
4027
- maskStoreTarget(target, false);
4028
- if (!target[STORE_OPTIMISTIC_OVERRIDE]) return;
4348
+ if (!target?.[STORE_OPTIMISTIC_OVERRIDE]) return;
4029
4349
  clearOptimisticOverride(target);
4030
4350
  }
4031
4351
  function clearOptimisticOverride(target) {
4032
4352
  const override = target[STORE_OPTIMISTIC_OVERRIDE];
4033
4353
  if (!override) return;
4034
- maskStoreTarget(target, false);
4035
4354
  const nodes = target[STORE_NODE];
4036
4355
  delete target[STORE_OPTIMISTIC_OVERRIDE];
4037
4356
  const wasProjectionWriteActive = projectionWriteActive;
@@ -4198,18 +4517,16 @@ const storePath = Object.assign(
4198
4517
  },
4199
4518
  { DELETE: DELETE }
4200
4519
  );
4201
- function mergedOverlay(target) {
4202
- const override = target[STORE_OVERRIDE];
4203
- const opt = target[STORE_OPTIMISTIC_OVERRIDE];
4204
- return override && opt ? { ...override, ...opt } : (opt ?? override);
4205
- }
4206
4520
  function snapshotImpl(item, track, map, lookup) {
4207
4521
  let target, isArray, override, result, unwrapped, v;
4208
4522
  if (!isWrappable(item)) return item;
4209
4523
  if (map && map.has(item)) return map.get(item);
4210
4524
  if (!map) map = new Map();
4211
4525
  if ((target = item[$TARGET] || lookup?.get(item)?.[$TARGET])) {
4212
- if (track) trackSelf(target, $TRACK);
4526
+ if (track) {
4527
+ trackSelf(target, $TRACK);
4528
+ if (pendingCheckActive) witnessAffectsMark(target);
4529
+ }
4213
4530
  override = mergedOverlay(target);
4214
4531
  isArray = Array.isArray(target[STORE_VALUE]);
4215
4532
  map.set(
@@ -4751,7 +5068,7 @@ class RevealController {
4751
5068
  }
4752
5069
  isMinimallyReady() {
4753
5070
  const order = untrack(this._orderAccessor);
4754
- if (order === "together") return this.isReady();
5071
+ if (order === "together") return this._forEachOwnedSlot(isSlotMinimallyReady);
4755
5072
  if (order === "natural") {
4756
5073
  let hasSlot = false;
4757
5074
  let anyReady = false;
@@ -4875,9 +5192,6 @@ class CollectionQueue extends Queue {
4875
5192
  this._sources.clear();
4876
5193
  }
4877
5194
  }
4878
- if (this._collectionType & STATUS_PENDING && flags & STATUS_ERROR) {
4879
- return super.notify(node, STATUS_ERROR, flags, error);
4880
- }
4881
5195
  if (this._collectionType & STATUS_PENDING && this._initialized)
4882
5196
  return super.notify(node, type, flags, error);
4883
5197
  if (flags & this._collectionType) {
@@ -4888,7 +5202,7 @@ class CollectionQueue extends Queue {
4888
5202
  this._sources.add(source);
4889
5203
  if (wasEmpty) setSignal(this._disabled, true);
4890
5204
  if (this._collectionType & STATUS_ERROR) {
4891
- setSignal(this._error, source._error?.cause ?? source._error);
5205
+ setSignal(this._error, unwrapStatusError(source._error));
4892
5206
  }
4893
5207
  }
4894
5208
  }
@@ -5081,6 +5395,7 @@ export {
5081
5395
  NotReadyError,
5082
5396
  SUPPORTS_PROXY,
5083
5397
  action,
5398
+ affects,
5084
5399
  clearSnapshots,
5085
5400
  createContext,
5086
5401
  createEffect,