@solidjs/signals 0.13.13 → 2.0.0-beta.8

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 (44) hide show
  1. package/README.md +8 -7
  2. package/dist/dev.js +312 -174
  3. package/dist/node.cjs +1068 -953
  4. package/dist/prod.js +744 -619
  5. package/dist/types/boundaries.d.ts +44 -3
  6. package/dist/types/core/core.d.ts +2 -2
  7. package/dist/types/core/effect.d.ts +3 -2
  8. package/dist/types/core/graph.d.ts +1 -0
  9. package/dist/types/core/scheduler.d.ts +1 -0
  10. package/dist/types/core/types.d.ts +2 -2
  11. package/dist/types/index.d.ts +1 -1
  12. package/dist/types/signals.d.ts +34 -26
  13. package/dist/types/store/optimistic.d.ts +3 -3
  14. package/dist/types/store/projection.d.ts +19 -5
  15. package/dist/types/store/store.d.ts +4 -4
  16. package/dist/types-cjs/boundaries.d.cts +93 -0
  17. package/dist/types-cjs/core/action.d.cts +1 -0
  18. package/dist/types-cjs/core/async.d.cts +6 -0
  19. package/dist/types-cjs/core/constants.d.cts +25 -0
  20. package/dist/types-cjs/core/context.d.cts +28 -0
  21. package/dist/types-cjs/core/core.d.cts +54 -0
  22. package/dist/types-cjs/core/dev.d.cts +49 -0
  23. package/dist/types-cjs/core/effect.d.cts +31 -0
  24. package/dist/types-cjs/core/error.d.cts +14 -0
  25. package/dist/types-cjs/core/external.d.cts +26 -0
  26. package/dist/types-cjs/core/graph.d.cts +4 -0
  27. package/dist/types-cjs/core/heap.d.cts +14 -0
  28. package/dist/types-cjs/core/index.d.cts +12 -0
  29. package/dist/types-cjs/core/lanes.d.cts +54 -0
  30. package/dist/types-cjs/core/owner.d.cts +26 -0
  31. package/dist/types-cjs/core/scheduler.d.cts +82 -0
  32. package/dist/types-cjs/core/types.d.cts +86 -0
  33. package/dist/types-cjs/index.d.cts +9 -0
  34. package/dist/types-cjs/map.d.cts +24 -0
  35. package/dist/types-cjs/package.json +3 -0
  36. package/dist/types-cjs/signals.d.cts +200 -0
  37. package/dist/types-cjs/store/index.d.cts +9 -0
  38. package/dist/types-cjs/store/optimistic.d.cts +19 -0
  39. package/dist/types-cjs/store/projection.d.cts +40 -0
  40. package/dist/types-cjs/store/reconcile.d.cts +1 -0
  41. package/dist/types-cjs/store/store.d.cts +68 -0
  42. package/dist/types-cjs/store/storePath.d.cts +30 -0
  43. package/dist/types-cjs/store/utils.d.cts +43 -0
  44. package/package.json +31 -24
package/dist/dev.js CHANGED
@@ -240,6 +240,23 @@ let inTrackedQueueCallback = false;
240
240
  let _enforceLoadingBoundary = false;
241
241
  let _hitUnhandledAsync = false;
242
242
  let stashedOptimisticReads = null;
243
+ const transientStoreNodes = new Set();
244
+ function registerTransientStoreNode(node) {
245
+ transientStoreNodes.add(node);
246
+ }
247
+ function sweepTransientStoreNodes() {
248
+ if (transientStoreNodes.size === 0) return;
249
+ for (const node of transientStoreNodes) {
250
+ if (node._subs !== null) {
251
+ transientStoreNodes.delete(node);
252
+ continue;
253
+ }
254
+ if (node._pendingValue !== NOT_PENDING) continue;
255
+ if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
256
+ transientStoreNodes.delete(node);
257
+ node._unobserved?.();
258
+ }
259
+ }
243
260
  function resetUnhandledAsync() {
244
261
  _hitUnhandledAsync = false;
245
262
  }
@@ -426,7 +443,7 @@ class GlobalQueue extends Queue {
426
443
  stashedOptimisticReads = new Set();
427
444
  for (let i = 0; i < stashedTransition._optimisticNodes.length; i++) {
428
445
  const node = stashedTransition._optimisticNodes[i];
429
- if (node._fn || node._pureWrite) continue;
446
+ if (node._fn || node._ownedWrite) continue;
430
447
  stashedOptimisticReads.add(node);
431
448
  queueStashedOptimisticEffects(node);
432
449
  }
@@ -589,6 +606,7 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
589
606
  optimisticStores.clear();
590
607
  schedule();
591
608
  }
609
+ sweepTransientStoreNodes();
592
610
  cleanupCompletedLanes(completingTransition);
593
611
  }
594
612
  }
@@ -790,6 +808,7 @@ function unobserved(el) {
790
808
  dep = unlinkSubs(dep);
791
809
  }
792
810
  el._deps = null;
811
+ el._depsTail = null;
793
812
  disposeChildren(el, true);
794
813
  }
