@bquery/bquery 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +716 -586
- 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-C5QOVvRn.js +421 -0
- package/dist/a11y-C5QOVvRn.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-CuuTijA6.js +684 -0
- package/dist/component-CuuTijA6.js.map +1 -0
- package/dist/component.es.mjs +9 -6
- package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
- package/dist/{config-DRmZZno3.js.map → config-BW35FKuA.js.map} +1 -1
- package/dist/constraints-3lV9yyBw.js +100 -0
- package/dist/constraints-3lV9yyBw.js.map +1 -0
- package/dist/core/collection.d.ts +48 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +92 -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 +8 -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-Cjl7GUu8.js +717 -0
- package/dist/core-Cjl7GUu8.js.map +1 -0
- package/dist/core-DnlyjbF2.js +112 -0
- package/dist/core-DnlyjbF2.js.map +1 -0
- package/dist/core.es.mjs +45 -44
- package/dist/custom-directives-7wAShnnd.js +9 -0
- package/dist/custom-directives-7wAShnnd.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-D2fQLhDN.js +122 -0
- package/dist/devtools-D2fQLhDN.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-B8EgyzaI.js +244 -0
- package/dist/dnd-B8EgyzaI.js.map +1 -0
- package/dist/dnd.es.mjs +6 -0
- package/dist/env-NeVmr4Gf.js +19 -0
- package/dist/env-NeVmr4Gf.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 +39 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +139 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +179 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms-C3yovgH9.js +141 -0
- package/dist/forms-C3yovgH9.js.map +1 -0
- package/dist/forms.es.mjs +14 -0
- package/dist/full.d.ts +35 -7
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +182 -91
- 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/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-BnnhTFOS.js +89 -0
- package/dist/i18n-BnnhTFOS.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 +227 -136
- 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-Di2Ta22s.js +340 -0
- package/dist/media-Di2Ta22s.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-qPj_TYGv.js +530 -0
- package/dist/motion-qPj_TYGv.js.map +1 -0
- package/dist/motion.es.mjs +27 -23
- package/dist/{view-C70lA3vf.js → mount-SM07RUa6.js} +166 -160
- package/dist/mount-SM07RUa6.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-CPbCprb6.js} +21 -22
- package/dist/{platform-Dr9b6fsq.js.map → platform-CPbCprb6.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-cPoOHFLY.js +64 -0
- package/dist/plugin-cPoOHFLY.js.map +1 -0
- package/dist/plugin.es.mjs +9 -0
- package/dist/reactive/computed.d.ts +7 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive-Cfv0RK6x.js +233 -0
- package/dist/reactive-Cfv0RK6x.js.map +1 -0
- package/dist/reactive.es.mjs +19 -20
- package/dist/registry-CWf368tT.js +26 -0
- package/dist/registry-CWf368tT.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 +14 -6
- 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/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-BrthaP_z.js +473 -0
- package/dist/router-BrthaP_z.js.map +1 -0
- package/dist/router.es.mjs +13 -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-B2qd_WBB.js +248 -0
- package/dist/ssr-B2qd_WBB.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-DWpyH6p5.js +338 -0
- package/dist/store-DWpyH6p5.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-CsqjNUyy.js +224 -0
- package/dist/testing-CsqjNUyy.js.map +1 -0
- package/dist/testing.es.mjs +9 -0
- package/dist/type-guards-Do9DWgNp.js +44 -0
- package/dist/type-guards-Do9DWgNp.js.map +1 -0
- package/dist/untrack-DJVQQ2WM.js +33 -0
- package/dist/untrack-DJVQQ2WM.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 +177 -141
- 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 +104 -29
- package/src/component/html.ts +5 -5
- package/src/component/index.ts +2 -0
- package/src/component/library.ts +26 -2
- package/src/component/scope.ts +212 -0
- package/src/component/types.ts +94 -40
- package/src/core/collection.ts +707 -628
- package/src/core/element.ts +981 -774
- package/src/core/env.ts +60 -0
- package/src/core/index.ts +49 -48
- package/src/core/shared.ts +62 -13
- package/src/core/utils/index.ts +148 -83
- 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 +278 -0
- package/src/forms/index.ts +65 -0
- package/src/forms/types.ts +154 -0
- package/src/forms/validators.ts +265 -0
- package/src/full.ts +253 -2
- 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 +108 -36
- package/src/media/battery.ts +116 -0
- package/src/media/breakpoints.ts +131 -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 +57 -48
- package/src/motion/morph.ts +151 -0
- package/src/motion/parallax.ts +120 -0
- package/src/motion/reduced-motion.ts +66 -17
- package/src/motion/types.ts +271 -208
- package/src/motion/typewriter.ts +164 -0
- package/src/plugin/index.ts +37 -0
- package/src/plugin/registry.ts +269 -0
- package/src/plugin/types.ts +137 -0
- package/src/reactive/computed.ts +130 -92
- package/src/router/bq-link.ts +279 -0
- package/src/router/constraints.ts +201 -0
- package/src/router/index.ts +49 -41
- package/src/router/match.ts +312 -106
- package/src/router/path-pattern.ts +52 -0
- package/src/router/query.ts +38 -35
- package/src/router/router.ts +402 -211
- package/src/router/types.ts +139 -93
- package/src/router/use-route.ts +68 -0
- package/src/router/utils.ts +157 -116
- package/src/security/index.ts +2 -7
- package/src/security/sanitize.ts +70 -70
- package/src/security/trusted-html.ts +71 -71
- package/src/ssr/hydrate.ts +82 -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 +467 -329
- package/src/store/define-store.ts +49 -49
- package/src/store/index.ts +27 -22
- package/src/store/mapping.ts +74 -74
- package/src/store/persisted.ts +206 -19
- package/src/store/types.ts +157 -2
- package/src/store/utils.ts +135 -141
- package/src/store/watch.ts +53 -53
- package/src/storybook/index.ts +2 -1
- 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 +30 -0
- package/src/view/evaluate.ts +292 -290
- package/src/view/process.ts +108 -92
- 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 +0 -648
- 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
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Store factory helpers.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createStore } from './create-store';
|
|
6
|
-
import { getStore, hasStore } from './registry';
|
|
7
|
-
import type { Store, StoreDefinition } from './types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Creates a store factory that returns the store instance.
|
|
11
|
-
*
|
|
12
|
-
* The store is lazily created on first call and cached in the global store
|
|
13
|
-
* registry. Subsequent calls return the same instance. After calling
|
|
14
|
-
* `destroyStore(id)`, the next factory call will create a fresh store.
|
|
15
|
-
*
|
|
16
|
-
* @param id - Store identifier
|
|
17
|
-
* @param definition - Store definition without id
|
|
18
|
-
* @returns A function that returns the store instance
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* const useCounter = defineStore('counter', {
|
|
23
|
-
* state: () => ({ count: 0 }),
|
|
24
|
-
* actions: { increment() { this.count++; } },
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* const counter = useCounter();
|
|
28
|
-
* counter.increment();
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export const defineStore = <
|
|
32
|
-
S extends Record<string, unknown>,
|
|
33
|
-
G extends Record<string, unknown> = Record<string, never>,
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types
|
|
35
|
-
A extends Record<string, (...args: any[]) => any> = Record<string, never>,
|
|
36
|
-
>(
|
|
37
|
-
id: string,
|
|
38
|
-
definition: Omit<StoreDefinition<S, G, A>, 'id'>
|
|
39
|
-
): (() => Store<S, G, A>) => {
|
|
40
|
-
// Check registry first to avoid noisy warnings from createStore()
|
|
41
|
-
// when the factory is called multiple times (intended usage pattern).
|
|
42
|
-
// createStore() only called when store doesn't exist or was destroyed.
|
|
43
|
-
return () => {
|
|
44
|
-
if (hasStore(id)) {
|
|
45
|
-
return getStore(id) as Store<S, G, A>;
|
|
46
|
-
}
|
|
47
|
-
return createStore({ id, ...definition });
|
|
48
|
-
};
|
|
49
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Store factory helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createStore } from './create-store';
|
|
6
|
+
import { getStore, hasStore } from './registry';
|
|
7
|
+
import type { Store, StoreDefinition } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a store factory that returns the store instance.
|
|
11
|
+
*
|
|
12
|
+
* The store is lazily created on first call and cached in the global store
|
|
13
|
+
* registry. Subsequent calls return the same instance. After calling
|
|
14
|
+
* `destroyStore(id)`, the next factory call will create a fresh store.
|
|
15
|
+
*
|
|
16
|
+
* @param id - Store identifier
|
|
17
|
+
* @param definition - Store definition without id
|
|
18
|
+
* @returns A function that returns the store instance
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const useCounter = defineStore('counter', {
|
|
23
|
+
* state: () => ({ count: 0 }),
|
|
24
|
+
* actions: { increment() { this.count++; } },
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* const counter = useCounter();
|
|
28
|
+
* counter.increment();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const defineStore = <
|
|
32
|
+
S extends Record<string, unknown>,
|
|
33
|
+
G extends Record<string, unknown> = Record<string, never>,
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types
|
|
35
|
+
A extends Record<string, (...args: any[]) => any> = Record<string, never>,
|
|
36
|
+
>(
|
|
37
|
+
id: string,
|
|
38
|
+
definition: Omit<StoreDefinition<S, G, A>, 'id'>
|
|
39
|
+
): (() => Store<S, G, A>) => {
|
|
40
|
+
// Check registry first to avoid noisy warnings from createStore()
|
|
41
|
+
// when the factory is called multiple times (intended usage pattern).
|
|
42
|
+
// createStore() only called when store doesn't exist or was destroyed.
|
|
43
|
+
return () => {
|
|
44
|
+
if (hasStore(id)) {
|
|
45
|
+
return getStore(id) as Store<S, G, A>;
|
|
46
|
+
}
|
|
47
|
+
return createStore({ id, ...definition });
|
|
48
|
+
};
|
|
49
|
+
};
|
package/src/store/index.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Store module exports.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
1
|
+
/**
|
|
2
|
+
* Store module exports.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
ActionContext,
|
|
7
|
+
Actions,
|
|
8
|
+
Getters,
|
|
9
|
+
OnActionCallback,
|
|
10
|
+
PersistedStoreOptions,
|
|
11
|
+
StateFactory,
|
|
12
|
+
StorageBackend,
|
|
13
|
+
Store,
|
|
14
|
+
StoreDefinition,
|
|
15
|
+
StorePatch,
|
|
16
|
+
StorePlugin,
|
|
17
|
+
StoreSerializer,
|
|
18
|
+
StoreSubscriber,
|
|
19
|
+
} from './types';
|
|
20
|
+
|
|
21
|
+
export { createStore } from './create-store';
|
|
22
|
+
export { defineStore } from './define-store';
|
|
23
|
+
export { mapActions, mapGetters, mapState } from './mapping';
|
|
24
|
+
export { createPersistedStore } from './persisted';
|
|
25
|
+
export { registerPlugin } from './plugins';
|
|
26
|
+
export { destroyStore, getStore, listStores } from './registry';
|
|
27
|
+
export { watchStore } from './watch';
|
package/src/store/mapping.ts
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mapping helpers for store state and actions.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Maps store state properties to a reactive object for use in components.
|
|
7
|
-
*
|
|
8
|
-
* @param store - The store instance
|
|
9
|
-
* @param keys - State keys to map
|
|
10
|
-
* @returns Object with mapped properties
|
|
11
|
-
*/
|
|
12
|
-
export const mapState = <S extends Record<string, unknown>, K extends keyof S>(
|
|
13
|
-
store: S,
|
|
14
|
-
keys: K[]
|
|
15
|
-
): Pick<S, K> => {
|
|
16
|
-
const mapped = {} as Pick<S, K>;
|
|
17
|
-
|
|
18
|
-
for (const key of keys) {
|
|
19
|
-
Object.defineProperty(mapped, key, {
|
|
20
|
-
get: () => store[key],
|
|
21
|
-
enumerable: true,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return mapped;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Maps store getters to a reactive object for use in components.
|
|
30
|
-
*
|
|
31
|
-
* @param store - The store instance
|
|
32
|
-
* @param keys - Getter keys to map
|
|
33
|
-
* @returns Object with mapped getters
|
|
34
|
-
*/
|
|
35
|
-
export const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(
|
|
36
|
-
store: G,
|
|
37
|
-
keys: K[]
|
|
38
|
-
): Pick<G, K> => {
|
|
39
|
-
const mapped = {} as Pick<G, K>;
|
|
40
|
-
|
|
41
|
-
for (const key of keys) {
|
|
42
|
-
Object.defineProperty(mapped, key, {
|
|
43
|
-
get: () => store[key],
|
|
44
|
-
enumerable: true,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return mapped;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Maps store actions to an object for easier destructuring.
|
|
53
|
-
*
|
|
54
|
-
* @param store - The store instance
|
|
55
|
-
* @param keys - Action keys to map
|
|
56
|
-
* @returns Object with mapped actions
|
|
57
|
-
*/
|
|
58
|
-
export const mapActions = <
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types
|
|
60
|
-
A extends Record<string, (...args: any[]) => any>,
|
|
61
|
-
K extends keyof A,
|
|
62
|
-
>(
|
|
63
|
-
store: A,
|
|
64
|
-
keys: K[]
|
|
65
|
-
): Pick<A, K> => {
|
|
66
|
-
const mapped = {} as Pick<A, K>;
|
|
67
|
-
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
(mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>
|
|
70
|
-
(store[key] as (...args: unknown[]) => unknown)(...args);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return mapped;
|
|
74
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Mapping helpers for store state and actions.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Maps store state properties to a reactive object for use in components.
|
|
7
|
+
*
|
|
8
|
+
* @param store - The store instance
|
|
9
|
+
* @param keys - State keys to map
|
|
10
|
+
* @returns Object with mapped properties
|
|
11
|
+
*/
|
|
12
|
+
export const mapState = <S extends Record<string, unknown>, K extends keyof S>(
|
|
13
|
+
store: S,
|
|
14
|
+
keys: K[]
|
|
15
|
+
): Pick<S, K> => {
|
|
16
|
+
const mapped = {} as Pick<S, K>;
|
|
17
|
+
|
|
18
|
+
for (const key of keys) {
|
|
19
|
+
Object.defineProperty(mapped, key, {
|
|
20
|
+
get: () => store[key],
|
|
21
|
+
enumerable: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return mapped;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Maps store getters to a reactive object for use in components.
|
|
30
|
+
*
|
|
31
|
+
* @param store - The store instance
|
|
32
|
+
* @param keys - Getter keys to map
|
|
33
|
+
* @returns Object with mapped getters
|
|
34
|
+
*/
|
|
35
|
+
export const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(
|
|
36
|
+
store: G,
|
|
37
|
+
keys: K[]
|
|
38
|
+
): Pick<G, K> => {
|
|
39
|
+
const mapped = {} as Pick<G, K>;
|
|
40
|
+
|
|
41
|
+
for (const key of keys) {
|
|
42
|
+
Object.defineProperty(mapped, key, {
|
|
43
|
+
get: () => store[key],
|
|
44
|
+
enumerable: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return mapped;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Maps store actions to an object for easier destructuring.
|
|
53
|
+
*
|
|
54
|
+
* @param store - The store instance
|
|
55
|
+
* @param keys - Action keys to map
|
|
56
|
+
* @returns Object with mapped actions
|
|
57
|
+
*/
|
|
58
|
+
export const mapActions = <
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types
|
|
60
|
+
A extends Record<string, (...args: any[]) => any>,
|
|
61
|
+
K extends keyof A,
|
|
62
|
+
>(
|
|
63
|
+
store: A,
|
|
64
|
+
keys: K[]
|
|
65
|
+
): Pick<A, K> => {
|
|
66
|
+
const mapped = {} as Pick<A, K>;
|
|
67
|
+
|
|
68
|
+
for (const key of keys) {
|
|
69
|
+
(mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>
|
|
70
|
+
(store[key] as (...args: unknown[]) => unknown)(...args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return mapped;
|
|
74
|
+
};
|
package/src/store/persisted.ts
CHANGED
|
@@ -2,15 +2,96 @@
|
|
|
2
2
|
* Store persistence helpers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { isPrototypePollutionKey } from '../core/utils/object';
|
|
5
6
|
import { createStore } from './create-store';
|
|
6
|
-
import
|
|
7
|
+
import { isDev } from './utils';
|
|
8
|
+
import type { PersistedStoreOptions, StorageBackend, Store, StoreDefinition } from './types';
|
|
9
|
+
|
|
10
|
+
/** @internal Version key suffix */
|
|
11
|
+
const VERSION_SUFFIX = '__version';
|
|
12
|
+
|
|
13
|
+
/** @internal Default JSON serializer */
|
|
14
|
+
const defaultSerializer = {
|
|
15
|
+
serialize: (state: unknown) => JSON.stringify(state),
|
|
16
|
+
deserialize: (raw: string) => JSON.parse(raw) as unknown,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** @internal Check whether a value can be merged into store state. */
|
|
20
|
+
const isPersistedStateObject = (value: unknown): value is Record<string, unknown> => {
|
|
21
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;
|
|
22
|
+
|
|
23
|
+
const prototype = Object.getPrototypeOf(value);
|
|
24
|
+
return prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
25
|
+
};
|
|
7
26
|
|
|
8
27
|
/**
|
|
9
|
-
*
|
|
28
|
+
* Applies persisted state onto the default state while ignoring dangerous
|
|
29
|
+
* prototype-pollution keys such as `__proto__`, `constructor`, and `prototype`.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
const mergePersistedState = <S extends Record<string, unknown>>(
|
|
34
|
+
defaultState: S,
|
|
35
|
+
persisted: Record<string, unknown>
|
|
36
|
+
): S => {
|
|
37
|
+
const merged = { ...defaultState };
|
|
38
|
+
for (const [key, value] of Object.entries(persisted)) {
|
|
39
|
+
if (isPrototypePollutionKey(key)) continue;
|
|
40
|
+
if (!Object.prototype.hasOwnProperty.call(defaultState, key)) continue;
|
|
41
|
+
merged[key as keyof S] = value as S[keyof S];
|
|
42
|
+
}
|
|
43
|
+
return merged;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** @internal Resolve the default storage backend safely. */
|
|
47
|
+
const getDefaultStorage = (): StorageBackend | undefined => {
|
|
48
|
+
try {
|
|
49
|
+
return globalThis.localStorage;
|
|
50
|
+
} catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a store with automatic persistence.
|
|
57
|
+
*
|
|
58
|
+
* Supports configurable storage backends, custom serializers, and schema
|
|
59
|
+
* versioning with migration functions. All options are optional and
|
|
60
|
+
* backward-compatible with the simple `(definition, storageKey?)` signature.
|
|
10
61
|
*
|
|
11
62
|
* @param definition - Store definition
|
|
12
|
-
* @param
|
|
63
|
+
* @param options - Persistence options or a plain string storage key for backward compatibility
|
|
13
64
|
* @returns The reactive store instance
|
|
65
|
+
*
|
|
66
|
+
* @example Basic usage (localStorage + JSON)
|
|
67
|
+
* ```ts
|
|
68
|
+
* const store = createPersistedStore({
|
|
69
|
+
* id: 'settings',
|
|
70
|
+
* state: () => ({ theme: 'dark' }),
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example With sessionStorage and custom key
|
|
75
|
+
* ```ts
|
|
76
|
+
* const store = createPersistedStore(
|
|
77
|
+
* { id: 'session', state: () => ({ token: '' }) },
|
|
78
|
+
* { key: 'my-session', storage: sessionStorage },
|
|
79
|
+
* );
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example With versioning and migration
|
|
83
|
+
* ```ts
|
|
84
|
+
* const store = createPersistedStore(
|
|
85
|
+
* { id: 'app', state: () => ({ name: '', theme: 'auto' }) },
|
|
86
|
+
* {
|
|
87
|
+
* version: 2,
|
|
88
|
+
* migrate: (old, v) => {
|
|
89
|
+
* if (v < 2) return { ...old, theme: 'auto' };
|
|
90
|
+
* return old;
|
|
91
|
+
* },
|
|
92
|
+
* },
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
14
95
|
*/
|
|
15
96
|
export const createPersistedStore = <
|
|
16
97
|
S extends Record<string, unknown>,
|
|
@@ -19,9 +100,40 @@ export const createPersistedStore = <
|
|
|
19
100
|
A extends Record<string, (...args: any[]) => any> = Record<string, never>,
|
|
20
101
|
>(
|
|
21
102
|
definition: StoreDefinition<S, G, A>,
|
|
22
|
-
|
|
103
|
+
options?: PersistedStoreOptions | string
|
|
23
104
|
): Store<S, G, A> => {
|
|
24
|
-
|
|
105
|
+
// Normalize options — a plain string is treated as the storage key for backward compatibility
|
|
106
|
+
const opts: PersistedStoreOptions =
|
|
107
|
+
typeof options === 'string' ? { key: options } : (options ?? {});
|
|
108
|
+
|
|
109
|
+
const key = opts.key ?? `bquery-store-${definition.id}`;
|
|
110
|
+
const storage = opts.storage ?? getDefaultStorage();
|
|
111
|
+
const serializer = opts.serializer ?? defaultSerializer;
|
|
112
|
+
const version = opts.version;
|
|
113
|
+
const migrate = opts.migrate;
|
|
114
|
+
const versionKey = key + VERSION_SUFFIX;
|
|
115
|
+
let shouldPersistInitialVersion = storage !== undefined && version !== undefined;
|
|
116
|
+
let pendingVersionWrite = false;
|
|
117
|
+
let canRetryPendingVersionAfterCreate = false;
|
|
118
|
+
|
|
119
|
+
const tryPersistVersion = (warningMessage?: string): boolean => {
|
|
120
|
+
if (!storage || version === undefined) return false;
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
storage.setItem(versionKey, String(version));
|
|
124
|
+
return true;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (
|
|
127
|
+
warningMessage &&
|
|
128
|
+
isDev() &&
|
|
129
|
+
typeof console !== 'undefined' &&
|
|
130
|
+
typeof console.warn === 'function'
|
|
131
|
+
) {
|
|
132
|
+
console.warn(warningMessage, error);
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
25
137
|
|
|
26
138
|
const originalStateFactory = definition.state;
|
|
27
139
|
|
|
@@ -30,31 +142,106 @@ export const createPersistedStore = <
|
|
|
30
142
|
state: () => {
|
|
31
143
|
const defaultState = originalStateFactory();
|
|
32
144
|
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
145
|
+
if (!storage) return defaultState;
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const saved = storage.getItem(key);
|
|
149
|
+
if (!saved) return defaultState;
|
|
150
|
+
|
|
151
|
+
const deserialized = serializer.deserialize(saved);
|
|
152
|
+
if (!isPersistedStateObject(deserialized)) {
|
|
153
|
+
return defaultState;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let persisted = deserialized;
|
|
157
|
+
|
|
158
|
+
// Handle versioning & migration
|
|
159
|
+
if (version !== undefined && migrate) {
|
|
160
|
+
const rawVersion = storage.getItem(versionKey);
|
|
161
|
+
const parsedVersion = rawVersion !== null ? Number(rawVersion) : 0;
|
|
162
|
+
const oldVersion = Number.isFinite(parsedVersion) ? parsedVersion : 0;
|
|
163
|
+
|
|
164
|
+
if (oldVersion !== version) {
|
|
165
|
+
shouldPersistInitialVersion = false;
|
|
166
|
+
pendingVersionWrite = true;
|
|
167
|
+
const migrated = migrate(persisted, oldVersion);
|
|
168
|
+
if (!isPersistedStateObject(migrated)) {
|
|
169
|
+
return defaultState;
|
|
170
|
+
}
|
|
171
|
+
persisted = migrated;
|
|
172
|
+
|
|
173
|
+
let migratedStatePersisted = false;
|
|
174
|
+
// Save the migrated state and version immediately when possible.
|
|
175
|
+
// If the state write fails, never advance the version key.
|
|
176
|
+
try {
|
|
177
|
+
storage.setItem(key, serializer.serialize(persisted));
|
|
178
|
+
migratedStatePersisted = true;
|
|
179
|
+
canRetryPendingVersionAfterCreate = true;
|
|
180
|
+
} catch (e) {
|
|
181
|
+
// Migration will re-run on next load, but state is still usable
|
|
182
|
+
if (
|
|
183
|
+
isDev() &&
|
|
184
|
+
typeof console !== 'undefined' &&
|
|
185
|
+
typeof console.warn === 'function'
|
|
186
|
+
) {
|
|
187
|
+
console.warn(
|
|
188
|
+
`[bQuery store "${definition.id}"] Failed to persist migrated state:`,
|
|
189
|
+
e
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (
|
|
195
|
+
migratedStatePersisted &&
|
|
196
|
+
tryPersistVersion(
|
|
197
|
+
`[bQuery store "${definition.id}"] Failed to persist migrated version:`
|
|
198
|
+
)
|
|
199
|
+
) {
|
|
200
|
+
pendingVersionWrite = false;
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
shouldPersistInitialVersion = false;
|
|
38
204
|
}
|
|
39
|
-
} catch {
|
|
40
|
-
// Ignore parse errors
|
|
41
205
|
}
|
|
42
|
-
}
|
|
43
206
|
|
|
44
|
-
|
|
207
|
+
return mergePersistedState(defaultState, persisted);
|
|
208
|
+
} catch {
|
|
209
|
+
// Ignore parse errors
|
|
210
|
+
return defaultState;
|
|
211
|
+
}
|
|
45
212
|
},
|
|
46
213
|
};
|
|
47
214
|
|
|
48
215
|
const store = createStore(wrappedDefinition);
|
|
49
216
|
|
|
217
|
+
// Persist the version number on first creation
|
|
218
|
+
if (shouldPersistInitialVersion && storage) {
|
|
219
|
+
tryPersistVersion();
|
|
220
|
+
} else if (
|
|
221
|
+
pendingVersionWrite &&
|
|
222
|
+
canRetryPendingVersionAfterCreate &&
|
|
223
|
+
tryPersistVersion(
|
|
224
|
+
`[bQuery store "${definition.id}"] Failed to persist migrated version after store creation:`
|
|
225
|
+
)
|
|
226
|
+
) {
|
|
227
|
+
pendingVersionWrite = false;
|
|
228
|
+
}
|
|
229
|
+
|
|
50
230
|
// Subscribe to save changes
|
|
51
231
|
store.$subscribe((state) => {
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
232
|
+
if (!storage) return;
|
|
233
|
+
try {
|
|
234
|
+
storage.setItem(key, serializer.serialize(state));
|
|
235
|
+
if (
|
|
236
|
+
pendingVersionWrite &&
|
|
237
|
+
tryPersistVersion(
|
|
238
|
+
`[bQuery store "${definition.id}"] Failed to persist migrated version after a successful state write:`
|
|
239
|
+
)
|
|
240
|
+
) {
|
|
241
|
+
pendingVersionWrite = false;
|
|
57
242
|
}
|
|
243
|
+
} catch {
|
|
244
|
+
// Ignore quota errors
|
|
58
245
|
}
|
|
59
246
|
});
|
|
60
247
|
|