@bquery/bquery 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +193 -23
  2. package/dist/a11y/announce.d.ts +43 -0
  3. package/dist/a11y/announce.d.ts.map +1 -0
  4. package/dist/a11y/audit.d.ts +42 -0
  5. package/dist/a11y/audit.d.ts.map +1 -0
  6. package/dist/a11y/index.d.ts +53 -0
  7. package/dist/a11y/index.d.ts.map +1 -0
  8. package/dist/a11y/media-preferences.d.ts +77 -0
  9. package/dist/a11y/media-preferences.d.ts.map +1 -0
  10. package/dist/a11y/roving-tab-index.d.ts +38 -0
  11. package/dist/a11y/roving-tab-index.d.ts.map +1 -0
  12. package/dist/a11y/skip-link.d.ts +37 -0
  13. package/dist/a11y/skip-link.d.ts.map +1 -0
  14. package/dist/a11y/trap-focus.d.ts +49 -0
  15. package/dist/a11y/trap-focus.d.ts.map +1 -0
  16. package/dist/a11y/types.d.ts +152 -0
  17. package/dist/a11y/types.d.ts.map +1 -0
  18. package/dist/a11y-C5QOVvRn.js +421 -0
  19. package/dist/a11y-C5QOVvRn.js.map +1 -0
  20. package/dist/a11y.es.mjs +14 -0
  21. package/dist/component/component.d.ts +13 -5
  22. package/dist/component/component.d.ts.map +1 -1
  23. package/dist/component/html.d.ts +40 -3
  24. package/dist/component/html.d.ts.map +1 -1
  25. package/dist/component/index.d.ts +3 -2
  26. package/dist/component/index.d.ts.map +1 -1
  27. package/dist/component/library.d.ts.map +1 -1
  28. package/dist/component/scope.d.ts +138 -0
  29. package/dist/component/scope.d.ts.map +1 -0
  30. package/dist/component/types.d.ts +184 -17
  31. package/dist/component/types.d.ts.map +1 -1
  32. package/dist/component-CuuTijA6.js +684 -0
  33. package/dist/component-CuuTijA6.js.map +1 -0
  34. package/dist/component.es.mjs +10 -6
  35. package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
  36. package/dist/config-BW35FKuA.js.map +1 -0
  37. package/dist/constraints-3lV9yyBw.js +100 -0
  38. package/dist/constraints-3lV9yyBw.js.map +1 -0
  39. package/dist/core/collection.d.ts +48 -0
  40. package/dist/core/collection.d.ts.map +1 -1
  41. package/dist/core/element.d.ts +92 -0
  42. package/dist/core/element.d.ts.map +1 -1
  43. package/dist/core/env.d.ts +18 -0
  44. package/dist/core/env.d.ts.map +1 -0
  45. package/dist/core/index.d.ts +1 -0
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/shared.d.ts +8 -0
  48. package/dist/core/shared.d.ts.map +1 -1
  49. package/dist/core/utils/index.d.ts +52 -41
  50. package/dist/core/utils/index.d.ts.map +1 -1
  51. package/dist/core-Cjl7GUu8.js +717 -0
  52. package/dist/core-Cjl7GUu8.js.map +1 -0
  53. package/dist/{core-DPdbItcq.js → core-DnlyjbF2.js} +1 -1
  54. package/dist/{core-DPdbItcq.js.map → core-DnlyjbF2.js.map} +1 -1
  55. package/dist/core.es.mjs +45 -44
  56. package/dist/custom-directives-7wAShnnd.js +9 -0
  57. package/dist/custom-directives-7wAShnnd.js.map +1 -0
  58. package/dist/devtools/devtools.d.ts +212 -0
  59. package/dist/devtools/devtools.d.ts.map +1 -0
  60. package/dist/devtools/index.d.ts +20 -0
  61. package/dist/devtools/index.d.ts.map +1 -0
  62. package/dist/devtools/types.d.ts +69 -0
  63. package/dist/devtools/types.d.ts.map +1 -0
  64. package/dist/devtools-D2fQLhDN.js +122 -0
  65. package/dist/devtools-D2fQLhDN.js.map +1 -0
  66. package/dist/devtools.es.mjs +19 -0
  67. package/dist/dnd/draggable.d.ts +51 -0
  68. package/dist/dnd/draggable.d.ts.map +1 -0
  69. package/dist/dnd/droppable.d.ts +38 -0
  70. package/dist/dnd/droppable.d.ts.map +1 -0
  71. package/dist/dnd/index.d.ts +47 -0
  72. package/dist/dnd/index.d.ts.map +1 -0
  73. package/dist/dnd/sortable.d.ts +43 -0
  74. package/dist/dnd/sortable.d.ts.map +1 -0
  75. package/dist/dnd/types.d.ts +250 -0
  76. package/dist/dnd/types.d.ts.map +1 -0
  77. package/dist/dnd-B8EgyzaI.js +244 -0
  78. package/dist/dnd-B8EgyzaI.js.map +1 -0
  79. package/dist/dnd.es.mjs +6 -0
  80. package/dist/env-NeVmr4Gf.js +19 -0
  81. package/dist/env-NeVmr4Gf.js.map +1 -0
  82. package/dist/forms/create-form.d.ts +49 -0
  83. package/dist/forms/create-form.d.ts.map +1 -0
  84. package/dist/forms/index.d.ts +39 -0
  85. package/dist/forms/index.d.ts.map +1 -0
  86. package/dist/forms/types.d.ts +139 -0
  87. package/dist/forms/types.d.ts.map +1 -0
  88. package/dist/forms/validators.d.ts +179 -0
  89. package/dist/forms/validators.d.ts.map +1 -0
  90. package/dist/forms-C3yovgH9.js +141 -0
  91. package/dist/forms-C3yovgH9.js.map +1 -0
  92. package/dist/forms.es.mjs +14 -0
  93. package/dist/full.d.ts +37 -9
  94. package/dist/full.d.ts.map +1 -1
  95. package/dist/full.es.mjs +186 -91
  96. package/dist/full.iife.js +47 -31
  97. package/dist/full.iife.js.map +1 -1
  98. package/dist/full.umd.js +47 -31
  99. package/dist/full.umd.js.map +1 -1
  100. package/dist/i18n/formatting.d.ts +40 -0
  101. package/dist/i18n/formatting.d.ts.map +1 -0
  102. package/dist/i18n/i18n.d.ts +48 -0
  103. package/dist/i18n/i18n.d.ts.map +1 -0
  104. package/dist/i18n/index.d.ts +57 -0
  105. package/dist/i18n/index.d.ts.map +1 -0
  106. package/dist/i18n/translate.d.ts +83 -0
  107. package/dist/i18n/translate.d.ts.map +1 -0
  108. package/dist/i18n/types.d.ts +156 -0
  109. package/dist/i18n/types.d.ts.map +1 -0
  110. package/dist/i18n-BnnhTFOS.js +89 -0
  111. package/dist/i18n-BnnhTFOS.js.map +1 -0
  112. package/dist/i18n.es.mjs +6 -0
  113. package/dist/index.d.ts +11 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.es.mjs +233 -138
  116. package/dist/media/battery.d.ts +35 -0
  117. package/dist/media/battery.d.ts.map +1 -0
  118. package/dist/media/breakpoints.d.ts +51 -0
  119. package/dist/media/breakpoints.d.ts.map +1 -0
  120. package/dist/media/clipboard.d.ts +30 -0
  121. package/dist/media/clipboard.d.ts.map +1 -0
  122. package/dist/media/device-sensors.d.ts +54 -0
  123. package/dist/media/device-sensors.d.ts.map +1 -0
  124. package/dist/media/geolocation.d.ts +38 -0
  125. package/dist/media/geolocation.d.ts.map +1 -0
  126. package/dist/media/index.d.ts +42 -0
  127. package/dist/media/index.d.ts.map +1 -0
  128. package/dist/media/media-query.d.ts +36 -0
  129. package/dist/media/media-query.d.ts.map +1 -0
  130. package/dist/media/network.d.ts +35 -0
  131. package/dist/media/network.d.ts.map +1 -0
  132. package/dist/media/types.d.ts +173 -0
  133. package/dist/media/types.d.ts.map +1 -0
  134. package/dist/media/viewport.d.ts +32 -0
  135. package/dist/media/viewport.d.ts.map +1 -0
  136. package/dist/media-Di2Ta22s.js +340 -0
  137. package/dist/media-Di2Ta22s.js.map +1 -0
  138. package/dist/media.es.mjs +12 -0
  139. package/dist/motion/index.d.ts +7 -3
  140. package/dist/motion/index.d.ts.map +1 -1
  141. package/dist/motion/morph.d.ts +27 -0
  142. package/dist/motion/morph.d.ts.map +1 -0
  143. package/dist/motion/parallax.d.ts +30 -0
  144. package/dist/motion/parallax.d.ts.map +1 -0
  145. package/dist/motion/reduced-motion.d.ts +36 -3
  146. package/dist/motion/reduced-motion.d.ts.map +1 -1
  147. package/dist/motion/types.d.ts +58 -0
  148. package/dist/motion/types.d.ts.map +1 -1
  149. package/dist/motion/typewriter.d.ts +31 -0
  150. package/dist/motion/typewriter.d.ts.map +1 -0
  151. package/dist/motion-qPj_TYGv.js +530 -0
  152. package/dist/motion-qPj_TYGv.js.map +1 -0
  153. package/dist/motion.es.mjs +27 -23
  154. package/dist/mount-SM07RUa6.js +403 -0
  155. package/dist/mount-SM07RUa6.js.map +1 -0
  156. package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
  157. package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
  158. package/dist/{platform-B7JhGBc7.js → platform-CPbCprb6.js} +3 -3
  159. package/dist/platform-CPbCprb6.js.map +1 -0
  160. package/dist/platform.es.mjs +2 -2
  161. package/dist/plugin/index.d.ts +22 -0
  162. package/dist/plugin/index.d.ts.map +1 -0
  163. package/dist/plugin/registry.d.ts +108 -0
  164. package/dist/plugin/registry.d.ts.map +1 -0
  165. package/dist/plugin/types.d.ts +110 -0
  166. package/dist/plugin/types.d.ts.map +1 -0
  167. package/dist/plugin-cPoOHFLY.js +64 -0
  168. package/dist/plugin-cPoOHFLY.js.map +1 -0
  169. package/dist/plugin.es.mjs +9 -0
  170. package/dist/reactive/computed.d.ts +7 -0
  171. package/dist/reactive/computed.d.ts.map +1 -1
  172. package/dist/reactive-Cfv0RK6x.js +233 -0
  173. package/dist/reactive-Cfv0RK6x.js.map +1 -0
  174. package/dist/reactive.es.mjs +18 -17
  175. package/dist/registry-CWf368tT.js +26 -0
  176. package/dist/registry-CWf368tT.js.map +1 -0
  177. package/dist/router/bq-link.d.ts +112 -0
  178. package/dist/router/bq-link.d.ts.map +1 -0
  179. package/dist/router/constraints.d.ts +9 -0
  180. package/dist/router/constraints.d.ts.map +1 -0
  181. package/dist/router/index.d.ts +14 -6
  182. package/dist/router/index.d.ts.map +1 -1
  183. package/dist/router/match.d.ts +0 -1
  184. package/dist/router/match.d.ts.map +1 -1
  185. package/dist/router/path-pattern.d.ts +14 -0
  186. package/dist/router/path-pattern.d.ts.map +1 -0
  187. package/dist/router/query.d.ts.map +1 -1
  188. package/dist/router/router.d.ts +3 -1
  189. package/dist/router/router.d.ts.map +1 -1
  190. package/dist/router/types.d.ts +48 -4
  191. package/dist/router/types.d.ts.map +1 -1
  192. package/dist/router/use-route.d.ts +50 -0
  193. package/dist/router/use-route.d.ts.map +1 -0
  194. package/dist/router/utils.d.ts +3 -0
  195. package/dist/router/utils.d.ts.map +1 -1
  196. package/dist/router-BrthaP_z.js +473 -0
  197. package/dist/router-BrthaP_z.js.map +1 -0
  198. package/dist/router.es.mjs +13 -10
  199. package/dist/{sanitize-jyJ2ryE2.js → sanitize-B1V4JswB.js} +95 -83
  200. package/dist/sanitize-B1V4JswB.js.map +1 -0
  201. package/dist/security/index.d.ts +2 -0
  202. package/dist/security/index.d.ts.map +1 -1
  203. package/dist/security/sanitize.d.ts +4 -1
  204. package/dist/security/sanitize.d.ts.map +1 -1
  205. package/dist/security/trusted-html.d.ts +53 -0
  206. package/dist/security/trusted-html.d.ts.map +1 -0
  207. package/dist/security.es.mjs +10 -9
  208. package/dist/ssr/hydrate.d.ts +65 -0
  209. package/dist/ssr/hydrate.d.ts.map +1 -0
  210. package/dist/ssr/index.d.ts +59 -0
  211. package/dist/ssr/index.d.ts.map +1 -0
  212. package/dist/ssr/render.d.ts +62 -0
  213. package/dist/ssr/render.d.ts.map +1 -0
  214. package/dist/ssr/serialize.d.ts +118 -0
  215. package/dist/ssr/serialize.d.ts.map +1 -0
  216. package/dist/ssr/types.d.ts +70 -0
  217. package/dist/ssr/types.d.ts.map +1 -0
  218. package/dist/ssr-B2qd_WBB.js +248 -0
  219. package/dist/ssr-B2qd_WBB.js.map +1 -0
  220. package/dist/ssr.es.mjs +9 -0
  221. package/dist/store/create-store.d.ts.map +1 -1
  222. package/dist/store/define-store.d.ts +1 -1
  223. package/dist/store/define-store.d.ts.map +1 -1
  224. package/dist/store/index.d.ts +1 -1
  225. package/dist/store/index.d.ts.map +1 -1
  226. package/dist/store/mapping.d.ts +1 -1
  227. package/dist/store/mapping.d.ts.map +1 -1
  228. package/dist/store/persisted.d.ts +38 -4
  229. package/dist/store/persisted.d.ts.map +1 -1
  230. package/dist/store/types.d.ts +140 -3
  231. package/dist/store/types.d.ts.map +1 -1
  232. package/dist/store/utils.d.ts +2 -2
  233. package/dist/store/utils.d.ts.map +1 -1
  234. package/dist/store/watch.d.ts +1 -1
  235. package/dist/store/watch.d.ts.map +1 -1
  236. package/dist/store-DWpyH6p5.js +338 -0
  237. package/dist/store-DWpyH6p5.js.map +1 -0
  238. package/dist/store.es.mjs +11 -10
  239. package/dist/storybook/index.d.ts +37 -0
  240. package/dist/storybook/index.d.ts.map +1 -0
  241. package/dist/storybook.es.mjs +151 -0
  242. package/dist/storybook.es.mjs.map +1 -0
  243. package/dist/testing/index.d.ts +23 -0
  244. package/dist/testing/index.d.ts.map +1 -0
  245. package/dist/testing/testing.d.ts +156 -0
  246. package/dist/testing/testing.d.ts.map +1 -0
  247. package/dist/testing/types.d.ts +134 -0
  248. package/dist/testing/types.d.ts.map +1 -0
  249. package/dist/testing-CsqjNUyy.js +224 -0
  250. package/dist/testing-CsqjNUyy.js.map +1 -0
  251. package/dist/testing.es.mjs +9 -0
  252. package/dist/type-guards-Do9DWgNp.js +44 -0
  253. package/dist/type-guards-Do9DWgNp.js.map +1 -0
  254. package/dist/untrack-DJVQQ2WM.js +33 -0
  255. package/dist/untrack-DJVQQ2WM.js.map +1 -0
  256. package/dist/view/custom-directives.d.ts +20 -0
  257. package/dist/view/custom-directives.d.ts.map +1 -0
  258. package/dist/view/evaluate.d.ts.map +1 -1
  259. package/dist/view/process.d.ts.map +1 -1
  260. package/dist/view.es.mjs +11 -10
  261. package/package.json +52 -11
  262. package/src/a11y/announce.ts +131 -0
  263. package/src/a11y/audit.ts +314 -0
  264. package/src/a11y/index.ts +68 -0
  265. package/src/a11y/media-preferences.ts +255 -0
  266. package/src/a11y/roving-tab-index.ts +164 -0
  267. package/src/a11y/skip-link.ts +255 -0
  268. package/src/a11y/trap-focus.ts +184 -0
  269. package/src/a11y/types.ts +183 -0
  270. package/src/component/component.ts +345 -65
  271. package/src/component/html.ts +153 -53
  272. package/src/component/index.ts +12 -2
  273. package/src/component/library.ts +66 -28
  274. package/src/component/scope.ts +212 -0
  275. package/src/component/types.ts +238 -19
  276. package/src/core/collection.ts +707 -628
  277. package/src/core/element.ts +981 -774
  278. package/src/core/env.ts +60 -0
  279. package/src/core/index.ts +49 -48
  280. package/src/core/shared.ts +62 -13
  281. package/src/core/utils/index.ts +148 -83
  282. package/src/devtools/devtools.ts +410 -0
  283. package/src/devtools/index.ts +48 -0
  284. package/src/devtools/types.ts +104 -0
  285. package/src/dnd/draggable.ts +296 -0
  286. package/src/dnd/droppable.ts +228 -0
  287. package/src/dnd/index.ts +62 -0
  288. package/src/dnd/sortable.ts +307 -0
  289. package/src/dnd/types.ts +293 -0
  290. package/src/forms/create-form.ts +278 -0
  291. package/src/forms/index.ts +65 -0
  292. package/src/forms/types.ts +154 -0
  293. package/src/forms/validators.ts +265 -0
  294. package/src/full.ts +260 -3
  295. package/src/i18n/formatting.ts +67 -0
  296. package/src/i18n/i18n.ts +200 -0
  297. package/src/i18n/index.ts +67 -0
  298. package/src/i18n/translate.ts +182 -0
  299. package/src/i18n/types.ts +171 -0
  300. package/src/index.ts +108 -36
  301. package/src/media/battery.ts +116 -0
  302. package/src/media/breakpoints.ts +131 -0
  303. package/src/media/clipboard.ts +80 -0
  304. package/src/media/device-sensors.ts +158 -0
  305. package/src/media/geolocation.ts +119 -0
  306. package/src/media/index.ts +76 -0
  307. package/src/media/media-query.ts +92 -0
  308. package/src/media/network.ts +115 -0
  309. package/src/media/types.ts +177 -0
  310. package/src/media/viewport.ts +84 -0
  311. package/src/motion/index.ts +57 -48
  312. package/src/motion/morph.ts +151 -0
  313. package/src/motion/parallax.ts +120 -0
  314. package/src/motion/reduced-motion.ts +66 -17
  315. package/src/motion/transition.ts +97 -97
  316. package/src/motion/types.ts +63 -0
  317. package/src/motion/typewriter.ts +164 -0
  318. package/src/platform/announcer.ts +208 -208
  319. package/src/platform/config.ts +163 -163
  320. package/src/platform/cookies.ts +165 -165
  321. package/src/platform/index.ts +39 -39
  322. package/src/platform/meta.ts +168 -168
  323. package/src/plugin/index.ts +37 -0
  324. package/src/plugin/registry.ts +269 -0
  325. package/src/plugin/types.ts +137 -0
  326. package/src/reactive/async-data.ts +486 -486
  327. package/src/reactive/computed.ts +130 -92
  328. package/src/reactive/index.ts +37 -37
  329. package/src/reactive/signal.ts +29 -29
  330. package/src/router/bq-link.ts +279 -0
  331. package/src/router/constraints.ts +201 -0
  332. package/src/router/index.ts +49 -41
  333. package/src/router/match.ts +312 -106
  334. package/src/router/path-pattern.ts +52 -0
  335. package/src/router/query.ts +38 -35
  336. package/src/router/router.ts +402 -211
  337. package/src/router/types.ts +139 -93
  338. package/src/router/use-route.ts +68 -0
  339. package/src/router/utils.ts +157 -116
  340. package/src/security/constants.ts +211 -211
  341. package/src/security/index.ts +12 -10
  342. package/src/security/sanitize.ts +6 -2
  343. package/src/security/trusted-html.ts +71 -0
  344. package/src/ssr/hydrate.ts +82 -0
  345. package/src/ssr/index.ts +70 -0
  346. package/src/ssr/render.ts +508 -0
  347. package/src/ssr/serialize.ts +296 -0
  348. package/src/ssr/types.ts +81 -0
  349. package/src/store/create-store.ts +467 -329
  350. package/src/store/define-store.ts +2 -1
  351. package/src/store/index.ts +27 -22
  352. package/src/store/mapping.ts +2 -1
  353. package/src/store/persisted.ts +249 -61
  354. package/src/store/types.ts +247 -94
  355. package/src/store/utils.ts +135 -141
  356. package/src/store/watch.ts +2 -1
  357. package/src/storybook/index.ts +480 -0
  358. package/src/testing/index.ts +42 -0
  359. package/src/testing/testing.ts +593 -0
  360. package/src/testing/types.ts +170 -0
  361. package/src/view/custom-directives.ts +30 -0
  362. package/src/view/evaluate.ts +292 -290
  363. package/src/view/process.ts +108 -92
  364. package/dist/component-CY5MVoYN.js +0 -531
  365. package/dist/component-CY5MVoYN.js.map +0 -1
  366. package/dist/config-DRmZZno3.js.map +0 -1
  367. package/dist/core-CK2Mfpf4.js +0 -648
  368. package/dist/core-CK2Mfpf4.js.map +0 -1
  369. package/dist/motion-C5DRdPnO.js +0 -415
  370. package/dist/motion-C5DRdPnO.js.map +0 -1
  371. package/dist/platform-B7JhGBc7.js.map +0 -1
  372. package/dist/reactive-BDya-ia8.js +0 -253
  373. package/dist/reactive-BDya-ia8.js.map +0 -1
  374. package/dist/router-CijiICxt.js +0 -188
  375. package/dist/router-CijiICxt.js.map +0 -1
  376. package/dist/sanitize-jyJ2ryE2.js.map +0 -1
  377. package/dist/store-CPK9E62U.js +0 -262
  378. package/dist/store-CPK9E62U.js.map +0 -1
  379. package/dist/view-Cdi0g-qo.js +0 -396
  380. package/dist/view-Cdi0g-qo.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router-BrthaP_z.js","names":[],"sources":["../src/router/state.ts","../src/router/navigation.ts","../src/router/bq-link.ts","../src/router/links.ts","../src/router/query.ts","../src/router/path-pattern.ts","../src/router/match.ts","../src/router/utils.ts","../src/router/router.ts","../src/router/use-route.ts"],"sourcesContent":["/**\n * Internal router state (active router and current route signal).\n * @module bquery/router\n */\n\nimport { computed, signal, type ReadonlySignal, type Signal } from '../reactive/index';\nimport type { Route, Router } from './types';\n\n// ============================================================================\n// Internal State\n// ============================================================================\n\n/** @internal */\nlet activeRouter: Router | null = null;\n\n/** @internal */\nexport const routeSignal: Signal<Route> = signal<Route>({\n path: '',\n params: {},\n query: {},\n matched: null,\n hash: '',\n});\n\n/**\n * Reactive signal containing the current route.\n *\n * @example\n * ```ts\n * import { currentRoute } from 'bquery/router';\n * import { effect } from 'bquery/reactive';\n *\n * effect(() => {\n * document.title = `Page: ${currentRoute.value.path}`;\n * });\n * ```\n */\nexport const currentRoute: ReadonlySignal<Route> = computed(() => routeSignal.value);\n\n/** @internal */\nexport const getActiveRouter = (): Router | null => activeRouter;\n\n/** @internal */\nexport const setActiveRouter = (router: Router | null): void => {\n activeRouter = router;\n};\n","/**\n * Navigation helpers and global router access.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\n\n/**\n * Navigates to a new path.\n *\n * @param path - The path to navigate to\n * @param options - Navigation options\n *\n * @example\n * ```ts\n * import { navigate } from 'bquery/router';\n *\n * // Push to history\n * await navigate('/dashboard');\n *\n * // Replace current entry\n * await navigate('/login', { replace: true });\n * ```\n */\nexport const navigate = async (\n path: string,\n options: { replace?: boolean } = {}\n): Promise<void> => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized. Call createRouter() first.');\n }\n\n await activeRouter[options.replace ? 'replace' : 'push'](path);\n};\n\n/**\n * Programmatically go back in history.\n *\n * @example\n * ```ts\n * import { back } from 'bquery/router';\n * back();\n * ```\n */\nexport const back = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.back();\n } else {\n history.back();\n }\n};\n\n/**\n * Programmatically go forward in history.\n *\n * @example\n * ```ts\n * import { forward } from 'bquery/router';\n * forward();\n * ```\n */\nexport const forward = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.forward();\n } else {\n history.forward();\n }\n};\n","/**\r\n * `<bq-link>` custom element for declarative SPA navigation.\r\n *\r\n * Exposes an accessible custom element that behaves like a link for\r\n * client-side routing. Automatically toggles an active class when the\r\n * target path matches the current route.\r\n *\r\n * @module bquery/router\r\n *\r\n * @example\r\n * ```html\r\n * <bq-link to=\"/\">Home</bq-link>\r\n * <bq-link to=\"/about\" active-class=\"selected\">About</bq-link>\r\n * <bq-link to=\"/settings\" replace exact>Settings</bq-link>\r\n * ```\r\n */\r\n\r\nimport { effect, type CleanupFn } from '../reactive/index';\r\nimport { navigate } from './navigation';\r\nimport { getActiveRouter, routeSignal } from './state';\r\n\r\n/**\r\n * Default CSS class applied when the link's target path is active.\r\n * @internal\r\n */\r\nconst DEFAULT_ACTIVE_CLASS = 'active';\r\n\r\n/** @internal */\r\nconst tokenizeClassNames = (value: string): string[] => {\r\n return value\r\n .split(/\\s+/)\r\n .map((token) => token.trim())\r\n .filter((token) => token.length > 0);\r\n};\r\n\r\n/** @internal SSR-safe base class for environments without HTMLElement. */\r\nconst BQ_LINK_BASE =\r\n typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement);\r\n\r\n/**\r\n * `<bq-link>` — A navigation custom element for bQuery routers.\r\n *\r\n * Attributes:\r\n * - `to` — Target path (required). Example: `to=\"/dashboard\"`.\r\n * - `replace` — If present, replaces the current history entry instead of pushing.\r\n * - `exact` — If present, the active class is only applied on an exact path match.\r\n * - `active-class` — CSS class added when the route is active (default: `'active'`).\r\n *\r\n * The custom element itself acts as the interactive link target using\r\n * `role=\"link\"` and keyboard handling. It does not render a native `<a>`,\r\n * so browser-native link affordances like context-menu \"open in new tab\"\r\n * are not provided automatically.\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerBqLink } from '@bquery/bquery/router';\r\n *\r\n * // Register the <bq-link> element (idempotent)\r\n * registerBqLink();\r\n *\r\n * // Then use in HTML:\r\n * // <bq-link to=\"/about\">About</bq-link>\r\n * ```\r\n */\r\nexport class BqLinkElement extends BQ_LINK_BASE {\r\n /** @internal */\r\n private _cleanup: CleanupFn | null = null;\r\n\r\n /** @internal */\r\n private _trackedActiveClasses = new Map<string, boolean>();\r\n\r\n static get observedAttributes(): string[] {\r\n return ['to', 'replace', 'exact', 'active-class'];\r\n }\r\n\r\n /** The target path for navigation. */\r\n get to(): string {\r\n const to = this.getAttribute('to');\r\n return to == null || to.trim() === '' ? '/' : to;\r\n }\r\n\r\n set to(value: string) {\r\n this.setAttribute('to', value);\r\n }\r\n\r\n /** Whether to replace the current history entry. */\r\n get replace(): boolean {\r\n return this.hasAttribute('replace');\r\n }\r\n\r\n set replace(value: boolean) {\r\n if (value) {\r\n this.setAttribute('replace', '');\r\n } else {\r\n this.removeAttribute('replace');\r\n }\r\n }\r\n\r\n /** Whether to match the path exactly for active class. */\r\n get exact(): boolean {\r\n return this.hasAttribute('exact');\r\n }\r\n\r\n set exact(value: boolean) {\r\n if (value) {\r\n this.setAttribute('exact', '');\r\n } else {\r\n this.removeAttribute('exact');\r\n }\r\n }\r\n\r\n /** CSS class applied when the route is active. */\r\n get activeClass(): string {\r\n return this.getAttribute('active-class') ?? DEFAULT_ACTIVE_CLASS;\r\n }\r\n\r\n set activeClass(value: string) {\r\n this.setAttribute('active-class', value);\r\n }\r\n\r\n /** @internal */\r\n connectedCallback(): void {\r\n // Set role for accessibility if not an <a> already\r\n if (!this.getAttribute('role')) {\r\n this.setAttribute('role', 'link');\r\n }\r\n\r\n // Make focusable if not already\r\n if (!this.hasAttribute('tabindex')) {\r\n this.setAttribute('tabindex', '0');\r\n }\r\n\r\n // Attach click handler\r\n this.addEventListener('click', this._handleClick);\r\n this.addEventListener('keydown', this._handleKeydown);\r\n\r\n // Set up reactive active-class tracking\r\n this._setupActiveTracking();\r\n }\r\n\r\n /** @internal */\r\n disconnectedCallback(): void {\r\n this.removeEventListener('click', this._handleClick);\r\n this.removeEventListener('keydown', this._handleKeydown);\r\n\r\n if (this._cleanup) {\r\n this._cleanup();\r\n this._cleanup = null;\r\n }\r\n\r\n this._clearTrackedActiveClasses();\r\n }\r\n\r\n /** @internal */\r\n attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {\r\n // Re-setup active tracking when relevant attributes change\r\n if (name === 'to' || name === 'exact' || name === 'active-class') {\r\n if (this.isConnected) {\r\n this._setupActiveTracking();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Sets up the reactive effect that toggles the active CSS class\r\n * based on the current route.\r\n * @internal\r\n */\r\n private _setupActiveTracking(): void {\r\n // Clean up previous effect\r\n if (this._cleanup) {\r\n this._cleanup();\r\n this._cleanup = null;\r\n }\r\n\r\n this._clearTrackedActiveClasses();\r\n\r\n const targetPath = this.to;\r\n const exactMatch = this.exact;\r\n const cssClasses = tokenizeClassNames(this.activeClass);\r\n this._trackedActiveClasses = new Map(\r\n cssClasses.map((cssClass) => [cssClass, this.classList.contains(cssClass)])\r\n );\r\n\r\n this._cleanup = effect(() => {\r\n const current = routeSignal.value.path;\r\n const isMatch = exactMatch\r\n ? current === targetPath\r\n : targetPath === '/'\r\n ? current === '/'\r\n : current === targetPath ||\r\n current.startsWith(targetPath.endsWith('/') ? targetPath : targetPath + '/');\r\n\r\n for (const cssClass of cssClasses) {\r\n const wasPresentInitially = this._trackedActiveClasses.get(cssClass) ?? false;\r\n this.classList.toggle(cssClass, isMatch || wasPresentInitially);\r\n }\r\n\r\n // Update aria-current for accessibility\r\n if (isMatch) {\r\n this.setAttribute('aria-current', 'page');\r\n } else {\r\n this.removeAttribute('aria-current');\r\n }\r\n });\r\n }\r\n\r\n /** @internal */\r\n private _clearTrackedActiveClasses(): void {\r\n for (const [cssClass, wasPresentInitially] of this._trackedActiveClasses) {\r\n this.classList.toggle(cssClass, wasPresentInitially);\r\n }\r\n this._trackedActiveClasses.clear();\r\n }\r\n\r\n /**\r\n * Handles click events for SPA navigation.\r\n * @internal\r\n */\r\n private _handleClick = (e: Event): void => {\r\n if (!(e instanceof MouseEvent)) return;\r\n if (e.defaultPrevented) return;\r\n if (e.button !== 0) return; // Only left clicks\r\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;\r\n\r\n e.preventDefault();\r\n this._navigate();\r\n };\r\n\r\n /**\r\n * Handles keyboard activation (Enter).\r\n * @internal\r\n */\r\n private _handleKeydown = (e: Event): void => {\r\n if (e instanceof KeyboardEvent && e.key === 'Enter') {\r\n e.preventDefault();\r\n this._navigate();\r\n }\r\n };\r\n\r\n /**\r\n * Performs the actual navigation.\r\n * @internal\r\n */\r\n private _navigate(): void {\r\n const targetPath = this.to;\r\n if (!targetPath) return;\r\n if (!getActiveRouter()) return;\r\n\r\n void navigate(targetPath, { replace: this.replace }).catch((err) => {\r\n console.error('bq-link: Navigation failed:', err);\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Registers the `<bq-link>` custom element.\r\n *\r\n * This function is idempotent — calling it multiple times is safe.\r\n * The element is registered under the tag name `bq-link`.\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerBqLink } from '@bquery/bquery/router';\r\n *\r\n * registerBqLink();\r\n *\r\n * // Now use <bq-link to=\"/about\">About</bq-link> in HTML\r\n * ```\r\n */\r\nexport const registerBqLink = (): void => {\r\n if (\r\n typeof HTMLElement !== 'undefined' &&\r\n typeof customElements !== 'undefined' &&\r\n !customElements.get('bq-link')\r\n ) {\r\n customElements.define('bq-link', BqLinkElement);\r\n }\r\n};\r\n","/**\n * Link helpers for client-side navigation.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\nimport { navigate } from './navigation';\n\n// ============================================================================\n// Router Link Helper\n// ============================================================================\n\n/**\n * Creates click handler for router links.\n * Attach to anchor elements to enable client-side navigation.\n *\n * @param path - Target path\n * @param options - Navigation options\n * @returns Click event handler\n *\n * @example\n * ```ts\n * import { link } from 'bquery/router';\n * import { $ } from 'bquery/core';\n *\n * $('#nav-home').on('click', link('/'));\n * $('#nav-about').on('click', link('/about'));\n * ```\n */\nexport const link = (path: string, options: { replace?: boolean } = {}): ((e: Event) => void) => {\n return (e: Event) => {\n e.preventDefault();\n void navigate(path, options).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n};\n\n/**\n * Intercepts all link clicks within a container for client-side routing.\n * Only intercepts links with matching origins and no target attribute.\n *\n * @param container - The container element to intercept links in\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```ts\n * import { interceptLinks } from 'bquery/router';\n *\n * // Intercept all links in the app\n * const cleanup = interceptLinks(document.body);\n *\n * // Later, remove the interceptor\n * cleanup();\n * ```\n */\nexport const interceptLinks = (container?: Element): (() => void) => {\n // Provide safe default in DOM environments only\n const targetContainer = container ?? (typeof document !== 'undefined' ? document.body : null);\n if (!targetContainer) {\n // No container available (SSR or invalid input)\n return () => undefined;\n }\n\n const handler = (e: Event) => {\n // Only intercept standard left-clicks without modifier keys\n if (!(e instanceof MouseEvent)) return;\n if (e.defaultPrevented) return; // Already handled\n if (e.button !== 0) return; // Not left-click (middle-click opens new tab, right-click shows context menu)\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; // Modifier keys (Ctrl/Cmd-click = new tab)\n\n // Guard against non-Element targets and non-DOM environments\n if (typeof Element === 'undefined' || !(e.target instanceof Element)) return;\n const target = e.target as HTMLElement;\n const anchor = target.closest('a');\n\n if (!anchor) return;\n\n // Cross-realm compatible anchor check: use owner document's constructor if available\n const anchorWindow = anchor.ownerDocument.defaultView;\n const AnchorConstructor = anchorWindow?.HTMLAnchorElement ?? HTMLAnchorElement;\n if (!(anchor instanceof AnchorConstructor)) return;\n\n if (anchor.target) return; // Has target attribute\n if (anchor.hasAttribute('download')) return;\n if (typeof window === 'undefined') return; // Non-window environment\n if (anchor.origin !== window.location.origin) return; // External link\n\n // Get active router config to handle base paths correctly.\n // If no router is active, proceed with no base/hash; navigate() will throw a\n // \"No router initialized\" error, which is caught and logged below.\n const router = getActiveRouter();\n if (!router) {\n // No active router - trigger navigate(), allowing its error to be logged here\n e.preventDefault();\n void navigate(anchor.pathname + anchor.search + anchor.hash).catch((err) => {\n console.error('Navigation failed:', err);\n });\n return;\n }\n\n const base = router.base;\n const useHash = router.hash;\n\n // Detect hash-routing mode: links written as href=\"#/page\"\n // In this case, anchor.hash contains the route path\n let path: string;\n if (useHash && anchor.hash && anchor.hash.startsWith('#/')) {\n // Hash-routing mode: extract path from the hash\n // e.g., href=\"#/page?foo=bar\" → path = \"/page?foo=bar\"\n path = anchor.hash.slice(1); // Remove leading #\n } else {\n // History mode: use pathname + search + hash\n // Strip base from pathname to avoid duplication (router.push() re-adds it)\n let pathname = anchor.pathname;\n if (base && base !== '/' && pathname.startsWith(base)) {\n pathname = pathname.slice(base.length) || '/';\n }\n path = pathname + anchor.search + anchor.hash;\n }\n\n e.preventDefault();\n void navigate(path).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n\n targetContainer.addEventListener('click', handler);\n return () => targetContainer.removeEventListener('click', handler);\n};\n","/**\r\n * Query string helpers.\r\n * @module bquery/router\r\n */\r\n\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\n\r\n/**\r\n * Parses query string into an object.\r\n * Single values are stored as strings, duplicate keys become arrays.\r\n * @internal\r\n *\r\n * @example\r\n * parseQuery('?foo=1') // { foo: '1' }\r\n * parseQuery('?tag=a&tag=b') // { tag: ['a', 'b'] }\r\n * parseQuery('?x=1&y=2&x=3') // { x: ['1', '3'], y: '2' }\r\n */\r\nexport const parseQuery = (search: string): Record<string, string | string[]> => {\r\n const query: Record<string, string | string[]> = {};\r\n const params = new URLSearchParams(search);\r\n\r\n params.forEach((value, key) => {\r\n if (isPrototypePollutionKey(key)) return;\r\n const existing = query[key];\r\n if (existing === undefined) {\r\n // First occurrence: store as string\r\n query[key] = value;\r\n } else if (Array.isArray(existing)) {\r\n // Already an array: append\r\n existing.push(value);\r\n } else {\r\n // Second occurrence: convert to array\r\n query[key] = [existing, value];\r\n }\r\n });\r\n\r\n return query;\r\n};\r\n","/**\r\n * Shared helpers for parsing route path params and constraints.\r\n * @internal\r\n */\r\n\r\n/** Validates whether a character can start a route param name. @internal */\r\nexport const isParamStart = (char: string | undefined): boolean =>\r\n char !== undefined &&\r\n ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char === '_');\r\n\r\n/** Validates whether a character can appear after the start of a route param name. @internal */\r\nexport const isParamChar = (char: string | undefined): boolean =>\r\n isParamStart(char) || (char !== undefined && char >= '0' && char <= '9');\r\n\r\n/** Reads a route param constraint while preserving escaped chars and nested groups. @internal */\r\nexport const readConstraint = (\r\n path: string,\r\n startIndex: number\r\n): { constraint: string; endIndex: number } | null => {\r\n let depth = 1;\r\n let constraint = '';\r\n let i = startIndex + 1;\r\n let inCharacterClass = false;\r\n\r\n while (i < path.length) {\r\n const char = path[i];\r\n\r\n if (char === '\\\\' && i + 1 < path.length) {\r\n constraint += char + path[i + 1];\r\n i += 2;\r\n continue;\r\n }\r\n\r\n if (char === '[' && !inCharacterClass) {\r\n inCharacterClass = true;\r\n } else if (char === ']' && inCharacterClass) {\r\n inCharacterClass = false;\r\n } else if (!inCharacterClass && char === '(') {\r\n depth++;\r\n } else if (!inCharacterClass && char === ')') {\r\n depth--;\r\n if (depth === 0) {\r\n return { constraint, endIndex: i + 1 };\r\n }\r\n }\r\n\r\n constraint += char;\r\n i++;\r\n }\r\n\r\n return null;\r\n};\r\n","/**\r\n * Route matching helpers.\r\n * @module bquery/router\r\n */\r\n\r\nimport { parseQuery } from './query';\r\nimport { getNormalizedRouteConstraint, getRouteConstraintRegex } from './constraints';\r\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\r\nimport type { Route, RouteDefinition } from './types';\r\n\r\nconst readConstraintOrThrow = (\r\n path: string,\r\n startIndex: number\r\n): { constraint: string; endIndex: number } => {\r\n const parsedConstraint = readConstraint(path, startIndex);\r\n if (!parsedConstraint) {\r\n throw new Error(\r\n `bQuery router: Invalid route param constraint syntax in path \"${path}\" at index ${startIndex}.`\r\n );\r\n }\r\n return parsedConstraint;\r\n};\r\n\r\ntype RouteParamDescriptor = {\r\n name: string;\r\n constraint?: string;\r\n nextIndex: number;\r\n};\r\n\r\nconst validatedRoutePathCache = new Set<string>();\r\n\r\nconst readParamDescriptor = (path: string, index: number): RouteParamDescriptor | null => {\r\n if (path[index] !== ':' || !isParamStart(path[index + 1])) {\r\n return null;\r\n }\r\n\r\n let nameEnd = index + 2;\r\n while (nameEnd < path.length && isParamChar(path[nameEnd])) {\r\n nameEnd++;\r\n }\r\n\r\n let nextIndex = nameEnd;\r\n let constraint: string | undefined;\r\n\r\n if (path[nameEnd] === '(') {\r\n const parsedConstraint = readConstraintOrThrow(path, nameEnd);\r\n constraint = parsedConstraint.constraint;\r\n nextIndex = parsedConstraint.endIndex;\r\n }\r\n\r\n return {\r\n name: path.slice(index + 1, nameEnd),\r\n constraint,\r\n nextIndex,\r\n };\r\n};\r\n\r\nconst validateRoutePathPattern = (path: string): void => {\r\n if (validatedRoutePathCache.has(path)) {\r\n return;\r\n }\r\n\r\n for (let i = 0; i < path.length; ) {\r\n const char = path[i];\r\n\r\n if (char === ':' && isParamStart(path[i + 1])) {\r\n const param = readParamDescriptor(path, i);\r\n if (param?.constraint) {\r\n getNormalizedRouteConstraint(param.constraint);\r\n }\r\n i = param?.nextIndex ?? i + 1;\r\n continue;\r\n }\r\n\r\n i++;\r\n }\r\n\r\n validatedRoutePathCache.add(path);\r\n};\r\n\r\nconst findSegmentBoundary = (value: string, startIndex: number): number => {\r\n const slashIndex = value.indexOf('/', startIndex);\r\n return slashIndex === -1 ? value.length : slashIndex;\r\n};\r\n\r\nconst readNextStaticChunk = (path: string, startIndex: number): string => {\r\n let chunkEnd = startIndex;\r\n\r\n while (chunkEnd < path.length) {\r\n if (path[chunkEnd] === '*') {\r\n break;\r\n }\r\n\r\n if (path[chunkEnd] === ':' && isParamStart(path[chunkEnd + 1])) {\r\n break;\r\n }\r\n\r\n chunkEnd++;\r\n }\r\n\r\n return path.slice(startIndex, chunkEnd);\r\n};\r\n\r\nconst findAnchoredCandidateEnds = (\r\n actualPath: string,\r\n startIndex: number,\r\n limit: number,\r\n nextStaticChunk: string\r\n): number[] => {\r\n const candidates: number[] = [];\r\n let searchIndex = startIndex;\r\n\r\n while (searchIndex <= limit) {\r\n const candidateEnd = actualPath.indexOf(nextStaticChunk, searchIndex);\r\n if (candidateEnd === -1 || candidateEnd > limit) {\r\n break;\r\n }\r\n\r\n candidates.push(candidateEnd);\r\n searchIndex = candidateEnd + 1;\r\n }\r\n\r\n return candidates.reverse();\r\n};\r\n\r\nconst matchPathPattern = (routePath: string, actualPath: string): Record<string, string> | null => {\r\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\r\n // within a single route/path match attempt.\r\n const memo = new Map<string, Record<string, string> | null>();\r\n\r\n const matchFrom = (routeIndex: number, pathIndex: number): Record<string, string> | null => {\r\n const memoKey = `${routeIndex}:${pathIndex}`;\r\n if (memo.has(memoKey)) {\r\n return memo.get(memoKey) ?? null;\r\n }\r\n\r\n if (routeIndex === routePath.length) {\r\n const result = pathIndex === actualPath.length ? {} : null;\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n\r\n const routeChar = routePath[routeIndex];\r\n\r\n if (routeChar === '*') {\r\n if (routeIndex === routePath.length - 1) {\r\n const result = {};\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n\r\n const nextStaticChunk = readNextStaticChunk(routePath, routeIndex + 1);\r\n const anchoredCandidateEnds =\r\n nextStaticChunk.length > 0\r\n ? findAnchoredCandidateEnds(actualPath, pathIndex, actualPath.length, nextStaticChunk)\r\n : null;\r\n\r\n const iterateCandidateEnds = anchoredCandidateEnds\r\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (const candidateEnd of anchoredCandidateEnds) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n }\r\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (let candidateEnd = actualPath.length; candidateEnd >= pathIndex; candidateEnd--) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n const wildcardMatch = iterateCandidateEnds((candidateEnd) => {\r\n const suffixMatch = matchFrom(routeIndex + 1, candidateEnd);\r\n if (suffixMatch) {\r\n memo.set(memoKey, suffixMatch);\r\n return suffixMatch;\r\n }\r\n return null;\r\n });\r\n\r\n if (wildcardMatch) {\r\n return wildcardMatch;\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n const param = readParamDescriptor(routePath, routeIndex);\r\n if (param) {\r\n const constraintRegex = param.constraint\r\n ? getRouteConstraintRegex(param.constraint)\r\n : undefined;\r\n const candidateLimit = param.constraint\r\n ? actualPath.length\r\n : findSegmentBoundary(actualPath, pathIndex);\r\n const nextStaticChunk = readNextStaticChunk(routePath, param.nextIndex);\r\n const anchoredCandidateEnds =\r\n nextStaticChunk.length > 0\r\n ? findAnchoredCandidateEnds(actualPath, pathIndex, candidateLimit, nextStaticChunk)\r\n : null;\r\n\r\n const iterateCandidateEnds = anchoredCandidateEnds\r\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (const candidateEnd of anchoredCandidateEnds) {\r\n if (candidateEnd <= pathIndex) {\r\n continue;\r\n }\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n }\r\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n const paramMatch = iterateCandidateEnds((candidateEnd) => {\r\n const candidateValue = actualPath.slice(pathIndex, candidateEnd);\r\n\r\n if (constraintRegex) {\r\n if (!constraintRegex.test(candidateValue)) {\r\n return null;\r\n }\r\n }\r\n\r\n const suffixMatch = matchFrom(param.nextIndex, candidateEnd);\r\n if (suffixMatch) {\r\n const result = {\r\n [param.name]: candidateValue,\r\n ...suffixMatch,\r\n };\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n return null;\r\n });\r\n\r\n if (paramMatch) {\r\n return paramMatch;\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n if (pathIndex >= actualPath.length || routeChar !== actualPath[pathIndex]) {\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n const result = matchFrom(routeIndex + 1, pathIndex + 1);\r\n memo.set(memoKey, result);\r\n return result;\r\n };\r\n\r\n return matchFrom(0, 0);\r\n};\r\n\r\n/**\r\n * Matches a path against route definitions and extracts params.\r\n * @internal\r\n */\r\nexport const matchRoute = (\r\n path: string,\r\n routes: RouteDefinition[]\r\n): { matched: RouteDefinition; params: Record<string, string> } | null => {\r\n for (const route of routes) {\r\n validateRoutePathPattern(route.path);\r\n const params = matchPathPattern(route.path, path);\r\n if (params) {\r\n return { matched: route, params };\r\n }\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Creates a Route object from the current URL.\r\n * @internal\r\n */\r\nexport const createRoute = (\r\n pathname: string,\r\n search: string,\r\n hash: string,\r\n routes: RouteDefinition[]\r\n): Route => {\r\n const result = matchRoute(pathname, routes);\r\n\r\n return {\r\n path: pathname,\r\n params: result?.params ?? {},\r\n query: parseQuery(search),\r\n matched: result?.matched ?? null,\r\n hash: hash.replace(/^#/, ''),\r\n };\r\n};\r\n","/**\r\n * Router utilities.\r\n * @module bquery/router\r\n */\r\n\r\nimport { computed, type ReadonlySignal } from '../reactive/index';\r\nimport { getRouteConstraintRegex } from './constraints';\r\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\r\nimport { getActiveRouter, routeSignal } from './state';\r\nimport type { RouteDefinition } from './types';\r\n\r\n// ============================================================================\r\n// Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Flattens nested routes into a single array with full paths.\r\n * Does NOT include the router base - base is only for browser history.\r\n * @internal\r\n */\r\nexport const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {\r\n const result: RouteDefinition[] = [];\r\n\r\n for (const route of routes) {\r\n const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\\/+/g, '/');\r\n\r\n result.push({\r\n ...route,\r\n path: fullPath,\r\n });\r\n\r\n if (route.children) {\r\n result.push(...flattenRoutes(route.children, fullPath));\r\n }\r\n }\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Resolves a route by name and params.\r\n *\r\n * @param name - The route name\r\n * @param params - Route params to interpolate\r\n * @returns The resolved path\r\n * @throws {Error} If no router is initialized, the route name is unknown,\r\n * a required path param is missing from `params`, a param value does not satisfy\r\n * its route regex constraint, or a route param constraint has invalid syntax\r\n *\r\n * @example\r\n * ```ts\r\n * import { resolve } from 'bquery/router';\r\n *\r\n * const path = resolve('user', { id: '42' });\r\n * // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }\r\n * ```\r\n */\r\nexport const resolve = (name: string, params: Record<string, string> = {}): string => {\r\n const activeRouter = getActiveRouter();\r\n if (!activeRouter) {\r\n throw new Error('bQuery router: No router initialized.');\r\n }\r\n\r\n const route = activeRouter.routes.find((r) => r.name === name);\r\n if (!route) {\r\n throw new Error(`bQuery router: Route \"${name}\" not found.`);\r\n }\r\n\r\n let path = '';\r\n for (let i = 0; i < route.path.length; ) {\r\n if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {\r\n let nameEnd = i + 2;\r\n while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {\r\n nameEnd++;\r\n }\r\n\r\n let nextIndex = nameEnd;\r\n let constraint: string | null = null;\r\n if (route.path[nameEnd] === '(') {\r\n const parsedConstraint = readConstraint(route.path, nameEnd);\r\n if (!parsedConstraint) {\r\n throw new Error(\r\n `bQuery router: Invalid constraint syntax in path \"${route.path}\" for route \"${name}\".`\r\n );\r\n }\r\n constraint = parsedConstraint.constraint;\r\n nextIndex = parsedConstraint.endIndex;\r\n }\r\n\r\n const key = route.path.slice(i + 1, nameEnd);\r\n const value = params[key];\r\n if (value === undefined) {\r\n throw new Error(`bQuery router: Missing required param \"${key}\" for route \"${name}\".`);\r\n }\r\n if (constraint && !getRouteConstraintRegex(constraint).test(value)) {\r\n throw new Error(\r\n `bQuery router: Param \"${key}\" with value \"${value}\" does not satisfy the route constraint \"${constraint}\" for route \"${name}\".`\r\n );\r\n }\r\n\r\n path += encodeURIComponent(value);\r\n i = nextIndex;\r\n continue;\r\n }\r\n\r\n path += route.path[i];\r\n i++;\r\n }\r\n\r\n return path;\r\n};\r\n\r\n/**\r\n * Checks if a path matches the current route.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly (default: false)\r\n * @returns True if the path matches\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActive } from 'bquery/router';\r\n *\r\n * if (isActive('/dashboard')) {\r\n * // Highlight nav item\r\n * }\r\n * ```\r\n */\r\nexport const isActive = (path: string, exact = false): boolean => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n};\r\n\r\n/**\r\n * Creates a computed signal that checks if a path is active.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly\r\n * @returns A reactive signal\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActiveSignal } from 'bquery/router';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * const dashboardActive = isActiveSignal('/dashboard');\r\n * effect(() => {\r\n * navItem.classList.toggle('active', dashboardActive.value);\r\n * });\r\n * ```\r\n */\r\nexport const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {\r\n return computed(() => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n });\r\n};\r\n","/**\r\n * Router creation and lifecycle management.\r\n * @module bquery/router\r\n */\r\n\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\nimport { createRoute } from './match';\r\nimport { currentRoute, getActiveRouter, routeSignal, setActiveRouter } from './state';\r\nimport type { NavigationGuard, Route, Router, RouterOptions } from './types';\r\nimport { flattenRoutes } from './utils';\r\n\r\n// ============================================================================\r\n// Router Creation\r\n// ============================================================================\r\n\r\nconst MAX_SCROLL_POSITION_ENTRIES = 100;\r\n\r\nconst sanitizeHistoryState = (state: Record<string, unknown>): Record<string, unknown> => {\r\n const sanitized: Record<string, unknown> = {};\r\n\r\n for (const [key, value] of Object.entries(state)) {\r\n if (isPrototypePollutionKey(key)) continue;\r\n sanitized[key] = value;\r\n }\r\n\r\n return sanitized;\r\n};\r\n\r\n/**\r\n * Creates and initializes a router instance.\r\n *\r\n * @param options - Router configuration\r\n * @returns The router instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createRouter } from 'bquery/router';\r\n *\r\n * const router = createRouter({\r\n * routes: [\r\n * { path: '/', component: () => import('./pages/Home') },\r\n * { path: '/about', component: () => import('./pages/About') },\r\n * { path: '/user/:id(\\\\d+)', component: () => import('./pages/User') },\r\n * { path: '/old-page', redirectTo: '/new-page' },\r\n * { path: '*', component: () => import('./pages/NotFound') },\r\n * ],\r\n * base: '/app',\r\n * scrollRestoration: true,\r\n * });\r\n *\r\n * router.beforeEach((to, from) => {\r\n * if (to.path === '/admin' && !isAuthenticated()) {\r\n * return false; // Cancel navigation\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const createRouter = (options: RouterOptions): Router => {\r\n // Clean up any existing router to prevent guard leakage\r\n const existingRouter = getActiveRouter();\r\n if (existingRouter) {\r\n existingRouter.destroy();\r\n }\r\n\r\n const { routes, base = '', hash: useHash = false, scrollRestoration = false } = options;\r\n\r\n // Instance-specific guards and hooks (not shared globally)\r\n const beforeGuards: NavigationGuard[] = [];\r\n const afterHooks: Array<(to: Route, from: Route) => void> = [];\r\n\r\n // Flatten nested routes (base-relative, not including the base path)\r\n const flatRoutes = flattenRoutes(routes);\r\n\r\n // Scroll position storage keyed by history state id\r\n const scrollPositions = new Map<string, { x: number; y: number }>();\r\n let currentScrollKey = '0';\r\n let scrollKeyCounter = 0;\r\n let previousScrollRestoration: History['scrollRestoration'] | null = null;\r\n\r\n // Enable manual scroll restoration if scrollRestoration is configured\r\n if (scrollRestoration && typeof history !== 'undefined' && 'scrollRestoration' in history) {\r\n previousScrollRestoration = history.scrollRestoration;\r\n if (history.scrollRestoration !== 'manual') {\r\n history.scrollRestoration = 'manual';\r\n }\r\n\r\n const state =\r\n history.state && typeof history.state === 'object'\r\n ? (history.state as Record<string, unknown>)\r\n : {};\r\n\r\n if (typeof state.__bqScrollKey !== 'string') {\r\n const currentUrl = useHash\r\n ? window.location.hash || '#/'\r\n : `${window.location.pathname}${window.location.search}${window.location.hash}`;\r\n history.replaceState({ ...state, __bqScrollKey: currentScrollKey }, '', currentUrl);\r\n }\r\n }\r\n\r\n /**\r\n * Generates a unique key for the current history entry.\r\n * @internal\r\n */\r\n const getScrollKey = (): string => {\r\n return (history.state && history.state.__bqScrollKey) || currentScrollKey;\r\n };\r\n\r\n /**\r\n * Generates a unique key for a new history entry.\r\n * @internal\r\n */\r\n const createScrollKey = (): string => `${Date.now()}-${scrollKeyCounter++}`;\r\n\r\n /**\r\n * Saves current scroll position for the current history entry.\r\n * @internal\r\n */\r\n const saveScrollPosition = (key = getScrollKey()): void => {\r\n if (!scrollRestoration) return;\r\n if (scrollPositions.has(key)) {\r\n // Refresh the insertion order so pruning behaves like an LRU cache.\r\n scrollPositions.delete(key);\r\n }\r\n scrollPositions.set(key, { x: window.scrollX, y: window.scrollY });\r\n while (scrollPositions.size > MAX_SCROLL_POSITION_ENTRIES) {\r\n const oldestKey = scrollPositions.keys().next().value as string | undefined;\r\n if (oldestKey === undefined) {\r\n break;\r\n }\r\n scrollPositions.delete(oldestKey);\r\n }\r\n };\r\n\r\n /**\r\n * Restores scroll position for the current history entry.\r\n * @internal\r\n */\r\n const restoreScrollPosition = (key = getScrollKey()): void => {\r\n if (!scrollRestoration) return;\r\n const pos = scrollPositions.get(key);\r\n if (pos) {\r\n window.scrollTo(pos.x, pos.y);\r\n } else {\r\n window.scrollTo(0, 0);\r\n }\r\n };\r\n\r\n /**\r\n * Builds history state for canceled navigations without dropping\r\n * the scroll restoration key for the current entry.\r\n * @internal\r\n */\r\n const getRestoreHistoryState = (): Record<string, unknown> => {\r\n const state =\r\n history.state && typeof history.state === 'object'\r\n ? { ...(history.state as Record<string, unknown>) }\r\n : {};\r\n\r\n if (scrollRestoration) {\r\n state.__bqScrollKey = currentScrollKey;\r\n }\r\n\r\n return state;\r\n };\r\n\r\n /**\r\n * Gets the current path from the URL.\r\n */\r\n const getCurrentPath = (): { pathname: string; search: string; hash: string } => {\r\n if (useHash) {\r\n const hashPath = window.location.hash.slice(1) || '/';\r\n // In hash routing, URL structure is #/path?query#fragment\r\n // Extract hash fragment first (after the second #)\r\n const [pathWithQuery, hashPart = ''] = hashPath.split('#');\r\n // Then extract query from the path\r\n const [pathname, search = ''] = pathWithQuery.split('?');\r\n return {\r\n pathname,\r\n search: search ? `?${search}` : '',\r\n hash: hashPart ? `#${hashPart}` : '',\r\n };\r\n }\r\n\r\n let pathname = window.location.pathname;\r\n if (base && (pathname === base || pathname.startsWith(base + '/'))) {\r\n pathname = pathname.slice(base.length) || '/';\r\n }\r\n\r\n return {\r\n pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n };\r\n };\r\n\r\n /**\r\n * Updates the route signal with current URL state.\r\n */\r\n const syncRoute = (): void => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const newRoute = createRoute(pathname, search, hash, flatRoutes);\r\n routeSignal.value = newRoute;\r\n };\r\n\r\n /**\r\n * Performs navigation with guards.\r\n */\r\n const performNavigation = async (\r\n path: string,\r\n method: 'pushState' | 'replaceState',\r\n visitedPaths: Set<string> = new Set()\r\n ): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Parse the target path\r\n const url = new URL(path, window.location.origin);\r\n const resolvedPath = `${url.pathname}${url.search}${url.hash}`;\r\n if (visitedPaths.has(resolvedPath)) {\r\n throw new Error(`bQuery router: redirect loop detected for path \"${resolvedPath}\"`);\r\n }\r\n visitedPaths.add(resolvedPath);\r\n const to = createRoute(url.pathname, url.search, url.hash, flatRoutes);\r\n\r\n // Check for redirectTo on the matched route\r\n if (to.matched?.redirectTo) {\r\n // Navigate to the redirect target instead\r\n await performNavigation(to.matched.redirectTo, method, visitedPaths);\r\n return;\r\n }\r\n\r\n // Run route-level beforeEnter guard\r\n if (to.matched?.beforeEnter) {\r\n const result = await to.matched.beforeEnter(to, from);\r\n if (result === false) {\r\n return; // Cancel navigation\r\n }\r\n }\r\n\r\n // Run beforeEach guards\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n return; // Cancel navigation\r\n }\r\n }\r\n\r\n // Save scroll position before navigation\r\n saveScrollPosition();\r\n\r\n // Update browser history\r\n const existingScrollKey = scrollRestoration ? getScrollKey() : undefined;\r\n const scrollKey =\r\n method === 'replaceState' && existingScrollKey ? existingScrollKey : createScrollKey();\r\n const fullPath = useHash ? `#${path}` : `${base}${path}`;\r\n const baseState =\r\n scrollRestoration && history.state && typeof history.state === 'object'\r\n ? sanitizeHistoryState(history.state as Record<string, unknown>)\r\n : {};\r\n const state = scrollRestoration ? { ...baseState, __bqScrollKey: scrollKey } : {};\r\n history[method](state, '', fullPath);\r\n currentScrollKey = scrollKey;\r\n\r\n // Update route signal\r\n syncRoute();\r\n\r\n // Scroll to top on push navigation\r\n if (scrollRestoration && method === 'pushState') {\r\n window.scrollTo(0, 0);\r\n }\r\n\r\n // Run afterEach hooks\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n /**\r\n * Handle popstate events (back/forward).\r\n */\r\n const handlePopState = async (event: PopStateEvent): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = routeSignal.value;\r\n const to = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Check for redirectTo on the matched route\r\n if (to.matched?.redirectTo) {\r\n await performNavigation(to.matched.redirectTo, 'replaceState');\r\n return;\r\n }\r\n\r\n // Run route-level beforeEnter guard\r\n if (to.matched?.beforeEnter) {\r\n const result = await to.matched.beforeEnter(to, from);\r\n if (result === false) {\r\n // Restore previous state with full URL (including query/hash)\r\n const queryString = new URLSearchParams(\r\n Object.entries(from.query).flatMap(([key, value]) =>\r\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\r\n )\r\n ).toString();\r\n const searchStr = queryString ? `?${queryString}` : '';\r\n const hashStr = from.hash ? `#${from.hash}` : '';\r\n const restorePath = useHash\r\n ? `#${from.path}${searchStr}${hashStr}`\r\n : `${base}${from.path}${searchStr}${hashStr}`;\r\n history.replaceState(getRestoreHistoryState(), '', restorePath);\r\n return;\r\n }\r\n }\r\n\r\n // Run beforeEach guards (supports async guards)\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n // Restore previous state with full URL (including query/hash)\r\n const queryString = new URLSearchParams(\r\n Object.entries(from.query).flatMap(([key, value]) =>\r\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\r\n )\r\n ).toString();\r\n const search = queryString ? `?${queryString}` : '';\r\n const hash = from.hash ? `#${from.hash}` : '';\r\n const restorePath = useHash\r\n ? `#${from.path}${search}${hash}`\r\n : `${base}${from.path}${search}${hash}`;\r\n history.replaceState(getRestoreHistoryState(), '', restorePath);\r\n return;\r\n }\r\n }\r\n\r\n // Save scroll position of the page we're leaving\r\n saveScrollPosition(currentScrollKey);\r\n\r\n // Update scroll key from history state\r\n currentScrollKey =\r\n (event.state as { __bqScrollKey?: string } | null)?.__bqScrollKey ?? getScrollKey();\r\n\r\n syncRoute();\r\n\r\n // Restore scroll position for the entry we're navigating to\r\n restoreScrollPosition(currentScrollKey);\r\n\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n // Attach popstate listener\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n // Initialize route\r\n syncRoute();\r\n\r\n const router: Router = {\r\n push: (path: string) => performNavigation(path, 'pushState'),\r\n replace: (path: string) => performNavigation(path, 'replaceState'),\r\n back: () => history.back(),\r\n forward: () => history.forward(),\r\n go: (delta: number) => history.go(delta),\r\n\r\n beforeEach: (guard: NavigationGuard) => {\r\n beforeGuards.push(guard);\r\n return () => {\r\n const index = beforeGuards.indexOf(guard);\r\n if (index > -1) beforeGuards.splice(index, 1);\r\n };\r\n },\r\n\r\n afterEach: (hook: (to: Route, from: Route) => void) => {\r\n afterHooks.push(hook);\r\n return () => {\r\n const index = afterHooks.indexOf(hook);\r\n if (index > -1) afterHooks.splice(index, 1);\r\n };\r\n },\r\n\r\n currentRoute,\r\n routes: flatRoutes,\r\n base,\r\n hash: useHash,\r\n\r\n destroy: () => {\r\n window.removeEventListener('popstate', handlePopState);\r\n beforeGuards.length = 0;\r\n afterHooks.length = 0;\r\n scrollPositions.clear();\r\n // Restore the previous scroll restoration mode on destroy\r\n if (\r\n previousScrollRestoration !== null &&\r\n typeof history !== 'undefined' &&\r\n 'scrollRestoration' in history\r\n ) {\r\n history.scrollRestoration = previousScrollRestoration;\r\n }\r\n setActiveRouter(null);\r\n },\r\n };\r\n\r\n setActiveRouter(router);\r\n return router;\r\n};\r\n","/**\r\n * Reactive route composable.\r\n * @module bquery/router\r\n */\r\n\r\nimport { computed, type ReadonlySignal } from '../reactive/index';\r\nimport { routeSignal } from './state';\r\nimport type { Route, RouteDefinition } from './types';\r\n\r\n// ============================================================================\r\n// useRoute Composable\r\n// ============================================================================\r\n\r\n/**\r\n * Return type for {@link useRoute}.\r\n * Provides reactive access to individual route properties.\r\n */\r\nexport type UseRouteReturn = {\r\n /** Full reactive route object */\r\n route: ReadonlySignal<Route>;\r\n /** Reactive current path */\r\n path: ReadonlySignal<string>;\r\n /** Reactive route params */\r\n params: ReadonlySignal<Record<string, string>>;\r\n /** Reactive query params */\r\n query: ReadonlySignal<Record<string, string | string[]>>;\r\n /** Reactive hash fragment (without #) */\r\n hash: ReadonlySignal<string>;\r\n /** Reactive matched route definition */\r\n matched: ReadonlySignal<RouteDefinition | null>;\r\n};\r\n\r\nconst route = computed(() => routeSignal.value);\r\nconst path = computed(() => route.value.path);\r\nconst params = computed(() => route.value.params);\r\nconst query = computed(() => route.value.query);\r\nconst hash = computed(() => route.value.hash);\r\nconst matched = computed(() => route.value.matched);\r\n\r\nconst routeHandle: UseRouteReturn = { route, path, params, query, hash, matched };\r\n\r\n/**\r\n * Returns reactive access to the current route, params, query, and hash.\r\n *\r\n * Each property is a readonly computed signal that updates automatically\r\n * when the route changes. This is useful for fine-grained reactivity\r\n * where you only need to subscribe to specific route parts.\r\n *\r\n * @returns An object with reactive route properties\r\n *\r\n * @example\r\n * ```ts\r\n * import { useRoute } from '@bquery/bquery/router';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const { path, params, query, hash } = useRoute();\r\n *\r\n * effect(() => {\r\n * console.log('Path:', path.value);\r\n * console.log('Params:', params.value);\r\n * console.log('Query:', query.value);\r\n * console.log('Hash:', hash.value);\r\n * });\r\n * ```\r\n */\r\nexport const useRoute = (): UseRouteReturn => {\r\n return routeHandle;\r\n};\r\n"],"mappings":"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"}
