@bquery/bquery 1.7.0 → 1.8.1

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 (262) hide show
  1. package/README.md +760 -716
  2. package/dist/{a11y-C5QOVvRn.js → a11y-DVBCy09c.js} +3 -3
  3. package/dist/a11y-DVBCy09c.js.map +1 -0
  4. package/dist/a11y.es.mjs +1 -1
  5. package/dist/component/library.d.ts.map +1 -1
  6. package/dist/{component-CuuTijA6.js → component-L3-JfOFz.js} +5 -5
  7. package/dist/component-L3-JfOFz.js.map +1 -0
  8. package/dist/component.es.mjs +1 -1
  9. package/dist/{config-BW35FKuA.js → config-DhT9auRm.js} +1 -1
  10. package/dist/{config-BW35FKuA.js.map → config-DhT9auRm.js.map} +1 -1
  11. package/dist/{constraints-3lV9yyBw.js → constraints-D5RHQLmP.js} +1 -1
  12. package/dist/constraints-D5RHQLmP.js.map +1 -0
  13. package/dist/core/collection.d.ts +86 -0
  14. package/dist/core/collection.d.ts.map +1 -1
  15. package/dist/core/element.d.ts +28 -0
  16. package/dist/core/element.d.ts.map +1 -1
  17. package/dist/core/shared.d.ts +6 -0
  18. package/dist/core/shared.d.ts.map +1 -1
  19. package/dist/core-DdtZHzsS.js +168 -0
  20. package/dist/core-DdtZHzsS.js.map +1 -0
  21. package/dist/{core-Cjl7GUu8.js → core-EMYSLzaT.js} +289 -259
  22. package/dist/core-EMYSLzaT.js.map +1 -0
  23. package/dist/core.es.mjs +48 -47
  24. package/dist/{custom-directives-7wAShnnd.js → custom-directives-Dr4C5lVV.js} +1 -1
  25. package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
  26. package/dist/{devtools-D2fQLhDN.js → devtools-BhB2iDPT.js} +2 -2
  27. package/dist/devtools-BhB2iDPT.js.map +1 -0
  28. package/dist/devtools.es.mjs +1 -1
  29. package/dist/{dnd-B8EgyzaI.js → dnd-NwZBYh4l.js} +1 -1
  30. package/dist/dnd-NwZBYh4l.js.map +1 -0
  31. package/dist/dnd.es.mjs +1 -1
  32. package/dist/{env-NeVmr4Gf.js → env-CTdvLaH2.js} +1 -1
  33. package/dist/env-CTdvLaH2.js.map +1 -0
  34. package/dist/forms/create-form.d.ts.map +1 -1
  35. package/dist/forms/index.d.ts +3 -2
  36. package/dist/forms/index.d.ts.map +1 -1
  37. package/dist/forms/types.d.ts +46 -0
  38. package/dist/forms/types.d.ts.map +1 -1
  39. package/dist/forms/use-field.d.ts +34 -0
  40. package/dist/forms/use-field.d.ts.map +1 -0
  41. package/dist/forms/validators.d.ts +25 -0
  42. package/dist/forms/validators.d.ts.map +1 -1
  43. package/dist/forms-UcRHsYxC.js +227 -0
  44. package/dist/forms-UcRHsYxC.js.map +1 -0
  45. package/dist/forms.es.mjs +14 -12
  46. package/dist/full.d.ts +17 -26
  47. package/dist/full.d.ts.map +1 -1
  48. package/dist/full.es.mjs +206 -181
  49. package/dist/full.iife.js +33 -33
  50. package/dist/full.iife.js.map +1 -1
  51. package/dist/full.umd.js +33 -33
  52. package/dist/full.umd.js.map +1 -1
  53. package/dist/function-Cybd57JV.js +33 -0
  54. package/dist/function-Cybd57JV.js.map +1 -0
  55. package/dist/{i18n-BnnhTFOS.js → i18n-kuF6Ekj6.js} +3 -3
  56. package/dist/i18n-kuF6Ekj6.js.map +1 -0
  57. package/dist/i18n.es.mjs +1 -1
  58. package/dist/index.es.mjs +251 -228
  59. package/dist/media/breakpoints.d.ts.map +1 -1
  60. package/dist/media/types.d.ts +2 -2
  61. package/dist/media/types.d.ts.map +1 -1
  62. package/dist/{media-Di2Ta22s.js → media-i-fB5WxI.js} +3 -3
  63. package/dist/media-i-fB5WxI.js.map +1 -0
  64. package/dist/media.es.mjs +1 -1
  65. package/dist/{motion-qPj_TYGv.js → motion-BJsAuULb.js} +2 -2
  66. package/dist/motion-BJsAuULb.js.map +1 -0
  67. package/dist/motion.es.mjs +1 -1
  68. package/dist/{mount-SM07RUa6.js → mount-B4Y8bk8Z.js} +5 -5
  69. package/dist/mount-B4Y8bk8Z.js.map +1 -0
  70. package/dist/{platform-CPbCprb6.js → platform-Dw2gE3zI.js} +3 -3
  71. package/dist/{platform-CPbCprb6.js.map → platform-Dw2gE3zI.js.map} +1 -1
  72. package/dist/platform.es.mjs +2 -2
  73. package/dist/plugin/registry.d.ts.map +1 -1
  74. package/dist/{plugin-cPoOHFLY.js → plugin-C2WuC8SF.js} +20 -18
  75. package/dist/plugin-C2WuC8SF.js.map +1 -0
  76. package/dist/plugin.es.mjs +1 -1
  77. package/dist/reactive/async-data.d.ts +28 -3
  78. package/dist/reactive/async-data.d.ts.map +1 -1
  79. package/dist/reactive/computed.d.ts +3 -0
  80. package/dist/reactive/computed.d.ts.map +1 -1
  81. package/dist/reactive/effect.d.ts +3 -0
  82. package/dist/reactive/effect.d.ts.map +1 -1
  83. package/dist/reactive/http.d.ts +194 -0
  84. package/dist/reactive/http.d.ts.map +1 -0
  85. package/dist/reactive/index.d.ts +2 -2
  86. package/dist/reactive/index.d.ts.map +1 -1
  87. package/dist/reactive/pagination.d.ts +126 -0
  88. package/dist/reactive/pagination.d.ts.map +1 -0
  89. package/dist/reactive/polling.d.ts +55 -0
  90. package/dist/reactive/polling.d.ts.map +1 -0
  91. package/dist/reactive/readonly.d.ts +20 -1
  92. package/dist/reactive/readonly.d.ts.map +1 -1
  93. package/dist/reactive/rest.d.ts +293 -0
  94. package/dist/reactive/rest.d.ts.map +1 -0
  95. package/dist/reactive/scope.d.ts +140 -0
  96. package/dist/reactive/scope.d.ts.map +1 -0
  97. package/dist/reactive/signal.d.ts +16 -2
  98. package/dist/reactive/signal.d.ts.map +1 -1
  99. package/dist/reactive/to-value.d.ts +57 -0
  100. package/dist/reactive/to-value.d.ts.map +1 -0
  101. package/dist/reactive/websocket.d.ts +285 -0
  102. package/dist/reactive/websocket.d.ts.map +1 -0
  103. package/dist/reactive-DwkhUJfP.js +1148 -0
  104. package/dist/reactive-DwkhUJfP.js.map +1 -0
  105. package/dist/reactive.es.mjs +38 -19
  106. package/dist/{registry-CWf368tT.js → registry-B08iilIh.js} +1 -1
  107. package/dist/{registry-CWf368tT.js.map → registry-B08iilIh.js.map} +1 -1
  108. package/dist/router/constraints.d.ts.map +1 -1
  109. package/dist/router/index.d.ts +1 -1
  110. package/dist/router/index.d.ts.map +1 -1
  111. package/dist/router/router.d.ts.map +1 -1
  112. package/dist/router/state.d.ts +25 -2
  113. package/dist/router/state.d.ts.map +1 -1
  114. package/dist/router-CQikC9Ed.js +492 -0
  115. package/dist/router-CQikC9Ed.js.map +1 -0
  116. package/dist/router.es.mjs +9 -8
  117. package/dist/ssr/hydrate.d.ts.map +1 -1
  118. package/dist/{ssr-B2qd_WBB.js → ssr-_dAcGdzu.js} +4 -4
  119. package/dist/ssr-_dAcGdzu.js.map +1 -0
  120. package/dist/ssr.es.mjs +1 -1
  121. package/dist/store/persisted.d.ts.map +1 -1
  122. package/dist/{store-DWpyH6p5.js → store-Cb3gPRve.js} +7 -7
  123. package/dist/store-Cb3gPRve.js.map +1 -0
  124. package/dist/store.es.mjs +2 -2
  125. package/dist/storybook.es.mjs.map +1 -1
  126. package/dist/{testing-CsqjNUyy.js → testing-C5Sjfsna.js} +8 -8
  127. package/dist/testing-C5Sjfsna.js.map +1 -0
  128. package/dist/testing.es.mjs +1 -1
  129. package/dist/{type-guards-Do9DWgNp.js → type-guards-BMX2c0LP.js} +1 -1
  130. package/dist/{type-guards-Do9DWgNp.js.map → type-guards-BMX2c0LP.js.map} +1 -1
  131. package/dist/untrack-D0fnO5k2.js +36 -0
  132. package/dist/untrack-D0fnO5k2.js.map +1 -0
  133. package/dist/view/custom-directives.d.ts.map +1 -1
  134. package/dist/view.es.mjs +4 -4
  135. package/package.json +177 -177
  136. package/src/a11y/announce.ts +131 -131
  137. package/src/a11y/audit.ts +314 -314
  138. package/src/a11y/index.ts +68 -68
  139. package/src/a11y/media-preferences.ts +255 -255
  140. package/src/a11y/roving-tab-index.ts +164 -164
  141. package/src/a11y/skip-link.ts +255 -255
  142. package/src/a11y/trap-focus.ts +184 -184
  143. package/src/a11y/types.ts +183 -183
  144. package/src/component/component.ts +599 -599
  145. package/src/component/html.ts +153 -153
  146. package/src/component/index.ts +52 -52
  147. package/src/component/library.ts +540 -542
  148. package/src/component/scope.ts +212 -212
  149. package/src/component/types.ts +310 -310
  150. package/src/core/collection.ts +876 -707
  151. package/src/core/element.ts +1015 -981
  152. package/src/core/env.ts +60 -60
  153. package/src/core/index.ts +49 -49
  154. package/src/core/shared.ts +77 -62
  155. package/src/core/utils/index.ts +148 -148
  156. package/src/devtools/devtools.ts +410 -410
  157. package/src/devtools/index.ts +48 -48
  158. package/src/devtools/types.ts +104 -104
  159. package/src/dnd/draggable.ts +296 -296
  160. package/src/dnd/droppable.ts +228 -228
  161. package/src/dnd/index.ts +62 -62
  162. package/src/dnd/sortable.ts +307 -307
  163. package/src/dnd/types.ts +293 -293
  164. package/src/forms/create-form.ts +320 -278
  165. package/src/forms/index.ts +70 -65
  166. package/src/forms/types.ts +203 -154
  167. package/src/forms/use-field.ts +231 -0
  168. package/src/forms/validators.ts +294 -265
  169. package/src/full.ts +554 -480
  170. package/src/i18n/formatting.ts +67 -67
  171. package/src/i18n/i18n.ts +200 -200
  172. package/src/i18n/index.ts +67 -67
  173. package/src/i18n/translate.ts +182 -182
  174. package/src/i18n/types.ts +171 -171
  175. package/src/index.ts +108 -108
  176. package/src/media/battery.ts +116 -116
  177. package/src/media/breakpoints.ts +129 -131
  178. package/src/media/clipboard.ts +80 -80
  179. package/src/media/device-sensors.ts +158 -158
  180. package/src/media/geolocation.ts +119 -119
  181. package/src/media/index.ts +76 -76
  182. package/src/media/media-query.ts +92 -92
  183. package/src/media/network.ts +115 -115
  184. package/src/media/types.ts +177 -177
  185. package/src/media/viewport.ts +84 -84
  186. package/src/motion/index.ts +57 -57
  187. package/src/motion/morph.ts +151 -151
  188. package/src/motion/parallax.ts +120 -120
  189. package/src/motion/reduced-motion.ts +66 -66
  190. package/src/motion/types.ts +271 -271
  191. package/src/motion/typewriter.ts +164 -164
  192. package/src/plugin/index.ts +37 -37
  193. package/src/plugin/registry.ts +284 -269
  194. package/src/plugin/types.ts +137 -137
  195. package/src/reactive/async-data.ts +250 -29
  196. package/src/reactive/computed.ts +144 -130
  197. package/src/reactive/effect.ts +29 -6
  198. package/src/reactive/http.ts +790 -0
  199. package/src/reactive/index.ts +60 -0
  200. package/src/reactive/pagination.ts +317 -0
  201. package/src/reactive/polling.ts +179 -0
  202. package/src/reactive/readonly.ts +52 -8
  203. package/src/reactive/rest.ts +859 -0
  204. package/src/reactive/scope.ts +276 -0
  205. package/src/reactive/signal.ts +61 -1
  206. package/src/reactive/to-value.ts +71 -0
  207. package/src/reactive/websocket.ts +849 -0
  208. package/src/router/bq-link.ts +279 -279
  209. package/src/router/constraints.ts +204 -201
  210. package/src/router/index.ts +49 -49
  211. package/src/router/match.ts +312 -312
  212. package/src/router/path-pattern.ts +52 -52
  213. package/src/router/query.ts +38 -38
  214. package/src/router/router.ts +421 -402
  215. package/src/router/state.ts +51 -3
  216. package/src/router/types.ts +139 -139
  217. package/src/router/use-route.ts +68 -68
  218. package/src/router/utils.ts +157 -157
  219. package/src/security/index.ts +12 -12
  220. package/src/ssr/hydrate.ts +84 -82
  221. package/src/ssr/index.ts +70 -70
  222. package/src/ssr/render.ts +508 -508
  223. package/src/ssr/serialize.ts +296 -296
  224. package/src/ssr/types.ts +81 -81
  225. package/src/store/create-store.ts +467 -467
  226. package/src/store/index.ts +27 -27
  227. package/src/store/persisted.ts +245 -249
  228. package/src/store/types.ts +247 -247
  229. package/src/store/utils.ts +135 -135
  230. package/src/storybook/index.ts +480 -480
  231. package/src/testing/index.ts +42 -42
  232. package/src/testing/testing.ts +593 -593
  233. package/src/testing/types.ts +170 -170
  234. package/src/view/custom-directives.ts +28 -30
  235. package/src/view/evaluate.ts +292 -292
  236. package/src/view/process.ts +108 -108
  237. package/dist/a11y-C5QOVvRn.js.map +0 -1
  238. package/dist/component-CuuTijA6.js.map +0 -1
  239. package/dist/constraints-3lV9yyBw.js.map +0 -1
  240. package/dist/core-Cjl7GUu8.js.map +0 -1
  241. package/dist/core-DnlyjbF2.js +0 -112
  242. package/dist/core-DnlyjbF2.js.map +0 -1
  243. package/dist/custom-directives-7wAShnnd.js.map +0 -1
  244. package/dist/devtools-D2fQLhDN.js.map +0 -1
  245. package/dist/dnd-B8EgyzaI.js.map +0 -1
  246. package/dist/env-NeVmr4Gf.js.map +0 -1
  247. package/dist/forms-C3yovgH9.js +0 -141
  248. package/dist/forms-C3yovgH9.js.map +0 -1
  249. package/dist/i18n-BnnhTFOS.js.map +0 -1
  250. package/dist/media-Di2Ta22s.js.map +0 -1
  251. package/dist/motion-qPj_TYGv.js.map +0 -1
  252. package/dist/mount-SM07RUa6.js.map +0 -1
  253. package/dist/plugin-cPoOHFLY.js.map +0 -1
  254. package/dist/reactive-Cfv0RK6x.js +0 -233
  255. package/dist/reactive-Cfv0RK6x.js.map +0 -1
  256. package/dist/router-BrthaP_z.js +0 -473
  257. package/dist/router-BrthaP_z.js.map +0 -1
  258. package/dist/ssr-B2qd_WBB.js.map +0 -1
  259. package/dist/store-DWpyH6p5.js.map +0 -1
  260. package/dist/testing-CsqjNUyy.js.map +0 -1
  261. package/dist/untrack-DJVQQ2WM.js +0 -33
  262. package/dist/untrack-DJVQQ2WM.js.map +0 -1
