@bquery/bquery 1.6.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -18
- package/dist/a11y/announce.d.ts +43 -0
- package/dist/a11y/announce.d.ts.map +1 -0
- package/dist/a11y/audit.d.ts +42 -0
- package/dist/a11y/audit.d.ts.map +1 -0
- package/dist/a11y/index.d.ts +53 -0
- package/dist/a11y/index.d.ts.map +1 -0
- package/dist/a11y/media-preferences.d.ts +77 -0
- package/dist/a11y/media-preferences.d.ts.map +1 -0
- package/dist/a11y/roving-tab-index.d.ts +38 -0
- package/dist/a11y/roving-tab-index.d.ts.map +1 -0
- package/dist/a11y/skip-link.d.ts +37 -0
- package/dist/a11y/skip-link.d.ts.map +1 -0
- package/dist/a11y/trap-focus.d.ts +49 -0
- package/dist/a11y/trap-focus.d.ts.map +1 -0
- package/dist/a11y/types.d.ts +152 -0
- package/dist/a11y/types.d.ts.map +1 -0
- package/dist/a11y-DVBCy09c.js +421 -0
- package/dist/a11y-DVBCy09c.js.map +1 -0
- package/dist/a11y.es.mjs +14 -0
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/html.d.ts.map +1 -1
- package/dist/component/index.d.ts +2 -1
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/library.d.ts.map +1 -1
- package/dist/component/scope.d.ts +138 -0
- package/dist/component/scope.d.ts.map +1 -0
- package/dist/component/types.d.ts +53 -1
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-L3-JfOFz.js +684 -0
- package/dist/component-L3-JfOFz.js.map +1 -0
- package/dist/component.es.mjs +9 -6
- package/dist/{config-DRmZZno3.js → config-DhT9auRm.js} +4 -4
- package/dist/{config-DRmZZno3.js.map → config-DhT9auRm.js.map} +1 -1
- package/dist/constraints-D5RHQLmP.js +100 -0
- package/dist/constraints-D5RHQLmP.js.map +1 -0
- package/dist/core/collection.d.ts +134 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +120 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/env.d.ts +18 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/shared.d.ts +14 -0
- package/dist/core/shared.d.ts.map +1 -1
- package/dist/core/utils/index.d.ts +52 -41
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core-DdtZHzsS.js +168 -0
- package/dist/core-DdtZHzsS.js.map +1 -0
- package/dist/{core-CCEabVHl.js → core-EMYSLzaT.js} +293 -194
- package/dist/core-EMYSLzaT.js.map +1 -0
- package/dist/core.es.mjs +48 -46
- package/dist/custom-directives-Dr4C5lVV.js +9 -0
- package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
- package/dist/devtools/devtools.d.ts +212 -0
- package/dist/devtools/devtools.d.ts.map +1 -0
- package/dist/devtools/index.d.ts +20 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/types.d.ts +69 -0
- package/dist/devtools/types.d.ts.map +1 -0
- package/dist/devtools-BhB2iDPT.js +122 -0
- package/dist/devtools-BhB2iDPT.js.map +1 -0
- package/dist/devtools.es.mjs +19 -0
- package/dist/dnd/draggable.d.ts +51 -0
- package/dist/dnd/draggable.d.ts.map +1 -0
- package/dist/dnd/droppable.d.ts +38 -0
- package/dist/dnd/droppable.d.ts.map +1 -0
- package/dist/dnd/index.d.ts +47 -0
- package/dist/dnd/index.d.ts.map +1 -0
- package/dist/dnd/sortable.d.ts +43 -0
- package/dist/dnd/sortable.d.ts.map +1 -0
- package/dist/dnd/types.d.ts +250 -0
- package/dist/dnd/types.d.ts.map +1 -0
- package/dist/dnd-NwZBYh4l.js +244 -0
- package/dist/dnd-NwZBYh4l.js.map +1 -0
- package/dist/dnd.es.mjs +6 -0
- package/dist/env-CTdvLaH2.js +19 -0
- package/dist/env-CTdvLaH2.js.map +1 -0
- package/dist/forms/create-form.d.ts +49 -0
- package/dist/forms/create-form.d.ts.map +1 -0
- package/dist/forms/index.d.ts +40 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +185 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/use-field.d.ts +34 -0
- package/dist/forms/use-field.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +204 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms-UcRHsYxC.js +227 -0
- package/dist/forms-UcRHsYxC.js.map +1 -0
- package/dist/forms.es.mjs +16 -0
- package/dist/full.d.ts +30 -11
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +209 -93
- package/dist/full.iife.js +47 -31
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +47 -31
- package/dist/full.umd.js.map +1 -1
- package/dist/function-Cybd57JV.js +33 -0
- package/dist/function-Cybd57JV.js.map +1 -0
- package/dist/i18n/formatting.d.ts +40 -0
- package/dist/i18n/formatting.d.ts.map +1 -0
- package/dist/i18n/i18n.d.ts +48 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +57 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/translate.d.ts +83 -0
- package/dist/i18n/translate.d.ts.map +1 -0
- package/dist/i18n/types.d.ts +156 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n-kuF6Ekj6.js +89 -0
- package/dist/i18n-kuF6Ekj6.js.map +1 -0
- package/dist/i18n.es.mjs +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +257 -143
- package/dist/media/battery.d.ts +35 -0
- package/dist/media/battery.d.ts.map +1 -0
- package/dist/media/breakpoints.d.ts +51 -0
- package/dist/media/breakpoints.d.ts.map +1 -0
- package/dist/media/clipboard.d.ts +30 -0
- package/dist/media/clipboard.d.ts.map +1 -0
- package/dist/media/device-sensors.d.ts +54 -0
- package/dist/media/device-sensors.d.ts.map +1 -0
- package/dist/media/geolocation.d.ts +38 -0
- package/dist/media/geolocation.d.ts.map +1 -0
- package/dist/media/index.d.ts +42 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/media-query.d.ts +36 -0
- package/dist/media/media-query.d.ts.map +1 -0
- package/dist/media/network.d.ts +35 -0
- package/dist/media/network.d.ts.map +1 -0
- package/dist/media/types.d.ts +173 -0
- package/dist/media/types.d.ts.map +1 -0
- package/dist/media/viewport.d.ts +32 -0
- package/dist/media/viewport.d.ts.map +1 -0
- package/dist/media-i-fB5WxI.js +340 -0
- package/dist/media-i-fB5WxI.js.map +1 -0
- package/dist/media.es.mjs +12 -0
- package/dist/motion/index.d.ts +7 -3
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/morph.d.ts +27 -0
- package/dist/motion/morph.d.ts.map +1 -0
- package/dist/motion/parallax.d.ts +30 -0
- package/dist/motion/parallax.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +36 -3
- package/dist/motion/reduced-motion.d.ts.map +1 -1
- package/dist/motion/types.d.ts +58 -0
- package/dist/motion/types.d.ts.map +1 -1
- package/dist/motion/typewriter.d.ts +31 -0
- package/dist/motion/typewriter.d.ts.map +1 -0
- package/dist/motion-BJsAuULb.js +530 -0
- package/dist/motion-BJsAuULb.js.map +1 -0
- package/dist/motion.es.mjs +27 -23
- package/dist/{view-C70lA3vf.js → mount-B4Y8bk8Z.js} +166 -160
- package/dist/mount-B4Y8bk8Z.js.map +1 -0
- package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
- package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
- package/dist/{platform-Dr9b6fsq.js → platform-Dw2gE3zI.js} +21 -22
- package/dist/{platform-Dr9b6fsq.js.map → platform-Dw2gE3zI.js.map} +1 -1
- package/dist/platform.es.mjs +2 -2
- package/dist/plugin/index.d.ts +22 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/registry.d.ts +108 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/types.d.ts +110 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin-C2WuC8SF.js +66 -0
- package/dist/plugin-C2WuC8SF.js.map +1 -0
- package/dist/plugin.es.mjs +9 -0
- package/dist/reactive/async-data.d.ts +28 -3
- package/dist/reactive/async-data.d.ts.map +1 -1
- package/dist/reactive/computed.d.ts +10 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive/effect.d.ts +3 -0
- package/dist/reactive/effect.d.ts.map +1 -1
- package/dist/reactive/http.d.ts +194 -0
- package/dist/reactive/http.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/pagination.d.ts +126 -0
- package/dist/reactive/pagination.d.ts.map +1 -0
- package/dist/reactive/polling.d.ts +55 -0
- package/dist/reactive/polling.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +20 -1
- package/dist/reactive/readonly.d.ts.map +1 -1
- package/dist/reactive/rest.d.ts +293 -0
- package/dist/reactive/rest.d.ts.map +1 -0
- package/dist/reactive/scope.d.ts +140 -0
- package/dist/reactive/scope.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +16 -2
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/to-value.d.ts +57 -0
- package/dist/reactive/to-value.d.ts.map +1 -0
- package/dist/reactive/websocket.d.ts +285 -0
- package/dist/reactive/websocket.d.ts.map +1 -0
- package/dist/reactive-DwkhUJfP.js +1148 -0
- package/dist/reactive-DwkhUJfP.js.map +1 -0
- package/dist/reactive.es.mjs +38 -20
- package/dist/registry-B08iilIh.js +26 -0
- package/dist/registry-B08iilIh.js.map +1 -0
- package/dist/router/bq-link.d.ts +112 -0
- package/dist/router/bq-link.d.ts.map +1 -0
- package/dist/router/constraints.d.ts +9 -0
- package/dist/router/constraints.d.ts.map +1 -0
- package/dist/router/index.d.ts +15 -7
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/match.d.ts +0 -1
- package/dist/router/match.d.ts.map +1 -1
- package/dist/router/path-pattern.d.ts +14 -0
- package/dist/router/path-pattern.d.ts.map +1 -0
- package/dist/router/query.d.ts.map +1 -1
- package/dist/router/router.d.ts +3 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/state.d.ts +25 -2
- package/dist/router/state.d.ts.map +1 -1
- package/dist/router/types.d.ts +48 -4
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/use-route.d.ts +50 -0
- package/dist/router/use-route.d.ts.map +1 -0
- package/dist/router/utils.d.ts +3 -0
- package/dist/router/utils.d.ts.map +1 -1
- package/dist/router-CQikC9Ed.js +492 -0
- package/dist/router-CQikC9Ed.js.map +1 -0
- package/dist/router.es.mjs +14 -10
- package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
- package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
- package/dist/security/index.d.ts +2 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security.es.mjs +1 -1
- package/dist/ssr/hydrate.d.ts +65 -0
- package/dist/ssr/hydrate.d.ts.map +1 -0
- package/dist/ssr/index.d.ts +59 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/render.d.ts +62 -0
- package/dist/ssr/render.d.ts.map +1 -0
- package/dist/ssr/serialize.d.ts +118 -0
- package/dist/ssr/serialize.d.ts.map +1 -0
- package/dist/ssr/types.d.ts +70 -0
- package/dist/ssr/types.d.ts.map +1 -0
- package/dist/ssr-_dAcGdzu.js +248 -0
- package/dist/ssr-_dAcGdzu.js.map +1 -0
- package/dist/ssr.es.mjs +9 -0
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/index.d.ts +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/persisted.d.ts +38 -4
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/store/types.d.ts +138 -1
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/utils.d.ts +2 -2
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store-Cb3gPRve.js +338 -0
- package/dist/store-Cb3gPRve.js.map +1 -0
- package/dist/store.es.mjs +11 -10
- package/dist/storybook/index.d.ts.map +1 -1
- package/dist/storybook.es.mjs +1 -1
- package/dist/storybook.es.mjs.map +1 -1
- package/dist/testing/index.d.ts +23 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/testing.d.ts +156 -0
- package/dist/testing/testing.d.ts.map +1 -0
- package/dist/testing/types.d.ts +134 -0
- package/dist/testing/types.d.ts.map +1 -0
- package/dist/testing-C5Sjfsna.js +224 -0
- package/dist/testing-C5Sjfsna.js.map +1 -0
- package/dist/testing.es.mjs +9 -0
- package/dist/type-guards-BMX2c0LP.js +44 -0
- package/dist/type-guards-BMX2c0LP.js.map +1 -0
- package/dist/untrack-D0fnO5k2.js +36 -0
- package/dist/untrack-D0fnO5k2.js.map +1 -0
- package/dist/view/custom-directives.d.ts +20 -0
- package/dist/view/custom-directives.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts.map +1 -1
- package/dist/view/process.d.ts.map +1 -1
- package/dist/view.es.mjs +9 -9
- package/package.json +47 -11
- package/src/a11y/announce.ts +131 -0
- package/src/a11y/audit.ts +314 -0
- package/src/a11y/index.ts +68 -0
- package/src/a11y/media-preferences.ts +255 -0
- package/src/a11y/roving-tab-index.ts +164 -0
- package/src/a11y/skip-link.ts +255 -0
- package/src/a11y/trap-focus.ts +184 -0
- package/src/a11y/types.ts +183 -0
- package/src/component/component.ts +599 -524
- package/src/component/html.ts +153 -153
- package/src/component/index.ts +52 -50
- package/src/component/library.ts +540 -518
- package/src/component/scope.ts +212 -0
- package/src/component/types.ts +310 -256
- package/src/core/collection.ts +249 -1
- package/src/core/element.ts +252 -11
- package/src/core/env.ts +60 -0
- package/src/core/index.ts +1 -0
- package/src/core/shared.ts +64 -0
- package/src/core/utils/index.ts +66 -1
- package/src/devtools/devtools.ts +410 -0
- package/src/devtools/index.ts +48 -0
- package/src/devtools/types.ts +104 -0
- package/src/dnd/draggable.ts +296 -0
- package/src/dnd/droppable.ts +228 -0
- package/src/dnd/index.ts +62 -0
- package/src/dnd/sortable.ts +307 -0
- package/src/dnd/types.ts +293 -0
- package/src/forms/create-form.ts +320 -0
- package/src/forms/index.ts +70 -0
- package/src/forms/types.ts +203 -0
- package/src/forms/use-field.ts +231 -0
- package/src/forms/validators.ts +294 -0
- package/src/full.ts +554 -229
- package/src/i18n/formatting.ts +67 -0
- package/src/i18n/i18n.ts +200 -0
- package/src/i18n/index.ts +67 -0
- package/src/i18n/translate.ts +182 -0
- package/src/i18n/types.ts +171 -0
- package/src/index.ts +72 -0
- package/src/media/battery.ts +116 -0
- package/src/media/breakpoints.ts +129 -0
- package/src/media/clipboard.ts +80 -0
- package/src/media/device-sensors.ts +158 -0
- package/src/media/geolocation.ts +119 -0
- package/src/media/index.ts +76 -0
- package/src/media/media-query.ts +92 -0
- package/src/media/network.ts +115 -0
- package/src/media/types.ts +177 -0
- package/src/media/viewport.ts +84 -0
- package/src/motion/index.ts +11 -2
- package/src/motion/morph.ts +151 -0
- package/src/motion/parallax.ts +120 -0
- package/src/motion/reduced-motion.ts +52 -3
- package/src/motion/types.ts +63 -0
- package/src/motion/typewriter.ts +164 -0
- package/src/plugin/index.ts +37 -0
- package/src/plugin/registry.ts +284 -0
- package/src/plugin/types.ts +137 -0
- package/src/reactive/async-data.ts +250 -29
- package/src/reactive/computed.ts +53 -1
- package/src/reactive/effect.ts +29 -6
- package/src/reactive/http.ts +790 -0
- package/src/reactive/index.ts +60 -0
- package/src/reactive/pagination.ts +317 -0
- package/src/reactive/polling.ts +179 -0
- package/src/reactive/readonly.ts +52 -8
- package/src/reactive/rest.ts +859 -0
- package/src/reactive/scope.ts +276 -0
- package/src/reactive/signal.ts +61 -1
- package/src/reactive/to-value.ts +71 -0
- package/src/reactive/websocket.ts +849 -0
- package/src/router/bq-link.ts +279 -0
- package/src/router/constraints.ts +204 -0
- package/src/router/index.ts +15 -7
- package/src/router/match.ts +255 -49
- package/src/router/path-pattern.ts +52 -0
- package/src/router/query.ts +3 -0
- package/src/router/router.ts +258 -48
- package/src/router/state.ts +51 -3
- package/src/router/types.ts +50 -4
- package/src/router/use-route.ts +68 -0
- package/src/router/utils.ts +44 -3
- package/src/security/index.ts +12 -17
- package/src/security/sanitize.ts +70 -70
- package/src/security/trusted-html.ts +71 -71
- package/src/ssr/hydrate.ts +84 -0
- package/src/ssr/index.ts +70 -0
- package/src/ssr/render.ts +508 -0
- package/src/ssr/serialize.ts +296 -0
- package/src/ssr/types.ts +81 -0
- package/src/store/create-store.ts +146 -8
- package/src/store/define-store.ts +49 -49
- package/src/store/index.ts +5 -0
- package/src/store/mapping.ts +74 -74
- package/src/store/persisted.ts +245 -62
- package/src/store/types.ts +247 -92
- package/src/store/utils.ts +4 -10
- package/src/store/watch.ts +53 -53
- package/src/storybook/index.ts +480 -479
- package/src/testing/index.ts +42 -0
- package/src/testing/testing.ts +593 -0
- package/src/testing/types.ts +170 -0
- package/src/view/custom-directives.ts +28 -0
- package/src/view/evaluate.ts +2 -0
- package/src/view/process.ts +19 -3
- package/dist/component-BEQgt5hl.js +0 -600
- package/dist/component-BEQgt5hl.js.map +0 -1
- package/dist/core-BGQJVw0-.js +0 -35
- package/dist/core-BGQJVw0-.js.map +0 -1
- package/dist/core-CCEabVHl.js.map +0 -1
- package/dist/effect-AFRW_Plg.js +0 -84
- package/dist/effect-AFRW_Plg.js.map +0 -1
- package/dist/motion-D9TcHxOF.js +0 -415
- package/dist/motion-D9TcHxOF.js.map +0 -1
- package/dist/reactive-DSkct0dO.js +0 -254
- package/dist/reactive-DSkct0dO.js.map +0 -1
- package/dist/router-CbDhl8rS.js +0 -188
- package/dist/router-CbDhl8rS.js.map +0 -1
- package/dist/store-BwDvI45q.js +0 -263
- package/dist/store-BwDvI45q.js.map +0 -1
- package/dist/untrack-B0rVscTc.js +0 -7
- package/dist/untrack-B0rVscTc.js.map +0 -1
- package/dist/view-C70lA3vf.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive-DwkhUJfP.js","names":[],"sources":["../src/reactive/batch.ts","../src/reactive/async-data.ts","../src/reactive/http.ts","../src/reactive/linked.ts","../src/reactive/pagination.ts","../src/reactive/persisted.ts","../src/reactive/polling.ts","../src/reactive/readonly.ts","../src/reactive/rest.ts","../src/reactive/type-guards.ts","../src/reactive/to-value.ts","../src/reactive/watch.ts","../src/reactive/websocket.ts"],"sourcesContent":["/**\n * Batched reactive updates.\n */\n\nimport { beginBatch, endBatch } from './internals';\n\n/**\n * Batches multiple signal updates into a single notification cycle.\n *\n * Updates made inside the batch function are deferred until the batch\n * completes, preventing intermediate re-renders and improving performance.\n *\n * @param fn - Function containing multiple signal updates\n */\nexport const batch = (fn: () => void): void => {\n beginBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n};\n","/**\n * Async data and fetch composables built on bQuery signals.\n *\n * @module bquery/reactive\n */\n\nimport { merge } from '../core/utils/object';\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\nimport { computed } from './computed';\nimport { effect } from './effect';\nimport { Signal, signal } from './core';\nimport { untrack } from './untrack';\n\n/** Allowed status values for async composables. */\nexport type AsyncDataStatus = 'idle' | 'pending' | 'success' | 'error';\n\n/** Reactive source types that can trigger refreshes. */\nexport type AsyncWatchSource = (() => unknown) | { value: unknown };\n\n/** Options shared by async composables. */\nexport interface UseAsyncDataOptions<TResult, TData = TResult> {\n /** Run the handler immediately (default: true). */\n immediate?: boolean;\n /** Default data value before the first successful execution. */\n defaultValue?: TData;\n /** Optional reactive sources that trigger refreshes when they change. */\n watch?: AsyncWatchSource[];\n /** Transform the resolved value before storing it. */\n transform?: (value: TResult) => TData;\n /** Called after a successful execution. */\n onSuccess?: (value: TData) => void;\n /** Called after a failed execution. */\n onError?: (error: Error) => void;\n}\n\n/** Return value of useAsyncData() and useFetch(). */\nexport interface AsyncDataState<TData> {\n /** Reactive data signal. */\n data: Signal<TData | undefined>;\n /** Last error encountered by the composable. */\n error: Signal<Error | null>;\n /** Current lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Computed boolean that mirrors `status === 'pending'`. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Execute the handler manually. Returns the cached data value when called after dispose(). */\n execute: () => Promise<TData | undefined>;\n /** Alias for execute(). */\n refresh: () => Promise<TData | undefined>;\n /** Abort the current in-flight request (useFetch only; no-op for useAsyncData). */\n abort: () => void;\n /** Clear data, error, and status back to the initial state. */\n clear: () => void;\n /** Dispose reactive watchers and prevent future executions. */\n dispose: () => void;\n}\n\n/** Configuration for automatic request retries in useFetch(). */\nexport interface UseFetchRetryConfig {\n /** Maximum number of retry attempts (default: 3). */\n count: number;\n /** Delay in ms between retries, or a function receiving the attempt index. */\n delay?: number | ((attempt: number) => number);\n /** Predicate deciding whether to retry. Defaults to network / 5xx errors. */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Options for useFetch(). */\nexport interface UseFetchOptions<TResponse = unknown, TData = TResponse>\n extends UseAsyncDataOptions<TResponse, TData>, Omit<RequestInit, 'body' | 'headers' | 'signal'> {\n /** Base URL prepended to relative URLs. */\n baseUrl?: string;\n /** Query parameters appended to the request URL. */\n query?: Record<string, unknown>;\n /** Request headers. */\n headers?: HeadersInit;\n /** Request body, including plain objects for JSON requests. */\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\n /** Override the parser used for the response body. */\n parseAs?: BqueryFetchParseAs;\n /** Custom fetch implementation for testing or adapters. */\n fetcher?: typeof fetch;\n /** Request timeout in milliseconds. 0 means no timeout. */\n timeout?: number;\n /** External AbortSignal for request cancellation. */\n signal?: AbortSignal;\n /** Retry configuration. Pass a number for simple retry count, or a config object. */\n retry?: number | UseFetchRetryConfig;\n /** Custom status validation. Returns `true` for acceptable statuses. */\n validateStatus?: (status: number) => boolean;\n}\n\n/** Input accepted by useFetch(). */\nexport type FetchInput = string | URL | Request | (() => string | URL | Request);\n\nconst normalizeError = (error: unknown): Error => {\n if (error instanceof Error) return error;\n if (typeof error === 'string') {\n return new Error(error);\n }\n\n try {\n return new Error(JSON.stringify(error));\n } catch {\n return new Error(String(error));\n }\n};\n\nconst readWatchSource = (source: AsyncWatchSource): unknown => {\n if (typeof source === 'function') {\n return source();\n }\n return source.value;\n};\n\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\n const headers = new Headers();\n for (const source of sources) {\n if (!source) continue;\n new Headers(source).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n return headers;\n};\n\nconst isBodyLike = (value: unknown): value is BodyInit => {\n if (typeof value === 'string') return true;\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\n return true;\n }\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\n};\n\nconst serializeBody = (\n body: UseFetchOptions['body'],\n headers: Headers\n): BodyInit | null | undefined => {\n if (body == null) return body;\n if (isBodyLike(body)) return body;\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n};\n\nconst resolveInput = (input: FetchInput): string | URL | Request => {\n return typeof input === 'function' ? input() : input;\n};\n\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) {\n url.searchParams.append(key, String(item));\n }\n }\n continue;\n }\n\n url.searchParams.set(key, String(value));\n }\n};\n\nconst toUrl = (input: string | URL, baseUrl?: string): URL => {\n const runtimeBase =\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\n ? window.location.href\n : 'http://localhost';\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\n return input instanceof URL ? new URL(input.toString(), base) : new URL(input, base);\n};\n\nconst parseResponse = async <TResponse>(\n response: Response,\n parseAs: BqueryFetchParseAs\n): Promise<TResponse> => {\n if (parseAs === 'response') return response as TResponse;\n if (parseAs === 'text') return (await response.text()) as TResponse;\n if (parseAs === 'blob') return (await response.blob()) as TResponse;\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as TResponse;\n if (parseAs === 'formData') return (await response.formData()) as TResponse;\n\n const text = await response.text();\n if (!text) {\n return undefined as TResponse;\n }\n\n try {\n return JSON.parse(text) as TResponse;\n } catch (error) {\n const detail = response.url ? ` for ${response.url}` : '';\n throw new Error(\n `Failed to parse JSON response${detail} (status ${response.status}): ${error instanceof Error ? error.message : String(error)}`\n );\n }\n};\n\nconst normalizeMethod = (method?: string): string | undefined => {\n const normalized = method?.trim();\n return normalized ? normalized.toUpperCase() : undefined;\n};\n\nconst resolveMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n bodyProvided: boolean\n): string | undefined => {\n const requestMethod =\n requestInput instanceof Request ? normalizeMethod(requestInput.method) : undefined;\n return explicitMethod ?? requestMethod ?? (bodyProvided ? 'POST' : undefined);\n};\n\nconst resolveRequestInitMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n method: string | undefined\n): string | undefined => {\n if (explicitMethod) return explicitMethod;\n return requestInput instanceof Request ? undefined : method;\n};\n\nconst toRequestInit = (request: Request): RequestInit => {\n const requestMethod = normalizeMethod(request.method);\n let body: BodyInit | undefined;\n if (requestMethod !== 'GET' && requestMethod !== 'HEAD' && !request.bodyUsed) {\n try {\n body = request.clone().body ?? undefined;\n } catch {\n body = undefined;\n }\n }\n\n return {\n method: requestMethod,\n headers: request.headers,\n body,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n };\n};\n\n/**\n * Create a reactive wrapper around an async resolver.\n *\n * @template TResult - Raw result type returned by the handler\n * @template TData - Stored data type after optional transformation\n * @param handler - Async function to execute\n * @param options - Execution, transform, and refresh options\n * @returns Reactive data state with execute(), refresh(), and clear()\n *\n * @example\n * ```ts\n * const user = useAsyncData(() => fetch('/api/user').then((res) => res.json()));\n * ```\n */\nexport const useAsyncData = <TResult, TData = TResult>(\n handler: () => Promise<TResult>,\n options: UseAsyncDataOptions<TResult, TData> = {}\n): AsyncDataState<TData> => {\n const immediate = options.immediate ?? true;\n const data = signal<TData | undefined>(options.defaultValue);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n let executionId = 0;\n let disposed = false;\n let stopWatching = (): void => {};\n\n const clear = (): void => {\n executionId += 1;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n executionId += 1;\n stopWatching();\n };\n\n const execute = async (): Promise<TData | undefined> => {\n if (disposed) {\n return data.peek();\n }\n\n const currentExecution = ++executionId;\n status.value = 'pending';\n error.value = null;\n\n try {\n const resolved = await handler();\n const transformed = options.transform\n ? options.transform(resolved)\n : (resolved as unknown as TData);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n data.value = transformed;\n status.value = 'success';\n options.onSuccess?.(transformed);\n return transformed;\n } catch (caught) {\n const normalizedError = normalizeError(caught);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n error.value = normalizedError;\n status.value = 'error';\n options.onError?.(normalizedError);\n return data.peek();\n }\n };\n\n if (options.watch?.length) {\n let initialized = false;\n stopWatching = effect(() => {\n for (const source of options.watch ?? []) {\n readWatchSource(source);\n }\n\n if (!initialized) {\n initialized = true;\n if (immediate) {\n void untrack(() => execute());\n }\n return;\n }\n\n void untrack(() => execute());\n });\n } else if (immediate) {\n void execute();\n }\n\n return {\n data,\n error,\n status,\n pending,\n execute,\n refresh: execute,\n abort: () => {},\n clear,\n dispose,\n };\n};\n\n/** @internal */\nconst DEFAULT_VALIDATE_STATUS = (status: number): boolean => status >= 200 && status < 300;\n\n/** @internal */\nconst isDomExceptionNamed = (error: unknown, name: string): error is DOMException =>\n error instanceof DOMException && error.name === name;\n\n/** @internal */\nconst isTimeoutDomException = (error: unknown): error is DOMException =>\n isDomExceptionNamed(error, 'TimeoutError');\n\n/** @internal */\nconst isAbortDomException = (error: unknown): error is DOMException =>\n isDomExceptionNamed(error, 'AbortError');\n\n/** @internal */\nconst DEFAULT_RETRY_ON = (error: Error): boolean => {\n if (\n isAbortDomException(error) ||\n isTimeoutDomException(error) ||\n (error as Error & { code?: string }).code === 'ABORT' ||\n (error as Error & { code?: string }).code === 'TIMEOUT'\n ) {\n return false;\n }\n const status = (error as Error & { status?: number }).status;\n return status === undefined || status >= 500;\n};\n\n/** @internal */\nconst normalizeRetryConfig = (retry: UseFetchOptions['retry']): UseFetchRetryConfig | undefined => {\n if (retry == null) return undefined;\n if (typeof retry === 'number') return { count: retry };\n return retry;\n};\n\n/** @internal */\nconst resolveRetryDelay = (delay: UseFetchRetryConfig['delay'], attempt: number): number => {\n if (delay == null) return Math.min(1000 * 2 ** attempt, 30_000);\n if (typeof delay === 'number') return delay;\n return delay(attempt);\n};\n\n/** @internal */\nconst sleepWithSignal = (ms: number, abortSignal?: AbortSignal): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(abortSignal.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n return;\n }\n let cleanedUp = false;\n let timer: ReturnType<typeof setTimeout>;\n\n const onAbort = (): void => {\n if (cleanedUp) return;\n cleanedUp = true;\n clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n reject(abortSignal?.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n };\n\n timer = setTimeout(() => {\n if (cleanedUp) return;\n cleanedUp = true;\n abortSignal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n });\n\n/**\n * Reactive fetch composable using the browser Fetch API.\n *\n * Supports timeout, abort, retry, and custom status validation in addition\n * to the core useFetch features (query params, JSON body, baseUrl, watch).\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param input - Request URL, Request object, or lazy input factory\n * @param options - Request and reactive state options\n * @returns Reactive fetch state with execute(), refresh(), abort(), clear(), and dispose()\n *\n * @example\n * ```ts\n * const users = useFetch<{ id: number; name: string }[]>('/api/users', {\n * timeout: 5000,\n * retry: 3,\n * });\n * ```\n */\nexport const useFetch = <TResponse = unknown, TData = TResponse>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n): AsyncDataState<TData> => {\n const fetchConfig = getBqueryConfig().fetch;\n const parseAs = options.parseAs ?? fetchConfig?.parseAs ?? 'json';\n const fetcher = options.fetcher ?? fetch;\n const validateStatus = options.validateStatus ?? DEFAULT_VALIDATE_STATUS;\n\n let currentAbortController: AbortController | null = null;\n const normalizeAbortLikeError = (reason: unknown, didTimeout: boolean): Error => {\n const isTimeout =\n didTimeout ||\n isTimeoutDomException(reason) ||\n isTimeoutDomException(currentAbortController?.signal.reason);\n\n return Object.assign(\n new Error(isTimeout ? `Request timeout of ${options.timeout}ms exceeded` : 'Request aborted'),\n { code: isTimeout ? 'TIMEOUT' : 'ABORT' }\n );\n };\n\n const state = useAsyncData<TResponse, TData>(async () => {\n const requestInput = resolveInput(input);\n const requestUrl =\n typeof requestInput === 'string' || requestInput instanceof URL\n ? toUrl(requestInput, options.baseUrl ?? fetchConfig?.baseUrl)\n : requestInput instanceof Request && options.query\n ? new URL(requestInput.url)\n : null;\n\n if (requestUrl && options.query) {\n appendQuery(requestUrl, options.query);\n }\n\n const baseHeaders = toHeaders(\n fetchConfig?.headers,\n requestInput instanceof Request ? requestInput.headers : undefined,\n options.headers\n );\n const bodyProvided = options.body != null;\n const explicitMethod = normalizeMethod(options.method);\n const method = resolveMethod(explicitMethod, requestInput, bodyProvided);\n const bodylessMethod = method === 'GET' || method === 'HEAD' ? method : null;\n if (bodyProvided && bodylessMethod) {\n throw new Error(`Cannot send a request body with ${bodylessMethod} requests`);\n }\n const requestInitMethod = resolveRequestInitMethod(explicitMethod, requestInput, method);\n const retryConfig = normalizeRetryConfig(options.retry);\n const maxAttempts = (retryConfig?.count ?? 0) + 1;\n\n // Abort controller: compose timeout + external signal + manual abort\n const abortController = new AbortController();\n currentAbortController = abortController;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let didTimeout = false;\n let externalAbortHandler: (() => void) | undefined;\n\n if (options.signal) {\n if (options.signal.aborted) {\n abortController.abort(options.signal.reason);\n } else {\n externalAbortHandler = () => abortController.abort(options.signal?.reason);\n options.signal.addEventListener('abort', externalAbortHandler, { once: true });\n }\n }\n\n if (options.timeout && options.timeout > 0) {\n timeoutId = setTimeout(() => {\n didTimeout = true;\n abortController.abort(new DOMException('Request timeout', 'TimeoutError'));\n }, options.timeout);\n }\n\n const baseRequestInit: Omit<RequestInit, 'body' | 'signal'> = {\n ...options,\n method: requestInitMethod,\n headers: baseHeaders,\n };\n\n delete (baseRequestInit as Partial<UseFetchOptions>).baseUrl;\n delete (baseRequestInit as Partial<UseFetchOptions>).query;\n delete (baseRequestInit as Partial<UseFetchOptions>).parseAs;\n delete (baseRequestInit as Partial<UseFetchOptions>).fetcher;\n delete (baseRequestInit as Partial<UseFetchOptions>).defaultValue;\n delete (baseRequestInit as Partial<UseFetchOptions>).immediate;\n delete (baseRequestInit as Partial<UseFetchOptions>).watch;\n delete (baseRequestInit as Partial<UseFetchOptions>).transform;\n delete (baseRequestInit as Partial<UseFetchOptions>).onSuccess;\n delete (baseRequestInit as Partial<UseFetchOptions>).onError;\n delete (baseRequestInit as Partial<UseFetchOptions>).timeout;\n delete (baseRequestInit as Partial<UseFetchOptions>).retry;\n delete (baseRequestInit as Partial<UseFetchOptions>).validateStatus;\n\n let requestTarget: Request | string | URL = requestUrl ?? requestInput;\n if (\n requestInput instanceof Request &&\n requestUrl &&\n requestUrl.toString() !== requestInput.url\n ) {\n requestTarget = new Request(requestUrl.toString(), toRequestInit(requestInput));\n }\n\n const createAttemptRequestInit = (): RequestInit => {\n const headers = new Headers(baseHeaders);\n return {\n ...baseRequestInit,\n headers,\n body: serializeBody(options.body, headers),\n signal: abortController.signal,\n };\n };\n\n if (\n maxAttempts > 1 &&\n typeof ReadableStream !== 'undefined' &&\n options.body instanceof ReadableStream\n ) {\n throw new Error('Cannot retry requests with ReadableStream bodies');\n }\n\n if (\n maxAttempts > 1 &&\n typeof Request !== 'undefined' &&\n requestTarget instanceof Request &&\n requestTarget.body !== null\n ) {\n throw new Error('Cannot retry requests with non-replayable Request bodies');\n }\n let lastError: Error | undefined;\n\n try {\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const response = await fetcher(requestTarget, createAttemptRequestInit());\n\n if (!validateStatus(response.status)) {\n throw Object.assign(new Error(`Request failed with status ${response.status}`), {\n response,\n status: response.status,\n statusText: response.statusText,\n });\n }\n\n return await parseResponse<TResponse>(response, parseAs);\n } catch (error) {\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Abort errors should not be retried\n if (\n abortController.signal.aborted ||\n isAbortDomException(normalizedError) ||\n isTimeoutDomException(normalizedError)\n ) {\n throw normalizeAbortLikeError(\n abortController.signal.aborted ? abortController.signal.reason : normalizedError,\n didTimeout\n );\n }\n\n lastError = normalizedError;\n\n const shouldRetry = retryConfig\n ? (retryConfig.retryOn ?? DEFAULT_RETRY_ON)(normalizedError, attempt)\n : false;\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n throw normalizedError;\n }\n\n await sleepWithSignal(\n resolveRetryDelay(retryConfig!.delay, attempt),\n abortController.signal\n );\n }\n }\n\n throw lastError!;\n } finally {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n if (options.signal && externalAbortHandler) {\n options.signal.removeEventListener('abort', externalAbortHandler);\n }\n if (currentAbortController === abortController) {\n currentAbortController = null;\n }\n }\n }, options);\n\n // Override abort with real abort logic\n state.abort = (): void => {\n if (currentAbortController) {\n currentAbortController.abort(new DOMException('Request aborted', 'AbortError'));\n }\n };\n\n return state;\n};\n\n/**\n * Create a preconfigured useFetch() helper.\n *\n * @param defaults - Default request options merged into every useFetch() call\n * @returns A useFetch-compatible function with merged defaults\n *\n * @example\n * ```ts\n * const useApiFetch = createUseFetch({ baseUrl: 'https://api.example.com' });\n * const profile = useApiFetch('/profile');\n * ```\n */\n/** Overload for factories without a configured transform, preserving per-call `TResponse -> TData` inference. */\nexport function createUseFetch<TDefaultResponse = unknown>(\n defaults?: UseFetchOptions<TDefaultResponse, TDefaultResponse>\n): <TResponse = TDefaultResponse, TData = TResponse>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\n/** Overload for factories with a configured transform, preserving the transformed factory data type by default. */\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData>\n): <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData> = {}\n) {\n return <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n ): AsyncDataState<TData> => {\n const resolvedDefaults = defaults as unknown as UseFetchOptions<TResponse, TData>;\n const mergedQuery = merge({}, resolvedDefaults.query ?? {}, options.query ?? {}) as Record<\n string,\n unknown\n >;\n\n return useFetch<TResponse, TData>(input, {\n ...resolvedDefaults,\n ...options,\n headers: toHeaders(resolvedDefaults.headers, options.headers),\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\n });\n };\n}\n","/**\n * Imperative HTTP client with Axios-like API, interceptors, retry, timeout,\n * cancellation, and progress tracking — built on the native Fetch API.\n *\n * @module bquery/reactive\n */\n\nimport { merge, isPlainObject } from '../core/utils/object';\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Configuration for automatic request retries. */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3). */\n count: number;\n /** Delay in ms between retries, or a function receiving the attempt index. */\n delay?: number | ((attempt: number) => number);\n /** Predicate deciding whether to retry a given error. Defaults to network / 5xx errors. */\n retryOn?: (error: HttpError, attempt: number) => boolean;\n /** Called before each retry attempt with the error and 1-indexed attempt number. */\n onRetry?: (error: HttpError, attempt: number) => void;\n}\n\n/** Progress information emitted during upload or download. */\nexport interface HttpProgressEvent {\n /** Bytes transferred so far. */\n loaded: number;\n /** Total bytes if known, otherwise 0. */\n total: number;\n /** Percentage between 0 and 100, or `undefined` when total is unknown. */\n percent: number | undefined;\n}\n\n/** Full request configuration accepted by the HTTP client. */\nexport interface HttpRequestConfig extends Omit<RequestInit, 'body' | 'headers' | 'signal'> {\n /** Request URL (resolved against `baseUrl`). */\n url?: string;\n /** Base URL prepended to relative request URLs. */\n baseUrl?: string;\n /** Request headers. */\n headers?: HeadersInit;\n /** Query parameters appended to the URL. */\n query?: Record<string, unknown>;\n /** Request body — plain objects/arrays are JSON-serialised automatically. */\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\n /** Request timeout in milliseconds. 0 means no timeout (default). */\n timeout?: number;\n /** Response parsing strategy. */\n parseAs?: BqueryFetchParseAs;\n /** Custom status validation. Returns `true` for acceptable statuses. Default: `status >= 200 && status < 300`. */\n validateStatus?: (status: number) => boolean;\n /** Custom fetch implementation for testing or adapters. */\n fetcher?: typeof fetch;\n /** External `AbortSignal` for request cancellation. */\n signal?: AbortSignal;\n /** Retry configuration. Pass a number for simple retry count, or a `RetryConfig` object. */\n retry?: number | RetryConfig;\n /** Called repeatedly as response body chunks arrive. */\n onDownloadProgress?: (event: HttpProgressEvent) => void;\n}\n\n/** Structured HTTP response returned by every client method. */\nexport interface HttpResponse<T = unknown> {\n /** Parsed response data. */\n data: T;\n /** HTTP status code. */\n status: number;\n /** HTTP status text. */\n statusText: string;\n /** Response headers. */\n headers: Headers;\n /** Resolved request configuration used for this call. */\n config: HttpRequestConfig;\n}\n\n/** Error subclass thrown on failed HTTP requests with rich metadata. */\nexport class HttpError extends Error {\n /** HTTP response (available when the server replied). */\n response?: HttpResponse;\n /** Resolved request configuration. */\n config: HttpRequestConfig;\n /** Original error code string (e.g. `'TIMEOUT'`, `'ABORT'`, `'NETWORK'`). */\n code: string;\n\n constructor(message: string, config: HttpRequestConfig, code: string, response?: HttpResponse) {\n super(message);\n this.name = 'HttpError';\n this.config = config;\n this.code = code;\n this.response = response;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Interceptors\n// ---------------------------------------------------------------------------\n\n/** Single interceptor handler pair. */\nexport interface Interceptor<T> {\n fulfilled?: (value: T) => T | Promise<T>;\n rejected?: (error: unknown) => unknown;\n}\n\n/** Manager for adding and removing interceptors. */\nexport interface InterceptorManager<T> {\n /** Register an interceptor. Returns a numeric id for later removal via `eject()`. */\n use(fulfilled?: (value: T) => T | Promise<T>, rejected?: (error: unknown) => unknown): number;\n /** Remove a previously registered interceptor by id. */\n eject(id: number): void;\n /** Remove all interceptors. */\n clear(): void;\n}\n\n/** @internal */\ninterface InterceptorEntry<T> {\n id: number;\n fulfilled?: (value: T) => T | Promise<T>;\n rejected?: (error: unknown) => unknown;\n}\n\n/** @internal */\nfunction createInterceptorManager<T>(): InterceptorManager<T> & {\n /** @internal */ forEach(fn: (entry: InterceptorEntry<T>) => void): void;\n} {\n const entries: Array<InterceptorEntry<T> | null> = [];\n let nextId = 0;\n\n return {\n use(fulfilled, rejected) {\n const id = nextId++;\n entries.push({ id, fulfilled, rejected });\n return id;\n },\n eject(id) {\n const index = entries.findIndex((e) => e?.id === id);\n if (index !== -1) entries[index] = null;\n },\n clear() {\n entries.length = 0;\n },\n forEach(fn) {\n for (const entry of entries) {\n if (entry) fn(entry);\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// HttpClient interface\n// ---------------------------------------------------------------------------\n\n/** Imperative HTTP client with interceptors and convenience method shortcuts. */\nexport interface HttpClient {\n /** Send a request using the provided configuration. */\n request<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a GET request. */\n get<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a POST request. */\n post<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a PUT request. */\n put<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a PATCH request. */\n patch<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a DELETE request. */\n delete<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a HEAD request. */\n head<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send an OPTIONS request. */\n options<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Request and response interceptors. */\n interceptors: {\n request: InterceptorManager<HttpRequestConfig>;\n response: InterceptorManager<HttpResponse>;\n };\n /** The merged default configuration used by this client. */\n defaults: HttpRequestConfig;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_VALIDATE_STATUS = (status: number): boolean => status >= 200 && status < 300;\n\nconst DEFAULT_RETRY_ON = (error: HttpError): boolean => {\n if (error.code === 'PARSE') return false;\n if (error.code === 'TIMEOUT' || error.code === 'NETWORK') return true;\n const status = error.response?.status;\n return status !== undefined && status >= 500;\n};\n\n/** @internal */\nconst normalizeRetry = (retry: HttpRequestConfig['retry']): RetryConfig | undefined => {\n if (retry == null) return undefined;\n if (typeof retry === 'number') return { count: retry };\n return retry;\n};\n\n/** @internal */\nconst resolveRetryDelay = (delay: RetryConfig['delay'], attempt: number): number => {\n if (delay == null) return Math.min(1000 * 2 ** attempt, 30_000);\n if (typeof delay === 'number') return delay;\n return delay(attempt);\n};\n\n/** @internal */\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n return;\n }\n let timer: ReturnType<typeof setTimeout>;\n const onAbort = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n reject(signal?.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n };\n timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n if (signal) {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n\n/** @internal */\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\n const headers = new Headers();\n for (const source of sources) {\n if (!source) continue;\n new Headers(source).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n return headers;\n};\n\n/** @internal */\nconst isBodyLike = (value: unknown): value is BodyInit => {\n if (typeof value === 'string') return true;\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\n return true;\n }\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\n};\n\n/** @internal */\nconst serializeBody = (\n body: HttpRequestConfig['body'],\n headers: Headers\n): BodyInit | null | undefined => {\n if (body == null) return body;\n if (isBodyLike(body)) return body;\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n return JSON.stringify(body);\n};\n\n/** @internal */\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) url.searchParams.append(key, String(item));\n }\n continue;\n }\n url.searchParams.set(key, String(value));\n }\n};\n\n/** @internal */\nconst buildUrl = (url: string, baseUrl?: string): URL => {\n const runtimeBase =\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\n ? window.location.href\n : 'http://localhost';\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\n return new URL(url, base);\n};\n\n/** @internal */\nconst parseResponseBody = async <T>(\n response: Response,\n parseAs: BqueryFetchParseAs,\n config: HttpRequestConfig\n): Promise<T> => {\n if (parseAs === 'response') return response as T;\n if (parseAs === 'text') return (await response.text()) as T;\n if (parseAs === 'blob') return (await response.blob()) as T;\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as T;\n if (parseAs === 'formData') return (await response.formData()) as T;\n\n const text = await response.text();\n if (!text) return undefined as T;\n\n try {\n return JSON.parse(text) as T;\n } catch (parseError) {\n const detail = response.url ? ` for ${response.url}` : '';\n throw new HttpError(\n `Failed to parse JSON response${detail} (status ${response.status}): ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n config,\n 'PARSE',\n {\n data: text,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n }\n );\n }\n};\n\n/** @internal – wrap a response body stream to report download progress. */\nconst wrapDownloadStream = (\n response: Response,\n onProgress: (event: HttpProgressEvent) => void\n): Response => {\n const body = response.body;\n if (!body) return response;\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10) || 0;\n let loaded = 0;\n\n const reader = body.getReader();\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n loaded += value.byteLength;\n onProgress({\n loaded,\n total,\n percent: total > 0 ? Math.round((loaded / total) * 100) : undefined,\n });\n controller.enqueue(value);\n },\n cancel(reason) {\n reader.cancel(reason);\n },\n });\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n};\n\n// ---------------------------------------------------------------------------\n// Core request execution\n// ---------------------------------------------------------------------------\n\n/** @internal Execute a single HTTP request (no retry/interceptor logic). */\nconst executeRequest = async <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> => {\n const fetchConfig = getBqueryConfig().fetch;\n const parseAs = config.parseAs ?? fetchConfig?.parseAs ?? 'json';\n const fetcher = config.fetcher ?? fetch;\n const validateStatus = config.validateStatus ?? DEFAULT_VALIDATE_STATUS;\n\n const urlString = config.url ?? '/';\n const url = buildUrl(urlString, config.baseUrl ?? fetchConfig?.baseUrl);\n\n if (config.query) {\n appendQuery(url, config.query);\n }\n\n const headers = toHeaders(fetchConfig?.headers, config.headers);\n const serializedBody = serializeBody(config.body, headers);\n\n // Build RequestInit, omitting non-standard keys\n const requestInit: RequestInit = {};\n if (config.method) requestInit.method = config.method.toUpperCase();\n requestInit.headers = headers;\n if (serializedBody != null) requestInit.body = serializedBody;\n if (config.cache) requestInit.cache = config.cache;\n if (config.credentials) requestInit.credentials = config.credentials;\n if (config.integrity) requestInit.integrity = config.integrity;\n if (config.keepalive !== undefined) requestInit.keepalive = config.keepalive;\n if (config.mode) requestInit.mode = config.mode;\n if (config.redirect) requestInit.redirect = config.redirect;\n if (config.referrer) requestInit.referrer = config.referrer;\n if (config.referrerPolicy) requestInit.referrerPolicy = config.referrerPolicy;\n\n // Abort / timeout\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let mergedSignal: AbortSignal | undefined = config.signal;\n let externalAbortHandler: (() => void) | undefined;\n\n if (config.timeout && config.timeout > 0) {\n const controller = new AbortController();\n\n if (config.signal) {\n // Compose: abort when *either* the external signal or the timeout fires\n externalAbortHandler = () => controller.abort(config.signal?.reason);\n config.signal.addEventListener('abort', externalAbortHandler, { once: true });\n }\n\n timeoutId = setTimeout(() => {\n controller.abort(new DOMException('Request timeout', 'TimeoutError'));\n }, config.timeout);\n\n mergedSignal = controller.signal;\n }\n\n if (mergedSignal) requestInit.signal = mergedSignal;\n\n try {\n let response = await fetcher(url.toString(), requestInit);\n\n if (config.onDownloadProgress) {\n response = wrapDownloadStream(response, config.onDownloadProgress);\n }\n\n if (!validateStatus(response.status)) {\n throw new HttpError(\n `Request failed with status ${response.status}`,\n config,\n 'ERR_BAD_RESPONSE',\n {\n data: undefined,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n }\n );\n }\n\n const data = await parseResponseBody<T>(response, parseAs, config);\n\n const httpResponse: HttpResponse<T> = {\n data,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n };\n\n return httpResponse;\n } catch (error) {\n if (error instanceof HttpError) throw error;\n\n if (error instanceof DOMException) {\n if (error.name === 'AbortError' || error.name === 'TimeoutError') {\n const isTimeout = error.name === 'TimeoutError' || error.message === 'Request timeout';\n throw new HttpError(\n isTimeout ? `Request timeout of ${config.timeout}ms exceeded` : 'Request aborted',\n config,\n isTimeout ? 'TIMEOUT' : 'ABORT'\n );\n }\n }\n\n throw new HttpError(error instanceof Error ? error.message : String(error), config, 'NETWORK');\n } finally {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n if (config.signal && externalAbortHandler) {\n config.signal.removeEventListener('abort', externalAbortHandler);\n }\n }\n};\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a preconfigured HTTP client instance with interceptors.\n *\n * @param defaults - Default request configuration merged into every request\n * @returns An `HttpClient` with `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()`, `.options()`\n *\n * @example\n * ```ts\n * import { createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({\n * baseUrl: 'https://api.example.com',\n * headers: { authorization: 'Bearer token' },\n * timeout: 10_000,\n * });\n *\n * api.interceptors.request.use((config) => {\n * config.headers = { ...Object.fromEntries(new Headers(config.headers)), 'x-req-id': crypto.randomUUID() };\n * return config;\n * });\n *\n * const { data } = await api.get<User[]>('/users');\n * ```\n */\nexport function createHttp(defaults: HttpRequestConfig = {}): HttpClient {\n const requestInterceptors = createInterceptorManager<HttpRequestConfig>();\n const responseInterceptors = createInterceptorManager<HttpResponse>();\n\n const mergeConfig = (perCall: HttpRequestConfig): HttpRequestConfig => {\n const mergedQuery = merge({}, defaults.query ?? {}, perCall.query ?? {}) as Record<\n string,\n unknown\n >;\n\n return {\n ...defaults,\n ...perCall,\n headers: toHeaders(defaults.headers, perCall.headers),\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\n };\n };\n\n const dispatchRequest = async <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> => {\n // Run request interceptors\n let resolvedConfig = config;\n const requestChain: Array<InterceptorEntry<HttpRequestConfig>> = [];\n requestInterceptors.forEach((entry) => requestChain.push(entry));\n\n for (const { fulfilled, rejected } of requestChain) {\n try {\n if (fulfilled) {\n resolvedConfig = await fulfilled(resolvedConfig);\n }\n } catch (err) {\n if (rejected) {\n const result = await rejected(err);\n if (isPlainObject(result)) {\n resolvedConfig = result as unknown as HttpRequestConfig;\n } else {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n // Execute with retry\n const retryConfig = normalizeRetry(resolvedConfig.retry);\n let lastError: HttpError | undefined;\n\n const maxAttempts = (retryConfig?.count ?? 0) + 1;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n let response = await executeRequest<T>(resolvedConfig);\n\n // Run response interceptors\n const responseChain: Array<InterceptorEntry<HttpResponse>> = [];\n responseInterceptors.forEach((entry) => responseChain.push(entry));\n\n for (const { fulfilled, rejected } of responseChain) {\n try {\n if (fulfilled) {\n response = (await fulfilled(response as HttpResponse)) as HttpResponse<T>;\n }\n } catch (err) {\n if (rejected) {\n const result = await rejected(err);\n if (result && typeof result === 'object' && 'data' in result) {\n response = result as HttpResponse<T>;\n } else {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n return response;\n } catch (error) {\n const httpError =\n error instanceof HttpError\n ? error\n : new HttpError(\n error instanceof Error ? error.message : String(error),\n resolvedConfig,\n 'NETWORK'\n );\n\n lastError = httpError;\n\n const shouldRetry = retryConfig\n ? (retryConfig.retryOn ?? DEFAULT_RETRY_ON)(httpError, attempt)\n : false;\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n // Run response error interceptors before throwing\n const responseChain: Array<InterceptorEntry<HttpResponse>> = [];\n responseInterceptors.forEach((entry) => responseChain.push(entry));\n\n let finalError: unknown = httpError;\n for (const { rejected } of responseChain) {\n if (rejected) {\n try {\n const result = await rejected(finalError);\n if (result && typeof result === 'object' && 'data' in result) {\n return result as HttpResponse<T>;\n }\n if (result != null) {\n finalError = result;\n }\n } catch (innerErr) {\n if (innerErr != null) {\n finalError = innerErr;\n }\n }\n }\n }\n\n if (!(finalError instanceof Error)) {\n finalError = httpError;\n }\n\n throw finalError;\n }\n\n const retryDelay = retryConfig ? resolveRetryDelay(retryConfig.delay, attempt) : 0;\n retryConfig?.onRetry?.(httpError, attempt + 1);\n await sleep(retryDelay, resolvedConfig.signal);\n }\n }\n\n throw lastError!;\n };\n\n const request = <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> =>\n dispatchRequest<T>(mergeConfig(config));\n\n const client: HttpClient = {\n request,\n get: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'GET' }),\n post: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'POST', body }),\n put: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'PUT', body }),\n patch: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'PATCH', body }),\n delete: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'DELETE' }),\n head: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'HEAD' }),\n options: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'OPTIONS' }),\n interceptors: {\n request: requestInterceptors,\n response: responseInterceptors,\n },\n defaults,\n };\n\n return client;\n}\n\n/**\n * Default HTTP client instance using global bQuery fetch config.\n *\n * @example\n * ```ts\n * import { http } from '@bquery/bquery/reactive';\n *\n * const { data } = await http.get<User[]>('/api/users');\n * const { data: created } = await http.post('/api/users', { name: 'Ada' });\n * ```\n */\nexport const http: HttpClient = createHttp();\n\n// ---------------------------------------------------------------------------\n// Request Queue\n// ---------------------------------------------------------------------------\n\n/** Options for `createRequestQueue()`. */\nexport interface RequestQueueOptions {\n /** Maximum number of concurrent in-flight requests (default: 6). */\n concurrency?: number;\n}\n\n/** A queued request entry. */\ninterface QueueEntry<T = unknown> {\n execute: () => Promise<HttpResponse<T>>;\n resolve: (value: HttpResponse<T>) => void;\n reject: (reason: unknown) => void;\n}\n\n/** Return value of `createRequestQueue()`. */\nexport interface RequestQueue {\n /** Enqueue a request. Returns a promise that resolves when the request completes. */\n add: <T = unknown>(execute: () => Promise<HttpResponse<T>>) => Promise<HttpResponse<T>>;\n /** Number of requests currently being processed. */\n readonly pending: number;\n /** Number of requests waiting in the queue. */\n readonly size: number;\n /** Remove all pending (not yet started) requests from the queue. Their promises will reject. */\n clear: () => void;\n}\n\n/**\n * Create a request queue with a concurrency limit.\n *\n * Useful for rate-limiting parallel HTTP requests (e.g. browser connection limits,\n * API throttling) while maintaining a simple promise-based interface.\n *\n * @param options - Queue configuration\n * @returns A `RequestQueue` with `.add()`, `.clear()`, `.pending`, and `.size`\n *\n * @example\n * ```ts\n * import { createRequestQueue, createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({ baseUrl: 'https://api.example.com' });\n * const queue = createRequestQueue({ concurrency: 3 });\n *\n * // These will run at most 3 at a time\n * const results = await Promise.all(\n * ids.map(id => queue.add(() => api.get(`/items/${id}`)))\n * );\n * ```\n */\nexport function createRequestQueue(options: RequestQueueOptions = {}): RequestQueue {\n const { concurrency = 6 } = options;\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new Error('Request queue concurrency must be a positive integer');\n }\n const queue: Array<QueueEntry> = [];\n let running = 0;\n\n const drain = (): void => {\n while (running < concurrency && queue.length > 0) {\n const entry = queue.shift()!;\n running++;\n Promise.resolve()\n .then(entry.execute)\n .then(entry.resolve, entry.reject)\n .finally(() => {\n running--;\n drain();\n });\n }\n };\n\n return {\n add<T = unknown>(execute: () => Promise<HttpResponse<T>>): Promise<HttpResponse<T>> {\n return new Promise<HttpResponse<T>>((resolve, reject) => {\n queue.push({\n execute: execute as () => Promise<HttpResponse>,\n resolve: resolve as (value: HttpResponse) => void,\n reject,\n });\n drain();\n });\n },\n get pending() {\n return running;\n },\n get size() {\n return queue.length;\n },\n clear() {\n const cleared = queue.splice(0);\n for (const entry of cleared) {\n entry.reject(new Error('Request queue cleared'));\n }\n },\n };\n}\n","/**\n * Linked (writable) computed helpers.\n */\n\nimport { computed, Computed } from './computed';\n\n/**\n * A writable computed-like signal.\n */\nexport interface LinkedSignal<T> {\n /** Gets or sets the current value with dependency tracking. */\n value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a writable computed signal by linking a getter and setter.\n *\n * @template T - The derived value type\n * @param getValue - Getter that derives the current value\n * @param setValue - Setter that writes back to underlying signals\n * @returns A writable computed-like signal\n *\n * @example\n * ```ts\n * const first = signal('Ada');\n * const last = signal('Lovelace');\n * const fullName = linkedSignal(\n * () => `${first.value} ${last.value}`,\n * (next) => {\n * const [a, b] = next.split(' ');\n * first.value = a ?? '';\n * last.value = b ?? '';\n * }\n * );\n * ```\n */\nexport const linkedSignal = <T>(\n getValue: () => T,\n setValue: (value: T) => void\n): LinkedSignal<T> => {\n const derived: Computed<T> = computed(getValue);\n\n return {\n get value(): T {\n return derived.value;\n },\n set value(next: T) {\n setValue(next);\n },\n peek(): T {\n return derived.peek();\n },\n };\n};\n","/**\n * Pagination and infinite-scroll composables for reactive data fetching.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\nimport {\n useFetch,\n type AsyncDataState,\n type AsyncDataStatus,\n type UseFetchOptions,\n} from './async-data';\n\n// ---------------------------------------------------------------------------\n// usePaginatedFetch\n// ---------------------------------------------------------------------------\n\n/** Options for usePaginatedFetch(). */\nexport interface UsePaginatedFetchOptions<\n TResponse = unknown,\n TData = TResponse,\n> extends UseFetchOptions<TResponse, TData> {\n /** Initial page number (default: 1). */\n initialPage?: number;\n}\n\n/** Return value of usePaginatedFetch(). */\nexport interface PaginatedState<TData> extends AsyncDataState<TData> {\n /** Current page number signal (writable). */\n page: Signal<number>;\n /** Go to the next page. */\n next: () => Promise<TData | undefined>;\n /** Go to the previous page (minimum 1). */\n prev: () => Promise<TData | undefined>;\n /** Jump to a specific page. */\n goTo: (page: number) => Promise<TData | undefined>;\n}\n\n/**\n * Reactive paginated fetch composable.\n *\n * Takes a URL factory receiving the current page number, and exposes\n * `page`, `next()`, `prev()`, and `goTo()` helpers alongside the\n * standard `AsyncDataState`.\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param inputFactory - Function that receives the page number and returns a URL string, URL, or Request\n * @param options - Fetch and pagination options\n * @returns Paginated data state\n *\n * @example\n * ```ts\n * import { usePaginatedFetch } from '@bquery/bquery/reactive';\n *\n * const users = usePaginatedFetch<User[]>(\n * (page) => `/api/users?page=${page}`,\n * { baseUrl: 'https://api.example.com' }\n * );\n *\n * // Navigate pages\n * await users.next();\n * await users.prev();\n * await users.goTo(5);\n * console.log(users.page.value); // 5\n * ```\n */\nexport const usePaginatedFetch = <TResponse = unknown, TData = TResponse>(\n inputFactory: (page: number) => string | URL | Request,\n options: UsePaginatedFetchOptions<TResponse, TData> = {}\n): PaginatedState<TData> => {\n const { initialPage = 1, ...fetchOptions } = options;\n const page = signal(initialPage);\n\n const state = useFetch<TResponse, TData>(() => inputFactory(page.value), {\n ...fetchOptions,\n watch: fetchOptions.watch,\n });\n\n const next = async (): Promise<TData | undefined> => {\n page.value = page.peek() + 1;\n return state.execute();\n };\n\n const prev = async (): Promise<TData | undefined> => {\n const current = page.peek();\n if (current > 1) {\n page.value = current - 1;\n }\n return state.execute();\n };\n\n const goTo = async (target: number): Promise<TData | undefined> => {\n page.value = Math.max(1, target);\n return state.execute();\n };\n\n return {\n ...state,\n page,\n next,\n prev,\n goTo,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useInfiniteFetch\n// ---------------------------------------------------------------------------\n\n/** Options for useInfiniteFetch(). */\nexport interface UseInfiniteFetchOptions<\n TResponse = unknown,\n TData = TResponse,\n TCursor = number,\n> extends Omit<UseFetchOptions<TResponse, TData>, 'transform'> {\n /** Extract the cursor for the next page from a response. */\n getNextCursor: (lastResponse: TResponse, allPages: TResponse[]) => TCursor | undefined;\n /** Transform all accumulated pages into the final data shape. */\n transform?: (pages: TResponse[]) => TData;\n /** Initial cursor value (default: undefined, meaning first page). */\n initialCursor?: TCursor;\n}\n\n/** Return value of useInfiniteFetch(). */\nexport interface InfiniteState<TData, TResponse = unknown> {\n /** All accumulated page data, transformed. */\n data: Signal<TData | undefined>;\n /** Raw accumulated pages. */\n pages: Signal<TResponse[]>;\n /** Last error encountered. */\n error: Signal<Error | null>;\n /** Current lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Computed boolean that mirrors `status === 'pending'`. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether there are more pages to load. */\n hasMore: { readonly value: boolean; peek(): boolean };\n /** Fetch the next page and append it to the accumulated data. */\n fetchNextPage: () => Promise<TData | undefined>;\n /** Reset all pages and re-fetch from the initial cursor. */\n refresh: () => Promise<TData | undefined>;\n /** Clear all accumulated data. */\n clear: () => void;\n /** Dispose reactive watchers and prevent future executions. */\n dispose: () => void;\n}\n\n/**\n * Reactive infinite-scroll / load-more composable.\n *\n * Accumulates pages of data and exposes `fetchNextPage()` to load\n * additional results. Uses a cursor-based approach with `getNextCursor()`\n * to determine pagination.\n *\n * @template TResponse - Raw parsed response type for a single page\n * @template TData - Transformed accumulated data type\n * @template TCursor - Cursor type used for pagination\n * @param inputFactory - Function receiving the cursor and returning a FetchInput\n * @param options - Fetch and infinite-scroll options\n * @returns Infinite data state with fetchNextPage(), hasMore, and accumulated pages\n *\n * @example\n * ```ts\n * import { useInfiniteFetch } from '@bquery/bquery/reactive';\n *\n * const feed = useInfiniteFetch<Post[], Post[]>(\n * (cursor) => `/api/posts?cursor=${cursor ?? ''}`,\n * {\n * getNextCursor: (page) => page.length > 0 ? page[page.length - 1].id : undefined,\n * transform: (pages) => pages.flat(),\n * baseUrl: 'https://api.example.com',\n * }\n * );\n *\n * // Load more pages\n * await feed.fetchNextPage();\n * console.log(feed.data.value); // All accumulated posts\n * console.log(feed.hasMore.value); // true if more pages available\n * ```\n */\nexport const useInfiniteFetch = <TResponse = unknown, TData = TResponse[], TCursor = number>(\n inputFactory: (cursor: TCursor | undefined) => string | URL | Request,\n options: UseInfiniteFetchOptions<TResponse, TData, TCursor>\n): InfiniteState<TData, TResponse> => {\n const {\n getNextCursor,\n transform: transformPages,\n initialCursor,\n immediate = true,\n // Keep these callbacks on the infinite-fetch layer instead of forwarding\n // them into the inner per-page useFetch() instance.\n onSuccess: infiniteOnSuccess,\n onError: infiniteOnError,\n ...fetchOptions\n } = options;\n\n const pages = signal<TResponse[]>([]);\n const data = signal<TData | undefined>(options.defaultValue);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n const nextCursor = signal<TCursor | undefined>(initialCursor);\n const hasMore = computed(() => pages.value.length === 0 || nextCursor.value !== undefined);\n\n let disposed = false;\n let executionId = 0;\n\n const applyTransform = (allPages: TResponse[]): TData => {\n if (transformPages) {\n return transformPages(allPages);\n }\n return allPages as unknown as TData;\n };\n\n const fetchNextPage = async (): Promise<TData | undefined> => {\n if (disposed) return data.peek();\n\n const currentExecution = ++executionId;\n status.value = 'pending';\n error.value = null;\n\n try {\n const cursor = nextCursor.peek();\n const input = inputFactory(cursor);\n const pageState = useFetch<TResponse>(input, {\n ...(fetchOptions as UseFetchOptions<TResponse>),\n immediate: false,\n watch: undefined,\n });\n\n const pageData = await pageState.execute();\n const pageError = pageState.error.peek();\n pageState.dispose();\n\n if (disposed || currentExecution !== executionId) return data.peek();\n\n // Check if the inner fetch encountered an error\n if (pageError) {\n error.value = pageError;\n status.value = 'error';\n infiniteOnError?.(pageError);\n return data.peek();\n }\n\n if (pageData !== undefined) {\n const typedPageData = pageData as TResponse;\n const newPages: TResponse[] = [...pages.peek(), typedPageData];\n pages.value = newPages;\n\n const newCursor = getNextCursor(typedPageData, newPages);\n nextCursor.value = newCursor;\n\n const transformed = applyTransform(newPages);\n data.value = transformed;\n status.value = 'success';\n infiniteOnSuccess?.(transformed);\n return transformed;\n }\n\n status.value = 'success';\n return data.peek();\n } catch (caught) {\n if (disposed || currentExecution !== executionId) return data.peek();\n\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n error.value = normalizedError;\n status.value = 'error';\n infiniteOnError?.(normalizedError);\n return data.peek();\n }\n };\n\n const refresh = async (): Promise<TData | undefined> => {\n pages.value = [];\n nextCursor.value = initialCursor;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n executionId += 1;\n return fetchNextPage();\n };\n\n const clear = (): void => {\n executionId += 1;\n pages.value = [];\n nextCursor.value = initialCursor;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n executionId += 1;\n };\n\n if (immediate) {\n void fetchNextPage();\n }\n\n return {\n data,\n pages,\n error,\n status,\n pending,\n hasMore,\n fetchNextPage,\n refresh,\n clear,\n dispose,\n };\n};\n","/**\n * LocalStorage-backed signals.\n */\n\nimport { signal, Signal } from './core';\nimport { effect } from './effect';\n\n/**\n * Creates a signal that persists to localStorage.\n *\n * @template T - The type of the signal value\n * @param key - The localStorage key\n * @param initialValue - The initial value if not found in storage\n * @returns A Signal that syncs with localStorage (falls back to in-memory if unavailable)\n */\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\n // Check if localStorage is available and accessible\n let hasLocalStorage = false;\n let storage: Storage | null = null;\n\n try {\n // In Safari private mode, accessing localStorage can throw SecurityError\n storage = globalThis.localStorage;\n if (storage) {\n // Test actual access to ensure it's not just present but usable\n // Use a randomized test key to avoid overwriting real user data\n const testKey = `__bquery_test_${Math.random().toString(36).slice(2, 9)}__`;\n const testValue = '__test__';\n try {\n storage.setItem(testKey, testValue);\n storage.getItem(testKey);\n hasLocalStorage = true;\n } finally {\n // Ensure we don't leave any test data behind\n try {\n storage.removeItem(testKey);\n } catch {\n // Ignore cleanup errors (e.g., storage becoming unavailable)\n }\n }\n }\n } catch {\n // localStorage unavailable or access denied (Safari private mode, sandboxed iframes, etc.)\n hasLocalStorage = false;\n }\n\n let stored: T = initialValue;\n\n if (hasLocalStorage && storage) {\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n stored = JSON.parse(raw) as T;\n }\n } catch {\n // Use initial value on parse error or access denial\n }\n }\n\n const sig = signal(stored);\n\n // Only set up persistence effect if localStorage is available\n if (hasLocalStorage && storage) {\n effect(() => {\n try {\n storage!.setItem(key, JSON.stringify(sig.value));\n } catch {\n // Ignore storage errors (quota exceeded, sandboxed iframes, etc.)\n }\n });\n }\n\n return sig;\n};\n","/**\n * Reactive polling composable for periodic data fetching.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { effect } from './effect';\nimport { signal } from './core';\nimport { untrack } from './untrack';\nimport { useFetch, type AsyncDataState, type FetchInput, type UseFetchOptions } from './async-data';\n\n/** Options for usePolling(). */\nexport interface UsePollingOptions<TResponse = unknown, TData = TResponse> extends UseFetchOptions<\n TResponse,\n TData\n> {\n /** Polling interval in milliseconds. */\n interval: number;\n /** Whether polling is initially enabled (default: true). Can be a reactive getter. */\n enabled?: boolean | (() => boolean);\n /** Pause polling when the document is hidden (default: true). */\n pauseOnHidden?: boolean;\n /** Pause polling when the browser is offline (default: true). */\n pauseOnOffline?: boolean;\n}\n\n/** Extended return value from usePolling(). */\nexport interface PollingState<TData> extends AsyncDataState<TData> {\n /** Pause polling. */\n pause: () => void;\n /** Resume polling. */\n resume: () => void;\n /** Reactive boolean indicating whether polling is currently active. */\n isActive: { readonly value: boolean; peek(): boolean };\n}\n\n/**\n * Reactive polling composable that periodically fetches data.\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param input - Request URL, Request object, or lazy input factory\n * @param options - Polling and fetch options\n * @returns Extended fetch state with pause(), resume(), and isActive\n *\n * @example\n * ```ts\n * import { usePolling } from '@bquery/bquery/reactive';\n *\n * const notifications = usePolling<Notification[]>('/api/notifications', {\n * interval: 30_000,\n * pauseOnHidden: true,\n * pauseOnOffline: true,\n * });\n *\n * // Manually pause/resume\n * notifications.pause();\n * notifications.resume();\n * ```\n */\nexport const usePolling = <TResponse = unknown, TData = TResponse>(\n input: FetchInput,\n options: UsePollingOptions<TResponse, TData>\n): PollingState<TData> => {\n const {\n interval,\n enabled: enabledOption = true,\n pauseOnHidden = true,\n pauseOnOffline = true,\n immediate = true,\n ...fetchOptions\n } = options;\n\n if (!Number.isFinite(interval) || interval < 1) {\n throw new Error('Polling interval must be a finite number of at least 1');\n }\n\n const manuallyPaused = signal(false);\n const documentHidden = signal(false);\n const browserOffline = signal(false);\n\n const enabledGetter = typeof enabledOption === 'function' ? enabledOption : () => enabledOption;\n\n const isActive = computed(\n () =>\n enabledGetter() &&\n !manuallyPaused.value &&\n !(pauseOnHidden && documentHidden.value) &&\n !(pauseOnOffline && browserOffline.value)\n );\n\n // Create the underlying useFetch with immediate control\n const fetchState = useFetch<TResponse, TData>(input, {\n ...fetchOptions,\n immediate: immediate && enabledGetter(),\n });\n\n let intervalId: ReturnType<typeof setInterval> | undefined;\n let cleanups: Array<() => void> = [];\n\n const startPolling = (): void => {\n stopPolling();\n intervalId = setInterval(() => {\n void fetchState.execute();\n }, interval);\n };\n\n const stopPolling = (): void => {\n if (intervalId !== undefined) {\n clearInterval(intervalId);\n intervalId = undefined;\n }\n };\n\n // Watch isActive and start/stop polling accordingly\n const stopWatcher = effect(() => {\n const active = isActive.value;\n untrack(() => {\n if (active) {\n startPolling();\n } else {\n stopPolling();\n }\n });\n });\n\n // Listen for visibility changes\n if (pauseOnHidden && typeof document !== 'undefined') {\n documentHidden.value = document.hidden;\n const onVisibilityChange = (): void => {\n documentHidden.value = document.hidden;\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n cleanups.push(() => document.removeEventListener('visibilitychange', onVisibilityChange));\n }\n\n // Listen for online/offline changes\n if (pauseOnOffline && typeof window !== 'undefined') {\n const onOnline = (): void => {\n browserOffline.value = false;\n };\n const onOffline = (): void => {\n browserOffline.value = true;\n };\n window.addEventListener('online', onOnline);\n window.addEventListener('offline', onOffline);\n cleanups.push(() => {\n window.removeEventListener('online', onOnline);\n window.removeEventListener('offline', onOffline);\n });\n browserOffline.value =\n typeof navigator !== 'undefined' && navigator.onLine !== undefined\n ? !navigator.onLine\n : false;\n }\n\n const originalDispose = fetchState.dispose;\n\n const dispose = (): void => {\n stopPolling();\n stopWatcher();\n for (const cleanup of cleanups) cleanup();\n cleanups = [];\n originalDispose();\n };\n\n return {\n ...fetchState,\n pause: () => {\n manuallyPaused.value = true;\n },\n resume: () => {\n manuallyPaused.value = false;\n },\n isActive,\n dispose,\n };\n};\n","/**\n * Read-only signal wrappers.\n */\n\nimport type { Signal } from './core';\n\nconst READONLY_SIGNAL_BRAND: unique symbol = Symbol('bquery.readonlySignal');\n\n/** @internal */\ntype ReadonlySignalWrapper<T> = ReadonlySignal<T> & {\n readonly [READONLY_SIGNAL_BRAND]: true;\n};\n\n/**\n * A readonly wrapper around a signal that prevents writes.\n * Provides read-only access to a signal's value while maintaining reactivity.\n *\n * @template T - The type of the wrapped value\n */\nexport interface ReadonlySignal<T> {\n /** Gets the current value with dependency tracking. */\n readonly value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Determines whether a value is a bQuery readonly signal wrapper.\n *\n * @internal\n */\nexport const isReadonlySignal = <T>(value: unknown): value is ReturnType<typeof readonly<T>> => {\n return (\n typeof value === 'object' &&\n value !== null &&\n Object.prototype.hasOwnProperty.call(value, READONLY_SIGNAL_BRAND)\n );\n};\n\n/**\n * Creates a read-only view of a signal.\n * Useful for exposing reactive state without allowing modifications.\n *\n * @template T - The type of the signal value\n * @param sig - The signal to wrap\n * @returns A readonly signal wrapper\n */\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignalWrapper<T> =>\n Object.defineProperties(\n {},\n {\n value: {\n get(): T {\n return sig.value;\n },\n enumerable: true,\n },\n peek: {\n value(): T {\n return sig.peek();\n },\n enumerable: true,\n },\n [READONLY_SIGNAL_BRAND]: {\n value: true,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n }\n ) as ReadonlySignalWrapper<T>;\n\n/**\n * Branded readonly wrapper type produced by {@link readonly}.\n *\n * Useful for APIs that compose additional behavior on top of a readonly signal\n * without widening to arbitrary structural `{ value, peek }` objects.\n */\nexport type ReadonlySignalHandle<T> = ReturnType<typeof readonly<T>>;\n","/**\n * REST resource composable for CRUD operations with optimistic updates,\n * form submission, and reactive caching built on the bQuery fetch layer.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\nimport { useFetch, type AsyncDataStatus, type UseFetchOptions } from './async-data';\nimport { createHttp, type HttpClient, type HttpRequestConfig, type HttpResponse } from './http';\n\n// ---------------------------------------------------------------------------\n// useResource — full CRUD composable\n// ---------------------------------------------------------------------------\n\n/** HTTP method shortcuts available on a resource. */\nexport interface ResourceActions<T> {\n /** Fetch the resource (GET). */\n fetch: () => Promise<T | undefined>;\n /** Create a new item (POST). */\n create: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Replace the resource (PUT). */\n update: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Partially update the resource (PATCH). */\n patch: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Delete the resource (DELETE). */\n remove: () => Promise<void>;\n}\n\n/** Options for `useResource()`. */\nexport interface UseResourceOptions<T = unknown> extends Omit<\n UseFetchOptions<T>,\n 'method' | 'body'\n> {\n /** Enable optimistic updates for mutating operations (default: false). */\n optimistic?: boolean;\n /** Called after any successful mutation (create / update / patch / remove). */\n onMutationSuccess?: (data: T | undefined, action: string) => void;\n /** Called after a failed mutation, receives the error and action name. */\n onMutationError?: (error: Error, action: string) => void;\n}\n\n/** Return value of `useResource()`. */\nexport interface UseResourceReturn<T> {\n /** Reactive resource data. */\n data: Signal<T | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Lifecycle status for the initial fetch. */\n status: Signal<AsyncDataStatus>;\n /** Whether the initial fetch is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether any mutation is in progress. */\n isMutating: { readonly value: boolean; peek(): boolean };\n /** CRUD actions. */\n actions: ResourceActions<T>;\n /** Refresh the resource (re-GET). */\n refresh: () => Promise<T | undefined>;\n /** Clear data, error, and status. */\n clear: () => void;\n /** Dispose all reactive state and prevent future operations. */\n dispose: () => void;\n}\n\n/**\n * Reactive REST resource composable providing CRUD operations.\n *\n * Binds a base URL to a resource and exposes `fetch`, `create`, `update`,\n * `patch`, and `remove` helpers with optional optimistic updates.\n *\n * @template T - Resource data type\n * @param url - Resource endpoint URL or getter\n * @param options - Fetch and resource options\n * @returns Reactive resource state with CRUD actions\n *\n * @example\n * ```ts\n * import { useResource } from '@bquery/bquery/reactive';\n *\n * const user = useResource<User>('/api/users/1', {\n * baseUrl: 'https://api.example.com',\n * optimistic: true,\n * });\n *\n * // Read\n * await user.actions.fetch();\n *\n * // Update\n * await user.actions.patch({ name: 'Ada' });\n *\n * // Delete\n * await user.actions.remove();\n * ```\n */\nexport const useResource = <T = unknown>(\n url: string | URL | (() => string | URL),\n options: UseResourceOptions<T> = {}\n): UseResourceReturn<T> => {\n const { optimistic = false, onMutationSuccess, onMutationError, ...fetchOptions } = options;\n\n // Internal fetch state for the GET\n const fetchState = useFetch<T>(url, {\n ...fetchOptions,\n });\n\n const mutating = signal(false);\n const isMutating = computed(() => mutating.value);\n\n let disposed = false;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const stripGetLifecycleOptions = <TResult>(): Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n > => {\n const {\n defaultValue: _defaultValue,\n transform: _transform,\n onSuccess: _onSuccess,\n onError: _onError,\n ...remainingOpts\n } = fetchOptions;\n return remainingOpts as Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n >;\n };\n\n const executeMutation = async (\n action: string,\n method: string,\n body?: Partial<T> | Record<string, unknown>,\n optimisticData?: T | undefined\n ): Promise<T | undefined> => {\n if (disposed) return fetchState.data.peek();\n\n const previousData = fetchState.data.peek();\n\n // Optimistic update\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = optimisticData;\n }\n\n mutating.value = true;\n fetchState.error.value = null;\n\n try {\n const mutationState = useFetch<T>(resolveUrl(), {\n ...stripGetLifecycleOptions<T>(),\n method,\n body: body ?? undefined,\n immediate: false,\n watch: undefined,\n });\n\n const result = await mutationState.execute();\n const mutationError = mutationState.error.peek();\n mutationState.dispose();\n\n if (disposed) return fetchState.data.peek();\n\n // Check if the inner fetch encountered an error\n if (mutationError) {\n // Rollback on optimistic failure\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = previousData;\n }\n\n fetchState.error.value = mutationError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(mutationError, action);\n return fetchState.data.peek();\n }\n\n // For non-DELETE mutations, update data with server response\n if (method !== 'DELETE' && result !== undefined) {\n fetchState.data.value = result;\n }\n\n mutating.value = false;\n fetchState.status.value = 'success';\n onMutationSuccess?.(result, action);\n return result;\n } catch (caught) {\n if (disposed) return fetchState.data.peek();\n\n // Rollback on optimistic failure\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = previousData;\n }\n\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n fetchState.error.value = normalizedError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(normalizedError, action);\n return fetchState.data.peek();\n }\n };\n\n const actions: ResourceActions<T> = {\n fetch: () => fetchState.execute(),\n create: (body) => executeMutation('create', 'POST', body),\n update: (body) => {\n const base = fetchState.data.peek();\n return executeMutation(\n 'update',\n 'PUT',\n body,\n optimistic && base !== undefined ? ({ ...base, ...body } as T) : undefined\n );\n },\n patch: (body) => {\n const base = fetchState.data.peek();\n return executeMutation(\n 'patch',\n 'PATCH',\n body,\n optimistic && base !== undefined ? ({ ...base, ...body } as T) : undefined\n );\n },\n remove: async () => {\n await executeMutation('remove', 'DELETE');\n if (!disposed && fetchState.error.peek() == null) {\n fetchState.data.value = undefined;\n }\n },\n };\n\n const originalDispose = fetchState.dispose;\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n originalDispose();\n };\n\n return {\n data: fetchState.data,\n error: fetchState.error,\n status: fetchState.status,\n pending: fetchState.pending,\n isMutating,\n actions,\n refresh: fetchState.execute,\n clear: fetchState.clear,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useSubmit — form submission composable\n// ---------------------------------------------------------------------------\n\n/** Options for `useSubmit()`. */\nexport interface UseSubmitOptions<TResponse = unknown> extends Omit<\n UseFetchOptions<TResponse>,\n 'body' | 'immediate'\n> {\n /** HTTP method (default: `'POST'`). */\n method?: string;\n}\n\n/** Return value of `useSubmit()`. */\nexport interface UseSubmitReturn<TResponse = unknown> {\n /** Last response data. */\n data: Signal<TResponse | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Current status. */\n status: Signal<AsyncDataStatus>;\n /** Whether the submission is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Submit data to the endpoint. */\n submit: (body: Record<string, unknown> | FormData | BodyInit) => Promise<TResponse | undefined>;\n /** Reset state. */\n clear: () => void;\n}\n\n/**\n * Reactive form submission composable.\n *\n * Provides a `submit()` function that sends data to an endpoint with\n * reactive status, data, and error signals.\n *\n * @template TResponse - Response data type\n * @param url - Submission endpoint URL\n * @param options - Fetch options (method defaults to POST)\n * @returns Reactive submission state with `submit()` and `clear()`\n *\n * @example\n * ```ts\n * import { useSubmit } from '@bquery/bquery/reactive';\n *\n * const form = useSubmit<{ id: number }>('/api/users', {\n * baseUrl: 'https://api.example.com',\n * headers: { 'x-csrf': token },\n * });\n *\n * const result = await form.submit({ name: 'Ada', email: 'ada@example.com' });\n * console.log(form.status.value); // 'success'\n * ```\n */\nexport const useSubmit = <TResponse = unknown>(\n url: string | URL,\n options: UseSubmitOptions<TResponse> = {}\n): UseSubmitReturn<TResponse> => {\n const { method = 'POST', ...fetchOptions } = options;\n\n const data = signal<TResponse | undefined>(undefined);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n\n const submit = async (\n body: Record<string, unknown> | FormData | BodyInit\n ): Promise<TResponse | undefined> => {\n status.value = 'pending';\n error.value = null;\n\n try {\n const state = useFetch<TResponse>(url, {\n ...fetchOptions,\n method,\n body: body as UseFetchOptions['body'],\n immediate: false,\n watch: undefined,\n });\n\n const result = await state.execute();\n const fetchError = state.error.peek();\n state.dispose();\n\n if (fetchError) {\n error.value = fetchError;\n status.value = 'error';\n return undefined;\n }\n\n data.value = result;\n status.value = 'success';\n return result;\n } catch (caught) {\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n error.value = normalizedError;\n status.value = 'error';\n return undefined;\n }\n };\n\n const clear = (): void => {\n data.value = undefined;\n error.value = null;\n status.value = 'idle';\n };\n\n return {\n data,\n error,\n status,\n pending,\n submit,\n clear,\n };\n};\n\n// ---------------------------------------------------------------------------\n// createRestClient — imperative REST client\n// ---------------------------------------------------------------------------\n\n/** Typed CRUD methods for a REST endpoint. */\nexport interface RestClient<T = unknown> {\n /** GET all items. */\n list: (config?: HttpRequestConfig) => Promise<HttpResponse<T[]>>;\n /** GET a single item by ID. */\n get: (id: string | number, config?: HttpRequestConfig) => Promise<HttpResponse<T>>;\n /** POST a new item. */\n create: (\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** PUT (full replace) an item by ID. */\n update: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** PATCH (partial update) an item by ID. */\n patch: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** DELETE an item by ID. */\n remove: (id: string | number, config?: HttpRequestConfig) => Promise<HttpResponse<void>>;\n /** The underlying HttpClient instance. */\n http: HttpClient;\n}\n\n/**\n * Create a typed REST client for a specific API resource.\n *\n * Wraps `createHttp()` and maps standard CRUD operations to their\n * conventional REST endpoints (`GET /`, `GET /:id`, `POST /`, `PUT /:id`,\n * `PATCH /:id`, `DELETE /:id`).\n *\n * @template T - Resource item type\n * @param baseUrl - Base URL of the resource (e.g. `https://api.example.com/users`)\n * @param defaults - Default request configuration merged into every call\n * @returns Typed REST client with `list`, `get`, `create`, `update`, `patch`, `remove`\n *\n * @example\n * ```ts\n * import { createRestClient } from '@bquery/bquery/reactive';\n *\n * interface User { id: number; name: string; email: string }\n *\n * const users = createRestClient<User>('https://api.example.com/users', {\n * headers: { authorization: '******' },\n * timeout: 10_000,\n * });\n *\n * const { data: allUsers } = await users.list();\n * const { data: user } = await users.get(1);\n * const { data: created } = await users.create({ name: 'Ada' });\n * await users.update(1, { name: 'Ada', email: 'ada@example.com' });\n * await users.patch(1, { email: 'new@example.com' });\n * await users.remove(1);\n * ```\n */\nexport const createRestClient = <T = unknown>(\n baseUrl: string,\n defaults: HttpRequestConfig = {}\n): RestClient<T> => {\n const httpClient = createHttp({ ...defaults });\n\n // Ensure the base URL ends without a trailing slash for consistent joining\n let base = baseUrl;\n while (base.endsWith('/')) base = base.slice(0, -1);\n\n return {\n list: (config) => httpClient.get<T[]>(base, config),\n get: (id, config) => httpClient.get<T>(`${base}/${encodeURIComponent(String(id))}`, config),\n create: (body, config) => httpClient.post<T>(base, body as HttpRequestConfig['body'], config),\n update: (id, body, config) =>\n httpClient.put<T>(\n `${base}/${encodeURIComponent(String(id))}`,\n body as HttpRequestConfig['body'],\n config\n ),\n patch: (id, body, config) =>\n httpClient.patch<T>(\n `${base}/${encodeURIComponent(String(id))}`,\n body as HttpRequestConfig['body'],\n config\n ),\n remove: (id, config) =>\n httpClient.delete<void>(`${base}/${encodeURIComponent(String(id))}`, config),\n http: httpClient,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useResourceList — reactive collection CRUD\n// ---------------------------------------------------------------------------\n\n/** Extract a unique identifier from an item. */\nexport type IdExtractor<T> = (item: T) => string | number;\n\n/** Options for `useResourceList()`. */\nexport interface UseResourceListOptions<T = unknown> extends Omit<\n UseFetchOptions<T[]>,\n 'method' | 'body'\n> {\n /** Extract the unique ID from each item (default: `item.id`). */\n getId?: IdExtractor<T>;\n /** Enable optimistic list mutations (default: false). */\n optimistic?: boolean;\n /** Called after a successful list mutation. */\n onMutationSuccess?: (action: string) => void;\n /** Called after a failed list mutation. */\n onMutationError?: (error: Error, action: string) => void;\n}\n\n/** CRUD actions for a list resource. */\nexport interface ResourceListActions<T> {\n /** Refresh the list (GET). */\n fetch: () => Promise<T[] | undefined>;\n /** Add a new item to the list (POST). */\n add: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Update an existing item (PUT) by ID. */\n update: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>\n ) => Promise<T | undefined>;\n /** Partially update an existing item (PATCH) by ID. */\n patch: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>\n ) => Promise<T | undefined>;\n /** Remove an item from the list (DELETE) by ID. */\n remove: (id: string | number) => Promise<void>;\n}\n\n/** Return value of `useResourceList()`. */\nexport interface UseResourceListReturn<T> {\n /** Reactive list data. */\n data: Signal<T[] | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Whether the list fetch is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether any mutation is in progress. */\n isMutating: { readonly value: boolean; peek(): boolean };\n /** CRUD actions. */\n actions: ResourceListActions<T>;\n /** Refresh the list. */\n refresh: () => Promise<T[] | undefined>;\n /** Clear data, error, and status. */\n clear: () => void;\n /** Dispose all reactive state. */\n dispose: () => void;\n}\n\n/**\n * Reactive list/collection CRUD composable with optimistic add, remove, and update.\n *\n * Fetches a list of items and provides typed CRUD helpers that update the\n * reactive array optimistically or after server confirmation.\n *\n * @template T - Item type\n * @param url - List endpoint URL or getter\n * @param options - Fetch and list options\n * @returns Reactive list state with CRUD actions\n *\n * @example\n * ```ts\n * import { useResourceList } from '@bquery/bquery/reactive';\n *\n * interface Todo { id: number; title: string; done: boolean }\n *\n * const todos = useResourceList<Todo>('/api/todos', {\n * baseUrl: 'https://api.example.com',\n * optimistic: true,\n * getId: (t) => t.id,\n * });\n *\n * await todos.actions.add({ title: 'Buy milk', done: false });\n * await todos.actions.patch(1, { done: true });\n * await todos.actions.remove(1);\n * ```\n */\nexport const useResourceList = <T = unknown>(\n url: string | URL | (() => string | URL),\n options: UseResourceListOptions<T> = {}\n): UseResourceListReturn<T> => {\n const {\n getId = (item: T) => (item as Record<string, unknown>).id as string | number,\n optimistic = false,\n onMutationSuccess,\n onMutationError,\n ...fetchOptions\n } = options;\n\n const fetchState = useFetch<T[]>(url, { ...fetchOptions });\n\n const mutating = signal(false);\n const isMutating = computed(() => mutating.value);\n\n let disposed = false;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const baseUrl = (): string => {\n let base = resolveUrl();\n while (base.endsWith('/')) base = base.slice(0, -1);\n return base;\n };\n\n const toMutationFetchOptions = <TResult>(): Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n > => {\n // Strip list-level async-data defaults/callbacks; mutations operate on item payloads instead.\n const {\n defaultValue: _defaultValue,\n transform: _transform,\n onSuccess: _onSuccess,\n onError: _onError,\n ...transportOpts\n } = fetchOptions;\n return transportOpts as Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n >;\n };\n\n const runMutation = async <TResult>(\n action: string,\n method: string,\n urlSuffix: string,\n body: Record<string, unknown> | Partial<T> | undefined,\n applyOptimistic: (() => void) | undefined,\n rollback: (() => void) | undefined\n ): Promise<TResult | undefined> => {\n if (disposed) return undefined;\n\n if (optimistic && applyOptimistic) applyOptimistic();\n\n mutating.value = true;\n fetchState.error.value = null;\n\n try {\n const mutationUrl = `${baseUrl()}${urlSuffix}`;\n const mutationState = useFetch<TResult>(mutationUrl, {\n ...toMutationFetchOptions<TResult>(),\n method,\n body: body ?? undefined,\n immediate: false,\n watch: undefined,\n });\n\n const result = await mutationState.execute();\n const mutationError = mutationState.error.peek();\n mutationState.dispose();\n\n if (disposed) return undefined;\n\n if (mutationError) {\n if (optimistic && rollback) rollback();\n fetchState.error.value = mutationError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(mutationError, action);\n return undefined;\n }\n\n mutating.value = false;\n fetchState.status.value = 'success';\n onMutationSuccess?.(action);\n return result as TResult | undefined;\n } catch (caught) {\n if (disposed) return undefined;\n if (optimistic && rollback) rollback();\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n fetchState.error.value = normalizedError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(normalizedError, action);\n return undefined;\n }\n };\n\n const actions: ResourceListActions<T> = {\n fetch: () => fetchState.execute(),\n\n add: async (body) => {\n const previousList = fetchState.data.peek();\n const optimisticItem = body as T;\n const optimisticInsertionIndex = previousList?.length ?? 0;\n\n const result = await runMutation<T>(\n 'add',\n 'POST',\n '',\n body as Record<string, unknown>,\n optimistic\n ? () => {\n fetchState.data.value = [...(previousList ?? []), optimisticItem];\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n if (optimistic) {\n const next = [...current];\n // Replace the optimistic placeholder when it is still present; otherwise append.\n if (\n optimisticInsertionIndex < next.length &&\n next[optimisticInsertionIndex] === optimisticItem\n ) {\n next[optimisticInsertionIndex] = result;\n } else {\n next.push(result);\n }\n fetchState.data.value = next;\n } else {\n fetchState.data.value = [...current, result];\n }\n }\n\n return result;\n },\n\n update: async (id, body) => {\n const previousList = fetchState.data.peek();\n\n const result = await runMutation<T>(\n 'update',\n 'PUT',\n `/${encodeURIComponent(String(id))}`,\n body as Record<string, unknown>,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.map((item) =>\n getId(item) === id ? ({ ...item, ...body } as T) : item\n );\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.map((item) => (getId(item) === id ? result : item));\n }\n\n return result;\n },\n\n patch: async (id, body) => {\n const previousList = fetchState.data.peek();\n\n const result = await runMutation<T>(\n 'patch',\n 'PATCH',\n `/${encodeURIComponent(String(id))}`,\n body as Record<string, unknown>,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.map((item) =>\n getId(item) === id ? ({ ...item, ...body } as T) : item\n );\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.map((item) => (getId(item) === id ? result : item));\n }\n\n return result;\n },\n\n remove: async (id) => {\n const previousList = fetchState.data.peek();\n\n await runMutation<void>(\n 'remove',\n 'DELETE',\n `/${encodeURIComponent(String(id))}`,\n undefined,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.filter((item) => getId(item) !== id);\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n // If not optimistic, remove from the list after server confirms\n if (!optimistic && !disposed && fetchState.error.peek() == null) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.filter((item) => getId(item) !== id);\n }\n },\n };\n\n const originalDispose = fetchState.dispose;\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n originalDispose();\n };\n\n return {\n data: fetchState.data as Signal<T[] | undefined>,\n error: fetchState.error,\n status: fetchState.status,\n pending: fetchState.pending,\n isMutating,\n actions,\n refresh: fetchState.execute,\n clear: fetchState.clear,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// Request deduplication\n// ---------------------------------------------------------------------------\n\n/** @internal In-flight request/operation cache for deduplication. */\nconst inflightRequests = new Map<string, Promise<unknown>>();\n\n/**\n * Deduplicate identical in-flight requests or operations keyed by `key`.\n *\n * If an operation with the same key is already in flight, reuse its promise\n * instead of starting a new one. Once the operation completes, the entry is removed.\n *\n * @param key - Cache key for the in-flight operation (for HTTP, typically URL + serialized query)\n * @param execute - The operation function to run if no duplicate is in flight\n * @returns The shared result promise for callers using the same key concurrently\n *\n * @example\n * ```ts\n * import { deduplicateRequest, createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({ baseUrl: 'https://api.example.com' });\n *\n * // Both calls share the same in-flight operation\n * const [a, b] = await Promise.all([\n * deduplicateRequest('/users', () => api.get('/users')),\n * deduplicateRequest('/users', () => api.get('/users')),\n * ]);\n * ```\n */\nexport function deduplicateRequest<T>(key: string, execute: () => Promise<T>): Promise<T> {\n const existing = inflightRequests.get(key);\n if (existing) return existing as Promise<T>;\n\n const promise = execute().finally(() => {\n inflightRequests.delete(key);\n });\n\n inflightRequests.set(key, promise);\n return promise;\n}\n","/**\n * Type guards for reactive primitives.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\n\n/**\n * Type guard to check if a value is a Signal instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Signal\n */\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\n\n/**\n * Type guard to check if a value is a Computed instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Computed\n */\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\n","/**\n * Utility to unwrap reactive or plain values.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\nimport { readonly, isReadonlySignal } from './readonly';\n\n/**\n * A value that may be a raw value, a Signal, a `readonly()` wrapper, or a Computed.\n *\n * Useful for APIs that accept both reactive and plain inputs.\n *\n * Readonly wrappers are limited to the values returned by {@link readonly}. This keeps\n * the type aligned with runtime behavior, where arbitrary structural `{ value, peek }`\n * objects are intentionally returned unchanged.\n *\n * @template T - The underlying value type\n *\n * @example\n * ```ts\n * function useTitle(title: MaybeSignal<string>) {\n * document.title = toValue(title);\n * }\n *\n * useTitle('Hello'); // plain string\n * useTitle(signal('Hello')); // reactive signal\n * useTitle(computed(() => 'Hi')); // computed value\n * ```\n */\nexport type MaybeSignal<T> = T | Signal<T> | ReturnType<typeof readonly<T>> | Computed<T>;\n\n/**\n * Extracts the current value from a Signal, a bQuery `readonly()` wrapper, a\n * Computed, or returns the raw value as-is. This eliminates repetitive\n * `isSignal(x) ? x.value : x` patterns throughout user code.\n *\n * Reading a Signal or Computed via `toValue()` uses `.value`, so the\n * read **does** participate in reactive tracking when called inside\n * an effect or computed.\n *\n * @template T - The underlying value type\n * @param source - A plain value, Signal, bQuery readonly wrapper, or Computed\n * @returns The unwrapped value\n *\n * @example\n * ```ts\n * import { signal, computed, toValue } from '@bquery/bquery/reactive';\n *\n * const count = signal(5);\n * const doubled = computed(() => count.value * 2);\n *\n * toValue(42); // 42\n * toValue(count); // 5\n * toValue(doubled); // 10\n * toValue(null); // null\n * ```\n */\nexport const toValue = <T>(source: MaybeSignal<T>): T => {\n if (source instanceof Signal || source instanceof Computed) {\n return source.value;\n }\n\n if (isReadonlySignal<T>(source)) {\n return source.value;\n }\n\n // Remaining values are plain `T` inputs. Structural readonly-like objects that are not\n // branded bQuery wrappers intentionally fall through and are returned unchanged.\n return source as T;\n};\n","/**\n * Value watching helpers.\n */\n\nimport type { Computed } from './computed';\nimport type { Signal } from './core';\nimport type { CleanupFn } from './internals';\n\nimport { effect } from './effect';\n\n/**\n * Options for the watch function.\n */\nexport interface WatchOptions<T> {\n /** If true, the callback is invoked immediately with the current value. */\n immediate?: boolean;\n /** Custom equality function. Defaults to Object.is. */\n equals?: (a: T, b: T | undefined) => boolean;\n}\n\n/**\n * Watches a signal or computed value and calls a callback with old and new values.\n * Unlike effect, watch provides access to the previous value.\n * The callback is only invoked when the value actually changes (compared via Object.is or custom equals).\n *\n * @template T - The type of the watched value\n * @param source - The signal or computed to watch\n * @param callback - Function called with (newValue, oldValue) on changes\n * @param options - Watch options\n * @returns A cleanup function to stop watching\n *\n * @example\n * ```ts\n * const count = signal(0);\n * watch(count, (newVal, oldVal) => {\n * console.log(`Changed from ${oldVal} to ${newVal}`);\n * });\n *\n * // With custom equality for objects\n * const user = signal({ id: 1, name: 'Alice' });\n * watch(user, (newVal, oldVal) => { ... }, {\n * equals: (a, b) => a?.id === b?.id\n * });\n * ```\n */\nexport const watch = <T>(\n source: Signal<T> | Computed<T>,\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions<T> = {}\n): CleanupFn => {\n const { immediate = false, equals = Object.is } = options;\n let oldValue: T | undefined;\n let isFirst = true;\n\n return effect(() => {\n const newValue = source.value;\n\n if (isFirst) {\n isFirst = false;\n oldValue = newValue;\n if (immediate) {\n callback(newValue, undefined);\n }\n return;\n }\n\n // Only call callback if value actually changed\n if (!equals(newValue, oldValue)) {\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n });\n};\n","/**\n * Reactive WebSocket composable with auto-reconnect, heartbeat,\n * message history, and signal-based connection state.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Connection status for a WebSocket. */\nexport type WebSocketStatus = 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED';\n/** Connection status for an EventSource. */\nexport type EventSourceStatus = 'CONNECTING' | 'OPEN' | 'CLOSED';\n\n/** Configuration for automatic reconnection. */\nexport interface WebSocketReconnectConfig {\n /** Maximum number of reconnection attempts. Use `0` to disable reconnection (default: Infinity / unlimited). */\n maxAttempts?: number;\n /** Base delay in ms between reconnects (default: 1000). */\n delay?: number;\n /** Maximum delay in ms between reconnects (default: 30000). */\n maxDelay?: number;\n /** Multiply factor for exponential backoff (default: 2). */\n factor?: number;\n /** Custom predicate — return `false` to prevent a reconnect attempt. */\n shouldReconnect?: (event: CloseEvent, attempts: number) => boolean;\n}\n\n/** Reconnect configuration supported by `useEventSource()`. */\nexport type EventSourceReconnectConfig = Pick<\n WebSocketReconnectConfig,\n 'maxAttempts' | 'delay' | 'maxDelay' | 'factor'\n>;\n\n/** Configuration for keep-alive heartbeats. */\nexport interface WebSocketHeartbeatConfig {\n /** Outgoing ping message (default: `'ping'`). */\n message?: string | ArrayBufferLike | Blob | ArrayBufferView;\n /** Interval in ms between heartbeat pings (default: 30 000). */\n interval?: number;\n /** Time in ms to wait for a pong before assuming the connection is dead (default: 10 000). */\n pongTimeout?: number;\n /** Expected response message. If set, only messages matching this value reset the pong timer. */\n responseMessage?: string;\n}\n\n/** Serializer/deserializer for typed messaging. */\nexport interface WebSocketSerializer<TSend = unknown, TReceive = unknown> {\n /** Serialize a value before sending over the wire. Default: `JSON.stringify`. */\n serialize?: (data: TSend) => string | ArrayBufferLike | Blob | ArrayBufferView;\n /** Deserialize an incoming message. Default: `JSON.parse`. */\n deserialize?: (event: MessageEvent) => TReceive;\n}\n\n/** Full configuration accepted by `useWebSocket()`. */\nexport interface UseWebSocketOptions<\n TSend = unknown,\n TReceive = unknown,\n> extends WebSocketSerializer<TSend, TReceive> {\n /** Sub-protocols to request during the WebSocket handshake. */\n protocols?: string | string[];\n /** Open the connection immediately (default: true). */\n immediate?: boolean;\n /** Automatically reconnect on unexpected close (default: true). Pass `false` or config. */\n autoReconnect?: boolean | WebSocketReconnectConfig;\n /** Keep-alive heartbeat configuration. Pass `true` for defaults or a config object. */\n heartbeat?: boolean | WebSocketHeartbeatConfig;\n /** Maximum number of messages to keep in `history` (default: 0 = disabled). */\n historySize?: number;\n /** Called when the connection opens. */\n onOpen?: (event: Event) => void;\n /** Called when a message is received (after deserialization). */\n onMessage?: (data: TReceive, event: MessageEvent) => void;\n /** Called when the connection closes. */\n onClose?: (event: CloseEvent) => void;\n /** Called when a connection error occurs. */\n onError?: (event: Event) => void;\n /** Called after a successful reconnection. Receives the reconnection attempt count. */\n onReconnect?: (attempts: number) => void;\n}\n\n/** Return value of `useWebSocket()`. */\nexport interface UseWebSocketReturn<TSend = unknown, TReceive = unknown> {\n /** Reactive connection status. */\n status: { readonly value: WebSocketStatus; peek(): WebSocketStatus };\n /** Reactive last received message (deserialized). */\n data: Signal<TReceive | undefined>;\n /** Last error event. */\n error: Signal<Event | null>;\n /** Rolling message history (newest last). */\n history: Signal<TReceive[]>;\n /** Computed boolean — `true` when the socket is `OPEN`. */\n isConnected: { readonly value: boolean; peek(): boolean };\n /** Number of reconnection attempts since last successful open. */\n reconnectAttempts: Signal<number>;\n /** Round-trip latency in ms measured via heartbeat pings (requires `heartbeat` option). */\n latency: Signal<number>;\n /** Timestamp of the last unexpected disconnection, or 0 if never disconnected. */\n lastDisconnectedAt: Signal<number>;\n /**\n * Send a message.\n *\n * If the socket is not `OPEN`, the message is queued and sent once a\n * connection is (re)established, subject to the configured options.\n */\n send: (data: TSend) => void;\n /**\n * Send raw data without serialization.\n *\n * Uses the same queuing behavior as {@link send}: data is queued when the\n * socket is not `OPEN` and flushed once a connection is (re)established.\n */\n sendRaw: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;\n /** Manually open / reconnect the WebSocket. */\n open: () => void;\n /** Gracefully close the connection. */\n close: (code?: number, reason?: string) => void;\n /** Tear down all resources (close + remove listeners + stop reconnect/heartbeat). */\n dispose: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** @internal */\nfunction resolveReconnect(\n opt: UseWebSocketOptions['autoReconnect']\n): WebSocketReconnectConfig | false;\n/** @internal */\nfunction resolveReconnect(\n opt: UseEventSourceOptions['autoReconnect']\n): EventSourceReconnectConfig | false;\n/** @internal */\nfunction resolveReconnect(\n opt: boolean | WebSocketReconnectConfig | EventSourceReconnectConfig | undefined\n): WebSocketReconnectConfig | EventSourceReconnectConfig | false {\n if (opt === false) return false;\n if (opt === true || opt === undefined) return {};\n return opt;\n}\n\n/** @internal */\nconst resolveHeartbeat = (\n opt: UseWebSocketOptions['heartbeat']\n): WebSocketHeartbeatConfig | false => {\n if (!opt) return false;\n if (opt === true) return {};\n return opt;\n};\n\n/** @internal */\nconst computeDelay = (attempt: number, config: WebSocketReconnectConfig): number => {\n const base = config.delay ?? 1000;\n const factor = config.factor ?? 2;\n const max = config.maxDelay ?? 30_000;\n return Math.min(base * factor ** attempt, max);\n};\n\n// ---------------------------------------------------------------------------\n// useWebSocket\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive WebSocket composable with auto-reconnect, heartbeat,\n * typed messaging, and signal-based connection state.\n *\n * @template TSend - Type of outgoing messages (serialized via `serialize`)\n * @template TReceive - Type of incoming messages (deserialized via `deserialize`)\n * @param url - WebSocket URL (`ws://` or `wss://`) or a getter returning one\n * @param options - Connection, reconnect, heartbeat, and serialization options\n * @returns Reactive WebSocket state with `send()`, `open()`, `close()`, and `dispose()`\n *\n * @example\n * ```ts\n * import { useWebSocket } from '@bquery/bquery/reactive';\n *\n * const ws = useWebSocket<{ type: string; payload: unknown }>('wss://api.example.com/ws', {\n * autoReconnect: { maxAttempts: 5, delay: 2000 },\n * heartbeat: true,\n * historySize: 50,\n * onMessage: (data) => console.log('Received:', data),\n * });\n *\n * ws.send({ type: 'subscribe', payload: { channel: 'updates' } });\n *\n * // Reactive state\n * effect(() => {\n * console.log('Connected:', ws.isConnected.value);\n * console.log('Last message:', ws.data.value);\n * });\n *\n * // Cleanup\n * ws.dispose();\n * ```\n */\nexport const useWebSocket = <TSend = string, TReceive = string>(\n url: string | URL | (() => string | URL),\n options: UseWebSocketOptions<TSend, TReceive> = {}\n): UseWebSocketReturn<TSend, TReceive> => {\n const {\n protocols,\n immediate = true,\n historySize = 0,\n onOpen,\n onMessage,\n onClose,\n onError,\n onReconnect,\n } = options;\n\n const serialize = options.serialize ?? ((d: TSend) => JSON.stringify(d));\n const deserialize =\n options.deserialize ??\n ((event: MessageEvent) => {\n const raw = event.data;\n if (typeof raw === 'string') {\n try {\n return JSON.parse(raw) as TReceive;\n } catch {\n return raw as unknown as TReceive;\n }\n }\n return raw as TReceive;\n });\n\n // --- Reactive state ---\n const status = signal<WebSocketStatus>('CLOSED');\n const data = signal<TReceive | undefined>(undefined);\n const error = signal<Event | null>(null);\n const history = signal<TReceive[]>([]);\n const reconnectAttempts = signal(0);\n const latency = signal(0);\n const lastDisconnectedAt = signal(0);\n const isConnected = computed(() => status.value === 'OPEN');\n\n // --- Internal state ---\n let ws: WebSocket | null = null;\n let disposed = false;\n let explicitClose = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n let pongTimer: ReturnType<typeof setTimeout> | undefined;\n let internalReconnectCount = 0;\n let isAutoReconnecting = false;\n let pingSentAt = 0;\n const sendQueue: Array<string | ArrayBufferLike | Blob | ArrayBufferView> = [];\n\n const reconnectConfig = resolveReconnect(options.autoReconnect);\n const heartbeatConfig = resolveHeartbeat(options.heartbeat);\n\n // --- Heartbeat ---\n const startHeartbeat = (): void => {\n if (!heartbeatConfig) return;\n stopHeartbeat();\n const interval = heartbeatConfig.interval ?? 30_000;\n const timeout = heartbeatConfig.pongTimeout ?? 10_000;\n const pingMsg = heartbeatConfig.message ?? 'ping';\n\n heartbeatTimer = setInterval(() => {\n if (ws?.readyState === WebSocket.OPEN) {\n pingSentAt = Date.now();\n ws.send(pingMsg);\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n }\n pongTimer = setTimeout(() => {\n // No pong received — force close to trigger reconnect\n ws?.close(4000, 'Heartbeat timeout');\n }, timeout);\n }\n }, interval);\n };\n\n const stopHeartbeat = (): void => {\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n }\n };\n\n const resetPongTimer = (): void => {\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n }\n if (pingSentAt > 0) {\n latency.value = Date.now() - pingSentAt;\n pingSentAt = 0;\n }\n };\n\n // --- Reconnect ---\n const scheduleReconnect = (event: CloseEvent): void => {\n if (disposed || explicitClose || !reconnectConfig) return;\n\n const maxAttempts = reconnectConfig.maxAttempts ?? Infinity;\n\n if (internalReconnectCount >= maxAttempts) return;\n\n if (\n reconnectConfig.shouldReconnect &&\n !reconnectConfig.shouldReconnect(event, internalReconnectCount)\n ) {\n return;\n }\n\n const delay = computeDelay(internalReconnectCount, reconnectConfig);\n reconnectTimer = setTimeout(() => {\n internalReconnectCount++;\n reconnectAttempts.value = internalReconnectCount;\n isAutoReconnecting = true;\n open();\n }, delay);\n };\n\n const cancelReconnect = (): void => {\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n };\n\n // --- Queue ---\n const flushQueue = (): void => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n let index = 0;\n for (; index < sendQueue.length; index++) {\n if (ws.readyState !== WebSocket.OPEN) {\n break;\n }\n ws.send(sendQueue[index]);\n }\n\n if (index > 0) {\n sendQueue.splice(0, index);\n }\n };\n\n // --- Core ---\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const open = (): void => {\n if (disposed) return;\n cancelReconnect();\n\n // Clean up any existing connection\n if (ws) {\n stopHeartbeat();\n pingSentAt = 0;\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n ws = null;\n }\n\n explicitClose = false;\n status.value = 'CONNECTING';\n error.value = null;\n\n try {\n ws = new WebSocket(resolveUrl(), protocols);\n } catch {\n status.value = 'CLOSED';\n return;\n }\n\n ws.onopen = (event: Event): void => {\n status.value = 'OPEN';\n const wasReconnecting = isAutoReconnecting;\n const reconnectCount = internalReconnectCount;\n internalReconnectCount = 0;\n reconnectAttempts.value = 0;\n isAutoReconnecting = false;\n flushQueue();\n startHeartbeat();\n onOpen?.(event);\n if (wasReconnecting) {\n onReconnect?.(reconnectCount);\n }\n };\n\n ws.onmessage = (event: MessageEvent): void => {\n // Heartbeat pong detection\n if (heartbeatConfig) {\n const responseMsg = heartbeatConfig.responseMessage;\n if (responseMsg === undefined || event.data === responseMsg) {\n resetPongTimer();\n }\n }\n\n const deserialized = deserialize(event);\n data.value = deserialized;\n\n if (historySize > 0) {\n const current = history.peek();\n const updated = [...current, deserialized];\n history.value = updated.length > historySize ? updated.slice(-historySize) : updated;\n }\n\n onMessage?.(deserialized, event);\n };\n\n ws.onclose = (event: CloseEvent): void => {\n status.value = 'CLOSED';\n stopHeartbeat();\n\n if (!explicitClose) {\n lastDisconnectedAt.value = Date.now();\n }\n\n onClose?.(event);\n\n if (!explicitClose && !disposed) {\n scheduleReconnect(event);\n }\n };\n\n ws.onerror = (event: Event): void => {\n error.value = event;\n onError?.(event);\n };\n };\n\n const close = (code?: number, reason?: string): void => {\n explicitClose = true;\n cancelReconnect();\n stopHeartbeat();\n\n if (ws) {\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n status.value = 'CLOSING';\n ws.close(code, reason);\n }\n }\n };\n\n const send = (msg: TSend): void => {\n if (disposed) return;\n const serialized = serialize(msg);\n sendRaw(serialized);\n };\n\n const sendRaw = (raw: string | ArrayBufferLike | Blob | ArrayBufferView): void => {\n if (disposed) return;\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(raw);\n } else {\n sendQueue.push(raw);\n }\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n close();\n sendQueue.length = 0;\n ws = null;\n };\n\n // --- Start ---\n if (immediate) {\n open();\n }\n\n return {\n status,\n data,\n error,\n history,\n isConnected,\n reconnectAttempts,\n latency,\n lastDisconnectedAt,\n send,\n sendRaw,\n open,\n close,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useWebSocketChannel — topic-based multiplexer\n// ---------------------------------------------------------------------------\n\n/** Default channel message format used by `useWebSocketChannel()`. */\nexport interface ChannelMessage<T = unknown> {\n /** Channel / topic name. */\n channel: string;\n /** Message payload. */\n data: T;\n}\n\n/** Configuration for `useWebSocketChannel()`. */\nexport interface UseWebSocketChannelOptions<TSend = unknown, TReceive = unknown> {\n /**\n * Extract the channel name from an incoming deserialized message.\n * Default: reads `(msg as ChannelMessage).channel`.\n */\n getChannel?: (msg: TReceive) => string | undefined;\n /**\n * Wrap a payload + channel into the wire format before sending.\n * Default: `{ channel, data }`.\n */\n wrap?: (channel: string, data: TSend) => TReceive;\n}\n\n/** A single channel subscription returned by `subscribe()`. */\nexport interface ChannelSubscription<TReceive = unknown> {\n /** Reactive last message received on this channel. */\n data: Signal<TReceive | undefined>;\n /** Unsubscribe from this channel. */\n unsubscribe: () => void;\n}\n\n/** Return value of `useWebSocketChannel()`. */\nexport interface UseWebSocketChannelReturn<TSend = unknown, TReceive = unknown> {\n /** Subscribe to a topic. Multiple subscriptions to the same channel share a signal. */\n subscribe: (channel: string) => ChannelSubscription<TReceive>;\n /** Publish a message to a channel. */\n publish: (channel: string, data: TSend) => void;\n /** The underlying `useWebSocket` return for direct access. */\n ws: UseWebSocketReturn<TReceive, TReceive>;\n}\n\n/**\n * Topic-based channel multiplexer over a single WebSocket connection.\n *\n * Builds on `useWebSocket()` and routes incoming messages to per-channel\n * reactive signals based on a configurable channel extractor.\n *\n * @template TSend - Type of outgoing message payloads\n * @template TReceive - Type of incoming deserialized messages\n * @param url - WebSocket URL\n * @param wsOptions - All `useWebSocket` options\n * @param channelOptions - Channel routing configuration\n * @returns Channel multiplexer with `subscribe()`, `publish()`, and the underlying `ws`\n *\n * @example\n * ```ts\n * import { useWebSocketChannel } from '@bquery/bquery/reactive';\n *\n * const chat = useWebSocketChannel('wss://chat.example.com/ws');\n *\n * const general = chat.subscribe('general');\n * const updates = chat.subscribe('updates');\n *\n * effect(() => console.log('General:', general.data.value));\n *\n * chat.publish('general', { text: 'Hello!' });\n * ```\n */\nexport const useWebSocketChannel = <TSend = unknown, TReceive = unknown>(\n url: string | URL | (() => string | URL),\n wsOptions: UseWebSocketOptions<TReceive, TReceive> = {},\n channelOptions: UseWebSocketChannelOptions<TSend, TReceive> = {}\n): UseWebSocketChannelReturn<TSend, TReceive> => {\n const getChannel =\n channelOptions.getChannel ?? ((msg: TReceive) => (msg as ChannelMessage).channel);\n\n const wrap =\n channelOptions.wrap ??\n ((ch: string, data: TSend) => ({ channel: ch, data }) as unknown as TReceive);\n\n const channels = new Map<string, Signal<TReceive | undefined>>();\n const channelSubscriptions = new Map<string, number>();\n\n const ws = useWebSocket<TReceive, TReceive>(url, {\n ...wsOptions,\n onMessage: (msg, event) => {\n const ch = getChannel(msg);\n if (ch !== undefined) {\n const sig = channels.get(ch);\n if (sig) {\n sig.value = msg;\n }\n }\n wsOptions.onMessage?.(msg, event);\n },\n });\n\n const subscribe = (channel: string): ChannelSubscription<TReceive> => {\n let sig = channels.get(channel);\n if (!sig) {\n sig = signal<TReceive | undefined>(undefined);\n channels.set(channel, sig);\n }\n channelSubscriptions.set(channel, (channelSubscriptions.get(channel) ?? 0) + 1);\n let unsubscribed = false;\n\n return {\n data: sig,\n unsubscribe: () => {\n if (unsubscribed) return;\n unsubscribed = true;\n const remaining = (channelSubscriptions.get(channel) ?? 1) - 1;\n if (remaining <= 0) {\n channelSubscriptions.delete(channel);\n channels.delete(channel);\n } else {\n channelSubscriptions.set(channel, remaining);\n }\n },\n };\n };\n\n const publish = (channel: string, data: TSend): void => {\n ws.send(wrap(channel, data));\n };\n\n return { subscribe, publish, ws };\n};\n\n// ---------------------------------------------------------------------------\n// useEventSource\n// ---------------------------------------------------------------------------\n\n/** Configuration for `useEventSource()`. */\nexport interface UseEventSourceOptions<TData = unknown> {\n /** Whether to open the connection immediately (default: true). */\n immediate?: boolean;\n /** Automatically reconnect on error (default: true). Pass a reconnect config to customize delay and attempt limits. */\n autoReconnect?: boolean | EventSourceReconnectConfig;\n /** Event names to listen for besides the default `message` event. */\n events?: string[];\n /** Deserializer for incoming event data. Default: `JSON.parse` with string fallback. */\n deserialize?: (data: string) => TData;\n /** EventSource init options (e.g. `withCredentials`). */\n eventSourceInit?: EventSourceInit;\n /** Called when the connection opens. */\n onOpen?: (event: Event) => void;\n /** Called when a message is received. */\n onMessage?: (data: TData, event: MessageEvent) => void;\n /** Called when an error occurs. */\n onError?: (event: Event) => void;\n}\n\n/** Return value of `useEventSource()`. */\nexport interface UseEventSourceReturn<TData = unknown> {\n /** Current connection status (`CONNECTING`, `OPEN`, `CLOSED`). */\n status: { readonly value: EventSourceStatus; peek(): EventSourceStatus };\n /** Last received data (deserialized). */\n data: Signal<TData | undefined>;\n /** Last event name that delivered data. */\n eventName: Signal<string | undefined>;\n /** Last error event. */\n error: Signal<Event | null>;\n /** Computed boolean — `true` when the EventSource is open. */\n isConnected: { readonly value: boolean; peek(): boolean };\n /** Manually open / reconnect the EventSource. */\n open: () => void;\n /** Close the connection. */\n close: () => void;\n /** Tear down all resources. */\n dispose: () => void;\n}\n\n/**\n * Reactive Server-Sent Events (SSE) composable.\n *\n * Wraps the native `EventSource` API with reactive signals, auto-reconnect,\n * and typed deserialization.\n *\n * @template TData - Type of deserialized event data\n * @param url - SSE endpoint URL or a getter returning one\n * @param options - EventSource options\n * @returns Reactive EventSource state with `open()`, `close()`, and `dispose()`\n *\n * @example\n * ```ts\n * import { useEventSource } from '@bquery/bquery/reactive';\n *\n * const sse = useEventSource<{ type: string; message: string }>('/api/events', {\n * events: ['notification', 'update'],\n * onMessage: (data) => console.log('Event:', data),\n * });\n *\n * effect(() => {\n * if (sse.data.value) {\n * console.log(`[${sse.eventName.value}]`, sse.data.value);\n * }\n * });\n *\n * sse.dispose();\n * ```\n */\nexport const useEventSource = <TData = unknown>(\n url: string | URL | (() => string | URL),\n options: UseEventSourceOptions<TData> = {}\n): UseEventSourceReturn<TData> => {\n const { immediate = true, events = [], eventSourceInit, onOpen, onMessage, onError } = options;\n\n const deserialize =\n options.deserialize ??\n ((raw: string) => {\n try {\n return JSON.parse(raw) as TData;\n } catch {\n return raw as unknown as TData;\n }\n });\n\n const status = signal<EventSourceStatus>('CLOSED');\n const data = signal<TData | undefined>(undefined);\n const eventName = signal<string | undefined>(undefined);\n const error = signal<Event | null>(null);\n const isConnected = computed(() => status.value === 'OPEN');\n\n const reconnectConfig = resolveReconnect(options.autoReconnect);\n\n let es: EventSource | null = null;\n let disposed = false;\n let explicitClose = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let reconnectAttemptCount = 0;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const handleMessage =\n (name: string) =>\n (event: MessageEvent): void => {\n const deserialized = deserialize(event.data);\n data.value = deserialized;\n eventName.value = name;\n onMessage?.(deserialized, event);\n };\n\n const cancelReconnect = (): void => {\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n };\n\n const scheduleReconnect = (): void => {\n if (disposed || explicitClose || !reconnectConfig) return;\n\n const maxAttempts = reconnectConfig.maxAttempts ?? Infinity;\n if (reconnectAttemptCount >= maxAttempts) return;\n\n const delay = computeDelay(reconnectAttemptCount, reconnectConfig);\n reconnectTimer = setTimeout(() => {\n reconnectAttemptCount++;\n open();\n }, delay);\n };\n\n const open = (): void => {\n if (disposed) return;\n cancelReconnect();\n\n if (es) {\n es.close();\n es = null;\n }\n\n explicitClose = false;\n status.value = 'CONNECTING';\n error.value = null;\n\n try {\n es = new EventSource(resolveUrl(), eventSourceInit);\n } catch {\n status.value = 'CLOSED';\n return;\n }\n\n es.onopen = (event: Event): void => {\n status.value = 'OPEN';\n reconnectAttemptCount = 0;\n onOpen?.(event);\n };\n\n es.onerror = (event: Event): void => {\n error.value = event;\n onError?.(event);\n\n // EventSource closes on error when readyState is CLOSED\n if (es?.readyState === EventSource.CLOSED) {\n status.value = 'CLOSED';\n if (!explicitClose && !disposed) {\n scheduleReconnect();\n }\n }\n };\n\n // Default \"message\" event\n es.addEventListener('message', handleMessage('message'));\n\n // Named events\n for (const name of events) {\n es.addEventListener(name, handleMessage(name) as EventListener);\n }\n };\n\n const close = (): void => {\n explicitClose = true;\n cancelReconnect();\n if (es) {\n es.close();\n es = null;\n }\n status.value = 'CLOSED';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n close();\n };\n\n if (immediate) {\n open();\n }\n\n return {\n status,\n data,\n eventName,\n error,\n isConnected,\n open,\n close,\n dispose,\n };\n};\n"],"mappings":"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"}
|
package/dist/reactive.es.mjs
CHANGED
|
@@ -1,22 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import { n as
|
|
4
|
-
import { t as y } from "./untrack-B0rVscTc.js";
|
|
1
|
+
import { c as s, i as a, n as t, o as u, r as c, t as o } from "./core-DdtZHzsS.js";
|
|
2
|
+
import { C as i, D as n, E as p, S as l, T as S, _ as m, a as d, b as f, c as g, d as h, f as C, g as b, h as R, i as k, l as F, m as y, n as D, o as E, r as q, s as v, t as w, u as x, v as H, w as P, x as W, y as A } from "./reactive-DwkhUJfP.js";
|
|
3
|
+
import { n as L, r as Q, t as T } from "./untrack-D0fnO5k2.js";
|
|
5
4
|
export {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
i as
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
L as Computed,
|
|
6
|
+
f as HttpError,
|
|
7
|
+
o as Signal,
|
|
8
|
+
n as batch,
|
|
9
|
+
Q as computed,
|
|
10
|
+
W as createHttp,
|
|
11
|
+
l as createRequestQueue,
|
|
12
|
+
g as createRestClient,
|
|
13
|
+
P as createUseFetch,
|
|
14
|
+
F as deduplicateRequest,
|
|
15
|
+
c as effect,
|
|
16
|
+
a as effectScope,
|
|
17
|
+
u as getCurrentScope,
|
|
18
|
+
i as http,
|
|
19
|
+
E as isComputed,
|
|
20
|
+
v as isSignal,
|
|
21
|
+
A as linkedSignal,
|
|
22
|
+
s as onScopeDispose,
|
|
23
|
+
b as persistedSignal,
|
|
24
|
+
y as readonly,
|
|
25
|
+
t as signal,
|
|
26
|
+
d as toValue,
|
|
27
|
+
T as untrack,
|
|
28
|
+
S as useAsyncData,
|
|
29
|
+
w as useEventSource,
|
|
30
|
+
p as useFetch,
|
|
31
|
+
m as useInfiniteFetch,
|
|
32
|
+
H as usePaginatedFetch,
|
|
33
|
+
R as usePolling,
|
|
34
|
+
x as useResource,
|
|
35
|
+
h as useResourceList,
|
|
36
|
+
C as useSubmit,
|
|
37
|
+
D as useWebSocket,
|
|
38
|
+
q as useWebSocketChannel,
|
|
39
|
+
k as watch
|
|
22
40
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var n = () => {
|
|
2
|
+
if (!(typeof window > "u"))
|
|
3
|
+
return window.__BQUERY_DEVTOOLS__ || (window.__BQUERY_DEVTOOLS__ = { stores: /* @__PURE__ */ new Map() }), window.__BQUERY_DEVTOOLS__;
|
|
4
|
+
}, _ = (e, r) => {
|
|
5
|
+
const o = n();
|
|
6
|
+
o && (o.stores.set(e, r), o.onStoreCreated?.(e, r));
|
|
7
|
+
}, s = (e) => {
|
|
8
|
+
typeof window > "u" || !window.__BQUERY_DEVTOOLS__ || window.__BQUERY_DEVTOOLS__.stores.delete(e);
|
|
9
|
+
}, a = (e, r) => {
|
|
10
|
+
typeof window > "u" || window.__BQUERY_DEVTOOLS__?.onStateChange?.(e, r);
|
|
11
|
+
}, t = /* @__PURE__ */ new Map(), i = (e) => t.has(e), w = (e, r) => {
|
|
12
|
+
t.set(e, r);
|
|
13
|
+
}, d = (e) => t.get(e), v = () => Array.from(t.keys()), S = (e) => {
|
|
14
|
+
t.delete(e), s(e);
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
w as a,
|
|
18
|
+
v as i,
|
|
19
|
+
d as n,
|
|
20
|
+
a as o,
|
|
21
|
+
i as r,
|
|
22
|
+
_ as s,
|
|
23
|
+
S as t
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=registry-B08iilIh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-B08iilIh.js","names":[],"sources":["../src/store/devtools.ts","../src/store/registry.ts"],"sourcesContent":["/**\n * Devtools integration for stores.\n * @internal\n */\n\ndeclare global {\n interface Window {\n __BQUERY_DEVTOOLS__?: {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n };\n }\n}\n\nexport type DevtoolsHook = {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n};\n\nconst ensureDevtools = (): DevtoolsHook | undefined => {\n if (typeof window === 'undefined') return undefined;\n if (!window.__BQUERY_DEVTOOLS__) {\n window.__BQUERY_DEVTOOLS__ = { stores: new Map() };\n }\n return window.__BQUERY_DEVTOOLS__;\n};\n\nexport const registerDevtoolsStore = (id: string, store: unknown): void => {\n const devtools = ensureDevtools();\n if (!devtools) return;\n devtools.stores.set(id, store);\n devtools.onStoreCreated?.(id, store);\n};\n\nexport const unregisterDevtoolsStore = (id: string): void => {\n if (typeof window === 'undefined' || !window.__BQUERY_DEVTOOLS__) return;\n window.__BQUERY_DEVTOOLS__.stores.delete(id);\n};\n\nexport const notifyDevtoolsStateChange = (id: string, state: unknown): void => {\n if (typeof window === 'undefined') return;\n window.__BQUERY_DEVTOOLS__?.onStateChange?.(id, state);\n};\n","/**\n * Store registry utilities.\n */\n\nimport { unregisterDevtoolsStore } from './devtools';\nimport type { Store } from './types';\n\n/** @internal Registry of all stores for devtools */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst storeRegistry = new Map<string, Store<any, any, any>>();\n\n/** @internal */\nexport const hasStore = (id: string): boolean => storeRegistry.has(id);\n\n/** @internal */\nexport const registerStore = (\n id: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>\n): void => {\n storeRegistry.set(id, store);\n};\n\n/**\n * Retrieves an existing store by its ID.\n *\n * @param id - The store identifier\n * @returns The store instance or undefined if not found\n */\nexport const getStore = <T = unknown>(id: string): T | undefined => {\n return storeRegistry.get(id) as T | undefined;\n};\n\n/**\n * Lists all registered store IDs.\n *\n * @returns Array of store IDs\n */\nexport const listStores = (): string[] => {\n return Array.from(storeRegistry.keys());\n};\n\n/**\n * Removes a store from the registry.\n *\n * @param id - The store identifier\n */\nexport const destroyStore = (id: string): void => {\n storeRegistry.delete(id);\n unregisterDevtoolsStore(id);\n};\n"],"mappings":"AAqBA,IAAM,IAAA,MAAiD;AACrD,MAAI,SAAO,SAAW;AACtB,WAAK,OAAO,wBACV,OAAO,sBAAsB,EAAE,QAAQ,oBAAI,IAAA,EAAK,IAE3C,OAAO;GAGH,IAAA,CAAyB,GAAY,MAAyB;AACzE,QAAM,IAAW,EAAA;AACjB,EAAK,MACL,EAAS,OAAO,IAAI,GAAI,CAAA,GACxB,EAAS,iBAAiB,GAAI,CAAA;GAGnB,IAAA,CAA2B,MAAqB;AAC3D,EAAI,OAAO,SAAW,OAAe,CAAC,OAAO,uBAC7C,OAAO,oBAAoB,OAAO,OAAO,CAAA;GAG9B,IAAA,CAA6B,GAAY,MAAyB;AAC7E,EAAI,OAAO,SAAW,OACtB,OAAO,qBAAqB,gBAAgB,GAAI,CAAA;GClC5C,IAAgB,oBAAI,IAAA,GAGb,IAAA,CAAY,MAAwB,EAAc,IAAI,CAAA,GAGtD,IAAA,CACX,GAEA,MACS;AACT,EAAA,EAAc,IAAI,GAAI,CAAA;GASX,IAAA,CAAyB,MAC7B,EAAc,IAAI,CAAA,GAQd,IAAA,MACJ,MAAM,KAAK,EAAc,KAAA,CAAM,GAQ3B,IAAA,CAAgB,MAAqB;AAChD,EAAA,EAAc,OAAO,CAAA,GACrB,EAAwB,CAAA"}
|