@solidjs/signals 2.0.0-beta.7 → 2.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/dev.js +401 -199
  2. package/dist/node.cjs +1403 -1259
  3. package/dist/prod.js +1053 -905
  4. package/dist/types/boundaries.d.ts +79 -3
  5. package/dist/types/core/action.d.ts +34 -0
  6. package/dist/types/core/constants.d.ts +17 -0
  7. package/dist/types/core/core.d.ts +108 -9
  8. package/dist/types/core/dev.d.ts +1 -1
  9. package/dist/types/core/effect.d.ts +3 -2
  10. package/dist/types/core/owner.d.ts +54 -3
  11. package/dist/types/core/scheduler.d.ts +19 -2
  12. package/dist/types/core/types.d.ts +2 -5
  13. package/dist/types/index.d.ts +2 -2
  14. package/dist/types/map.d.ts +32 -3
  15. package/dist/types/signals.d.ts +283 -16
  16. package/dist/types/store/optimistic.d.ts +38 -12
  17. package/dist/types/store/projection.d.ts +54 -14
  18. package/dist/types/store/reconcile.d.ts +22 -0
  19. package/dist/types/store/store.d.ts +64 -14
  20. package/dist/types/store/storePath.d.ts +28 -0
  21. package/dist/types/store/utils.d.ts +78 -7
  22. package/dist/types-cjs/boundaries.d.cts +79 -3
  23. package/dist/types-cjs/core/action.d.cts +34 -0
  24. package/dist/types-cjs/core/constants.d.cts +17 -0
  25. package/dist/types-cjs/core/core.d.cts +108 -9
  26. package/dist/types-cjs/core/dev.d.cts +1 -1
  27. package/dist/types-cjs/core/effect.d.cts +3 -2
  28. package/dist/types-cjs/core/owner.d.cts +54 -3
  29. package/dist/types-cjs/core/scheduler.d.cts +19 -2
  30. package/dist/types-cjs/core/types.d.cts +2 -5
  31. package/dist/types-cjs/index.d.cts +2 -2
  32. package/dist/types-cjs/map.d.cts +32 -3
  33. package/dist/types-cjs/signals.d.cts +283 -16
  34. package/dist/types-cjs/store/optimistic.d.cts +38 -12
  35. package/dist/types-cjs/store/projection.d.cts +54 -14
  36. package/dist/types-cjs/store/reconcile.d.cts +22 -0
  37. package/dist/types-cjs/store/store.d.cts +64 -14
  38. package/dist/types-cjs/store/storePath.d.cts +28 -0
  39. package/dist/types-cjs/store/utils.d.cts +78 -7
  40. package/package.json +4 -3
package/dist/dev.js CHANGED
@@ -35,6 +35,12 @@ const REACTIVE_DISPOSED = 1 << 6;
35
35
  const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
36
36
  const REACTIVE_SNAPSHOT_STALE = 1 << 8;
37
37
  const REACTIVE_LAZY = 1 << 9;
38
+ const CONFIG_OWNED_WRITE = 1 << 0;
39
+ const CONFIG_NO_SNAPSHOT = 1 << 1;
40
+ const CONFIG_TRANSPARENT = 1 << 2;
41
+ const CONFIG_IN_SNAPSHOT_SCOPE = 1 << 3;
42
+ const CONFIG_CHILDREN_FORBIDDEN = 1 << 4;
43
+ const CONFIG_AUTO_DISPOSE = 1 << 5;
38
44
  const STATUS_PENDING = 1 << 0;
39
45
  const STATUS_ERROR = 1 << 1;
40
46
  const STATUS_UNINITIALIZED = 1 << 2;
@@ -240,6 +246,23 @@ let inTrackedQueueCallback = false;
240
246
  let _enforceLoadingBoundary = false;
241
247
  let _hitUnhandledAsync = false;
242
248
  let stashedOptimisticReads = null;
249
+ const transientStoreNodes = new Set();
250
+ function registerTransientStoreNode(node) {
251
+ transientStoreNodes.add(node);
252
+ }
253
+ function sweepTransientStoreNodes() {
254
+ if (transientStoreNodes.size === 0) return;
255
+ for (const node of transientStoreNodes) {
256
+ if (node._subs !== null) {
257
+ transientStoreNodes.delete(node);
258
+ continue;
259
+ }
260
+ if (node._pendingValue !== NOT_PENDING) continue;
261
+ if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
262
+ transientStoreNodes.delete(node);
263
+ node._unobserved?.();
264
+ }
265
+ }
243
266
  function resetUnhandledAsync() {
244
267
  _hitUnhandledAsync = false;
245
268
  }
@@ -292,6 +315,7 @@ function mergeTransitionState(target, outgoing) {
292
315
  if (!targetReporters) target._asyncReporters.set(source, (targetReporters = new Set()));
293
316
  for (const reporter of reporters) targetReporters.add(reporter);
294
317
  }
318
+ for (const sub of outgoing._gatedSubs) target._gatedSubs.add(sub);
295
319
  }
