sigmx 0.1.0 → 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 (308) hide show
  1. package/README.md +54 -43
  2. package/dist/cli.js +3 -1
  3. package/dist/cli.js.map +2 -2
  4. package/dist/kernel/compile.d.ts +8 -9
  5. package/dist/kernel/compile.js +102 -67
  6. package/dist/kernel/compile.js.map +2 -2
  7. package/dist/kernel/contracts.d.ts +12 -13
  8. package/dist/kernel/index.d.ts +11 -12
  9. package/dist/kernel/index.js +14 -12
  10. package/dist/kernel/index.js.map +3 -3
  11. package/dist/kernel/precompile.d.ts +8 -12
  12. package/dist/kernel/precompile.js +33 -76
  13. package/dist/kernel/precompile.js.map +2 -2
  14. package/dist/kernel/precompiled.d.ts +7 -4
  15. package/dist/kernel/precompiled.js +5 -5
  16. package/dist/kernel/precompiled.js.map +2 -2
  17. package/dist/kernel/reactive.d.ts +13 -11
  18. package/dist/kernel/reactive.js +96 -71
  19. package/dist/kernel/reactive.js.map +3 -3
  20. package/dist/kernel/runtime.js +85 -63
  21. package/dist/kernel/runtime.js.map +3 -3
  22. package/dist/kernel/scan.d.ts +2 -11
  23. package/dist/kernel/scan.js +26 -9
  24. package/dist/kernel/scan.js.map +2 -2
  25. package/dist/kernel/state.d.ts +5 -8
  26. package/dist/kernel/state.js +114 -76
  27. package/dist/kernel/state.js.map +2 -2
  28. package/dist/kernel/strict-csp.d.ts +0 -5
  29. package/dist/kernel/strict-csp.js +2 -2
  30. package/dist/kernel/strict-csp.js.map +2 -2
  31. package/dist/lib/casing.d.ts +4 -1
  32. package/dist/lib/casing.js +8 -1
  33. package/dist/lib/casing.js.map +2 -2
  34. package/dist/lib/objects.d.ts +5 -4
  35. package/dist/lib/objects.js +13 -5
  36. package/dist/lib/objects.js.map +2 -2
  37. package/dist/lib/schedule.d.ts +3 -5
  38. package/dist/lib/schedule.js +12 -10
  39. package/dist/lib/schedule.js.map +2 -2
  40. package/dist/lib/sse.d.ts +10 -1
  41. package/dist/lib/sse.js +32 -28
  42. package/dist/lib/sse.js.map +2 -2
  43. package/dist/plugins/def.d.ts +5 -0
  44. package/dist/plugins/def.js +22 -0
  45. package/dist/plugins/def.js.map +7 -0
  46. package/dist/plugins/directives/attribute-sync.js +8 -12
  47. package/dist/plugins/directives/attribute-sync.js.map +2 -2
  48. package/dist/plugins/directives/boost.d.ts +1 -1
  49. package/dist/plugins/directives/boost.js +34 -30
  50. package/dist/plugins/directives/boost.js.map +2 -2
  51. package/dist/plugins/directives/busy-flag.js +13 -16
  52. package/dist/plugins/directives/busy-flag.js.map +2 -2
  53. package/dist/plugins/directives/class-toggle.js +17 -16
  54. package/dist/plugins/directives/class-toggle.js.map +2 -2
  55. package/dist/plugins/directives/cloak.js +2 -7
  56. package/dist/plugins/directives/cloak.js.map +2 -2
  57. package/dist/plugins/directives/collapse.js +36 -37
  58. package/dist/plugins/directives/collapse.js.map +2 -2
  59. package/dist/plugins/directives/declare.js +5 -8
  60. package/dist/plugins/directives/declare.js.map +2 -2
  61. package/dist/plugins/directives/derive.js +9 -15
  62. package/dist/plugins/directives/derive.js.map +2 -2
  63. package/dist/plugins/directives/element-ref.js +8 -8
  64. package/dist/plugins/directives/element-ref.js.map +2 -2
  65. package/dist/plugins/directives/event-listener.js +18 -23
  66. package/dist/plugins/directives/event-listener.js.map +2 -2
  67. package/dist/plugins/directives/frame-loop.js +9 -14
  68. package/dist/plugins/directives/frame-loop.js.map +2 -2
  69. package/dist/plugins/directives/html.js +6 -7
  70. package/dist/plugins/directives/html.js.map +2 -2
  71. package/dist/plugins/directives/inline-style.js +17 -20
  72. package/dist/plugins/directives/inline-style.js.map +2 -2
  73. package/dist/plugins/directives/mask.js +19 -23
  74. package/dist/plugins/directives/mask.js.map +2 -2
  75. package/dist/plugins/directives/media-query.d.ts +4 -1
  76. package/dist/plugins/directives/media-query.js +13 -12
  77. package/dist/plugins/directives/media-query.js.map +2 -2
  78. package/dist/plugins/directives/on-mount.js +4 -9
  79. package/dist/plugins/directives/on-mount.js.map +2 -2
  80. package/dist/plugins/directives/patch-listener.js +24 -19
  81. package/dist/plugins/directives/patch-listener.js.map +2 -2
  82. package/dist/plugins/directives/remove-me.js +7 -8
  83. package/dist/plugins/directives/remove-me.js.map +2 -2
  84. package/dist/plugins/directives/scroll-to.d.ts +4 -1
  85. package/dist/plugins/directives/scroll-to.js +8 -14
  86. package/dist/plugins/directives/scroll-to.js.map +2 -2
  87. package/dist/plugins/directives/size-watch.js +7 -12
  88. package/dist/plugins/directives/size-watch.js.map +2 -2
  89. package/dist/plugins/directives/state-dump.js +6 -10
  90. package/dist/plugins/directives/state-dump.js.map +2 -2
  91. package/dist/plugins/directives/storage-sync.js +13 -9
  92. package/dist/plugins/directives/storage-sync.js.map +2 -2
  93. package/dist/plugins/directives/teleport.js +8 -14
  94. package/dist/plugins/directives/teleport.js.map +2 -2
  95. package/dist/plugins/directives/text-content.js +6 -7
  96. package/dist/plugins/directives/text-content.js.map +2 -2
  97. package/dist/plugins/directives/timer.js +7 -13
  98. package/dist/plugins/directives/timer.js.map +2 -2
  99. package/dist/plugins/directives/transition.d.ts +1 -2
  100. package/dist/plugins/directives/transition.js +32 -34
  101. package/dist/plugins/directives/transition.js.map +2 -2
  102. package/dist/plugins/directives/tween.d.ts +2 -2
  103. package/dist/plugins/directives/tween.js +34 -50
  104. package/dist/plugins/directives/tween.js.map +2 -2
  105. package/dist/plugins/directives/two-way-bind.d.ts +1 -1
  106. package/dist/plugins/directives/two-way-bind.js +70 -67
  107. package/dist/plugins/directives/two-way-bind.js.map +2 -2
  108. package/dist/plugins/directives/url-params.js +36 -59
  109. package/dist/plugins/directives/url-params.js.map +3 -3
  110. package/dist/plugins/directives/url-replace.js +6 -7
  111. package/dist/plugins/directives/url-replace.js.map +2 -2
  112. package/dist/plugins/directives/validity.js +6 -9
  113. package/dist/plugins/directives/validity.js.map +2 -2
  114. package/dist/plugins/directives/viewport.js +18 -23
  115. package/dist/plugins/directives/viewport.js.map +2 -2
  116. package/dist/plugins/directives/visibility.js +9 -14
  117. package/dist/plugins/directives/visibility.js.map +2 -2
  118. package/dist/plugins/directives/watch.d.ts +0 -1
  119. package/dist/plugins/directives/watch.js +2 -8
  120. package/dist/plugins/directives/watch.js.map +2 -2
  121. package/dist/plugins/functions/bulk-set.js +10 -7
  122. package/dist/plugins/functions/bulk-set.js.map +2 -2
  123. package/dist/plugins/functions/bulk-toggle.js +10 -7
  124. package/dist/plugins/functions/bulk-toggle.js.map +2 -2
  125. package/dist/plugins/functions/confirm.js +2 -2
  126. package/dist/plugins/functions/confirm.js.map +2 -2
  127. package/dist/plugins/functions/copy-text.js +5 -5
  128. package/dist/plugins/functions/copy-text.js.map +2 -2
  129. package/dist/plugins/functions/dispatch.js +5 -5
  130. package/dist/plugins/functions/dispatch.js.map +2 -2
  131. package/dist/plugins/functions/locale-format.d.ts +4 -1
  132. package/dist/plugins/functions/locale-format.js +9 -16
  133. package/dist/plugins/functions/locale-format.js.map +2 -2
  134. package/dist/plugins/functions/range-map.js +6 -6
  135. package/dist/plugins/functions/range-map.js.map +2 -2
  136. package/dist/plugins/functions/request.d.ts +7 -3
  137. package/dist/plugins/functions/request.js +85 -80
  138. package/dist/plugins/functions/request.js.map +2 -2
  139. package/dist/plugins/functions/untracked-read.js +3 -2
  140. package/dist/plugins/functions/untracked-read.js.map +2 -2
  141. package/dist/plugins/functions/websocket.d.ts +3 -3
  142. package/dist/plugins/functions/websocket.js +18 -25
  143. package/dist/plugins/functions/websocket.js.map +2 -2
  144. package/dist/plugins/index.d.ts +34 -36
  145. package/dist/plugins/index.js +31 -35
  146. package/dist/plugins/index.js.map +2 -2
  147. package/dist/plugins/server-events/apply-elements.d.ts +1 -1
  148. package/dist/plugins/server-events/apply-elements.js +41 -40
  149. package/dist/plugins/server-events/apply-elements.js.map +2 -2
  150. package/dist/plugins/server-events/apply-state.js +9 -12
  151. package/dist/plugins/server-events/apply-state.js.map +2 -2
  152. package/dist/plugins/server-events/morph.d.ts +0 -2
  153. package/dist/plugins/server-events/morph.js +58 -55
  154. package/dist/plugins/server-events/morph.js.map +3 -3
  155. package/dist/presets/all.d.ts +0 -1
  156. package/dist/presets/all.js +22 -26
  157. package/dist/presets/all.js.map +2 -2
  158. package/dist/presets/essentials.d.ts +0 -1
  159. package/dist/presets/essentials.js +27 -9
  160. package/dist/presets/essentials.js.map +2 -2
  161. package/dist/presets/minimal.d.ts +0 -1
  162. package/dist/presets/minimal.js +2 -2
  163. package/dist/presets/minimal.js.map +2 -2
  164. package/dist/server.d.ts +108 -0
  165. package/dist/server.js +218 -0
  166. package/dist/server.js.map +7 -0
  167. package/dist/sigmx.standalone.js +1 -1
  168. package/dist/standalone.js.map +2 -2
  169. package/dist/vite.d.ts +2 -2
  170. package/dist/vite.js +48 -15
  171. package/dist/vite.js.map +2 -2
  172. package/package.json +21 -2
  173. package/dist/auto.d.ts +0 -1
  174. package/dist/auto.js +0 -7
  175. package/dist/auto.js.map +0 -7
  176. package/dist/core/csp.d.ts +0 -7
  177. package/dist/core/csp.js +0 -20
  178. package/dist/core/csp.js.map +0 -7
  179. package/dist/core/engine.d.ts +0 -10
  180. package/dist/core/engine.js +0 -200
  181. package/dist/core/engine.js.map +0 -7
  182. package/dist/core/expr.d.ts +0 -12
  183. package/dist/core/expr.js +0 -94
  184. package/dist/core/expr.js.map +0 -7
  185. package/dist/core/index.d.ts +0 -16
  186. package/dist/core/index.js +0 -46
  187. package/dist/core/index.js.map +0 -7
  188. package/dist/core/signals.d.ts +0 -42
  189. package/dist/core/signals.js +0 -195
  190. package/dist/core/signals.js.map +0 -7
  191. package/dist/core/store.d.ts +0 -32
  192. package/dist/core/store.js +0 -185
  193. package/dist/core/store.js.map +0 -7
  194. package/dist/core/types.d.ts +0 -101
  195. package/dist/core/types.js +0 -1
  196. package/dist/core/types.js.map +0 -7
  197. package/dist/plugins/actions/clipboard.d.ts +0 -2
  198. package/dist/plugins/actions/clipboard.js +0 -11
  199. package/dist/plugins/actions/clipboard.js.map +0 -7
  200. package/dist/plugins/actions/fit.d.ts +0 -2
  201. package/dist/plugins/actions/fit.js +0 -14
  202. package/dist/plugins/actions/fit.js.map +0 -7
  203. package/dist/plugins/actions/intl.d.ts +0 -2
  204. package/dist/plugins/actions/intl.js +0 -21
  205. package/dist/plugins/actions/intl.js.map +0 -7
  206. package/dist/plugins/actions/peek.d.ts +0 -2
  207. package/dist/plugins/actions/peek.js +0 -6
  208. package/dist/plugins/actions/peek.js.map +0 -7
  209. package/dist/plugins/actions/setAll.d.ts +0 -2
  210. package/dist/plugins/actions/setAll.js +0 -11
  211. package/dist/plugins/actions/setAll.js.map +0 -7
  212. package/dist/plugins/actions/toggleAll.d.ts +0 -2
  213. package/dist/plugins/actions/toggleAll.js +0 -11
  214. package/dist/plugins/actions/toggleAll.js.map +0 -7
  215. package/dist/plugins/attributes/attr.d.ts +0 -2
  216. package/dist/plugins/attributes/attr.js +0 -20
  217. package/dist/plugins/attributes/attr.js.map +0 -7
  218. package/dist/plugins/attributes/bind.d.ts +0 -6
  219. package/dist/plugins/attributes/bind.js +0 -81
  220. package/dist/plugins/attributes/bind.js.map +0 -7
  221. package/dist/plugins/attributes/class.d.ts +0 -2
  222. package/dist/plugins/attributes/class.js +0 -22
  223. package/dist/plugins/attributes/class.js.map +0 -7
  224. package/dist/plugins/attributes/computed.d.ts +0 -2
  225. package/dist/plugins/attributes/computed.js +0 -20
  226. package/dist/plugins/attributes/computed.js.map +0 -7
  227. package/dist/plugins/attributes/customValidity.d.ts +0 -2
  228. package/dist/plugins/attributes/customValidity.js +0 -14
  229. package/dist/plugins/attributes/customValidity.js.map +0 -7
  230. package/dist/plugins/attributes/effect.d.ts +0 -2
  231. package/dist/plugins/attributes/effect.js +0 -12
  232. package/dist/plugins/attributes/effect.js.map +0 -7
  233. package/dist/plugins/attributes/indicator.d.ts +0 -2
  234. package/dist/plugins/attributes/indicator.js +0 -20
  235. package/dist/plugins/attributes/indicator.js.map +0 -7
  236. package/dist/plugins/attributes/init.d.ts +0 -2
  237. package/dist/plugins/attributes/init.js +0 -14
  238. package/dist/plugins/attributes/init.js.map +0 -7
  239. package/dist/plugins/attributes/jsonSignals.d.ts +0 -2
  240. package/dist/plugins/attributes/jsonSignals.js +0 -15
  241. package/dist/plugins/attributes/jsonSignals.js.map +0 -7
  242. package/dist/plugins/attributes/matchMedia.d.ts +0 -2
  243. package/dist/plugins/attributes/matchMedia.js +0 -19
  244. package/dist/plugins/attributes/matchMedia.js.map +0 -7
  245. package/dist/plugins/attributes/on.d.ts +0 -5
  246. package/dist/plugins/attributes/on.js +0 -28
  247. package/dist/plugins/attributes/on.js.map +0 -7
  248. package/dist/plugins/attributes/onIntersect.d.ts +0 -2
  249. package/dist/plugins/attributes/onIntersect.js +0 -28
  250. package/dist/plugins/attributes/onIntersect.js.map +0 -7
  251. package/dist/plugins/attributes/onInterval.d.ts +0 -2
  252. package/dist/plugins/attributes/onInterval.js +0 -18
  253. package/dist/plugins/attributes/onInterval.js.map +0 -7
  254. package/dist/plugins/attributes/onRaf.d.ts +0 -1
  255. package/dist/plugins/attributes/onRaf.js +0 -19
  256. package/dist/plugins/attributes/onRaf.js.map +0 -7
  257. package/dist/plugins/attributes/onResize.d.ts +0 -1
  258. package/dist/plugins/attributes/onResize.js +0 -17
  259. package/dist/plugins/attributes/onResize.js.map +0 -7
  260. package/dist/plugins/attributes/onSignalPatch.d.ts +0 -5
  261. package/dist/plugins/attributes/onSignalPatch.js +0 -35
  262. package/dist/plugins/attributes/onSignalPatch.js.map +0 -7
  263. package/dist/plugins/attributes/persist.d.ts +0 -6
  264. package/dist/plugins/attributes/persist.js +0 -16
  265. package/dist/plugins/attributes/persist.js.map +0 -7
  266. package/dist/plugins/attributes/queryString.d.ts +0 -5
  267. package/dist/plugins/attributes/queryString.js +0 -54
  268. package/dist/plugins/attributes/queryString.js.map +0 -7
  269. package/dist/plugins/attributes/ref.d.ts +0 -2
  270. package/dist/plugins/attributes/ref.js +0 -13
  271. package/dist/plugins/attributes/ref.js.map +0 -7
  272. package/dist/plugins/attributes/replaceUrl.d.ts +0 -1
  273. package/dist/plugins/attributes/replaceUrl.js +0 -11
  274. package/dist/plugins/attributes/replaceUrl.js.map +0 -7
  275. package/dist/plugins/attributes/scrollIntoView.d.ts +0 -2
  276. package/dist/plugins/attributes/scrollIntoView.js +0 -19
  277. package/dist/plugins/attributes/scrollIntoView.js.map +0 -7
  278. package/dist/plugins/attributes/show.d.ts +0 -2
  279. package/dist/plugins/attributes/show.js +0 -19
  280. package/dist/plugins/attributes/show.js.map +0 -7
  281. package/dist/plugins/attributes/signals.d.ts +0 -2
  282. package/dist/plugins/attributes/signals.js +0 -13
  283. package/dist/plugins/attributes/signals.js.map +0 -7
  284. package/dist/plugins/attributes/style.d.ts +0 -2
  285. package/dist/plugins/attributes/style.js +0 -25
  286. package/dist/plugins/attributes/style.js.map +0 -7
  287. package/dist/plugins/attributes/text.d.ts +0 -1
  288. package/dist/plugins/attributes/text.js +0 -13
  289. package/dist/plugins/attributes/text.js.map +0 -7
  290. package/dist/plugins/attributes/viewTransition.d.ts +0 -1
  291. package/dist/plugins/attributes/viewTransition.js +0 -11
  292. package/dist/plugins/attributes/viewTransition.js.map +0 -7
  293. package/dist/plugins/directives/transition-name.d.ts +0 -1
  294. package/dist/plugins/directives/transition-name.js +0 -11
  295. package/dist/plugins/directives/transition-name.js.map +0 -7
  296. package/dist/plugins/directives/trap.d.ts +0 -5
  297. package/dist/plugins/directives/trap.js +0 -48
  298. package/dist/plugins/directives/trap.js.map +0 -7
  299. package/dist/sigmx.auto.js +0 -5
  300. package/dist/utils/object.d.ts +0 -9
  301. package/dist/utils/object.js +0 -26
  302. package/dist/utils/object.js.map +0 -7
  303. package/dist/utils/text.d.ts +0 -7
  304. package/dist/utils/text.js +0 -15
  305. package/dist/utils/text.js.map +0 -7
  306. package/dist/utils/timing.d.ts +0 -14
  307. package/dist/utils/timing.js +0 -58
  308. package/dist/utils/timing.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/state.ts"],