795
814
  function link(dep, sub) {
@@ -1382,7 +1401,9 @@ function recompute(el, create = false) {
1382
1401
  if (lane) currentOptimisticLane = lane;
1383
1402
  }
1384
1403
  try {
1385
- value = handleAsync(el, el._fn(value));
1404
+ const prevInFlight = el._inFlight;
1405
+ const fnResult = el._fn(value);
1406
+ value = el._inFlight !== prevInFlight ? fnResult : handleAsync(el, fnResult);
1386
1407
  clearStatus(el, create);
1387
1408
  const resolvedLane = resolveLane(el);
1388
1409
  if (resolvedLane) {
@@ -1481,7 +1502,7 @@ function updateIfNecessary(el) {
1481
1502
  }
1482
1503
  el._flags = el._flags & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
1483
1504
  }
1484
- function computed(fn, initialValue, options) {
1505
+ function computed(fn, options) {
1485
1506
  const transparent = options?.transparent ?? false;
1486
1507
  const self = {
1487
1508
  id:
@@ -1489,14 +1510,14 @@ function computed(fn, initialValue, options) {
1489
1510
  (transparent ? context?.id : context?.id != null ? getNextChildId(context) : undefined),
1490
1511
  _transparent: transparent || undefined,
1491
1512
  _equals: options?.equals != null ? options.equals : isEqual,
1492
- _pureWrite: !!options?.pureWrite,
1513
+ _ownedWrite: !!options?.ownedWrite,
1493
1514
  _unobserved: options?.unobserved,
1494
1515
  _disposal: null,
1495
1516
  _queue: context?._queue ?? globalQueue,
1496
1517
  _context: context?._context ?? defaultContext,
1497
1518
  _childCount: 0,
1498
1519
  _fn: fn,
1499
- _value: initialValue,
1520
+ _value: undefined,
1500
1521
  _height: 0,
1501
1522
  _child: null,
1502
1523
  _nextHeap: undefined,
@@ -1538,7 +1559,7 @@ function computed(fn, initialValue, options) {
1538
1559
  if (parent) self._height = parent._height + 1;
1539
1560
  if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
1540
1561
  if (externalSourceConfig) {
1541
- const bridgeSignal = signal(undefined, { equals: false, pureWrite: true });
1562
+ const bridgeSignal = signal(undefined, { equals: false, ownedWrite: true });
1542
1563
  const source = externalSourceConfig.factory(self._fn, () => {
1543
1564
  setSignal(bridgeSignal, undefined);
1544
1565
  });
@@ -1560,7 +1581,7 @@ function computed(fn, initialValue, options) {
1560
1581
  function signal(v, options, firewall = null) {
1561
1582
  const s = {
1562
1583
  _equals: options?.equals != null ? options.equals : isEqual,
1563
- _pureWrite: !!options?.pureWrite,
1584
+ _ownedWrite: !!options?.ownedWrite,
1564
1585
  _noSnapshot: !!options?._noSnapshot,
1565
1586
  _unobserved: options?.unobserved,
1566
1587
  _value: v,
@@ -1591,8 +1612,8 @@ function optimisticSignal(v, options) {
1591
1612
  s._overrideValue = NOT_PENDING;
1592
1613
  return s;
1593
1614
  }
1594
- function optimisticComputed(fn, initialValue, options) {
1595
- const c = computed(fn, initialValue, options);
1615
+ function optimisticComputed(fn, options) {
1616
+ const c = computed(fn, options);
1596
1617
  c._overrideValue = NOT_PENDING;
1597
1618
  return c;
1598
1619
  }
@@ -1672,10 +1693,16 @@ function read(el) {
1672
1693
  }
1673
1694
  let c = context;
1674
1695
  if (c?._root) c = c._parentComputed;
1675
- if (refreshing && el._fn) recompute(el);
1676
- if (el._flags & REACTIVE_LAZY) {
1677
- el._flags &= ~REACTIVE_LAZY;
1678
- recompute(el, true);
1696
+ const computed = el;
1697
+ if (typeof computed._fn === "function") {
1698
+ const comp = el;
1699
+ if (refreshing && !(comp._flags & REACTIVE_DISPOSED)) recompute(comp);
1700
+ if (comp._flags & REACTIVE_LAZY) {
1701
+ comp._flags &= ~REACTIVE_LAZY;
1702
+ recompute(comp, true);
1703
+ } else if (comp._flags & REACTIVE_DISPOSED) {
1704
+ recompute(comp, true);
1705
+ }
1679
1706
  }
1680
1707
  const owner = el._firewall || el;
1681
1708
  if (strictRead && owner._statusFlags & STATUS_PENDING) {
@@ -1695,7 +1722,6 @@ function read(el) {
1695
1722
  throw new Error(message);
1696
1723
  }
1697
1724
  if (c && tracking) {
1698
- if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
1699
1725
  link(el, c);
1700
1726
  if (owner._fn) {
1701
1727
  const isZombie = el._flags & REACTIVE_ZOMBIE;
@@ -1780,7 +1806,8 @@ function read(el) {
1780
1806
  if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
1781
1807
  return el._overrideValue;
1782
1808
  }
1783
- return !c ||
1809
+ const value =
1810
+ !c ||
1784
1811
  (currentOptimisticLane !== null &&
1785
1812
  (el._overrideValue !== undefined ||
1786
1813
  el._optimisticLane ||
@@ -1788,14 +1815,26 @@ function read(el) {
1788
1815
  !!(owner._statusFlags & STATUS_PENDING))) ||
1789
1816
  el._pendingValue === NOT_PENDING ||
1790
1817
  (stale && el._transition && activeTransition !== el._transition)
1791
- ? el._value
1792
- : el._pendingValue;
1818
+ ? el._value
1819
+ : el._pendingValue;
1820
+ if (
1821
+ !c &&
1822
+ owner === el &&
1823
+ typeof computed._fn === "function" &&
1824
+ !computed._preventAutoDisposal &&
1825
+ !(owner._statusFlags & STATUS_PENDING) &&
1826
+ !computed._parent &&
1827
+ !el._subs
1828
+ ) {
1829
+ unobserved(el);
1830
+ }
1831
+ return value;
1793
1832
  }
1794
1833
  function setSignal(el, v) {
1795
- if (!el._pureWrite && !context?._childrenForbidden && context && el._firewall !== context) {
1834
+ if (!el._ownedWrite && !context?._childrenForbidden && context && el._firewall !== context) {
1796
1835
  const message =
1797
1836
  "Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
1798
- "Move the write outside or set the `pureWrite` option if this is intentional.";
1837
+ "Move the write outside or set the `ownedWrite` option if this is intentional.";
1799
1838
  emitDiagnostic({
1800
1839
  code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
1801
1840
  kind: "write",
@@ -1879,7 +1918,7 @@ function runWithOwner(owner, fn) {
1879
1918
  }
1880
1919
  function getPendingSignal(el) {
1881
1920
  if (!el._pendingSignal) {
1882
- el._pendingSignal = optimisticSignal(false, { pureWrite: true });
1921
+ el._pendingSignal = optimisticSignal(false, { ownedWrite: true });
1883
1922
  if (el._parentSource) {
1884
1923
  el._pendingSignal._parentSource = el;
1885
1924
  }
@@ -2022,26 +2061,23 @@ function hasContext(context, owner) {
2022
2061
  function isUndefined(value) {
2023
2062
  return typeof value === "undefined";
2024
2063
  }
2025
- function effect(compute, effect, error, initialValue, options) {
2064
+ function effect(compute, effect, error, options) {
2026
2065
  let initialized = false;
2027
- const node = computed(
2028
- options?.render ? p => staleValues(() => compute(p)) : compute,
2029
- initialValue,
2030
- {
2031
- ...options,
2032
- equals: () => {
2033
- node._modified = !node._error;
2034
- if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
2035
- return false;
2036
- },
2037
- lazy: true
2038
- }
2039
- );
2040
- node._prevValue = initialValue;
2066
+ const isUser = !!options?.user;
2067
+ const node = computed(isUser ? compute : p => staleValues(() => compute(p)), {
2068
+ ...options,
2069
+ equals: () => {
2070
+ node._modified = !node._error;
2071
+ if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
2072
+ return false;
2073
+ },
2074
+ lazy: true
2075
+ });
2076
+ node._prevValue = undefined;
2041
2077
  node._effectFn = effect;
2042
2078
  node._errorFn = error;
2043
2079
  node._cleanup = undefined;
2044
- node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
2080
+ node._type = isUser ? EFFECT_USER : EFFECT_RENDER;
2045
2081
  node._notifyStatus = (status, error) => {
2046
2082
  const actualStatus = status !== undefined ? status : node._statusFlags;
2047
2083
  const actualError = error !== undefined ? error : node._error;
@@ -2065,22 +2101,25 @@ function effect(compute, effect, error, initialValue, options) {
2065
2101
  node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
2066
2102
  if (_hitUnhandledAsync) {
2067
2103
  resetUnhandledAsync();
2068
- const err = new Error("An async value must be rendered inside a Loading boundary.");
2069
- emitDiagnostic({
2070
- code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
2071
- kind: "async",
2072
- severity: "error",
2073
- message: err.message,
2074
- ownerId: node.id,
2075
- ownerName: node._name
2076
- });
2077
- if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
2104
+ if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
2105
+ const message =
2106
+ "An async value was read outside a Loading boundary. The root mount will be deferred until all pending async settles.";
2107
+ emitDiagnostic({
2108
+ code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
2109
+ kind: "async",
2110
+ severity: "warn",
2111
+ message: message,
2112
+ ownerId: node.id,
2113
+ ownerName: node._name
2114
+ });
2115
+ console.warn(message);
2116
+ }
2078
2117
  }
2079
2118
  }
2080
2119
  };
2081
2120
  recompute(node, true);
2082
2121
  !options?.defer &&
2083
- (node._type === EFFECT_USER
2122
+ (node._type === EFFECT_USER || options?.schedule
2084
2123
  ? node._queue.enqueue(node._type, runEffect.bind(node))
2085
2124
  : runEffect.call(node));
2086
2125
  initialized = true;
@@ -2148,7 +2187,6 @@ function trackedEffect(fn, options) {
2148
2187
  }
2149
2188
  node._cleanup = cleanup;
2150
2189
  },
2151
- undefined,
2152
2190
  { ...options, lazy: true }
2153
2191
  );
2154
2192
  node._cleanup = undefined;
@@ -2257,31 +2295,29 @@ function accessor(node) {
2257
2295
  fn.$r = true;
2258
2296
  return fn;
2259
2297
  }
2260
- function createSignal(first, second, third) {
2298
+ function createSignal(first, second) {
2261
2299
  if (typeof first === "function") {
2262
- const node = computed(first, second, third);
2300
+ const node = computed(first, second);
2301
+ node._preventAutoDisposal = true;
2263
2302
  return [accessor(node), setSignal.bind(null, node)];
2264
2303
  }
2265
2304
  const node = signal(first, second);
2266
2305
  registerGraph(node, getOwner());
2267
2306
  return [accessor(node), setSignal.bind(null, node)];
2268
2307
  }
2269
- function createMemo(compute, value, options) {
2270
- let node = computed(compute, value, options);
2308
+ function createMemo(compute, options) {
2309
+ let node = computed(compute, options);
2271
2310
  return accessor(node);
2272
2311
  }
2273
- function createEffect(compute, effectFn, value, options) {
2274
- effect(compute, effectFn.effect || effectFn, effectFn.error, value, {
2275
- ...options,
2276
- name: options?.name ?? "effect"
2277
- });
2278
- }
2279
- function createRenderEffect(compute, effectFn, value, options) {
2280
- effect(compute, effectFn, undefined, value, {
2281
- render: true,
2312
+ function createEffect(compute, effectFn, options) {
2313
+ effect(compute, effectFn.effect || effectFn, effectFn.error, {
2314
+ user: true,
2282
2315
  ...{ ...options, name: options?.name ?? "effect" }
2283
2316
  });
2284
2317
  }
2318
+ function createRenderEffect(compute, effectFn, options) {
2319
+ effect(compute, effectFn, undefined, { ...options, name: options?.name ?? "effect" });
2320
+ }
2285
2321
  function createTrackedEffect(compute, options) {
2286
2322
  trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
2287
2323
  }
@@ -2305,8 +2341,11 @@ function createReaction(effectFn, options) {
2305
2341
  dispose(node);
2306
2342
  },
2307
2343
  effectFn.error,
2308
- undefined,
2309
- { defer: true, ...(true ? { ...options, name: options?.name ?? "effect" } : options) }
2344
+ {
2345
+ ...(true ? { ...options, name: options?.name ?? "effect" } : options),
2346
+ user: true,
2347
+ defer: true
2348
+ }
2310
2349
  );
2311
2350
  });
2312
2351
  };
@@ -2331,9 +2370,10 @@ function resolve(fn) {
2331
2370
  });
2332
2371
  });
2333
2372
  }
2334
- function createOptimistic(first, second, third) {
2373
+ function createOptimistic(first, second) {
2335
2374
  if (typeof first === "function") {
2336
- const node = optimisticComputed(first, second, third);
2375
+ const node = optimisticComputed(first, second);
2376
+ node._preventAutoDisposal = true;
2337
2377
  return [accessor(node), setSignal.bind(null, node)];
2338
2378
  }
2339
2379
  const node = optimisticSignal(first, second);
@@ -2499,7 +2539,7 @@ function reconcile(value, key) {
2499
2539
  applyState(value, state, keyFn);
2500
2540
  };
2501
2541
  }
2502
- function createProjectionInternal(fn, initialValue = {}, options) {
2542
+ function createProjectionInternal(fn, seed, options) {
2503
2543
  let node;
2504
2544
  const wrappedMap = new WeakMap();
2505
2545
  const wrapper = s => {
@@ -2519,31 +2559,39 @@ function createProjectionInternal(fn, initialValue = {}, options) {
2519
2559
  wrappedMap.set(source, wrapped);
2520
2560
  return wrapped;
2521
2561
  };
2522
- const wrappedStore = wrapProjection(initialValue);
2523
- node = computed(() => {
2524
- const owner = getOwner();
2525
- let settled = false;
2526
- let result;
2527
- const draft = new Proxy(
2528
- wrappedStore,
2529
- createWriteTraps(() => !settled || owner._inFlight === result)
2530
- );
2531
- storeSetter(draft, s => {
2532
- result = fn(s);
2533
- settled = true;
2534
- const value = handleAsync(owner, result, value => {
2535
- value !== s &&
2536
- value !== undefined &&
2537
- storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
2538
- });
2539
- value !== s && value !== undefined && reconcile(value, options?.key || "id")(wrappedStore);
2540
- });
2541
- });
2562
+ const wrappedStore = wrapProjection(seed);
2563
+ node = computed(
2564
+ () => {
2565
+ if (!node) node = getOwner();
2566
+ runProjectionComputed(wrappedStore, fn, options?.key || "id");
2567
+ },
2568
+ options?.name ? { name: options.name } : undefined
2569
+ );
2542
2570
  node._preventAutoDisposal = true;
2543
2571
  return { store: wrappedStore, node: node };
2544
2572
  }
2545
- function createProjection(fn, initialValue = {}, options) {
2546
- return createProjectionInternal(fn, initialValue, options).store;
2573
+ function createProjection(fn, seed, options) {
2574
+ return createProjectionInternal(fn, seed, options).store;
2575
+ }
2576
+ function runProjectionComputed(wrappedStore, fn, key, wrapCommit) {
2577
+ const owner = getOwner();
2578
+ let settled = false;
2579
+ let result;
2580
+ const draft = new Proxy(
2581
+ wrappedStore,
2582
+ createWriteTraps(() => !settled || owner._inFlight === result)
2583
+ );
2584
+ storeSetter(draft, s => {
2585
+ result = fn(s);
2586
+ settled = true;
2587
+ const commit = v => {
2588
+ if (v === s || v === undefined) return;
2589
+ const write = () => storeSetter(wrappedStore, reconcile(v, key));
2590
+ wrapCommit ? wrapCommit(write) : write();
2591
+ };
2592
+ commit(handleAsync(owner, result, commit));
2593
+ });
2594
+ return owner;
2547
2595
  }
2548
2596
  function createWriteTraps(isActive) {
2549
2597
  const traps = {
@@ -2654,7 +2702,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
2654
2702
  {
2655
2703
  equals: equals,
2656
2704
  unobserved() {
2657
- delete nodes[property];
2705
+ if (nodes[property] === s) delete nodes[property];
2658
2706
  }
2659
2707
  },
2660
2708
  firewall
@@ -2728,19 +2776,51 @@ function prepareStoreWrite(target, store, property) {
2728
2776
  if (useOptimistic) trackOptimisticStore(store);
2729
2777
  return { base: base, overrideKey: overrideKey, state: state };
2730
2778
  }
2731
- function notifyStoreProperty(target, property, mode, value) {
2732
- if (target[STORE_HAS]?.[property]) setSignal(target[STORE_HAS][property], mode !== "delete");
2779
+ function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
2780
+ if (nodes[property]) return nodes[property];
2781
+ const initial = isWrappable(prev) ? wrap(prev, target) : prev;
2782
+ const node = getNode(
2783
+ nodes,
2784
+ property,
2785
+ initial,
2786
+ target[STORE_FIREWALL],
2787
+ isEqual,
2788
+ target[STORE_OPTIMISTIC],
2789
+ snapshotProps
2790
+ );
2791
+ registerTransientStoreNode(node);
2792
+ return node;
2793
+ }
2794
+ function notifyStoreProperty(target, property, mode, value, prev, prevHas) {
2795
+ const skipUpsert = projectionWriteActive || target[STORE_OPTIMISTIC];
2796
+ const newHas = mode !== "delete";
2797
+ const existingHas = target[STORE_HAS]?.[property];
2798
+ if (existingHas) {
2799
+ setSignal(existingHas, newHas);
2800
+ } else if (!skipUpsert && mode !== "invalidate" && prevHas !== newHas) {
2801
+ const hasNode = upsertStoreNode(target, getNodes(target, STORE_HAS), property, prevHas);
2802
+ setSignal(hasNode, newHas);
2803
+ }
2733
2804
  const nodes = getNodes(target, STORE_NODE);
2734
2805
  if (mode === "set") {
2735
- nodes[property] &&
2806
+ if (nodes[property]) {
2736
2807
  setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
2808
+ } else if (!skipUpsert) {
2809
+ const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
2810
+ setSignal(node, () => (isWrappable(value) ? wrap(value, target) : value));
2811
+ }
2737
2812
  } else if (mode === "invalidate") {
2738
2813
  if (nodes[property]) {
2739
2814
  setSignal(nodes[property], {});
2740
2815
  delete nodes[property];
2741
2816
  }
2742
2817
  } else {
2743
- nodes[property] && setSignal(nodes[property], undefined);
2818
+ if (nodes[property]) {
2819
+ setSignal(nodes[property], undefined);
2820
+ } else if (!skipUpsert) {
2821
+ const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
2822
+ setSignal(node, undefined);
2823
+ }
2744
2824
  }
2745
2825
  nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
2746
2826
  }
@@ -2837,18 +2917,13 @@ const storeTraps = {
2837
2917
  : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
2838
2918
  ? target[STORE_OVERRIDE][property] !== $DELETED
2839
2919
  : property in target[STORE_VALUE];
2840
- if (!writeOnly(target[$PROXY])) {
2841
- getObserver() &&
2842
- read(
2843
- getNode(
2844
- getNodes(target, STORE_HAS),
2845
- property,
2846
- has,
2847
- target[STORE_FIREWALL],
2848
- isEqual,
2849
- target[STORE_OPTIMISTIC]
2850
- )
2851
- );
2920
+ if (writeOnly(target[$PROXY])) return has;
2921
+ const nodes = getNodes(target, STORE_HAS);
2922
+ if (nodes[property]) return read(nodes[property]);
2923
+ if (getObserver()) {
2924
+ return read(
2925
+ getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
2926
+ );
2852
2927
  }
2853
2928
  return has;
2854
2929
  },
@@ -2867,6 +2942,12 @@ const storeTraps = {
2867
2942
  : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
2868
2943
  ? target[STORE_OVERRIDE][property]
2869
2944
  : base;
2945
+ const prevHas =
2946
+ target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
2947
+ ? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
2948
+ : target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
2949
+ ? target[STORE_OVERRIDE][property] !== $DELETED
2950
+ : property in target[STORE_VALUE];
2870
2951
  const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
2871
2952
  const isArrayIndexWrite = Array.isArray(state) && property !== "length";
2872
2953
  const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
@@ -2886,11 +2967,21 @@ const storeTraps = {
2886
2967
  override[property] = value;
2887
2968
  if (nextLength !== undefined) override.length = nextLength;
2888
2969
  }
2889
- notifyStoreProperty(target, property, "set", value);
2890
- if (Array.isArray(state)) {
2970
+ notifyStoreProperty(target, property, "set", value, prev, prevHas);
2971
+ if (Array.isArray(state) && property !== "length" && nextLength !== undefined) {
2891
2972
  const nodes = getNodes(target, STORE_NODE);
2892
- const lengthValue = property === "length" ? value : nextLength;
2893
- lengthValue !== undefined && nodes.length && setSignal(nodes.length, lengthValue);
2973
+ if (nodes.length) {
2974
+ setSignal(nodes.length, nextLength);
2975
+ } else if (!projectionWriteActive && !target[STORE_OPTIMISTIC]) {
2976
+ const node = upsertStoreNode(
2977
+ target,
2978
+ nodes,
2979
+ "length",
2980
+ len,
2981
+ target[STORE_SNAPSHOT_PROPS]
2982
+ );
2983
+ setSignal(node, nextLength);
2984
+ }
2894
2985
  }
2895
2986
  if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
2896
2987
  });
@@ -2948,7 +3039,7 @@ const storeTraps = {
2948
3039
  } else if (target[overrideKey] && property in target[overrideKey]) {
2949
3040
  delete target[overrideKey][property];
2950
3041
  } else return true;
2951
- notifyStoreProperty(target, property, "delete");
3042
+ notifyStoreProperty(target, property, "delete", undefined, prev, true);
2952
3043
  });
2953
3044
  }
2954
3045
  return true;
@@ -3021,7 +3112,7 @@ function createStore(first, second, options) {
3021
3112
  function createOptimisticStore(first, second, options) {
3022
3113
  GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
3023
3114
  const derived = typeof first === "function";
3024
- const initialValue = (derived ? second : first) ?? {};
3115
+ const initialValue = derived ? second : first;
3025
3116
  const fn = derived ? first : undefined;
3026
3117
  const { store: wrappedStore } = createOptimisticProjectionInternal(fn, initialValue, options);
3027
3118
  return [wrappedStore, fn => storeSetter(wrappedStore, fn)];
@@ -3055,7 +3146,7 @@ function clearOptimisticStore(store) {
3055
3146
  }
3056
3147
  delete target[STORE_OPTIMISTIC_OVERRIDE];
3057
3148
  }
3058
- function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
3149
+ function createOptimisticProjectionInternal(fn, initialValue, options) {
3059
3150
  let node;
3060
3151
  const wrappedMap = new WeakMap();
3061
3152
  const wrapper = s => {
@@ -3078,37 +3169,25 @@ function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
3078
3169
  };
3079
3170
  const wrappedStore = wrapProjection(initialValue);
3080
3171
  if (fn) {
3081
- node = computed(() => {
3082
- const owner = getOwner();
3083
- let settled = false;
3084
- let result;
3085
- const draft = new Proxy(
3086
- wrappedStore,
3087
- createWriteTraps(() => !settled || owner._inFlight === result)
3088
- );
3172
+ const wrapCommit = write => {
3089
3173
  setProjectionWriteActive(true);
3090
3174
  try {
3091
- storeSetter(draft, s => {
3092
- result = fn(s);
3093
- settled = true;
3094
- const value = handleAsync(owner, result, value => {
3095
- setProjectionWriteActive(true);
3096
- try {
3097
- value !== s &&
3098
- value !== undefined &&
3099
- storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
3100
- } finally {
3101
- setProjectionWriteActive(false);
3102
- }
3103
- });
3104
- value !== s &&
3105
- value !== undefined &&
3106
- reconcile(value, options?.key || "id")(wrappedStore);
3107
- });
3175
+ write();
3108
3176
  } finally {
3109
3177
  setProjectionWriteActive(false);
3110
3178
  }
3111
- });
3179
+ };
3180
+ node = computed(
3181
+ () => {
3182
+ setProjectionWriteActive(true);
3183
+ try {
3184
+ runProjectionComputed(wrappedStore, fn, options?.key || "id", wrapCommit);
3185
+ } finally {
3186
+ setProjectionWriteActive(false);
3187
+ }
3188
+ },
3189
+ options?.name ? { name: options.name } : undefined
3190
+ );
3112
3191
  node._preventAutoDisposal = true;
3113
3192
  }
3114
3193
  return { store: wrappedStore, node: node };
@@ -3386,7 +3465,7 @@ function mapArray(list, map, options) {
3386
3465
  }
3387
3466
  }
3388
3467
  : map;
3389
- return createMemo(
3468
+ const node = computed(
3390
3469
  updateKeyedMap.bind({
3391
3470
  _owner: createOwner(),
3392
3471
  _len: 0,
@@ -3401,8 +3480,10 @@ function mapArray(list, map, options) {
3401
3480
  _fallback: options?.fallback
3402
3481
  })
3403
3482
  );
3483
+ node._preventAutoDisposal = true;
3484
+ return accessor(node);
3404
3485
  }
3405
- const pureOptions = { pureWrite: true };
3486
+ const pureOptions = { ownedWrite: true };
3406
3487
  function updateKeyedMap() {
3407
3488
  const newItems = this._list() || [],
3408
3489
  newLen = newItems.length;
@@ -3539,17 +3620,21 @@ function repeat(count, map, options) {
3539
3620
  }
3540
3621
  }
3541
3622
  : map;
3542
- return updateRepeat.bind({
3543
- _owner: createOwner(),
3544
- _len: 0,
3545
- _offset: 0,
3546
- _count: count,
3547
- _map: wrappedMap,
3548
- _nodes: [],
3549
- _mappings: [],
3550
- _from: options?.from,
3551
- _fallback: options?.fallback
3552
- });
3623
+ const node = computed(
3624
+ updateRepeat.bind({
3625
+ _owner: createOwner(),
3626
+ _len: 0,
3627
+ _offset: 0,
3628
+ _count: count,
3629
+ _map: wrappedMap,
3630
+ _nodes: [],
3631
+ _mappings: [],
3632
+ _from: options?.from,
3633
+ _fallback: options?.fallback
3634
+ })
3635
+ );
3636
+ node._preventAutoDisposal = true;
3637
+ return accessor(node);
3553
3638
  }
3554
3639
  function updateRepeat() {
3555
3640
  const newLen = this._count();
@@ -3606,7 +3691,7 @@ function compare(key, a, b) {
3606
3691
  return key ? key(a) === key(b) : true;
3607
3692
  }
3608
3693
  function boundaryComputed(fn, propagationMask) {
3609
- const node = computed(fn, undefined, { lazy: true });
3694
+ const node = computed(fn, { lazy: true });
3610
3695
  node._notifyStatus = (status, error) => {
3611
3696
  const flags = status !== undefined ? status : node._statusFlags;
3612
3697
  const actualError = error !== undefined ? error : node._error;
@@ -3631,12 +3716,16 @@ const ON_INIT = Symbol();
3631
3716
  const RevealControllerContext = createContext(null);
3632
3717
  let _revealUsed = false;
3633
3718
  const FALSE_ACCESSOR = () => false;
3719
+ const SEQUENTIAL_ACCESSOR = () => "sequential";
3634
3720
  function isRevealController(slot) {
3635
3721
  return slot instanceof RevealController;
3636
3722
  }
3637
3723
  function isSlotReady(slot) {
3638
3724
  return isRevealController(slot) ? slot.isReady() : slot._sources.size === 0 && !slot._pending;
3639
3725
  }
3726
+ function isSlotMinimallyReady(slot) {
3727
+ return isRevealController(slot) ? slot.isMinimallyReady() : isSlotReady(slot);
3728
+ }
3640
3729
  function setSlotState(slot, controller, disabled, collapsed) {
3641
3730
  setSignal(slot._disabled, disabled);
3642
3731
  setSignal(slot._collapsed, collapsed);
@@ -3648,16 +3737,17 @@ function setSlotState(slot, controller, disabled, collapsed) {
3648
3737
  slot._revealController = undefined;
3649
3738
  }
3650
3739
  class RevealController {
3651
- _togetherAccessor;
3740
+ _orderAccessor;
3652
3741
  _collapsedAccessor;
3653
3742
  _slots = [];
3654
3743
  _parentController;
3655
- _disabled = signal(false, { pureWrite: true, _noSnapshot: true });
3656
- _collapsed = signal(false, { pureWrite: true, _noSnapshot: true });
3744
+ _disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
3745
+ _collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
3657
3746
  _ready = true;
3747
+ _minimallyReady = true;
3658
3748
  _evaluating = false;
3659
- constructor(together, collapsed) {
3660
- this._togetherAccessor = together;
3749
+ constructor(order, collapsed) {
3750
+ this._orderAccessor = order;
3661
3751
  this._collapsedAccessor = collapsed;
3662
3752
  }
3663
3753
  _forEachOwnedSlot(fn) {
@@ -3672,12 +3762,37 @@ class RevealController {
3672
3762
  isReady() {
3673
3763
  return this._forEachOwnedSlot(isSlotReady);
3674
3764
  }
3765
+ isMinimallyReady() {
3766
+ const order = untrack(this._orderAccessor);
3767
+ if (order === "together") return this.isReady();
3768
+ if (order === "natural") {
3769
+ let hasSlot = false;
3770
+ let anyReady = false;
3771
+ this._forEachOwnedSlot(slot => {
3772
+ hasSlot = true;
3773
+ if (isSlotMinimallyReady(slot)) {
3774
+ anyReady = true;
3775
+ return false;
3776
+ }
3777
+ });
3778
+ return !hasSlot || anyReady;
3779
+ }
3780
+ let firstReady = true;
3781
+ this._forEachOwnedSlot(slot => {
3782
+ firstReady = isSlotMinimallyReady(slot);
3783
+ return false;
3784
+ });
3785
+ return firstReady;
3786
+ }
3675
3787
  register(slot) {
3676
3788
  if (this._slots.includes(slot)) return;
3677
3789
  this._slots.push(slot);
3678
- const together = !!untrack(this._togetherAccessor);
3679
- setSignal(slot._disabled, true),
3680
- setSignal(slot._collapsed, together ? false : !!untrack(this._collapsedAccessor));
3790
+ const order = untrack(this._orderAccessor);
3791
+ (setSignal(slot._disabled, true),
3792
+ setSignal(
3793
+ slot._collapsed,
3794
+ order === "sequential" ? !!untrack(this._collapsedAccessor) : false
3795
+ ));
3681
3796
  untrack(() => this.evaluate());
3682
3797
  }
3683
3798
  unregister(slot) {
@@ -3689,29 +3804,52 @@ class RevealController {
3689
3804
  if (this._evaluating) return;
3690
3805
  this._evaluating = true;
3691
3806
  const wasReady = this._ready;
3807
+ const wasMinReady = this._minimallyReady;
3692
3808
  try {
3693
3809
  const disabled = disabledOverride ?? read(this._disabled),
3694
- collapseTail = !!untrack(this._collapsedAccessor),
3810
+ order = untrack(this._orderAccessor),
3811
+ collapseTail = order === "sequential" && !!untrack(this._collapsedAccessor),
3695
3812
  collapsed = collapsedOverride ?? collapseTail;
3696
- if (disabled && collapsed)
3697
- this._forEachOwnedSlot(slot => setSlotState(slot, this, true, true));
3698
- else if (!!untrack(this._togetherAccessor)) {
3699
- const ready = this.isReady();
3700
- this._forEachOwnedSlot(slot => setSlotState(slot, this, !ready, false));
3813
+ if (disabled) {
3814
+ this._forEachOwnedSlot(slot => setSlotState(slot, this, true, collapsed));
3815
+ } else if (order === "natural") {
3816
+ this._forEachOwnedSlot(slot => {
3817
+ if (isRevealController(slot)) {
3818
+ setSignal(slot._collapsed, false);
3819
+ setSignal(slot._disabled, false);
3820
+ slot.evaluate(false, false);
3821
+ } else {
3822
+ setSlotState(slot, this, !isSlotReady(slot), false);
3823
+ }
3824
+ });
3825
+ } else if (order === "together") {
3826
+ const minReady = this._forEachOwnedSlot(isSlotMinimallyReady);
3827
+ this._forEachOwnedSlot(slot => setSlotState(slot, this, !minReady, false));
3701
3828
  } else {
3702
3829
  let pendingSeen = false;
3703
3830
  this._forEachOwnedSlot(slot => {
3704
3831
  if (pendingSeen) return setSlotState(slot, this, true, collapseTail);
3705
3832
  if (isSlotReady(slot)) return setSlotState(slot, this, false, false);
3706
3833
  pendingSeen = true;
3707
- setSlotState(slot, this, true, false);
3834
+ if (isRevealController(slot)) {
3835
+ setSignal(slot._collapsed, false);
3836
+ setSignal(slot._disabled, false);
3837
+ slot.evaluate(false, false);
3838
+ } else {
3839
+ setSlotState(slot, this, true, false);
3840
+ }
3708
3841
  });
3709
3842
  }
3710
3843
  } finally {
3711
3844
  this._ready = this.isReady();
3845
+ this._minimallyReady = this.isMinimallyReady();
3712
3846
  this._evaluating = false;
3713
3847
  }
3714
- if (this._parentController && wasReady !== this._ready) this._parentController.evaluate();
3848
+ if (
3849
+ this._parentController &&
3850
+ (wasReady !== this._ready || wasMinReady !== this._minimallyReady)
3851
+ )
3852
+ this._parentController.evaluate();
3715
3853
  }
3716
3854
  }
3717
3855
  class CollectionQueue extends Queue {
@@ -3719,8 +3857,8 @@ class CollectionQueue extends Queue {
3719
3857
  _sources = new Set();
3720
3858
  _tree;
3721
3859
  _pending = true;
3722
- _disabled = signal(false, { pureWrite: true, _noSnapshot: true });
3723
- _collapsed = signal(false, { pureWrite: true, _noSnapshot: true });
3860
+ _disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
3861
+ _collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
3724
3862
  _revealController;
3725
3863
  _initialized = false;
3726
3864
  _onFn;
@@ -3836,7 +3974,7 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
3836
3974
  const decision = computed(() => {
3837
3975
  if (!read(queue._disabled)) {
3838
3976
  const resolved = read(tree);
3839
- if (!untrack(() => read(queue._disabled))) return (queue._initialized = true), resolved;
3977
+ if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
3840
3978
  }
3841
3979
  if (_revealUsed && read(queue._collapsed)) return undefined;
3842
3980
  return fallback(queue);
@@ -3860,14 +3998,14 @@ function createRevealOrder(fn, options) {
3860
3998
  _revealUsed = true;
3861
3999
  const owner = createOwner();
3862
4000
  const parentController = getContext(RevealControllerContext);
3863
- const together = options?.together || FALSE_ACCESSOR,
4001
+ const order = options?.order || SEQUENTIAL_ACCESSOR,
3864
4002
  collapsed = options?.collapsed || FALSE_ACCESSOR;
3865
- const controller = new RevealController(together, collapsed);
4003
+ const controller = new RevealController(order, collapsed);
3866
4004
  setContext(RevealControllerContext, controller, owner);
3867
4005
  return runWithOwner(owner, () => {
3868
4006
  const value = fn();
3869
4007
  computed(() => {
3870
- together();
4008
+ order();
3871
4009
  collapsed();
3872
4010
  controller.evaluate();
3873
4011
  });