296
320
  function resolveOptimisticNodes(nodes) {
297
321
  for (let i = 0; i < nodes.length; i++) {
@@ -422,11 +446,15 @@ class GlobalQueue extends Queue {
422
446
  scheduled = dirtyQueue._max >= dirtyQueue._min;
423
447
  reassignPendingTransition(stashedTransition._pendingNodes);
424
448
  activeTransition = null;
425
- if (!stashedTransition._actions.length && stashedTransition._optimisticNodes.length) {
449
+ if (
450
+ !stashedTransition._actions.length &&
451
+ !stashedTransition._asyncReporters.size &&
452
+ stashedTransition._optimisticNodes.length
453
+ ) {
426
454
  stashedOptimisticReads = new Set();
427
455
  for (let i = 0; i < stashedTransition._optimisticNodes.length; i++) {
428
456
  const node = stashedTransition._optimisticNodes[i];
429
- if (node._fn || node._ownedWrite) continue;
457
+ if (node._fn || node._config & CONFIG_OWNED_WRITE) continue;
430
458
  stashedOptimisticReads.add(node);
431
459
  queueStashedOptimisticEffects(node);
432
460
  }
@@ -492,7 +520,8 @@ class GlobalQueue extends Queue {
492
520
  _optimisticStores: new Set(),
493
521
  _actions: [],
494
522
  _queueStash: { _queues: [[], []], _children: [] },
495
- _done: false
523
+ _done: false,
524
+ _gatedSubs: new Set()
496
525
  };
497
526
  } else if (transition) {
498
527
  const outgoing = activeTransition;
@@ -531,7 +560,7 @@ function insertSubs(node, optimistic = false) {
531
560
  const sourceLane = node._optimisticLane || currentOptimisticLane;
532
561
  const hasSnapshot = node._snapshotValue !== undefined;
533
562
  for (let s = node._subs; s !== null; s = s._nextSub) {
534
- if (hasSnapshot && s._sub._inSnapshotScope) {
563
+ if (hasSnapshot && s._sub._config & CONFIG_IN_SNAPSHOT_SCOPE) {
535
564
  s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
536
565
  continue;
537
566
  }
@@ -579,6 +608,22 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
579
608
  resolveOptimisticNodes(
580
609
  completingTransition ? completingTransition._optimisticNodes : globalQueue._optimisticNodes
581
610
  );
611
+ if (completingTransition && completingTransition._gatedSubs.size) {
612
+ for (const sub of completingTransition._gatedSubs) {
613
+ if (sub._flags & REACTIVE_DISPOSED) continue;
614
+ if (sub._type === EFFECT_TRACKED) {
615
+ if (!sub._modified) {
616
+ sub._modified = true;
617
+ sub._queue.enqueue(EFFECT_USER, sub._run);
618
+ }
619
+ continue;
620
+ }
621
+ const queue = sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
622
+ if (queue._min > sub._height) queue._min = sub._height;
623
+ insertIntoHeap(sub, queue);
624
+ }
625
+ completingTransition._gatedSubs.clear();
626
+ }
582
627
  const optimisticStores = completingTransition
583
628
  ? completingTransition._optimisticStores
584
629
  : globalQueue._optimisticStores;
@@ -589,6 +634,7 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
589
634
  optimisticStores.clear();
590
635
  schedule();
591
636
  }
637
+ sweepTransientStoreNodes();
592
638
  cleanupCompletedLanes(completingTransition);
593
639
  }
594
640
  }
@@ -778,7 +824,8 @@ function unlinkSubs(link) {
778
824
  dep._subs = nextSub;
779
825
  if (nextSub === null) {
780
826
  dep._unobserved?.();
781
- dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
827
+ const c = dep;
828
+ c._fn && c._config & CONFIG_AUTO_DISPOSE && !(c._flags & REACTIVE_ZOMBIE) && unobserved(c);
782
829
  }
783
830
  }
784
831
  return nextDep;
@@ -895,7 +942,7 @@ function runDisposal(node, zombie) {
895
942
  }
896
943
  function childId(owner, consume) {
897
944
  let counter = owner;
898
- while (counter._transparent && counter._parent) counter = counter._parent;
945
+ while (counter._config & CONFIG_TRANSPARENT && counter._parent) counter = counter._parent;
899
946
  if (counter.id != null)
900
947
  return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
901
948
  throw new Error("Cannot get child id from owner without an id");
@@ -935,7 +982,7 @@ function createOwner(options) {
935
982
  id:
936
983
  options?.id ??
937
984
  (transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
938
- _transparent: transparent || undefined,
985
+ _config: transparent ? CONFIG_TRANSPARENT : 0,
939
986
  _root: true,
940
987
  _parentComputed: parent?._root ? parent._parentComputed : parent,
941
988
  _firstChild: null,
@@ -951,10 +998,16 @@ function createOwner(options) {
951
998
  disposeChildren(owner, self);
952
999
  }
953
1000
  };
954
- if (parent?._childrenForbidden) {
955
- throw new Error(
956
- "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
957
- );
1001
+ if (parent && parent._config & CONFIG_CHILDREN_FORBIDDEN) {
1002
+ emitDiagnostic({
1003
+ code: "PRIMITIVE_IN_FORBIDDEN_SCOPE",
1004
+ kind: "lifecycle",
1005
+ severity: "error",
1006
+ message: PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE,
1007
+ ownerId: parent.id,
1008
+ ownerName: parent._name
1009
+ });
1010
+ throw new Error(PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE);
958
1011
  }
959
1012
  if (parent) {
960
1013
  const lastChild = parent._firstChild;
@@ -1281,6 +1334,8 @@ function enableExternalSource(config) {
1281
1334
  }
1282
1335
  GlobalQueue._update = recompute;
1283
1336
  GlobalQueue._dispose = disposeChildren;
1337
+ const PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE =
1338
+ "[PRIMITIVE_IN_FORBIDDEN_SCOPE] Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled";
1284
1339
  let tracking = false;
1285
1340
  let stale = false;
1286
1341
  let refreshing = false;
@@ -1319,7 +1374,7 @@ function releaseSubtree(owner) {
1319
1374
  }
1320
1375
  if (child._fn) {
1321
1376
  const comp = child;
1322
- comp._inSnapshotScope = false;
1377
+ comp._config &= ~CONFIG_IN_SNAPSHOT_SCOPE;
1323
1378
  if (comp._flags & REACTIVE_SNAPSHOT_STALE) {
1324
1379
  comp._flags &= ~REACTIVE_SNAPSHOT_STALE;
1325
1380
  comp._flags |= REACTIVE_DIRTY;
@@ -1359,7 +1414,7 @@ function recompute(el, create = false) {
1359
1414
  clearSignals(el);
1360
1415
  }
1361
1416
  }
1362
- const isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
1417
+ let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
1363
1418
  const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
1364
1419
  const wasPending = !!(el._statusFlags & STATUS_PENDING);
1365
1420
  const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
@@ -1381,9 +1436,25 @@ function recompute(el, create = false) {
1381
1436
  if (isOptimisticDirty) {
1382
1437
  const lane = resolveLane(el);
1383
1438
  if (lane) currentOptimisticLane = lane;
1439
+ } else if (activeTransition && !create && activeTransition._optimisticNodes.length) {
1440
+ for (let d = el._deps; d; d = d._nextDep) {
1441
+ const dep = d._dep;
1442
+ if (dep._flags & REACTIVE_OPTIMISTIC_DIRTY) {
1443
+ const depLane = resolveLane(dep);
1444
+ if (depLane) {
1445
+ isOptimisticDirty = true;
1446
+ currentOptimisticLane = depLane;
1447
+ el._flags |= REACTIVE_OPTIMISTIC_DIRTY;
1448
+ assignOrMergeLane(el, depLane);
1449
+ break;
1450
+ }
1451
+ }
1452
+ }
1384
1453
  }
1385
1454
  try {
1386
- value = handleAsync(el, el._fn(value));
1455
+ const prevInFlight = el._inFlight;
1456
+ const fnResult = el._fn(value);
1457
+ value = el._inFlight !== prevInFlight ? fnResult : handleAsync(el, fnResult);
1387
1458
  clearStatus(el, create);
1388
1459
  const resolvedLane = resolveLane(el);
1389
1460
  if (resolvedLane) {
@@ -1482,22 +1553,25 @@ function updateIfNecessary(el) {
1482
1553
  }
1483
1554
  el._flags = el._flags & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
1484
1555
  }
1485
- function computed(fn, initialValue, options) {
1556
+ function computed(fn, options) {
1486
1557
  const transparent = options?.transparent ?? false;
1487
1558
  const self = {
1488
1559
  id:
1489
1560
  options?.id ??
1490
1561
  (transparent ? context?.id : context?.id != null ? getNextChildId(context) : undefined),
1491
- _transparent: transparent || undefined,
1562
+ _config:
1563
+ (transparent ? CONFIG_TRANSPARENT : 0) |
1564
+ (options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
1565
+ (!context || options?.lazy ? CONFIG_AUTO_DISPOSE : 0) |
1566
+ (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
1492
1567
  _equals: options?.equals != null ? options.equals : isEqual,
1493
- _ownedWrite: !!options?.ownedWrite,
1494
1568
  _unobserved: options?.unobserved,
1495
1569
  _disposal: null,
1496
1570
  _queue: context?._queue ?? globalQueue,
1497
1571
  _context: context?._context ?? defaultContext,
1498
1572
  _childCount: 0,
1499
1573
  _fn: fn,
1500
- _value: initialValue,
1574
+ _value: undefined,
1501
1575
  _height: 0,
1502
1576
  _child: null,
1503
1577
  _nextHeap: undefined,
@@ -1521,10 +1595,16 @@ function computed(fn, initialValue, options) {
1521
1595
  self._name = options?.name ?? "computed";
1522
1596
  self._prevHeap = self;
1523
1597
  const parent = context?._root ? context._parentComputed : context;
1524
- if (context?._childrenForbidden) {
1525
- throw new Error(
1526
- "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
1527
- );
1598
+ if (context && context._config & CONFIG_CHILDREN_FORBIDDEN) {
1599
+ emitDiagnostic({
1600
+ code: "PRIMITIVE_IN_FORBIDDEN_SCOPE",
1601
+ kind: "lifecycle",
1602
+ severity: "error",
1603
+ message: PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE,
1604
+ ownerId: context.id,
1605
+ ownerName: context._name
1606
+ });
1607
+ throw new Error(PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE);
1528
1608
  }
1529
1609
  if (context) {
1530
1610
  const lastChild = context._firstChild;
@@ -1537,7 +1617,6 @@ function computed(fn, initialValue, options) {
1537
1617
  }
1538
1618
  DEV$1.hooks.onOwner?.(self);
1539
1619
  if (parent) self._height = parent._height + 1;
1540
- if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
1541
1620
  if (externalSourceConfig) {
1542
1621
  const bridgeSignal = signal(undefined, { equals: false, ownedWrite: true });
1543
1622
  const source = externalSourceConfig.factory(self._fn, () => {
@@ -1561,8 +1640,9 @@ function computed(fn, initialValue, options) {
1561
1640
  function signal(v, options, firewall = null) {
1562
1641
  const s = {
1563
1642
  _equals: options?.equals != null ? options.equals : isEqual,
1564
- _ownedWrite: !!options?.ownedWrite,
1565
- _noSnapshot: !!options?._noSnapshot,
1643
+ _config:
1644
+ (options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
1645
+ (options?._noSnapshot ? CONFIG_NO_SNAPSHOT : 0),
1566
1646
  _unobserved: options?.unobserved,
1567
1647
  _value: v,
1568
1648
  _subs: null,
@@ -1579,7 +1659,7 @@ function signal(v, options, firewall = null) {
1579
1659
  firewall && (firewall._child = s);
1580
1660
  if (
1581
1661
  snapshotCaptureActive &&
1582
- !s._noSnapshot &&
1662
+ !(s._config & CONFIG_NO_SNAPSHOT) &&
1583
1663
  !((firewall?._statusFlags ?? 0) & STATUS_PENDING)
1584
1664
  ) {
1585
1665
  s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
@@ -1592,8 +1672,8 @@ function optimisticSignal(v, options) {
1592
1672
  s._overrideValue = NOT_PENDING;
1593
1673
  return s;
1594
1674
  }
1595
- function optimisticComputed(fn, initialValue, options) {
1596
- const c = computed(fn, initialValue, options);
1675
+ function optimisticComputed(fn, options) {
1676
+ const c = computed(fn, options);
1597
1677
  c._overrideValue = NOT_PENDING;
1598
1678
  return c;
1599
1679
  }
@@ -1687,7 +1767,7 @@ function read(el) {
1687
1767
  const owner = el._firewall || el;
1688
1768
  if (strictRead && owner._statusFlags & STATUS_PENDING) {
1689
1769
  const message =
1690
- `Reading a pending async value directly in ${strictRead}. ` +
1770
+ `[PENDING_ASYNC_UNTRACKED_READ] Reading a pending async value directly in ${strictRead}. ` +
1691
1771
  `Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`;
1692
1772
  emitDiagnostic({
1693
1773
  code: "PENDING_ASYNC_UNTRACKED_READ",
@@ -1718,9 +1798,9 @@ function read(el) {
1718
1798
  }
1719
1799
  if (owner._statusFlags & STATUS_PENDING) {
1720
1800
  if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
1721
- if (c?._childrenForbidden) {
1801
+ if (c && c._config & CONFIG_CHILDREN_FORBIDDEN) {
1722
1802
  const message =
1723
- "Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
1803
+ "[PENDING_ASYNC_FORBIDDEN_SCOPE] Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
1724
1804
  "Use createEffect instead which supports async-aware reactivity.";
1725
1805
  emitDiagnostic({
1726
1806
  code: "PENDING_ASYNC_FORBIDDEN_SCOPE",
@@ -1757,7 +1837,7 @@ function read(el) {
1757
1837
  return read(el);
1758
1838
  } else throw el._error;
1759
1839
  }
1760
- if (snapshotCaptureActive && c && c._inSnapshotScope) {
1840
+ if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
1761
1841
  const sv = el._snapshotValue;
1762
1842
  if (sv !== undefined) {
1763
1843
  const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
@@ -1768,7 +1848,7 @@ function read(el) {
1768
1848
  }
1769
1849
  if (strictRead) {
1770
1850
  const message =
1771
- `Reactive value read directly in ${strictRead} will not update. ` +
1851
+ `[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
1772
1852
  `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
1773
1853
  emitDiagnostic({
1774
1854
  code: "STRICT_READ_UNTRACKED",
@@ -1786,6 +1866,18 @@ function read(el) {
1786
1866
  if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
1787
1867
  return el._overrideValue;
1788
1868
  }
1869
+ if (
1870
+ activeTransition !== null &&
1871
+ currentOptimisticLane !== null &&
1872
+ !latestReadActive &&
1873
+ el._pendingValue !== NOT_PENDING &&
1874
+ owner === el &&
1875
+ !el._fn &&
1876
+ c
1877
+ ) {
1878
+ activeTransition._gatedSubs.add(c);
1879
+ return el._value;
1880
+ }
1789
1881
  const value =
1790
1882
  !c ||
1791
1883
  (currentOptimisticLane !== null &&
@@ -1801,9 +1893,8 @@ function read(el) {
1801
1893
  !c &&
1802
1894
  owner === el &&
1803
1895
  typeof computed._fn === "function" &&
1804
- !computed._preventAutoDisposal &&
1896
+ el._config & CONFIG_AUTO_DISPOSE &&
1805
1897
  !(owner._statusFlags & STATUS_PENDING) &&
1806
- !computed._parent &&
1807
1898
  !el._subs
1808
1899
  ) {
1809
1900
  unobserved(el);
@@ -1811,9 +1902,14 @@ function read(el) {
1811
1902
  return value;
1812
1903
  }
1813
1904
  function setSignal(el, v) {
1814
- if (!el._ownedWrite && !context?._childrenForbidden && context && el._firewall !== context) {
1905
+ if (
1906
+ !(el._config & CONFIG_OWNED_WRITE) &&
1907
+ !(context && context._config & CONFIG_CHILDREN_FORBIDDEN) &&
1908
+ context &&
1909
+ el._firewall !== context
1910
+ ) {
1815
1911
  const message =
1816
- "Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
1912
+ "[SIGNAL_WRITE_IN_OWNED_SCOPE] Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
1817
1913
  "Move the write outside or set the `ownedWrite` option if this is intentional.";
1818
1914
  emitDiagnostic({
1819
1915
  code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
@@ -1874,7 +1970,7 @@ function setSignal(el, v) {
1874
1970
  function runWithOwner(owner, fn) {
1875
1971
  if (owner && owner._flags & REACTIVE_DISPOSED) {
1876
1972
  const message =
1877
- "runWithOwner called with a disposed owner. Children created inside will never be disposed.";
1973
+ "[RUN_WITH_DISPOSED_OWNER] runWithOwner called with a disposed owner. Children created inside will never be disposed.";
1878
1974
  emitDiagnostic({
1879
1975
  code: "RUN_WITH_DISPOSED_OWNER",
1880
1976
  kind: "owner",
@@ -2041,26 +2137,24 @@ function hasContext(context, owner) {
2041
2137
  function isUndefined(value) {
2042
2138
  return typeof value === "undefined";
2043
2139
  }
2044
- function effect(compute, effect, error, initialValue, options) {
2140
+ function effect(compute, effect, error, options) {
2045
2141
  let initialized = false;
2046
- const node = computed(
2047
- options?.render ? p => staleValues(() => compute(p)) : compute,
2048
- initialValue,
2049
- {
2050
- ...options,
2051
- equals: () => {
2052
- node._modified = !node._error;
2053
- if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
2054
- return false;
2055
- },
2056
- lazy: true
2057
- }
2058
- );
2059
- node._prevValue = initialValue;
2142
+ const isUser = !!options?.user;
2143
+ const node = computed(isUser ? compute : p => staleValues(() => compute(p)), {
2144
+ ...options,
2145
+ equals: () => {
2146
+ node._modified = !node._error;
2147
+ if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
2148
+ return false;
2149
+ },
2150
+ lazy: true
2151
+ });
2152
+ node._config &= ~CONFIG_AUTO_DISPOSE;
2153
+ node._prevValue = undefined;
2060
2154
  node._effectFn = effect;
2061
2155
  node._errorFn = error;
2062
2156
  node._cleanup = undefined;
2063
- node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
2157
+ node._type = isUser ? EFFECT_USER : EFFECT_RENDER;
2064
2158
  node._notifyStatus = (status, error) => {
2065
2159
  const actualStatus = status !== undefined ? status : node._statusFlags;
2066
2160
  const actualError = error !== undefined ? error : node._error;
@@ -2085,29 +2179,31 @@ function effect(compute, effect, error, initialValue, options) {
2085
2179
  if (_hitUnhandledAsync) {
2086
2180
  resetUnhandledAsync();
2087
2181
  if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
2088
- const message = "An async value must be rendered inside a Loading boundary.";
2182
+ const message =
2183
+ "[ASYNC_OUTSIDE_LOADING_BOUNDARY] An async value was read outside a Loading boundary. The root mount will be deferred until all pending async settles.";
2089
2184
  emitDiagnostic({
2090
2185
  code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
2091
2186
  kind: "async",
2092
- severity: "error",
2187
+ severity: "warn",
2093
2188
  message: message,
2094
2189
  ownerId: node.id,
2095
2190
  ownerName: node._name
2096
2191
  });
2097
- throw new Error(message);
2192
+ console.warn(message);
2098
2193
  }
2099
2194
  }
2100
2195
  }
2101
2196
  };
2102
2197
  recompute(node, true);
2103
2198
  !options?.defer &&
2104
- (node._type === EFFECT_USER
2199
+ (node._type === EFFECT_USER || options?.schedule
2105
2200
  ? node._queue.enqueue(node._type, runEffect.bind(node))
2106
2201
  : runEffect.call(node));
2107
2202
  initialized = true;
2108
2203
  cleanup(() => node._cleanup?.());
2109
2204
  if (!node._parent) {
2110
- const message = "Effects created outside a reactive context will never be disposed";
2205
+ const message =
2206
+ "[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
2111
2207
  emitDiagnostic({
2112
2208
  code: "NO_OWNER_EFFECT",
2113
2209
  kind: "lifecycle",
@@ -2169,11 +2265,10 @@ function trackedEffect(fn, options) {
2169
2265
  }
2170
2266
  node._cleanup = cleanup;
2171
2267
  },
2172
- undefined,
2173
2268
  { ...options, lazy: true }
2174
2269
  );
2175
2270
  node._cleanup = undefined;
2176
- node._childrenForbidden = true;
2271
+ node._config = (node._config & ~CONFIG_AUTO_DISPOSE) | CONFIG_CHILDREN_FORBIDDEN;
2177
2272
  node._modified = true;
2178
2273
  node._type = EFFECT_TRACKED;
2179
2274
  node._notifyStatus = (status, error) => {
@@ -2188,7 +2283,8 @@ function trackedEffect(fn, options) {
2188
2283
  node._queue.enqueue(EFFECT_USER, run);
2189
2284
  cleanup(() => node._cleanup?.());
2190
2285
  if (!node._parent) {
2191
- const message = "Effects created outside a reactive context will never be disposed";
2286
+ const message =
2287
+ "[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
2192
2288
  emitDiagnostic({
2193
2289
  code: "NO_OWNER_EFFECT",
2194
2290
  kind: "lifecycle",
@@ -2249,7 +2345,8 @@ function onCleanup(fn) {
2249
2345
  {
2250
2346
  const owner = getOwner();
2251
2347
  if (!owner) {
2252
- const message = "onCleanup called outside a reactive context will never be run";
2348
+ const message =
2349
+ "[NO_OWNER_CLEANUP] onCleanup called outside a reactive context will never be run";
2253
2350
  emitDiagnostic({
2254
2351
  code: "NO_OWNER_CLEANUP",
2255
2352
  kind: "lifecycle",
@@ -2257,9 +2354,9 @@ function onCleanup(fn) {
2257
2354
  message: message
2258
2355
  });
2259
2356
  console.warn(message);
2260
- } else if (owner._childrenForbidden) {
2357
+ } else if (owner._config & CONFIG_CHILDREN_FORBIDDEN) {
2261
2358
  const message =
2262
- "Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead";
2359
+ "[CLEANUP_IN_FORBIDDEN_SCOPE] Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead";
2263
2360
  emitDiagnostic({
2264
2361
  code: "CLEANUP_IN_FORBIDDEN_SCOPE",
2265
2362
  kind: "lifecycle",
@@ -2274,14 +2371,12 @@ function onCleanup(fn) {
2274
2371
  return cleanup(fn);
2275
2372
  }
2276
2373
  function accessor(node) {
2277
- const fn = read.bind(null, node);
2278
- fn.$r = true;
2279
- return fn;
2374
+ return read.bind(null, node);
2280
2375
  }
2281
2376
  function createSignal(first, second) {
2282
2377
  if (typeof first === "function") {
2283
- const node = computed(first, undefined, second);
2284
- node._preventAutoDisposal = true;
2378
+ const node = computed(first, second);
2379
+ node._config &= ~CONFIG_AUTO_DISPOSE;
2285
2380
  return [accessor(node), setSignal.bind(null, node)];
2286
2381
  }
2287
2382
  const node = signal(first, second);
@@ -2289,20 +2384,30 @@ function createSignal(first, second) {
2289
2384
  return [accessor(node), setSignal.bind(null, node)];
2290
2385
  }
2291
2386
  function createMemo(compute, options) {
2292
- let node = computed(compute, undefined, options);
2293
- return accessor(node);
2387
+ return accessor(computed(compute, options));
2294
2388
  }
2295
2389
  function createEffect(compute, effectFn, options) {
2296
- effect(compute, effectFn.effect || effectFn, effectFn.error, undefined, {
2297
- ...options,
2298
- name: options?.name ?? "effect"
2390
+ if (effectFn === undefined) {
2391
+ const message =
2392
+ "[MISSING_EFFECT_FN] createEffect requires both a compute function and an effect function. " +
2393
+ "Use `createEffect(() => signal(), value => doWork(value))`. " +
2394
+ "If you want a derived value, use `createMemo`. " +
2395
+ "If you want a one-shot side effect, just call the function directly.";
2396
+ emitDiagnostic({
2397
+ code: "MISSING_EFFECT_FN",
2398
+ kind: "lifecycle",
2399
+ severity: "error",
2400
+ message: message
2401
+ });
2402
+ throw new Error(message);
2403
+ }
2404
+ effect(compute, effectFn.effect || effectFn, effectFn.error, {
2405
+ user: true,
2406
+ ...{ ...options, name: options?.name ?? "effect" }
2299
2407
  });
2300
2408
  }
2301
2409
  function createRenderEffect(compute, effectFn, options) {
2302
- effect(compute, effectFn, undefined, undefined, {
2303
- render: true,
2304
- ...{ ...options, name: options?.name ?? "effect" }
2305
- });
2410
+ effect(compute, effectFn, undefined, { ...options, name: options?.name ?? "effect" });
2306
2411
  }
2307
2412
  function createTrackedEffect(compute, options) {
2308
2413
  trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
@@ -2327,8 +2432,11 @@ function createReaction(effectFn, options) {
2327
2432
  dispose(node);
2328
2433
  },
2329
2434
  effectFn.error,
2330
- undefined,
2331
- { defer: true, ...(true ? { ...options, name: options?.name ?? "effect" } : options) }
2435
+ {
2436
+ ...(true ? { ...options, name: options?.name ?? "effect" } : options),
2437
+ user: true,
2438
+ defer: true
2439
+ }
2332
2440
  );
2333
2441
  });
2334
2442
  };
@@ -2355,8 +2463,8 @@ function resolve(fn) {
2355
2463
  }
2356
2464
  function createOptimistic(first, second) {
2357
2465
  if (typeof first === "function") {
2358
- const node = optimisticComputed(first, undefined, second);
2359
- node._preventAutoDisposal = true;
2466
+ const node = optimisticComputed(first, second);
2467
+ node._config &= ~CONFIG_AUTO_DISPOSE;
2360
2468
  return [accessor(node), setSignal.bind(null, node)];
2361
2469
  }
2362
2470
  const node = optimisticSignal(first, second);
@@ -2365,7 +2473,7 @@ function createOptimistic(first, second) {
2365
2473
  }
2366
2474
  function onSettled(callback) {
2367
2475
  const owner = getOwner();
2368
- owner && !owner._childrenForbidden
2476
+ owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)
2369
2477
  ? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
2370
2478
  : globalQueue.enqueue(EFFECT_USER, () => {
2371
2479
  const cleanup = callback();
@@ -2543,31 +2651,39 @@ function createProjectionInternal(fn, seed, options) {
2543
2651
  return wrapped;
2544
2652
  };
2545
2653
  const wrappedStore = wrapProjection(seed);
2546
- node = computed(() => {
2547
- const owner = getOwner();
2548
- let settled = false;
2549
- let result;
2550
- const draft = new Proxy(
2551
- wrappedStore,
2552
- createWriteTraps(() => !settled || owner._inFlight === result)
2553
- );
2554
- storeSetter(draft, s => {
2555
- result = fn(s);
2556
- settled = true;
2557
- const value = handleAsync(owner, result, value => {
2558
- value !== s &&
2559
- value !== undefined &&
2560
- storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
2561
- });
2562
- value !== s && value !== undefined && reconcile(value, options?.key || "id")(wrappedStore);
2563
- });
2564
- });
2565
- node._preventAutoDisposal = true;
2654
+ node = computed(
2655
+ () => {
2656
+ if (!node) node = getOwner();
2657
+ runProjectionComputed(wrappedStore, fn, options?.key || "id");
2658
+ },
2659
+ options?.name ? { name: options.name } : undefined
2660
+ );
2661
+ node._config &= ~CONFIG_AUTO_DISPOSE;
2566
2662
  return { store: wrappedStore, node: node };
2567
2663
  }
2568
2664
  function createProjection(fn, seed, options) {
2569
2665
  return createProjectionInternal(fn, seed, options).store;
2570
2666
  }
2667
+ function runProjectionComputed(wrappedStore, fn, key, wrapCommit) {
2668
+ const owner = getOwner();
2669
+ let settled = false;
2670
+ let result;
2671
+ const draft = new Proxy(
2672
+ wrappedStore,
2673
+ createWriteTraps(() => !settled || owner._inFlight === result)
2674
+ );
2675
+ storeSetter(draft, s => {
2676
+ result = fn(s);
2677
+ settled = true;
2678
+ const commit = v => {
2679
+ if (v === s || v === undefined) return;
2680
+ const write = () => storeSetter(wrappedStore, reconcile(v, key));
2681
+ wrapCommit ? wrapCommit(write) : write();
2682
+ };
2683
+ commit(handleAsync(owner, result, commit));
2684
+ });
2685
+ return owner;
2686
+ }
2571
2687
  function createWriteTraps(isActive) {
2572
2688
  const traps = {
2573
2689
  get(_, prop) {
@@ -2677,7 +2793,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
2677
2793
  {
2678
2794
  equals: equals,
2679
2795
  unobserved() {
2680
- delete nodes[property];
2796
+ if (nodes[property] === s) delete nodes[property];
2681
2797
  }
2682
2798
  },
2683
2799
  firewall
@@ -2751,19 +2867,51 @@ function prepareStoreWrite(target, store, property) {
2751
2867
  if (useOptimistic) trackOptimisticStore(store);
2752
2868
  return { base: base, overrideKey: overrideKey, state: state };
2753
2869
  }
2754
- function notifyStoreProperty(target, property, mode, value) {
2755
- if (target[STORE_HAS]?.[property]) setSignal(target[STORE_HAS][property], mode !== "delete");
2870
+ function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
2871
+ if (nodes[property]) return nodes[property];
2872
+ const initial = isWrappable(prev) ? wrap(prev, target) : prev;
2873
+ const node = getNode(
2874
+ nodes,
2875
+ property,
2876
+ initial,
2877
+ target[STORE_FIREWALL],
2878
+ isEqual,
2879
+ target[STORE_OPTIMISTIC],
2880
+ snapshotProps
2881
+ );
2882
+ registerTransientStoreNode(node);
2883
+ return node;
2884
+ }
2885
+ function notifyStoreProperty(target, property, mode, value, prev, prevHas) {
2886
+ const skipUpsert = projectionWriteActive || target[STORE_OPTIMISTIC];
2887
+ const newHas = mode !== "delete";
2888
+ const existingHas = target[STORE_HAS]?.[property];
2889
+ if (existingHas) {
2890
+ setSignal(existingHas, newHas);
2891
+ } else if (!skipUpsert && mode !== "invalidate" && prevHas !== newHas) {
2892
+ const hasNode = upsertStoreNode(target, getNodes(target, STORE_HAS), property, prevHas);
2893
+ setSignal(hasNode, newHas);
2894
+ }
2756
2895
  const nodes = getNodes(target, STORE_NODE);
2757
2896
  if (mode === "set") {
2758
- nodes[property] &&
2897
+ if (nodes[property]) {
2759
2898
  setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
2899
+ } else if (!skipUpsert) {
2900
+ const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
2901
+ setSignal(node, () => (isWrappable(value) ? wrap(value, target) : value));
2902
+ }
2760
2903
  } else if (mode === "invalidate") {
2761
2904
  if (nodes[property]) {
2762
2905
  setSignal(nodes[property], {});
2763
2906
  delete nodes[property];
2764
2907
  }
2765
2908
  } else {
2766
- nodes[property] && setSignal(nodes[property], undefined);
2909
+ if (nodes[property]) {
2910
+ setSignal(nodes[property], undefined);
2911
+ } else if (!skipUpsert) {
2912
+ const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
2913
+ setSignal(node, undefined);
2914
+ }
2767
2915
  }
2768
2916
  nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
2769
2917
  }
@@ -2838,7 +2986,7 @@ const storeTraps = {
2838
2986
  }
2839
2987
  if (strictRead && typeof property === "string") {
2840
2988
  const message =
2841
- `Reactive value read directly in ${strictRead} will not update. ` +
2989
+ `[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
2842
2990
  `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
2843
2991
  emitDiagnostic({
2844
2992
  code: "STRICT_READ_UNTRACKED",
@@ -2860,18 +3008,13 @@ const storeTraps = {
2860
3008
  : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
2861
3009
  ? target[STORE_OVERRIDE][property] !== $DELETED
2862
3010
  : property in target[STORE_VALUE];
2863
- if (!writeOnly(target[$PROXY])) {
2864
- getObserver() &&
2865
- read(
2866
- getNode(
2867
- getNodes(target, STORE_HAS),
2868
- property,
2869
- has,
2870
- target[STORE_FIREWALL],
2871
- isEqual,
2872
- target[STORE_OPTIMISTIC]
2873
- )
2874
- );
3011
+ if (writeOnly(target[$PROXY])) return has;
3012
+ const nodes = getNodes(target, STORE_HAS);
3013
+ if (nodes[property]) return read(nodes[property]);
3014
+ if (getObserver()) {
3015
+ return read(
3016
+ getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
3017
+ );
2875
3018
  }
2876
3019
  return has;
2877
3020
  },
@@ -2890,6 +3033,12 @@ const storeTraps = {
2890
3033
  : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
2891
3034
  ? target[STORE_OVERRIDE][property]
2892
3035
  : base;
3036
+ const prevHas =
3037
+ target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
3038
+ ? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
3039
+ : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
3040
+ ? target[STORE_OVERRIDE][property] !== $DELETED
3041
+ : property in target[STORE_VALUE];
2893
3042
  const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
2894
3043
  const isArrayIndexWrite = Array.isArray(state) && property !== "length";
2895
3044
  const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
@@ -2909,11 +3058,21 @@ const storeTraps = {
2909
3058
  override[property] = value;
2910
3059
  if (nextLength !== undefined) override.length = nextLength;
2911
3060
  }
2912
- notifyStoreProperty(target, property, "set", value);
2913
- if (Array.isArray(state)) {
3061
+ notifyStoreProperty(target, property, "set", value, prev, prevHas);
3062
+ if (Array.isArray(state) && property !== "length" && nextLength !== undefined) {
2914
3063
  const nodes = getNodes(target, STORE_NODE);
2915
- const lengthValue = property === "length" ? value : nextLength;
2916
- lengthValue !== undefined && nodes.length && setSignal(nodes.length, lengthValue);
3064
+ if (nodes.length) {
3065
+ setSignal(nodes.length, nextLength);
3066
+ } else if (!projectionWriteActive && !target[STORE_OPTIMISTIC]) {
3067
+ const node = upsertStoreNode(
3068
+ target,
3069
+ nodes,
3070
+ "length",
3071
+ len,
3072
+ target[STORE_SNAPSHOT_PROPS]
3073
+ );
3074
+ setSignal(node, nextLength);
3075
+ }
2917
3076
  }
2918
3077
  if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
2919
3078
  });
@@ -2971,7 +3130,7 @@ const storeTraps = {
2971
3130
  } else if (target[overrideKey] && property in target[overrideKey]) {
2972
3131
  delete target[overrideKey][property];
2973
3132
  } else return true;
2974
- notifyStoreProperty(target, property, "delete");
3133
+ notifyStoreProperty(target, property, "delete", undefined, prev, true);
2975
3134
  });
2976
3135
  }
2977
3136
  return true;
@@ -3101,38 +3260,26 @@ function createOptimisticProjectionInternal(fn, initialValue, options) {
3101
3260
  };
3102
3261
  const wrappedStore = wrapProjection(initialValue);
3103
3262
  if (fn) {
3104
- node = computed(() => {
3105
- const owner = getOwner();
3106
- let settled = false;
3107
- let result;
3108
- const draft = new Proxy(
3109
- wrappedStore,
3110
- createWriteTraps(() => !settled || owner._inFlight === result)
3111
- );
3263
+ const wrapCommit = write => {
3112
3264
  setProjectionWriteActive(true);
3113
3265
  try {
3114
- storeSetter(draft, s => {
3115
- result = fn(s);
3116
- settled = true;
3117
- const value = handleAsync(owner, result, value => {
3118
- setProjectionWriteActive(true);
3119
- try {
3120
- value !== s &&
3121
- value !== undefined &&
3122
- storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
3123
- } finally {
3124
- setProjectionWriteActive(false);
3125
- }
3126
- });
3127
- value !== s &&
3128
- value !== undefined &&
3129
- reconcile(value, options?.key || "id")(wrappedStore);
3130
- });
3266
+ write();
3131
3267
  } finally {
3132
3268
  setProjectionWriteActive(false);
3133
3269
  }
3134
- });
3135
- node._preventAutoDisposal = true;
3270
+ };
3271
+ node = computed(
3272
+ () => {
3273
+ setProjectionWriteActive(true);
3274
+ try {
3275
+ runProjectionComputed(wrappedStore, fn, options?.key || "id", wrapCommit);
3276
+ } finally {
3277
+ setProjectionWriteActive(false);
3278
+ }
3279
+ },
3280
+ options?.name ? { name: options.name } : undefined
3281
+ );
3282
+ node._config &= ~CONFIG_AUTO_DISPOSE;
3136
3283
  }
3137
3284
  return { store: wrappedStore, node: node };
3138
3285
  }
@@ -3409,22 +3556,22 @@ function mapArray(list, map, options) {
3409
3556
  }
3410
3557
  }
3411
3558
  : map;
3412
- const node = computed(
3413
- updateKeyedMap.bind({
3414
- _owner: createOwner(),
3415
- _len: 0,
3416
- _list: list,
3417
- _items: [],
3418
- _map: wrappedMap,
3419
- _mappings: [],
3420
- _nodes: [],
3421
- _key: keyFn,
3422
- _rows: keyFn || options?.keyed === false ? [] : undefined,
3423
- _indexes: indexes ? [] : undefined,
3424
- _fallback: options?.fallback
3425
- })
3426
- );
3427
- node._preventAutoDisposal = true;
3559
+ const data = {
3560
+ _owner: createOwner(),
3561
+ _len: 0,
3562
+ _list: list,
3563
+ _items: [],
3564
+ _map: wrappedMap,
3565
+ _mappings: [],
3566
+ _nodes: [],
3567
+ _key: keyFn,
3568
+ _rows: keyFn || options?.keyed === false ? [] : undefined,
3569
+ _indexes: indexes ? [] : undefined,
3570
+ _fallback: options?.fallback
3571
+ };
3572
+ const node = computed(updateKeyedMap.bind(data));
3573
+ data._owner._parentComputed = node;
3574
+ node._config &= ~CONFIG_AUTO_DISPOSE;
3428
3575
  return accessor(node);
3429
3576
  }
3430
3577
  const pureOptions = { ownedWrite: true };
@@ -3577,7 +3724,7 @@ function repeat(count, map, options) {
3577
3724
  _fallback: options?.fallback
3578
3725
  })
3579
3726
  );
3580
- node._preventAutoDisposal = true;
3727
+ node._config &= ~CONFIG_AUTO_DISPOSE;
3581
3728
  return accessor(node);
3582
3729
  }
3583
3730
  function updateRepeat() {
@@ -3635,7 +3782,7 @@ function compare(key, a, b) {
3635
3782
  return key ? key(a) === key(b) : true;
3636
3783
  }
3637
3784
  function boundaryComputed(fn, propagationMask) {
3638
- const node = computed(fn, undefined, { lazy: true });
3785
+ const node = computed(fn, { lazy: true });
3639
3786
  node._notifyStatus = (status, error) => {
3640
3787
  const flags = status !== undefined ? status : node._statusFlags;
3641
3788
  const actualError = error !== undefined ? error : node._error;
@@ -3643,7 +3790,7 @@ function boundaryComputed(fn, propagationMask) {
3643
3790
  node._queue.notify(node, node._propagationMask, flags, actualError);
3644
3791
  };
3645
3792
  node._propagationMask = propagationMask;
3646
- node._preventAutoDisposal = true;
3793
+ node._config &= ~CONFIG_AUTO_DISPOSE;
3647
3794
  recompute(node, true);
3648
3795
  return node;
3649
3796
  }
@@ -3660,12 +3807,16 @@ const ON_INIT = Symbol();
3660
3807
  const RevealControllerContext = createContext(null);
3661
3808
  let _revealUsed = false;
3662
3809
  const FALSE_ACCESSOR = () => false;
3810
+ const SEQUENTIAL_ACCESSOR = () => "sequential";
3663
3811
  function isRevealController(slot) {
3664
3812
  return slot instanceof RevealController;
3665
3813
  }
3666
3814
  function isSlotReady(slot) {
3667
3815
  return isRevealController(slot) ? slot.isReady() : slot._sources.size === 0 && !slot._pending;
3668
3816
  }
3817
+ function isSlotMinimallyReady(slot) {
3818
+ return isRevealController(slot) ? slot.isMinimallyReady() : isSlotReady(slot);
3819
+ }
3669
3820
  function setSlotState(slot, controller, disabled, collapsed) {
3670
3821
  setSignal(slot._disabled, disabled);
3671
3822
  setSignal(slot._collapsed, collapsed);
@@ -3677,16 +3828,17 @@ function setSlotState(slot, controller, disabled, collapsed) {
3677
3828
  slot._revealController = undefined;
3678
3829
  }
3679
3830
  class RevealController {
3680
- _togetherAccessor;
3831
+ _orderAccessor;
3681
3832
  _collapsedAccessor;
3682
3833
  _slots = [];
3683
3834
  _parentController;
3684
3835
  _disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
3685
3836
  _collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
3686
3837
  _ready = true;
3838
+ _minimallyReady = true;
3687
3839
  _evaluating = false;
3688
- constructor(together, collapsed) {
3689
- this._togetherAccessor = together;
3840
+ constructor(order, collapsed) {
3841
+ this._orderAccessor = order;
3690
3842
  this._collapsedAccessor = collapsed;
3691
3843
  }
3692
3844
  _forEachOwnedSlot(fn) {
@@ -3701,12 +3853,37 @@ class RevealController {
3701
3853
  isReady() {
3702
3854
  return this._forEachOwnedSlot(isSlotReady);
3703
3855
  }
3856
+ isMinimallyReady() {
3857
+ const order = untrack(this._orderAccessor);
3858
+ if (order === "together") return this.isReady();
3859
+ if (order === "natural") {
3860
+ let hasSlot = false;
3861
+ let anyReady = false;
3862
+ this._forEachOwnedSlot(slot => {
3863
+ hasSlot = true;
3864
+ if (isSlotMinimallyReady(slot)) {
3865
+ anyReady = true;
3866
+ return false;
3867
+ }
3868
+ });
3869
+ return !hasSlot || anyReady;
3870
+ }
3871
+ let firstReady = true;
3872
+ this._forEachOwnedSlot(slot => {
3873
+ firstReady = isSlotMinimallyReady(slot);
3874
+ return false;
3875
+ });
3876
+ return firstReady;
3877
+ }
3704
3878
  register(slot) {
3705
3879
  if (this._slots.includes(slot)) return;
3706
3880
  this._slots.push(slot);
3707
- const together = !!untrack(this._togetherAccessor);
3881
+ const order = untrack(this._orderAccessor);
3708
3882
  (setSignal(slot._disabled, true),
3709
- setSignal(slot._collapsed, together ? false : !!untrack(this._collapsedAccessor)));
3883
+ setSignal(
3884
+ slot._collapsed,
3885
+ order === "sequential" ? !!untrack(this._collapsedAccessor) : false
3886
+ ));
3710
3887
  untrack(() => this.evaluate());
3711
3888
  }
3712
3889
  unregister(slot) {
@@ -3718,29 +3895,52 @@ class RevealController {
3718
3895
  if (this._evaluating) return;
3719
3896
  this._evaluating = true;
3720
3897
  const wasReady = this._ready;
3898
+ const wasMinReady = this._minimallyReady;
3721
3899
  try {
3722
3900
  const disabled = disabledOverride ?? read(this._disabled),
3723
- collapseTail = !!untrack(this._collapsedAccessor),
3901
+ order = untrack(this._orderAccessor),
3902
+ collapseTail = order === "sequential" && !!untrack(this._collapsedAccessor),
3724
3903
  collapsed = collapsedOverride ?? collapseTail;
3725
- if (disabled && collapsed)
3726
- this._forEachOwnedSlot(slot => setSlotState(slot, this, true, true));
3727
- else if (!!untrack(this._togetherAccessor)) {
3728
- const ready = this.isReady();
3729
- this._forEachOwnedSlot(slot => setSlotState(slot, this, !ready, false));
3904
+ if (disabled) {
3905
+ this._forEachOwnedSlot(slot => setSlotState(slot, this, true, collapsed));
3906
+ } else if (order === "natural") {
3907
+ this._forEachOwnedSlot(slot => {
3908
+ if (isRevealController(slot)) {
3909
+ setSignal(slot._collapsed, false);
3910
+ setSignal(slot._disabled, false);
3911
+ slot.evaluate(false, false);
3912
+ } else {
3913
+ setSlotState(slot, this, !isSlotReady(slot), false);
3914
+ }
3915
+ });
3916
+ } else if (order === "together") {
3917
+ const minReady = this._forEachOwnedSlot(isSlotMinimallyReady);
3918
+ this._forEachOwnedSlot(slot => setSlotState(slot, this, !minReady, false));
3730
3919
  } else {
3731
3920
  let pendingSeen = false;
3732
3921
  this._forEachOwnedSlot(slot => {
3733
3922
  if (pendingSeen) return setSlotState(slot, this, true, collapseTail);
3734
3923
  if (isSlotReady(slot)) return setSlotState(slot, this, false, false);
3735
3924
  pendingSeen = true;
3736
- setSlotState(slot, this, true, false);
3925
+ if (isRevealController(slot)) {
3926
+ setSignal(slot._collapsed, false);
3927
+ setSignal(slot._disabled, false);
3928
+ slot.evaluate(false, false);
3929
+ } else {
3930
+ setSlotState(slot, this, true, false);
3931
+ }
3737
3932
  });
3738
3933
  }
3739
3934
  } finally {
3740
3935
  this._ready = this.isReady();
3936
+ this._minimallyReady = this.isMinimallyReady();
3741
3937
  this._evaluating = false;
3742
3938
  }
3743
- if (this._parentController && wasReady !== this._ready) this._parentController.evaluate();
3939
+ if (
3940
+ this._parentController &&
3941
+ (wasReady !== this._ready || wasMinReady !== this._minimallyReady)
3942
+ )
3943
+ this._parentController.evaluate();
3744
3944
  }
3745
3945
  }
3746
3946
  class CollectionQueue extends Queue {
@@ -3829,7 +4029,8 @@ class CollectionQueue extends Queue {
3829
4029
  }
3830
4030
  function createCollectionBoundary(type, fn, fallback, onFn) {
3831
4031
  if (!getOwner()) {
3832
- const message = "Boundaries created outside a reactive context will never be disposed.";
4032
+ const message =
4033
+ "[NO_OWNER_BOUNDARY] Boundaries created outside a reactive context will never be disposed.";
3833
4034
  emitDiagnostic({
3834
4035
  code: "NO_OWNER_BOUNDARY",
3835
4036
  kind: "lifecycle",
@@ -3862,15 +4063,16 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
3862
4063
  controller.register(queue);
3863
4064
  cleanup(() => controller.unregister(queue));
3864
4065
  }
3865
- const decision = computed(() => {
3866
- if (!read(queue._disabled)) {
3867
- const resolved = read(tree);
3868
- if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
3869
- }
3870
- if (_revealUsed && read(queue._collapsed)) return undefined;
3871
- return fallback(queue);
3872
- });
3873
- return accessor(decision);
4066
+ return accessor(
4067
+ computed(() => {
4068
+ if (!read(queue._disabled)) {
4069
+ const resolved = read(tree);
4070
+ if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
4071
+ }
4072
+ if (_revealUsed && read(queue._collapsed)) return undefined;
4073
+ return fallback(queue);
4074
+ })
4075
+ );
3874
4076
  }
3875
4077
  function createLoadingBoundary(fn, fallback, options) {
3876
4078
  return createCollectionBoundary(STATUS_PENDING, fn, () => fallback(), options?.on);
@@ -3889,14 +4091,14 @@ function createRevealOrder(fn, options) {
3889
4091
  _revealUsed = true;
3890
4092
  const owner = createOwner();
3891
4093
  const parentController = getContext(RevealControllerContext);
3892
- const together = options?.together || FALSE_ACCESSOR,
4094
+ const order = options?.order || SEQUENTIAL_ACCESSOR,
3893
4095
  collapsed = options?.collapsed || FALSE_ACCESSOR;
3894
- const controller = new RevealController(together, collapsed);
4096
+ const controller = new RevealController(order, collapsed);
3895
4097
  setContext(RevealControllerContext, controller, owner);
3896
4098
  return runWithOwner(owner, () => {
3897
4099
  const value = fn();
3898
4100
  computed(() => {
3899
- together();
4101
+ order();
3900
4102
  collapsed();
3901
4103
  controller.evaluate();
3902
4104
  });