@@ -1,16 +1,17 @@
1
- import { a as s, c as e, d as t, f as i, i as r, l as n, n as o, o as c, p as u, r as k, s as l, t as p, u as v } from "./router-BrthaP_z.js";
1
+ import { a as s, c as e, d as i, f as t, i as r, l as n, m as o, n as c, o as u, p as g, r as k, s as l, t as v, u as m } from "./router-CQikC9Ed.js";
2
2
  export {
3
3
  e as BqLinkElement,
4
- v as back,
5
- o as createRouter,
6
- u as currentRoute,
7
- t as forward,
8
- c as interceptLinks,
4
+ m as back,
5
+ c as createRouter,
6
+ g as currentRoute,
7
+ i as forward,
8
+ u as interceptLinks,
9
9
  k as isActive,
10
10
  r as isActiveSignal,
11
+ o as isNavigating,
11
12
  l as link,
12
- i as navigate,
13
+ t as navigate,
13
14
  n as registerBqLink,
14
15
  s as resolve,
15
- p as useRoute
16
+ v as useRoute
16
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../../src/ssr/hydrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGxE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG;IAC/C;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,GAAG,OAAO,EAC1B,SAAS,cAAc,EACvB,UAAS,mBAAwB,KAChC,IAUF,CAAC"}
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../../src/ssr/hydrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGxE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG;IAC/C;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,GAAG,OAAO,EAC1B,SAAS,cAAc,EACvB,UAAS,mBAAwB,KAChC,IAYF,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { n as I, p as R } from "./sanitize-B1V4JswB.js";
2
2
  import { i as S } from "./object-BCk-1c8T.js";
3
- import { n as C, r as L } from "./reactive-Cfv0RK6x.js";
4
- import { i as F, n as _ } from "./registry-CWf368tT.js";
5
- import { n as j } from "./mount-SM07RUa6.js";
3
+ import { o as C, s as L } from "./reactive-DwkhUJfP.js";
4
+ import { i as F, n as _ } from "./registry-B08iilIh.js";
5
+ import { n as j } from "./mount-B4Y8bk8Z.js";
6
6
  var X = (t, r, e = {}) => {
7
7
  const { hydrate: o = !0, ...i } = e;
8
8
  if (!o) throw new Error("bQuery ssr: hydrateMount() requires { hydrate: true } when options are provided.");
@@ -245,4 +245,4 @@ export {
245
245
  tt as t
246
246
  };
247
247
 
248
- //# sourceMappingURL=ssr-B2qd_WBB.js.map
248
+ //# sourceMappingURL=ssr-_dAcGdzu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssr-_dAcGdzu.js","names":[],"sources":["../src/ssr/hydrate.ts","../src/ssr/serialize.ts","../src/ssr/render.ts"],"sourcesContent":["/**\n * Hydration support for server-rendered DOM.\n *\n * Enables the client-side view system to reuse existing server-rendered DOM\n * elements instead of re-rendering them, by attaching reactive bindings\n * to the pre-existing DOM structure.\n *\n * @module bquery/ssr\n */\n\nimport type { BindingContext, MountOptions, View } from '../view/types';\nimport { mount } from '../view/mount';\n\n/**\n * Extended mount options that include hydration mode.\n */\nexport type HydrateMountOptions = MountOptions & {\n /**\n * When present, must be `true` so the mount operation reuses existing DOM elements\n * instead of re-rendering them. Reactive bindings (effects) are\n * still attached so the DOM updates reactively from that point on.\n *\n * @default true\n */\n hydrate?: true;\n};\n\n/**\n * Mounts a reactive view with optional hydration support.\n *\n * When `hydrate: true` is set, the existing server-rendered DOM is preserved\n * and reactive bindings are attached on top. The DOM is NOT re-rendered;\n * instead, effects begin tracking signals so future changes update the DOM.\n *\n * This is the client-side counterpart to `renderToString()`. The typical flow:\n * 1. Server: `renderToString(template, data)` → send HTML to client\n * 2. Client: `hydrateMount('#app', reactiveContext, { hydrate: true })`\n *\n * Under the hood, `hydrateMount` simply delegates to the standard `mount()`\n * function. The `mount()` function already processes existing DOM elements\n * and attaches reactive effects to them — it does not clear/replace content.\n * The `hydrate` flag is a semantic marker indicating developer intent and\n * ensures the existing DOM structure is preserved.\n *\n * @param selector - CSS selector or Element to hydrate\n * @param context - Binding context with signals, computed values, and functions\n * @param options - Mount options with `hydrate: true`\n * @returns The mounted View instance\n *\n * @example\n * ```ts\n * import { hydrateMount } from '@bquery/bquery/ssr';\n * import { signal, computed } from '@bquery/bquery/reactive';\n *\n * // Server rendered:\n * // <div id=\"app\"><h1>Welcome</h1><p>Hello, World!</p></div>\n *\n * // Client hydration — attaches reactivity to existing DOM:\n * const name = signal('World');\n * const greeting = computed(() => `Hello, ${name.value}!`);\n *\n * const view = hydrateMount('#app', { name, greeting }, { hydrate: true });\n *\n * // Now updating `name.value` will reactively update the DOM\n * name.value = 'Alice'; // <p> updates to \"Hello, Alice!\"\n * ```\n */\nexport const hydrateMount = (\n selector: string | Element,\n context: BindingContext,\n options: HydrateMountOptions = {}\n): View => {\n const { hydrate = true, ...mountOptions } = options;\n\n if (!hydrate) {\n throw new Error(\n 'bQuery ssr: hydrateMount() requires { hydrate: true } when options are provided.'\n );\n }\n\n // Hydration uses the standard mount which processes existing DOM\n // and attaches reactive effects without clearing content.\n return mount(selector, context, mountOptions);\n};\n","/**\n * Store state serialization for SSR.\n *\n * Provides utilities to serialize store state into a `<script>` tag\n * for client-side hydration, and to deserialize state on the client.\n *\n * @module bquery/ssr\n */\n\nimport { getStore, listStores } from '../store/index';\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport type { DeserializedStoreState, SerializeOptions } from './types';\n\nconst isStoreStateObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst sanitizeHydrationState = (value: Record<string, unknown>): Record<string, unknown> => {\n const sanitized: Record<string, unknown> = {};\n for (const [key, entryValue] of Object.entries(value)) {\n if (isPrototypePollutionKey(key)) continue;\n sanitized[key] = entryValue;\n }\n return sanitized;\n};\n\n/**\n * Result of store state serialization.\n */\nexport type SerializeResult = {\n /** JSON string of the state map */\n stateJson: string;\n /** Complete `<script>` tag ready to embed in HTML */\n scriptTag: string;\n};\n\n/**\n * Escapes a string for safe embedding in a `<script>` tag.\n * Prevents XSS via `</script>` injection and HTML entities.\n *\n * @internal\n */\nconst escapeForScript = (str: string): string => {\n return str\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/\\//g, '\\\\u002f')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n};\n\n/**\n * Escapes a string for safe embedding in an HTML attribute value.\n * @internal\n */\nconst escapeForHtmlAttribute = (str: string): string => {\n return str\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n};\n\n/**\n * Serializes the state of registered stores into a JSON string and\n * a `<script>` tag suitable for embedding in server-rendered HTML.\n *\n * The serialized state can be picked up on the client using\n * `deserializeStoreState()` to restore stores to their server-side values.\n *\n * @param options - Serialization options\n * @returns Object with JSON string and ready-to-use script tag\n *\n * @example\n * ```ts\n * import { serializeStoreState } from '@bquery/bquery/ssr';\n * import { createStore } from '@bquery/bquery/store';\n *\n * const store = createStore({\n * id: 'counter',\n * state: () => ({ count: 42 }),\n * });\n *\n * const { scriptTag } = serializeStoreState();\n * // '<script id=\"__BQUERY_STORE_STATE__\">window.__BQUERY_INITIAL_STATE__={\"counter\":{\"count\":42}}</script>'\n * ```\n *\n * @example\n * ```ts\n * // Serialize only specific stores\n * const { scriptTag } = serializeStoreState({ storeIds: ['counter'] });\n * ```\n */\nexport const serializeStoreState = (options: SerializeOptions = {}): SerializeResult => {\n const {\n scriptId = '__BQUERY_STORE_STATE__',\n globalKey = '__BQUERY_INITIAL_STATE__',\n storeIds,\n serialize = JSON.stringify,\n } = options;\n\n if (isPrototypePollutionKey(globalKey)) {\n throw new Error(\n `serializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (isPrototypePollutionKey(scriptId)) {\n throw new Error(\n `serializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n const ids = storeIds ?? listStores();\n const stateMap = Object.create(null) as Record<string, Record<string, unknown>>;\n\n for (const id of ids) {\n if (isPrototypePollutionKey(id)) {\n continue;\n }\n\n const store = getStore<{ $state: Record<string, unknown> }>(id);\n if (store) {\n stateMap[id] = sanitizeHydrationState(store.$state);\n }\n }\n\n const stateJson = serialize(stateMap);\n if (typeof stateJson !== 'string') {\n throw new Error('serializeStoreState: custom serialize function must return a string.');\n }\n\n if (serialize !== JSON.stringify) {\n let parsedStateJson: unknown;\n try {\n parsedStateJson = JSON.parse(stateJson);\n } catch {\n throw new Error('serializeStoreState: custom serialize function returned invalid JSON.');\n }\n\n if (!isStoreStateObject(parsedStateJson)) {\n throw new Error(\n 'serializeStoreState: custom serialize function must return a JSON object string.'\n );\n }\n }\n\n const escapedJson = escapeForScript(stateJson);\n const escapedGlobalKey = escapeForScript(JSON.stringify(globalKey));\n const escapedScriptId = escapeForHtmlAttribute(scriptId);\n const scriptTag = `<script id=\"${escapedScriptId}\">window[${escapedGlobalKey}]=${escapedJson}</script>`;\n\n return { stateJson, scriptTag };\n};\n\n/**\n * Deserializes store state from the global variable set by the SSR script tag.\n *\n * Call this on the client before creating stores to pre-populate them with\n * server-rendered state. After deserialization, the script tag and global\n * variable are cleaned up automatically.\n *\n * @param globalKey - The global variable name where state was serialized\n * @param scriptId - The ID of the SSR script tag to remove after hydration\n * @returns The deserialized state map, or an empty object if not found\n *\n * @example\n * ```ts\n * import { deserializeStoreState } from '@bquery/bquery/ssr';\n *\n * // Call before creating stores\n * const state = deserializeStoreState();\n * // state = { counter: { count: 42 } }\n * ```\n */\nexport const deserializeStoreState = (\n globalKey = '__BQUERY_INITIAL_STATE__',\n scriptId = '__BQUERY_STORE_STATE__'\n): DeserializedStoreState => {\n if (isPrototypePollutionKey(globalKey)) {\n throw new Error(\n `deserializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (isPrototypePollutionKey(scriptId)) {\n throw new Error(\n `deserializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (typeof window === 'undefined') {\n return {};\n }\n\n const state = (window as unknown as Record<string, unknown>)[globalKey];\n if (!state) {\n return {};\n }\n\n // Clean up global variable\n try {\n delete (window as unknown as Record<string, unknown>)[globalKey];\n } catch {\n // In strict mode on some environments, delete may fail\n (window as unknown as Record<string, unknown>)[globalKey] = undefined;\n }\n\n // Clean up script tag\n if (typeof document !== 'undefined' && typeof document.getElementById === 'function') {\n const scriptEl = document.getElementById(scriptId);\n if (scriptEl) {\n scriptEl.remove();\n }\n }\n\n if (!isStoreStateObject(state)) {\n return {};\n }\n\n for (const value of Object.values(state)) {\n if (!isStoreStateObject(value)) {\n return {};\n }\n }\n\n const sanitizedStateMap = Object.create(null) as DeserializedStoreState;\n\n for (const [storeId, storeState] of Object.entries(state)) {\n if (isPrototypePollutionKey(storeId) || !isStoreStateObject(storeState)) {\n continue;\n }\n\n sanitizedStateMap[storeId] = sanitizeHydrationState(storeState);\n }\n\n return sanitizedStateMap;\n};\n\n/**\n * Hydrates a store with pre-serialized state from SSR.\n *\n * If the store exists and has a `$patch` method, this applies the\n * deserialized state as a patch. Otherwise, the state is ignored.\n *\n * @param storeId - The store ID to hydrate\n * @param state - The plain state object to apply\n *\n * @example\n * ```ts\n * import { hydrateStore, deserializeStoreState } from '@bquery/bquery/ssr';\n * import { createStore } from '@bquery/bquery/store';\n *\n * // 1. Deserialize state from SSR script tag\n * const ssrState = deserializeStoreState();\n *\n * // 2. Create store (gets initial values from factory)\n * const store = createStore({\n * id: 'counter',\n * state: () => ({ count: 0 }),\n * });\n *\n * // 3. Apply SSR state\n * if (ssrState.counter) {\n * hydrateStore('counter', ssrState.counter);\n * }\n * // store.count is now 42 (from SSR)\n * ```\n */\nexport const hydrateStore = (storeId: string, state: Record<string, unknown>): void => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const store = getStore<{ $patch?: (partial: any) => void }>(storeId);\n if (store && typeof store.$patch === 'function') {\n store.$patch(sanitizeHydrationState(state));\n }\n};\n\n/**\n * Hydrates all stores at once from a deserialized state map.\n *\n * Convenience wrapper that calls `hydrateStore` for each entry in the state map.\n *\n * @param stateMap - Map of store IDs to their state objects\n *\n * @example\n * ```ts\n * import { hydrateStores, deserializeStoreState } from '@bquery/bquery/ssr';\n *\n * const ssrState = deserializeStoreState();\n * hydrateStores(ssrState);\n * ```\n */\nexport const hydrateStores = (stateMap: DeserializedStoreState): void => {\n for (const [storeId, state] of Object.entries(stateMap)) {\n hydrateStore(storeId, state);\n }\n};\n","/**\n * SSR rendering utilities.\n *\n * Server-side renders bQuery templates to HTML strings by evaluating\n * directive attributes against a plain data context. Uses a lightweight\n * DOM implementation to process templates without a browser.\n *\n * @module bquery/ssr\n */\n\nimport { isComputed, isSignal, type Signal } from '../reactive/index';\nimport { DANGEROUS_PROTOCOLS } from '../security/constants';\nimport { sanitizeHtml } from '../security/sanitize';\nimport type { BindingContext } from '../view/types';\nimport type { RenderOptions, SSRResult } from './types';\nimport { serializeStoreState } from './serialize';\n\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\nconst escapeHtmlText = (value: string): string =>\n value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\nconst escapeHtmlAttribute = (value: string): string =>\n escapeHtmlText(value).replace(/\"/g, '&quot;');\n\nconst isUnsafeUrlAttribute = (name: string): boolean => {\n const normalized = name.toLowerCase();\n return (\n normalized === 'href' ||\n normalized === 'src' ||\n normalized === 'xlink:href' ||\n normalized === 'formaction' ||\n normalized === 'action' ||\n normalized === 'poster' ||\n normalized === 'background' ||\n normalized === 'cite' ||\n normalized === 'data'\n );\n};\n\nconst sanitizeUrlForProtocolCheck = (value: string): string =>\n value\n .trim()\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\n .replace(/\\s+/g, '')\n .toLowerCase();\n\nconst isUnsafeUrlValue = (value: string): boolean => {\n const normalized = sanitizeUrlForProtocolCheck(value);\n return DANGEROUS_PROTOCOLS.some((protocol) => normalized.startsWith(protocol));\n};\n\nconst serializeSSRNode = (node: Node): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return escapeHtmlText(node.textContent ?? '');\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const el = node as Element;\n const tagName = el.tagName.toLowerCase();\n\n if (tagName === 'script') {\n return '';\n }\n\n let attrs = '';\n for (const attr of el.attributes) {\n const attrName = attr.name.toLowerCase();\n if (attrName.startsWith('on')) {\n continue;\n }\n if (isUnsafeUrlAttribute(attrName) && isUnsafeUrlValue(attr.value)) {\n continue;\n }\n attrs += ` ${attr.name}=\"${escapeHtmlAttribute(attr.value)}\"`;\n }\n\n if (VOID_ELEMENTS.has(tagName)) {\n return `<${tagName}${attrs}>`;\n }\n\n let childrenHtml = '';\n for (const child of el.childNodes) {\n childrenHtml += serializeSSRNode(child);\n }\n\n return `<${tagName}${attrs}>${childrenHtml}</${tagName}>`;\n};\n\n/**\n * Unwraps a value — if it's a signal/computed, returns `.value`, otherwise returns as-is.\n * @internal\n */\nconst unwrap = (value: unknown): unknown => {\n if (isSignal(value) || isComputed(value)) {\n return (value as Signal<unknown>).value;\n }\n return value;\n};\n\n/**\n * Evaluates a simple expression against a context.\n * Supports dot-notation property access, negation, ternary, and basic comparisons.\n * Unlike the view module's `evaluate()`, this does NOT use `new Function()` —\n * it uses a safe subset for SSR to avoid `unsafe-eval` in server environments.\n *\n * Falls back to `new Function()` for complex expressions.\n *\n * @internal\n */\nconst evaluateSSR = <T = unknown>(expression: string, context: BindingContext): T => {\n const trimmed = expression.trim();\n\n // Handle negation: !expr\n if (trimmed.startsWith('!')) {\n return !evaluateSSR(trimmed.slice(1).trim(), context) as T;\n }\n\n // Handle string literals\n if (\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) ||\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n ) {\n return trimmed.slice(1, -1) as T;\n }\n\n // Handle numeric literals\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n return Number(trimmed) as T;\n }\n\n // Handle boolean literals\n if (trimmed === 'true') return true as T;\n if (trimmed === 'false') return false as T;\n if (trimmed === 'null') return null as T;\n if (trimmed === 'undefined') return undefined as T;\n\n // Handle dot-notation property access: a.b.c\n if (/^[\\w$]+(?:\\.[\\w$]+)*$/.test(trimmed)) {\n const parts = trimmed.split('.');\n let current: unknown = context;\n for (const part of parts) {\n if (current == null) return undefined as T;\n // First level: unwrap signals\n if (current === context) {\n current = unwrap((current as Record<string, unknown>)[part]);\n } else {\n current = (current as Record<string, unknown>)[part];\n }\n }\n return current as T;\n }\n\n // For complex expressions, fall back to Function-based evaluation\n try {\n const keys = Object.keys(context);\n const values = keys.map((k) => unwrap(context[k]));\n const fn = new Function(...keys, `return (${trimmed});`);\n return fn(...values) as T;\n } catch {\n return undefined as T;\n }\n};\n\n/**\n * Parses a `bq-for` expression like `item in items` or `(item, index) in items`.\n * @internal\n */\nconst parseForExpression = (\n expression: string\n): { itemName: string; indexName?: string; listExpr: string } | null => {\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\n if (!match) return null;\n return {\n itemName: match[1],\n indexName: match[2] || undefined,\n listExpr: match[3].trim(),\n };\n};\n\n/**\n * Processes an element's SSR directives, modifying it in place.\n * Returns `false` if the element should be removed from output (bq-if = false).\n * @internal\n */\nconst processSSRElement = (\n el: Element,\n context: BindingContext,\n prefix: string,\n doc: Document\n): boolean => {\n // Handle bq-if: remove element if condition is falsy\n const ifExpr = el.getAttribute(`${prefix}-if`);\n if (ifExpr !== null) {\n const condition = evaluateSSR<boolean>(ifExpr, context);\n if (!condition) {\n return false; // Signal to remove this element\n }\n }\n\n // Handle bq-show: set display:none if falsy\n const showExpr = el.getAttribute(`${prefix}-show`);\n if (showExpr !== null) {\n const condition = evaluateSSR<boolean>(showExpr, context);\n if (!condition) {\n const htmlEl = el as unknown as { style?: { display?: string } };\n if (htmlEl.style) {\n htmlEl.style.display = 'none';\n } else {\n el.setAttribute('style', 'display: none;');\n }\n }\n }\n\n // Handle bq-text: set text content\n const textExpr = el.getAttribute(`${prefix}-text`);\n if (textExpr !== null) {\n const value = evaluateSSR(textExpr, context);\n el.textContent = String(value ?? '');\n }\n\n // Handle bq-html: sanitize to match client-side default behavior\n const htmlExpr = el.getAttribute(`${prefix}-html`);\n if (htmlExpr !== null) {\n const value = evaluateSSR(htmlExpr, context);\n el.innerHTML = String(sanitizeHtml(String(value ?? '')));\n }\n\n // Handle bq-class: add classes\n const classExpr = el.getAttribute(`${prefix}-class`);\n if (classExpr !== null) {\n const trimmedClass = classExpr.trim();\n if (trimmedClass.startsWith('{')) {\n // Object syntax: { active: isActive, disabled: !enabled }\n const inner = trimmedClass.slice(1, -1).trim();\n const pairs = inner.split(',');\n for (const pair of pairs) {\n const colonIdx = pair.indexOf(':');\n if (colonIdx > -1) {\n const className = pair\n .slice(0, colonIdx)\n .trim()\n .replace(/^['\"]|['\"]$/g, '');\n const condExpr = pair.slice(colonIdx + 1).trim();\n const condition = evaluateSSR<boolean>(condExpr, context);\n if (condition) {\n el.classList.add(className);\n }\n }\n }\n } else {\n const result = evaluateSSR<string | string[]>(classExpr, context);\n if (typeof result === 'string') {\n result\n .split(/\\s+/)\n .filter(Boolean)\n .forEach((cls) => el.classList.add(cls));\n } else if (Array.isArray(result)) {\n result.filter(Boolean).forEach((cls) => el.classList.add(cls));\n }\n }\n }\n\n // Handle bq-style: set inline styles\n const styleExpr = el.getAttribute(`${prefix}-style`);\n if (styleExpr !== null) {\n const result = evaluateSSR<Record<string, string>>(styleExpr, context);\n if (result && typeof result === 'object') {\n const htmlEl = el as HTMLElement;\n for (const [prop, val] of Object.entries(result)) {\n // Convert camelCase to kebab-case\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(val));\n }\n }\n }\n\n // Handle bq-bind:attr — set arbitrary attributes\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith(`${prefix}-bind:`)) {\n const attrName = attr.name.slice(`${prefix}-bind:`.length);\n const value = evaluateSSR(attr.value, context);\n if (value === false || value === null || value === undefined) {\n el.removeAttribute(attrName);\n } else if (value === true) {\n el.setAttribute(attrName, '');\n } else {\n el.setAttribute(attrName, String(value));\n }\n }\n }\n\n // Handle bq-for: list rendering\n const forExpr = el.getAttribute(`${prefix}-for`);\n if (forExpr !== null) {\n const parsed = parseForExpression(forExpr);\n if (parsed) {\n const list = evaluateSSR<unknown[]>(parsed.listExpr, context);\n if (Array.isArray(list) && el.parentNode) {\n const parent = el.parentNode;\n for (let i = 0; i < list.length; i++) {\n const item = list[i];\n const clone = el.cloneNode(true) as Element;\n\n // Remove the bq-for attribute from clones\n clone.removeAttribute(`${prefix}-for`);\n clone.removeAttribute(':key');\n clone.removeAttribute(`${prefix}-key`);\n\n // Create item context\n const itemContext: BindingContext = {\n ...context,\n [parsed.itemName]: item,\n };\n if (parsed.indexName) {\n itemContext[parsed.indexName] = i;\n }\n\n // Recursively process the clone\n processSSRElement(clone, itemContext, prefix, doc);\n processSSRChildren(clone, itemContext, prefix, doc);\n\n parent.insertBefore(clone, el);\n }\n\n // Remove the original template element\n parent.removeChild(el);\n return true; // Already handled children\n }\n }\n }\n\n return true;\n};\n\n/**\n * Recursively processes children of an element for SSR.\n * @internal\n */\nconst processSSRChildren = (\n parent: Element,\n context: BindingContext,\n prefix: string,\n doc: Document\n): void => {\n // Process children in reverse to handle removals safely\n const children = Array.from(parent.children);\n for (const child of children) {\n // Skip bq-for elements — they're handled by parent\n if (child.hasAttribute(`${prefix}-for`)) {\n // Process the for directive on this element\n const keep = processSSRElement(child, context, prefix, doc);\n if (!keep) {\n child.remove();\n }\n continue;\n }\n\n const keep = processSSRElement(child, context, prefix, doc);\n if (!keep) {\n child.remove();\n continue;\n }\n\n // Recurse into children\n processSSRChildren(child, context, prefix, doc);\n }\n};\n\n/**\n * Strips all directive attributes (bq-*) from an element and its descendants.\n * @internal\n */\nconst stripDirectiveAttributes = (el: Element, prefix: string): void => {\n // Remove directive attributes from this element\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith(`${prefix}-`) || attr.name.startsWith(':') || attr.name === ':key') {\n el.removeAttribute(attr.name);\n }\n }\n\n // Recurse into children\n for (const child of Array.from(el.children)) {\n stripDirectiveAttributes(child, prefix);\n }\n};\n\n/**\n * Server-side renders a bQuery template to an HTML string.\n *\n * Takes an HTML template with bQuery directives (bq-text, bq-if, bq-for, etc.)\n * and a data context, then evaluates the directives to produce a static HTML string.\n * This HTML can be sent to the client and later hydrated with `mount()` using\n * `{ hydrate: true }`.\n *\n * Supported directives:\n * - `bq-text` — Sets text content\n * - `bq-html` — Sets innerHTML\n * - `bq-if` — Conditional rendering (removes element if falsy)\n * - `bq-show` — Toggle visibility via `display: none`\n * - `bq-class` — Dynamic class binding (object or expression syntax)\n * - `bq-style` — Dynamic inline styles\n * - `bq-for` — List rendering\n * - `bq-bind:attr` — Dynamic attribute binding\n *\n * @param template - HTML template string with bq-* directives\n * @param data - Plain data object (signals will be unwrapped automatically)\n * @param options - Rendering options\n * @returns SSR result with HTML string and optional store state\n *\n * @example\n * ```ts\n * import { renderToString } from '@bquery/bquery/ssr';\n * import { signal } from '@bquery/bquery/reactive';\n *\n * const result = renderToString(\n * '<div><h1 bq-text=\"title\"></h1><p bq-if=\"showBody\">Hello!</p></div>',\n * { title: 'Welcome', showBody: true }\n * );\n *\n * console.log(result.html);\n * // '<div><h1>Welcome</h1><p>Hello!</p></div>'\n * ```\n *\n * @example\n * ```ts\n * // With bq-for list rendering\n * const result = renderToString(\n * '<ul><li bq-for=\"item in items\" bq-text=\"item.name\"></li></ul>',\n * { items: [{ name: 'Alice' }, { name: 'Bob' }] }\n * );\n *\n * console.log(result.html);\n * // '<ul><li>Alice</li><li>Bob</li></ul>'\n * ```\n */\nexport const renderToString = (\n template: string,\n data: BindingContext,\n options: RenderOptions = {}\n): SSRResult => {\n const { prefix = 'bq', stripDirectives = false, includeStoreState = false } = options;\n\n if (!template || typeof template !== 'string') {\n throw new Error('bQuery SSR: template must be a non-empty string.');\n }\n\n if (typeof DOMParser === 'undefined') {\n throw new Error(\n 'bQuery SSR: DOMParser is not available in this environment. Provide a DOMParser-compatible implementation before calling renderToString().'\n );\n }\n\n // Create a DOM document for processing\n const parser = new DOMParser();\n const doc = parser.parseFromString(template.trim(), 'text/html');\n const body = doc.body || doc.documentElement;\n\n if (!body) {\n throw new Error('bQuery SSR: Failed to parse template.');\n }\n\n // Process all children of the body\n processSSRChildren(body, data, prefix, doc);\n\n // Strip directive attributes if requested\n if (stripDirectives) {\n for (const child of Array.from(body.children)) {\n stripDirectiveAttributes(child, prefix);\n }\n }\n\n let html = '';\n for (const child of body.childNodes) {\n html += serializeSSRNode(child);\n }\n\n // Handle store state serialization\n let storeState: string | undefined;\n if (includeStoreState) {\n const storeIds = Array.isArray(includeStoreState) ? includeStoreState : undefined;\n storeState = serializeStoreState({ storeIds }).stateJson;\n }\n\n return { html, storeState };\n};\n"],"mappings":"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"}
package/dist/ssr.es.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as r, i as t, n as a, o, r as s, t as i } from "./ssr-B2qd_WBB.js";
1
+ import { a as r, i as t, n as a, o, r as s, t as i } from "./ssr-_dAcGdzu.js";
2
2
  export {
3
3
  a as deserializeStoreState,
4
4
  o as hydrateMount,
@@ -1 +1 @@
1
- {"version":3,"file":"persisted.d.ts","sourceRoot":"","sources":["../../src/store/persisted.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAkB,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA+C7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzE,YAAY,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACpC,UAAU,qBAAqB,GAAG,MAAM,KACvC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAiJf,CAAC"}
1
+ {"version":3,"file":"persisted.d.ts","sourceRoot":"","sources":["../../src/store/persisted.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAkB,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA+C7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzE,YAAY,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACpC,UAAU,qBAAqB,GAAG,MAAM,KACvC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CA6If,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { i as T } from "./object-BCk-1c8T.js";
2
- import { l as E } from "./type-guards-Do9DWgNp.js";
3
- import { n as q } from "./core-DnlyjbF2.js";
4
- import { u as V } from "./reactive-Cfv0RK6x.js";
5
- import { r as B, t as L } from "./untrack-DJVQQ2WM.js";
6
- import { t as U } from "./env-NeVmr4Gf.js";
7
- import { a as G, n as Q, o as H, r as C, s as J } from "./registry-CWf368tT.js";
2
+ import { l as E } from "./type-guards-BMX2c0LP.js";
3
+ import { n as q } from "./core-DdtZHzsS.js";
4
+ import { D as V } from "./reactive-DwkhUJfP.js";
5
+ import { r as B, t as L } from "./untrack-D0fnO5k2.js";
6
+ import { t as U } from "./env-CTdvLaH2.js";
7
+ import { a as G, n as Q, o as H, r as C, s as J } from "./registry-B08iilIh.js";
8
8
  var M = [], ce = (e) => {
9
9
  M.push(e);
10
10
  }, W = (e, t) => {
@@ -335,4 +335,4 @@ export {
335
335
  ge as t
336
336
  };
337
337
 
338
- //# sourceMappingURL=store-DWpyH6p5.js.map
338
+ //# sourceMappingURL=store-Cb3gPRve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-Cb3gPRve.js","names":[],"sources":["../src/store/plugins.ts","../src/store/utils.ts","../src/store/create-store.ts","../src/store/define-store.ts","../src/store/mapping.ts","../src/store/persisted.ts","../src/store/watch.ts"],"sourcesContent":["/**\n * Store plugins API.\n */\n\nimport type { Store, StoreDefinition, StorePlugin } from './types';\n\n/** @internal Registered plugins */\nconst plugins: StorePlugin[] = [];\n\n/**\n * Registers a plugin that extends all stores.\n *\n * @param plugin - The plugin function\n */\nexport const registerPlugin = (plugin: StorePlugin): void => {\n plugins.push(plugin);\n};\n\n/** @internal */\nexport const applyPlugins = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: StoreDefinition<any, any, any>\n): void => {\n for (const plugin of plugins) {\n const extension = plugin({ store, options });\n if (extension) {\n Object.assign(store, extension);\n }\n }\n};\n","/**\n * Internal utilities for the store module.\n * @internal\n */\n\nimport { detectDevEnvironment } from '../core/env';\n\n/**\n * Check if a value is a plain object (not array, null, Date, etc.).\n * @internal\n */\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return (\n value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\n );\n};\n\n/**\n * Deep clones an object. Used for deep reactivity support.\n * @internal\n */\nexport const deepClone = <T>(obj: T): T => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(deepClone) as T;\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as T;\n }\n\n if (obj instanceof Map) {\n return new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepClone(v)])) as T;\n }\n\n if (obj instanceof Set) {\n return new Set(Array.from(obj).map(deepClone)) as T;\n }\n\n const cloned = {} as T;\n for (const key of Object.keys(obj)) {\n (cloned as Record<string, unknown>)[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return cloned;\n};\n\n/**\n * Compares two values for deep equality.\n * @internal\n */\nexport const deepEqual = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (const [key, value] of a.entries()) {\n if (!b.has(key) || !deepEqual(value, b.get(key))) return false;\n }\n return true;\n }\n\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n for (const value of a.values()) {\n let found = false;\n for (const candidate of b.values()) {\n if (deepEqual(value, candidate)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n return true;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((item, i) => deepEqual(item, b[i]));\n }\n\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n\n if (keysA.length !== keysB.length) return false;\n\n return keysA.every((key) =>\n deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\n );\n};\n\n/**\n * Detects if nested objects were mutated but the reference stayed the same.\n * Returns the keys where nested mutations were detected.\n * @internal\n */\nexport const detectNestedMutations = <S extends Record<string, unknown>>(\n before: S,\n after: S,\n signalValues: Map<keyof S, unknown>\n): Array<keyof S> => {\n const mutatedKeys: Array<keyof S> = [];\n\n for (const key of Object.keys(after) as Array<keyof S>) {\n const beforeValue = before[key];\n const afterValue = after[key];\n const signalValue = signalValues.get(key);\n\n // Check if it's the same reference but content changed\n if (\n signalValue === afterValue &&\n isPlainObject(beforeValue) &&\n isPlainObject(afterValue) &&\n !deepEqual(beforeValue, afterValue)\n ) {\n mutatedKeys.push(key);\n }\n }\n\n return mutatedKeys;\n};\n\n/** @internal Returns whether development warnings should be enabled */\nexport const isDev = (): boolean => detectDevEnvironment();\n","/**\n * Store creation logic.\n */\n\nimport { isPromise } from '../core/utils/type-guards';\nimport {\n batch,\n computed,\n signal,\n untrack,\n type ReadonlySignal,\n type Signal,\n} from '../reactive/index';\nimport { notifyDevtoolsStateChange, registerDevtoolsStore } from './devtools';\nimport { applyPlugins } from './plugins';\nimport { getStore, hasStore, registerStore } from './registry';\nimport type {\n ActionContext,\n Getters,\n OnActionCallback,\n Store,\n StoreDefinition,\n StoreSubscriber,\n} from './types';\nimport { deepClone, detectNestedMutations, isDev } from './utils';\n\n/**\n * Creates a reactive store with state, getters, and actions.\n *\n * @template S - State type\n * @template G - Getters type\n * @template A - Actions type\n * @param definition - Store definition\n * @returns The reactive store instance\n */\nexport const createStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n definition: StoreDefinition<S, G, A>\n): Store<S, G, A> => {\n const { id, state: stateFactory, getters = {} as Getters<S, G>, actions = {} as A } = definition;\n\n // Check for duplicate store IDs\n if (hasStore(id)) {\n console.warn(`bQuery store: Store \"${id}\" already exists. Returning existing instance.`);\n return getStore(id) as Store<S, G, A>;\n }\n\n // Create initial state\n const initialState = stateFactory();\n\n // Create signals for each state property\n const stateSignals = new Map<keyof S, Signal<unknown>>();\n for (const key of Object.keys(initialState) as Array<keyof S>) {\n stateSignals.set(key, signal(initialState[key]));\n }\n\n // Subscribers for $subscribe\n const subscribers: Array<StoreSubscriber<S>> = [];\n\n // Action lifecycle hooks for $onAction\n const actionListeners: Array<OnActionCallback<S, G, A>> = [];\n\n const reportOnActionError = (\n phase: 'listener' | 'after' | 'onError',\n actionName: string,\n error: unknown\n ): void => {\n if (!isDev() || typeof console === 'undefined' || typeof console.error !== 'function') return;\n console.error(\n `[bQuery store \"${id}\"] Error in $onAction ${phase} for action \"${actionName}\"`,\n error\n );\n };\n\n const warnedAsyncOnActionListeners = new WeakSet<OnActionCallback<S, G, A>>();\n\n const warnAsyncOnActionListener = (\n listener: OnActionCallback<S, G, A>,\n actionName: string\n ): void => {\n if (!isDev() || typeof console === 'undefined' || typeof console.warn !== 'function') return;\n if (warnedAsyncOnActionListeners.has(listener)) return;\n warnedAsyncOnActionListeners.add(listener);\n console.warn(\n `[bQuery store \"${id}\"] Async $onAction listener detected for action \"${actionName}\". If it awaits, register after()/onError() before the first await; late registrations will not affect the current action.`\n );\n };\n\n /**\n * Executes an action observer callback without allowing observer failures to\n * affect the action result. Handles both synchronous exceptions and async\n * rejections, routing all failures through the standard $onAction logger.\n *\n * @internal\n */\n const runOnActionCallback = (\n phase: 'listener' | 'after' | 'onError',\n actionName: string,\n callback: () => unknown,\n listener?: OnActionCallback<S, G, A>\n ): void => {\n try {\n const result = callback();\n if (isPromise(result)) {\n if (phase === 'listener' && listener) {\n warnAsyncOnActionListener(listener, actionName);\n }\n void result.catch((error) => {\n reportOnActionError(phase, actionName, error);\n });\n }\n } catch (error) {\n reportOnActionError(phase, actionName, error);\n }\n };\n\n /**\n * Gets the current state.\n *\n * For subscriber notifications (where a plain object snapshot is needed),\n * this creates a shallow copy. For internal reads, use stateProxy directly.\n *\n * **Note:** Returns a shallow snapshot. Nested object mutations will NOT\n * trigger reactive updates. This differs from frameworks like Pinia that\n * use deep reactivity. To update nested state, replace the entire object.\n *\n * Uses `untrack()` to prevent accidental dependency tracking when called\n * from within reactive contexts (e.g., `effect()` or `computed()`).\n *\n * @internal\n */\n const getCurrentState = (): S =>\n untrack(() => {\n return { ...stateProxy };\n });\n\n /**\n * Notifies subscribers of state changes.\n * Short-circuits if there are no subscribers and devtools aren't active\n * to avoid unnecessary snapshot overhead.\n * @internal\n */\n const notifySubscribers = (): void => {\n // Early return if no subscribers and no devtools hook\n const hasDevtools =\n typeof window !== 'undefined' &&\n typeof window.__BQUERY_DEVTOOLS__?.onStateChange === 'function';\n if (subscribers.length === 0 && !hasDevtools) {\n return;\n }\n\n const currentState = getCurrentState();\n for (const callback of subscribers) {\n callback(currentState);\n }\n\n notifyDevtoolsStateChange(id, currentState);\n };\n\n /**\n * Cached state proxy that lazily reads signal values.\n * Uses a Proxy to avoid creating new objects on each access.\n *\n * **Note:** This returns a shallow snapshot of the state. Nested object\n * mutations will NOT trigger reactive updates. For nested reactivity,\n * replace the entire object or use signals for nested properties.\n *\n * @internal\n */\n const stateProxy = new Proxy({} as S, {\n get: (_, prop: string | symbol) => {\n const key = prop as keyof S;\n if (stateSignals.has(key)) {\n return stateSignals.get(key)!.value;\n }\n return undefined;\n },\n ownKeys: () => Array.from(stateSignals.keys()) as string[],\n getOwnPropertyDescriptor: (_, prop) => {\n if (stateSignals.has(prop as keyof S)) {\n return { enumerable: true, configurable: true };\n }\n return undefined;\n },\n has: (_, prop) => stateSignals.has(prop as keyof S),\n });\n\n // Create computed getters\n const getterComputed = new Map<keyof G, ReadonlySignal<unknown>>();\n\n // Build the store proxy\n const store = {} as Store<S, G, A>;\n\n // Define state properties with getters/setters\n for (const key of Object.keys(initialState) as Array<keyof S>) {\n Object.defineProperty(store, key, {\n get: () => stateSignals.get(key)!.value,\n set: (value: unknown) => {\n stateSignals.get(key)!.value = value;\n notifySubscribers();\n },\n enumerable: true,\n configurable: false,\n });\n }\n\n // Define getters as computed properties\n for (const key of Object.keys(getters) as Array<keyof G>) {\n const getterFn = getters[key];\n\n // Create computed that reads from state signals via proxy (more efficient)\n const computedGetter = computed(() => {\n const state = stateProxy;\n // For getter dependencies, pass a proxy that reads from computed getters\n const getterProxy = new Proxy({} as G, {\n get: (_, prop: string | symbol) => {\n const propKey = prop as keyof G;\n if (getterComputed.has(propKey)) {\n return getterComputed.get(propKey)!.value;\n }\n return undefined;\n },\n });\n return getterFn(state, getterProxy);\n });\n\n getterComputed.set(key, computedGetter as unknown as ReadonlySignal<unknown>);\n\n Object.defineProperty(store, key, {\n get: () => computedGetter.value,\n enumerable: true,\n configurable: false,\n });\n }\n\n // Bind actions to the store context, with $onAction lifecycle support\n for (const key of Object.keys(actions) as Array<keyof A>) {\n const actionFn = actions[key];\n const actionName = key as keyof A & string;\n\n // Wrap action to enable 'this' binding and $onAction hooks\n (store as Record<string, unknown>)[actionName] = function (...args: unknown[]) {\n // Create a context that allows 'this.property' access\n const context = new Proxy(store, {\n get: (target, prop) => {\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\n return stateSignals.get(prop as keyof S)!.value;\n }\n return (target as Record<string, unknown>)[prop as string];\n },\n set: (target, prop, value) => {\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\n stateSignals.get(prop as keyof S)!.value = value;\n notifySubscribers();\n return true;\n }\n // Allow non-state property assignments (e.g., temporary variables in actions)\n // by delegating to the target object rather than returning false\n return Reflect.set(target, prop, value);\n },\n });\n\n // Run $onAction hooks if any listeners are registered\n if (actionListeners.length === 0) {\n return actionFn.apply(context, args);\n }\n\n const afterHooks: Array<(result: unknown) => void> = [];\n const errorHooks: Array<(error: unknown) => void> = [];\n const listenerSnapshot = [...actionListeners];\n\n const listenerContext = {\n name: actionName,\n store,\n args: args as Parameters<A[typeof actionName]>,\n after: (callback: (result: Awaited<ReturnType<A[typeof actionName]>>) => void) => {\n afterHooks.push((result) =>\n callback(result as Awaited<ReturnType<A[typeof actionName]>>)\n );\n },\n onError: (callback: (error: unknown) => void) => {\n errorHooks.push(callback);\n },\n } satisfies ActionContext<S, G, A, typeof actionName>;\n\n // Notify all action listeners (before phase)\n for (const listener of listenerSnapshot) {\n runOnActionCallback('listener', actionName, () => listener(listenerContext), listener);\n }\n\n let result: unknown;\n try {\n result = actionFn.apply(context, args);\n } catch (error) {\n for (const hook of errorHooks) {\n runOnActionCallback('onError', actionName, () => hook(error));\n }\n throw error;\n }\n\n // Handle async actions (promises)\n if (isPromise(result)) {\n return result.then(\n (resolved) => {\n for (const hook of afterHooks) {\n runOnActionCallback('after', actionName, () => hook(resolved));\n }\n return resolved;\n },\n (error) => {\n for (const hook of errorHooks) {\n runOnActionCallback('onError', actionName, () => hook(error));\n }\n throw error;\n }\n );\n }\n\n // Sync action — run after hooks immediately\n for (const hook of afterHooks) {\n runOnActionCallback('after', actionName, () => hook(result));\n }\n return result;\n };\n }\n\n // Add store utility methods\n Object.defineProperties(store, {\n $id: {\n value: id,\n writable: false,\n enumerable: false,\n },\n $reset: {\n value: () => {\n const fresh = stateFactory();\n batch(() => {\n for (const [key, sig] of stateSignals) {\n sig.value = fresh[key];\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $subscribe: {\n value: (callback: StoreSubscriber<S>) => {\n subscribers.push(callback);\n return () => {\n const index = subscribers.indexOf(callback);\n if (index > -1) subscribers.splice(index, 1);\n };\n },\n writable: false,\n enumerable: false,\n },\n $onAction: {\n value: (callback: OnActionCallback<S, G, A>) => {\n actionListeners.push(callback);\n return () => {\n const index = actionListeners.indexOf(callback);\n if (index > -1) actionListeners.splice(index, 1);\n };\n },\n writable: false,\n enumerable: false,\n },\n $patch: {\n value: (partial: Partial<S> | ((state: S) => void)) => {\n batch(() => {\n if (typeof partial === 'function') {\n // Capture state before mutation for nested mutation detection\n const devMode = isDev();\n const stateBefore = devMode ? deepClone(getCurrentState()) : null;\n const signalValuesBefore = devMode\n ? new Map(Array.from(stateSignals.entries()).map(([k, s]) => [k, s.value]))\n : null;\n\n // Mutation function\n const state = getCurrentState();\n partial(state);\n\n // Detect nested mutations in development mode\n if (devMode && stateBefore && signalValuesBefore) {\n const mutatedKeys = detectNestedMutations(stateBefore, state, signalValuesBefore);\n if (mutatedKeys.length > 0) {\n console.warn(\n `[bQuery store \"${id}\"] Nested mutation detected in $patch() for keys: ${mutatedKeys\n .map(String)\n .join(', ')}.\\n` +\n 'Nested object mutations do not trigger reactive updates because the store uses shallow reactivity.\\n' +\n 'To fix this, either:\\n' +\n ' 1. Replace the entire object: state.user = { ...state.user, name: \"New\" }\\n' +\n ' 2. Use $patchDeep() for automatic deep cloning\\n' +\n 'See: https://bquery.dev/guide/store#deep-reactivity'\n );\n }\n }\n\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n } else {\n // Partial object\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $patchDeep: {\n value: (partial: Partial<S> | ((state: S) => void)) => {\n batch(() => {\n if (typeof partial === 'function') {\n // Deep clone state before mutation to ensure new references\n const state = deepClone(getCurrentState());\n partial(state);\n\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n } else {\n // Deep clone each value in partial to ensure new references\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = deepClone(value);\n }\n }\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $state: {\n get: () => getCurrentState(),\n enumerable: false,\n },\n });\n\n // Register store\n registerStore(id, store);\n\n // Apply plugins\n applyPlugins(store, definition);\n\n // Notify devtools\n registerDevtoolsStore(id, store);\n\n return store;\n};\n","/**\n * Store factory helpers.\n */\n\nimport { createStore } from './create-store';\nimport { getStore, hasStore } from './registry';\nimport type { Store, StoreDefinition } from './types';\n\n/**\n * Creates a store factory that returns the store instance.\n *\n * The store is lazily created on first call and cached in the global store\n * registry. Subsequent calls return the same instance. After calling\n * `destroyStore(id)`, the next factory call will create a fresh store.\n *\n * @param id - Store identifier\n * @param definition - Store definition without id\n * @returns A function that returns the store instance\n *\n * @example\n * ```ts\n * const useCounter = defineStore('counter', {\n * state: () => ({ count: 0 }),\n * actions: { increment() { this.count++; } },\n * });\n *\n * const counter = useCounter();\n * counter.increment();\n * ```\n */\nexport const defineStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n id: string,\n definition: Omit<StoreDefinition<S, G, A>, 'id'>\n): (() => Store<S, G, A>) => {\n // Check registry first to avoid noisy warnings from createStore()\n // when the factory is called multiple times (intended usage pattern).\n // createStore() only called when store doesn't exist or was destroyed.\n return () => {\n if (hasStore(id)) {\n return getStore(id) as Store<S, G, A>;\n }\n return createStore({ id, ...definition });\n };\n};\n","/**\n * Mapping helpers for store state and actions.\n */\n\n/**\n * Maps store state properties to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - State keys to map\n * @returns Object with mapped properties\n */\nexport const mapState = <S extends Record<string, unknown>, K extends keyof S>(\n store: S,\n keys: K[]\n): Pick<S, K> => {\n const mapped = {} as Pick<S, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store getters to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - Getter keys to map\n * @returns Object with mapped getters\n */\nexport const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(\n store: G,\n keys: K[]\n): Pick<G, K> => {\n const mapped = {} as Pick<G, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store actions to an object for easier destructuring.\n *\n * @param store - The store instance\n * @param keys - Action keys to map\n * @returns Object with mapped actions\n */\nexport const mapActions = <\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any>,\n K extends keyof A,\n>(\n store: A,\n keys: K[]\n): Pick<A, K> => {\n const mapped = {} as Pick<A, K>;\n\n for (const key of keys) {\n (mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>\n (store[key] as (...args: unknown[]) => unknown)(...args);\n }\n\n return mapped;\n};\n","/**\n * Store persistence helpers.\n */\n\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport { createStore } from './create-store';\nimport { isDev } from './utils';\nimport type { PersistedStoreOptions, StorageBackend, Store, StoreDefinition } from './types';\n\n/** @internal Version key suffix */\nconst VERSION_SUFFIX = '__version';\n\n/** @internal Default JSON serializer */\nconst defaultSerializer = {\n serialize: (state: unknown) => JSON.stringify(state),\n deserialize: (raw: string) => JSON.parse(raw) as unknown,\n};\n\n/** @internal Check whether a value can be merged into store state. */\nconst isPersistedStateObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n};\n\n/**\n * Applies persisted state onto the default state while ignoring dangerous\n * prototype-pollution keys such as `__proto__`, `constructor`, and `prototype`.\n *\n * @internal\n */\nconst mergePersistedState = <S extends Record<string, unknown>>(\n defaultState: S,\n persisted: Record<string, unknown>\n): S => {\n const merged = { ...defaultState };\n for (const [key, value] of Object.entries(persisted)) {\n if (isPrototypePollutionKey(key)) continue;\n if (!Object.prototype.hasOwnProperty.call(defaultState, key)) continue;\n merged[key as keyof S] = value as S[keyof S];\n }\n return merged;\n};\n\n/** @internal Resolve the default storage backend safely. */\nconst getDefaultStorage = (): StorageBackend | undefined => {\n try {\n return globalThis.localStorage;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Creates a store with automatic persistence.\n *\n * Supports configurable storage backends, custom serializers, and schema\n * versioning with migration functions. All options are optional and\n * backward-compatible with the simple `(definition, storageKey?)` signature.\n *\n * @param definition - Store definition\n * @param options - Persistence options or a plain string storage key for backward compatibility\n * @returns The reactive store instance\n *\n * @example Basic usage (localStorage + JSON)\n * ```ts\n * const store = createPersistedStore({\n * id: 'settings',\n * state: () => ({ theme: 'dark' }),\n * });\n * ```\n *\n * @example With sessionStorage and custom key\n * ```ts\n * const store = createPersistedStore(\n * { id: 'session', state: () => ({ token: '' }) },\n * { key: 'my-session', storage: sessionStorage },\n * );\n * ```\n *\n * @example With versioning and migration\n * ```ts\n * const store = createPersistedStore(\n * { id: 'app', state: () => ({ name: '', theme: 'auto' }) },\n * {\n * version: 2,\n * migrate: (old, v) => {\n * if (v < 2) return { ...old, theme: 'auto' };\n * return old;\n * },\n * },\n * );\n * ```\n */\nexport const createPersistedStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n definition: StoreDefinition<S, G, A>,\n options?: PersistedStoreOptions | string\n): Store<S, G, A> => {\n // Normalize options — a plain string is treated as the storage key for backward compatibility\n const opts: PersistedStoreOptions =\n typeof options === 'string' ? { key: options } : (options ?? {});\n\n const key = opts.key ?? `bquery-store-${definition.id}`;\n const storage = opts.storage ?? getDefaultStorage();\n const serializer = opts.serializer ?? defaultSerializer;\n const version = opts.version;\n const migrate = opts.migrate;\n const versionKey = key + VERSION_SUFFIX;\n let shouldPersistInitialVersion = storage !== undefined && version !== undefined;\n let pendingVersionWrite = false;\n let canRetryPendingVersionAfterCreate = false;\n\n const tryPersistVersion = (warningMessage?: string): boolean => {\n if (!storage || version === undefined) return false;\n\n try {\n storage.setItem(versionKey, String(version));\n return true;\n } catch (error) {\n if (\n warningMessage &&\n isDev() &&\n typeof console !== 'undefined' &&\n typeof console.warn === 'function'\n ) {\n console.warn(warningMessage, error);\n }\n return false;\n }\n };\n\n const originalStateFactory = definition.state;\n\n const wrappedDefinition: StoreDefinition<S, G, A> = {\n ...definition,\n state: () => {\n const defaultState = originalStateFactory();\n\n if (!storage) return defaultState;\n\n try {\n const saved = storage.getItem(key);\n if (!saved) return defaultState;\n\n const deserialized = serializer.deserialize(saved);\n if (!isPersistedStateObject(deserialized)) {\n return defaultState;\n }\n\n let persisted = deserialized;\n\n // Handle versioning & migration\n if (version !== undefined && migrate) {\n const rawVersion = storage.getItem(versionKey);\n const parsedVersion = rawVersion !== null ? Number(rawVersion) : 0;\n const oldVersion = Number.isFinite(parsedVersion) ? parsedVersion : 0;\n\n if (oldVersion !== version) {\n shouldPersistInitialVersion = false;\n pendingVersionWrite = true;\n const migrated = migrate(persisted, oldVersion);\n if (!isPersistedStateObject(migrated)) {\n return defaultState;\n }\n persisted = migrated;\n\n let migratedStatePersisted = false;\n // Save the migrated state and version immediately when possible.\n // If the state write fails, never advance the version key.\n try {\n storage.setItem(key, serializer.serialize(persisted));\n migratedStatePersisted = true;\n canRetryPendingVersionAfterCreate = true;\n } catch (e) {\n // Migration will re-run on next load, but state is still usable\n if (isDev() && typeof console !== 'undefined' && typeof console.warn === 'function') {\n console.warn(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated state:`,\n e\n );\n }\n }\n\n if (\n migratedStatePersisted &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version:`\n )\n ) {\n pendingVersionWrite = false;\n }\n } else {\n shouldPersistInitialVersion = false;\n }\n }\n\n return mergePersistedState(defaultState, persisted);\n } catch {\n // Ignore parse errors\n return defaultState;\n }\n },\n };\n\n const store = createStore(wrappedDefinition);\n\n // Persist the version number on first creation\n if (shouldPersistInitialVersion && storage) {\n tryPersistVersion();\n } else if (\n pendingVersionWrite &&\n canRetryPendingVersionAfterCreate &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after store creation:`\n )\n ) {\n pendingVersionWrite = false;\n }\n\n // Subscribe to save changes\n store.$subscribe((state) => {\n if (!storage) return;\n try {\n storage.setItem(key, serializer.serialize(state));\n if (\n pendingVersionWrite &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after a successful state write:`\n )\n ) {\n pendingVersionWrite = false;\n }\n } catch {\n // Ignore quota errors\n }\n });\n\n return store;\n};\n","/**\n * Store watch helpers.\n */\n\nimport type { Store } from './types';\nimport { deepEqual } from './utils';\n\nexport type WatchStoreOptions<T> = {\n /** Call the callback immediately with the current value. */\n immediate?: boolean;\n /** Use deep comparison when determining changes. */\n deep?: boolean;\n /** Custom equality check for selected values. */\n equals?: (a: T, b: T) => boolean;\n};\n\n/**\n * Watch a selected slice of store state.\n *\n * @param store - The store instance\n * @param selector - Function to select the watched value\n * @param callback - Called when the selected value changes\n * @param options - Watch options\n * @returns Unsubscribe function\n */\nexport const watchStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any>,\n T,\n>(\n store: Store<S, G, A>,\n selector: (state: S) => T,\n callback: (value: T, previous: T | undefined) => void,\n options: WatchStoreOptions<T> = {}\n): (() => void) => {\n const equals = options.equals ?? (options.deep ? deepEqual : Object.is);\n let previous = selector(store.$state);\n\n if (options.immediate) {\n callback(previous, undefined);\n }\n\n return store.$subscribe((state) => {\n const current = selector(state);\n if (!equals(current, previous)) {\n const prev = previous;\n previous = current;\n callback(current, prev);\n }\n });\n};\n"],"mappings":"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"}
package/dist/store.es.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { i as e, n as r, t as s } from "./registry-CWf368tT.js";
2
- import { a as o, c as i, i as S, n as m, o as p, r as c, s as n, t as d } from "./store-DWpyH6p5.js";
1
+ import { i as e, n as r, t as s } from "./registry-B08iilIh.js";
2
+ import { a as o, c as i, i as S, n as m, o as p, r as c, s as n, t as d } from "./store-Cb3gPRve.js";
3
3
  export {
4
4
  m as createPersistedStore,
5
5
  n as createStore,
@@ -1 +1 @@
1
- {"version":3,"file":"storybook.es.mjs","names":[],"sources":["../src/storybook/index.ts"],"sourcesContent":["/**\r\n * Storybook template helpers for authoring bQuery component stories.\r\n *\r\n * `storyHtml` mirrors bQuery's string-based `html` tag while adding support for\r\n * Storybook-friendly boolean attribute shorthand (`?disabled=${true}`).\r\n *\r\n * @module bquery/storybook\r\n */\r\n\r\nimport { sanitizeHtml } from '../security/sanitize';\r\n\r\ntype StoryValue = string | number | boolean | null | undefined | StoryValue[] | (() => StoryValue);\r\n\r\n/**\r\n * Marks template interpolation boundaries while inferring sanitizer allowlists.\r\n * Uses the null character because authored HTML/template strings should not\r\n * contain it, making it a safe internal sentinel during parsing.\r\n */\r\nconst INTERPOLATION_BOUNDARY_MARKER = '\\u0000';\r\n\r\nconst isWhitespace = (value: string): boolean => {\r\n return value === ' ' || value === '\\t' || value === '\\n' || value === '\\r' || value === '\\f';\r\n};\r\n\r\n/**\r\n * Detects interpolation boundaries embedded into joined template string fragments.\r\n */\r\nconst isInterpolationBoundaryMarker = (value: string): boolean =>\r\n value === INTERPOLATION_BOUNDARY_MARKER;\r\n\r\nconst isAttributeSeparator = (value: string): boolean => {\r\n return isWhitespace(value) || isInterpolationBoundaryMarker(value);\r\n};\r\n\r\nconst isAsciiLetter = (value: string): boolean => {\r\n const code = value.charCodeAt(0);\r\n\r\n return (code >= 65 && code <= 90) || (code >= 97 && code <= 122);\r\n};\r\n\r\nconst isAttributeNameStart = (value: string): boolean => isAsciiLetter(value);\r\n\r\nconst isAttributeNameChar = (value: string): boolean => {\r\n const code = value.charCodeAt(0);\r\n\r\n return (\r\n isAsciiLetter(value) ||\r\n (code >= 48 && code <= 57) ||\r\n value === ':' ||\r\n value === '.' ||\r\n value === '_' ||\r\n value === '-'\r\n );\r\n};\r\n\r\nconst isQuoteChar = (value: string): boolean => value === '\"' || value === \"'\";\r\n\r\nconst isTagNameChar = (value: string): boolean => {\r\n const code = value.charCodeAt(0);\r\n\r\n return (\r\n isAsciiLetter(value) ||\r\n (code >= 48 && code <= 57) ||\r\n value === '.' ||\r\n value === '_' ||\r\n value === '-'\r\n );\r\n};\r\n\r\nconst hasLineBreak = (value: string): boolean => {\r\n for (let index = 0; index < value.length; index += 1) {\r\n if (value[index] === '\\n' || value[index] === '\\r') {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst getTagNameEnd = (fragment: string): number => {\r\n let index = 0;\r\n\r\n while (\r\n index < fragment.length &&\r\n !isAttributeSeparator(fragment[index]) &&\r\n fragment[index] !== '/' &&\r\n fragment[index] !== '>'\r\n ) {\r\n index += 1;\r\n }\r\n\r\n return index;\r\n};\r\n\r\nconst isCustomElementTagName = (tagName: string): boolean => {\r\n if (!tagName.includes('-') || !isAsciiLetter(tagName[0])) {\r\n return false;\r\n }\r\n\r\n const last = tagName[tagName.length - 1];\r\n const code = last.charCodeAt(0);\r\n\r\n return isAsciiLetter(last) || (code >= 48 && code <= 57) || last === '.' || last === '_';\r\n};\r\n\r\nconst isAutoAllowedStoryAttribute = (attributeName: string): boolean => {\r\n return attributeName !== 'style' && !attributeName.startsWith('on');\r\n};\r\n\r\nconst findBooleanAttributeSuffix = (\r\n part: string\r\n): { attribute: string; basePart: string; spacing: string } | null => {\r\n let index = part.length - 1;\r\n\r\n while (index >= 0 && isWhitespace(part[index])) {\r\n index -= 1;\r\n }\r\n\r\n if (index < 0 || part[index] !== '=') {\r\n return null;\r\n }\r\n\r\n index -= 1;\r\n\r\n while (index >= 0 && isWhitespace(part[index])) {\r\n index -= 1;\r\n }\r\n\r\n const attributeEnd = index;\r\n\r\n while (\r\n index >= 0 &&\r\n !isWhitespace(part[index]) &&\r\n part[index] !== '?' &&\r\n part[index] !== '=' &&\r\n part[index] !== '/' &&\r\n part[index] !== '>'\r\n ) {\r\n index -= 1;\r\n }\r\n\r\n const attributeStart = index + 1;\r\n\r\n if (attributeStart > attributeEnd || part[index] !== '?') {\r\n return null;\r\n }\r\n\r\n const questionMarkIndex = index;\r\n let spacingStart = questionMarkIndex;\r\n\r\n while (spacingStart > 0 && isWhitespace(part[spacingStart - 1])) {\r\n spacingStart -= 1;\r\n }\r\n\r\n return {\r\n attribute: part.slice(attributeStart, attributeEnd + 1),\r\n basePart: part.slice(0, spacingStart),\r\n spacing: part.slice(spacingStart, questionMarkIndex),\r\n };\r\n};\r\n\r\nconst collectOpeningTagFragments = (template: string): string[] => {\r\n const fragments: string[] = [];\r\n let index = 0;\r\n\r\n while (index < template.length) {\r\n if (template[index] !== '<') {\r\n index += 1;\r\n continue;\r\n }\r\n\r\n const next = template[index + 1];\r\n\r\n if (!next || next === '/' || next === '!' || next === '?') {\r\n index += 1;\r\n continue;\r\n }\r\n\r\n let cursor = index + 1;\r\n\r\n if (!isAsciiLetter(template[cursor])) {\r\n index += 1;\r\n continue;\r\n }\r\n\r\n while (cursor < template.length && isTagNameChar(template[cursor])) {\r\n cursor += 1;\r\n }\r\n\r\n const tagStart = index + 1;\r\n const tagName = template.slice(tagStart, cursor);\r\n\r\n if (!tagName) {\r\n index += 1;\r\n continue;\r\n }\r\n\r\n let inQuote: '\"' | \"'\" | null = null;\r\n let tagEnd = cursor;\r\n\r\n while (tagEnd < template.length) {\r\n const char = template[tagEnd];\r\n\r\n if (inQuote) {\r\n if (char === inQuote) {\r\n inQuote = null;\r\n }\r\n\r\n tagEnd += 1;\r\n continue;\r\n }\r\n\r\n if (char === '\"' || char === \"'\") {\r\n inQuote = char;\r\n tagEnd += 1;\r\n continue;\r\n }\r\n\r\n if (char === '>') {\r\n fragments.push(template.slice(index + 1, tagEnd));\r\n tagEnd += 1;\r\n break;\r\n }\r\n\r\n tagEnd += 1;\r\n }\r\n\r\n index = tagEnd;\r\n }\r\n\r\n return fragments;\r\n};\r\n\r\n/**\r\n * Consumes a literal HTML attribute value starting at the given index.\r\n *\r\n * Returns the position immediately after a quoted or unquoted value. When the\r\n * current position reaches an interpolation boundary (optionally after\r\n * whitespace), the returned index advances past the boundary marker so\r\n * interpolated attributes do not swallow following authored attributes during\r\n * sanitizer allowlist inference.\r\n *\r\n * @param fragment - The opening-tag fragment currently being scanned\r\n * @param index - The position immediately after the `=` sign\r\n * @returns The index after the consumed literal value, or just past an\r\n * interpolation boundary when no literal value should be consumed from the\r\n * current template fragment.\r\n */\r\nconst skipAttributeValue = (fragment: string, index: number): number => {\r\n if (index >= fragment.length) {\r\n return index;\r\n }\r\n\r\n let cursor = index;\r\n\r\n if (isInterpolationBoundaryMarker(fragment[cursor])) {\r\n return cursor + 1;\r\n }\r\n\r\n while (cursor < fragment.length && isWhitespace(fragment[cursor])) {\r\n cursor += 1;\r\n }\r\n\r\n if (cursor >= fragment.length) {\r\n return cursor;\r\n }\r\n\r\n if (isInterpolationBoundaryMarker(fragment[cursor])) {\r\n return cursor + 1;\r\n }\r\n\r\n const quote = fragment[cursor];\r\n\r\n if (isQuoteChar(quote)) {\r\n cursor += 1;\r\n\r\n while (cursor < fragment.length) {\r\n if (fragment[cursor] === quote) {\r\n return cursor + 1;\r\n }\r\n\r\n cursor += 1;\r\n }\r\n\r\n return cursor;\r\n }\r\n\r\n while (\r\n cursor < fragment.length &&\r\n !isAttributeSeparator(fragment[cursor]) &&\r\n fragment[cursor] !== '/' &&\r\n fragment[cursor] !== '>'\r\n ) {\r\n cursor += 1;\r\n }\r\n\r\n if (cursor < fragment.length && isInterpolationBoundaryMarker(fragment[cursor])) {\r\n return cursor + 1;\r\n }\r\n\r\n return cursor;\r\n};\r\n\r\nconst collectAttributesFromTagFragment = (\r\n fragment: string,\r\n allowAttributes: Set<string>,\r\n autoAllowAttributes: boolean\r\n): void => {\r\n let index = 0;\r\n\r\n while (index < fragment.length && !isAttributeSeparator(fragment[index])) {\r\n index += 1;\r\n }\r\n\r\n while (index < fragment.length) {\r\n while (index < fragment.length && isAttributeSeparator(fragment[index])) {\r\n index += 1;\r\n }\r\n\r\n if (index >= fragment.length || fragment[index] === '/') {\r\n return;\r\n }\r\n\r\n // Skip standalone colons (e.g. namespace prefixes or framework-specific bindings)\r\n if (fragment[index] === ':') {\r\n index += 1;\r\n continue;\r\n }\r\n\r\n const hasBooleanPrefix = fragment[index] === '?';\r\n\r\n if (hasBooleanPrefix) {\r\n index += 1;\r\n }\r\n\r\n if (index >= fragment.length || !isAttributeNameStart(fragment[index])) {\r\n // Skip unrecognised character to avoid an infinite loop\r\n index += 1;\r\n continue;\r\n }\r\n\r\n const nameStart = index;\r\n\r\n index += 1;\r\n\r\n while (index < fragment.length && isAttributeNameChar(fragment[index])) {\r\n index += 1;\r\n }\r\n\r\n const attributeName = fragment.slice(nameStart, index).toLowerCase();\r\n\r\n while (index < fragment.length && isAttributeSeparator(fragment[index])) {\r\n index += 1;\r\n }\r\n\r\n if (index < fragment.length && fragment[index] === '=') {\r\n if (autoAllowAttributes && isAutoAllowedStoryAttribute(attributeName)) {\r\n allowAttributes.add(attributeName);\r\n }\r\n index = skipAttributeValue(fragment, index + 1);\r\n continue;\r\n }\r\n\r\n if (hasBooleanPrefix && autoAllowAttributes && isAutoAllowedStoryAttribute(attributeName)) {\r\n allowAttributes.add(attributeName);\r\n }\r\n }\r\n};\r\n\r\nconst collectTemplateSanitizeOptions = (strings: TemplateStringsArray) => {\r\n const template = strings.join(INTERPOLATION_BOUNDARY_MARKER);\r\n const allowTags = new Set<string>();\r\n const allowAttributes = new Set<string>();\r\n\r\n for (const fragment of collectOpeningTagFragments(template)) {\r\n const tagName = fragment.slice(0, getTagNameEnd(fragment)).toLowerCase();\r\n const isCustomElement = isCustomElementTagName(tagName);\r\n\r\n if (isCustomElement) {\r\n allowTags.add(tagName);\r\n }\r\n\r\n collectAttributesFromTagFragment(fragment, allowAttributes, isCustomElement);\r\n }\r\n\r\n return {\r\n allowTags: Array.from(allowTags),\r\n allowAttributes: Array.from(allowAttributes),\r\n };\r\n};\r\n\r\nconst resolveStoryValue = (value: StoryValue): string => {\r\n if (value == null) {\r\n return '';\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n return value.map((item) => resolveStoryValue(item)).join('');\r\n }\r\n\r\n if (typeof value === 'function') {\r\n return resolveStoryValue(value());\r\n }\r\n\r\n return String(value);\r\n};\r\n\r\nconst resolveBooleanStoryValue = (value: StoryValue): boolean => {\r\n if (value == null) {\r\n return false;\r\n }\r\n\r\n if (typeof value === 'function') {\r\n return resolveBooleanStoryValue(value());\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n return Boolean(resolveStoryValue(value));\r\n }\r\n\r\n if (typeof value === 'boolean') {\r\n return value;\r\n }\r\n\r\n return Boolean(value);\r\n};\r\n\r\n/**\r\n * Tagged template literal for Storybook render functions.\r\n *\r\n * Supports boolean attribute shorthand compatible with Storybook's string\r\n * renderer:\r\n *\r\n * ```ts\r\n * storyHtml`<bq-button ?disabled=${true}>Save</bq-button>`;\r\n * // => '<bq-button disabled=\"\">Save</bq-button>'\r\n * ```\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values\r\n * @returns HTML string compatible with `@storybook/web-components`\r\n */\r\nexport const storyHtml = (strings: TemplateStringsArray, ...values: StoryValue[]): string => {\r\n const rendered = strings.reduce((acc, part, index) => {\r\n if (index >= values.length) {\r\n return `${acc}${part}`;\r\n }\r\n\r\n const booleanAttributeMatch = findBooleanAttributeSuffix(part);\r\n\r\n if (booleanAttributeMatch) {\r\n const { attribute, basePart, spacing } = booleanAttributeMatch;\r\n const preservedSpacing = hasLineBreak(spacing) ? spacing : '';\r\n const isEnabled = resolveBooleanStoryValue(values[index]);\r\n\r\n return `${acc}${basePart}${isEnabled ? `${spacing}${attribute}` : preservedSpacing}`;\r\n }\r\n\r\n return `${acc}${part}${resolveStoryValue(values[index])}`;\r\n }, '');\r\n\r\n return sanitizeHtml(rendered, collectTemplateSanitizeOptions(strings));\r\n};\r\n\r\n/**\r\n * Conditionally render a value or template fragment.\r\n *\r\n * @param condition - Condition that controls rendering\r\n * @param truthyValue - Value or callback rendered when the condition is truthy\r\n * @param falsyValue - Optional value or callback rendered when the condition is falsy\r\n * @returns Rendered string fragment, or an empty string when the condition is\r\n * falsy and no fallback is provided\r\n */\r\nexport const when = (\r\n condition: unknown,\r\n truthyValue: StoryValue,\r\n falsyValue?: StoryValue\r\n): string => {\r\n return resolveStoryValue(condition ? truthyValue : falsyValue);\r\n};\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"storybook.es.mjs","names":[],"sources":["../src/storybook/index.ts"],"sourcesContent":["/**\n * Storybook template helpers for authoring bQuery component stories.\n *\n * `storyHtml` mirrors bQuery's string-based `html` tag while adding support for\n * Storybook-friendly boolean attribute shorthand (`?disabled=${true}`).\n *\n * @module bquery/storybook\n */\n\nimport { sanitizeHtml } from '../security/sanitize';\n\ntype StoryValue = string | number | boolean | null | undefined | StoryValue[] | (() => StoryValue);\n\n/**\n * Marks template interpolation boundaries while inferring sanitizer allowlists.\n * Uses the null character because authored HTML/template strings should not\n * contain it, making it a safe internal sentinel during parsing.\n */\nconst INTERPOLATION_BOUNDARY_MARKER = '\\u0000';\n\nconst isWhitespace = (value: string): boolean => {\n return value === ' ' || value === '\\t' || value === '\\n' || value === '\\r' || value === '\\f';\n};\n\n/**\n * Detects interpolation boundaries embedded into joined template string fragments.\n */\nconst isInterpolationBoundaryMarker = (value: string): boolean =>\n value === INTERPOLATION_BOUNDARY_MARKER;\n\nconst isAttributeSeparator = (value: string): boolean => {\n return isWhitespace(value) || isInterpolationBoundaryMarker(value);\n};\n\nconst isAsciiLetter = (value: string): boolean => {\n const code = value.charCodeAt(0);\n\n return (code >= 65 && code <= 90) || (code >= 97 && code <= 122);\n};\n\nconst isAttributeNameStart = (value: string): boolean => isAsciiLetter(value);\n\nconst isAttributeNameChar = (value: string): boolean => {\n const code = value.charCodeAt(0);\n\n return (\n isAsciiLetter(value) ||\n (code >= 48 && code <= 57) ||\n value === ':' ||\n value === '.' ||\n value === '_' ||\n value === '-'\n );\n};\n\nconst isQuoteChar = (value: string): boolean => value === '\"' || value === \"'\";\n\nconst isTagNameChar = (value: string): boolean => {\n const code = value.charCodeAt(0);\n\n return (\n isAsciiLetter(value) ||\n (code >= 48 && code <= 57) ||\n value === '.' ||\n value === '_' ||\n value === '-'\n );\n};\n\nconst hasLineBreak = (value: string): boolean => {\n for (let index = 0; index < value.length; index += 1) {\n if (value[index] === '\\n' || value[index] === '\\r') {\n return true;\n }\n }\n\n return false;\n};\n\nconst getTagNameEnd = (fragment: string): number => {\n let index = 0;\n\n while (\n index < fragment.length &&\n !isAttributeSeparator(fragment[index]) &&\n fragment[index] !== '/' &&\n fragment[index] !== '>'\n ) {\n index += 1;\n }\n\n return index;\n};\n\nconst isCustomElementTagName = (tagName: string): boolean => {\n if (!tagName.includes('-') || !isAsciiLetter(tagName[0])) {\n return false;\n }\n\n const last = tagName[tagName.length - 1];\n const code = last.charCodeAt(0);\n\n return isAsciiLetter(last) || (code >= 48 && code <= 57) || last === '.' || last === '_';\n};\n\nconst isAutoAllowedStoryAttribute = (attributeName: string): boolean => {\n return attributeName !== 'style' && !attributeName.startsWith('on');\n};\n\nconst findBooleanAttributeSuffix = (\n part: string\n): { attribute: string; basePart: string; spacing: string } | null => {\n let index = part.length - 1;\n\n while (index >= 0 && isWhitespace(part[index])) {\n index -= 1;\n }\n\n if (index < 0 || part[index] !== '=') {\n return null;\n }\n\n index -= 1;\n\n while (index >= 0 && isWhitespace(part[index])) {\n index -= 1;\n }\n\n const attributeEnd = index;\n\n while (\n index >= 0 &&\n !isWhitespace(part[index]) &&\n part[index] !== '?' &&\n part[index] !== '=' &&\n part[index] !== '/' &&\n part[index] !== '>'\n ) {\n index -= 1;\n }\n\n const attributeStart = index + 1;\n\n if (attributeStart > attributeEnd || part[index] !== '?') {\n return null;\n }\n\n const questionMarkIndex = index;\n let spacingStart = questionMarkIndex;\n\n while (spacingStart > 0 && isWhitespace(part[spacingStart - 1])) {\n spacingStart -= 1;\n }\n\n return {\n attribute: part.slice(attributeStart, attributeEnd + 1),\n basePart: part.slice(0, spacingStart),\n spacing: part.slice(spacingStart, questionMarkIndex),\n };\n};\n\nconst collectOpeningTagFragments = (template: string): string[] => {\n const fragments: string[] = [];\n let index = 0;\n\n while (index < template.length) {\n if (template[index] !== '<') {\n index += 1;\n continue;\n }\n\n const next = template[index + 1];\n\n if (!next || next === '/' || next === '!' || next === '?') {\n index += 1;\n continue;\n }\n\n let cursor = index + 1;\n\n if (!isAsciiLetter(template[cursor])) {\n index += 1;\n continue;\n }\n\n while (cursor < template.length && isTagNameChar(template[cursor])) {\n cursor += 1;\n }\n\n const tagStart = index + 1;\n const tagName = template.slice(tagStart, cursor);\n\n if (!tagName) {\n index += 1;\n continue;\n }\n\n let inQuote: '\"' | \"'\" | null = null;\n let tagEnd = cursor;\n\n while (tagEnd < template.length) {\n const char = template[tagEnd];\n\n if (inQuote) {\n if (char === inQuote) {\n inQuote = null;\n }\n\n tagEnd += 1;\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n inQuote = char;\n tagEnd += 1;\n continue;\n }\n\n if (char === '>') {\n fragments.push(template.slice(index + 1, tagEnd));\n tagEnd += 1;\n break;\n }\n\n tagEnd += 1;\n }\n\n index = tagEnd;\n }\n\n return fragments;\n};\n\n/**\n * Consumes a literal HTML attribute value starting at the given index.\n *\n * Returns the position immediately after a quoted or unquoted value. When the\n * current position reaches an interpolation boundary (optionally after\n * whitespace), the returned index advances past the boundary marker so\n * interpolated attributes do not swallow following authored attributes during\n * sanitizer allowlist inference.\n *\n * @param fragment - The opening-tag fragment currently being scanned\n * @param index - The position immediately after the `=` sign\n * @returns The index after the consumed literal value, or just past an\n * interpolation boundary when no literal value should be consumed from the\n * current template fragment.\n */\nconst skipAttributeValue = (fragment: string, index: number): number => {\n if (index >= fragment.length) {\n return index;\n }\n\n let cursor = index;\n\n if (isInterpolationBoundaryMarker(fragment[cursor])) {\n return cursor + 1;\n }\n\n while (cursor < fragment.length && isWhitespace(fragment[cursor])) {\n cursor += 1;\n }\n\n if (cursor >= fragment.length) {\n return cursor;\n }\n\n if (isInterpolationBoundaryMarker(fragment[cursor])) {\n return cursor + 1;\n }\n\n const quote = fragment[cursor];\n\n if (isQuoteChar(quote)) {\n cursor += 1;\n\n while (cursor < fragment.length) {\n if (fragment[cursor] === quote) {\n return cursor + 1;\n }\n\n cursor += 1;\n }\n\n return cursor;\n }\n\n while (\n cursor < fragment.length &&\n !isAttributeSeparator(fragment[cursor]) &&\n fragment[cursor] !== '/' &&\n fragment[cursor] !== '>'\n ) {\n cursor += 1;\n }\n\n if (cursor < fragment.length && isInterpolationBoundaryMarker(fragment[cursor])) {\n return cursor + 1;\n }\n\n return cursor;\n};\n\nconst collectAttributesFromTagFragment = (\n fragment: string,\n allowAttributes: Set<string>,\n autoAllowAttributes: boolean\n): void => {\n let index = 0;\n\n while (index < fragment.length && !isAttributeSeparator(fragment[index])) {\n index += 1;\n }\n\n while (index < fragment.length) {\n while (index < fragment.length && isAttributeSeparator(fragment[index])) {\n index += 1;\n }\n\n if (index >= fragment.length || fragment[index] === '/') {\n return;\n }\n\n // Skip standalone colons (e.g. namespace prefixes or framework-specific bindings)\n if (fragment[index] === ':') {\n index += 1;\n continue;\n }\n\n const hasBooleanPrefix = fragment[index] === '?';\n\n if (hasBooleanPrefix) {\n index += 1;\n }\n\n if (index >= fragment.length || !isAttributeNameStart(fragment[index])) {\n // Skip unrecognised character to avoid an infinite loop\n index += 1;\n continue;\n }\n\n const nameStart = index;\n\n index += 1;\n\n while (index < fragment.length && isAttributeNameChar(fragment[index])) {\n index += 1;\n }\n\n const attributeName = fragment.slice(nameStart, index).toLowerCase();\n\n while (index < fragment.length && isAttributeSeparator(fragment[index])) {\n index += 1;\n }\n\n if (index < fragment.length && fragment[index] === '=') {\n if (autoAllowAttributes && isAutoAllowedStoryAttribute(attributeName)) {\n allowAttributes.add(attributeName);\n }\n index = skipAttributeValue(fragment, index + 1);\n continue;\n }\n\n if (hasBooleanPrefix && autoAllowAttributes && isAutoAllowedStoryAttribute(attributeName)) {\n allowAttributes.add(attributeName);\n }\n }\n};\n\nconst collectTemplateSanitizeOptions = (strings: TemplateStringsArray) => {\n const template = strings.join(INTERPOLATION_BOUNDARY_MARKER);\n const allowTags = new Set<string>();\n const allowAttributes = new Set<string>();\n\n for (const fragment of collectOpeningTagFragments(template)) {\n const tagName = fragment.slice(0, getTagNameEnd(fragment)).toLowerCase();\n const isCustomElement = isCustomElementTagName(tagName);\n\n if (isCustomElement) {\n allowTags.add(tagName);\n }\n\n collectAttributesFromTagFragment(fragment, allowAttributes, isCustomElement);\n }\n\n return {\n allowTags: Array.from(allowTags),\n allowAttributes: Array.from(allowAttributes),\n };\n};\n\nconst resolveStoryValue = (value: StoryValue): string => {\n if (value == null) {\n return '';\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => resolveStoryValue(item)).join('');\n }\n\n if (typeof value === 'function') {\n return resolveStoryValue(value());\n }\n\n return String(value);\n};\n\nconst resolveBooleanStoryValue = (value: StoryValue): boolean => {\n if (value == null) {\n return false;\n }\n\n if (typeof value === 'function') {\n return resolveBooleanStoryValue(value());\n }\n\n if (Array.isArray(value)) {\n return Boolean(resolveStoryValue(value));\n }\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n return Boolean(value);\n};\n\n/**\n * Tagged template literal for Storybook render functions.\n *\n * Supports boolean attribute shorthand compatible with Storybook's string\n * renderer:\n *\n * ```ts\n * storyHtml`<bq-button ?disabled=${true}>Save</bq-button>`;\n * // => '<bq-button disabled=\"\">Save</bq-button>'\n * ```\n *\n * @param strings - Template literal string parts\n * @param values - Interpolated values\n * @returns HTML string compatible with `@storybook/web-components`\n */\nexport const storyHtml = (strings: TemplateStringsArray, ...values: StoryValue[]): string => {\n const rendered = strings.reduce((acc, part, index) => {\n if (index >= values.length) {\n return `${acc}${part}`;\n }\n\n const booleanAttributeMatch = findBooleanAttributeSuffix(part);\n\n if (booleanAttributeMatch) {\n const { attribute, basePart, spacing } = booleanAttributeMatch;\n const preservedSpacing = hasLineBreak(spacing) ? spacing : '';\n const isEnabled = resolveBooleanStoryValue(values[index]);\n\n return `${acc}${basePart}${isEnabled ? `${spacing}${attribute}` : preservedSpacing}`;\n }\n\n return `${acc}${part}${resolveStoryValue(values[index])}`;\n }, '');\n\n return sanitizeHtml(rendered, collectTemplateSanitizeOptions(strings));\n};\n\n/**\n * Conditionally render a value or template fragment.\n *\n * @param condition - Condition that controls rendering\n * @param truthyValue - Value or callback rendered when the condition is truthy\n * @param falsyValue - Optional value or callback rendered when the condition is falsy\n * @returns Rendered string fragment, or an empty string when the condition is\n * falsy and no fallback is provided\n */\nexport const when = (\n condition: unknown,\n truthyValue: StoryValue,\n falsyValue?: StoryValue\n): string => {\n return resolveStoryValue(condition ? truthyValue : falsyValue);\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { n as p } from "./core-DnlyjbF2.js";
2
- import { u as R } from "./reactive-Cfv0RK6x.js";
3
- import { t as q } from "./constraints-3lV9yyBw.js";
1
+ import { n as p } from "./core-DdtZHzsS.js";
2
+ import { D as R } from "./reactive-DwkhUJfP.js";
3
+ import { t as q } from "./constraints-D5RHQLmP.js";
4
4
  var b = (e) => e !== void 0 && (e >= "a" && e <= "z" || e >= "A" && e <= "Z" || e >= "0" && e <= "9" || e === "_"), $ = (e, o) => {
5
5
  let t = 1, i = "", r = o + 1;
6
6
  for (; r < e.length; ) {
@@ -182,7 +182,7 @@ function z(e = {}) {
182
182
  }
183
183
  };
184
184
  }
185
- function L(e, o, t = {}) {
185
+ function D(e, o, t = {}) {
186
186
  if (!e) throw new Error("bQuery testing: fireEvent requires a valid element");
187
187
  if (!o) throw new Error("bQuery testing: fireEvent requires an event name");
188
188
  const { bubbles: i = !0, cancelable: r = !0, composed: n = !0, detail: u } = t;
@@ -200,7 +200,7 @@ function L(e, o, t = {}) {
200
200
  const l = e.dispatchEvent(s);
201
201
  return P(), l;
202
202
  }
203
- async function T(e, o = {}) {
203
+ async function L(e, o = {}) {
204
204
  if (typeof e != "function") throw new Error("bQuery testing: waitFor requires a predicate function");
205
205
  const { timeout: t = 1e3, interval: i = 10 } = o, r = Date.now();
206
206
  for (; ; ) {
@@ -216,9 +216,9 @@ export {
216
216
  x as a,
217
217
  F as i,
218
218
  P as n,
219
- T as o,
219
+ L as o,
220
220
  z as r,
221
- L as t
221
+ D as t
222
222
  };
223
223
 
224
- //# sourceMappingURL=testing-CsqjNUyy.js.map
224
+ //# sourceMappingURL=testing-C5Sjfsna.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing-C5Sjfsna.js","names":[],"sources":["../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for bQuery.js.\n *\n * Provides helpers for mounting components, controlling signals, mocking\n * the router, dispatching events, and asserting async conditions — all\n * designed for use with `bun:test` and happy-dom.\n *\n * @module bquery/testing\n */\n\nimport { batch, Signal, signal } from '../reactive/index';\nimport { getNormalizedRouteConstraint } from '../router/constraints';\nimport type {\n FireEventOptions,\n MockRouteDefinition,\n MockRouter,\n MockRouterOptions,\n MockSignal,\n RenderComponentOptions,\n RenderResult,\n TestRoute,\n WaitForOptions,\n} from './types';\n\n// ============================================================================\n// renderComponent\n// ============================================================================\n\nconst isWordChar = (char: string | undefined): boolean =>\n char !== undefined &&\n ((char >= 'a' && char <= 'z') ||\n (char >= 'A' && char <= 'Z') ||\n (char >= '0' && char <= '9') ||\n char === '_');\n\nconst readRouteConstraint = (\n pattern: string,\n startIndex: number\n): { constraint: string; endIndex: number } | null => {\n let depth = 1;\n let constraint = '';\n let i = startIndex + 1;\n\n while (i < pattern.length) {\n const char = pattern[i];\n\n if (char === '\\\\' && i + 1 < pattern.length) {\n constraint += char + pattern[i + 1];\n i += 2;\n continue;\n }\n\n if (char === '(') {\n depth++;\n } else if (char === ')') {\n depth--;\n if (depth === 0) {\n return { constraint, endIndex: i + 1 };\n }\n }\n\n constraint += char;\n i++;\n }\n\n return null;\n};\n\nconst routeConstraintRegexCache = new Map<string, RegExp>();\n\nconst getRouteConstraintRegex = (constraint: string): RegExp => {\n const normalized = getNormalizedRouteConstraint(constraint);\n const cached = routeConstraintRegexCache.get(normalized);\n if (cached) {\n return cached;\n }\n\n const compiled = new RegExp(`^(?:${normalized})$`);\n routeConstraintRegexCache.set(normalized, compiled);\n return compiled;\n};\n\n/**\n * Mounts a custom element by tag name for testing and returns a handle\n * to interact with it.\n *\n * The element is created, configured with the given props and slots,\n * and appended to the container (defaults to `document.body`). Call\n * `unmount()` to remove the element and trigger its `disconnectedCallback`.\n *\n * @param tagName - The custom element tag name (must already be registered)\n * @param options - Props, slots, and container configuration\n * @returns A {@link RenderResult} with the element and an unmount function\n * @throws {Error} If the tag name is not a valid custom element name\n *\n * @example\n * ```ts\n * import { renderComponent } from '@bquery/bquery/testing';\n *\n * const { el, unmount } = renderComponent('my-counter', {\n * props: { start: '5' },\n * });\n * expect(el.shadowRoot?.textContent).toContain('5');\n * unmount();\n * ```\n */\nexport function renderComponent(\n tagName: string,\n options: RenderComponentOptions = {}\n): RenderResult {\n if (!tagName || !tagName.includes('-')) {\n throw new Error(\n `bQuery testing: \"${tagName}\" is not a valid custom element tag name (must contain a hyphen)`\n );\n }\n\n const { props, slots, container = document.body } = options;\n\n const el = document.createElement(tagName);\n\n // Set attributes (props) before connecting\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (value === null || value === undefined) continue;\n el.setAttribute(key, String(value));\n }\n }\n\n // Inject slot content before connecting so the component can discover it\n if (slots) {\n if (typeof slots === 'string') {\n el.innerHTML = slots;\n } else {\n const parts: string[] = [];\n for (const [slotName, html] of Object.entries(slots)) {\n if (slotName === 'default') {\n parts.push(html);\n } else {\n const safeSlotName = slotName\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n parts.push(`<div slot=\"${safeSlotName}\">${html}</div>`);\n }\n }\n el.innerHTML = parts.join('');\n }\n }\n\n // Connect — triggers connectedCallback\n container.appendChild(el);\n\n const unmount = (): void => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n };\n\n return { el, unmount };\n}\n\n// ============================================================================\n// flushEffects\n// ============================================================================\n\n/**\n * Synchronously flushes any pending reactive effects.\n *\n * In bQuery's reactive system, effects outside of a batch are executed\n * synchronously. This helper exists primarily for clarity and for\n * flushing effects that may have been deferred inside a batch.\n *\n * Internally it performs a no-op batch to trigger the flush of any\n * pending observers that were queued during a prior `batch()` call.\n *\n * @example\n * ```ts\n * import { signal, batch } from '@bquery/bquery/reactive';\n * import { flushEffects } from '@bquery/bquery/testing';\n *\n * const count = signal(0);\n * let observed = 0;\n * effect(() => { observed = count.value; });\n *\n * batch(() => { count.value = 42; });\n * flushEffects();\n * expect(observed).toBe(42);\n * ```\n */\nexport function flushEffects(): void {\n // A no-op batch triggers endBatch which flushes any pending observers.\n // Since bQuery's effects are synchronous outside of batches, this is\n // mainly useful after manual batch calls or micro-task boundaries.\n batch(() => {\n /* intentionally empty — triggers pending observer flush */\n });\n}\n\n// ============================================================================\n// mockSignal\n// ============================================================================\n\n/**\n * Creates a controllable signal for tests with `set()` and `reset()` helpers.\n *\n * This is a thin wrapper around `signal()` that records the initial value\n * and adds explicit `set()` / `reset()` methods for clearer test intent.\n *\n * @template T - The type of the signal value\n * @param initialValue - The initial value\n * @returns A {@link MockSignal} instance\n *\n * @example\n * ```ts\n * import { mockSignal } from '@bquery/bquery/testing';\n *\n * const count = mockSignal(0);\n * count.set(5);\n * expect(count.value).toBe(5);\n * count.reset();\n * expect(count.value).toBe(0);\n * ```\n */\nexport function mockSignal<T>(initialValue: T): MockSignal<T> {\n const s = signal(initialValue) as Signal<T> & {\n set: (value: T) => void;\n reset: () => void;\n initialValue: T;\n };\n\n Object.defineProperty(s, 'initialValue', {\n value: initialValue,\n writable: false,\n enumerable: true,\n });\n\n s.set = function (value: T): void {\n s.value = value;\n };\n\n s.reset = function (): void {\n s.value = initialValue;\n };\n\n return s as MockSignal<T>;\n}\n\n// ============================================================================\n// mockRouter\n// ============================================================================\n\n/**\n * Parses a path string into the route's `path`, `query`, and `hash` parts.\n * @internal\n */\nfunction parsePath(\n fullPath: string,\n base: string\n): { path: string; query: Record<string, string | string[]>; hash: string } {\n let working = fullPath;\n\n // Strip base prefix\n if (base && working.startsWith(base)) {\n working = working.slice(base.length) || '/';\n }\n\n // Extract hash\n let hash = '';\n const hashIdx = working.indexOf('#');\n if (hashIdx >= 0) {\n hash = working.slice(hashIdx + 1);\n working = working.slice(0, hashIdx);\n }\n\n // Extract query string\n const query: Record<string, string | string[]> = {};\n const qIdx = working.indexOf('?');\n if (qIdx >= 0) {\n const qs = working.slice(qIdx + 1);\n working = working.slice(0, qIdx);\n for (const pair of qs.split('&')) {\n const eqIdx = pair.indexOf('=');\n const key = eqIdx >= 0 ? decodeURIComponent(pair.slice(0, eqIdx)) : decodeURIComponent(pair);\n const val = eqIdx >= 0 ? decodeURIComponent(pair.slice(eqIdx + 1)) : '';\n const existing = query[key];\n if (existing !== undefined) {\n if (Array.isArray(existing)) {\n existing.push(val);\n } else {\n query[key] = [existing, val];\n }\n } else {\n query[key] = val;\n }\n }\n }\n\n return { path: working || '/', query, hash };\n}\n\n/**\n * Matches a path against a route definition, extracting params.\n * @internal\n */\nfunction matchRoute(\n path: string,\n routes: MockRouteDefinition[]\n): { matched: MockRouteDefinition | null; params: Record<string, string> } {\n for (const route of routes) {\n const params = matchRoutePattern(route.path, path);\n if (params) {\n return { matched: route, params };\n }\n }\n return { matched: null, params: {} };\n}\n\n/**\n * Builds param matches from a route path pattern without compiling the full path into a regex.\n * @internal\n */\nfunction matchRoutePattern(pattern: string, path: string): Record<string, string> | null {\n if (pattern === '*') {\n return {};\n }\n\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\n // within a single pattern/path match attempt.\n const memo = new Map<string, Record<string, string> | null>();\n\n const findSegmentBoundary = (value: string, startIndex: number): number => {\n const slashIndex = value.indexOf('/', startIndex);\n return slashIndex === -1 ? value.length : slashIndex;\n };\n\n const matchFrom = (patternIndex: number, pathIndex: number): Record<string, string> | null => {\n const memoKey = `${patternIndex}:${pathIndex}`;\n if (memo.has(memoKey)) {\n return memo.get(memoKey) ?? null;\n }\n\n if (patternIndex === pattern.length) {\n const result = pathIndex === path.length ? {} : null;\n memo.set(memoKey, result);\n return result;\n }\n\n const patternChar = pattern[patternIndex];\n\n if (patternChar === '*') {\n for (let candidateEnd = path.length; candidateEnd >= pathIndex; candidateEnd--) {\n const suffixMatch = matchFrom(patternIndex + 1, candidateEnd);\n if (suffixMatch) {\n memo.set(memoKey, suffixMatch);\n return suffixMatch;\n }\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n if (patternChar === ':' && isWordChar(pattern[patternIndex + 1])) {\n let nameEnd = patternIndex + 2;\n while (nameEnd < pattern.length && isWordChar(pattern[nameEnd])) {\n nameEnd++;\n }\n\n const name = pattern.slice(patternIndex + 1, nameEnd);\n let nextPatternIndex = nameEnd;\n let constraint: string | undefined;\n let catchAll = false;\n\n if (pattern[nameEnd] === '(') {\n const parsedConstraint = readRouteConstraint(pattern, nameEnd);\n if (parsedConstraint) {\n constraint = parsedConstraint.constraint;\n nextPatternIndex = parsedConstraint.endIndex;\n }\n }\n\n if (pattern[nextPatternIndex] === '*') {\n catchAll = true;\n nextPatternIndex++;\n }\n\n const candidateLimit = catchAll\n ? path.length\n : constraint\n ? path.length\n : findSegmentBoundary(path, pathIndex);\n\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\n const candidateValue = path.slice(pathIndex, candidateEnd);\n if (constraint) {\n const constraintRegex = getRouteConstraintRegex(constraint);\n if (!constraintRegex.test(candidateValue)) {\n continue;\n }\n }\n\n const suffixMatch = matchFrom(nextPatternIndex, candidateEnd);\n if (suffixMatch) {\n const result = {\n [name]: candidateValue,\n ...suffixMatch,\n };\n memo.set(memoKey, result);\n return result;\n }\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n if (pathIndex >= path.length || patternChar !== path[pathIndex]) {\n memo.set(memoKey, null);\n return null;\n }\n\n const result = matchFrom(patternIndex + 1, pathIndex + 1);\n memo.set(memoKey, result);\n return result;\n };\n\n return matchFrom(0, 0);\n}\n\n/**\n * Creates a lightweight mock router for testing that does not interact\n * with the browser History API.\n *\n * The mock router provides a reactive `currentRoute` signal that updates\n * when `push()` or `replace()` is called, making it ideal for testing\n * components or logic that depend on route state.\n *\n * @param options - Mock router configuration\n * @returns A {@link MockRouter} instance\n *\n * @example\n * ```ts\n * import { mockRouter } from '@bquery/bquery/testing';\n *\n * const router = mockRouter({\n * routes: [\n * { path: '/', component: () => null },\n * { path: '/user/:id', component: () => null },\n * ],\n * initialPath: '/',\n * });\n *\n * router.push('/user/42');\n * expect(router.currentRoute.value.params.id).toBe('42');\n * router.destroy();\n * ```\n */\nexport function mockRouter(options: MockRouterOptions = {}): MockRouter {\n const routes = options.routes ?? [{ path: '*', component: () => null }];\n const base = options.base ?? '';\n const initialPath = options.initialPath ?? '/';\n\n const resolveRoute = (fullPath: string): TestRoute => {\n const { path, query, hash } = parsePath(fullPath, base);\n const { matched, params } = matchRoute(path, routes);\n return { path, params, query, matched, hash };\n };\n\n const routeSignal = signal<TestRoute>(resolveRoute(initialPath));\n\n return {\n push(path: string): void {\n routeSignal.value = resolveRoute(path);\n },\n replace(path: string): void {\n routeSignal.value = resolveRoute(path);\n },\n get currentRoute(): Signal<TestRoute> {\n return routeSignal;\n },\n get routes(): MockRouteDefinition[] {\n return routes;\n },\n destroy(): void {\n routeSignal.dispose();\n },\n };\n}\n\n// ============================================================================\n// fireEvent\n// ============================================================================\n\n/**\n * Dispatches a synthetic event on an element and flushes pending effects.\n *\n * By default the event bubbles, is cancelable, and is composed (crosses\n * shadow DOM boundaries). Pass a `detail` option to create a `CustomEvent`.\n *\n * @param el - The target element\n * @param eventName - The event type (e.g. 'click', 'input', 'my-event')\n * @param options - Event configuration\n * @returns `true` if the event was not cancelled\n *\n * @example\n * ```ts\n * import { fireEvent } from '@bquery/bquery/testing';\n *\n * const button = document.createElement('button');\n * let clicked = false;\n * button.addEventListener('click', () => { clicked = true; });\n * fireEvent(button, 'click');\n * expect(clicked).toBe(true);\n * ```\n */\nexport function fireEvent(el: Element, eventName: string, options: FireEventOptions = {}): boolean {\n if (!el) {\n throw new Error('bQuery testing: fireEvent requires a valid element');\n }\n if (!eventName) {\n throw new Error('bQuery testing: fireEvent requires an event name');\n }\n\n const { bubbles = true, cancelable = true, composed = true, detail } = options;\n\n let event: Event;\n if (detail !== undefined) {\n event = new CustomEvent(eventName, { bubbles, cancelable, composed, detail });\n } else {\n event = new Event(eventName, { bubbles, cancelable, composed });\n }\n\n const result = el.dispatchEvent(event);\n\n // Flush any effects triggered by event handlers\n flushEffects();\n\n return result;\n}\n\n// ============================================================================\n// waitFor\n// ============================================================================\n\n/**\n * Waits for a predicate to return `true`, polling at a configurable interval.\n *\n * Useful for asserting conditions that depend on asynchronous operations,\n * timers, or deferred reactive updates.\n *\n * @param predicate - A function that returns `true` when the condition is met\n * @param options - Timeout and interval configuration\n * @returns A promise that resolves when the predicate returns `true`\n * @throws {Error} If the predicate does not return `true` within the timeout\n *\n * @example\n * ```ts\n * import { waitFor } from '@bquery/bquery/testing';\n *\n * await waitFor(() => document.querySelector('.loaded') !== null, {\n * timeout: 2000,\n * });\n * ```\n */\nexport async function waitFor(\n predicate: () => boolean | Promise<boolean>,\n options: WaitForOptions = {}\n): Promise<void> {\n if (typeof predicate !== 'function') {\n throw new Error('bQuery testing: waitFor requires a predicate function');\n }\n\n const { timeout = 1000, interval = 10 } = options;\n const start = Date.now();\n\n while (true) {\n try {\n const result = await predicate();\n if (result) return;\n } catch {\n // Predicate threw — treat as not-yet-met and keep polling\n }\n\n if (Date.now() - start >= timeout) {\n throw new Error(\n `bQuery testing: waitFor timed out after ${timeout}ms — predicate never returned true`\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a, i as r, n as e, o as s, r as t, t as n } from "./testing-CsqjNUyy.js";
1
+ import { a, i as r, n as e, o as s, r as t, t as n } from "./testing-C5Sjfsna.js";
2
2
  export {
3
3
  n as fireEvent,
4
4
  e as flushEffects,
@@ -41,4 +41,4 @@ export {
41
41
  i as u
42
42
  };
43
43
 
44
- //# sourceMappingURL=type-guards-Do9DWgNp.js.map
44
+ //# sourceMappingURL=type-guards-BMX2c0LP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"type-guards-Do9DWgNp.js","names":[],"sources":["../src/core/utils/type-guards.ts"],"sourcesContent":["/**\n * Type guard helpers.\n *\n * @module bquery/core/utils/type-guards\n */\n\n/**\n * Checks if a value is a DOM Element.\n *\n * @param value - The value to check\n * @returns True if the value is an Element\n */\nexport function isElement(value: unknown): value is Element {\n return typeof Element !== 'undefined' && value instanceof Element;\n}\n\n/**\n * Checks if a value is a BQueryCollection-like object.\n *\n * @param value - The value to check\n * @returns True if the value has an elements array property\n */\nexport function isCollection(value: unknown): value is { elements: Element[] } {\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\n}\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check\n * @returns True if the value is a function\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a value is a string.\n *\n * @param value - The value to check\n * @returns True if the value is a string\n */\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a number (excluding NaN).\n *\n * @param value - The value to check\n * @returns True if the value is a valid number\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check\n * @returns True if the value is a boolean\n */\nexport function isBoolean(value: unknown): value is boolean {\n return typeof value === 'boolean';\n}\n\n/**\n * Checks if a value is an array.\n *\n * @template T - The type of array elements\n * @param value - The value to check\n * @returns True if the value is an array\n */\nexport function isArray<T = unknown>(value: unknown): value is T[] {\n return Array.isArray(value);\n}\n\n/**\n * Checks if a value is a Date instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Date\n */\nexport function isDate(value: unknown): value is Date {\n return value instanceof Date;\n}\n\n/**\n * Checks if a value is a Promise-like object.\n *\n * @param value - The value to check\n * @returns True if the value is a Promise-like object\n */\nexport function isPromise<T = unknown>(value: unknown): value is Promise<T> {\n return Boolean(\n value &&\n (value instanceof Promise ||\n (typeof value === 'object' &&\n 'then' in (value as object) &&\n typeof (value as { then?: unknown }).then === 'function'))\n );\n}\n\n/**\n * Checks if a value is a non-null object.\n *\n * @param value - The value to check\n * @returns True if the value is an object\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"AAYA,SAAgB,EAAU,GAAkC;AAC1D,SAAO,OAAO,UAAY,OAAe,aAAiB;;AAS5D,SAAgB,EAAa,GAAkD;AAC7E,SAAO,GAAQ,KAAS,OAAO,KAAU,YAAY,cAAe;;AAStE,SAAgB,EAAW,GAA0D;AACnF,SAAO,OAAO,KAAU;;AAS1B,SAAgB,EAAS,GAAiC;AACxD,SAAO,OAAO,KAAU;;AAS1B,SAAgB,EAAS,GAAiC;AACxD,SAAO,OAAO,KAAU,YAAY,CAAC,OAAO,MAAM,CAAA;;AASpD,SAAgB,EAAU,GAAkC;AAC1D,SAAO,OAAO,KAAU;;AAU1B,SAAgB,EAAqB,GAA8B;AACjE,SAAO,MAAM,QAAQ,CAAA;;AASvB,SAAgB,EAAO,GAA+B;AACpD,SAAO,aAAiB;;AAS1B,SAAgB,EAAuB,GAAqC;AAC1E,SAAO,GACL,MACC,aAAiB,WACf,OAAO,KAAU,YAChB,UAAW,KACX,OAAQ,EAA6B,QAAS;;AAUtD,SAAgB,EAAS,GAAkD;AACzE,SAAO,OAAO,KAAU,YAAY,MAAU"}
1
+ {"version":3,"file":"type-guards-BMX2c0LP.js","names":[],"sources":["../src/core/utils/type-guards.ts"],"sourcesContent":["/**\n * Type guard helpers.\n *\n * @module bquery/core/utils/type-guards\n */\n\n/**\n * Checks if a value is a DOM Element.\n *\n * @param value - The value to check\n * @returns True if the value is an Element\n */\nexport function isElement(value: unknown): value is Element {\n return typeof Element !== 'undefined' && value instanceof Element;\n}\n\n/**\n * Checks if a value is a BQueryCollection-like object.\n *\n * @param value - The value to check\n * @returns True if the value has an elements array property\n */\nexport function isCollection(value: unknown): value is { elements: Element[] } {\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\n}\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check\n * @returns True if the value is a function\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a value is a string.\n *\n * @param value - The value to check\n * @returns True if the value is a string\n */\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a number (excluding NaN).\n *\n * @param value - The value to check\n * @returns True if the value is a valid number\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check\n * @returns True if the value is a boolean\n */\nexport function isBoolean(value: unknown): value is boolean {\n return typeof value === 'boolean';\n}\n\n/**\n * Checks if a value is an array.\n *\n * @template T - The type of array elements\n * @param value - The value to check\n * @returns True if the value is an array\n */\nexport function isArray<T = unknown>(value: unknown): value is T[] {\n return Array.isArray(value);\n}\n\n/**\n * Checks if a value is a Date instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Date\n */\nexport function isDate(value: unknown): value is Date {\n return value instanceof Date;\n}\n\n/**\n * Checks if a value is a Promise-like object.\n *\n * @param value - The value to check\n * @returns True if the value is a Promise-like object\n */\nexport function isPromise<T = unknown>(value: unknown): value is Promise<T> {\n return Boolean(\n value &&\n (value instanceof Promise ||\n (typeof value === 'object' &&\n 'then' in (value as object) &&\n typeof (value as { then?: unknown }).then === 'function'))\n );\n}\n\n/**\n * Checks if a value is a non-null object.\n *\n * @param value - The value to check\n * @returns True if the value is an object\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"AAYA,SAAgB,EAAU,GAAkC;AAC1D,SAAO,OAAO,UAAY,OAAe,aAAiB;;AAS5D,SAAgB,EAAa,GAAkD;AAC7E,SAAO,GAAQ,KAAS,OAAO,KAAU,YAAY,cAAe;;AAStE,SAAgB,EAAW,GAA0D;AACnF,SAAO,OAAO,KAAU;;AAS1B,SAAgB,EAAS,GAAiC;AACxD,SAAO,OAAO,KAAU;;AAS1B,SAAgB,EAAS,GAAiC;AACxD,SAAO,OAAO,KAAU,YAAY,CAAC,OAAO,MAAM,CAAA;;AASpD,SAAgB,EAAU,GAAkC;AAC1D,SAAO,OAAO,KAAU;;AAU1B,SAAgB,EAAqB,GAA8B;AACjE,SAAO,MAAM,QAAQ,CAAA;;AASvB,SAAgB,EAAO,GAA+B;AACpD,SAAO,aAAiB;;AAS1B,SAAgB,EAAuB,GAAqC;AAC1E,SAAO,GACL,MACC,aAAiB,WACf,OAAO,KAAU,YAChB,UAAW,KACX,OAAQ,EAA6B,QAAS;;AAUtD,SAAgB,EAAS,GAAkD;AACzE,SAAO,OAAO,KAAU,YAAY,MAAU"}
@@ -0,0 +1,36 @@
1
+ import { a as h, f as c, g as r, h as a, m as u, p as d, s as o, u as i } from "./core-DdtZHzsS.js";
2
+ var l = class {
3
+ constructor(s) {
4
+ this.compute = s, this.hasCachedValue = !1, this.dirty = !0, this.disposed = !1, this.subscribers = /* @__PURE__ */ new Set(), this.markDirty = () => {
5
+ if (this.disposed) return;
6
+ this.dirty = !0;
7
+ const e = Array.from(this.subscribers);
8
+ for (const t of e) u(t);
9
+ };
10
+ }
11
+ get value() {
12
+ if (this.disposed)
13
+ return this.hasCachedValue || (this.cachedValue = r(() => this.compute()), this.hasCachedValue = !0), this.cachedValue;
14
+ const s = c();
15
+ return s && (this.subscribers.add(s), d(s, this)), this.dirty && (this.dirty = !1, i(this.markDirty), this.cachedValue = a(this.markDirty, this.compute), this.hasCachedValue = !0), this.cachedValue;
16
+ }
17
+ peek() {
18
+ return this.disposed ? (this.hasCachedValue || (this.cachedValue = r(() => this.compute()), this.hasCachedValue = !0), this.cachedValue) : (this.dirty && (this.dirty = !1, i(this.markDirty), this.cachedValue = a(this.markDirty, this.compute), this.hasCachedValue = !0), this.cachedValue);
19
+ }
20
+ unsubscribe(s) {
21
+ this.subscribers.delete(s);
22
+ }
23
+ dispose() {
24
+ this.disposed = !0, this.dirty && (this.hasCachedValue = !1), this.dirty = !1, i(this.markDirty), this.subscribers.clear();
25
+ }
26
+ }, n = (s) => {
27
+ const e = new l(s), t = h();
28
+ return o(t) && t._addDisposer(() => e.dispose()), e;
29
+ }, f = (s) => r(s);
30
+ export {
31
+ l as n,
32
+ n as r,
33
+ f as t
34
+ };
35
+
36
+ //# sourceMappingURL=untrack-D0fnO5k2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrack-D0fnO5k2.js","names":[],"sources":["../src/reactive/computed.ts","../src/reactive/untrack.ts"],"sourcesContent":["/**\n * Computed reactive values.\n */\n\nimport {\n clearDependencies,\n getCurrentObserver,\n registerDependency,\n scheduleObserver,\n track,\n withoutCurrentObserver,\n type ReactiveSource,\n} from './internals';\nimport { getActiveScope, hasScopeDisposer } from './scope';\n\n/**\n * A computed value that derives from other reactive sources.\n *\n * Computed values are lazily evaluated and cached. They only\n * recompute when their dependencies change.\n *\n * @template T - The type of the computed value\n */\nexport class Computed<T> implements ReactiveSource {\n private cachedValue!: T;\n private hasCachedValue = false;\n private dirty = true;\n private disposed = false;\n private subscribers = new Set<() => void>();\n private readonly markDirty = () => {\n if (this.disposed) {\n return;\n }\n this.dirty = true;\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\n const subscribersSnapshot = Array.from(this.subscribers);\n for (const subscriber of subscribersSnapshot) {\n scheduleObserver(subscriber);\n }\n };\n\n /**\n * Creates a new computed value.\n * @param compute - Function that computes the value\n */\n constructor(private readonly compute: () => T) {}\n\n /**\n * Gets the computed value, recomputing if dependencies changed.\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\n */\n get value(): T {\n if (this.disposed) {\n if (!this.hasCachedValue) {\n this.cachedValue = withoutCurrentObserver(() => this.compute());\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n const current = getCurrentObserver();\n if (current) {\n this.subscribers.add(current);\n registerDependency(current, this);\n }\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n /**\n * Reads the current computed value without tracking.\n * Useful when you need the value but don't want to create a dependency.\n *\n * @returns The current cached value (recomputes if dirty)\n */\n peek(): T {\n if (this.disposed) {\n if (!this.hasCachedValue) {\n this.cachedValue = withoutCurrentObserver(() => this.compute());\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n /**\n * Removes an observer from this computed's subscriber set.\n * @internal\n */\n unsubscribe(observer: () => void): void {\n this.subscribers.delete(observer);\n }\n\n /**\n * Disposes the computed value by unsubscribing its internal observer\n * from all upstream dependencies and clearing subscribers.\n */\n dispose(): void {\n this.disposed = true;\n if (this.dirty) {\n this.hasCachedValue = false;\n }\n this.dirty = false;\n clearDependencies(this.markDirty);\n this.subscribers.clear();\n }\n}\n\n/**\n * Creates a new computed value.\n *\n * If created inside an {@link effectScope}, the computed value is automatically\n * collected and will be disposed when the scope stops.\n *\n * @template T - The type of the computed value\n * @param fn - Function that computes the value from reactive sources\n * @returns A new Computed instance\n */\nexport const computed = <T>(fn: () => T): Computed<T> => {\n const c = new Computed(fn);\n\n // Auto-register with the current scope so scope.stop() disposes this computed\n const scope = getActiveScope();\n if (hasScopeDisposer(scope)) {\n scope._addDisposer(() => c.dispose());\n }\n\n return c;\n};\n","/**\n * Dependency tracking control helpers.\n */\n\nimport { withoutCurrentObserver } from './internals';\n\n/**\n * Executes a function without tracking any signal dependencies.\n * Useful when reading a signal value without creating a reactive dependency.\n *\n * This implementation temporarily hides the current observer rather than\n * disabling tracking globally. This ensures that nested reactive internals\n * (e.g., computed recomputation triggered during untrack) can still properly\n * track their own dependencies.\n *\n * @template T - The return type of the function\n * @param fn - The function to execute without tracking\n * @returns The result of the function\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => {\n * // This read creates a dependency\n * console.log(count.value);\n * // This read does not create a dependency\n * const snapshot = untrack(() => count.value);\n * });\n * ```\n */\nexport const untrack = <T>(fn: () => T): T => withoutCurrentObserver(fn);\n"],"mappings":";AAuBA,IAAa,IAAb,MAAmD;AAAA,EAsBjD,YAAY,GAAmC;AAAlB,SAAA,UAAA,yBApBJ,iBACT,oBACG,uBACG,oBAAI,IAAA,0BACS;AACjC,UAAI,KAAK,SACP;AAEF,WAAK,QAAQ;AAEb,YAAM,IAAsB,MAAM,KAAK,KAAK,WAAA;AAC5C,iBAAW,KAAc,EACvB,CAAA,EAAiB,CAAA;AAAA;;EAcrB,IAAI,QAAW;AACb,QAAI,KAAK;AACP,aAAK,KAAK,mBACR,KAAK,cAAc,EAAA,MAA6B,KAAK,QAAA,CAAS,GAC9D,KAAK,iBAAiB,KAEjB,KAAK;AAGd,UAAM,IAAU,EAAA;AAChB,WAAI,MACF,KAAK,YAAY,IAAI,CAAA,GACrB,EAAmB,GAAS,IAAA,IAE1B,KAAK,UACP,KAAK,QAAQ,IAEb,EAAkB,KAAK,SAAA,GACvB,KAAK,cAAc,EAAM,KAAK,WAAW,KAAK,OAAA,GAC9C,KAAK,iBAAiB,KAEjB,KAAK;AAAA;EASd,OAAU;AACR,WAAI,KAAK,YACF,KAAK,mBACR,KAAK,cAAc,EAAA,MAA6B,KAAK,QAAA,CAAS,GAC9D,KAAK,iBAAiB,KAEjB,KAAK,gBAGV,KAAK,UACP,KAAK,QAAQ,IAEb,EAAkB,KAAK,SAAA,GACvB,KAAK,cAAc,EAAM,KAAK,WAAW,KAAK,OAAA,GAC9C,KAAK,iBAAiB,KAEjB,KAAK;AAAA;EAOd,YAAY,GAA4B;AACtC,SAAK,YAAY,OAAO,CAAA;AAAA;EAO1B,UAAgB;AACd,SAAK,WAAW,IACZ,KAAK,UACP,KAAK,iBAAiB,KAExB,KAAK,QAAQ,IACb,EAAkB,KAAK,SAAA,GACvB,KAAK,YAAY,MAAA;AAAA;GAcR,IAAA,CAAe,MAA6B;AACvD,QAAM,IAAI,IAAI,EAAS,CAAA,GAGjB,IAAQ,EAAA;AACd,SAAI,EAAiB,CAAA,KACnB,EAAM,aAAA,MAAmB,EAAE,QAAA,CAAS,GAG/B;GChHI,IAAA,CAAc,MAAmB,EAAuB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"custom-directives.d.ts","sourceRoot":"","sources":["../../src/view/custom-directives.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAIrF;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,GAC1C,UAAU,uBAAuB,GAAG,IAAI,KACvC,IAEF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,gBAAgB,GAAG,SAEpE,CAAC"}
1
+ {"version":3,"file":"custom-directives.d.ts","sourceRoot":"","sources":["../../src/view/custom-directives.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAIrF;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,GAAI,UAAU,uBAAuB,GAAG,IAAI,KAAG,IAE1F,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,gBAAgB,GAAG,SAEpE,CAAC"}