@fluixi/reactive 1.0.0-alpha.82 → 1.0.0-alpha.84

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 (169) hide show
  1. package/README.md +4 -0
  2. package/dist/cdn/reactive.cjs +2673 -1
  3. package/dist/cdn/reactive.global.js +2 -1
  4. package/dist/cdn/reactive.mjs +2657 -1
  5. package/dist/cdn/signal.cjs +299 -1
  6. package/dist/cdn/signal.d.ts +1 -1
  7. package/dist/cdn/signal.global.js +2 -1
  8. package/dist/cdn/signal.js +1 -1
  9. package/dist/cdn/signal.mjs +276 -1
  10. package/dist/index.cjs +2673 -1
  11. package/dist/index.mjs +2657 -1
  12. package/dist/lib/index.cjs +2674 -1
  13. package/dist/lib/index.js +1 -1
  14. package/dist/lib/index.mjs +2659 -1
  15. package/dist/lib/observable/index.cjs +386 -1
  16. package/dist/lib/observable/index.mjs +364 -1
  17. package/dist/lib/observable/observable.cjs +384 -1
  18. package/dist/lib/observable/observable.d.ts +0 -137
  19. package/dist/lib/observable/observable.d.ts.map +1 -1
  20. package/dist/lib/observable/observable.js +0 -71
  21. package/dist/lib/observable/observable.mjs +361 -1
  22. package/dist/lib/observable/subscription.cjs +180 -1
  23. package/dist/lib/observable/subscription.d.ts +0 -12
  24. package/dist/lib/observable/subscription.d.ts.map +1 -1
  25. package/dist/lib/observable/subscription.js +0 -12
  26. package/dist/lib/observable/subscription.mjs +157 -1
  27. package/dist/lib/observable/types.cjs +18 -1
  28. package/dist/lib/observable/types.d.ts.map +1 -1
  29. package/dist/lib/predicates.cjs +44 -1
  30. package/dist/lib/predicates.d.ts +2 -2
  31. package/dist/lib/predicates.js +2 -2
  32. package/dist/lib/predicates.mjs +23 -1
  33. package/dist/lib/signal/api.cjs +571 -1
  34. package/dist/lib/signal/api.d.ts +211 -1
  35. package/dist/lib/signal/api.d.ts.map +1 -1
  36. package/dist/lib/signal/api.js +207 -12
  37. package/dist/lib/signal/api.mjs +548 -1
  38. package/dist/lib/signal/cached-resource.cjs +672 -1
  39. package/dist/lib/signal/cached-resource.d.ts +28 -16
  40. package/dist/lib/signal/cached-resource.d.ts.map +1 -1
  41. package/dist/lib/signal/cached-resource.js +35 -29
  42. package/dist/lib/signal/cached-resource.mjs +650 -1
  43. package/dist/lib/signal/graph/children.cjs +325 -1
  44. package/dist/lib/signal/graph/children.js +1 -1
  45. package/dist/lib/signal/graph/children.mjs +302 -1
  46. package/dist/lib/signal/graph/compat.cjs +578 -1
  47. package/dist/lib/signal/graph/compat.d.ts +13 -13
  48. package/dist/lib/signal/graph/compat.d.ts.map +1 -1
  49. package/dist/lib/signal/graph/compat.js +51 -32
  50. package/dist/lib/signal/graph/compat.mjs +556 -1
  51. package/dist/lib/signal/graph/core.cjs +295 -1
  52. package/dist/lib/signal/graph/core.d.ts +28 -24
  53. package/dist/lib/signal/graph/core.d.ts.map +1 -1
  54. package/dist/lib/signal/graph/core.js +45 -31
  55. package/dist/lib/signal/graph/core.mjs +273 -1
  56. package/dist/lib/signal/graph/debounced.cjs +668 -1
  57. package/dist/lib/signal/graph/debounced.d.ts +5 -5
  58. package/dist/lib/signal/graph/debounced.d.ts.map +1 -1
  59. package/dist/lib/signal/graph/debounced.js +5 -5
  60. package/dist/lib/signal/graph/debounced.mjs +645 -1
  61. package/dist/lib/signal/graph/derived.cjs +496 -1
  62. package/dist/lib/signal/graph/derived.d.ts +1 -1
  63. package/dist/lib/signal/graph/derived.js +1 -1
  64. package/dist/lib/signal/graph/derived.mjs +473 -1
  65. package/dist/lib/signal/graph/detect.cjs +66 -1
  66. package/dist/lib/signal/graph/detect.mjs +45 -1
  67. package/dist/lib/signal/graph/error-boundary.cjs +301 -1
  68. package/dist/lib/signal/graph/error-boundary.js +3 -3
  69. package/dist/lib/signal/graph/error-boundary.mjs +278 -1
  70. package/dist/lib/signal/graph/index.cjs +305 -1
  71. package/dist/lib/signal/graph/index.d.ts +7 -6
  72. package/dist/lib/signal/graph/index.d.ts.map +1 -1
  73. package/dist/lib/signal/graph/index.js +7 -6
  74. package/dist/lib/signal/graph/index.mjs +283 -1
  75. package/dist/lib/signal/graph/observe.cjs +163 -0
  76. package/dist/lib/signal/graph/observe.d.ts +141 -0
  77. package/dist/lib/signal/graph/observe.d.ts.map +1 -0
  78. package/dist/lib/signal/graph/observe.js +149 -0
  79. package/dist/lib/signal/graph/observe.mjs +140 -0
  80. package/dist/lib/signal/graph/resource.cjs +620 -1
  81. package/dist/lib/signal/graph/resource.d.ts +1 -1
  82. package/dist/lib/signal/graph/resource.js +7 -8
  83. package/dist/lib/signal/graph/resource.mjs +597 -1
  84. package/dist/lib/signal/graph/runtime.cjs +501 -1
  85. package/dist/lib/signal/graph/runtime.d.ts +9 -9
  86. package/dist/lib/signal/graph/runtime.d.ts.map +1 -1
  87. package/dist/lib/signal/graph/runtime.js +56 -37
  88. package/dist/lib/signal/graph/runtime.mjs +478 -1
  89. package/dist/lib/signal/graph/signal-next.cjs +1208 -1
  90. package/dist/lib/signal/graph/signal-next.d.ts +5 -5
  91. package/dist/lib/signal/graph/signal-next.d.ts.map +1 -1
  92. package/dist/lib/signal/graph/signal-next.js +14 -12
  93. package/dist/lib/signal/graph/signal-next.mjs +1186 -1
  94. package/dist/lib/signal/graph/ssr-hooks.cjs +60 -1
  95. package/dist/lib/signal/graph/ssr-hooks.d.ts +6 -7
  96. package/dist/lib/signal/graph/ssr-hooks.d.ts.map +1 -1
  97. package/dist/lib/signal/graph/ssr-hooks.js +6 -7
  98. package/dist/lib/signal/graph/ssr-hooks.mjs +39 -1
  99. package/dist/lib/signal/graph/state.cjs +72 -1
  100. package/dist/lib/signal/graph/state.d.ts +43 -10
  101. package/dist/lib/signal/graph/state.d.ts.map +1 -1
  102. package/dist/lib/signal/graph/state.js +83 -21
  103. package/dist/lib/signal/graph/state.mjs +49 -1
  104. package/dist/lib/signal/graph/suspense.cjs +301 -1
  105. package/dist/lib/signal/graph/suspense.js +4 -4
  106. package/dist/lib/signal/graph/suspense.mjs +278 -1
  107. package/dist/lib/signal/index-legacy.cjs +2540 -1
  108. package/dist/lib/signal/index-legacy.d.ts +1 -1
  109. package/dist/lib/signal/index-legacy.js +1 -1
  110. package/dist/lib/signal/index-legacy.mjs +2518 -1
  111. package/dist/lib/signal/index.cjs +1275 -1
  112. package/dist/lib/signal/index.d.ts +5 -2
  113. package/dist/lib/signal/index.d.ts.map +1 -1
  114. package/dist/lib/signal/index.js +8 -3
  115. package/dist/lib/signal/index.mjs +1253 -1
  116. package/dist/lib/signal/list.cjs +549 -1
  117. package/dist/lib/signal/list.d.ts +5 -5
  118. package/dist/lib/signal/list.js +10 -10
  119. package/dist/lib/signal/list.mjs +526 -1
  120. package/dist/lib/signal/resource-api.cjs +626 -1
  121. package/dist/lib/signal/resource-api.d.ts +5 -5
  122. package/dist/lib/signal/resource-api.js +5 -5
  123. package/dist/lib/signal/resource-api.mjs +603 -1
  124. package/dist/lib/signal/signal.cjs +2023 -1
  125. package/dist/lib/signal/signal.d.ts +4 -4
  126. package/dist/lib/signal/signal.d.ts.map +1 -1
  127. package/dist/lib/signal/signal.js +22 -23
  128. package/dist/lib/signal/signal.mjs +2000 -1
  129. package/dist/lib/signal/types.cjs +38 -1
  130. package/dist/lib/signal/types.d.ts.map +1 -1
  131. package/dist/lib/signal/types.js +2 -2
  132. package/dist/lib/signal/types.mjs +17 -1
  133. package/dist/lib/signal/utilities.cjs +1012 -1
  134. package/dist/lib/signal/utilities.d.ts +0 -108
  135. package/dist/lib/signal/utilities.d.ts.map +1 -1
  136. package/dist/lib/signal/utilities.js +0 -158
  137. package/dist/lib/signal/utilities.mjs +990 -1
  138. package/dist/lib/store/api.cjs +612 -1
  139. package/dist/lib/store/api.d.ts +33 -0
  140. package/dist/lib/store/api.d.ts.map +1 -1
  141. package/dist/lib/store/api.js +41 -8
  142. package/dist/lib/store/api.mjs +596 -1
  143. package/dist/lib/store/index.cjs +691 -1
  144. package/dist/lib/store/index.js +1 -1
  145. package/dist/lib/store/index.mjs +676 -1
  146. package/dist/lib/store/setter.types.cjs +18 -1
  147. package/dist/lib/store/setter.types.d.ts +43 -3
  148. package/dist/lib/store/setter.types.d.ts.map +1 -1
  149. package/dist/lib/store/store.cjs +658 -1
  150. package/dist/lib/store/store.d.ts +72 -0
  151. package/dist/lib/store/store.d.ts.map +1 -1
  152. package/dist/lib/store/store.js +294 -11
  153. package/dist/lib/store/store.mjs +644 -1
  154. package/dist/lib/store/types.cjs +18 -1
  155. package/dist/lib/store/types.d.ts +1 -1
  156. package/dist/lib/store/types.d.ts.map +1 -1
  157. package/dist/lib/store/utils.cjs +43 -1
  158. package/dist/lib/store/utils.d.ts +1 -1
  159. package/dist/lib/store/utils.js +1 -1
  160. package/dist/lib/store/utils.mjs +22 -1
  161. package/dist/lib/subject.cjs +450 -1
  162. package/dist/lib/subject.js +3 -91
  163. package/dist/lib/subject.mjs +427 -1
  164. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  165. package/dist/version.generated.cjs +27 -1
  166. package/dist/version.generated.d.ts +1 -1
  167. package/dist/version.generated.js +2 -2
  168. package/dist/version.generated.mjs +7 -1
  169. package/package.json +5 -4
