@solidjs/signals 0.13.11 → 0.13.13

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
@@ -145,21 +145,53 @@ function adjustHeight(el, heap) {
145
145
  }
146
146
  }
147
147
  const hooks = {};
148
- const DEV = {
148
+ const diagnosticListeners = new Set();
149
+ const diagnosticCaptures = new Set();
150
+ let diagnosticSequence = 0;
151
+ const diagnostics = {
152
+ subscribe(listener) {
153
+ diagnosticListeners.add(listener);
154
+ return () => diagnosticListeners.delete(listener);
155
+ },
156
+ capture() {
157
+ const events = [];
158
+ diagnosticCaptures.add(events);
159
+ return {
160
+ get events() {
161
+ return events;
162
+ },
163
+ clear() {
164
+ events.length = 0;
165
+ },
166
+ stop() {
167
+ diagnosticCaptures.delete(events);
168
+ return [...events];
169
+ }
170
+ };
171
+ }
172
+ };
173
+ const DEV$1 = {
149
174
  hooks: hooks,
175
+ diagnostics: diagnostics,
150
176
  getChildren: getChildren,
151
177
  getSignals: getSignals,
152
178
  getParent: getParent,
153
179
  getSources: getSources,
154
180
  getObservers: getObservers
155
181
  };
182
+ function emitDiagnostic(event) {
183
+ const entry = { sequence: ++diagnosticSequence, ...event };
184
+ for (const listener of diagnosticListeners) listener(entry);
185
+ for (const capture of diagnosticCaptures) capture.push(entry);
186
+ return entry;
187
+ }
156
188
  function registerGraph(value, owner) {
157
189
  value._owner = owner;
158
190
  if (owner) {
159
191
  if (!owner._signals) owner._signals = [];
160
192
  owner._signals.push(value);
161
193
  }
162
- DEV.hooks.onGraph?.(value, owner);
194
+ DEV$1.hooks.onGraph?.(value, owner);
163
195
  }
164
196
  function clearSignals(node) {
165
197
  node._signals = undefined;
@@ -252,13 +284,13 @@ function setTrackedQueueCallback(value) {
252
284
  function mergeTransitionState(target, outgoing) {
253
285
  outgoing._done = target;
254
286
  target._actions.push(...outgoing._actions);
255
- for (const lane of activeLanes) {
256
- if (lane._transition === outgoing) lane._transition = target;
257
- }
287
+ for (const lane of activeLanes) if (lane._transition === outgoing) lane._transition = target;
258
288
  target._optimisticNodes.push(...outgoing._optimisticNodes);
259
289
  for (const store of outgoing._optimisticStores) target._optimisticStores.add(store);
260
- for (const node of outgoing._asyncNodes) {
261
- if (!target._asyncNodes.includes(node)) target._asyncNodes.push(node);
290
+ for (const [source, reporters] of outgoing._asyncReporters) {
291
+ let targetReporters = target._asyncReporters.get(source);
292
+ if (!targetReporters) target._asyncReporters.set(source, (targetReporters = new Set()));
293
+ for (const reporter of reporters) targetReporters.add(reporter);
262
294
  }
263
295
  }
264
296
  function resolveOptimisticNodes(nodes) {
@@ -424,7 +456,7 @@ class GlobalQueue extends Queue {
424
456
  this.run(EFFECT_RENDER);
425
457
  runLaneEffects(EFFECT_USER);
426
458
  this.run(EFFECT_USER);
427
- if (true) DEV.hooks.onUpdate?.();
459
+ if (true) DEV$1.hooks.onUpdate?.();
428
460
  } finally {
429
461
  this._running = false;
430
462
  }
@@ -435,10 +467,11 @@ class GlobalQueue extends Queue {
435
467
  const actualError = error !== undefined ? error : node._error;
436
468
  if (activeTransition && actualError) {
437
469
  const source = actualError.source;
438
- if (!activeTransition._asyncNodes.includes(source)) {
439
- activeTransition._asyncNodes.push(source);
440
- schedule();
441
- }
470
+ let reporters = activeTransition._asyncReporters.get(source);
471
+ if (!reporters) activeTransition._asyncReporters.set(source, (reporters = new Set()));
472
+ const prevSize = reporters.size;
473
+ reporters.add(node);
474
+ if (reporters.size !== prevSize) schedule();
442
475
  }
443
476
  if (_enforceLoadingBoundary) _hitUnhandledAsync = true;
444
477
  }
@@ -454,7 +487,7 @@ class GlobalQueue extends Queue {
454
487
  activeTransition = transition ?? {
455
488
  _time: clock,
456
489
  _pendingNodes: [],
457
- _asyncNodes: [],
490
+ _asyncReporters: new Map(),
458
491
  _optimisticNodes: [],
459
492
  _optimisticStores: new Set(),
460
493
  _actions: [],
@@ -593,13 +626,37 @@ function flush() {
593
626
  function runQueue(queue, type) {
594
627
  for (let i = 0; i < queue.length; i++) queue[i](type);
595
628
  }
629
+ function reporterBlocksSource(reporter, source) {
630
+ if (reporter._flags & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
631
+ if (reporter._pendingSource === source || reporter._pendingSources?.has(source)) return true;
632
+ for (let dep = reporter._deps; dep; dep = dep._nextDep) {
633
+ let current = dep._dep;
634
+ while (current) {
635
+ if (current === source || current._firewall === source) return true;
636
+ current = current._parentSource;
637
+ }
638
+ }
639
+ return !!(
640
+ reporter._statusFlags & STATUS_PENDING &&
641
+ reporter._error instanceof NotReadyError &&
642
+ reporter._error.source === source
643
+ );
644
+ }
596
645
  function transitionComplete(transition) {
597
646
  if (transition._done) return true;
598
647
  if (transition._actions.length) return false;
599
648
  let done = true;
600
- for (let i = 0; i < transition._asyncNodes.length; i++) {
601
- const node = transition._asyncNodes[i];
602
- if (node._statusFlags & STATUS_PENDING && node._error?.source === node) {
649
+ for (const [source, reporters] of transition._asyncReporters) {
650
+ let hasLive = false;
651
+ for (const reporter of reporters) {
652
+ if (reporterBlocksSource(reporter, source)) {
653
+ hasLive = true;
654
+ break;
655
+ }
656
+ reporters.delete(reporter);
657
+ }
658
+ if (!hasLive) transition._asyncReporters.delete(source);
659
+ else if (source._statusFlags & STATUS_PENDING && source._error?.source === source) {
603
660
  done = false;
604
661
  break;
605
662
  }
@@ -907,7 +964,7 @@ function createOwner(options) {
907
964
  parent._firstChild = owner;
908
965
  }
909
966
  }
910
- DEV.hooks.onOwner?.(owner);
967
+ DEV$1.hooks.onOwner?.(owner);
911
968
  return owner;
912
969
  }
913
970
  function createRoot(init, options) {
@@ -1024,6 +1081,7 @@ function handleAsync(el, result, setter) {
1024
1081
  if (el._inFlight !== result) return;
1025
1082
  if (el._flags & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
1026
1083
  globalQueue.initTransition(resolveTransition(el));
1084
+ const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
1027
1085
  clearStatus(el);
1028
1086
  const lane = resolveLane(el);
1029
1087
  if (lane) lane._pendingAsync.delete(el);
@@ -1037,9 +1095,10 @@ function handleAsync(el, result, setter) {
1037
1095
  }
1038
1096
  el._time = clock;
1039
1097
  } else if (lane) {
1098
+ const isEffect = el._type;
1040
1099
  const prevValue = el._value;
1041
1100
  const equals = el._equals;
1042
- if (!equals || !equals(value, prevValue)) {
1101
+ if ((!isEffect && wasUninitialized) || !equals || !equals(value, prevValue)) {
1043
1102
  el._value = value;
1044
1103
  el._time = clock;
1045
1104
  if (el._latestValueComputed) {
@@ -1302,6 +1361,7 @@ function recompute(el, create = false) {
1302
1361
  const isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
1303
1362
  const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
1304
1363
  const wasPending = !!(el._statusFlags & STATUS_PENDING);
1364
+ const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
1305
1365
  const oldcontext = context;
1306
1366
  context = el;
1307
1367
  el._depsTail = null;
@@ -1367,7 +1427,8 @@ function recompute(el, create = false) {
1367
1427
  : el._pendingValue === NOT_PENDING
1368
1428
  ? el._value
1369
1429
  : el._pendingValue;
1370
- const valueChanged = !el._equals || !el._equals(compareValue, value);
1430
+ const valueChanged =
1431
+ (!isEffect && wasUninitialized) || !el._equals || !el._equals(compareValue, value);
1371
1432
  if (valueChanged) {
1372
1433
  const prevVisible = hasOverride ? el._overrideValue : undefined;
1373
1434
  if (create || (isEffect && activeTransition !== el._transition) || isOptimisticDirty) {
@@ -1473,7 +1534,7 @@ function computed(fn, initialValue, options) {
1473
1534
  context._firstChild = self;
1474
1535
  }
1475
1536
  }
1476
- DEV.hooks.onOwner?.(self);
1537
+ DEV$1.hooks.onOwner?.(self);
1477
1538
  if (parent) self._height = parent._height + 1;
1478
1539
  if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
1479
1540
  if (externalSourceConfig) {
@@ -1618,10 +1679,20 @@ function read(el) {
1618
1679
  }
1619
1680
  const owner = el._firewall || el;
1620
1681
  if (strictRead && owner._statusFlags & STATUS_PENDING) {
1621
- throw new Error(
1682
+ const message =
1622
1683
  `Reading a pending async value directly in ${strictRead}. ` +
1623
- `Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`
1624
- );
1684
+ `Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`;
1685
+ emitDiagnostic({
1686
+ code: "PENDING_ASYNC_UNTRACKED_READ",
1687
+ kind: "async",
1688
+ severity: "error",
1689
+ message: message,
1690
+ ownerId: c?.id,
1691
+ ownerName: c?._name,
1692
+ nodeName: owner?._name,
1693
+ data: { strictRead: strictRead }
1694
+ });
1695
+ throw new Error(message);
1625
1696
  }
1626
1697
  if (c && tracking) {
1627
1698
  if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
@@ -1642,10 +1713,19 @@ function read(el) {
1642
1713
  if (owner._statusFlags & STATUS_PENDING) {
1643
1714
  if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
1644
1715
  if (c?._childrenForbidden) {
1645
- console.warn(
1716
+ const message =
1646
1717
  "Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
1647
- "Use createEffect instead which supports async-aware reactivity."
1648
- );
1718
+ "Use createEffect instead which supports async-aware reactivity.";
1719
+ emitDiagnostic({
1720
+ code: "PENDING_ASYNC_FORBIDDEN_SCOPE",
1721
+ kind: "async",
1722
+ severity: "warn",
1723
+ message: message,
1724
+ ownerId: c.id,
1725
+ ownerName: c._name,
1726
+ nodeName: owner?._name
1727
+ });
1728
+ console.warn(message);
1649
1729
  }
1650
1730
  if (currentOptimisticLane) {
1651
1731
  const pendingLane = owner._optimisticLane;
@@ -1680,11 +1760,22 @@ function read(el) {
1680
1760
  return snapshot;
1681
1761
  }
1682
1762
  }
1683
- if (strictRead)
1684
- console.warn(
1763
+ if (strictRead) {
1764
+ const message =
1685
1765
  `Reactive value read directly in ${strictRead} will not update. ` +
1686
- `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`
1687
- );
1766
+ `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
1767
+ emitDiagnostic({
1768
+ code: "STRICT_READ_UNTRACKED",
1769
+ kind: "strict-read",
1770
+ severity: "warn",
1771
+ message: message,
1772
+ ownerId: c?.id,
1773
+ ownerName: c?._name,
1774
+ nodeName: owner?._name,
1775
+ data: { strictRead: strictRead }
1776
+ });
1777
+ console.warn(message);
1778
+ }
1688
1779
  if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) {
1689
1780
  if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
1690
1781
  return el._overrideValue;
@@ -1701,8 +1792,21 @@ function read(el) {
1701
1792
  : el._pendingValue;
1702
1793
  }
1703
1794
  function setSignal(el, v) {
1704
- if (!el._pureWrite && !context?._childrenForbidden && context && el._firewall !== context)
1705
- console.warn("A Signal was written to in an owned scope.");
1795
+ if (!el._pureWrite && !context?._childrenForbidden && context && el._firewall !== context) {
1796
+ const message =
1797
+ "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.";
1799
+ emitDiagnostic({
1800
+ code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
1801
+ kind: "write",
1802
+ severity: "error",
1803
+ message: message,
1804
+ ownerId: context.id,
1805
+ ownerName: context._name,
1806
+ nodeName: el._name
1807
+ });
1808
+ throw new Error(message);
1809
+ }
1706
1810
  if (el._transition && activeTransition !== el._transition)
1707
1811
  globalQueue.initTransition(el._transition);
1708
1812
  const isOptimistic = el._overrideValue !== undefined && !projectionWriteActive;
@@ -1749,10 +1853,19 @@ function setSignal(el, v) {
1749
1853
  return v;
1750
1854
  }
1751
1855
  function runWithOwner(owner, fn) {
1752
- if (owner && owner._flags & REACTIVE_DISPOSED)
1753
- console.warn(
1754
- "runWithOwner called with a disposed owner. Children created inside will never be disposed."
1755
- );
1856
+ if (owner && owner._flags & REACTIVE_DISPOSED) {
1857
+ const message =
1858
+ "runWithOwner called with a disposed owner. Children created inside will never be disposed.";
1859
+ emitDiagnostic({
1860
+ code: "RUN_WITH_DISPOSED_OWNER",
1861
+ kind: "owner",
1862
+ severity: "warn",
1863
+ message: message,
1864
+ ownerId: owner.id,
1865
+ ownerName: owner._name
1866
+ });
1867
+ console.warn(message);
1868
+ }
1756
1869
  const oldContext = context;
1757
1870
  const prevTracking = tracking;
1758
1871
  context = owner;
@@ -1953,6 +2066,14 @@ function effect(compute, effect, error, initialValue, options) {
1953
2066
  if (_hitUnhandledAsync) {
1954
2067
  resetUnhandledAsync();
1955
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
+ });
1956
2077
  if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
1957
2078
  }
1958
2079
  }
@@ -1964,8 +2085,19 @@ function effect(compute, effect, error, initialValue, options) {
1964
2085
  : runEffect.call(node));
1965
2086
  initialized = true;
1966
2087
  cleanup(() => node._cleanup?.());
1967
- if (!node._parent)
1968
- console.warn("Effects created outside a reactive context will never be disposed");
2088
+ if (!node._parent) {
2089
+ const message = "Effects created outside a reactive context will never be disposed";
2090
+ emitDiagnostic({
2091
+ code: "NO_OWNER_EFFECT",
2092
+ kind: "lifecycle",
2093
+ severity: "warn",
2094
+ message: message,
2095
+ ownerId: node.id,
2096
+ ownerName: node._name,
2097
+ data: { effectType: "effect" }
2098
+ });
2099
+ console.warn(message);
2100
+ }
1969
2101
  }
1970
2102
  function runEffect() {
1971
2103
  if (!this._modified || this._flags & REACTIVE_DISPOSED) return;
@@ -2034,8 +2166,19 @@ function trackedEffect(fn, options) {
2034
2166
  node._run = run;
2035
2167
  node._queue.enqueue(EFFECT_USER, run);
2036
2168
  cleanup(() => node._cleanup?.());
2037
- if (!node._parent)
2038
- console.warn("Effects created outside a reactive context will never be disposed");
2169
+ if (!node._parent) {
2170
+ const message = "Effects created outside a reactive context will never be disposed";
2171
+ emitDiagnostic({
2172
+ code: "NO_OWNER_EFFECT",
2173
+ kind: "lifecycle",
2174
+ severity: "warn",
2175
+ message: message,
2176
+ ownerId: node.id,
2177
+ ownerName: node._name,
2178
+ data: { effectType: "trackedEffect" }
2179
+ });
2180
+ console.warn(message);
2181
+ }
2039
2182
  }
2040
2183
  function restoreTransition(transition, fn) {
2041
2184
  globalQueue.initTransition(transition);
@@ -2084,11 +2227,28 @@ function action(genFn) {
2084
2227
  function onCleanup(fn) {
2085
2228
  {
2086
2229
  const owner = getOwner();
2087
- if (!owner) console.warn("onCleanup called outside a reactive context will never be run");
2088
- else if (owner._childrenForbidden)
2089
- throw new Error(
2090
- "Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead"
2091
- );
2230
+ if (!owner) {
2231
+ const message = "onCleanup called outside a reactive context will never be run";
2232
+ emitDiagnostic({
2233
+ code: "NO_OWNER_CLEANUP",
2234
+ kind: "lifecycle",
2235
+ severity: "warn",
2236
+ message: message
2237
+ });
2238
+ console.warn(message);
2239
+ } else if (owner._childrenForbidden) {
2240
+ const message =
2241
+ "Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead";
2242
+ emitDiagnostic({
2243
+ code: "CLEANUP_IN_FORBIDDEN_SCOPE",
2244
+ kind: "lifecycle",
2245
+ severity: "error",
2246
+ message: message,
2247
+ ownerId: owner.id,
2248
+ ownerName: owner._name
2249
+ });
2250
+ throw new Error(message);
2251
+ }
2092
2252
  }
2093
2253
  return cleanup(fn);
2094
2254
  }
@@ -2534,12 +2694,55 @@ function getKeys(source, override, enumerable = true) {
2534
2694
  return Array.from(keys);
2535
2695
  }
2536
2696
  function getPropertyDescriptor(source, override, property) {
2537
- let value = source;
2538
2697
  if (override && property in override) {
2539
- if (value[property] === $DELETED) return void 0;
2540
- if (!(property in value)) value = override;
2698
+ if (override[property] === $DELETED) return void 0;
2699
+ const overrideDesc = Reflect.getOwnPropertyDescriptor(override, property);
2700
+ if (overrideDesc?.get || overrideDesc?.set || !(property in source)) return overrideDesc;
2541
2701
  }
2542
- return Reflect.getOwnPropertyDescriptor(value, property);
2702
+ return Reflect.getOwnPropertyDescriptor(source, property);
2703
+ }
2704
+ function prepareStoreWrite(target, store, property) {
2705
+ if (target[STORE_OPTIMISTIC]) {
2706
+ const firewall = target[STORE_FIREWALL];
2707
+ if (firewall?._transition) {
2708
+ globalQueue.initTransition(firewall._transition);
2709
+ }
2710
+ }
2711
+ const state = target[STORE_VALUE];
2712
+ const base = state[property];
2713
+ if (
2714
+ snapshotCaptureActive &&
2715
+ typeof property !== "symbol" &&
2716
+ !((target[STORE_FIREWALL]?._statusFlags ?? 0) & STATUS_PENDING)
2717
+ ) {
2718
+ if (!target[STORE_SNAPSHOT_PROPS]) {
2719
+ target[STORE_SNAPSHOT_PROPS] = Object.create(null);
2720
+ snapshotSources?.add(target);
2721
+ }
2722
+ if (!(property in target[STORE_SNAPSHOT_PROPS])) {
2723
+ target[STORE_SNAPSHOT_PROPS][property] = base;
2724
+ }
2725
+ }
2726
+ const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
2727
+ const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
2728
+ if (useOptimistic) trackOptimisticStore(store);
2729
+ return { base: base, overrideKey: overrideKey, state: state };
2730
+ }
2731
+ function notifyStoreProperty(target, property, mode, value) {
2732
+ if (target[STORE_HAS]?.[property]) setSignal(target[STORE_HAS][property], mode !== "delete");
2733
+ const nodes = getNodes(target, STORE_NODE);
2734
+ if (mode === "set") {
2735
+ nodes[property] &&
2736
+ setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
2737
+ } else if (mode === "invalidate") {
2738
+ if (nodes[property]) {
2739
+ setSignal(nodes[property], {});
2740
+ delete nodes[property];
2741
+ }
2742
+ } else {
2743
+ nodes[property] && setSignal(nodes[property], undefined);
2744
+ }
2745
+ nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
2543
2746
  }
2544
2747
  let Writing = null;
2545
2748
  const storeTraps = {
@@ -2610,11 +2813,20 @@ const storeTraps = {
2610
2813
  );
2611
2814
  }
2612
2815
  }
2613
- if (strictRead && typeof property === "string")
2614
- console.warn(
2816
+ if (strictRead && typeof property === "string") {
2817
+ const message =
2615
2818
  `Reactive value read directly in ${strictRead} will not update. ` +
2616
- `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`
2617
- );
2819
+ `Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
2820
+ emitDiagnostic({
2821
+ code: "STRICT_READ_UNTRACKED",
2822
+ kind: "strict-read",
2823
+ severity: "warn",
2824
+ message: message,
2825
+ nodeName: String(property),
2826
+ data: { strictRead: strictRead, property: String(property), source: "store" }
2827
+ });
2828
+ console.warn(message);
2829
+ }
2618
2830
  return isWrappable(value) ? wrap(value, target) : value;
2619
2831
  },
2620
2832
  has(target, property) {
@@ -2643,31 +2855,12 @@ const storeTraps = {
2643
2855
  set(target, property, rawValue) {
2644
2856
  const store = target[$PROXY];
2645
2857
  if (writeOnly(store)) {
2646
- if (target[STORE_OPTIMISTIC]) {
2647
- const firewall = target[STORE_FIREWALL];
2648
- if (firewall?._transition) {
2649
- globalQueue.initTransition(firewall._transition);
2650
- }
2651
- }
2652
2858
  untrack(() => {
2653
- const state = target[STORE_VALUE];
2654
- const base = state[property];
2655
- if (
2656
- snapshotCaptureActive &&
2657
- typeof property !== "symbol" &&
2658
- !((target[STORE_FIREWALL]?._statusFlags ?? 0) & STATUS_PENDING)
2659
- ) {
2660
- if (!target[STORE_SNAPSHOT_PROPS]) {
2661
- target[STORE_SNAPSHOT_PROPS] = Object.create(null);
2662
- snapshotSources?.add(target);
2663
- }
2664
- if (!(property in target[STORE_SNAPSHOT_PROPS])) {
2665
- target[STORE_SNAPSHOT_PROPS][property] = base;
2666
- }
2667
- }
2668
- const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
2669
- const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
2670
- if (useOptimistic) trackOptimisticStore(store);
2859
+ const {
2860
+ base: base,
2861
+ overrideKey: overrideKey,
2862
+ state: state
2863
+ } = prepareStoreWrite(target, store, property);
2671
2864
  const prev =
2672
2865
  target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
2673
2866
  ? target[STORE_OPTIMISTIC_OVERRIDE][property]
@@ -2693,17 +2886,42 @@ const storeTraps = {
2693
2886
  override[property] = value;
2694
2887
  if (nextLength !== undefined) override.length = nextLength;
2695
2888
  }
2696
- const wrappable = isWrappable(value);
2697
- target[STORE_HAS]?.[property] && setSignal(target[STORE_HAS][property], true);
2698
- const nodes = getNodes(target, STORE_NODE);
2699
- nodes[property] &&
2700
- setSignal(nodes[property], () => (wrappable ? wrap(value, target) : value));
2889
+ notifyStoreProperty(target, property, "set", value);
2701
2890
  if (Array.isArray(state)) {
2891
+ const nodes = getNodes(target, STORE_NODE);
2702
2892
  const lengthValue = property === "length" ? value : nextLength;
2703
2893
  lengthValue !== undefined && nodes.length && setSignal(nodes.length, lengthValue);
2704
2894
  }
2705
- nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
2706
- if (true) DEV.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
2895
+ if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
2896
+ });
2897
+ }
2898
+ return true;
2899
+ },
2900
+ defineProperty(target, property, descriptor) {
2901
+ const store = target[$PROXY];
2902
+ if (writeOnly(store)) {
2903
+ untrack(() => {
2904
+ const { base: base, overrideKey: overrideKey } = prepareStoreWrite(target, store, property);
2905
+ const normalizedDescriptor =
2906
+ "value" in descriptor
2907
+ ? {
2908
+ ...descriptor,
2909
+ value: descriptor.value?.[$TARGET]?.[STORE_VALUE] ?? descriptor.value
2910
+ }
2911
+ : descriptor;
2912
+ Object.defineProperty(
2913
+ target[overrideKey] || (target[overrideKey] = Object.create(null)),
2914
+ property,
2915
+ normalizedDescriptor
2916
+ );
2917
+ notifyStoreProperty(target, property, "invalidate");
2918
+ if (true) {
2919
+ const next =
2920
+ "value" in normalizedDescriptor
2921
+ ? normalizedDescriptor.value
2922
+ : normalizedDescriptor.get?.call(store);
2923
+ DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, next, base);
2924
+ }
2707
2925
  });
2708
2926
  }
2709
2927
  return true;
@@ -2730,10 +2948,7 @@ const storeTraps = {
2730
2948
  } else if (target[overrideKey] && property in target[overrideKey]) {
2731
2949
  delete target[overrideKey][property];
2732
2950
  } else return true;
2733
- if (target[STORE_HAS]?.[property]) setSignal(target[STORE_HAS][property], false);
2734
- const nodes = getNodes(target, STORE_NODE);
2735
- nodes[property] && setSignal(nodes[property], undefined);
2736
- nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
2951
+ notifyStoreProperty(target, property, "delete");
2737
2952
  });
2738
2953
  }
2739
2954
  return true;
@@ -2755,6 +2970,8 @@ const storeTraps = {
2755
2970
  if (property === $PROXY) return { value: target[$PROXY], writable: true, configurable: true };
2756
2971
  if (target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]) {
2757
2972
  if (target[STORE_OPTIMISTIC_OVERRIDE][property] === $DELETED) return undefined;
2973
+ const optDesc = Reflect.getOwnPropertyDescriptor(target[STORE_OPTIMISTIC_OVERRIDE], property);
2974
+ if (optDesc?.get || optDesc?.set || !(property in target[STORE_VALUE])) return optDesc;
2758
2975
  const baseDesc = getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
2759
2976
  if (baseDesc) {
2760
2977
  return { ...baseDesc, value: target[STORE_OPTIMISTIC_OVERRIDE][property] };
@@ -2948,7 +3165,12 @@ function updatePath(current, args, i = 0) {
2948
3165
  ) {
2949
3166
  const target = part !== undefined ? current[part] : current;
2950
3167
  const keys = Object.keys(value);
2951
- for (let i = 0; i < keys.length; i++) target[keys[i]] = value[keys[i]];
3168
+ for (let i = 0; i < keys.length; i++) {
3169
+ const key = keys[i];
3170
+ const desc = Object.getOwnPropertyDescriptor(value, key);
3171
+ if (desc.get || desc.set) Object.defineProperty(target, key, desc);
3172
+ else target[key] = desc.value;
3173
+ }
2952
3174
  } else {
2953
3175
  current[part] = value;
2954
3176
  }
@@ -3577,8 +3799,17 @@ class CollectionQueue extends Queue {
3577
3799
  }
3578
3800
  }
3579
3801
  function createCollectionBoundary(type, fn, fallback, onFn) {
3580
- if (!getOwner())
3581
- console.warn("Boundaries created outside a reactive context will never be disposed.");
3802
+ if (!getOwner()) {
3803
+ const message = "Boundaries created outside a reactive context will never be disposed.";
3804
+ emitDiagnostic({
3805
+ code: "NO_OWNER_BOUNDARY",
3806
+ kind: "lifecycle",
3807
+ severity: "warn",
3808
+ message: message,
3809
+ data: { boundaryType: type === STATUS_PENDING ? "loading" : "error" }
3810
+ });
3811
+ console.warn(message);
3812
+ }
3582
3813
  const owner = createOwner();
3583
3814
  if (_revealUsed) setContext(RevealControllerContext, null, owner);
3584
3815
  const queue = new CollectionQueue(type);
@@ -3704,6 +3935,7 @@ function flattenArray(children, results = [], options) {
3704
3935
  if (notReady) throw notReady;
3705
3936
  return needsUnwrap;
3706
3937
  }
3938
+ const DEV = DEV$1;
3707
3939
  export {
3708
3940
  $PROXY,
3709
3941
  $REFRESH,