sigmx 0.1.1 → 0.2.0

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 (165) hide show
  1. package/README.md +10 -10
  2. package/dist/kernel/compile.d.ts +8 -9
  3. package/dist/kernel/compile.js +102 -67
  4. package/dist/kernel/compile.js.map +2 -2
  5. package/dist/kernel/contracts.d.ts +11 -5
  6. package/dist/kernel/index.d.ts +2 -2
  7. package/dist/kernel/index.js +5 -6
  8. package/dist/kernel/index.js.map +2 -2
  9. package/dist/kernel/precompile.d.ts +8 -10
  10. package/dist/kernel/precompile.js +25 -75
  11. package/dist/kernel/precompile.js.map +2 -2
  12. package/dist/kernel/precompiled.d.ts +7 -4
  13. package/dist/kernel/precompiled.js +5 -5
  14. package/dist/kernel/precompiled.js.map +2 -2
  15. package/dist/kernel/reactive.d.ts +8 -2
  16. package/dist/kernel/reactive.js +91 -62
  17. package/dist/kernel/reactive.js.map +3 -3
  18. package/dist/kernel/runtime.js +78 -68
  19. package/dist/kernel/runtime.js.map +3 -3
  20. package/dist/kernel/scan.d.ts +1 -1
  21. package/dist/kernel/scan.js +3 -3
  22. package/dist/kernel/scan.js.map +2 -2
  23. package/dist/kernel/state.d.ts +4 -3
  24. package/dist/kernel/state.js +91 -80
  25. package/dist/kernel/state.js.map +2 -2
  26. package/dist/kernel/strict-csp.d.ts +0 -5
  27. package/dist/kernel/strict-csp.js +2 -2
  28. package/dist/kernel/strict-csp.js.map +2 -2
  29. package/dist/lib/casing.d.ts +4 -1
  30. package/dist/lib/casing.js +8 -1
  31. package/dist/lib/casing.js.map +2 -2
  32. package/dist/lib/objects.d.ts +5 -3
  33. package/dist/lib/objects.js +10 -5
  34. package/dist/lib/objects.js.map +2 -2
  35. package/dist/lib/schedule.d.ts +3 -3
  36. package/dist/lib/schedule.js +12 -10
  37. package/dist/lib/schedule.js.map +2 -2
  38. package/dist/lib/sse.d.ts +10 -0
  39. package/dist/lib/sse.js +32 -29
  40. package/dist/lib/sse.js.map +2 -2
  41. package/dist/plugins/def.d.ts +5 -0
  42. package/dist/plugins/def.js +22 -0
  43. package/dist/plugins/def.js.map +7 -0
  44. package/dist/plugins/directives/attribute-sync.js +8 -12
  45. package/dist/plugins/directives/attribute-sync.js.map +2 -2
  46. package/dist/plugins/directives/boost.d.ts +1 -1
  47. package/dist/plugins/directives/boost.js +34 -31
  48. package/dist/plugins/directives/boost.js.map +2 -2
  49. package/dist/plugins/directives/busy-flag.js +13 -16
  50. package/dist/plugins/directives/busy-flag.js.map +2 -2
  51. package/dist/plugins/directives/class-toggle.js +17 -16
  52. package/dist/plugins/directives/class-toggle.js.map +2 -2
  53. package/dist/plugins/directives/cloak.js +2 -7
  54. package/dist/plugins/directives/cloak.js.map +2 -2
  55. package/dist/plugins/directives/collapse.js +36 -37
  56. package/dist/plugins/directives/collapse.js.map +2 -2
  57. package/dist/plugins/directives/declare.js +5 -8
  58. package/dist/plugins/directives/declare.js.map +2 -2
  59. package/dist/plugins/directives/derive.js +9 -18
  60. package/dist/plugins/directives/derive.js.map +2 -2
  61. package/dist/plugins/directives/element-ref.js +8 -8
  62. package/dist/plugins/directives/element-ref.js.map +2 -2
  63. package/dist/plugins/directives/event-listener.js +18 -26
  64. package/dist/plugins/directives/event-listener.js.map +2 -2
  65. package/dist/plugins/directives/frame-loop.js +9 -14
  66. package/dist/plugins/directives/frame-loop.js.map +2 -2
  67. package/dist/plugins/directives/html.js +6 -7
  68. package/dist/plugins/directives/html.js.map +2 -2
  69. package/dist/plugins/directives/inline-style.js +17 -20
  70. package/dist/plugins/directives/inline-style.js.map +2 -2
  71. package/dist/plugins/directives/mask.js +19 -23
  72. package/dist/plugins/directives/mask.js.map +2 -2
  73. package/dist/plugins/directives/media-query.d.ts +4 -1
  74. package/dist/plugins/directives/media-query.js +13 -13
  75. package/dist/plugins/directives/media-query.js.map +2 -2
  76. package/dist/plugins/directives/on-mount.js +4 -12
  77. package/dist/plugins/directives/on-mount.js.map +2 -2
  78. package/dist/plugins/directives/patch-listener.js +24 -19
  79. package/dist/plugins/directives/patch-listener.js.map +2 -2
  80. package/dist/plugins/directives/remove-me.js +7 -8
  81. package/dist/plugins/directives/remove-me.js.map +2 -2
  82. package/dist/plugins/directives/scroll-to.d.ts +4 -1
  83. package/dist/plugins/directives/scroll-to.js +8 -14
  84. package/dist/plugins/directives/scroll-to.js.map +2 -2
  85. package/dist/plugins/directives/size-watch.js +7 -12
  86. package/dist/plugins/directives/size-watch.js.map +2 -2
  87. package/dist/plugins/directives/state-dump.js +6 -10
  88. package/dist/plugins/directives/state-dump.js.map +2 -2
  89. package/dist/plugins/directives/storage-sync.js +13 -9
  90. package/dist/plugins/directives/storage-sync.js.map +2 -2
  91. package/dist/plugins/directives/teleport.js +8 -14
  92. package/dist/plugins/directives/teleport.js.map +2 -2
  93. package/dist/plugins/directives/text-content.js +6 -7
  94. package/dist/plugins/directives/text-content.js.map +2 -2
  95. package/dist/plugins/directives/timer.js +7 -13
  96. package/dist/plugins/directives/timer.js.map +2 -2
  97. package/dist/plugins/directives/transition.d.ts +1 -2
  98. package/dist/plugins/directives/transition.js +32 -34
  99. package/dist/plugins/directives/transition.js.map +2 -2
  100. package/dist/plugins/directives/tween.d.ts +2 -2
  101. package/dist/plugins/directives/tween.js +34 -50
  102. package/dist/plugins/directives/tween.js.map +2 -2
  103. package/dist/plugins/directives/two-way-bind.d.ts +1 -1
  104. package/dist/plugins/directives/two-way-bind.js +70 -97
  105. package/dist/plugins/directives/two-way-bind.js.map +2 -2
  106. package/dist/plugins/directives/url-params.js +35 -59
  107. package/dist/plugins/directives/url-params.js.map +3 -3
  108. package/dist/plugins/directives/url-replace.js +6 -7
  109. package/dist/plugins/directives/url-replace.js.map +2 -2
  110. package/dist/plugins/directives/validity.js +6 -9
  111. package/dist/plugins/directives/validity.js.map +2 -2
  112. package/dist/plugins/directives/viewport.js +18 -26
  113. package/dist/plugins/directives/viewport.js.map +2 -2
  114. package/dist/plugins/directives/visibility.js +9 -14
  115. package/dist/plugins/directives/visibility.js.map +2 -2
  116. package/dist/plugins/directives/watch.js +2 -8
  117. package/dist/plugins/directives/watch.js.map +2 -2
  118. package/dist/plugins/functions/bulk-set.js +7 -6
  119. package/dist/plugins/functions/bulk-set.js.map +2 -2
  120. package/dist/plugins/functions/bulk-toggle.js +7 -6
  121. package/dist/plugins/functions/bulk-toggle.js.map +2 -2
  122. package/dist/plugins/functions/confirm.js +2 -2
  123. package/dist/plugins/functions/confirm.js.map +2 -2
  124. package/dist/plugins/functions/copy-text.js +5 -5
  125. package/dist/plugins/functions/copy-text.js.map +2 -2
  126. package/dist/plugins/functions/dispatch.js +5 -5
  127. package/dist/plugins/functions/dispatch.js.map +2 -2
  128. package/dist/plugins/functions/locale-format.d.ts +4 -1
  129. package/dist/plugins/functions/locale-format.js +9 -16
  130. package/dist/plugins/functions/locale-format.js.map +2 -2
  131. package/dist/plugins/functions/range-map.js +6 -6
  132. package/dist/plugins/functions/range-map.js.map +2 -2
  133. package/dist/plugins/functions/request.d.ts +7 -3
  134. package/dist/plugins/functions/request.js +77 -86
  135. package/dist/plugins/functions/request.js.map +2 -2
  136. package/dist/plugins/functions/untracked-read.js +3 -2
  137. package/dist/plugins/functions/untracked-read.js.map +2 -2
  138. package/dist/plugins/functions/websocket.d.ts +3 -3
  139. package/dist/plugins/functions/websocket.js +13 -24
  140. package/dist/plugins/functions/websocket.js.map +2 -2
  141. package/dist/plugins/index.d.ts +0 -2
  142. package/dist/plugins/index.js +0 -4
  143. package/dist/plugins/index.js.map +2 -2
  144. package/dist/plugins/server-events/apply-elements.d.ts +1 -1
  145. package/dist/plugins/server-events/apply-elements.js +41 -43
  146. package/dist/plugins/server-events/apply-elements.js.map +2 -2
  147. package/dist/plugins/server-events/apply-state.js +9 -12
  148. package/dist/plugins/server-events/apply-state.js.map +2 -2
  149. package/dist/plugins/server-events/morph.js +46 -66
  150. package/dist/plugins/server-events/morph.js.map +3 -3
  151. package/dist/presets/all.js +0 -4
  152. package/dist/presets/all.js.map +2 -2
  153. package/dist/server.d.ts +10 -4
  154. package/dist/server.js +42 -14
  155. package/dist/server.js.map +2 -2
  156. package/dist/sigmx.standalone.js +1 -1
  157. package/dist/vite.js +17 -7
  158. package/dist/vite.js.map +2 -2
  159. package/package.json +4 -2
  160. package/dist/plugins/directives/transition-name.d.ts +0 -1
  161. package/dist/plugins/directives/transition-name.js +0 -11
  162. package/dist/plugins/directives/transition-name.js.map +0 -7
  163. package/dist/plugins/directives/trap.d.ts +0 -5
  164. package/dist/plugins/directives/trap.js +0 -54
  165. package/dist/plugins/directives/trap.js.map +0 -7