4
- "sourcesContent": ["// Path-keyed signal store with JSON merge-patch semantics. No DOM dependency.\nimport { Computed, Signal, batch, onSettled } from './reactive.js'\nimport { expand, isPlain, toPredicate, type Filter } from '../lib/objects.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 /** Install a computed (or any signal) as the leaf at a path. */\n define(path: string, node: Signal<any>): void\n /** Leaf paths, optionally filtered. */\n paths(filter?: Filter): string[]\n /** Plain-object copy of the store or a namespace. */\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 /** Root namespace proxy: `$.count`, `$.user.name = 'x'`, `JSON.stringify($)`. */\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 kids.set(p, (set = new 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) => ((t as any)[k] = v, touch(), true),\n deleteProperty: (t, k) => (delete (t as any)[k], touch(), true),\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 = () => (shape.value, kids.get(p))\n px = new Proxy({}, {\n get: (_, k) => (!str(k) ? undefined : k === 'toJSON' ? () => snapshot(undefined, { at: p }) : get(join(p, k))),\n set: (_, k, v) => (str(k) && set(join(p, k), v), true),\n deleteProperty: (_, k) => (str(k) && remove(join(p, k)), true),\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 nsCache.set(p, px)\n }\n return px\n }\n\n const scope = new Proxy({}, {\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 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) => (listeners.add(fn), () => listeners.delete(fn)),\n get $() {\n return ns('')\n },\n scope,\n }\n}\n"],
5
- "mappings": "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",
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\n/** Split an identifier in any common casing into lowercase words. */\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 => words(s).map((w, i) => (i ? cap(w) : w)).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": "AAGA,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,MAAsB,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,MAAO,IAAI,IAAI,CAAC,IAAI,CAAE,EAAE,KAAK,EAAE;AACrF,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,9 +1,10 @@
1
1
  export declare const isPlain: (v: unknown) => v is Record<string, any>;