@@ -1,13 +1,16 @@
1
- import { a as s, c as e, i as r, l as t, n as i, o, r as c, s as n, t as l, u } from "./router-CijiICxt.js";
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";
2
2
  export {
3
- n as back,
4
- l as createRouter,
3
+ e as BqLinkElement,
4
+ v as back,
5
+ o as createRouter,
5
6
  u as currentRoute,
6
- e as forward,
7
- s as interceptLinks,
8
- i as isActive,
9
- c as isActiveSignal,
10
- o as link,
11
- t as navigate,
12
- r as resolve
7
+ t as forward,
8
+ c as interceptLinks,
9
+ k as isActive,
10
+ r as isActiveSignal,
11
+ l as link,
12
+ i as navigate,
13
+ n as registerBqLink,
14
+ s as resolve,
15
+ p as useRoute
13
16
  };
@@ -1,4 +1,4 @@
1
- var y = "bquery-sanitizer", D = /* @__PURE__ */ new Set([
1
+ var T = "bquery-sanitizer", U = /* @__PURE__ */ new Set([
2
2
  "a",
3
3
  "abbr",
4
4
  "address",
@@ -83,7 +83,7 @@ var y = "bquery-sanitizer", D = /* @__PURE__ */ new Set([
83
83
  "ul",
84
84
  "var",
85
85
  "wbr"
86
- ]), T = /* @__PURE__ */ new Set([
86
+ ]), S = /* @__PURE__ */ new Set([
87
87
  "script",
88
88
  "iframe",
89
89
  "frame",
@@ -100,7 +100,7 @@ var y = "bquery-sanitizer", D = /* @__PURE__ */ new Set([
100
100
  "svg",
101
101
  "foreignobject",
102
102
  "noscript"
103
- ]), U = /* @__PURE__ */ new Set([
103
+ ]), O = /* @__PURE__ */ new Set([
104
104
  "document",
105
105
  "window",
106
106
  "location",
@@ -153,132 +153,139 @@ var y = "bquery-sanitizer", D = /* @__PURE__ */ new Set([
153
153
  "type",
154
154
  "width",
155
155
  "aria-*"
156
- ]), H = [
156
+ ]), W = [
157
157
  "on",
158
158
  "formaction",
159
159
  "xlink:",
160
160
  "xmlns:"
161
- ], O = [
161
+ ], k = [
162
162
  "javascript:",
163
163
  "data:",
164
164
  "vbscript:",
165
165
  "file:"
166
- ], W = (t, e, r) => {
167
- const a = t.toLowerCase();
168
- for (const l of H) if (a.startsWith(l)) return !1;
169
- return r && a.startsWith("data-") || a.startsWith("aria-") ? !0 : e.has(a);
170
- }, k = (t) => {
171
- const e = t.toLowerCase().trim();
172
- return !U.has(e);
173
- }, P = (t) => t.replace(/[\u0000-\u001F\u007F]+/g, "").replace(/[\u200B-\u200D\uFEFF\u2028\u2029]+/g, "").replace(/\\u[\da-fA-F]{4}/g, "").replace(/\s+/g, "").toLowerCase(), N = (t) => {
174
- const e = P(t);
175
- for (const r of O) if (e.startsWith(r)) return !1;
166
+ ], z = (e, t, r) => {
167
+ const a = e.toLowerCase();
168
+ for (const l of W) if (a.startsWith(l)) return !1;
169
+ return r && a.startsWith("data-") || a.startsWith("aria-") ? !0 : t.has(a);
170
+ }, M = (e) => {
171
+ const t = e.toLowerCase().trim();
172
+ return !O.has(t);
173
+ }, P = (e) => e.replace(/[\u0000-\u001F\u007F]+/g, "").replace(/[\u200B-\u200D\uFEFF\u2028\u2029]+/g, "").replace(/\\u[\da-fA-F]{4}/g, "").replace(/\s+/g, "").toLowerCase(), L = (e) => {
174
+ const t = P(e);
175
+ for (const r of k) if (t.startsWith(r)) return !1;
176
176
  return !0;
177
- }, M = (t) => {
178
- const e = t.split(",");
179
- for (const r of e) {
177
+ }, q = (e) => {
178
+ const t = e.split(",");
179
+ for (const r of t) {
180
180
  const a = r.trim().split(/\s+/)[0];
181
- if (a && !N(a)) return !1;
181
+ if (a && !L(a)) return !1;
182
182
  }
183
183
  return !0;
184
- }, z = (t) => {
184
+ }, I = (e) => {
185
185
  try {
186
- const e = t.trim();
187
- if (e.startsWith("//")) return !0;
188
- const r = e.toLowerCase();
189
- return /^[a-z][a-z0-9+.-]*:/i.test(e) && !r.startsWith("http://") && !r.startsWith("https://") ? !0 : !r.startsWith("http://") && !r.startsWith("https://") ? !1 : typeof window > "u" || !window.location ? !0 : new URL(e, window.location.href).origin !== window.location.origin;
186
+ const t = e.trim();
187
+ if (t.startsWith("//")) return !0;
188
+ const r = t.toLowerCase();
189
+ return /^[a-z][a-z0-9+.-]*:/i.test(t) && !r.startsWith("http://") && !r.startsWith("https://") ? !0 : !r.startsWith("http://") && !r.startsWith("https://") ? !1 : typeof window > "u" || !window.location ? !0 : new URL(t, window.location.href).origin !== window.location.origin;
190
190
  } catch {
191
191
  return !0;
192
192
  }
193
- }, q = (t) => new DOMParser().parseFromString(t, "text/html"), S = (t) => {
194
- const e = (typeof t == "string" ? t : String(t ?? "")).trim(), r = document.createDocumentFragment();
195
- if (e.length === 0) return r;
196
- if (!(e.includes("<") || e.includes(">")))
197
- return r.appendChild(document.createTextNode(e)), r;
198
- const a = q(e).body;
193
+ }, V = (e) => new DOMParser().parseFromString(e, "text/html"), A = (e) => {
194
+ const t = (typeof e == "string" ? e : String(e ?? "")).trim(), r = document.createDocumentFragment();
195
+ if (t.length === 0) return r;
196
+ if (!(t.includes("<") || t.includes(">")))
197
+ return r.appendChild(document.createTextNode(t)), r;
198
+ const a = V(t).body;
199
199
  if (!a) return r;
200
200
  for (; a.firstChild; ) r.appendChild(a.firstChild);
201
201
  return r;
202
- }, f = (t, e = {}) => {
203
- const { allowTags: r = [], allowAttributes: a = [], allowDataAttributes: l = !0, stripAllTags: L = !1 } = e, x = new Set([...D, ...r.map((n) => n.toLowerCase())].filter((n) => !T.has(n))), R = /* @__PURE__ */ new Set([...F, ...a.map((n) => n.toLowerCase())]), c = S(t);
204
- if (L) return c.textContent ?? "";
205
- const h = document.createTreeWalker(c, NodeFilter.SHOW_ELEMENT), p = [];
206
- for (; h.nextNode(); ) {
207
- const n = h.currentNode, i = n.tagName.toLowerCase();
208
- if (T.has(i)) {
202
+ }, f = (e, t = {}) => {
203
+ const { allowTags: r = [], allowAttributes: a = [], allowDataAttributes: l = !0, stripAllTags: x = !1 } = t, H = new Set([...U, ...r.map((n) => n.toLowerCase())].filter((n) => !S.has(n))), _ = /* @__PURE__ */ new Set([...F, ...a.map((n) => n.toLowerCase())]), c = A(e);
204
+ if (x) return c.textContent ?? "";
205
+ const g = document.createTreeWalker(c, NodeFilter.SHOW_ELEMENT), p = [];
206
+ for (; g.nextNode(); ) {
207
+ const n = g.currentNode, i = n.tagName.toLowerCase();
208
+ if (S.has(i)) {
209
209
  p.push(n);
210
210
  continue;
211
211
  }
212
- if (!x.has(i)) {
212
+ if (!H.has(i)) {
213
213
  p.push(n);
214
214
  continue;
215
215
  }
216
216
  const u = [];
217
217
  for (const o of Array.from(n.attributes)) {
218
218
  const s = o.name.toLowerCase();
219
- if (!W(s, R, l)) {
219
+ if (!z(s, _, l)) {
220
220
  u.push(o.name);
221
221
  continue;
222
222
  }
223
- if ((s === "id" || s === "name") && !k(o.value)) {
223
+ if ((s === "id" || s === "name") && !M(o.value)) {
224
224
  u.push(o.name);
225
225
  continue;
226
226
  }
227
- if ((s === "href" || s === "src" || s === "action") && !N(o.value)) {
227
+ if ((s === "href" || s === "src" || s === "action") && !L(o.value)) {
228
228
  u.push(o.name);
229
229
  continue;
230
230
  }
231
- s === "srcset" && !M(o.value) && u.push(o.name);
231
+ s === "srcset" && !q(o.value) && u.push(o.name);
232
232
  }
233
233
  for (const o of u) n.removeAttribute(o);
234
234
  if (i === "a") {
235
- const o = n.getAttribute("href"), s = n.getAttribute("target")?.toLowerCase() === "_blank", _ = o && z(o);
236
- if (s || _) {
237
- const v = n.getAttribute("rel"), m = new Set(v ? v.split(/\s+/).filter(Boolean) : []);
235
+ const o = n.getAttribute("href"), s = n.getAttribute("target")?.toLowerCase() === "_blank", D = o && I(o);
236
+ if (s || D) {
237
+ const y = n.getAttribute("rel"), m = new Set(y ? y.split(/\s+/).filter(Boolean) : []);
238
238
  m.add("noopener"), m.add("noreferrer"), n.setAttribute("rel", Array.from(m).join(" "));
239
239
  }
240
240
  }
241
241
  }
242
242
  for (const n of p) n.remove();
243
- const g = (n) => {
243
+ const w = (n) => {
244
244
  const i = document.createElement("div");
245
245
  return i.appendChild(n.cloneNode(!0)), i.innerHTML;
246
- }, w = g(c), b = g(S(w));
247
- return w !== b ? c.textContent ?? "" : b;
248
- }, A = 1024, E = 8192, G = (t = 16) => {
249
- if (!Number.isInteger(t) || t < 1) throw new RangeError("generateNonce length must be a positive integer");
250
- if (t > A) throw new RangeError(`generateNonce length must not exceed ${A}`);
246
+ }, b = w(c), v = w(A(b));
247
+ return b !== v ? c.textContent ?? "" : v;
248
+ }, R = /* @__PURE__ */ Symbol("bquery.trusted-html.brand"), h = /* @__PURE__ */ Symbol("bquery.trusted-html"), j = (e) => e, B = (e) => {
249
+ const t = String(e);
250
+ return Object.freeze({
251
+ [R]: !0,
252
+ [h]: t,
253
+ toString: () => t
254
+ });
255
+ }, $ = (e) => typeof e == "object" && e !== null && R in e && h in e, X = (e) => e[h], E = 1024, C = 8192, K = (e = 16) => {
256
+ if (!Number.isInteger(e) || e < 1) throw new RangeError("generateNonce length must be a positive integer");
257
+ if (e > E) throw new RangeError(`generateNonce length must not exceed ${E}`);
251
258
  if (typeof globalThis.crypto > "u" || typeof globalThis.crypto.getRandomValues != "function") throw new Error("generateNonce requires crypto.getRandomValues (not available in this environment)");
252
259
  if (typeof globalThis.btoa != "function") throw new Error("generateNonce requires btoa (not available in this environment)");
253
- const e = new Uint8Array(t);
254
- globalThis.crypto.getRandomValues(e);
260
+ const t = new Uint8Array(e);
261
+ globalThis.crypto.getRandomValues(t);
255
262
  let r = "";
256
- for (let a = 0; a < e.length; a += E) {
257
- const l = e.subarray(a, Math.min(a + E, e.length));
263
+ for (let a = 0; a < t.length; a += C) {
264
+ const l = t.subarray(a, Math.min(a + C, t.length));
258
265
  r += String.fromCharCode(...l);
259
266
  }
260
267
  return globalThis.btoa(r).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
261
- }, V = (t) => {
268
+ }, Q = (e) => {
262
269
  if (typeof document > "u") return !1;
263
- const e = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
264
- return e ? (e.getAttribute("content") ?? "").includes(t) : !1;
265
- }, d = null, C = !1, j = () => typeof window < "u" && typeof window.trustedTypes < "u", I = () => {
270
+ const t = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
271
+ return t ? (t.getAttribute("content") ?? "").includes(e) : !1;
272
+ }, d = null, N = !1, Y = () => typeof window < "u" && typeof window.trustedTypes < "u", G = () => {
266
273
  if (d) return d;
267
- if (C || typeof window > "u") return null;
268
- const t = window;
269
- if (!t.trustedTypes) return null;
270
- C = !0;
274
+ if (N || typeof window > "u") return null;
275
+ const e = window;
276
+ if (!e.trustedTypes) return null;
277
+ N = !0;
271
278
  try {
272
- return d = t.trustedTypes.createPolicy(y, { createHTML: (e) => f(e) }), d;
273
- } catch (e) {
274
- const r = e instanceof Error ? e.message : String(e);
275
- return console.warn(`bQuery: Could not create Trusted Types policy "${y}": ${r}`), null;
279
+ return d = e.trustedTypes.createPolicy(T, { createHTML: (t) => f(t) }), d;
280
+ } catch (t) {
281
+ const r = t instanceof Error ? t.message : String(t);
282
+ return console.warn(`bQuery: Could not create Trusted Types policy "${T}": ${r}`), null;
276
283
  }
277
- }, B = (t) => {
278
- const e = I();
279
- return e ? e.createHTML(t) : f(t);
280
- }, $ = (t, e = {}) => f(t, e), X = (t) => {
281
- const e = {
284
+ }, Z = (e) => {
285
+ const t = G();
286
+ return t ? t.createHTML(e) : f(e);
287
+ }, J = (e, t = {}) => j(f(e, t)), ee = (e) => {
288
+ const t = {
282
289
  "&": "&amp;",
283
290
  "<": "&lt;",
284
291
  ">": "&gt;",
@@ -286,17 +293,22 @@ var y = "bquery-sanitizer", D = /* @__PURE__ */ new Set([
286
293
  "'": "&#x27;",
287
294
  "`": "&#x60;"
288
295
  };
289
- return t.replace(/[&<>"'`]/g, (r) => e[r]);
290
- }, K = (t) => f(t, { stripAllTags: !0 });
296
+ return e.replace(/[&<>"'`]/g, (r) => t[r]);
297
+ }, te = (e) => f(e, { stripAllTags: !0 });
291
298
  export {
292
- I as a,
293
- V as c,
294
- B as i,
295
- $ as n,
296
- j as o,
297
- K as r,
298
- G as s,
299
- X as t
299
+ G as a,
300
+ Q as c,
301
+ B as d,
302
+ X as f,
303
+ Z as i,
304
+ $ as l,
305
+ J as n,
306
+ Y as o,
307
+ k as p,
308
+ te as r,
309
+ K as s,
310
+ ee as t,
311
+ j as u
300
312
  };
301
313
 
302
- //# sourceMappingURL=sanitize-jyJ2ryE2.js.map
314
+ //# sourceMappingURL=sanitize-B1V4JswB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-B1V4JswB.js","names":[],"sources":["../src/security/constants.ts","../src/security/sanitize-core.ts","../src/security/trusted-html.ts","../src/security/csp.ts","../src/security/trusted-types.ts","../src/security/sanitize.ts"],"sourcesContent":["/**\n * Security constants and safe lists.\n *\n * @module bquery/security\n */\n\n/**\n * Trusted Types policy name.\n */\nexport const POLICY_NAME = 'bquery-sanitizer';\n\n/**\n * Default allowed HTML tags considered safe.\n */\nexport const DEFAULT_ALLOWED_TAGS = new Set([\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'blockquote',\n 'br',\n 'button',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'data',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'small',\n 'source',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'u',\n 'ul',\n 'var',\n 'wbr',\n]);\n\n/**\n * Explicitly dangerous tags that should never be allowed.\n * These are checked even if somehow added to allowTags.\n */\nexport const DANGEROUS_TAGS = new Set([\n 'script',\n 'iframe',\n 'frame',\n 'frameset',\n 'object',\n 'embed',\n 'applet',\n 'link',\n 'meta',\n 'style',\n 'base',\n 'template',\n // 'slot' is intentionally excluded here so component shadow markup can opt in\n // via sanitizeHtml(..., { allowTags: ['slot'] }). It remains disallowed by default\n // for general HTML writes, because DEFAULT_ALLOWED_TAGS does not include it.\n 'math',\n 'svg',\n 'foreignobject',\n 'noscript',\n]);\n\n/**\n * Reserved IDs that could cause DOM clobbering attacks.\n * These are prevented to avoid overwriting global browser objects.\n */\nexport const RESERVED_IDS = new Set([\n // Global objects\n 'document',\n 'window',\n 'location',\n 'top',\n 'self',\n 'parent',\n 'frames',\n 'history',\n 'navigator',\n 'screen',\n // Dangerous functions\n 'alert',\n 'confirm',\n 'prompt',\n 'eval',\n 'function',\n // Document properties\n 'cookie',\n 'domain',\n 'referrer',\n 'body',\n 'head',\n 'forms',\n 'images',\n 'links',\n 'scripts',\n // DOM traversal properties\n 'children',\n 'parentnode',\n 'firstchild',\n 'lastchild',\n // Content manipulation\n 'innerhtml',\n 'outerhtml',\n 'textcontent',\n]);\n\n/**\n * Default allowed attributes considered safe.\n * Note: 'style' is excluded by default because inline CSS can be abused for:\n * - UI redressing attacks\n * - Data exfiltration via url() in CSS\n * - CSS injection vectors\n * If you need to allow inline styles, add 'style' to allowAttributes in your\n * sanitizeHtml options, but ensure you implement proper CSS value validation.\n */\nexport const DEFAULT_ALLOWED_ATTRIBUTES = new Set([\n 'alt',\n 'class',\n 'dir',\n 'height',\n 'hidden',\n 'href',\n 'id',\n 'lang',\n 'loading',\n 'name',\n 'rel',\n 'role',\n 'src',\n 'srcset',\n 'tabindex',\n 'target',\n 'title',\n 'type',\n 'width',\n 'aria-*',\n]);\n\n/**\n * Dangerous attribute prefixes to always remove.\n */\nexport const DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\n\n/**\n * Dangerous URL protocols to block.\n */\nexport const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\n","/**\n * Core HTML sanitization logic.\n *\n * @module bquery/security\n * @internal\n */\n\nimport {\n DANGEROUS_ATTR_PREFIXES,\n DANGEROUS_PROTOCOLS,\n DANGEROUS_TAGS,\n DEFAULT_ALLOWED_ATTRIBUTES,\n DEFAULT_ALLOWED_TAGS,\n RESERVED_IDS,\n} from './constants';\nimport type { SanitizeOptions } from './types';\n\n/**\n * Check if an attribute name is allowed.\n * @internal\n */\nconst isAllowedAttribute = (\n name: string,\n allowedSet: Set<string>,\n allowDataAttrs: boolean\n): boolean => {\n const lowerName = name.toLowerCase();\n\n // Check dangerous prefixes\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\n if (lowerName.startsWith(prefix)) return false;\n }\n\n // Check data attributes\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\n\n // Check aria attributes (allowed by default)\n if (lowerName.startsWith('aria-')) return true;\n\n // Check explicit allow list\n return allowedSet.has(lowerName);\n};\n\n/**\n * Check if an ID/name value could cause DOM clobbering.\n * @internal\n */\nconst isSafeIdOrName = (value: string): boolean => {\n const lowerValue = value.toLowerCase().trim();\n return !RESERVED_IDS.has(lowerValue);\n};\n\n/**\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\n * Enhanced to prevent various bypass techniques.\n * @internal\n */\nconst normalizeUrl = (value: string): string =>\n value\n // Remove null bytes and control characters\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\n // Remove zero-width characters that could hide malicious content\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\n // Remove escaped Unicode sequences\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\n // Remove whitespace\n .replace(/\\s+/g, '')\n // Normalize case\n .toLowerCase();\n\n/**\n * Check if a URL value is safe.\n * @internal\n */\nconst isSafeUrl = (value: string): boolean => {\n const normalized = normalizeUrl(value);\n for (const protocol of DANGEROUS_PROTOCOLS) {\n if (normalized.startsWith(protocol)) return false;\n }\n return true;\n};\n\n/**\n * Check if a srcset attribute value is safe.\n * srcset contains comma-separated entries of \"url [descriptor]\".\n * Each individual URL must be validated.\n * @internal\n */\nconst isSafeSrcset = (value: string): boolean => {\n const entries = value.split(',');\n for (const entry of entries) {\n const url = entry.trim().split(/\\s+/)[0];\n if (url && !isSafeUrl(url)) return false;\n }\n return true;\n};\n\n/**\n * Check if a URL is external (different origin).\n * @internal\n */\nconst isExternalUrl = (url: string): boolean => {\n try {\n // Normalize URL by trimming whitespace\n const trimmedUrl = url.trim();\n\n // Protocol-relative URLs (//example.com) are always external.\n // CRITICAL: This check must run before the relative-URL check below;\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\n // Handling them up front guarantees correct security classification.\n if (trimmedUrl.startsWith('//')) {\n return true;\n }\n\n // Normalize URL for case-insensitive protocol checks\n const lowerUrl = trimmedUrl.toLowerCase();\n\n // Check for non-http(s) protocols which are considered external/special\n // (mailto:, tel:, ftp:, etc.)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n // These are special protocols, not traditional \"external\" links\n // but we treat them as external for security consistency\n return true;\n }\n\n // Relative URLs are not external\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n return false;\n }\n\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\n if (typeof window === 'undefined' || !window.location) {\n return true;\n }\n\n const urlObj = new URL(trimmedUrl, window.location.href);\n return urlObj.origin !== window.location.origin;\n } catch {\n // If URL parsing fails, treat as potentially external for safety\n return true;\n }\n};\n\n/**\n * Parse an HTML string into a Document using DOMParser.\n * This helper is intentionally separated to make the control-flow around HTML parsing\n * explicit for static analysis tools. It should ONLY be called when the input is\n * known to contain HTML syntax (angle brackets).\n *\n * DOMParser creates an inert document where scripts don't execute, making it safe\n * for parsing untrusted HTML that will subsequently be sanitized.\n *\n * @param htmlContent - A string that is known to contain HTML markup (has < or >)\n * @returns The parsed Document\n * @internal\n */\nconst parseHtmlDocument = (htmlContent: string): Document => {\n const parser = new DOMParser();\n // Parse as a full HTML document in an inert context; scripts won't execute\n return parser.parseFromString(htmlContent, 'text/html');\n};\n\n/**\n * Safely parse HTML string into a DocumentFragment using DOMParser.\n * DOMParser is preferred over innerHTML for security as it creates an inert document\n * where scripts don't execute and provides better static analysis recognition.\n *\n * This function includes input normalization to satisfy static analysis tools:\n * - Coerces input to string and trims whitespace\n * - For plain text (no HTML tags), creates a Text node directly without parsing\n * - Only invokes DOMParser for actual HTML-like content via parseHtmlDocument\n *\n * The separation between plain text handling and HTML parsing is intentional:\n * DOM text that contains no HTML syntax is never fed into an HTML parser,\n * preventing \"DOM text reinterpreted as HTML\" issues.\n *\n * @internal\n */\nconst parseHtmlSafely = (html: string): DocumentFragment => {\n // Step 1: Normalize input - coerce to string and trim\n // This defensive check handles edge cases even though TypeScript says it's a string\n const normalizedHtml = (typeof html === 'string' ? html : String(html ?? '')).trim();\n\n // Step 2: Create the fragment that will hold our result\n const fragment = document.createDocumentFragment();\n\n // Step 3: Early return for empty input\n if (normalizedHtml.length === 0) {\n return fragment;\n }\n\n // Step 4: If input contains no angle brackets, it's plain text - no HTML parsing needed.\n // Plain text is handled as a Text node, never passed to an HTML parser.\n // This explicitly prevents \"DOM text reinterpreted as HTML\" for purely textual inputs.\n const containsHtmlSyntax = normalizedHtml.includes('<') || normalizedHtml.includes('>');\n if (!containsHtmlSyntax) {\n fragment.appendChild(document.createTextNode(normalizedHtml));\n return fragment;\n }\n\n // Step 5: Input contains HTML syntax - parse it via the dedicated HTML parsing helper.\n // This separation makes the data-flow explicit: only strings with HTML syntax\n // are passed to DOMParser, satisfying static analysis requirements.\n const doc = parseHtmlDocument(normalizedHtml);\n\n // Move all children from the document body into the fragment.\n // This avoids interpolating untrusted HTML into an outer wrapper string.\n const body = doc.body;\n\n if (!body) {\n return fragment;\n }\n\n while (body.firstChild) {\n fragment.appendChild(body.firstChild);\n }\n\n return fragment;\n};\n\n/**\n * Core sanitization logic (without Trusted Types wrapper).\n * @internal\n */\nexport const sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\n const {\n allowTags = [],\n allowAttributes = [],\n allowDataAttributes = true,\n stripAllTags = false,\n } = options;\n\n // Build combined allow sets (excluding dangerous tags even if specified)\n const allowedTags = new Set(\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\n (tag) => !DANGEROUS_TAGS.has(tag)\n )\n );\n const allowedAttrs = new Set([\n ...DEFAULT_ALLOWED_ATTRIBUTES,\n ...allowAttributes.map((a) => a.toLowerCase()),\n ]);\n\n // Use DOMParser for safe HTML parsing (inert context, no script execution)\n const fragment = parseHtmlSafely(html);\n\n if (stripAllTags) {\n return fragment.textContent ?? '';\n }\n\n // Walk the DOM tree\n const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT);\n\n const toRemove: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n const tagName = el.tagName.toLowerCase();\n\n // Remove explicitly dangerous tags even if in allow list\n if (DANGEROUS_TAGS.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Remove disallowed tags entirely\n if (!allowedTags.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Process attributes\n const attrsToRemove: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n const attrName = attr.name.toLowerCase();\n\n // Check if attribute is allowed\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Check for DOM clobbering on id and name attributes\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate URL attributes\n if (\n (attrName === 'href' || attrName === 'src' || attrName === 'action') &&\n !isSafeUrl(attr.value)\n ) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate srcset URLs individually\n if (attrName === 'srcset' && !isSafeSrcset(attr.value)) {\n attrsToRemove.push(attr.name);\n }\n }\n\n // Remove disallowed attributes\n for (const attrName of attrsToRemove) {\n el.removeAttribute(attrName);\n }\n\n // Add rel=\"noopener noreferrer\" to external links for security\n if (tagName === 'a') {\n const href = el.getAttribute('href');\n const target = el.getAttribute('target');\n const hasTargetBlank = target?.toLowerCase() === '_blank';\n const isExternal = href && isExternalUrl(href);\n\n // Add security attributes to links opening in new window or external links\n if (hasTargetBlank || isExternal) {\n const existingRel = el.getAttribute('rel');\n const relValues = new Set(existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []);\n\n // Add noopener and noreferrer\n relValues.add('noopener');\n relValues.add('noreferrer');\n\n el.setAttribute('rel', Array.from(relValues).join(' '));\n }\n }\n }\n\n // Remove disallowed elements\n for (const el of toRemove) {\n el.remove();\n }\n\n // Serialize the sanitized fragment to HTML string.\n // We use a temporary container to get the innerHTML of the fragment.\n const serializeFragment = (frag: DocumentFragment): string => {\n const container = document.createElement('div');\n container.appendChild(frag.cloneNode(true));\n return container.innerHTML;\n };\n\n // Double-parse to prevent mutation XSS (mXSS).\n // Browsers may normalize HTML during serialization in ways that could create\n // new dangerous content when re-parsed. By re-parsing the sanitized output\n // and verifying stability, we ensure the final HTML is safe.\n const firstPass = serializeFragment(fragment);\n\n // Re-parse through DOMParser for mXSS detection.\n // Using DOMParser instead of innerHTML for security.\n const verifyFragment = parseHtmlSafely(firstPass);\n const secondPass = serializeFragment(verifyFragment);\n\n // Verify stability: if content mutates between parses, it indicates mXSS attempt\n if (firstPass !== secondPass) {\n // Content mutated during re-parse - potential mXSS detected.\n // Return safely escaped text content as fallback.\n return fragment.textContent ?? '';\n }\n\n return secondPass;\n};\n","declare const sanitizedHtmlBrand: unique symbol;\nconst trustedHtmlBrand: unique symbol = Symbol('bquery.trusted-html.brand');\nconst TRUSTED_HTML_VALUE = Symbol('bquery.trusted-html');\n\n/**\n * Branded HTML string produced by bQuery's sanitization or escaping template helpers.\n *\n * Values returned from {@link sanitizeHtml} carry sanitized markup. Values returned from\n * {@link safeHtml} preserve the template's static markup while escaping normal interpolations\n * and splicing {@link trusted} fragments verbatim. This brand is not intended for arbitrary\n * strings or manual concatenation outside those helpers.\n */\nexport type SanitizedHtml = string & { readonly [sanitizedHtmlBrand]: true };\n\n/**\n * Marker object that safeHtml can splice into templates without escaping again.\n */\nexport type TrustedHtml = { readonly [trustedHtmlBrand]: true; toString(): string };\n\ntype TrustedHtmlValue = TrustedHtml & { readonly [TRUSTED_HTML_VALUE]: string };\n\n/**\n * Apply the internal {@link SanitizedHtml} brand to helper output.\n *\n * @internal\n */\nexport const toSanitizedHtml = (html: string): SanitizedHtml => html as SanitizedHtml;\n\n/**\n * Mark a sanitized HTML string for verbatim splicing into safeHtml templates.\n *\n * @param html - HTML previously produced by sanitizeHtml, safeHtml, or another trusted bQuery helper\n * @returns Trusted HTML marker object for safeHtml interpolations\n *\n * @example\n * ```ts\n * const badge = trusted(sanitizeHtml('<strong onclick=\"alert(1)\">New</strong>'));\n * const markup = safeHtml`<span>${badge}</span>`;\n * ```\n */\nexport const trusted = (html: SanitizedHtml): TrustedHtml => {\n const value = String(html);\n return Object.freeze({\n [trustedHtmlBrand]: true as const,\n [TRUSTED_HTML_VALUE]: value,\n toString: () => value,\n });\n};\n\n/**\n * Check whether a value is a trusted HTML marker created by trusted().\n *\n * @internal\n */\nexport const isTrustedHtml = (value: unknown): value is TrustedHtml => {\n return (\n typeof value === 'object' &&\n value !== null &&\n trustedHtmlBrand in value &&\n TRUSTED_HTML_VALUE in value\n );\n};\n\n/**\n * Unwrap the raw HTML string stored inside a trusted HTML marker.\n *\n * @internal\n */\nexport const unwrapTrustedHtml = (value: TrustedHtml): string => {\n return (value as TrustedHtmlValue)[TRUSTED_HTML_VALUE];\n};\n","/**\n * Content Security Policy helpers.\n *\n * @module bquery/security\n */\n\n/** Maximum allowed nonce length to prevent memory issues */\nconst MAX_NONCE_LENGTH = 1024;\n\n/** Chunk size for building strings to avoid argument limit in String.fromCharCode */\nconst CHUNK_SIZE = 8192;\n\n/**\n * Generate a nonce for inline scripts/styles.\n * Use with Content-Security-Policy nonce directives.\n *\n * @param length - Nonce length in bytes (default: 16, max: 1024)\n * @returns Cryptographically random nonce string\n * @throws {Error} If crypto.getRandomValues or btoa are not available\n * @throws {RangeError} If length is invalid (negative, non-integer, or exceeds maximum)\n */\nexport const generateNonce = (length: number = 16): string => {\n // Validate length parameter\n if (!Number.isInteger(length) || length < 1) {\n throw new RangeError('generateNonce length must be a positive integer');\n }\n if (length > MAX_NONCE_LENGTH) {\n throw new RangeError(`generateNonce length must not exceed ${MAX_NONCE_LENGTH}`);\n }\n\n // Check for required globals in browser/crypto environments\n if (\n typeof globalThis.crypto === 'undefined' ||\n typeof globalThis.crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'generateNonce requires crypto.getRandomValues (not available in this environment)'\n );\n }\n if (typeof globalThis.btoa !== 'function') {\n throw new Error('generateNonce requires btoa (not available in this environment)');\n }\n\n const array = new Uint8Array(length);\n globalThis.crypto.getRandomValues(array);\n\n // Build string in chunks to avoid argument limit in String.fromCharCode\n let binaryString = '';\n for (let i = 0; i < array.length; i += CHUNK_SIZE) {\n const chunk = array.subarray(i, Math.min(i + CHUNK_SIZE, array.length));\n binaryString += String.fromCharCode(...chunk);\n }\n\n return globalThis.btoa(binaryString).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\n/**\n * Check if a CSP header is present with specific directive.\n * Useful for feature detection and fallback strategies.\n *\n * @param directive - The CSP directive to check (e.g., 'script-src')\n * @returns True if the directive appears to be enforced\n */\nexport const hasCSPDirective = (directive: string): boolean => {\n // Guard for non-DOM environments (SSR, tests, etc.)\n if (typeof document === 'undefined') {\n return false;\n }\n\n // Check meta tag\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\n if (meta) {\n const content = meta.getAttribute('content') ?? '';\n return content.includes(directive);\n }\n return false;\n};\n","/**\n * Trusted Types helpers for CSP compatibility.\n *\n * @module bquery/security\n */\n\nimport { POLICY_NAME } from './constants';\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport type { TrustedHTML, TrustedTypePolicy, TrustedTypesWindow } from './types';\n\n/** Cached Trusted Types policy */\nlet cachedPolicy: TrustedTypePolicy | null = null;\n\n/** Whether policy initialization has been attempted (to avoid retry spam) */\nlet policyInitAttempted = false;\n\n/**\n * Check if Trusted Types API is available.\n * @returns True if Trusted Types are supported\n */\nexport const isTrustedTypesSupported = (): boolean => {\n return (\n typeof window !== 'undefined' &&\n typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined'\n );\n};\n\n/**\n * Get or create the bQuery Trusted Types policy.\n * @returns The Trusted Types policy or null if unsupported\n */\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\n if (cachedPolicy) return cachedPolicy;\n if (policyInitAttempted) return null;\n\n if (typeof window === 'undefined') return null;\n\n const win = window as TrustedTypesWindow;\n if (!win.trustedTypes) return null;\n\n policyInitAttempted = true;\n\n try {\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\n createHTML: (input: string) => sanitizeHtmlCore(input),\n });\n return cachedPolicy;\n } catch (error) {\n // Policy may already exist or be blocked by CSP\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\": ${errorMessage}`);\n return null;\n }\n};\n\n/**\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\n * Falls back to regular string when Trusted Types are unavailable.\n *\n * @param html - The HTML string to wrap\n * @returns Trusted HTML value or sanitized string\n */\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\n const policy = getTrustedTypesPolicy();\n if (policy) {\n return policy.createHTML(html);\n }\n return sanitizeHtmlCore(html);\n};\n","/**\n * Security utilities for HTML sanitization.\n * All DOM writes are sanitized by default to prevent XSS attacks.\n *\n * @module bquery/security\n */\n\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport { toSanitizedHtml } from './trusted-html';\nimport type { SanitizedHtml } from './trusted-html';\nimport type { SanitizeOptions } from './types';\nexport { generateNonce } from './csp';\nexport { isTrustedTypesSupported } from './trusted-types';\nexport { trusted } from './trusted-html';\nexport type { SanitizedHtml, TrustedHtml } from './trusted-html';\n\n/**\n * Sanitize HTML string, removing dangerous elements and attributes.\n * Uses Trusted Types when available for CSP compliance.\n *\n * @param html - The HTML string to sanitize\n * @param options - Sanitization options\n * @returns Sanitized HTML string\n *\n * @example\n * ```ts\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\n * // Returns: '<div>Hello</div>'\n * ```\n */\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): SanitizedHtml => {\n return toSanitizedHtml(sanitizeHtmlCore(html, options));\n};\n\n/**\n * Escape HTML entities to prevent XSS.\n * Use this for displaying user content as text.\n *\n * @param text - The text to escape\n * @returns Escaped HTML string\n *\n * @example\n * ```ts\n * escapeHtml('<script>alert(1)</script>');\n * // Returns: '&lt;script&gt;alert(1)&lt;/script&gt;'\n * ```\n */\nexport const escapeHtml = (text: string): string => {\n const escapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '`': '&#x60;',\n };\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\n};\n\n/**\n * Strip all HTML tags and return plain text.\n *\n * @param html - The HTML string to strip\n * @returns Plain text content\n */\nexport const stripTags = (html: string): string => {\n return sanitizeHtmlCore(html, { stripAllTags: true });\n};\n\nexport type { SanitizeOptions } from './types';\n"],"mappings":"AASA,IAAa,IAAc,oBAKd,IAAuB,oBAAI,IAAI;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;CACD,GAMY,IAAiB,oBAAI,IAAI;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,EACA;CACD,GAMY,IAAe,oBAAI,IAAI;AAAA,EAElC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,E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"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  export { generateNonce, hasCSPDirective } from './csp';
7
7
  export { escapeHtml, sanitizeHtml as sanitize, sanitizeHtml, stripTags } from './sanitize';
8
+ export { trusted } from './trusted-html';
8
9
  export { createTrustedHtml, getTrustedTypesPolicy, isTrustedTypesSupported } from './trusted-types';
10
+ export type { SanitizedHtml, TrustedHtml } from './trusted-html';
9
11
  export type { SanitizeOptions } from './types';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,YAAY,IAAI,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACpG,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,YAAY,IAAI,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACpG,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
@@ -4,9 +4,12 @@
4
4
  *
5
5
  * @module bquery/security
6
6
  */
7
+ import type { SanitizedHtml } from './trusted-html';
7
8
  import type { SanitizeOptions } from './types';
8
9
  export { generateNonce } from './csp';
9
10
  export { isTrustedTypesSupported } from './trusted-types';
11
+ export { trusted } from './trusted-html';
12
+ export type { SanitizedHtml, TrustedHtml } from './trusted-html';
10
13
  /**
11
14
  * Sanitize HTML string, removing dangerous elements and attributes.
12
15
  * Uses Trusted Types when available for CSP compliance.
@@ -21,7 +24,7 @@ export { isTrustedTypesSupported } from './trusted-types';
21
24
  * // Returns: '<div>Hello</div>'
22
25
  * ```
23
26
  */
24
- export declare const sanitizeHtml: (html: string, options?: SanitizeOptions) => string;
27
+ export declare const sanitizeHtml: (html: string, options?: SanitizeOptions) => SanitizedHtml;
25
28
  /**
26
29
  * Escape HTML entities to prevent XSS.
27
30
  * Use this for displaying user content as text.
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,UAAS,eAAoB,KAAG,MAE1E,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MAUzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAExC,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEjE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,UAAS,eAAoB,KAAG,aAE1E,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MAUzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAExC,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}