@@ -37,10 +37,82 @@ declare class Store<T> {
37
37
  splice(path: string, start: number, deleteCount: number, ...items: any[]): any[];
38
38
  insert(path: string, index: number, value: any): void;
39
39
  removeAt(path: string, index: number): any[];
40
+ /**
41
+ * Swap a whole value, rather than merging into it.
42
+ *
43
+ * `set(partial)` merges per key, which is what you want for an object and never what
44
+ * you want for an array. This replaces: `replace(value)` at the root, or
45
+ * `replace(path, value)` further down.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const [items, set] = createStore([1, 2, 3]);
50
+ * set.replace([]); // now empty
51
+ * set.replace(['a', 'b']); // now two entries
52
+ * ```
53
+ */
54
+ replace(pathOrValue: any, maybeValue?: any): void;
55
+ /**
56
+ * Empty an array, at the root or at a path.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * set.clear(); // the root array
61
+ * set.clear('todos'); // a nested one
62
+ * ```
63
+ */
64
+ clear(path?: string): void;
40
65
  toObservable(): Observable<T>;
41
66
  dispose(): void;
42
67
  }
68
+ /**
69
+ * A fine-grained reactive store: a plain object tree that tracks reads per key.
70
+ *
71
+ * Returns the state and its setter as a tuple. The state is a proxy, so reading a
72
+ * property subscribes the current computation to that property alone, and a write
73
+ * elsewhere in the tree does not disturb it. Signals are created lazily, one per key
74
+ * that something actually reads, so the cost follows what the app looks at rather than
75
+ * the size of the state.
76
+ *
77
+ * The state is immutable from the outside by default, assigning to it does nothing, and
78
+ * `set` is the way in. That is what makes the tracking trustworthy, since every change
79
+ * goes through a path the store can see.
80
+ *
81
+ * `store()` wraps this as a single binding for the common case. Prefer it unless the
82
+ * state has a `set` key of its own, which the single-binding form cannot express.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const [state, setState] = createStore({ user: { name: 'Ada' }, count: 0 });
87
+ *
88
+ * effect(() => console.log(state.user.name)); // tracks user.name only
89
+ * setState('count', 1); // the effect does not re-run
90
+ * setState('user.name', 'Grace'); // now it does
91
+ * ```
92
+ *
93
+ * @example A patch merges the keys it names; a dot path reaches through arrays:
94
+ * ```ts
95
+ * setState({ count: 5 }); // user is untouched
96
+ * setState('todos.0.done', true);
97
+ * setState('count', (n) => n + 1); // or derive from the current value
98
+ * ```
99
+ */
43
100
  declare function createStore<T>(initialState: T, options?: StoreOptions<T>): [Immutable<T>, Store<T>['set']];