@@ -1,10 +1,13 @@
1
- import { expand, isPlain, toPredicate } from "../lib/objects.js";
1
+ import { expand, isPlain, safeKey, toPredicate } from "../lib/objects.js";
2
2
  import { batch, Computed, onSettled, Signal } from "./reactive.js";
3
- const parentOf = (p) => p.slice(0, Math.max(0, p.lastIndexOf(".")));
4
- const nameOf = (p) => p.slice(p.lastIndexOf(".") + 1);
3
+ const split = (p) => {
4
+ const i = p.lastIndexOf(".");
5
+ return [i < 0 ? "" : p.slice(0, i), p.slice(i + 1)];
6
+ };
5
7
  const join = (a, b) => a ? `${a}.${b}` : b;
6
- const under = (p, at) => !at || p === at || p.startsWith(`${at}.`);
8
+ const under = (p, at) => !at || p.startsWith(`${at}.`);
7
9
  const str = (k) => typeof k === "string";
10
+ const rawOf = /* @__PURE__ */ new WeakMap();
8
11
  const createStore = () => {
9
12
  const leaves = /* @__PURE__ */ new Map();
10
13
  const kids = /* @__PURE__ */ new Map([["", /* @__PURE__ */ new Set()]]);
@@ -12,15 +15,24 @@ const createStore = () => {
12
15
  const pending = /* @__PURE__ */ new Map();
13
16
  const listeners = /* @__PURE__ */ new Set();
14
17
  const nsCache = /* @__PURE__ */ new Map();
15
- const arrCache = /* @__PURE__ */ new WeakMap();
18
+ const proxies = /* @__PURE__ */ new WeakMap();
19
+ const link = (p) => {
20
+ const [parent, name] = split(p);
21
+ ensureNs(parent).add(name);
22
+ shape.bump();
23
+ };
24
+ const unlink = (p) => {
25
+ const [parent, name] = split(p);
26
+ kids.get(parent)?.delete(name);
27
+ shape.bump();
28
+ };
16
29
  const ensureNs = (p) => {
17
30
  let set2 = kids.get(p);
18
31
  if (!set2) {
19
32
  if (leaves.has(p)) dropLeaf(p);
20
33
  set2 = /* @__PURE__ */ new Set();
21
34
  kids.set(p, set2);
22
- ensureNs(parentOf(p)).add(nameOf(p));
23
- shape.bump();
35
+ link(p);
24
36
  }
25
37
  return set2;
26
38
  };
@@ -28,10 +40,10 @@ const createStore = () => {
28
40
  const s = leaves.get(p);
29
41
  if (!s) return;
30
42
  leaves.delete(p);
31
- kids.get(parentOf(p))?.delete(nameOf(p));
43
+ unlink(p);
32
44
  pending.set(p, null);
33
45
  s.bump();
34
- shape.bump();
46
+ if (s instanceof Computed) s.dispose();
35
47
  };
36
48
  const dropNs = (p) => {
37
49
  const set2 = kids.get(p);
@@ -39,34 +51,35 @@ const createStore = () => {
39
51
  for (const k of [...set2]) remove(join(p, k));
40
52
  if (p) {
41
53
  kids.delete(p);
42
- kids.get(parentOf(p))?.delete(nameOf(p));
43
54
  nsCache.delete(p);
55
+ unlink(p);
44
56
  }
45
- shape.bump();
46
57
  };
47
58
  const remove = (p) => batch(() => {
48
59
  dropLeaf(p);
49
60
  dropNs(p);
50
61
  });
51
62
  const define = (p, node) => batch(() => {
52
- if (kids.has(p)) dropNs(p);
63
+ dropNs(p);
53
64
  const old = leaves.get(p);
54
65
  leaves.set(p, node);
55
- ensureNs(parentOf(p)).add(nameOf(p));
56
- old?.bump();
57
- shape.bump();
66
+ link(p);
67
+ if (old) {
68
+ old.bump();
69
+ if (old instanceof Computed) old.dispose();
70
+ }
58
71
  });
59
72
  const set = (p, v) => batch(() => {
60
73
  if (v == null) return remove(p);
74
+ v = (v && rawOf.get(v)) ?? v;
61
75
  if (isPlain(v)) {
62
- const names = ensureNs(p);
63
- for (const k of [...names]) if (!(k in v)) remove(join(p, k));
64
- for (const k in v) set(join(p, k), v[k]);
76
+ for (const k of [...ensureNs(p)]) if (!(k in v)) remove(join(p, k));
77
+ for (const k in v) if (safeKey(k)) set(join(p, k), v[k]);
65
78
  return;
66
79
  }
67
- if (kids.has(p)) dropNs(p);
80
+ dropNs(p);
68
81
  const s = leaves.get(p);
69
- if (s instanceof Computed) throw new Error(`"${p}" is a computed signal and cannot be assigned`);
82
+ if (s instanceof Computed) throw new Error(`computed "${p}" is read-only`);
70
83
  if (s) {
71
84
  if (Object.is(s.peek(), v)) return;
72
85
  s.value = v;
@@ -77,41 +90,57 @@ const createStore = () => {
77
90
  });
78
91
  const merge = (patch, { at = "", ifMissing = false } = {}) => batch(() => {
79
92
  if (!isPlain(patch)) return;
80
- ensureNs(at);
81
- for (const k in patch) {
93
+ const keys = Object.keys(patch).filter(safeKey);
94
+ if (keys.length) ensureNs(at);
95
+ for (const k of keys) {
82
96
  const p = join(at, k);
83
97
  const v = patch[k];
98
+ const leaf = leaves.get(p);
99
+ if (leaf && (ifMissing || leaf instanceof Computed)) continue;
84
100
  if (v === null) {
85
101
  if (!ifMissing) remove(p);
86
- } else if (isPlain(v)) {
87
- merge(v, { at: p, ifMissing });
88
- } else if (!(ifMissing && (leaves.has(p) || kids.has(p))) && !(leaves.get(p) instanceof Computed)) {
89
- set(p, v);
90
- }
102
+ } else if (isPlain(v)) merge(v, { at: p, ifMissing });
103
+ else if (!(ifMissing && kids.has(p))) set(p, v);
91
104
  }
92
105
  });
106
+ const has = (p) => leaves.has(p) || kids.has(p);
93
107
  const wrapArray = (raw, s, p) => {
94
- let px = arrCache.get(raw);
95
- if (!px) {
96
- const touch = () => {
97
- pending.set(p, raw);
98
- s.bump();
99
- };
100
- px = new Proxy(raw, {
101
- set: (t, k, v) => {
102
- t[k] = v;
103
- touch();
104
- return true;
105
- },
106
- deleteProperty: (t, k) => {
107
- delete t[k];
108
- touch();
109
- return true;
110
- }
111
- });
112
- arrCache.set(raw, px);
108
+ let cache = proxies.get(s);
109
+ if (!cache) {
110
+ cache = /* @__PURE__ */ new WeakMap();
111
+ proxies.set(s, cache);
113
112
  }
114
- return px;
113
+ const touch = () => {
114
+ pending.set(p, raw);
115
+ s.bump();
116
+ return true;
117
+ };
118
+ const wrap = (target) => {
119
+ let px = cache?.get(target);
120
+ if (!px) {
121
+ px = new Proxy(target, {
122
+ get: (t, k, r) => {
123
+ const v = Reflect.get(t, k, r);
124
+ if (typeof v === "function" && Array.isArray(t)) return (...a) => batch(() => v.apply(r, a));
125
+ if (!v || typeof v !== "object" || !(Array.isArray(v) || isPlain(v))) return v;
126
+ const d = Object.getOwnPropertyDescriptor(t, k);
127
+ return d && !d.configurable && !d.writable ? v : wrap(v);
128
+ },
129
+ set: (t, k, v) => {
130
+ t[k] = (v && rawOf.get(v)) ?? v;
131
+ return touch();
132
+ },
133
+ deleteProperty: (t, k) => {
134
+ delete t[k];
135
+ return touch();
136
+ }
137
+ });
138
+ cache?.set(target, px);
139
+ rawOf.set(px, target);
140
+ }
141
+ return px;
142
+ };
143
+ return wrap(raw);
115
144
  };
116
145
  const get = (p) => {
117
146
  const s = leaves.get(p);
@@ -119,16 +148,15 @@ const createStore = () => {
119
148
  const v = s.value;
120
149
  return Array.isArray(v) ? wrapArray(v, s, p) : v;
121
150
  }
122
- if (kids.has(p)) return ns(p);
123
151
  shape.value;
124
- return void 0;
152
+ if (kids.has(p)) return ns(p);
125
153
  };
126
154
  const ns = (p) => {
127
155
  let px = nsCache.get(p);
128
156
  if (!px) {
129
- const names = () => {
157
+ const names = (k) => {
130
158
  shape.value;
131
- return kids.get(p);
159
+ return str(k) && !!kids.get(p)?.has(k);
132
160
  };
133
161
  px = new Proxy(
134
162
  {},
@@ -142,43 +170,27 @@ const createStore = () => {
142
170
  if (str(k)) remove(join(p, k));
143
171
  return true;
144
172
  },
145
- has: (_, k) => str(k) && !!names()?.has(k),
146
- ownKeys: () => [...names() ?? []],
147
- getOwnPropertyDescriptor: (_, k) => str(k) && names()?.has(k) ? { enumerable: true, configurable: true, writable: true, value: get(join(p, k)) } : void 0
173
+ has: (_, k) => names(k),
174
+ ownKeys: () => {
175
+ shape.value;
176
+ return [...kids.get(p) ?? []];
177
+ },
178
+ getOwnPropertyDescriptor: (_, k) => names(k) ? { enumerable: true, configurable: true, writable: true, value: get(join(p, k)) } : void 0
148
179
  }
149
180
  );
150
181
  nsCache.set(p, px);
151
182
  }
152
183
  return px;
153
184
  };
154
- const scope = new Proxy(
155
- {},
156
- {
157
- has: (_, k) => str(k) && k[0] === "$",
158
- get: (_, k) => !str(k) ? void 0 : k === "$" ? ns("") : get(k.slice(1)),
159
- set: (_, k, v) => {
160
- if (str(k)) k === "$" ? merge(v) : set(k.slice(1), v);
161
- return true;
162
- }
163
- }
164
- );
165
- const paths = (filter) => {
185
+ const paths = (filter, { computed = true } = {}) => {
166
186
  shape.value;
167
187
  const ok = toPredicate(filter);
168
- return [...leaves.keys()].filter(ok);
188
+ return [...leaves].filter(([p, s]) => ok(p) && (computed || !(s instanceof Computed))).map(([p]) => p);
169
189
  };
170
190
  const snapshot = (filter, { at = "", computed = true } = {}) => {
171
- shape.value;
172
- const ok = toPredicate(filter);
173
191
  const out = {};
174
- const rel = (p) => at ? p.slice(at.length + 1) : p;
175
- for (const [p, s] of leaves) {
176
- if (!under(p, at) || !ok(p) || !computed && s instanceof Computed) continue;
177
- expand(out, rel(p), s.value);
178
- }
179
- for (const p of kids.keys()) {
180
- if (p && p !== at && under(p, at) && ok(p) && !kids.get(p)?.size) expand(out, rel(p), {});
181
- }
192
+ for (const p of paths(filter, { computed }))
193
+ if (under(p, at)) expand(out, at ? p.slice(at.length + 1) : p, leaves.get(p)?.value);
182
194
  return out;
183
195
  };
184
196
  onSettled(() => {
@@ -193,7 +205,7 @@ const createStore = () => {
193
205
  set,
194
206
  merge,
195
207
  remove,
196
- has: (p) => leaves.has(p) || kids.has(p),
208
+ has,
197
209
  define,
198
210
  paths,
199
211
  snapshot,
@@ -203,8 +215,7 @@ const createStore = () => {
203
215
  },
204
216
  get $() {
205
217
  return ns("");
206
- },
207
- scope
218
+ }
208
219
  };
209
220
  };
210
221
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/state.ts"],
4
- "sourcesContent": ["import { expand, type Filter, isPlain, toPredicate } from '../lib/objects.js';\nimport { batch, Computed, onSettled, Signal } from './reactive.js';\n\nexport type Patch = Record<string, any>;\n\nexport interface Store {\n /** Value at a dotted path: a leaf value, a namespace proxy, or undefined. Reads subscribe. */\n get(path: string): any;\n /** Replace the value at a path. Plain objects become namespaces; null/undefined removes. */\n set(path: string, value: any): void;\n /** JSON merge-patch (RFC 7396): objects merge, null removes, everything else replaces. */\n merge(patch: Patch, options?: { at?: string; ifMissing?: boolean }): void;\n remove(path: string): void;\n has(path: string): boolean;\n define(path: string, node: Signal<any>): void;\n paths(filter?: Filter): string[];\n snapshot(filter?: Filter, options?: { at?: string; computed?: boolean }): Patch;\n /** Called after each settled batch with the nested object of changed paths (null = removed). */\n onPatch(fn: (patch: Patch) => void): () => void;\n readonly $: any;\n /** Identifier scope for compiled expressions: resolves `$count`, `$user`, and `$`. */\n readonly scope: object;\n}\n\nconst parentOf = (p: string): string => p.slice(0, Math.max(0, p.lastIndexOf('.')));\nconst nameOf = (p: string): string => p.slice(p.lastIndexOf('.') + 1);\nconst join = (a: string, b: string): string => (a ? `${a}.${b}` : b);\nconst under = (p: string, at: string): boolean => !at || p === at || p.startsWith(`${at}.`);\nconst str = (k: unknown): k is string => typeof k === 'string';\n\nexport const createStore = (): Store => {\n const leaves = new Map<string, Signal<any>>();\n const kids = new Map<string, Set<string>>([['', new Set()]]);\n const shape = new Signal(0); // bumped on any structural change; enumerations subscribe to it\n const pending = new Map<string, any>();\n const listeners = new Set<(p: Patch) => void>();\n const nsCache = new Map<string, any>();\n const arrCache = new WeakMap<object, any>();\n\n const ensureNs = (p: string): Set<string> => {\n let set = kids.get(p);\n if (!set) {\n if (leaves.has(p)) dropLeaf(p);\n set = new Set();\n kids.set(p, set);\n ensureNs(parentOf(p)).add(nameOf(p));\n shape.bump();\n }\n return set;\n };\n\n const dropLeaf = (p: string): void => {\n const s = leaves.get(p);\n if (!s) return;\n leaves.delete(p);\n kids.get(parentOf(p))?.delete(nameOf(p));\n pending.set(p, null);\n s.bump();\n shape.bump();\n };\n\n const dropNs = (p: string): void => {\n const set = kids.get(p);\n if (!set) return;\n for (const k of [...set]) remove(join(p, k));\n if (p) {\n kids.delete(p);\n kids.get(parentOf(p))?.delete(nameOf(p));\n nsCache.delete(p);\n }\n shape.bump();\n };\n\n const remove = (p: string): void =>\n batch(() => {\n dropLeaf(p);\n dropNs(p);\n });\n\n const define = (p: string, node: Signal<any>): void =>\n batch(() => {\n if (kids.has(p)) dropNs(p);\n const old = leaves.get(p);\n leaves.set(p, node);\n ensureNs(parentOf(p)).add(nameOf(p));\n old?.bump();\n shape.bump();\n });\n\n const set = (p: string, v: any): void =>\n batch(() => {\n if (v == null) return remove(p);\n if (isPlain(v)) {\n const names = ensureNs(p);\n for (const k of [...names]) if (!(k in v)) remove(join(p, k));\n for (const k in v) set(join(p, k), v[k]);\n return;\n }\n if (kids.has(p)) dropNs(p);\n const s = leaves.get(p);\n if (s instanceof Computed) throw new Error(`\"${p}\" is a computed signal and cannot be assigned`);\n if (s) {\n if (Object.is(s.peek(), v)) return;\n s.value = v;\n } else {\n define(p, new Signal(v));\n }\n pending.set(p, v);\n });\n\n const merge = (patch: Patch, { at = '', ifMissing = false } = {}): void =>\n batch(() => {\n if (!isPlain(patch)) return;\n ensureNs(at);\n for (const k in patch) {\n const p = join(at, k);\n const v = patch[k];\n if (v === null) {\n if (!ifMissing) remove(p);\n } else if (isPlain(v)) {\n merge(v, { at: p, ifMissing });\n } else if (!(ifMissing && (leaves.has(p) || kids.has(p))) && !(leaves.get(p) instanceof Computed)) {\n set(p, v); // computed leaves are skipped: patches from storage or a server cannot overwrite them\n }\n }\n });\n\n /** Arrays are returned through a proxy so in-place mutation notifies the leaf. */\n const wrapArray = (raw: any[], s: Signal<any>, p: string): any => {\n let px = arrCache.get(raw);\n if (!px) {\n const touch = () => {\n pending.set(p, raw);\n s.bump();\n };\n px = new Proxy(raw, {\n set: (t, k, v) => {\n (t as any)[k] = v;\n touch();\n return true;\n },\n deleteProperty: (t, k) => {\n delete (t as any)[k];\n touch();\n return true;\n },\n });\n arrCache.set(raw, px);\n }\n return px;\n };\n\n const get = (p: string): any => {\n const s = leaves.get(p);\n if (s) {\n const v = s.value;\n return Array.isArray(v) ? wrapArray(v, s, p) : v;\n }\n if (kids.has(p)) return ns(p);\n shape.value; // subscribe, so creating this path later re-runs the reader\n return undefined;\n };\n\n const ns = (p: string): any => {\n let px = nsCache.get(p);\n if (!px) {\n const names = () => {\n shape.value; // read so the effect tracks shape changes\n return kids.get(p);\n };\n px = new Proxy(\n {},\n {\n get: (_, k) =>\n !str(k) ? undefined : k === 'toJSON' ? () => snapshot(undefined, { at: p }) : get(join(p, k)),\n set: (_, k, v) => {\n if (str(k)) set(join(p, k), v);\n return true;\n },\n deleteProperty: (_, k) => {\n if (str(k)) remove(join(p, k));\n return true;\n },\n has: (_, k) => str(k) && !!names()?.has(k),\n ownKeys: () => [...(names() ?? [])],\n getOwnPropertyDescriptor: (_, k) =>\n str(k) && names()?.has(k)\n ? { enumerable: true, configurable: true, writable: true, value: get(join(p, k)) }\n : undefined,\n },\n );\n nsCache.set(p, px);\n }\n return px;\n };\n\n const scope = new Proxy(\n {},\n {\n has: (_, k) => str(k) && k[0] === '$',\n get: (_, k) => (!str(k) ? undefined : k === '$' ? ns('') : get(k.slice(1))),\n set: (_, k, v) => {\n if (str(k)) k === '$' ? merge(v) : set(k.slice(1), v);\n return true;\n },\n },\n );\n\n const paths = (filter?: Filter): string[] => {\n shape.value;\n const ok = toPredicate(filter);\n return [...leaves.keys()].filter(ok);\n };\n\n const snapshot = (filter?: Filter, { at = '', computed = true } = {}): Patch => {\n shape.value;\n const ok = toPredicate(filter);\n const out: Patch = {};\n const rel = (p: string) => (at ? p.slice(at.length + 1) : p);\n for (const [p, s] of leaves) {\n if (!under(p, at) || !ok(p) || (!computed && s instanceof Computed)) continue;\n expand(out, rel(p), s.value);\n }\n // Empty namespaces still appear as `{}`.\n for (const p of kids.keys()) {\n if (p && p !== at && under(p, at) && ok(p) && !kids.get(p)?.size) expand(out, rel(p), {});\n }\n return out;\n };\n\n onSettled(() => {\n if (!pending.size) return;\n const patch: Patch = {};\n for (const [p, v] of pending) expand(patch, p, v);\n pending.clear();\n for (const fn of listeners) fn(patch);\n });\n\n return {\n get,\n set,\n merge,\n remove,\n has: (p) => leaves.has(p) || kids.has(p),\n define,\n paths,\n snapshot,\n onPatch: (fn) => {\n listeners.add(fn);\n return () => listeners.delete(fn);\n },\n get $() {\n return ns('');\n },\n scope,\n };\n};\n"],
5
- "mappings": "AAAA,SAAS,QAAqB,SAAS,mBAAmB;AAC1D,SAAS,OAAO,UAAU,WAAW,cAAc;AAuBnD,MAAM,WAAW,CAAC,MAAsB,EAAE,MAAM,GAAG,KAAK,IAAI,GAAG,EAAE,YAAY,GAAG,CAAC,CAAC;AAClF,MAAM,SAAS,CAAC,MAAsB,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;AACpE,MAAM,OAAO,CAAC,GAAW,MAAuB,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK;AAClE,MAAM,QAAQ,CAAC,GAAW,OAAwB,CAAC,MAAM,MAAM,MAAM,EAAE,WAAW,GAAG,EAAE,GAAG;AAC1F,MAAM,MAAM,CAAC,MAA4B,OAAO,MAAM;AAE/C,MAAM,cAAc,MAAa;AACtC,QAAM,SAAS,oBAAI,IAAyB;AAC5C,QAAM,OAAO,oBAAI,IAAyB,CAAC,CAAC,IAAI,oBAAI,IAAI,CAAC,CAAC,CAAC;AAC3D,QAAM,QAAQ,IAAI,OAAO,CAAC;AAC1B,QAAM,UAAU,oBAAI,IAAiB;AACrC,QAAM,YAAY,oBAAI,IAAwB;AAC9C,QAAM,UAAU,oBAAI,IAAiB;AACrC,QAAM,WAAW,oBAAI,QAAqB;AAE1C,QAAM,WAAW,CAAC,MAA2B;AAC3C,QAAIA,OAAM,KAAK,IAAI,CAAC;AACpB,QAAI,CAACA,MAAK;AACR,UAAI,OAAO,IAAI,CAAC,EAAG,UAAS,CAAC;AAC7B,MAAAA,OAAM,oBAAI,IAAI;AACd,WAAK,IAAI,GAAGA,IAAG;AACf,eAAS,SAAS,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,CAAC;AACnC,YAAM,KAAK;AAAA,IACb;AACA,WAAOA;AAAA,EACT;AAEA,QAAM,WAAW,CAAC,MAAoB;AACpC,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,QAAI,CAAC,EAAG;AACR,WAAO,OAAO,CAAC;AACf,SAAK,IAAI,SAAS,CAAC,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC;AACvC,YAAQ,IAAI,GAAG,IAAI;AACnB,MAAE,KAAK;AACP,UAAM,KAAK;AAAA,EACb;AAEA,QAAM,SAAS,CAAC,MAAoB;AAClC,UAAMA,OAAM,KAAK,IAAI,CAAC;AACtB,QAAI,CAACA,KAAK;AACV,eAAW,KAAK,CAAC,GAAGA,IAAG,EAAG,QAAO,KAAK,GAAG,CAAC,CAAC;AAC3C,QAAI,GAAG;AACL,WAAK,OAAO,CAAC;AACb,WAAK,IAAI,SAAS,CAAC,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC;AACvC,cAAQ,OAAO,CAAC;AAAA,IAClB;AACA,UAAM,KAAK;AAAA,EACb;AAEA,QAAM,SAAS,CAAC,MACd,MAAM,MAAM;AACV,aAAS,CAAC;AACV,WAAO,CAAC;AAAA,EACV,CAAC;AAEH,QAAM,SAAS,CAAC,GAAW,SACzB,MAAM,MAAM;AACV,QAAI,KAAK,IAAI,CAAC,EAAG,QAAO,CAAC;AACzB,UAAM,MAAM,OAAO,IAAI,CAAC;AACxB,WAAO,IAAI,GAAG,IAAI;AAClB,aAAS,SAAS,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,CAAC;AACnC,SAAK,KAAK;AACV,UAAM,KAAK;AAAA,EACb,CAAC;AAEH,QAAM,MAAM,CAAC,GAAW,MACtB,MAAM,MAAM;AACV,QAAI,KAAK,KAAM,QAAO,OAAO,CAAC;AAC9B,QAAI,QAAQ,CAAC,GAAG;AACd,YAAM,QAAQ,SAAS,CAAC;AACxB,iBAAW,KAAK,CAAC,GAAG,KAAK,EAAG,KAAI,EAAE,KAAK,GAAI,QAAO,KAAK,GAAG,CAAC,CAAC;AAC5D,iBAAW,KAAK,EAAG,KAAI,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;AACvC;AAAA,IACF;AACA,QAAI,KAAK,IAAI,CAAC,EAAG,QAAO,CAAC;AACzB,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,QAAI,aAAa,SAAU,OAAM,IAAI,MAAM,IAAI,CAAC,+CAA+C;AAC/F,QAAI,GAAG;AACL,UAAI,OAAO,GAAG,EAAE,KAAK,GAAG,CAAC,EAAG;AAC5B,QAAE,QAAQ;AAAA,IACZ,OAAO;AACL,aAAO,GAAG,IAAI,OAAO,CAAC,CAAC;AAAA,IACzB;AACA,YAAQ,IAAI,GAAG,CAAC;AAAA,EAClB,CAAC;AAEH,QAAM,QAAQ,CAAC,OAAc,EAAE,KAAK,IAAI,YAAY,MAAM,IAAI,CAAC,MAC7D,MAAM,MAAM;AACV,QAAI,CAAC,QAAQ,KAAK,EAAG;AACrB,aAAS,EAAE;AACX,eAAW,KAAK,OAAO;AACrB,YAAM,IAAI,KAAK,IAAI,CAAC;AACpB,YAAM,IAAI,MAAM,CAAC;AACjB,UAAI,MAAM,MAAM;AACd,YAAI,CAAC,UAAW,QAAO,CAAC;AAAA,MAC1B,WAAW,QAAQ,CAAC,GAAG;AACrB,cAAM,GAAG,EAAE,IAAI,GAAG,UAAU,CAAC;AAAA,MAC/B,WAAW,EAAE,cAAc,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,IAAI,CAAC,aAAa,WAAW;AACjG,YAAI,GAAG,CAAC;AAAA,MACV;AAAA,IACF;AAAA,EACF,CAAC;AAGH,QAAM,YAAY,CAAC,KAAY,GAAgB,MAAmB;AAChE,QAAI,KAAK,SAAS,IAAI,GAAG;AACzB,QAAI,CAAC,IAAI;AACP,YAAM,QAAQ,MAAM;AAClB,gBAAQ,IAAI,GAAG,GAAG;AAClB,UAAE,KAAK;AAAA,MACT;AACA,WAAK,IAAI,MAAM,KAAK;AAAA,QAClB,KAAK,CAAC,GAAG,GAAG,MAAM;AAChB,UAAC,EAAU,CAAC,IAAI;AAChB,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA,QACA,gBAAgB,CAAC,GAAG,MAAM;AACxB,iBAAQ,EAAU,CAAC;AACnB,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AACD,eAAS,IAAI,KAAK,EAAE;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,CAAC,MAAmB;AAC9B,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,QAAI,GAAG;AACL,YAAM,IAAI,EAAE;AACZ,aAAO,MAAM,QAAQ,CAAC,IAAI,UAAU,GAAG,GAAG,CAAC,IAAI;AAAA,IACjD;AACA,QAAI,KAAK,IAAI,CAAC,EAAG,QAAO,GAAG,CAAC;AAC5B,UAAM;AACN,WAAO;AAAA,EACT;AAEA,QAAM,KAAK,CAAC,MAAmB;AAC7B,QAAI,KAAK,QAAQ,IAAI,CAAC;AACtB,QAAI,CAAC,IAAI;AACP,YAAM,QAAQ,MAAM;AAClB,cAAM;AACN,eAAO,KAAK,IAAI,CAAC;AAAA,MACnB;AACA,WAAK,IAAI;AAAA,QACP,CAAC;AAAA,QACD;AAAA,UACE,KAAK,CAAC,GAAG,MACP,CAAC,IAAI,CAAC,IAAI,SAAY,MAAM,WAAW,MAAM,SAAS,QAAW,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;AAAA,UAC9F,KAAK,CAAC,GAAG,GAAG,MAAM;AAChB,gBAAI,IAAI,CAAC,EAAG,KAAI,KAAK,GAAG,CAAC,GAAG,CAAC;AAC7B,mBAAO;AAAA,UACT;AAAA,UACA,gBAAgB,CAAC,GAAG,MAAM;AACxB,gBAAI,IAAI,CAAC,EAAG,QAAO,KAAK,GAAG,CAAC,CAAC;AAC7B,mBAAO;AAAA,UACT;AAAA,UACA,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;AAAA,UACzC,SAAS,MAAM,CAAC,GAAI,MAAM,KAAK,CAAC,CAAE;AAAA,UAClC,0BAA0B,CAAC,GAAG,MAC5B,IAAI,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC,IACpB,EAAE,YAAY,MAAM,cAAc,MAAM,UAAU,MAAM,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,IAC/E;AAAA,QACR;AAAA,MACF;AACA,cAAQ,IAAI,GAAG,EAAE;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,IAAI;AAAA,IAChB,CAAC;AAAA,IACD;AAAA,MACE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM;AAAA,MAClC,KAAK,CAAC,GAAG,MAAO,CAAC,IAAI,CAAC,IAAI,SAAY,MAAM,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,MACzE,KAAK,CAAC,GAAG,GAAG,MAAM;AAChB,YAAI,IAAI,CAAC,EAAG,OAAM,MAAM,MAAM,CAAC,IAAI,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC;AACpD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,CAAC,WAA8B;AAC3C,UAAM;AACN,UAAM,KAAK,YAAY,MAAM;AAC7B,WAAO,CAAC,GAAG,OAAO,KAAK,CAAC,EAAE,OAAO,EAAE;AAAA,EACrC;AAEA,QAAM,WAAW,CAAC,QAAiB,EAAE,KAAK,IAAI,WAAW,KAAK,IAAI,CAAC,MAAa;AAC9E,UAAM;AACN,UAAM,KAAK,YAAY,MAAM;AAC7B,UAAM,MAAa,CAAC;AACpB,UAAM,MAAM,CAAC,MAAe,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,IAAI;AAC1D,eAAW,CAAC,GAAG,CAAC,KAAK,QAAQ;AAC3B,UAAI,CAAC,MAAM,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,KAAM,CAAC,YAAY,aAAa,SAAW;AACrE,aAAO,KAAK,IAAI,CAAC,GAAG,EAAE,KAAK;AAAA,IAC7B;AAEA,eAAW,KAAK,KAAK,KAAK,GAAG;AAC3B,UAAI,KAAK,MAAM,MAAM,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,KAAM,QAAO,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,IAC1F;AACA,WAAO;AAAA,EACT;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,KAAM;AACnB,UAAM,QAAe,CAAC;AACtB,eAAW,CAAC,GAAG,CAAC,KAAK,QAAS,QAAO,OAAO,GAAG,CAAC;AAChD,YAAQ,MAAM;AACd,eAAW,MAAM,UAAW,IAAG,KAAK;AAAA,EACtC,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,CAAC,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,CAAC,OAAO;AACf,gBAAU,IAAI,EAAE;AAChB,aAAO,MAAM,UAAU,OAAO,EAAE;AAAA,IAClC;AAAA,IACA,IAAI,IAAI;AACN,aAAO,GAAG,EAAE;AAAA,IACd;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { expand, type Filter, isPlain, safeKey, toPredicate } from '../lib/objects.js';\nimport { batch, Computed, onSettled, Signal } from './reactive.js';\n\nexport type Patch = Record<string, any>;\n\nexport interface Store {\n /** Value at a dotted path: a leaf value, a namespace proxy, or undefined. Reads subscribe. */\n get(path: string): any;\n /** Replace the value at a path. Plain objects become namespaces; null/undefined removes. */\n set(path: string, value: any): void;\n /** JSON merge-patch (RFC 7396): objects merge, null removes, everything else replaces. */\n merge(patch: Patch, options?: { at?: string; ifMissing?: boolean }): void;\n remove(path: string): void;\n has(path: string): boolean;\n define(path: string, node: Signal<any>): void;\n /** Leaf paths, filtered; `computed: false` leaves out computed signals. */\n paths(filter?: Filter, options?: { computed?: boolean }): string[];\n snapshot(filter?: Filter, options?: { at?: string; computed?: boolean }): Patch;\n /** Called after each settled batch with the nested object of changed paths (null = removed). */\n onPatch(fn: (patch: Patch) => void): () => void;\n readonly $: any;\n}\n\n/** 'a.b.c' \u2192 ['a.b', 'c']; 'a' \u2192 ['', 'a']. */\nconst split = (p: string): [string, string] => {\n const i = p.lastIndexOf('.');\n return [i < 0 ? '' : p.slice(0, i), p.slice(i + 1)];\n};\nconst join = (a: string, b: string): string => (a ? `${a}.${b}` : b);\nconst under = (p: string, at: string): boolean => !at || p.startsWith(`${at}.`);\nconst str = (k: unknown): k is string => typeof k === 'string';\n/** Proxy \u2192 the raw array or object behind it, so a proxied value can be stored or compared. */\nconst rawOf = new WeakMap<object, object>();\n\nexport const createStore = (): Store => {\n const leaves = new Map<string, Signal<any>>();\n const kids = new Map<string, Set<string>>([['', new Set()]]);\n const shape = new Signal(0); // bumped on any structural change; enumerations subscribe to it\n const pending = new Map<string, any>();\n const listeners = new Set<(p: Patch) => void>();\n const nsCache = new Map<string, any>();\n /** Per leaf signal, per raw object: its reactive proxy. */\n const proxies = new WeakMap<Signal<any>, WeakMap<object, any>>();\n\n /** Register `p` under its parent namespace (creating the namespace chain) and mark the shape changed. */\n const link = (p: string): void => {\n const [parent, name] = split(p);\n ensureNs(parent).add(name);\n shape.bump();\n };\n const unlink = (p: string): void => {\n const [parent, name] = split(p);\n kids.get(parent)?.delete(name);\n shape.bump();\n };\n\n const ensureNs = (p: string): Set<string> => {\n let set = kids.get(p);\n if (!set) {\n if (leaves.has(p)) dropLeaf(p);\n set = new Set();\n kids.set(p, set);\n link(p);\n }\n return set;\n };\n\n const dropLeaf = (p: string): void => {\n const s = leaves.get(p);\n if (!s) return;\n leaves.delete(p);\n unlink(p);\n pending.set(p, null);\n s.bump();\n if (s instanceof Computed) s.dispose();\n };\n\n const dropNs = (p: string): void => {\n const set = kids.get(p);\n if (!set) return;\n for (const k of [...set]) remove(join(p, k));\n if (p) {\n kids.delete(p);\n nsCache.delete(p);\n unlink(p);\n }\n };\n\n const remove = (p: string): void =>\n batch(() => {\n dropLeaf(p);\n dropNs(p);\n });\n\n const define = (p: string, node: Signal<any>): void =>\n batch(() => {\n dropNs(p);\n const old = leaves.get(p);\n leaves.set(p, node);\n link(p);\n if (old) {\n old.bump();\n if (old instanceof Computed) old.dispose();\n }\n });\n\n const set = (p: string, v: any): void =>\n batch(() => {\n if (v == null) return remove(p);\n v = (v && rawOf.get(v)) ?? v;\n if (isPlain(v)) {\n for (const k of [...ensureNs(p)]) if (!(k in v)) remove(join(p, k));\n for (const k in v) if (safeKey(k)) set(join(p, k), v[k]);\n return;\n }\n dropNs(p);\n const s = leaves.get(p);\n if (s instanceof Computed) throw new Error(`computed \"${p}\" is read-only`);\n if (s) {\n if (Object.is(s.peek(), v)) return;\n s.value = v;\n } else {\n define(p, new Signal(v));\n }\n pending.set(p, v);\n });\n\n const merge = (patch: Patch, { at = '', ifMissing = false } = {}): void =>\n batch(() => {\n if (!isPlain(patch)) return;\n const keys = Object.keys(patch).filter(safeKey);\n if (keys.length) ensureNs(at);\n for (const k of keys) {\n const p = join(at, k);\n const v = patch[k];\n const leaf = leaves.get(p);\n // Existing values win under ifMissing, and computed leaves are never overwritten by a patch.\n if (leaf && (ifMissing || leaf instanceof Computed)) continue;\n if (v === null) {\n if (!ifMissing) remove(p);\n } else if (isPlain(v)) merge(v, { at: p, ifMissing });\n else if (!(ifMissing && kids.has(p))) set(p, v);\n }\n });\n\n const has = (p: string): boolean => leaves.has(p) || kids.has(p);\n\n /**\n * Arrays are returned through a proxy so in-place mutation notifies the leaf: writes anywhere\n * inside (nested objects and arrays included) bump the leaf, and array methods run as one batch.\n * Proxies are cached per leaf, so the same object under two paths notifies both.\n */\n const wrapArray = (raw: any[], s: Signal<any>, p: string): any => {\n let cache = proxies.get(s);\n if (!cache) {\n cache = new WeakMap();\n proxies.set(s, cache);\n }\n const touch = () => {\n pending.set(p, raw);\n s.bump();\n return true;\n };\n const wrap = (target: object): any => {\n let px = cache?.get(target);\n if (!px) {\n px = new Proxy(target, {\n get: (t, k, r) => {\n const v = Reflect.get(t, k, r);\n if (typeof v === 'function' && Array.isArray(t)) return (...a: any[]) => batch(() => v.apply(r, a));\n if (!v || typeof v !== 'object' || !(Array.isArray(v) || isPlain(v))) return v;\n const d = Object.getOwnPropertyDescriptor(t, k);\n return d && !d.configurable && !d.writable ? v : wrap(v); // frozen data: the proxy invariant forbids wrapping\n },\n set: (t, k, v) => {\n (t as any)[k] = (v && rawOf.get(v)) ?? v;\n return touch();\n },\n deleteProperty: (t, k) => {\n delete (t as any)[k];\n return touch();\n },\n });\n cache?.set(target, px);\n rawOf.set(px, target);\n }\n return px;\n };\n return wrap(raw);\n };\n\n const get = (p: string): any => {\n const s = leaves.get(p);\n if (s) {\n const v = s.value;\n return Array.isArray(v) ? wrapArray(v, s, p) : v;\n }\n shape.value; // subscribe: a namespace may become a leaf, and a missing path may appear\n if (kids.has(p)) return ns(p);\n };\n\n const ns = (p: string): any => {\n let px = nsCache.get(p);\n if (!px) {\n const names = (k: unknown): k is string => {\n shape.value; // read so the effect tracks shape changes\n return str(k) && !!kids.get(p)?.has(k);\n };\n px = new Proxy(\n {},\n {\n get: (_, k) =>\n !str(k) ? undefined : k === 'toJSON' ? () => snapshot(undefined, { at: p }) : get(join(p, k)),\n set: (_, k, v) => {\n if (str(k)) set(join(p, k), v);\n return true;\n },\n deleteProperty: (_, k) => {\n if (str(k)) remove(join(p, k));\n return true;\n },\n has: (_, k) => names(k),\n ownKeys: () => {\n shape.value;\n return [...(kids.get(p) ?? [])];\n },\n getOwnPropertyDescriptor: (_, k) =>\n names(k) ? { enumerable: true, configurable: true, writable: true, value: get(join(p, k)) } : undefined,\n },\n );\n nsCache.set(p, px);\n }\n return px;\n };\n\n const paths = (filter?: Filter, { computed = true } = {}): string[] => {\n shape.value;\n const ok = toPredicate(filter);\n return [...leaves].filter(([p, s]) => ok(p) && (computed || !(s instanceof Computed))).map(([p]) => p);\n };\n\n const snapshot = (filter?: Filter, { at = '', computed = true } = {}): Patch => {\n const out: Patch = {};\n for (const p of paths(filter, { computed }))\n if (under(p, at)) expand(out, at ? p.slice(at.length + 1) : p, leaves.get(p)?.value);\n return out;\n };\n\n onSettled(() => {\n if (!pending.size) return;\n const patch: Patch = {};\n for (const [p, v] of pending) expand(patch, p, v);\n pending.clear();\n for (const fn of listeners) fn(patch);\n });\n\n return {\n get,\n set,\n merge,\n remove,\n has,\n define,\n paths,\n snapshot,\n onPatch: (fn) => {\n listeners.add(fn);\n return () => listeners.delete(fn);\n },\n get $() {\n return ns('');\n },\n };\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["set"]
7
7
  }
@@ -1,7 +1,2 @@
1
1
  import type { Compiler } from './compile.js';
2
- /**
3
- * Compiler for pages with a strict Content-Security-Policy: compiles through a nonce-bearing
4
- * inline `<script>` (and a Trusted Types policy when present) instead of `new Function`.
5
- * Pass as `createSigmx({ compile: cspCompiler(nonce) })`.
6
- */
7
2
  export declare const cspCompiler: (nonce: string) => Compiler;
@@ -1,7 +1,7 @@
1
+ let policy;
1
2
  const cspCompiler = (nonce) => {
2
3
  if (!nonce) throw new Error("cspCompiler needs the page nonce");
3
- const tt = window.trustedTypes;
4
- const policy = tt?.createPolicy("sigmx", { createScript: (s) => s });
4
+ policy ??= window.trustedTypes?.createPolicy("sigmx", { createScript: (s) => s });
5
5
  return (params, body) => {
6
6
  const script = document.createElement("script");
7
7
  script.nonce = nonce;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/strict-csp.ts"],
4
- "sourcesContent": ["import type { Compiler } from './compile.js';\n\n/**\n * Compiler for pages with a strict Content-Security-Policy: compiles through a nonce-bearing\n * inline `<script>` (and a Trusted Types policy when present) instead of `new Function`.\n * Pass as `createSigmx({ compile: cspCompiler(nonce) })`.\n */\nexport const cspCompiler = (nonce: string): Compiler => {\n if (!nonce) throw new Error('cspCompiler needs the page nonce');\n const tt = (window as any).trustedTypes;\n const policy = tt?.createPolicy('sigmx', { createScript: (s: string) => s });\n return (params, body) => {\n const script = document.createElement('script');\n script.nonce = nonce;\n const text = `document.currentScript.f=function(${params.join(',')}){${body}}`;\n script.text = policy ? policy.createScript(text) : text;\n document.head.append(script);\n script.remove();\n const fn = (script as any).f;\n if (!fn) throw new Error('the Content-Security-Policy blocked expression compilation');\n return fn;\n };\n};\n"],
5
- "mappings": "AAOO,MAAM,cAAc,CAAC,UAA4B;AACtD,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,kCAAkC;AAC9D,QAAM,KAAM,OAAe;AAC3B,QAAM,SAAS,IAAI,aAAa,SAAS,EAAE,cAAc,CAAC,MAAc,EAAE,CAAC;AAC3E,SAAO,CAAC,QAAQ,SAAS;AACvB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,UAAM,OAAO,qCAAqC,OAAO,KAAK,GAAG,CAAC,KAAK,IAAI;AAC3E,WAAO,OAAO,SAAS,OAAO,aAAa,IAAI,IAAI;AACnD,aAAS,KAAK,OAAO,MAAM;AAC3B,WAAO,OAAO;AACd,UAAM,KAAM,OAAe;AAC3B,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,4DAA4D;AACrF,WAAO;AAAA,EACT;AACF;",
4
+ "sourcesContent": ["import type { Compiler } from './compile.js';\n\n/**\n * Compiler for pages with a strict Content-Security-Policy: compiles through a nonce-bearing\n * inline `<script>` (and a Trusted Types policy when present) instead of `new Function`.\n * Pass as `createSigmx({ compile: cspCompiler(nonce) })`.\n */\nlet policy: { createScript(s: string): any } | undefined;\n\nexport const cspCompiler = (nonce: string): Compiler => {\n if (!nonce) throw new Error('cspCompiler needs the page nonce');\n // One Trusted Types policy per page: creating a second one with the same name throws under a strict CSP.\n policy ??= (window as any).trustedTypes?.createPolicy('sigmx', { createScript: (s: string) => s });\n return (params, body) => {\n const script = document.createElement('script');\n script.nonce = nonce;\n const text = `document.currentScript.f=function(${params.join(',')}){${body}}`;\n script.text = policy ? policy.createScript(text) : text;\n document.head.append(script);\n script.remove();\n const fn = (script as any).f;\n if (!fn) throw new Error('the Content-Security-Policy blocked expression compilation');\n return fn;\n };\n};\n"],
5
+ "mappings": "AAOA,IAAI;AAEG,MAAM,cAAc,CAAC,UAA4B;AACtD,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,kCAAkC;AAE9D,aAAY,OAAe,cAAc,aAAa,SAAS,EAAE,cAAc,CAAC,MAAc,EAAE,CAAC;AACjG,SAAO,CAAC,QAAQ,SAAS;AACvB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,UAAM,OAAO,qCAAqC,OAAO,KAAK,GAAG,CAAC,KAAK,IAAI;AAC3E,WAAO,OAAO,SAAS,OAAO,aAAa,IAAI,IAAI;AACnD,aAAS,KAAK,OAAO,MAAM;AAC3B,WAAO,OAAO;AACd,UAAM,KAAM,OAAe;AAC3B,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,4DAA4D;AACrF,WAAO;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,5 +3,8 @@ export declare const kebab: (s: string) => string;
3
3
  export declare const snake: (s: string) => string;
4
4
  export declare const camel: (s: string) => string;
5
5
  export declare const pascal: (s: string) => string;
6
- /** Recase a dotted path segment by segment so `user.first-name` becomes `user.firstName`. */
6
+ /**
7
+ * Recase a dotted path segment by segment so `user.first-name` becomes `user.firstName`. Leading
8
+ * underscores survive (`_draft` stays `_draft`); an unknown style is an error.
9
+ */
7
10
  export declare const recase: (path: string, style: CaseStyle) => string;
@@ -5,7 +5,14 @@ const snake = (s) => words(s).join("_");
5
5
  const camel = (s) => words(s).map((w, i) => i ? cap(w) : w).join("");
6
6
  const pascal = (s) => words(s).map(cap).join("");
7
7
  const styles = { camel, kebab, snake, pascal };
8
- const recase = (path, style) => path.split(".").map(styles[style]).join(".");
8
+ const recase = (path, style) => {
9
+ const f = styles[style];
10
+ if (!f) throw new Error(`unknown case "${style}"`);
11
+ return path.split(".").map((seg) => {
12
+ const u = /^_+/.exec(seg)?.[0] ?? "";
13
+ return u + f(seg.slice(u.length));
14
+ }).join(".");
15
+ };
9
16
  export {
10
17
  camel,
11
18
  kebab,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/casing.ts"],
4
- "sourcesContent": ["export type CaseStyle = 'camel' | 'kebab' | 'snake' | 'pascal';\n\nconst words = (s: string): string[] =>\n s\n .replace(/([a-z0-9])([A-Z])|([A-Z]+)([A-Z][a-z])/g, '$1$3 $2$4')\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((w) => w.toLowerCase());\n\nconst cap = (w: string): string => w[0].toUpperCase() + w.slice(1);\n\nexport const kebab = (s: string): string => words(s).join('-');\nexport const snake = (s: string): string => words(s).join('_');\nexport const camel = (s: string): string =>\n words(s)\n .map((w, i) => (i ? cap(w) : w))\n .join('');\nexport const pascal = (s: string): string => words(s).map(cap).join('');\n\nconst styles = { camel, kebab, snake, pascal };\n\n/** Recase a dotted path segment by segment so `user.first-name` becomes `user.firstName`. */\nexport const recase = (path: string, style: CaseStyle): string => path.split('.').map(styles[style]).join('.');\n"],
5
- "mappings": "AAEA,MAAM,QAAQ,CAAC,MACb,EACG,QAAQ,2CAA2C,WAAW,EAC9D,MAAM,eAAe,EACrB,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAE/B,MAAM,MAAM,CAAC,MAAsB,EAAE,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAE1D,MAAM,QAAQ,CAAC,MAAsB,MAAM,CAAC,EAAE,KAAK,GAAG;AACtD,MAAM,QAAQ,CAAC,MAAsB,MAAM,CAAC,EAAE,KAAK,GAAG;AACtD,MAAM,QAAQ,CAAC,MACpB,MAAM,CAAC,EACJ,IAAI,CAAC,GAAG,MAAO,IAAI,IAAI,CAAC,IAAI,CAAE,EAC9B,KAAK,EAAE;AACL,MAAM,SAAS,CAAC,MAAsB,MAAM,CAAC,EAAE,IAAI,GAAG,EAAE,KAAK,EAAE;AAEtE,MAAM,SAAS,EAAE,OAAO,OAAO,OAAO,OAAO;AAGtC,MAAM,SAAS,CAAC,MAAc,UAA6B,KAAK,MAAM,GAAG,EAAE,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,GAAG;",
4
+ "sourcesContent": ["export type CaseStyle = 'camel' | 'kebab' | 'snake' | 'pascal';\n\nconst words = (s: string): string[] =>\n s\n .replace(/([a-z0-9])([A-Z])|([A-Z]+)([A-Z][a-z])/g, '$1$3 $2$4')\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((w) => w.toLowerCase());\n\nconst cap = (w: string): string => w[0].toUpperCase() + w.slice(1);\n\nexport const kebab = (s: string): string => words(s).join('-');\nexport const snake = (s: string): string => words(s).join('_');\nexport const camel = (s: string): string =>\n words(s)\n .map((w, i) => (i ? cap(w) : w))\n .join('');\nexport const pascal = (s: string): string => words(s).map(cap).join('');\n\nconst styles = { camel, kebab, snake, pascal };\n\n/**\n * Recase a dotted path segment by segment so `user.first-name` becomes `user.firstName`. Leading\n * underscores survive (`_draft` stays `_draft`); an unknown style is an error.\n */\nexport const recase = (path: string, style: CaseStyle): string => {\n const f = styles[style];\n if (!f) throw new Error(`unknown case \"${style}\"`);\n return path\n .split('.')\n .map((seg) => {\n const u = /^_+/.exec(seg)?.[0] ?? '';\n return u + f(seg.slice(u.length));\n })\n .join('.');\n};\n"],
5
+ "mappings": "AAEA,MAAM,QAAQ,CAAC,MACb,EACG,QAAQ,2CAA2C,WAAW,EAC9D,MAAM,eAAe,EACrB,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAE/B,MAAM,MAAM,CAAC,MAAsB,EAAE,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAE1D,MAAM,QAAQ,CAAC,MAAsB,MAAM,CAAC,EAAE,KAAK,GAAG;AACtD,MAAM,QAAQ,CAAC,MAAsB,MAAM,CAAC,EAAE,KAAK,GAAG;AACtD,MAAM,QAAQ,CAAC,MACpB,MAAM,CAAC,EACJ,IAAI,CAAC,GAAG,MAAO,IAAI,IAAI,CAAC,IAAI,CAAE,EAC9B,KAAK,EAAE;AACL,MAAM,SAAS,CAAC,MAAsB,MAAM,CAAC,EAAE,IAAI,GAAG,EAAE,KAAK,EAAE;AAEtE,MAAM,SAAS,EAAE,OAAO,OAAO,OAAO,OAAO;AAMtC,MAAM,SAAS,CAAC,MAAc,UAA6B;AAChE,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,CAAC,EAAG,OAAM,IAAI,MAAM,iBAAiB,KAAK,GAAG;AACjD,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,QAAQ;AACZ,UAAM,IAAI,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;AAClC,WAAO,IAAI,EAAE,IAAI,MAAM,EAAE,MAAM,CAAC;AAAA,EAClC,CAAC,EACA,KAAK,GAAG;AACb;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,10 @@
1
1
  export declare const isPlain: (v: unknown) => v is Record<string, any>;
2
+ /** Keys that would walk into Object.prototype are never written: patches can come from a network. */
3
+ export declare const safeKey: (k: string) => boolean;
2
4
  export declare const expand: (out: Record<string, any>, path: string, value: any) => Record<string, any>;
3
5
  export type Filter = {
4
- include?: RegExp | string;
5
- exclude?: RegExp | string;
6
+ include?: RegExp;
7
+ exclude?: RegExp;
6
8
  } | ((path: string) => boolean);
7
- /** Turn `{ include, exclude }` (regex or string) or a predicate into a path predicate. */
9
+ /** Turn `{ include, exclude }` regexes or a predicate into a path predicate. */
8
10
  export declare const toPredicate: (f?: Filter) => ((path: string) => boolean);
@@ -3,27 +3,32 @@ const isPlain = (v) => {
3
3
  const proto = Object.getPrototypeOf(v);
4
4
  return proto === Object.prototype || proto === null;
5
5
  };
6
+ const safeKey = (k) => k !== "__proto__" && k !== "constructor" && k !== "prototype";
6
7
  const expand = (out, path, value) => {
7
8
  const keys = path.split(".");
9
+ if (!keys.every(safeKey)) return out;
8
10
  const last = keys.pop();
9
11
  let cur = out;
10
12
  for (const k of keys) {
11
- if (!isPlain(cur[k])) cur[k] = {};
13
+ if (!isPlain(cur[k]) || !Object.hasOwn(cur, k)) cur[k] = {};
12
14
  cur = cur[k];
13
15
  }
14
16
  cur[last] = value;
15
17
  return out;
16
18
  };
17
- const re = (v, fallback) => v === void 0 ? fallback : typeof v === "string" ? new RegExp(v.replace(/^\/|\/$/g, "")) : v;
18
19
  const toPredicate = (f) => {
19
20
  if (typeof f === "function") return f;
20
- const inc = re(f?.include, /(?:)/);
21
- const exc = re(f?.exclude, /(?!)/);
22
- return (p) => inc.test(p) && !exc.test(p);
21
+ const test = (re, p) => {
22
+ if (!re) return void 0;
23
+ re.lastIndex = 0;
24
+ return re.test(p);
25
+ };
26
+ return (p) => (test(f?.include, p) ?? true) && !test(f?.exclude, p);
23
27
  };
24
28
  export {
25
29
  expand,
26
30
  isPlain,
31
+ safeKey,
27
32
  toPredicate
28
33
  };
29
34
  //# sourceMappingURL=objects.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/objects.ts"],
4
- "sourcesContent": ["export const isPlain = (v: unknown): v is Record<string, any> => {\n if (v === null || typeof v !== 'object') return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n};\n\nexport const expand = (out: Record<string, any>, path: string, value: any): Record<string, any> => {\n const keys = path.split('.');\n const last = keys.pop() as string;\n let cur = out;\n for (const k of keys) {\n if (!isPlain(cur[k])) cur[k] = {};\n cur = cur[k];\n }\n cur[last] = value;\n return out;\n};\n\nexport type Filter = { include?: RegExp | string; exclude?: RegExp | string } | ((path: string) => boolean);\n\nconst re = (v: RegExp | string | undefined, fallback: RegExp): RegExp =>\n v === undefined ? fallback : typeof v === 'string' ? new RegExp(v.replace(/^\\/|\\/$/g, '')) : v;\n\n/** Turn `{ include, exclude }` (regex or string) or a predicate into a path predicate. */\nexport const toPredicate = (f?: Filter): ((path: string) => boolean) => {\n if (typeof f === 'function') return f;\n const inc = re(f?.include, /(?:)/);\n const exc = re(f?.exclude, /(?!)/);\n return (p) => inc.test(p) && !exc.test(p);\n};\n"],
5
- "mappings": "AAAO,MAAM,UAAU,CAAC,MAAyC;AAC/D,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,QAAM,QAAQ,OAAO,eAAe,CAAC;AACrC,SAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAEO,MAAM,SAAS,CAAC,KAA0B,MAAc,UAAoC;AACjG,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,QAAM,OAAO,KAAK,IAAI;AACtB,MAAI,MAAM;AACV,aAAW,KAAK,MAAM;AACpB,QAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAG,KAAI,CAAC,IAAI,CAAC;AAChC,UAAM,IAAI,CAAC;AAAA,EACb;AACA,MAAI,IAAI,IAAI;AACZ,SAAO;AACT;AAIA,MAAM,KAAK,CAAC,GAAgC,aAC1C,MAAM,SAAY,WAAW,OAAO,MAAM,WAAW,IAAI,OAAO,EAAE,QAAQ,YAAY,EAAE,CAAC,IAAI;AAGxF,MAAM,cAAc,CAAC,MAA4C;AACtE,MAAI,OAAO,MAAM,WAAY,QAAO;AACpC,QAAM,MAAM,GAAG,GAAG,SAAS,MAAM;AACjC,QAAM,MAAM,GAAG,GAAG,SAAS,MAAM;AACjC,SAAO,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;AAC1C;",
4
+ "sourcesContent": ["export const isPlain = (v: unknown): v is Record<string, any> => {\n if (v === null || typeof v !== 'object') return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n};\n\n/** Keys that would walk into Object.prototype are never written: patches can come from a network. */\nexport const safeKey = (k: string): boolean => k !== '__proto__' && k !== 'constructor' && k !== 'prototype';\n\nexport const expand = (out: Record<string, any>, path: string, value: any): Record<string, any> => {\n const keys = path.split('.');\n if (!keys.every(safeKey)) return out;\n const last = keys.pop() as string;\n let cur = out;\n for (const k of keys) {\n if (!isPlain(cur[k]) || !Object.hasOwn(cur, k)) cur[k] = {};\n cur = cur[k];\n }\n cur[last] = value;\n return out;\n};\n\nexport type Filter = { include?: RegExp; exclude?: RegExp } | ((path: string) => boolean);\n\n/** Turn `{ include, exclude }` regexes or a predicate into a path predicate. */\nexport const toPredicate = (f?: Filter): ((path: string) => boolean) => {\n if (typeof f === 'function') return f;\n // Reset lastIndex so a /g or /y regex gives the same answer for every path.\n const test = (re: RegExp | undefined, p: string) => {\n if (!re) return undefined;\n re.lastIndex = 0;\n return re.test(p);\n };\n return (p) => (test(f?.include, p) ?? true) && !test(f?.exclude, p);\n};\n"],
5
+ "mappings": "AAAO,MAAM,UAAU,CAAC,MAAyC;AAC/D,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,QAAM,QAAQ,OAAO,eAAe,CAAC;AACrC,SAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAGO,MAAM,UAAU,CAAC,MAAuB,MAAM,eAAe,MAAM,iBAAiB,MAAM;AAE1F,MAAM,SAAS,CAAC,KAA0B,MAAc,UAAoC;AACjG,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,CAAC,KAAK,MAAM,OAAO,EAAG,QAAO;AACjC,QAAM,OAAO,KAAK,IAAI;AACtB,MAAI,MAAM;AACV,aAAW,KAAK,MAAM;AACpB,QAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,OAAO,KAAK,CAAC,EAAG,KAAI,CAAC,IAAI,CAAC;AAC1D,UAAM,IAAI,CAAC;AAAA,EACb;AACA,MAAI,IAAI,IAAI;AACZ,SAAO;AACT;AAKO,MAAM,cAAc,CAAC,MAA4C;AACtE,MAAI,OAAO,MAAM,WAAY,QAAO;AAEpC,QAAM,OAAO,CAAC,IAAwB,MAAc;AAClD,QAAI,CAAC,GAAI,QAAO;AAChB,OAAG,YAAY;AACf,WAAO,GAAG,KAAK,CAAC;AAAA,EAClB;AACA,SAAO,CAAC,OAAO,KAAK,GAAG,SAAS,CAAC,KAAK,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC;AACpE;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,12 @@
1
1
  export type Mods = Map<string, string[]>;
2
2
  type Fn = (...args: any[]) => void;
3
- /** '300ms' → 300, '2s' → 2000, '150' → 150. */
3
+ /** '300ms' → 300, '2s' → 2000, '150' → 150; `__x.1.5s` arrives split on the dot and is joined back first. */
4
4
  export declare const toMs: (args: string[] | undefined, fallback?: number) => number;
5
5
  export declare const delay: (fn: Fn, ms: number) => Fn;
6
6
  /** Debounce: wait for a quiet period. `leading` fires on the first call, `trailing` on the last. */
7
7
  export declare const debounce: (fn: Fn, ms: number, leading?: boolean, trailing?: boolean) => Fn;
8
8
  /** Throttle: at most one call per window. `leading` fires immediately, `trailing` fires once at the end. */
9
9
  export declare const throttle: (fn: Fn, ms: number, leading?: boolean, trailing?: boolean) => Fn;
10
- export declare const withTiming: (fn: Fn, mods: Mods) => Fn;
11
- export declare const withViewTransition: (fn: Fn, mods: Mods) => Fn;
10
+ /** Apply `__debounce` / `__throttle`; `cleanup` cancels a pending trailing call when the attribute unmounts. */
11
+ export declare const withTiming: (fn: Fn, mods: Mods, cleanup?: (f: () => void) => unknown) => Fn;
12
12
  export {};
@@ -1,5 +1,5 @@
1
1
  const toMs = (args, fallback = 0) => {
2
- for (const a of args ?? []) {
2
+ for (const a of args?.length ? [args.join("."), ...args] : []) {
3
3
  const m = /^(\d+(?:\.\d+)?)(ms|s)?$/.exec(a);
4
4
  if (m) return +m[1] * (m[2] === "s" ? 1e3 : 1);
5
5
  }
@@ -14,7 +14,7 @@ const limit = (fn, ms, leading, trailing, restart) => {
14
14
  if (trailing && last) fn(...last);
15
15
  last = void 0;
16
16
  };
17
- return (...args) => {
17
+ const limited = (...args) => {
18
18
  if (timer) {
19
19
  last = args;
20
20
  if (restart) {
@@ -27,25 +27,27 @@ const limit = (fn, ms, leading, trailing, restart) => {
27
27
  else last = args;
28
28
  timer = setTimeout(fire, ms);
29
29
  };
30
+ limited.cancel = () => {
31
+ clearTimeout(timer);
32
+ timer = last = void 0;
33
+ };
34
+ return limited;
30
35
  };
31
36
  const debounce = (fn, ms, leading = false, trailing = true) => limit(fn, ms, leading, trailing, true);
32
37
  const throttle = (fn, ms, leading = true, trailing = false) => limit(fn, ms, leading, trailing, false);
33
- const withTiming = (fn, mods) => {
34
- const d = mods.get("delay");
35
- if (d) fn = delay(fn, toMs(d));
38
+ const withTiming = (fn, mods, cleanup) => {
36
39
  const db = mods.get("debounce");
37
- if (db) fn = debounce(fn, toMs(db, 300), db.includes("leading"), !db.includes("notrailing"));
38
40
  const th = mods.get("throttle");
39
- if (th) fn = throttle(fn, toMs(th, 300), !th.includes("noleading"), th.includes("trailing"));
41
+ if (db) fn = limit(fn, toMs(db, 300), db.includes("leading"), !db.includes("notrailing"), true);
42
+ if (th) fn = limit(fn, toMs(th, 300), !th.includes("noleading"), th.includes("trailing"), false);
43
+ if (db || th) cleanup?.(fn.cancel);
40
44
  return fn;
41
45
  };
42
- const withViewTransition = (fn, mods) => mods.has("viewtransition") && "startViewTransition" in document ? (...args) => void document.startViewTransition(() => fn(...args)) : fn;
43
46
  export {
44
47
  debounce,
45
48
  delay,
46
49
  throttle,
47
50
  toMs,
48
- withTiming,
49
- withViewTransition
51
+ withTiming
50
52
  };
51
53
  //# sourceMappingURL=schedule.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/schedule.ts"],
4
- "sourcesContent": ["export type Mods = Map<string, string[]>;\ntype Fn = (...args: any[]) => void;\n\n/** '300ms' \u2192 300, '2s' \u2192 2000, '150' \u2192 150. */\nexport const toMs = (args: string[] | undefined, fallback = 0): number => {\n for (const a of args ?? []) {\n const m = /^(\\d+(?:\\.\\d+)?)(ms|s)?$/.exec(a);\n if (m) return +m[1] * (m[2] === 's' ? 1000 : 1);\n }\n return fallback;\n};\n\nexport const delay =\n (fn: Fn, ms: number): Fn =>\n (...args) =>\n void setTimeout(fn, ms, ...args);\n\n/** Shared rate limiter. `restart` makes it a debounce (the window restarts on every call). */\nconst limit = (fn: Fn, ms: number, leading: boolean, trailing: boolean, restart: boolean): Fn => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let last: any[] | undefined;\n const fire = () => {\n timer = undefined;\n if (trailing && last) fn(...last);\n last = undefined;\n };\n return (...args) => {\n if (timer) {\n last = args;\n if (restart) {\n clearTimeout(timer);\n timer = setTimeout(fire, ms);\n }\n return;\n }\n if (leading) fn(...args);\n else last = args;\n timer = setTimeout(fire, ms);\n };\n};\n\n/** Debounce: wait for a quiet period. `leading` fires on the first call, `trailing` on the last. */\nexport const debounce = (fn: Fn, ms: number, leading = false, trailing = true): Fn =>\n limit(fn, ms, leading, trailing, true);\n\n/** Throttle: at most one call per window. `leading` fires immediately, `trailing` fires once at the end. */\nexport const throttle = (fn: Fn, ms: number, leading = true, trailing = false): Fn =>\n limit(fn, ms, leading, trailing, false);\n\nexport const withTiming = (fn: Fn, mods: Mods): Fn => {\n const d = mods.get('delay');\n if (d) fn = delay(fn, toMs(d));\n const db = mods.get('debounce');\n if (db) fn = debounce(fn, toMs(db, 300), db.includes('leading'), !db.includes('notrailing'));\n const th = mods.get('throttle');\n if (th) fn = throttle(fn, toMs(th, 300), !th.includes('noleading'), th.includes('trailing'));\n return fn;\n};\n\nexport const withViewTransition = (fn: Fn, mods: Mods): Fn =>\n mods.has('viewtransition') && 'startViewTransition' in document\n ? (...args) => void document.startViewTransition(() => fn(...args))\n : fn;\n"],
5
- "mappings": "AAIO,MAAM,OAAO,CAAC,MAA4B,WAAW,MAAc;AACxE,aAAW,KAAK,QAAQ,CAAC,GAAG;AAC1B,UAAM,IAAI,2BAA2B,KAAK,CAAC;AAC3C,QAAI,EAAG,QAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,MAAO;AAAA,EAC/C;AACA,SAAO;AACT;AAEO,MAAM,QACX,CAAC,IAAQ,OACT,IAAI,SACF,KAAK,WAAW,IAAI,IAAI,GAAG,IAAI;AAGnC,MAAM,QAAQ,CAAC,IAAQ,IAAY,SAAkB,UAAmB,YAAyB;AAC/F,MAAI;AACJ,MAAI;AACJ,QAAM,OAAO,MAAM;AACjB,YAAQ;AACR,QAAI,YAAY,KAAM,IAAG,GAAG,IAAI;AAChC,WAAO;AAAA,EACT;AACA,SAAO,IAAI,SAAS;AAClB,QAAI,OAAO;AACT,aAAO;AACP,UAAI,SAAS;AACX,qBAAa,KAAK;AAClB,gBAAQ,WAAW,MAAM,EAAE;AAAA,MAC7B;AACA;AAAA,IACF;AACA,QAAI,QAAS,IAAG,GAAG,IAAI;AAAA,QAClB,QAAO;AACZ,YAAQ,WAAW,MAAM,EAAE;AAAA,EAC7B;AACF;AAGO,MAAM,WAAW,CAAC,IAAQ,IAAY,UAAU,OAAO,WAAW,SACvE,MAAM,IAAI,IAAI,SAAS,UAAU,IAAI;AAGhC,MAAM,WAAW,CAAC,IAAQ,IAAY,UAAU,MAAM,WAAW,UACtE,MAAM,IAAI,IAAI,SAAS,UAAU,KAAK;AAEjC,MAAM,aAAa,CAAC,IAAQ,SAAmB;AACpD,QAAM,IAAI,KAAK,IAAI,OAAO;AAC1B,MAAI,EAAG,MAAK,MAAM,IAAI,KAAK,CAAC,CAAC;AAC7B,QAAM,KAAK,KAAK,IAAI,UAAU;AAC9B,MAAI,GAAI,MAAK,SAAS,IAAI,KAAK,IAAI,GAAG,GAAG,GAAG,SAAS,SAAS,GAAG,CAAC,GAAG,SAAS,YAAY,CAAC;AAC3F,QAAM,KAAK,KAAK,IAAI,UAAU;AAC9B,MAAI,GAAI,MAAK,SAAS,IAAI,KAAK,IAAI,GAAG,GAAG,CAAC,GAAG,SAAS,WAAW,GAAG,GAAG,SAAS,UAAU,CAAC;AAC3F,SAAO;AACT;AAEO,MAAM,qBAAqB,CAAC,IAAQ,SACzC,KAAK,IAAI,gBAAgB,KAAK,yBAAyB,WACnD,IAAI,SAAS,KAAK,SAAS,oBAAoB,MAAM,GAAG,GAAG,IAAI,CAAC,IAChE;",
4
+ "sourcesContent": ["export type Mods = Map<string, string[]>;\ntype Fn = (...args: any[]) => void;\n\n/** '300ms' \u2192 300, '2s' \u2192 2000, '150' \u2192 150; `__x.1.5s` arrives split on the dot and is joined back first. */\nexport const toMs = (args: string[] | undefined, fallback = 0): number => {\n for (const a of args?.length ? [args.join('.'), ...args] : []) {\n const m = /^(\\d+(?:\\.\\d+)?)(ms|s)?$/.exec(a);\n if (m) return +m[1] * (m[2] === 's' ? 1000 : 1);\n }\n return fallback;\n};\n\nexport const delay =\n (fn: Fn, ms: number): Fn =>\n (...args) =>\n void setTimeout(fn, ms, ...args);\n\n/** Shared rate limiter. `restart` makes it a debounce (the window restarts on every call). */\ntype Limited = Fn & { cancel(): void };\nconst limit = (fn: Fn, ms: number, leading: boolean, trailing: boolean, restart: boolean): Limited => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let last: any[] | undefined;\n const fire = () => {\n timer = undefined;\n if (trailing && last) fn(...last);\n last = undefined;\n };\n const limited: Limited = (...args) => {\n if (timer) {\n last = args;\n if (restart) {\n clearTimeout(timer);\n timer = setTimeout(fire, ms);\n }\n return;\n }\n if (leading) fn(...args);\n else last = args;\n timer = setTimeout(fire, ms);\n };\n limited.cancel = () => {\n clearTimeout(timer);\n timer = last = undefined;\n };\n return limited;\n};\n\n/** Debounce: wait for a quiet period. `leading` fires on the first call, `trailing` on the last. */\nexport const debounce = (fn: Fn, ms: number, leading = false, trailing = true): Fn =>\n limit(fn, ms, leading, trailing, true);\n\n/** Throttle: at most one call per window. `leading` fires immediately, `trailing` fires once at the end. */\nexport const throttle = (fn: Fn, ms: number, leading = true, trailing = false): Fn =>\n limit(fn, ms, leading, trailing, false);\n\n/** Apply `__debounce` / `__throttle`; `cleanup` cancels a pending trailing call when the attribute unmounts. */\nexport const withTiming = (fn: Fn, mods: Mods, cleanup?: (f: () => void) => unknown): Fn => {\n const db = mods.get('debounce');\n const th = mods.get('throttle');\n if (db) fn = limit(fn, toMs(db, 300), db.includes('leading'), !db.includes('notrailing'), true);\n if (th) fn = limit(fn, toMs(th, 300), !th.includes('noleading'), th.includes('trailing'), false);\n if (db || th) cleanup?.((fn as Limited).cancel);\n return fn;\n};\n"],
5
+ "mappings": "AAIO,MAAM,OAAO,CAAC,MAA4B,WAAW,MAAc;AACxE,aAAW,KAAK,MAAM,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG;AAC7D,UAAM,IAAI,2BAA2B,KAAK,CAAC;AAC3C,QAAI,EAAG,QAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,MAAO;AAAA,EAC/C;AACA,SAAO;AACT;AAEO,MAAM,QACX,CAAC,IAAQ,OACT,IAAI,SACF,KAAK,WAAW,IAAI,IAAI,GAAG,IAAI;AAInC,MAAM,QAAQ,CAAC,IAAQ,IAAY,SAAkB,UAAmB,YAA8B;AACpG,MAAI;AACJ,MAAI;AACJ,QAAM,OAAO,MAAM;AACjB,YAAQ;AACR,QAAI,YAAY,KAAM,IAAG,GAAG,IAAI;AAChC,WAAO;AAAA,EACT;AACA,QAAM,UAAmB,IAAI,SAAS;AACpC,QAAI,OAAO;AACT,aAAO;AACP,UAAI,SAAS;AACX,qBAAa,KAAK;AAClB,gBAAQ,WAAW,MAAM,EAAE;AAAA,MAC7B;AACA;AAAA,IACF;AACA,QAAI,QAAS,IAAG,GAAG,IAAI;AAAA,QAClB,QAAO;AACZ,YAAQ,WAAW,MAAM,EAAE;AAAA,EAC7B;AACA,UAAQ,SAAS,MAAM;AACrB,iBAAa,KAAK;AAClB,YAAQ,OAAO;AAAA,EACjB;AACA,SAAO;AACT;AAGO,MAAM,WAAW,CAAC,IAAQ,IAAY,UAAU,OAAO,WAAW,SACvE,MAAM,IAAI,IAAI,SAAS,UAAU,IAAI;AAGhC,MAAM,WAAW,CAAC,IAAQ,IAAY,UAAU,MAAM,WAAW,UACtE,MAAM,IAAI,IAAI,SAAS,UAAU,KAAK;AAGjC,MAAM,aAAa,CAAC,IAAQ,MAAY,YAA6C;AAC1F,QAAM,KAAK,KAAK,IAAI,UAAU;AAC9B,QAAM,KAAK,KAAK,IAAI,UAAU;AAC9B,MAAI,GAAI,MAAK,MAAM,IAAI,KAAK,IAAI,GAAG,GAAG,GAAG,SAAS,SAAS,GAAG,CAAC,GAAG,SAAS,YAAY,GAAG,IAAI;AAC9F,MAAI,GAAI,MAAK,MAAM,IAAI,KAAK,IAAI,GAAG,GAAG,CAAC,GAAG,SAAS,WAAW,GAAG,GAAG,SAAS,UAAU,GAAG,KAAK;AAC/F,MAAI,MAAM,GAAI,WAAW,GAAe,MAAM;AAC9C,SAAO;AACT;",
6
6
  "names": []
7
7
  }