2
- /** Write `value` at a dotted path inside `out`, creating intermediate objects. */
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;
3
4
  export declare const expand: (out: Record<string, any>, path: string, value: any) => Record<string, any>;
4
5
  export type Filter = {
5
- include?: RegExp | string;
6
- exclude?: RegExp | string;
6
+ include?: RegExp;
7
+ exclude?: RegExp;
7
8
  } | ((path: string) => boolean);
8
- /** 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. */
9
10
  export declare const toPredicate: (f?: Filter) => ((path: string) => boolean);
@@ -3,24 +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
- for (const k of keys) cur = isPlain(cur[k]) ? cur[k] : cur[k] = {};
12
+ for (const k of keys) {
13
+ if (!isPlain(cur[k]) || !Object.hasOwn(cur, k)) cur[k] = {};
14
+ cur = cur[k];
15
+ }
11
16
  cur[last] = value;
12
17
  return out;
13
18
  };
14
- const re = (v, fallback) => v === void 0 ? fallback : typeof v === "string" ? new RegExp(v.replace(/^\/|\/$/g, "")) : v;
15
19
  const toPredicate = (f) => {
16
20
  if (typeof f === "function") return f;
17
- const inc = re(f?.include, /(?:)/);
18
- const exc = re(f?.exclude, /(?!)/);
19
- 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);
20
27
  };