101
+ /**
102
+ * A store you assign to directly, without a setter.
103
+ *
104
+ * The same per-key tracking as `createStore`, with the immutability dropped, so
105
+ * `state.count = 1` is a tracked write. Reach for it when the state is local to one
106
+ * component and the indirection of a setter buys nothing. The cost is that a change
107
+ * can come from anywhere holding the object.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * const state = createMutableStore({ count: 0 });
112
+ * effect(() => console.log(state.count));
113
+ * state.count = 1; // the effect re-runs
114
+ * ```
115
+ */
44
116
  declare function createMutableStore<T>(initialState: T, options?: Omit<StoreOptions<T>, 'immutable'>): Store<T>;
45
117
  /** A store whose state is derived from a reactive function. */
46
118
  declare function createComputedStore<T>(fn: () => T, options?: StoreOptions<T>): Store<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lib/store/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lib/store/store.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,63 @@
1
1
  import { $PROXY, batch, createEffect, createMemo, createSignal, untrack, } from '@fluixi/reactive/signal';
2
+ import { isObserved, reportReactiveDispose, reportReactiveMove, reportReactiveNode, withReactiveOrigin, } from '../signal/graph/observe.js';
2
3
  export const $RAW = Symbol('store-raw'), $NODE = Symbol('store-node'), $HAS = Symbol('store-has'), $SELF = Symbol('store-self'), $TRACK = Symbol('store-track'), $NAME = Symbol('store-name'), $STORE = Symbol('store-store');
