@bquery/bquery 1.2.0 → 1.3.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 +501 -427
- package/dist/batch-4LAvfLE7.js +13 -0
- package/dist/batch-4LAvfLE7.js.map +1 -0
- package/dist/component/component.d.ts +69 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/html.d.ts +35 -0
- package/dist/component/html.d.ts.map +1 -0
- package/dist/component/index.d.ts +3 -126
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/props.d.ts +18 -0
- package/dist/component/props.d.ts.map +1 -0
- package/dist/component/types.d.ts +77 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component.es.mjs +90 -59
- package/dist/component.es.mjs.map +1 -1
- package/dist/core/collection.d.ts +36 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/dom.d.ts +6 -0
- package/dist/core/dom.d.ts.map +1 -0
- package/dist/core/element.d.ts +8 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/utils/array.d.ts +74 -0
- package/dist/core/utils/array.d.ts.map +1 -0
- package/dist/core/utils/function.d.ts +70 -0
- package/dist/core/utils/function.d.ts.map +1 -0
- package/dist/core/utils/index.d.ts +70 -0
- package/dist/core/utils/index.d.ts.map +1 -0
- package/dist/core/utils/misc.d.ts +63 -0
- package/dist/core/utils/misc.d.ts.map +1 -0
- package/dist/core/utils/number.d.ts +65 -0
- package/dist/core/utils/number.d.ts.map +1 -0
- package/dist/core/utils/object.d.ts +133 -0
- package/dist/core/utils/object.d.ts.map +1 -0
- package/dist/core/utils/string.d.ts +80 -0
- package/dist/core/utils/string.d.ts.map +1 -0
- package/dist/core/utils/type-guards.d.ts +79 -0
- package/dist/core/utils/type-guards.d.ts.map +1 -0
- package/dist/core-COenAZjD.js +145 -0
- package/dist/core-COenAZjD.js.map +1 -0
- package/dist/core.es.mjs +411 -448
- package/dist/core.es.mjs.map +1 -1
- package/dist/full.d.ts +2 -2
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +87 -64
- package/dist/full.es.mjs.map +1 -1
- package/dist/full.iife.js +2 -2
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +2 -2
- package/dist/full.umd.js.map +1 -1
- package/dist/index.es.mjs +138 -68
- package/dist/index.es.mjs.map +1 -1
- package/dist/motion/animate.d.ts +25 -0
- package/dist/motion/animate.d.ts.map +1 -0
- package/dist/motion/easing.d.ts +30 -0
- package/dist/motion/easing.d.ts.map +1 -0
- package/dist/motion/flip.d.ts +55 -0
- package/dist/motion/flip.d.ts.map +1 -0
- package/dist/motion/index.d.ts +11 -138
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/keyframes.d.ts +21 -0
- package/dist/motion/keyframes.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +12 -0
- package/dist/motion/reduced-motion.d.ts.map +1 -0
- package/dist/motion/scroll.d.ts +15 -0
- package/dist/motion/scroll.d.ts.map +1 -0
- package/dist/motion/spring.d.ts +42 -0
- package/dist/motion/spring.d.ts.map +1 -0
- package/dist/motion/stagger.d.ts +22 -0
- package/dist/motion/stagger.d.ts.map +1 -0
- package/dist/motion/timeline.d.ts +21 -0
- package/dist/motion/timeline.d.ts.map +1 -0
- package/dist/motion/transition.d.ts +22 -0
- package/dist/motion/transition.d.ts.map +1 -0
- package/dist/motion/types.d.ts +182 -0
- package/dist/motion/types.d.ts.map +1 -0
- package/dist/motion.es.mjs +320 -61
- package/dist/motion.es.mjs.map +1 -1
- package/dist/persisted-Dz_ryNuC.js +278 -0
- package/dist/persisted-Dz_ryNuC.js.map +1 -0
- package/dist/reactive/batch.d.ts +13 -0
- package/dist/reactive/batch.d.ts.map +1 -0
- package/dist/reactive/computed.d.ts +50 -0
- package/dist/reactive/computed.d.ts.map +1 -0
- package/dist/reactive/core.d.ts +60 -0
- package/dist/reactive/core.d.ts.map +1 -0
- package/dist/reactive/effect.d.ts +15 -0
- package/dist/reactive/effect.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/internals.d.ts +36 -0
- package/dist/reactive/internals.d.ts.map +1 -0
- package/dist/reactive/linked.d.ts +36 -0
- package/dist/reactive/linked.d.ts.map +1 -0
- package/dist/reactive/persisted.d.ts +14 -0
- package/dist/reactive/persisted.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +26 -0
- package/dist/reactive/readonly.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +13 -312
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/type-guards.d.ts +20 -0
- package/dist/reactive/type-guards.d.ts.map +1 -0
- package/dist/reactive/untrack.d.ts +29 -0
- package/dist/reactive/untrack.d.ts.map +1 -0
- package/dist/reactive/watch.d.ts +42 -0
- package/dist/reactive/watch.d.ts.map +1 -0
- package/dist/reactive.es.mjs +30 -163
- package/dist/reactive.es.mjs.map +1 -1
- package/dist/router/index.d.ts +6 -252
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/links.d.ts +44 -0
- package/dist/router/links.d.ts.map +1 -0
- package/dist/router/match.d.ts +20 -0
- package/dist/router/match.d.ts.map +1 -0
- package/dist/router/navigation.d.ts +45 -0
- package/dist/router/navigation.d.ts.map +1 -0
- package/dist/router/query.d.ts +16 -0
- package/dist/router/query.d.ts.map +1 -0
- package/dist/router/router.d.ts +34 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/state.d.ts +27 -0
- package/dist/router/state.d.ts.map +1 -0
- package/dist/router/types.d.ts +88 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/utils.d.ts +65 -0
- package/dist/router/utils.d.ts.map +1 -0
- package/dist/router.es.mjs +168 -132
- package/dist/router.es.mjs.map +1 -1
- package/dist/sanitize-1FBEPAFH.js +272 -0
- package/dist/sanitize-1FBEPAFH.js.map +1 -0
- package/dist/security/constants.d.ts +42 -0
- package/dist/security/constants.d.ts.map +1 -0
- package/dist/security/csp.d.ts +24 -0
- package/dist/security/csp.d.ts.map +1 -0
- package/dist/security/index.d.ts +4 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/sanitize-core.d.ts +13 -0
- package/dist/security/sanitize-core.d.ts.map +1 -0
- package/dist/security/sanitize.d.ts +5 -57
- package/dist/security/sanitize.d.ts.map +1 -1
- package/dist/security/trusted-types.d.ts +25 -0
- package/dist/security/trusted-types.d.ts.map +1 -0
- package/dist/security/types.d.ts +36 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security.es.mjs +50 -277
- package/dist/security.es.mjs.map +1 -1
- package/dist/store/create-store.d.ts +15 -0
- package/dist/store/create-store.d.ts.map +1 -0
- package/dist/store/define-store.d.ts +28 -0
- package/dist/store/define-store.d.ts.map +1 -0
- package/dist/store/devtools.d.ts +22 -0
- package/dist/store/devtools.d.ts.map +1 -0
- package/dist/store/index.d.ts +10 -286
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/mapping.d.ts +28 -0
- package/dist/store/mapping.d.ts.map +1 -0
- package/dist/store/persisted.d.ts +13 -0
- package/dist/store/persisted.d.ts.map +1 -0
- package/dist/store/plugins.d.ts +13 -0
- package/dist/store/plugins.d.ts.map +1 -0
- package/dist/store/registry.d.ts +28 -0
- package/dist/store/registry.d.ts.map +1 -0
- package/dist/store/types.d.ts +71 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/utils.d.ts +28 -0
- package/dist/store/utils.d.ts.map +1 -0
- package/dist/store/watch.d.ts +23 -0
- package/dist/store/watch.d.ts.map +1 -0
- package/dist/store.es.mjs +22 -224
- package/dist/store.es.mjs.map +1 -1
- package/dist/type-guards-DRma3-Kc.js +16 -0
- package/dist/type-guards-DRma3-Kc.js.map +1 -0
- package/dist/untrack-BuEQKH7_.js +6 -0
- package/dist/untrack-BuEQKH7_.js.map +1 -0
- package/dist/view/directives/bind.d.ts +7 -0
- package/dist/view/directives/bind.d.ts.map +1 -0
- package/dist/view/directives/class.d.ts +8 -0
- package/dist/view/directives/class.d.ts.map +1 -0
- package/dist/view/directives/for.d.ts +23 -0
- package/dist/view/directives/for.d.ts.map +1 -0
- package/dist/view/directives/html.d.ts +7 -0
- package/dist/view/directives/html.d.ts.map +1 -0
- package/dist/view/directives/if.d.ts +7 -0
- package/dist/view/directives/if.d.ts.map +1 -0
- package/dist/view/directives/index.d.ts +12 -0
- package/dist/view/directives/index.d.ts.map +1 -0
- package/dist/view/directives/model.d.ts +7 -0
- package/dist/view/directives/model.d.ts.map +1 -0
- package/dist/view/directives/on.d.ts +7 -0
- package/dist/view/directives/on.d.ts.map +1 -0
- package/dist/view/directives/ref.d.ts +7 -0
- package/dist/view/directives/ref.d.ts.map +1 -0
- package/dist/view/directives/show.d.ts +7 -0
- package/dist/view/directives/show.d.ts.map +1 -0
- package/dist/view/directives/style.d.ts +7 -0
- package/dist/view/directives/style.d.ts.map +1 -0
- package/dist/view/directives/text.d.ts +7 -0
- package/dist/view/directives/text.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts +43 -0
- package/dist/view/evaluate.d.ts.map +1 -0
- package/dist/view/index.d.ts +3 -93
- package/dist/view/index.d.ts.map +1 -1
- package/dist/view/mount.d.ts +69 -0
- package/dist/view/mount.d.ts.map +1 -0
- package/dist/view/process.d.ts +26 -0
- package/dist/view/process.d.ts.map +1 -0
- package/dist/view/types.d.ts +36 -0
- package/dist/view/types.d.ts.map +1 -0
- package/dist/view.es.mjs +368 -267
- package/dist/view.es.mjs.map +1 -1
- package/dist/watch-CXyaBC_9.js +58 -0
- package/dist/watch-CXyaBC_9.js.map +1 -0
- package/package.json +132 -132
- package/src/component/component.ts +289 -0
- package/src/component/html.ts +53 -0
- package/src/component/index.ts +40 -414
- package/src/component/props.ts +116 -0
- package/src/component/types.ts +85 -0
- package/src/core/collection.ts +588 -454
- package/src/core/dom.ts +38 -0
- package/src/core/element.ts +746 -740
- package/src/core/index.ts +43 -0
- package/src/core/utils/array.ts +102 -0
- package/src/core/utils/function.ts +110 -0
- package/src/core/utils/index.ts +83 -0
- package/src/core/utils/misc.ts +82 -0
- package/src/core/utils/number.ts +78 -0
- package/src/core/utils/object.ts +206 -0
- package/src/core/utils/string.ts +112 -0
- package/src/core/utils/type-guards.ts +112 -0
- package/src/full.ts +187 -150
- package/src/index.ts +36 -36
- package/src/motion/animate.ts +113 -0
- package/src/motion/easing.ts +40 -0
- package/src/motion/flip.ts +176 -0
- package/src/motion/index.ts +41 -358
- package/src/motion/keyframes.ts +46 -0
- package/src/motion/reduced-motion.ts +17 -0
- package/src/motion/scroll.ts +57 -0
- package/src/motion/spring.ts +150 -0
- package/src/motion/stagger.ts +43 -0
- package/src/motion/timeline.ts +246 -0
- package/src/motion/transition.ts +51 -0
- package/src/motion/types.ts +198 -0
- package/src/reactive/batch.ts +22 -0
- package/src/reactive/computed.ts +92 -0
- package/src/reactive/core.ts +93 -0
- package/src/reactive/effect.ts +43 -0
- package/src/reactive/index.ts +23 -22
- package/src/reactive/internals.ts +105 -0
- package/src/reactive/linked.ts +56 -0
- package/src/reactive/persisted.ts +74 -0
- package/src/reactive/readonly.ts +35 -0
- package/src/reactive/signal.ts +20 -520
- package/src/reactive/type-guards.ts +22 -0
- package/src/reactive/untrack.ts +31 -0
- package/src/reactive/watch.ts +73 -0
- package/src/router/index.ts +41 -718
- package/src/router/links.ts +130 -0
- package/src/router/match.ts +106 -0
- package/src/router/navigation.ts +71 -0
- package/src/router/query.ts +35 -0
- package/src/router/router.ts +211 -0
- package/src/router/state.ts +46 -0
- package/src/router/types.ts +93 -0
- package/src/router/utils.ts +116 -0
- package/src/security/constants.ts +209 -0
- package/src/security/csp.ts +77 -0
- package/src/security/index.ts +4 -12
- package/src/security/sanitize-core.ts +343 -0
- package/src/security/sanitize.ts +66 -625
- package/src/security/trusted-types.ts +69 -0
- package/src/security/types.ts +40 -0
- package/src/store/create-store.ts +329 -0
- package/src/store/define-store.ts +48 -0
- package/src/store/devtools.ts +45 -0
- package/src/store/index.ts +22 -848
- package/src/store/mapping.ts +73 -0
- package/src/store/persisted.ts +61 -0
- package/src/store/plugins.ts +32 -0
- package/src/store/registry.ts +51 -0
- package/src/store/types.ts +94 -0
- package/src/store/utils.ts +141 -0
- package/src/store/watch.ts +52 -0
- package/src/view/directives/bind.ts +23 -0
- package/src/view/directives/class.ts +70 -0
- package/src/view/directives/for.ts +275 -0
- package/src/view/directives/html.ts +19 -0
- package/src/view/directives/if.ts +30 -0
- package/src/view/directives/index.ts +11 -0
- package/src/view/directives/model.ts +56 -0
- package/src/view/directives/on.ts +41 -0
- package/src/view/directives/ref.ts +41 -0
- package/src/view/directives/show.ts +26 -0
- package/src/view/directives/style.ts +47 -0
- package/src/view/directives/text.ts +15 -0
- package/src/view/evaluate.ts +274 -0
- package/src/view/index.ts +112 -1041
- package/src/view/mount.ts +200 -0
- package/src/view/process.ts +92 -0
- package/src/view/types.ts +44 -0
- package/dist/core/utils.d.ts +0 -313
- package/dist/core/utils.d.ts.map +0 -1
- package/src/core/utils.ts +0 -444
|
@@ -1,40 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Security utilities for HTML sanitization
|
|
2
|
+
* Security utilities for HTML sanitization.
|
|
3
3
|
* All DOM writes are sanitized by default to prevent XSS attacks.
|
|
4
4
|
*
|
|
5
5
|
* @module bquery/security
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export interface SanitizeOptions {
|
|
11
|
-
/** Allow these additional tags (default: none) */
|
|
12
|
-
allowTags?: string[];
|
|
13
|
-
/** Allow these additional attributes (default: none) */
|
|
14
|
-
allowAttributes?: string[];
|
|
15
|
-
/** Allow data-* attributes (default: true) */
|
|
16
|
-
allowDataAttributes?: boolean;
|
|
17
|
-
/** Strip all tags and return plain text (default: false) */
|
|
18
|
-
stripAllTags?: boolean;
|
|
19
|
-
}
|
|
20
|
-
/** Trusted Types policy interface */
|
|
21
|
-
interface TrustedTypePolicy {
|
|
22
|
-
createHTML: (input: string) => TrustedHTML;
|
|
23
|
-
}
|
|
24
|
-
/** Trusted HTML type placeholder for environments without Trusted Types */
|
|
25
|
-
interface TrustedHTML {
|
|
26
|
-
toString(): string;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Check if Trusted Types API is available.
|
|
30
|
-
* @returns True if Trusted Types are supported
|
|
31
|
-
*/
|
|
32
|
-
export declare const isTrustedTypesSupported: () => boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Get or create the bQuery Trusted Types policy.
|
|
35
|
-
* @returns The Trusted Types policy or null if unsupported
|
|
36
|
-
*/
|
|
37
|
-
export declare const getTrustedTypesPolicy: () => TrustedTypePolicy | null;
|
|
7
|
+
import type { SanitizeOptions } from './types';
|
|
8
|
+
export { generateNonce } from './csp';
|
|
9
|
+
export { isTrustedTypesSupported } from './trusted-types';
|
|
38
10
|
/**
|
|
39
11
|
* Sanitize HTML string, removing dangerous elements and attributes.
|
|
40
12
|
* Uses Trusted Types when available for CSP compliance.
|
|
@@ -50,14 +22,6 @@ export declare const getTrustedTypesPolicy: () => TrustedTypePolicy | null;
|
|
|
50
22
|
* ```
|
|
51
23
|
*/
|
|
52
24
|
export declare const sanitizeHtml: (html: string, options?: SanitizeOptions) => string;
|
|
53
|
-
/**
|
|
54
|
-
* Create a Trusted HTML value for use with Trusted Types-enabled sites.
|
|
55
|
-
* Falls back to regular string when Trusted Types are unavailable.
|
|
56
|
-
*
|
|
57
|
-
* @param html - The HTML string to wrap
|
|
58
|
-
* @returns Trusted HTML value or sanitized string
|
|
59
|
-
*/
|
|
60
|
-
export declare const createTrustedHtml: (html: string) => TrustedHTML | string;
|
|
61
25
|
/**
|
|
62
26
|
* Escape HTML entities to prevent XSS.
|
|
63
27
|
* Use this for displaying user content as text.
|
|
@@ -79,21 +43,5 @@ export declare const escapeHtml: (text: string) => string;
|
|
|
79
43
|
* @returns Plain text content
|
|
80
44
|
*/
|
|
81
45
|
export declare const stripTags: (html: string) => string;
|
|
82
|
-
|
|
83
|
-
* Generate a nonce for inline scripts/styles.
|
|
84
|
-
* Use with Content-Security-Policy nonce directives.
|
|
85
|
-
*
|
|
86
|
-
* @param length - Nonce length (default: 16)
|
|
87
|
-
* @returns Cryptographically random nonce string
|
|
88
|
-
*/
|
|
89
|
-
export declare const generateNonce: (length?: number) => string;
|
|
90
|
-
/**
|
|
91
|
-
* Check if a CSP header is present with specific directive.
|
|
92
|
-
* Useful for feature detection and fallback strategies.
|
|
93
|
-
*
|
|
94
|
-
* @param directive - The CSP directive to check (e.g., 'script-src')
|
|
95
|
-
* @returns True if the directive appears to be enforced
|
|
96
|
-
*/
|
|
97
|
-
export declare const hasCSPDirective: (directive: string) => boolean;
|
|
98
|
-
export {};
|
|
46
|
+
export type { SanitizeOptions } from './types';
|
|
99
47
|
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,UAAS,eAAoB,KAAG,MAE1E,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MAUzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAExC,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trusted Types helpers for CSP compatibility.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/security
|
|
5
|
+
*/
|
|
6
|
+
import type { TrustedHTML, TrustedTypePolicy } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Check if Trusted Types API is available.
|
|
9
|
+
* @returns True if Trusted Types are supported
|
|
10
|
+
*/
|
|
11
|
+
export declare const isTrustedTypesSupported: () => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Get or create the bQuery Trusted Types policy.
|
|
14
|
+
* @returns The Trusted Types policy or null if unsupported
|
|
15
|
+
*/
|
|
16
|
+
export declare const getTrustedTypesPolicy: () => TrustedTypePolicy | null;
|
|
17
|
+
/**
|
|
18
|
+
* Create a Trusted HTML value for use with Trusted Types-enabled sites.
|
|
19
|
+
* Falls back to regular string when Trusted Types are unavailable.
|
|
20
|
+
*
|
|
21
|
+
* @param html - The HTML string to wrap
|
|
22
|
+
* @returns Trusted HTML value or sanitized string
|
|
23
|
+
*/
|
|
24
|
+
export declare const createTrustedHtml: (html: string) => TrustedHTML | string;
|
|
25
|
+
//# sourceMappingURL=trusted-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted-types.d.ts","sourceRoot":"","sources":["../../src/security/trusted-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAC;AAQlF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAO,OAK1C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAO,iBAAiB,GAAG,IAsB5D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,WAAW,GAAG,MAM9D,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security types for sanitization, CSP compatibility, and Trusted Types.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/security
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Sanitizer configuration options.
|
|
8
|
+
*/
|
|
9
|
+
export interface SanitizeOptions {
|
|
10
|
+
/** Allow these additional tags (default: none) */
|
|
11
|
+
allowTags?: string[];
|
|
12
|
+
/** Allow these additional attributes (default: none) */
|
|
13
|
+
allowAttributes?: string[];
|
|
14
|
+
/** Allow data-* attributes (default: true) */
|
|
15
|
+
allowDataAttributes?: boolean;
|
|
16
|
+
/** Strip all tags and return plain text (default: false) */
|
|
17
|
+
stripAllTags?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Window interface extended with Trusted Types */
|
|
20
|
+
export interface TrustedTypesWindow extends Window {
|
|
21
|
+
trustedTypes?: {
|
|
22
|
+
createPolicy: (name: string, rules: {
|
|
23
|
+
createHTML?: (input: string) => string;
|
|
24
|
+
}) => TrustedTypePolicy;
|
|
25
|
+
isHTML?: (value: unknown) => boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Trusted Types policy interface */
|
|
29
|
+
export interface TrustedTypePolicy {
|
|
30
|
+
createHTML: (input: string) => TrustedHTML;
|
|
31
|
+
}
|
|
32
|
+
/** Trusted HTML type placeholder for environments without Trusted Types */
|
|
33
|
+
export interface TrustedHTML {
|
|
34
|
+
toString(): string;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/security/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,mDAAmD;AACnD,MAAM,WAAW,kBAAmB,SAAQ,MAAM;IAChD,YAAY,CAAC,EAAE;QACb,YAAY,EAAE,CACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;YAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;SAAE,KAC9C,iBAAiB,CAAC;QACvB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;KACtC,CAAC;CACH;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC;CAC5C;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,QAAQ,IAAI,MAAM,CAAC;CACpB"}
|
package/dist/security.es.mjs
CHANGED
|
@@ -1,285 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
if (
|
|
1
|
+
import { b as u, P as i } from "./sanitize-1FBEPAFH.js";
|
|
2
|
+
import { e as h, s as b, s as N, a as C } from "./sanitize-1FBEPAFH.js";
|
|
3
|
+
const s = 1024, a = 8192, p = (t = 16) => {
|
|
4
|
+
if (!Number.isInteger(t) || t < 1)
|
|
5
|
+
throw new RangeError("generateNonce length must be a positive integer");
|
|
6
|
+
if (t > s)
|
|
7
|
+
throw new RangeError(`generateNonce length must not exceed ${s}`);
|
|
8
|
+
if (typeof globalThis.crypto > "u" || typeof globalThis.crypto.getRandomValues != "function")
|
|
9
|
+
throw new Error(
|
|
10
|
+
"generateNonce requires crypto.getRandomValues (not available in this environment)"
|
|
11
|
+
);
|
|
12
|
+
if (typeof globalThis.btoa != "function")
|
|
13
|
+
throw new Error("generateNonce requires btoa (not available in this environment)");
|
|
14
|
+
const e = new Uint8Array(t);
|
|
15
|
+
globalThis.crypto.getRandomValues(e);
|
|
16
|
+
let r = "";
|
|
17
|
+
for (let n = 0; n < e.length; n += a) {
|
|
18
|
+
const l = e.subarray(n, Math.min(n + a, e.length));
|
|
19
|
+
r += String.fromCharCode(...l);
|
|
20
|
+
}
|
|
21
|
+
return globalThis.btoa(r).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
22
|
+
}, y = (t) => {
|
|
23
|
+
if (typeof document > "u")
|
|
24
|
+
return !1;
|
|
25
|
+
const e = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
26
|
+
return e ? (e.getAttribute("content") ?? "").includes(t) : !1;
|
|
27
|
+
};
|
|
28
|
+
let o = null, c = !1;
|
|
29
|
+
const g = () => typeof window < "u" && typeof window.trustedTypes < "u", d = () => {
|
|
30
|
+
if (o) return o;
|
|
31
|
+
if (c || typeof window > "u") return null;
|
|
5
32
|
const t = window;
|
|
6
33
|
if (!t.trustedTypes) return null;
|
|
34
|
+
c = !0;
|
|
7
35
|
try {
|
|
8
|
-
return
|
|
9
|
-
createHTML: (e) =>
|
|
10
|
-
}),
|
|
11
|
-
} catch {
|
|
12
|
-
|
|
36
|
+
return o = t.trustedTypes.createPolicy(i, {
|
|
37
|
+
createHTML: (e) => u(e)
|
|
38
|
+
}), o;
|
|
39
|
+
} catch (e) {
|
|
40
|
+
const r = e instanceof Error ? e.message : String(e);
|
|
41
|
+
return console.warn(`bQuery: Could not create Trusted Types policy "${i}": ${r}`), null;
|
|
13
42
|
}
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"address",
|
|
18
|
-
"article",
|
|
19
|
-
"aside",
|
|
20
|
-
"b",
|
|
21
|
-
"bdi",
|
|
22
|
-
"bdo",
|
|
23
|
-
"blockquote",
|
|
24
|
-
"br",
|
|
25
|
-
"button",
|
|
26
|
-
"caption",
|
|
27
|
-
"cite",
|
|
28
|
-
"code",
|
|
29
|
-
"col",
|
|
30
|
-
"colgroup",
|
|
31
|
-
"data",
|
|
32
|
-
"dd",
|
|
33
|
-
"del",
|
|
34
|
-
"details",
|
|
35
|
-
"dfn",
|
|
36
|
-
"div",
|
|
37
|
-
"dl",
|
|
38
|
-
"dt",
|
|
39
|
-
"em",
|
|
40
|
-
"figcaption",
|
|
41
|
-
"figure",
|
|
42
|
-
"footer",
|
|
43
|
-
"form",
|
|
44
|
-
"h1",
|
|
45
|
-
"h2",
|
|
46
|
-
"h3",
|
|
47
|
-
"h4",
|
|
48
|
-
"h5",
|
|
49
|
-
"h6",
|
|
50
|
-
"header",
|
|
51
|
-
"hgroup",
|
|
52
|
-
"hr",
|
|
53
|
-
"i",
|
|
54
|
-
"img",
|
|
55
|
-
"input",
|
|
56
|
-
"ins",
|
|
57
|
-
"kbd",
|
|
58
|
-
"label",
|
|
59
|
-
"legend",
|
|
60
|
-
"li",
|
|
61
|
-
"main",
|
|
62
|
-
"mark",
|
|
63
|
-
"nav",
|
|
64
|
-
"ol",
|
|
65
|
-
"optgroup",
|
|
66
|
-
"option",
|
|
67
|
-
"p",
|
|
68
|
-
"picture",
|
|
69
|
-
"pre",
|
|
70
|
-
"progress",
|
|
71
|
-
"q",
|
|
72
|
-
"rp",
|
|
73
|
-
"rt",
|
|
74
|
-
"ruby",
|
|
75
|
-
"s",
|
|
76
|
-
"samp",
|
|
77
|
-
"section",
|
|
78
|
-
"select",
|
|
79
|
-
"small",
|
|
80
|
-
"source",
|
|
81
|
-
"span",
|
|
82
|
-
"strong",
|
|
83
|
-
"sub",
|
|
84
|
-
"summary",
|
|
85
|
-
"sup",
|
|
86
|
-
"table",
|
|
87
|
-
"tbody",
|
|
88
|
-
"td",
|
|
89
|
-
"textarea",
|
|
90
|
-
"tfoot",
|
|
91
|
-
"th",
|
|
92
|
-
"thead",
|
|
93
|
-
"time",
|
|
94
|
-
"tr",
|
|
95
|
-
"u",
|
|
96
|
-
"ul",
|
|
97
|
-
"var",
|
|
98
|
-
"wbr"
|
|
99
|
-
]), b = /* @__PURE__ */ new Set([
|
|
100
|
-
"script",
|
|
101
|
-
"iframe",
|
|
102
|
-
"frame",
|
|
103
|
-
"frameset",
|
|
104
|
-
"object",
|
|
105
|
-
"embed",
|
|
106
|
-
"applet",
|
|
107
|
-
"link",
|
|
108
|
-
"meta",
|
|
109
|
-
"style",
|
|
110
|
-
"base",
|
|
111
|
-
"template",
|
|
112
|
-
"slot",
|
|
113
|
-
"math",
|
|
114
|
-
"svg",
|
|
115
|
-
"foreignobject",
|
|
116
|
-
"noscript"
|
|
117
|
-
]), v = /* @__PURE__ */ new Set([
|
|
118
|
-
// Global objects
|
|
119
|
-
"document",
|
|
120
|
-
"window",
|
|
121
|
-
"location",
|
|
122
|
-
"top",
|
|
123
|
-
"self",
|
|
124
|
-
"parent",
|
|
125
|
-
"frames",
|
|
126
|
-
"history",
|
|
127
|
-
"navigator",
|
|
128
|
-
"screen",
|
|
129
|
-
// Dangerous functions
|
|
130
|
-
"alert",
|
|
131
|
-
"confirm",
|
|
132
|
-
"prompt",
|
|
133
|
-
"eval",
|
|
134
|
-
"Function",
|
|
135
|
-
// Document properties
|
|
136
|
-
"cookie",
|
|
137
|
-
"domain",
|
|
138
|
-
"referrer",
|
|
139
|
-
"body",
|
|
140
|
-
"head",
|
|
141
|
-
"forms",
|
|
142
|
-
"images",
|
|
143
|
-
"links",
|
|
144
|
-
"scripts",
|
|
145
|
-
// DOM traversal properties
|
|
146
|
-
"children",
|
|
147
|
-
"parentNode",
|
|
148
|
-
"firstChild",
|
|
149
|
-
"lastChild",
|
|
150
|
-
// Content manipulation
|
|
151
|
-
"innerHTML",
|
|
152
|
-
"outerHTML",
|
|
153
|
-
"textContent"
|
|
154
|
-
]), N = /* @__PURE__ */ new Set([
|
|
155
|
-
"alt",
|
|
156
|
-
"class",
|
|
157
|
-
"dir",
|
|
158
|
-
"height",
|
|
159
|
-
"hidden",
|
|
160
|
-
"href",
|
|
161
|
-
"id",
|
|
162
|
-
"lang",
|
|
163
|
-
"loading",
|
|
164
|
-
"name",
|
|
165
|
-
"rel",
|
|
166
|
-
"role",
|
|
167
|
-
"src",
|
|
168
|
-
"srcset",
|
|
169
|
-
"style",
|
|
170
|
-
"tabindex",
|
|
171
|
-
"target",
|
|
172
|
-
"title",
|
|
173
|
-
"type",
|
|
174
|
-
"width",
|
|
175
|
-
"aria-*"
|
|
176
|
-
]), x = ["on", "formaction", "xlink:", "xmlns:"], R = ["javascript:", "data:", "vbscript:", "file:"], O = (t, e, o) => {
|
|
177
|
-
const s = t.toLowerCase();
|
|
178
|
-
for (const i of x)
|
|
179
|
-
if (s.startsWith(i)) return !1;
|
|
180
|
-
return o && s.startsWith("data-") || s.startsWith("aria-") ? !0 : e.has(s);
|
|
181
|
-
}, U = (t) => {
|
|
182
|
-
const e = t.toLowerCase().trim();
|
|
183
|
-
return !v.has(e);
|
|
184
|
-
}, W = (t) => t.replace(/[\u0000-\u001F\u007F]+/g, "").replace(/[\u200B-\u200D\uFEFF\u2028\u2029]+/g, "").replace(/\\u[\da-fA-F]{4}/g, "").replace(/\s+/g, "").toLowerCase(), _ = (t) => {
|
|
185
|
-
const e = W(t);
|
|
186
|
-
for (const o of R)
|
|
187
|
-
if (e.startsWith(o)) return !1;
|
|
188
|
-
return !0;
|
|
189
|
-
}, D = (t) => {
|
|
190
|
-
try {
|
|
191
|
-
const e = t.trim();
|
|
192
|
-
if (e.startsWith("//"))
|
|
193
|
-
return !0;
|
|
194
|
-
const o = e.toLowerCase();
|
|
195
|
-
return /^[a-z][a-z0-9+.-]*:/i.test(e) && !o.startsWith("http://") && !o.startsWith("https://") ? !0 : !o.startsWith("http://") && !o.startsWith("https://") ? !1 : typeof window > "u" || !window.location ? !0 : new URL(e, window.location.href).origin !== window.location.origin;
|
|
196
|
-
} catch {
|
|
197
|
-
return !0;
|
|
198
|
-
}
|
|
199
|
-
}, m = (t, e = {}) => {
|
|
200
|
-
const {
|
|
201
|
-
allowTags: o = [],
|
|
202
|
-
allowAttributes: s = [],
|
|
203
|
-
allowDataAttributes: i = !0,
|
|
204
|
-
stripAllTags: T = !1
|
|
205
|
-
} = e, y = new Set(
|
|
206
|
-
[...E, ...o.map((r) => r.toLowerCase())].filter(
|
|
207
|
-
(r) => !b.has(r)
|
|
208
|
-
)
|
|
209
|
-
), A = /* @__PURE__ */ new Set([
|
|
210
|
-
...N,
|
|
211
|
-
...s.map((r) => r.toLowerCase())
|
|
212
|
-
]), c = document.createElement("template");
|
|
213
|
-
if (c.innerHTML = t, T)
|
|
214
|
-
return c.content.textContent ?? "";
|
|
215
|
-
const h = document.createTreeWalker(c.content, NodeFilter.SHOW_ELEMENT), d = [];
|
|
216
|
-
for (; h.nextNode(); ) {
|
|
217
|
-
const r = h.currentNode, p = r.tagName.toLowerCase();
|
|
218
|
-
if (b.has(p)) {
|
|
219
|
-
d.push(r);
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
if (!y.has(p)) {
|
|
223
|
-
d.push(r);
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
const l = [];
|
|
227
|
-
for (const n of Array.from(r.attributes)) {
|
|
228
|
-
const a = n.name.toLowerCase();
|
|
229
|
-
if (!O(a, A, i)) {
|
|
230
|
-
l.push(n.name);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
if ((a === "id" || a === "name") && !U(n.value)) {
|
|
234
|
-
l.push(n.name);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
(a === "href" || a === "src" || a === "srcset") && !_(n.value) && l.push(n.name);
|
|
238
|
-
}
|
|
239
|
-
for (const n of l)
|
|
240
|
-
r.removeAttribute(n);
|
|
241
|
-
if (p === "a") {
|
|
242
|
-
const n = r.getAttribute("href"), L = r.getAttribute("target")?.toLowerCase() === "_blank", S = n && D(n);
|
|
243
|
-
if (L || S) {
|
|
244
|
-
const g = r.getAttribute("rel"), f = new Set(
|
|
245
|
-
g ? g.split(/\s+/).filter(Boolean) : []
|
|
246
|
-
);
|
|
247
|
-
f.add("noopener"), f.add("noreferrer"), r.setAttribute("rel", Array.from(f).join(" "));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
for (const r of d)
|
|
252
|
-
r.remove();
|
|
253
|
-
return c.innerHTML;
|
|
254
|
-
}, k = (t, e = {}) => m(t, e), H = (t) => {
|
|
255
|
-
const e = C();
|
|
256
|
-
return e ? e.createHTML(t) : k(t);
|
|
257
|
-
}, P = (t) => {
|
|
258
|
-
const e = {
|
|
259
|
-
"&": "&",
|
|
260
|
-
"<": "<",
|
|
261
|
-
">": ">",
|
|
262
|
-
'"': """,
|
|
263
|
-
"'": "'",
|
|
264
|
-
"`": "`"
|
|
265
|
-
};
|
|
266
|
-
return t.replace(/[&<>"'`]/g, (o) => e[o]);
|
|
267
|
-
}, M = (t) => m(t, { stripAllTags: !0 }), z = (t = 16) => {
|
|
268
|
-
const e = new Uint8Array(t);
|
|
269
|
-
return crypto.getRandomValues(e), btoa(String.fromCharCode(...e)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
270
|
-
}, j = (t) => {
|
|
271
|
-
const e = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
272
|
-
return e ? (e.getAttribute("content") ?? "").includes(t) : !1;
|
|
43
|
+
}, m = (t) => {
|
|
44
|
+
const e = d();
|
|
45
|
+
return e ? e.createHTML(t) : u(t);
|
|
273
46
|
};
|
|
274
47
|
export {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
48
|
+
m as createTrustedHtml,
|
|
49
|
+
h as escapeHtml,
|
|
50
|
+
p as generateNonce,
|
|
51
|
+
d as getTrustedTypesPolicy,
|
|
52
|
+
y as hasCSPDirective,
|
|
53
|
+
g as isTrustedTypesSupported,
|
|
54
|
+
b as sanitize,
|
|
55
|
+
N as sanitizeHtml,
|
|
56
|
+
C as stripTags
|
|
284
57
|
};
|
|
285
58
|
//# sourceMappingURL=security.es.mjs.map
|
package/dist/security.es.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.es.mjs","sources":["../src/security/sanitize.ts"],"sourcesContent":["/**\r\n * Security utilities for HTML sanitization, CSP compatibility, and Trusted Types.\r\n * All DOM writes are sanitized by default to prevent XSS attacks.\r\n *\r\n * @module bquery/security\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitizer configuration options.\r\n */\r\nexport interface SanitizeOptions {\r\n /** Allow these additional tags (default: none) */\r\n allowTags?: string[];\r\n /** Allow these additional attributes (default: none) */\r\n allowAttributes?: string[];\r\n /** Allow data-* attributes (default: true) */\r\n allowDataAttributes?: boolean;\r\n /** Strip all tags and return plain text (default: false) */\r\n stripAllTags?: boolean;\r\n}\r\n\r\n/**\r\n * Trusted Types policy name.\r\n */\r\nconst POLICY_NAME = 'bquery-sanitizer';\r\n\r\n// ============================================================================\r\n// Trusted Types Support\r\n// ============================================================================\r\n\r\n/** Window interface extended with Trusted Types */\r\ninterface TrustedTypesWindow extends Window {\r\n trustedTypes?: {\r\n createPolicy: (\r\n name: string,\r\n rules: { createHTML?: (input: string) => string }\r\n ) => TrustedTypePolicy;\r\n isHTML?: (value: unknown) => boolean;\r\n };\r\n}\r\n\r\n/** Trusted Types policy interface */\r\ninterface TrustedTypePolicy {\r\n createHTML: (input: string) => TrustedHTML;\r\n}\r\n\r\n/** Trusted HTML type placeholder for environments without Trusted Types */\r\ninterface TrustedHTML {\r\n toString(): string;\r\n}\r\n\r\n/** Cached Trusted Types policy */\r\nlet cachedPolicy: TrustedTypePolicy | null = null;\r\n\r\n/**\r\n * Check if Trusted Types API is available.\r\n * @returns True if Trusted Types are supported\r\n */\r\nexport const isTrustedTypesSupported = (): boolean => {\r\n return typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined';\r\n};\r\n\r\n/**\r\n * Get or create the bQuery Trusted Types policy.\r\n * @returns The Trusted Types policy or null if unsupported\r\n */\r\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\r\n if (cachedPolicy) return cachedPolicy;\r\n\r\n const win = window as TrustedTypesWindow;\r\n if (!win.trustedTypes) return null;\r\n\r\n try {\r\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\r\n createHTML: (input: string) => sanitizeHtmlCore(input),\r\n });\r\n return cachedPolicy;\r\n } catch {\r\n // Policy may already exist or be blocked by CSP\r\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\"`);\r\n return null;\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Default Safe Lists\r\n// ============================================================================\r\n\r\n/**\r\n * Default allowed HTML tags considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_TAGS = new Set([\r\n 'a',\r\n 'abbr',\r\n 'address',\r\n 'article',\r\n 'aside',\r\n 'b',\r\n 'bdi',\r\n 'bdo',\r\n 'blockquote',\r\n 'br',\r\n 'button',\r\n 'caption',\r\n 'cite',\r\n 'code',\r\n 'col',\r\n 'colgroup',\r\n 'data',\r\n 'dd',\r\n 'del',\r\n 'details',\r\n 'dfn',\r\n 'div',\r\n 'dl',\r\n 'dt',\r\n 'em',\r\n 'figcaption',\r\n 'figure',\r\n 'footer',\r\n 'form',\r\n 'h1',\r\n 'h2',\r\n 'h3',\r\n 'h4',\r\n 'h5',\r\n 'h6',\r\n 'header',\r\n 'hgroup',\r\n 'hr',\r\n 'i',\r\n 'img',\r\n 'input',\r\n 'ins',\r\n 'kbd',\r\n 'label',\r\n 'legend',\r\n 'li',\r\n 'main',\r\n 'mark',\r\n 'nav',\r\n 'ol',\r\n 'optgroup',\r\n 'option',\r\n 'p',\r\n 'picture',\r\n 'pre',\r\n 'progress',\r\n 'q',\r\n 'rp',\r\n 'rt',\r\n 'ruby',\r\n 's',\r\n 'samp',\r\n 'section',\r\n 'select',\r\n 'small',\r\n 'source',\r\n 'span',\r\n 'strong',\r\n 'sub',\r\n 'summary',\r\n 'sup',\r\n 'table',\r\n 'tbody',\r\n 'td',\r\n 'textarea',\r\n 'tfoot',\r\n 'th',\r\n 'thead',\r\n 'time',\r\n 'tr',\r\n 'u',\r\n 'ul',\r\n 'var',\r\n 'wbr',\r\n]);\r\n\r\n/**\r\n * Explicitly dangerous tags that should never be allowed.\r\n * These are checked even if somehow added to allowTags.\r\n */\r\nconst DANGEROUS_TAGS = new Set([\r\n 'script',\r\n 'iframe',\r\n 'frame',\r\n 'frameset',\r\n 'object',\r\n 'embed',\r\n 'applet',\r\n 'link',\r\n 'meta',\r\n 'style',\r\n 'base',\r\n 'template',\r\n 'slot',\r\n 'math',\r\n 'svg',\r\n 'foreignobject',\r\n 'noscript',\r\n]);\r\n\r\n/**\r\n * Reserved IDs that could cause DOM clobbering attacks.\r\n * These are prevented to avoid overwriting global browser objects.\r\n */\r\nconst RESERVED_IDS = new Set([\r\n // Global objects\r\n 'document',\r\n 'window',\r\n 'location',\r\n 'top',\r\n 'self',\r\n 'parent',\r\n 'frames',\r\n 'history',\r\n 'navigator',\r\n 'screen',\r\n // Dangerous functions\r\n 'alert',\r\n 'confirm',\r\n 'prompt',\r\n 'eval',\r\n 'Function',\r\n // Document properties\r\n 'cookie',\r\n 'domain',\r\n 'referrer',\r\n 'body',\r\n 'head',\r\n 'forms',\r\n 'images',\r\n 'links',\r\n 'scripts',\r\n // DOM traversal properties\r\n 'children',\r\n 'parentNode',\r\n 'firstChild',\r\n 'lastChild',\r\n // Content manipulation\r\n 'innerHTML',\r\n 'outerHTML',\r\n 'textContent',\r\n]);\r\n\r\n/**\r\n * Default allowed attributes considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_ATTRIBUTES = new Set([\r\n 'alt',\r\n 'class',\r\n 'dir',\r\n 'height',\r\n 'hidden',\r\n 'href',\r\n 'id',\r\n 'lang',\r\n 'loading',\r\n 'name',\r\n 'rel',\r\n 'role',\r\n 'src',\r\n 'srcset',\r\n 'style',\r\n 'tabindex',\r\n 'target',\r\n 'title',\r\n 'type',\r\n 'width',\r\n 'aria-*',\r\n]);\r\n\r\n/**\r\n * Dangerous attribute prefixes to always remove.\r\n */\r\nconst DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\r\n\r\n/**\r\n * Dangerous URL protocols to block.\r\n */\r\nconst DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\r\n\r\n// ============================================================================\r\n// Core Sanitization\r\n// ============================================================================\r\n\r\n/**\r\n * Check if an attribute name is allowed.\r\n * @internal\r\n */\r\nconst isAllowedAttribute = (\r\n name: string,\r\n allowedSet: Set<string>,\r\n allowDataAttrs: boolean\r\n): boolean => {\r\n const lowerName = name.toLowerCase();\r\n\r\n // Check dangerous prefixes\r\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\r\n if (lowerName.startsWith(prefix)) return false;\r\n }\r\n\r\n // Check data attributes\r\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\r\n\r\n // Check aria attributes (allowed by default)\r\n if (lowerName.startsWith('aria-')) return true;\r\n\r\n // Check explicit allow list\r\n return allowedSet.has(lowerName);\r\n};\r\n\r\n/**\r\n * Check if an ID/name value could cause DOM clobbering.\r\n * @internal\r\n */\r\nconst isSafeIdOrName = (value: string): boolean => {\r\n const lowerValue = value.toLowerCase().trim();\r\n return !RESERVED_IDS.has(lowerValue);\r\n};\r\n\r\n/**\r\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\r\n * Enhanced to prevent various bypass techniques.\r\n * @internal\r\n */\r\nconst normalizeUrl = (value: string): string =>\r\n value\r\n // Remove null bytes and control characters\r\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\r\n // Remove zero-width characters that could hide malicious content\r\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\r\n // Remove escaped Unicode sequences\r\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\r\n // Remove whitespace\r\n .replace(/\\s+/g, '')\r\n // Normalize case\r\n .toLowerCase();\r\n\r\n/**\r\n * Check if a URL value is safe.\r\n * @internal\r\n */\r\nconst isSafeUrl = (value: string): boolean => {\r\n const normalized = normalizeUrl(value);\r\n for (const protocol of DANGEROUS_PROTOCOLS) {\r\n if (normalized.startsWith(protocol)) return false;\r\n }\r\n return true;\r\n};\r\n\r\n/**\r\n * Check if a URL is external (different origin).\r\n * @internal\r\n */\r\nconst isExternalUrl = (url: string): boolean => {\r\n try {\r\n // Normalize URL by trimming whitespace\r\n const trimmedUrl = url.trim();\r\n \r\n // Protocol-relative URLs (//example.com) are always external.\r\n // CRITICAL: This check must run before the relative-URL check below;\r\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\r\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\r\n // Handling them up front guarantees correct security classification.\r\n if (trimmedUrl.startsWith('//')) {\r\n return true;\r\n }\r\n \r\n // Normalize URL for case-insensitive protocol checks\r\n const lowerUrl = trimmedUrl.toLowerCase();\r\n \r\n // Check for non-http(s) protocols which are considered external/special\r\n // (mailto:, tel:, ftp:, etc.)\r\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\r\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n // These are special protocols, not traditional \"external\" links\r\n // but we treat them as external for security consistency\r\n return true;\r\n }\r\n \r\n // Relative URLs are not external\r\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n return false;\r\n }\r\n \r\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\r\n if (typeof window === 'undefined' || !window.location) {\r\n return true;\r\n }\r\n \r\n const urlObj = new URL(trimmedUrl, window.location.href);\r\n return urlObj.origin !== window.location.origin;\r\n } catch {\r\n // If URL parsing fails, treat as potentially external for safety\r\n return true;\r\n }\r\n};\r\n\r\n/**\r\n * Core sanitization logic (without Trusted Types wrapper).\r\n * @internal\r\n */\r\nconst sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\r\n const {\r\n allowTags = [],\r\n allowAttributes = [],\r\n allowDataAttributes = true,\r\n stripAllTags = false,\r\n } = options;\r\n\r\n // Build combined allow sets (excluding dangerous tags even if specified)\r\n const allowedTags = new Set(\r\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\r\n (tag) => !DANGEROUS_TAGS.has(tag)\r\n )\r\n );\r\n const allowedAttrs = new Set([\r\n ...DEFAULT_ALLOWED_ATTRIBUTES,\r\n ...allowAttributes.map((a) => a.toLowerCase()),\r\n ]);\r\n\r\n // Use template for parsing\r\n const template = document.createElement('template');\r\n template.innerHTML = html;\r\n\r\n if (stripAllTags) {\r\n return template.content.textContent ?? '';\r\n }\r\n\r\n // Walk the DOM tree\r\n const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);\r\n\r\n const toRemove: Element[] = [];\r\n\r\n while (walker.nextNode()) {\r\n const el = walker.currentNode as Element;\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n // Remove explicitly dangerous tags even if in allow list\r\n if (DANGEROUS_TAGS.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Remove disallowed tags entirely\r\n if (!allowedTags.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Process attributes\r\n const attrsToRemove: string[] = [];\r\n for (const attr of Array.from(el.attributes)) {\r\n const attrName = attr.name.toLowerCase();\r\n\r\n // Check if attribute is allowed\r\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Check for DOM clobbering on id and name attributes\r\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Validate URL attributes\r\n if (\r\n (attrName === 'href' || attrName === 'src' || attrName === 'srcset') &&\r\n !isSafeUrl(attr.value)\r\n ) {\r\n attrsToRemove.push(attr.name);\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n for (const attrName of attrsToRemove) {\r\n el.removeAttribute(attrName);\r\n }\r\n\r\n // Add rel=\"noopener noreferrer\" to external links for security\r\n if (tagName === 'a') {\r\n const href = el.getAttribute('href');\r\n const target = el.getAttribute('target');\r\n const hasTargetBlank = target?.toLowerCase() === '_blank';\r\n const isExternal = href && isExternalUrl(href);\r\n\r\n // Add security attributes to links opening in new window or external links\r\n if (hasTargetBlank || isExternal) {\r\n const existingRel = el.getAttribute('rel');\r\n const relValues = new Set(\r\n existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []\r\n );\r\n \r\n // Add noopener and noreferrer\r\n relValues.add('noopener');\r\n relValues.add('noreferrer');\r\n \r\n el.setAttribute('rel', Array.from(relValues).join(' '));\r\n }\r\n }\r\n }\r\n\r\n // Remove disallowed elements\r\n for (const el of toRemove) {\r\n el.remove();\r\n }\r\n\r\n return template.innerHTML;\r\n};\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitize HTML string, removing dangerous elements and attributes.\r\n * Uses Trusted Types when available for CSP compliance.\r\n *\r\n * @param html - The HTML string to sanitize\r\n * @param options - Sanitization options\r\n * @returns Sanitized HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\r\n * // Returns: '<div>Hello</div>'\r\n * ```\r\n */\r\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): string => {\r\n return sanitizeHtmlCore(html, options);\r\n};\r\n\r\n/**\r\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\r\n * Falls back to regular string when Trusted Types are unavailable.\r\n *\r\n * @param html - The HTML string to wrap\r\n * @returns Trusted HTML value or sanitized string\r\n */\r\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\r\n const policy = getTrustedTypesPolicy();\r\n if (policy) {\r\n return policy.createHTML(html);\r\n }\r\n return sanitizeHtml(html);\r\n};\r\n\r\n/**\r\n * Escape HTML entities to prevent XSS.\r\n * Use this for displaying user content as text.\r\n *\r\n * @param text - The text to escape\r\n * @returns Escaped HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * escapeHtml('<script>alert(1)</script>');\r\n * // Returns: '<script>alert(1)</script>'\r\n * ```\r\n */\r\nexport const escapeHtml = (text: string): string => {\r\n const escapeMap: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '`': '`',\r\n };\r\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n};\r\n\r\n/**\r\n * Strip all HTML tags and return plain text.\r\n *\r\n * @param html - The HTML string to strip\r\n * @returns Plain text content\r\n */\r\nexport const stripTags = (html: string): string => {\r\n return sanitizeHtmlCore(html, { stripAllTags: true });\r\n};\r\n\r\n// ============================================================================\r\n// CSP Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Generate a nonce for inline scripts/styles.\r\n * Use with Content-Security-Policy nonce directives.\r\n *\r\n * @param length - Nonce length (default: 16)\r\n * @returns Cryptographically random nonce string\r\n */\r\nexport const generateNonce = (length: number = 16): string => {\r\n const array = new Uint8Array(length);\r\n crypto.getRandomValues(array);\r\n return btoa(String.fromCharCode(...array))\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=/g, '');\r\n};\r\n\r\n/**\r\n * Check if a CSP header is present with specific directive.\r\n * Useful for feature detection and fallback strategies.\r\n *\r\n * @param directive - The CSP directive to check (e.g., 'script-src')\r\n * @returns True if the directive appears to be enforced\r\n */\r\nexport const hasCSPDirective = (directive: string): boolean => {\r\n // Check meta tag\r\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\r\n if (meta) {\r\n const content = meta.getAttribute('content') ?? '';\r\n return content.includes(directive);\r\n }\r\n return false;\r\n};\r\n"],"names":["POLICY_NAME","cachedPolicy","isTrustedTypesSupported","getTrustedTypesPolicy","win","input","sanitizeHtmlCore","DEFAULT_ALLOWED_TAGS","DANGEROUS_TAGS","RESERVED_IDS","DEFAULT_ALLOWED_ATTRIBUTES","DANGEROUS_ATTR_PREFIXES","DANGEROUS_PROTOCOLS","isAllowedAttribute","name","allowedSet","allowDataAttrs","lowerName","prefix","isSafeIdOrName","value","lowerValue","normalizeUrl","isSafeUrl","normalized","protocol","isExternalUrl","url","trimmedUrl","lowerUrl","html","options","allowTags","allowAttributes","allowDataAttributes","stripAllTags","allowedTags","t","tag","allowedAttrs","a","template","walker","toRemove","el","tagName","attrsToRemove","attr","attrName","href","hasTargetBlank","isExternal","existingRel","relValues","sanitizeHtml","createTrustedHtml","policy","escapeHtml","text","escapeMap","char","stripTags","generateNonce","length","array","hasCSPDirective","directive","meta"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"security.es.mjs","sources":["../src/security/csp.ts","../src/security/trusted-types.ts"],"sourcesContent":["/**\n * Content Security Policy helpers.\n *\n * @module bquery/security\n */\n\n/** Maximum allowed nonce length to prevent memory issues */\nconst MAX_NONCE_LENGTH = 1024;\n\n/** Chunk size for building strings to avoid argument limit in String.fromCharCode */\nconst CHUNK_SIZE = 8192;\n\n/**\n * Generate a nonce for inline scripts/styles.\n * Use with Content-Security-Policy nonce directives.\n *\n * @param length - Nonce length in bytes (default: 16, max: 1024)\n * @returns Cryptographically random nonce string\n * @throws {Error} If crypto.getRandomValues or btoa are not available\n * @throws {RangeError} If length is invalid (negative, non-integer, or exceeds maximum)\n */\nexport const generateNonce = (length: number = 16): string => {\n // Validate length parameter\n if (!Number.isInteger(length) || length < 1) {\n throw new RangeError('generateNonce length must be a positive integer');\n }\n if (length > MAX_NONCE_LENGTH) {\n throw new RangeError(`generateNonce length must not exceed ${MAX_NONCE_LENGTH}`);\n }\n\n // Check for required globals in browser/crypto environments\n if (\n typeof globalThis.crypto === 'undefined' ||\n typeof globalThis.crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'generateNonce requires crypto.getRandomValues (not available in this environment)'\n );\n }\n if (typeof globalThis.btoa !== 'function') {\n throw new Error('generateNonce requires btoa (not available in this environment)');\n }\n\n const array = new Uint8Array(length);\n globalThis.crypto.getRandomValues(array);\n\n // Build string in chunks to avoid argument limit in String.fromCharCode\n let binaryString = '';\n for (let i = 0; i < array.length; i += CHUNK_SIZE) {\n const chunk = array.subarray(i, Math.min(i + CHUNK_SIZE, array.length));\n binaryString += String.fromCharCode(...chunk);\n }\n\n return globalThis.btoa(binaryString).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\n/**\n * Check if a CSP header is present with specific directive.\n * Useful for feature detection and fallback strategies.\n *\n * @param directive - The CSP directive to check (e.g., 'script-src')\n * @returns True if the directive appears to be enforced\n */\nexport const hasCSPDirective = (directive: string): boolean => {\n // Guard for non-DOM environments (SSR, tests, etc.)\n if (typeof document === 'undefined') {\n return false;\n }\n\n // Check meta tag\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\n if (meta) {\n const content = meta.getAttribute('content') ?? '';\n return content.includes(directive);\n }\n return false;\n};\n","/**\n * Trusted Types helpers for CSP compatibility.\n *\n * @module bquery/security\n */\n\nimport { POLICY_NAME } from './constants';\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport type { TrustedHTML, TrustedTypePolicy, TrustedTypesWindow } from './types';\n\n/** Cached Trusted Types policy */\nlet cachedPolicy: TrustedTypePolicy | null = null;\n\n/** Whether policy initialization has been attempted (to avoid retry spam) */\nlet policyInitAttempted = false;\n\n/**\n * Check if Trusted Types API is available.\n * @returns True if Trusted Types are supported\n */\nexport const isTrustedTypesSupported = (): boolean => {\n return (\n typeof window !== 'undefined' &&\n typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined'\n );\n};\n\n/**\n * Get or create the bQuery Trusted Types policy.\n * @returns The Trusted Types policy or null if unsupported\n */\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\n if (cachedPolicy) return cachedPolicy;\n if (policyInitAttempted) return null;\n\n if (typeof window === 'undefined') return null;\n\n const win = window as TrustedTypesWindow;\n if (!win.trustedTypes) return null;\n\n policyInitAttempted = true;\n\n try {\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\n createHTML: (input: string) => sanitizeHtmlCore(input),\n });\n return cachedPolicy;\n } catch (error) {\n // Policy may already exist or be blocked by CSP\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\": ${errorMessage}`);\n return null;\n }\n};\n\n/**\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\n * Falls back to regular string when Trusted Types are unavailable.\n *\n * @param html - The HTML string to wrap\n * @returns Trusted HTML value or sanitized string\n */\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\n const policy = getTrustedTypesPolicy();\n if (policy) {\n return policy.createHTML(html);\n }\n return sanitizeHtmlCore(html);\n};\n"],"names":["MAX_NONCE_LENGTH","CHUNK_SIZE","generateNonce","length","array","binaryString","i","chunk","hasCSPDirective","directive","meta","cachedPolicy","policyInitAttempted","isTrustedTypesSupported","getTrustedTypesPolicy","win","POLICY_NAME","input","sanitizeHtmlCore","error","errorMessage","createTrustedHtml","html","policy"],"mappings":";;AAOA,MAAMA,IAAmB,MAGnBC,IAAa,MAWNC,IAAgB,CAACC,IAAiB,OAAe;AAE5D,MAAI,CAAC,OAAO,UAAUA,CAAM,KAAKA,IAAS;AACxC,UAAM,IAAI,WAAW,iDAAiD;AAExE,MAAIA,IAASH;AACX,UAAM,IAAI,WAAW,wCAAwCA,CAAgB,EAAE;AAIjF,MACE,OAAO,WAAW,SAAW,OAC7B,OAAO,WAAW,OAAO,mBAAoB;AAE7C,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAGJ,MAAI,OAAO,WAAW,QAAS;AAC7B,UAAM,IAAI,MAAM,iEAAiE;AAGnF,QAAMI,IAAQ,IAAI,WAAWD,CAAM;AACnC,aAAW,OAAO,gBAAgBC,CAAK;AAGvC,MAAIC,IAAe;AACnB,WAASC,IAAI,GAAGA,IAAIF,EAAM,QAAQE,KAAKL,GAAY;AACjD,UAAMM,IAAQH,EAAM,SAASE,GAAG,KAAK,IAAIA,IAAIL,GAAYG,EAAM,MAAM,CAAC;AACtE,IAAAC,KAAgB,OAAO,aAAa,GAAGE,CAAK;AAAA,EAC9C;AAEA,SAAO,WAAW,KAAKF,CAAY,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,EAAE;AAC/F,GASaG,IAAkB,CAACC,MAA+B;AAE7D,MAAI,OAAO,WAAa;AACtB,WAAO;AAIT,QAAMC,IAAO,SAAS,cAAc,4CAA4C;AAChF,SAAIA,KACcA,EAAK,aAAa,SAAS,KAAK,IACjC,SAASD,CAAS,IAE5B;AACT;ACjEA,IAAIE,IAAyC,MAGzCC,IAAsB;AAMnB,MAAMC,IAA0B,MAEnC,OAAO,SAAW,OAClB,OAAQ,OAA8B,eAAiB,KAQ9CC,IAAwB,MAAgC;AACnE,MAAIH,EAAc,QAAOA;AAGzB,MAFIC,KAEA,OAAO,SAAW,IAAa,QAAO;AAE1C,QAAMG,IAAM;AACZ,MAAI,CAACA,EAAI,aAAc,QAAO;AAE9B,EAAAH,IAAsB;AAEtB,MAAI;AACF,WAAAD,IAAeI,EAAI,aAAa,aAAaC,GAAa;AAAA,MACxD,YAAY,CAACC,MAAkBC,EAAiBD,CAAK;AAAA,IAAA,CACtD,GACMN;AAAA,EACT,SAASQ,GAAO;AAEd,UAAMC,IAAeD,aAAiB,QAAQA,EAAM,UAAU,OAAOA,CAAK;AAC1E,mBAAQ,KAAK,kDAAkDH,CAAW,MAAMI,CAAY,EAAE,GACvF;AAAA,EACT;AACF,GASaC,IAAoB,CAACC,MAAuC;AACvE,QAAMC,IAAST,EAAA;AACf,SAAIS,IACKA,EAAO,WAAWD,CAAI,IAExBJ,EAAiBI,CAAI;AAC9B;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store creation logic.
|
|
3
|
+
*/
|
|
4
|
+
import type { Store, StoreDefinition } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Creates a reactive store with state, getters, and actions.
|
|
7
|
+
*
|
|
8
|
+
* @template S - State type
|
|
9
|
+
* @template G - Getters type
|
|
10
|
+
* @template A - Actions type
|
|
11
|
+
* @param definition - Store definition
|
|
12
|
+
* @returns The reactive store instance
|
|
13
|
+
*/
|
|
14
|
+
export declare const createStore: <S extends Record<string, unknown>, G extends Record<string, unknown> = Record<string, never>, A extends Record<string, (...args: any[]) => any> = Record<string, never>>(definition: StoreDefinition<S, G, A>) => Store<S, G, A>;
|
|
15
|
+
//# sourceMappingURL=create-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-store.d.ts","sourceRoot":"","sources":["../../src/store/create-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,OAAO,KAAK,EAAW,KAAK,EAAE,eAAe,EAAmB,MAAM,SAAS,CAAC;AAGhF;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzE,YAAY,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KACnC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAsSf,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store factory helpers.
|
|
3
|
+
*/
|
|
4
|
+
import type { Store, StoreDefinition } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Creates a store factory that returns the store instance.
|
|
7
|
+
*
|
|
8
|
+
* The store is lazily created on first call and cached in the global store
|
|
9
|
+
* registry. Subsequent calls return the same instance. After calling
|
|
10
|
+
* `destroyStore(id)`, the next factory call will create a fresh store.
|
|
11
|
+
*
|
|
12
|
+
* @param id - Store identifier
|
|
13
|
+
* @param definition - Store definition without id
|
|
14
|
+
* @returns A function that returns the store instance
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const useCounter = defineStore('counter', {
|
|
19
|
+
* state: () => ({ count: 0 }),
|
|
20
|
+
* actions: { increment() { this.count++; } },
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const counter = useCounter();
|
|
24
|
+
* counter.increment();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare const defineStore: <S extends Record<string, unknown>, G extends Record<string, unknown> = Record<string, never>, A extends Record<string, (...args: unknown[]) => unknown> = Record<string, never>>(id: string, definition: Omit<StoreDefinition<S, G, A>, "id">) => (() => Store<S, G, A>);
|
|
28
|
+
//# sourceMappingURL=define-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-store.d.ts","sourceRoot":"","sources":["../../src/store/define-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,WAAW,GACtB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACzD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEjF,IAAI,MAAM,EACV,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,KAC/C,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAUvB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devtools integration for stores.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
declare global {
|
|
6
|
+
interface Window {
|
|
7
|
+
__BQUERY_DEVTOOLS__?: {
|
|
8
|
+
stores: Map<string, unknown>;
|
|
9
|
+
onStoreCreated?: (id: string, store: unknown) => void;
|
|
10
|
+
onStateChange?: (id: string, state: unknown) => void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export type DevtoolsHook = {
|
|
15
|
+
stores: Map<string, unknown>;
|
|
16
|
+
onStoreCreated?: (id: string, store: unknown) => void;
|
|
17
|
+
onStateChange?: (id: string, state: unknown) => void;
|
|
18
|
+
};
|
|
19
|
+
export declare const registerDevtoolsStore: (id: string, store: unknown) => void;
|
|
20
|
+
export declare const unregisterDevtoolsStore: (id: string) => void;
|
|
21
|
+
export declare const notifyDevtoolsStateChange: (id: string, state: unknown) => void;
|
|
22
|
+
//# sourceMappingURL=devtools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../../src/store/devtools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,mBAAmB,CAAC,EAAE;YACpB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC7B,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;YACtD,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;SACtD,CAAC;KACH;CACF;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtD,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD,CAAC;AAUF,eAAO,MAAM,qBAAqB,GAAI,IAAI,MAAM,EAAE,OAAO,OAAO,KAAG,IAKlE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,IAAI,MAAM,KAAG,IAGpD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,IAAI,MAAM,EAAE,OAAO,OAAO,KAAG,IAGtE,CAAC"}
|