21
28
  export {
22
29
  expand,
23
30
  isPlain,
31
+ safeKey,
24
32
  toPredicate
25
33
  };
26
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\n/** Write `value` at a dotted path inside `out`, creating intermediate objects. */\nexport const expand = (out: Record<string, any>, path: string, value: any): Record<string, any> => {\n const keys = path.split('.')\n const last = keys.pop()!\n let cur = out\n for (const k of keys) cur = isPlain(cur[k]) ? cur[k] : (cur[k] = {})\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;AAGO,MAAM,SAAS,CAAC,KAA0B,MAAc,UAAoC;AACjG,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,QAAM,OAAO,KAAK,IAAI;AACtB,MAAI,MAAM;AACV,aAAW,KAAK,KAAM,OAAM,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,IAAK,IAAI,CAAC,IAAI,CAAC;AAClE,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,14 +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
- /** Apply `__delay`, `__debounce` and `__throttle` modifiers to a callback. */
11
- export declare const withTiming: (fn: Fn, mods: Mods) => Fn;
12
- /** Wrap a callback in `document.startViewTransition` when `__viewtransition` is present and supported. */
13
- 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;
14
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 = (fn: Fn, ms: number): Fn => (...args) => 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 => 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 => limit(fn, ms, leading, trailing, false)\n\n/** Apply `__delay`, `__debounce` and `__throttle` modifiers to a callback. */\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\n/** Wrap a callback in `document.startViewTransition` when `__viewtransition` is present and supported. */\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,QAAQ,CAAC,IAAQ,OAAmB,IAAI,SAAS,KAAK,WAAW,IAAI,IAAI,GAAG,IAAI;AAG7F,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,SAAa,MAAM,IAAI,IAAI,SAAS,UAAU,IAAI;AAGpH,MAAM,WAAW,CAAC,IAAQ,IAAY,UAAU,MAAM,WAAW,UAAc,MAAM,IAAI,IAAI,SAAS,UAAU,KAAK;AAGrH,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;AAGO,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
  }