3
4
  const NODES = new WeakMap();
4
5
  const PROXIES = new WeakMap();
5
- function createDataNode(initial) {
6
- const [get, set] = createSignal(initial);
6
+ const OWNERS = new WeakMap();
7
+ /** Every tracked object back to the state it belongs to, for deciding what is still in use. */
8
+ const ROOTS = new WeakMap();
9
+ /**
10
+ * Say goodbye to the signals of an object a write replaced.
11
+ *
12
+ * `set('items', [...items, one])` drops the old array but keeps the objects in it, so what
13
+ * is still reachable from the state keeps its nodes and only the rest is let go. Without
14
+ * this a watcher accumulates a card per key of every array a list ever had.
15
+ *
16
+ * Only when something is watching: this walks the state, and nothing else needs it.
17
+ */
18
+ function forgetReplaced(dead, state) {
19
+ if (!isTrackable(dead) || !isObserved())
20
+ return;
21
+ const alive = new Set();
22
+ const keep = (value) => {
23
+ if (!isTrackable(value) || alive.has(value))
24
+ return;
25
+ alive.add(value);
26
+ for (const child of Object.values(value))
27
+ keep(child);
28
+ };
29
+ keep(ROOTS.get(state) ?? state);
30
+ const seen = new Set();
31
+ const drop = (value) => {
32
+ if (!isTrackable(value))
33
+ return;
34
+ const target = value;
35
+ if (alive.has(target) || seen.has(target))
36
+ return;
37
+ seen.add(target);
38
+ const ns = NODES.get(target);
39
+ if (ns) {
40
+ for (const node of ns.keys.values())
41
+ reportReactiveDispose(node);
42
+ if (ns.all)
43
+ reportReactiveDispose(ns.all);
44
+ NODES.delete(target);
45
+ OWNERS.delete(target);
46
+ PROXIES.delete(target);
47
+ }
48
+ for (const child of Object.values(target))
49
+ drop(child);
50
+ };
51
+ drop(dead);
52
+ }
53
+ const pathOf = (base, key, array) => array ? `${base}[${String(key)}]` : `${base}.${String(key)}`;
54
+ function createDataNode(initial, ns, key) {
55
+ // A key signal is made the first time something reads it, which can be anywhere. Named and
56
+ // attributed to the object it belongs to, so a graph shows it under that object at the
57
+ // line the store was declared rather than wherever it was first read.
58
+ const owner = ns?.owner;
59
+ const label = owner && key !== undefined ? pathOf(owner.name, key, ns?.array) : undefined;
60
+ const [get, set] = withReactiveOrigin(owner?.store, () => createSignal(initial, label ? { name: label } : undefined));
7
61
  const node = get;
8
62
  node.$ = set;
9
63
  return node;
@@ -11,18 +65,52 @@ function createDataNode(initial) {
11
65
  function nodesOf(target) {
12
66
  let ns = NODES.get(target);
13
67
  if (!ns)
14
- NODES.set(target, (ns = { keys: new Map() }));
68
+ NODES.set(target, (ns = { keys: new Map(), owner: OWNERS.get(target), array: Array.isArray(target) }));
69
+ // An object can be reached before the store has claimed it, a write touches it, or it is
70
+ // read through something other than its parent's proxy. Caching "no owner" there would
71
+ // leave every key signal it ever makes unnamed and unattached.
72
+ else if (!ns.owner)
73
+ ns.owner = OWNERS.get(target);
15
74
  return ns;
16
75
  }
17
76
  function keyNode(ns, key, seed) {
18
77
  let node = ns.keys.get(key);
19
78
  if (!node)
20
- ns.keys.set(key, (node = createDataNode(seed)));
79
+ ns.keys.set(key, (node = createDataNode(seed, ns, key)));
21
80
  return node;
22
81
  }
82
+ /**
83
+ * Say where an object now sits in the state.
84
+ *
85
+ * A write that replaces a container leaves the objects inside it where they were, holding
86
+ * the same signals, under a new key signal. Re-claiming moves those signals across so they
87
+ * stay attached to the object they describe instead of to the node that used to hold it.
88
+ */
89
+ function claim(target, holder, name, parent) {
90
+ const was = OWNERS.get(target);
91
+ if (was && was.store === holder && was.name === name)
92
+ return;
93
+ const owner = { store: holder, name };
94
+ OWNERS.set(target, owner);
95
+ ROOTS.set(target, ROOTS.get(parent) ?? parent);
96
+ // It may already have a node store, from an earlier read or an earlier position.
97
+ const ns = NODES.get(target);
98
+ if (!ns)
99
+ return;
100
+ ns.owner = owner;
101
+ if (!isObserved())
102
+ return;
103
+ for (const [key, node] of ns.keys)
104
+ reportReactiveMove(node, holder, pathOf(name, key, ns.array));
105
+ if (ns.all)
106
+ reportReactiveMove(ns.all, holder, pathOf(name, '*', ns.array));
107
+ }
23
108
  function trackKeys(target) {
24
109
  const ns = nodesOf(target);
25
- (ns.all || (ns.all = createDataNode()))();
110
+ // Which keys exist, as opposed to what any one of them holds. It has no value of its own,
111
+ // so a graph would otherwise show an unexplained empty node the first time a list is
112
+ // iterated, which is exactly when one appears.
113
+ (ns.all || (ns.all = createDataNode(undefined, ns, '*')))();
26
114
  }
27
115
  // The signal setter reads a function argument as an updater, so a function value
28
116
  // has to be handed over wrapped.
@@ -73,8 +161,16 @@ const handler = {
73
161
  const desc = Object.getOwnPropertyDescriptor(target, key);
74
162
  if (desc && desc.get)
75
163
  return desc.get.call(receiver);
76
- const current = keyNode(nodesOf(target), key, value)();
77
- return isTrackable(current) ? box(current) : current;
164
+ const ns = nodesOf(target);
165
+ const holder = keyNode(ns, key, value);
166
+ const current = holder();
167
+ if (!isTrackable(current))
168
+ return current;
169
+ // A nested object hangs off the signal that holds it, not off the store, so a cart with
170
+ // three items reads as three objects rather than as a dozen loose keys.
171
+ if (ns.owner)
172
+ claim(current, holder, pathOf(ns.owner.name, key, ns.array), target);
173
+ return box(current);
78
174
  },
79
175
  set() {
80
176
  // The proxy is read-only; writes come in through the setter.
@@ -107,7 +203,38 @@ const handler = {
107
203
  // writes
108
204
  // Writes one key on a raw node and pokes what changed: the key's own signal, the
109
205
  // array length signal when the length moved, and the iteration signal.
110
- function writeKey(state, key, value) {
206
+ /**
207
+ * The raw form of a value on its way into the state.
208
+ *
209
+ * `set({ items: [...cart.items, one] })` spreads proxies back in, and a store that holds its
210
+ * own proxies tracks each of them twice: a second node store per object, a proxy wrapping a
211
+ * proxy, and a graph with two signals for every key.
212
+ */
213
+ function rawValue(value, seen = new Set()) {
214
+ if (value == null || typeof value !== 'object')
215
+ return value;
216
+ const raw = value[$RAW] ?? value;
217
+ if (seen.has(raw) || !isTrackable(raw))
218
+ return raw;
219
+ seen.add(raw);
220
+ let changed = false;
221
+ const swap = (v) => {
222
+ const next = rawValue(v, seen);
223
+ if (next !== v)
224
+ changed = true;
225
+ return next;
226
+ };
227
+ if (Array.isArray(raw)) {
228
+ const out = raw.map(swap);
229
+ return changed ? out : raw;
230
+ }
231
+ const out = {};
232
+ for (const k of Object.keys(raw))
233
+ out[k] = swap(raw[k]);
234
+ return changed ? out : raw;
235
+ }
236
+ function writeKey(state, key, rawInput) {
237
+ const value = rawValue(rawInput);
111
238
  const prev = state[key];
112
239
  if (prev === value && (value !== undefined || key in state))
113
240
  return;
@@ -121,6 +248,7 @@ function writeKey(state, key, value) {
121
248
  const node = ns.keys.get(key);
122
249
  if (node)
123
250
  pokeNode(node, value);
251
+ forgetReplaced(prev, state);
124
252
  if (isArray && state.length !== len) {
125
253
  const lengthNode = ns.keys.get('length');
126
254
  if (lengthNode)
@@ -189,6 +317,36 @@ function applyAt(current, segs, value) {
189
317
  function applyPath(root, path, value) {
190
318
  applyAt(root, parsePath(path), value);
191
319
  }
320
+ /**
321
+ * Whether a lone array argument is a batch of `[path, value]` pairs.
322
+ *
323
+ * The batch form and a replacement array are the same shape at the call site, so the
324
+ * entries decide. Every one has to be a pair with a string path; anything else is a
325
+ * value. An empty array is not a batch, which is what made `set([])` on an array root
326
+ * do nothing at all.
327
+ */
328
+ function isPathBatch(value) {
329
+ return (Array.isArray(value) &&
330
+ value.length > 0 &&
331
+ value.every((e) => Array.isArray(e) && e.length >= 2 && typeof e[0] === 'string'));
332
+ }
333
+ /**
334
+ * Replace an array's contents in place, keeping its identity.
335
+ *
336
+ * The tail is written away before the length moves, so an index that had a signal is
337
+ * told it is gone. Assigning `length` alone truncates without notifying anyone, which
338
+ * leaves a stale read behind on every removed index.
339
+ */
340
+ function replaceArray(target, next) {
341
+ // Keys are strings everywhere else, because every other path reaches writeKey through
342
+ // parsePath. A numeric key here would miss the node the proxy registered under '2'.
343
+ for (let i = target.length - 1; i >= next.length; i--)
344
+ writeKey(target, String(i), undefined);
345
+ if (target.length !== next.length)
346
+ writeKey(target, 'length', next.length);
347
+ for (let i = 0; i < next.length; i++)
348
+ writeKey(target, String(i), next[i]);
349
+ }
192
350
  /**
193
351
  * Runs the setter overloads against the raw root:
194
352
  * set(state => newState) whole-state updater, merged back
@@ -206,10 +364,22 @@ function applySet(root, args) {
206
364
  return;
207
365
  }
208
366
  if (Array.isArray(first) && args.length === 1) {
209
- for (const entry of first)
210
- if (Array.isArray(entry))
367
+ if (isPathBatch(first)) {
368
+ for (const entry of first)
211
369
  applyPath(root, entry[0], entry[1]);
212
- return;
370
+ return;
371
+ }
372
+ // Not a batch, so it is a value. Against an array root that is a replacement.
373
+ if (Array.isArray(root)) {
374
+ replaceArray(root, first);
375
+ return;
376
+ }
377
+ // An empty array asks for no updates, which is harmless either way.
378
+ if (first.length === 0)
379
+ return;
380
+ throw new TypeError('[fluixi] set() was given an array that is neither a batch of [path, value] ' +
381
+ 'pairs nor a replacement for an array root. Name the path you meant, as in ' +
382
+ "set('items', [...]).");
213
383
  }
214
384
  if (first &&
215
385
  typeof first === 'object' &&
@@ -254,6 +424,18 @@ class Store {
254
424
  this.options = options;
255
425
  this.root = initialState;
256
426
  this.set = ((...args) => batch(() => applySet(this.root, args)));
427
+ if (initialState && typeof initialState === 'object') {
428
+ OWNERS.set(initialState, { store: this, name: options.name ?? 'store' });
429
+ ROOTS.set(initialState, initialState);
430
+ }
431
+ // One node for the store itself, so the line that declared it is in the graph even
432
+ // though its key signals are not made until something reads them.
433
+ reportReactiveNode({
434
+ kind: 'store',
435
+ node: this,
436
+ handle: () => this.root,
437
+ name: options.name,
438
+ });
257
439
  }
258
440
  get state() {
259
441
  return box(this.root);
@@ -345,6 +527,58 @@ class Store {
345
527
  this.set(path, arr);
346
528
  return removed;
347
529
  }
530
+ /**
531
+ * Swap a whole value, rather than merging into it.
532
+ *
533
+ * `set(partial)` merges per key, which is what you want for an object and never what
534
+ * you want for an array. This replaces: `replace(value)` at the root, or
535
+ * `replace(path, value)` further down.
536
+ *
537
+ * @example
538
+ * ```ts
539
+ * const [items, set] = createStore([1, 2, 3]);
540
+ * set.replace([]); // now empty
541
+ * set.replace(['a', 'b']); // now two entries
542
+ * ```
543
+ */
544
+ replace(pathOrValue, maybeValue) {
545
+ if (arguments.length >= 2) {
546
+ const target = rawAt(this.root, String(pathOrValue));
547
+ const next = maybeValue;
548
+ if (Array.isArray(target) && Array.isArray(next)) {
549
+ replaceArray(target, next);
550
+ return;
551
+ }
552
+ this.set(pathOrValue, next);
553
+ return;
554
+ }
555
+ const root = this.root;
556
+ if (Array.isArray(root) && Array.isArray(pathOrValue)) {
557
+ replaceArray(root, pathOrValue);
558
+ return;
559
+ }
560
+ this.set(pathOrValue);
561
+ }
562
+ /**
563
+ * Empty an array, at the root or at a path.
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * set.clear(); // the root array
568
+ * set.clear('todos'); // a nested one
569
+ * ```
570
+ */
571
+ clear(path) {
572
+ const target = path === undefined ? this.root : rawAt(this.root, path);
573
+ if (Array.isArray(target)) {
574
+ replaceArray(target, []);
575
+ return;
576
+ }
577
+ if (target && typeof target === 'object') {
578
+ for (const key of Object.keys(target))
579
+ writeKey(target, key, undefined);
580
+ }
581
+ }
348
582
  toObservable() {
349
583
  const [get] = createSignal(this.state);
350
584
  return get.toObservable();
@@ -366,6 +600,8 @@ const SETTER_METHODS = [
366
600
  'splice',
367
601
  'insert',
368
602
  'removeAt',
603
+ 'replace',
604
+ 'clear',
369
605
  'unwrap',
370
606
  'toObservable',
371
607
  ];
@@ -375,11 +611,58 @@ function attachStoreMethods(target, store) {
375
611
  target.$ = store.reactive.bind(store);
376
612
  }
377
613
  // public api
614
+ /**
615
+ * A fine-grained reactive store: a plain object tree that tracks reads per key.
616
+ *
617
+ * Returns the state and its setter as a tuple. The state is a proxy, so reading a
618
+ * property subscribes the current computation to that property alone, and a write
619
+ * elsewhere in the tree does not disturb it. Signals are created lazily, one per key
620
+ * that something actually reads, so the cost follows what the app looks at rather than
621
+ * the size of the state.
622
+ *
623
+ * The state is immutable from the outside by default, assigning to it does nothing, and
624
+ * `set` is the way in. That is what makes the tracking trustworthy, since every change
625
+ * goes through a path the store can see.
626
+ *
627
+ * `store()` wraps this as a single binding for the common case. Prefer it unless the
628
+ * state has a `set` key of its own, which the single-binding form cannot express.
629
+ *
630
+ * @example
631
+ * ```ts
632
+ * const [state, setState] = createStore({ user: { name: 'Ada' }, count: 0 });
633
+ *
634
+ * effect(() => console.log(state.user.name)); // tracks user.name only
635
+ * setState('count', 1); // the effect does not re-run
636
+ * setState('user.name', 'Grace'); // now it does
637
+ * ```
638
+ *
639
+ * @example A patch merges the keys it names; a dot path reaches through arrays:
640
+ * ```ts
641
+ * setState({ count: 5 }); // user is untouched
642
+ * setState('todos.0.done', true);
643
+ * setState('count', (n) => n + 1); // or derive from the current value
644
+ * ```
645
+ */
378
646
  function createStore(initialState, options = { immutable: true }) {
379
647
  const store = new Store(initialState, options);
380
648
  attachStoreMethods(store.set, store);
381
649
  return [store.proxy, store.set];
382
650
  }
651
+ /**
652
+ * A store you assign to directly, without a setter.
653
+ *
654
+ * The same per-key tracking as `createStore`, with the immutability dropped, so
655
+ * `state.count = 1` is a tracked write. Reach for it when the state is local to one
656
+ * component and the indirection of a setter buys nothing. The cost is that a change
657
+ * can come from anywhere holding the object.
658
+ *
659
+ * @example
660
+ * ```ts
661
+ * const state = createMutableStore({ count: 0 });
662
+ * effect(() => console.log(state.count));
663
+ * state.count = 1; // the effect re-runs
664
+ * ```
665
+ */
383
666
  function createMutableStore(initialState, options = {}) {
384
667
  return new Store(initialState, { ...options, immutable: false });
385
668
  }