package/dist/lib/sse.d.ts CHANGED
@@ -4,7 +4,16 @@ export type ServerEvent = {
4
4
  id?: string;
5
5
  retry?: number;
6
6
  };
7
- /** Read a `text/event-stream` body, calling `onEvent` for each complete event. Resolves when the stream ends. */
7
+ type StreamState = {
8
+ id?: string;
9
+ retry?: number;
10
+ };
11
+ /**
12
+ * Parse one blank-line-delimited block of `field: value` lines (the SSE wire format). `id` and
13
+ * `retry` persist in `state` across blocks; comments start with `:`. Undefined without data lines.
14
+ */
15
+ export declare const parseBlock: (block: string, state?: StreamState) => ServerEvent | undefined;
8
16
  export declare const readEvents: (body: ReadableStream<Uint8Array>, onEvent: (e: ServerEvent) => void) => Promise<void>;
9
17
  /** Event payloads: each data line is `key value`; repeated keys join with newlines. */
10
18
  export declare const parseFields: (data: string) => Record<string, string>;
19
+ export {};
package/dist/lib/sse.js CHANGED
@@ -1,41 +1,44 @@
1
- const readEvents = async (body, onEvent) => {
2
- const reader = body.getReader();
3
- const decoder = new TextDecoder();
4
- let buffer = "";
1
+ const parseBlock = (block, state = {}) => {
5
2
  let event = "";
6
- let data = [];
7
- let id;
8
- let retry;
9
- const flush = () => {
10
- if (data.length) onEvent({ event: event || "message", data: data.join("\n"), id, retry });
11
- event = "";
12
- data = [];
13
- };
14
- const line = (l) => {
15
- if (!l) return flush();
16
- if (l[0] === ":") return;
3
+ const data = [];
4
+ for (const l of block.split(/\r?\n/)) {
17
5
  const c = l.indexOf(":");
6
+ if (!c) continue;
18
7
  const field = c < 0 ? l : l.slice(0, c);
19
- let v = c < 0 ? "" : l.slice(c + 1);
20
- if (v[0] === " ") v = v.slice(1);
8
+ const v = (c < 0 ? "" : l.slice(c + 1)).replace(/^ /, "");
21
9
  if (field === "event") event = v;
22
10
  else if (field === "data") data.push(v);
23
- else if (field === "id") id = v;
24
- else if (field === "retry" && /^\d+$/.test(v)) retry = +v;
11
+ else if (field === "id") state.id = v;
12
+ else if (field === "retry" && /^\d+$/.test(v)) state.retry = +v;
13
+ }
14
+ if (data.length) return { event: event || "message", data: data.join("\n"), id: state.id, retry: state.retry };
15
+ };
16
+ const readEvents = async (body, onEvent) => {
17
+ const reader = body.getReader();
18
+ const decoder = new TextDecoder();
19
+ const state = {};
20
+ let buffer = "";
21
+ let scan = 0;
22
+ const dispatch = (block) => {
23
+ const e = parseBlock(block, state);
24
+ if (e) onEvent(e);
25
25
  };
26
26
  for (; ; ) {
27
27
  const { value, done } = await reader.read();
28
- if (done) break;
29
- buffer += decoder.decode(value, { stream: true });
30
- let i;
31
- while ((i = buffer.search(/\r\n|\r|\n/)) >= 0) {
32
- const l = buffer.slice(0, i);
33
- buffer = buffer.slice(i + (buffer[i] === "\r" && buffer[i + 1] === "\n" ? 2 : 1));
34
- line(l);
28
+ buffer += decoder.decode(value, { stream: !done });
29
+ const sep = /\r?\n\r?\n/g;
30
+ sep.lastIndex = scan;
31
+ for (let m = sep.exec(buffer); m; m = sep.exec(buffer)) {
32
+ dispatch(buffer.slice(0, m.index));
33
+ buffer = buffer.slice(m.index + m[0].length);
34
+ sep.lastIndex = 0;
35
+ }
36
+ scan = Math.max(0, buffer.length - 3);
37
+ if (done) {
38
+ dispatch(buffer);
39
+ break;
35
40
  }
36
41
  }
37
- if (buffer) line(buffer);
38
- flush();
39
42
  };
40
43
  const parseFields = (data) => {
41
44
  const out = {};
@@ -49,6 +52,7 @@ ${v}` : v;
49
52
  return out;
50
53
  };
51
54
  export {
55
+ parseBlock,
52
56
  parseFields,
53
57
  readEvents
54
58
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/sse.ts"],
4
- "sourcesContent": ["export type ServerEvent = { event: string; data: string; id?: string; retry?: number }\n\n/** Read a `text/event-stream` body, calling `onEvent` for each complete event. Resolves when the stream ends. */\nexport const readEvents = async (body: ReadableStream<Uint8Array>, onEvent: (e: ServerEvent) => void): Promise<void> => {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let event = ''\n let data: string[] = []\n let id: string | undefined\n let retry: number | undefined\n const flush = () => {\n if (data.length) onEvent({ event: event || 'message', data: data.join('\\n'), id, retry })\n event = ''\n data = []\n }\n const line = (l: string) => {\n if (!l) return flush()\n if (l[0] === ':') return\n const c = l.indexOf(':')\n const field = c < 0 ? l : l.slice(0, c)\n let v = c < 0 ? '' : l.slice(c + 1)\n if (v[0] === ' ') v = v.slice(1)\n if (field === 'event') event = v\n else if (field === 'data') data.push(v)\n else if (field === 'id') id = v\n else if (field === 'retry' && /^\\d+$/.test(v)) retry = +v\n }\n for (;;) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n let i: number\n while ((i = buffer.search(/\\r\\n|\\r|\\n/)) >= 0) {\n const l = buffer.slice(0, i)\n buffer = buffer.slice(i + (buffer[i] === '\\r' && buffer[i + 1] === '\\n' ? 2 : 1))\n line(l)\n }\n }\n if (buffer) line(buffer)\n flush()\n}\n\n/** Event payloads: each data line is `key value`; repeated keys join with newlines. */\nexport const parseFields = (data: string): Record<string, string> => {\n const out: Record<string, string> = {}\n for (const l of data.split('\\n')) {\n const i = l.indexOf(' ')\n const k = i < 0 ? l : l.slice(0, i)\n const v = i < 0 ? '' : l.slice(i + 1)\n out[k] = k in out ? `${out[k]}\\n${v}` : v\n }\n return out\n}\n"],
5
- "mappings": "AAGO,MAAM,aAAa,OAAO,MAAkC,YAAqD;AACtH,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,QAAQ;AACZ,MAAI,OAAiB,CAAC;AACtB,MAAI;AACJ,MAAI;AACJ,QAAM,QAAQ,MAAM;AAClB,QAAI,KAAK,OAAQ,SAAQ,EAAE,OAAO,SAAS,WAAW,MAAM,KAAK,KAAK,IAAI,GAAG,IAAI,MAAM,CAAC;AACxF,YAAQ;AACR,WAAO,CAAC;AAAA,EACV;AACA,QAAM,OAAO,CAAC,MAAc;AAC1B,QAAI,CAAC,EAAG,QAAO,MAAM;AACrB,QAAI,EAAE,CAAC,MAAM,IAAK;AAClB,UAAM,IAAI,EAAE,QAAQ,GAAG;AACvB,UAAM,QAAQ,IAAI,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC;AACtC,QAAI,IAAI,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC;AAClC,QAAI,EAAE,CAAC,MAAM,IAAK,KAAI,EAAE,MAAM,CAAC;AAC/B,QAAI,UAAU,QAAS,SAAQ;AAAA,aACtB,UAAU,OAAQ,MAAK,KAAK,CAAC;AAAA,aAC7B,UAAU,KAAM,MAAK;AAAA,aACrB,UAAU,WAAW,QAAQ,KAAK,CAAC,EAAG,SAAQ,CAAC;AAAA,EAC1D;AACA,aAAS;AACP,UAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,QAAI;AACJ,YAAQ,IAAI,OAAO,OAAO,YAAY,MAAM,GAAG;AAC7C,YAAM,IAAI,OAAO,MAAM,GAAG,CAAC;AAC3B,eAAS,OAAO,MAAM,KAAK,OAAO,CAAC,MAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,OAAO,IAAI,EAAE;AAChF,WAAK,CAAC;AAAA,IACR;AAAA,EACF;AACA,MAAI,OAAQ,MAAK,MAAM;AACvB,QAAM;AACR;AAGO,MAAM,cAAc,CAAC,SAAyC;AACnE,QAAM,MAA8B,CAAC;AACrC,aAAW,KAAK,KAAK,MAAM,IAAI,GAAG;AAChC,UAAM,IAAI,EAAE,QAAQ,GAAG;AACvB,UAAM,IAAI,IAAI,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC;AAClC,UAAM,IAAI,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC;AACpC,QAAI,CAAC,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,EAAK,CAAC,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["export type ServerEvent = { event: string; data: string; id?: string; retry?: number };\ntype StreamState = { id?: string; retry?: number };\n\n/**\n * Parse one blank-line-delimited block of `field: value` lines (the SSE wire format). `id` and\n * `retry` persist in `state` across blocks; comments start with `:`. Undefined without data lines.\n */\nexport const parseBlock = (block: string, state: StreamState = {}): ServerEvent | undefined => {\n let event = '';\n const data: string[] = [];\n for (const l of block.split(/\\r?\\n/)) {\n const c = l.indexOf(':');\n if (!c) continue;\n const field = c < 0 ? l : l.slice(0, c);\n const v = (c < 0 ? '' : l.slice(c + 1)).replace(/^ /, '');\n if (field === 'event') event = v;\n else if (field === 'data') data.push(v);\n else if (field === 'id') state.id = v;\n else if (field === 'retry' && /^\\d+$/.test(v)) state.retry = +v;\n }\n if (data.length) return { event: event || 'message', data: data.join('\\n'), id: state.id, retry: state.retry };\n};\n\nexport const readEvents = async (\n body: ReadableStream<Uint8Array>,\n onEvent: (e: ServerEvent) => void,\n): Promise<void> => {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n const state: StreamState = {};\n let buffer = '';\n let scan = 0; // where the next separator search starts: no rescanning of a large partial event\n const dispatch = (block: string) => {\n const e = parseBlock(block, state);\n if (e) onEvent(e);\n };\n for (;;) {\n const { value, done } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n const sep = /\\r?\\n\\r?\\n/g;\n sep.lastIndex = scan;\n for (let m = sep.exec(buffer); m; m = sep.exec(buffer)) {\n dispatch(buffer.slice(0, m.index));\n buffer = buffer.slice(m.index + m[0].length);\n sep.lastIndex = 0;\n }\n scan = Math.max(0, buffer.length - 3);\n if (done) {\n dispatch(buffer);\n break;\n }\n }\n};\n\n/** Event payloads: each data line is `key value`; repeated keys join with newlines. */\nexport const parseFields = (data: string): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const l of data.split('\\n')) {\n const i = l.indexOf(' ');\n const k = i < 0 ? l : l.slice(0, i);\n const v = i < 0 ? '' : l.slice(i + 1);\n out[k] = k in out ? `${out[k]}\\n${v}` : v;\n }\n return out;\n};\n"],
5
+ "mappings": "AAOO,MAAM,aAAa,CAAC,OAAe,QAAqB,CAAC,MAA+B;AAC7F,MAAI,QAAQ;AACZ,QAAM,OAAiB,CAAC;AACxB,aAAW,KAAK,MAAM,MAAM,OAAO,GAAG;AACpC,UAAM,IAAI,EAAE,QAAQ,GAAG;AACvB,QAAI,CAAC,EAAG;AACR,UAAM,QAAQ,IAAI,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC;AACtC,UAAM,KAAK,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC,GAAG,QAAQ,MAAM,EAAE;AACxD,QAAI,UAAU,QAAS,SAAQ;AAAA,aACtB,UAAU,OAAQ,MAAK,KAAK,CAAC;AAAA,aAC7B,UAAU,KAAM,OAAM,KAAK;AAAA,aAC3B,UAAU,WAAW,QAAQ,KAAK,CAAC,EAAG,OAAM,QAAQ,CAAC;AAAA,EAChE;AACA,MAAI,KAAK,OAAQ,QAAO,EAAE,OAAO,SAAS,WAAW,MAAM,KAAK,KAAK,IAAI,GAAG,IAAI,MAAM,IAAI,OAAO,MAAM,MAAM;AAC/G;AAEO,MAAM,aAAa,OACxB,MACA,YACkB;AAClB,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,QAAqB,CAAC;AAC5B,MAAI,SAAS;AACb,MAAI,OAAO;AACX,QAAM,WAAW,CAAC,UAAkB;AAClC,UAAM,IAAI,WAAW,OAAO,KAAK;AACjC,QAAI,EAAG,SAAQ,CAAC;AAAA,EAClB;AACA,aAAS;AACP,UAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;AACjD,UAAM,MAAM;AACZ,QAAI,YAAY;AAChB,aAAS,IAAI,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI,IAAI,KAAK,MAAM,GAAG;AACtD,eAAS,OAAO,MAAM,GAAG,EAAE,KAAK,CAAC;AACjC,eAAS,OAAO,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM;AAC3C,UAAI,YAAY;AAAA,IAClB;AACA,WAAO,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC;AACpC,QAAI,MAAM;AACR,eAAS,MAAM;AACf;AAAA,IACF;AAAA,EACF;AACF;AAGO,MAAM,cAAc,CAAC,SAAyC;AACnE,QAAM,MAA8B,CAAC;AACrC,aAAW,KAAK,KAAK,MAAM,IAAI,GAAG;AAChC,UAAM,IAAI,EAAE,QAAQ,GAAG;AACvB,UAAM,IAAI,IAAI,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC;AAClC,UAAM,IAAI,IAAI,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC;AACpC,QAAI,CAAC,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,EAAK,CAAC,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,5 @@
1
+ import type { ActionPlugin, AttributePlugin, HandlerPlugin } from '../kernel/contracts.js';
2
+ /** Flags: 1 key required, 2 key forbidden, 4 value required, 8 value forbidden, 32 the value is a literal (`__dynamic` opts into an expression). */
3
+ export declare const dir: (name: string, flags: number, mount: AttributePlugin["mount"], args?: string[]) => AttributePlugin;
4
+ export declare const act: (name: string, call: ActionPlugin["call"]) => ActionPlugin;
5
+ export declare const srv: (name: string, handle: HandlerPlugin["handle"]) => HandlerPlugin;
@@ -0,0 +1,22 @@
1
+ const rule = (flags, required, forbidden) => flags & required ? "required" : flags & forbidden ? "forbidden" : void 0;
2
+ const dir = (name, flags, mount, args) => ({
3
+ type: "attribute",
4
+ name,
5
+ key: rule(flags, 1, 2),
6
+ value: rule(flags, 4, 8),
7
+ literal: !!(flags & 32),
8
+ args,
9
+ mount
10
+ });
11
+ const act = (name, call) => ({ type: "action", name, call });
12
+ const srv = (name, handle) => ({
13
+ type: "handler",
14
+ name,
15
+ handle
16
+ });
17
+ export {
18
+ act,
19
+ dir,
20
+ srv
21
+ };
22
+ //# sourceMappingURL=def.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/plugins/def.ts"],
4
+ "sourcesContent": ["// Compact constructors for the built-in plugins. They build the same objects as `attribute()`,\n// `action()` and `handler()` from the kernel; the numeric flags keep the bundle small.\nimport type { ActionPlugin, AttributePlugin, HandlerPlugin } from '../kernel/contracts.js';\n\ntype Rule = 'required' | 'forbidden' | undefined;\nconst rule = (flags: number, required: number, forbidden: number): Rule =>\n flags & required ? 'required' : flags & forbidden ? 'forbidden' : undefined;\n\n/** Flags: 1 key required, 2 key forbidden, 4 value required, 8 value forbidden, 32 the value is a literal (`__dynamic` opts into an expression). */\nexport const dir = (\n name: string,\n flags: number,\n mount: AttributePlugin['mount'],\n args?: string[],\n): AttributePlugin => ({\n type: 'attribute',\n name,\n key: rule(flags, 1, 2),\n value: rule(flags, 4, 8),\n literal: !!(flags & 32),\n args,\n mount,\n});\nexport const act = (name: string, call: ActionPlugin['call']): ActionPlugin => ({ type: 'action', name, call });\nexport const srv = (name: string, handle: HandlerPlugin['handle']): HandlerPlugin => ({\n type: 'handler',\n name,\n handle,\n});\n"],
5
+ "mappings": "AAKA,MAAM,OAAO,CAAC,OAAe,UAAkB,cAC7C,QAAQ,WAAW,aAAa,QAAQ,YAAY,cAAc;AAG7D,MAAM,MAAM,CACjB,MACA,OACA,OACA,UACqB;AAAA,EACrB,MAAM;AAAA,EACN;AAAA,EACA,KAAK,KAAK,OAAO,GAAG,CAAC;AAAA,EACrB,OAAO,KAAK,OAAO,GAAG,CAAC;AAAA,EACvB,SAAS,CAAC,EAAE,QAAQ;AAAA,EACpB;AAAA,EACA;AACF;AACO,MAAM,MAAM,CAAC,MAAc,UAA8C,EAAE,MAAM,UAAU,MAAM,KAAK;AACtG,MAAM,MAAM,CAAC,MAAc,YAAoD;AAAA,EACpF,MAAM;AAAA,EACN;AAAA,EACA;AACF;",
6
+ "names": []
7
+ }
@@ -1,18 +1,14 @@
1
- import { attribute } from "../../kernel/index.js";
1
+ import { dir } from "../def.js";
2
2
  const put = (el, name, v) => {
3
3
  if (v === false || v == null) el.removeAttribute(name);
4
- else el.setAttribute(name, v === true ? "" : typeof v === "object" ? JSON.stringify(v) : String(v));
4
+ else el.setAttribute(name, v === true ? "" : String(v));
5
5
  };
6
- const attr = attribute({
7
- name: "attr",
8
- value: "required",
9
- mount({ el, key, cased, evaluate, effect }) {
10
- effect(() => {
11
- if (key) return put(el, cased("kebab"), evaluate());
12
- const map = evaluate();
13
- for (const k in map) put(el, k, map[k]);
14
- });
15
- }
6
+ const attr = dir("attr", 4, ({ el, key, cased, evaluate, effect }) => {
7
+ effect(() => {
8
+ if (key) return put(el, cased("kebab"), evaluate());
9
+ const map = evaluate();
10
+ for (const k in map) put(el, k, map[k]);
11
+ });
16
12
  });
17
13
  export {
18
14
  attr
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/plugins/directives/attribute-sync.ts"],
4
- "sourcesContent": ["import { attribute } from '../../kernel/index.js'\n\nconst put = (el: Element, name: string, v: unknown) => {\n if (v === false || v == null) el.removeAttribute(name)\n else el.setAttribute(name, v === true ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v))\n}\n\n/** `attr:title=\"expr\"` or `attr=\"{ title: expr }\"`. true \u2192 present, false/null \u2192 removed. */\nexport const attr = attribute({\n name: 'attr',\n value: 'required',\n mount({ el, key, cased, evaluate, effect }) {\n effect(() => {\n if (key) return put(el, cased('kebab'), evaluate())\n const map = evaluate()\n for (const k in map) put(el, k, map[k])\n })\n },\n})\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAE1B,MAAM,MAAM,CAAC,IAAa,MAAc,MAAe;AACrD,MAAI,MAAM,SAAS,KAAK,KAAM,IAAG,gBAAgB,IAAI;AAAA,MAChD,IAAG,aAAa,MAAM,MAAM,OAAO,KAAK,OAAO,MAAM,WAAW,KAAK,UAAU,CAAC,IAAI,OAAO,CAAC,CAAC;AACpG;AAGO,MAAM,OAAO,UAAU;AAAA,EAC5B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM,EAAE,IAAI,KAAK,OAAO,UAAU,OAAO,GAAG;AAC1C,WAAO,MAAM;AACX,UAAI,IAAK,QAAO,IAAI,IAAI,MAAM,OAAO,GAAG,SAAS,CAAC;AAClD,YAAM,MAAM,SAAS;AACrB,iBAAW,KAAK,IAAK,KAAI,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,IACxC,CAAC;AAAA,EACH;AACF,CAAC;",
4
+ "sourcesContent": ["import { dir } from '../def.js';\n\nconst put = (el: Element, name: string, v: unknown) => {\n if (v === false || v == null) el.removeAttribute(name);\n else el.setAttribute(name, v === true ? '' : String(v));\n};\n\n/** `attr:title=\"expr\"` or `attr=\"{ title: expr }\"`. true \u2192 present, false/null \u2192 removed. */\nexport const attr = dir('attr', 4, ({ el, key, cased, evaluate, effect }) => {\n effect(() => {\n if (key) return put(el, cased('kebab'), evaluate());\n const map = evaluate();\n for (const k in map) put(el, k, map[k]);\n });\n});\n"],
5
+ "mappings": "AAAA,SAAS,WAAW;AAEpB,MAAM,MAAM,CAAC,IAAa,MAAc,MAAe;AACrD,MAAI,MAAM,SAAS,KAAK,KAAM,IAAG,gBAAgB,IAAI;AAAA,MAChD,IAAG,aAAa,MAAM,MAAM,OAAO,KAAK,OAAO,CAAC,CAAC;AACxD;AAGO,MAAM,OAAO,IAAI,QAAQ,GAAG,CAAC,EAAE,IAAI,KAAK,OAAO,UAAU,OAAO,MAAM;AAC3E,SAAO,MAAM;AACX,QAAI,IAAK,QAAO,IAAI,IAAI,MAAM,OAAO,GAAG,SAAS,CAAC;AAClD,UAAM,MAAM,SAAS;AACrB,eAAW,KAAK,IAAK,KAAI,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,EACxC,CAAC;AACH,CAAC;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Turns same-origin links and forms inside the element into requests whose full-document response
3
3
  * is morphed into the current page, with history entries: `boost` on a container (or `body`).
4
- * Needs `httpGet`, `httpPost` and `applyElements`. `__replace` replaces the history entry instead.
4
+ * Needs `httpGet`, `httpPost` and `applyElements`.
5
5
  */
6
6
  export declare const boost: import("../../kernel/contracts.js").AttributePlugin;