@mappoh/nova 0.1.16
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/dist/animation/parallax.d.ts +23 -0
- package/dist/animation/parallax.d.ts.map +1 -0
- package/dist/animation/parallax.js +96 -0
- package/dist/animation/parallax.js.map +1 -0
- package/dist/animation/scroll-animate.d.ts +30 -0
- package/dist/animation/scroll-animate.d.ts.map +1 -0
- package/dist/animation/scroll-animate.js +65 -0
- package/dist/animation/scroll-animate.js.map +1 -0
- package/dist/animation/scroll-observer.d.ts +32 -0
- package/dist/animation/scroll-observer.d.ts.map +1 -0
- package/dist/animation/scroll-observer.js +63 -0
- package/dist/animation/scroll-observer.js.map +1 -0
- package/dist/animation/smooth-scroll.d.ts +47 -0
- package/dist/animation/smooth-scroll.d.ts.map +1 -0
- package/dist/animation/smooth-scroll.js +169 -0
- package/dist/animation/smooth-scroll.js.map +1 -0
- package/dist/animation/text-reveal.d.ts +30 -0
- package/dist/animation/text-reveal.d.ts.map +1 -0
- package/dist/animation/text-reveal.js +164 -0
- package/dist/animation/text-reveal.js.map +1 -0
- package/dist/animation/ticker.d.ts +32 -0
- package/dist/animation/ticker.d.ts.map +1 -0
- package/dist/animation/ticker.js +62 -0
- package/dist/animation/ticker.js.map +1 -0
- package/dist/canvas/dot-grid.d.ts +50 -0
- package/dist/canvas/dot-grid.d.ts.map +1 -0
- package/dist/canvas/dot-grid.js +123 -0
- package/dist/canvas/dot-grid.js.map +1 -0
- package/dist/canvas/noise.d.ts +33 -0
- package/dist/canvas/noise.d.ts.map +1 -0
- package/dist/canvas/noise.js +241 -0
- package/dist/canvas/noise.js.map +1 -0
- package/dist/canvas/particles.d.ts +44 -0
- package/dist/canvas/particles.d.ts.map +1 -0
- package/dist/canvas/particles.js +138 -0
- package/dist/canvas/particles.js.map +1 -0
- package/dist/canvas/sequence.d.ts +43 -0
- package/dist/canvas/sequence.d.ts.map +1 -0
- package/dist/canvas/sequence.js +162 -0
- package/dist/canvas/sequence.js.map +1 -0
- package/dist/component/bind.d.ts +25 -0
- package/dist/component/bind.d.ts.map +1 -0
- package/dist/component/bind.js +28 -0
- package/dist/component/bind.js.map +1 -0
- package/dist/component/component.d.ts +76 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/component.js +219 -0
- package/dist/component/component.js.map +1 -0
- package/dist/component/connect.d.ts +60 -0
- package/dist/component/connect.d.ts.map +1 -0
- package/dist/component/connect.js +115 -0
- package/dist/component/connect.js.map +1 -0
- package/dist/component/html.d.ts +35 -0
- package/dist/component/html.d.ts.map +1 -0
- package/dist/component/html.js +51 -0
- package/dist/component/html.js.map +1 -0
- package/dist/component/hydrate.d.ts +37 -0
- package/dist/component/hydrate.d.ts.map +1 -0
- package/dist/component/hydrate.js +242 -0
- package/dist/component/hydrate.js.map +1 -0
- package/dist/component/index.d.ts +9 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +6 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/template.d.ts +30 -0
- package/dist/component/template.d.ts.map +1 -0
- package/dist/component/template.js +469 -0
- package/dist/component/template.js.map +1 -0
- package/dist/css/gradient-text.d.ts +40 -0
- package/dist/css/gradient-text.d.ts.map +1 -0
- package/dist/css/gradient-text.js +90 -0
- package/dist/css/gradient-text.js.map +1 -0
- package/dist/css/index.d.ts +3 -0
- package/dist/css/index.d.ts.map +1 -0
- package/dist/css/index.js +2 -0
- package/dist/css/index.js.map +1 -0
- package/dist/devtools/devtools.d.ts +27 -0
- package/dist/devtools/devtools.d.ts.map +1 -0
- package/dist/devtools/devtools.js +237 -0
- package/dist/devtools/devtools.js.map +1 -0
- package/dist/devtools/index.d.ts +3 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +2 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/drag/drag.d.ts +38 -0
- package/dist/drag/drag.d.ts.map +1 -0
- package/dist/drag/drag.js +181 -0
- package/dist/drag/drag.js.map +1 -0
- package/dist/drag/index.d.ts +3 -0
- package/dist/drag/index.d.ts.map +1 -0
- package/dist/drag/index.js +2 -0
- package/dist/drag/index.js.map +1 -0
- package/dist/dropdown/dropdown.d.ts +55 -0
- package/dist/dropdown/dropdown.d.ts.map +1 -0
- package/dist/dropdown/dropdown.js +314 -0
- package/dist/dropdown/dropdown.js.map +1 -0
- package/dist/dropdown/group.d.ts +18 -0
- package/dist/dropdown/group.d.ts.map +1 -0
- package/dist/dropdown/group.js +119 -0
- package/dist/dropdown/group.js.map +1 -0
- package/dist/dropdown/index.d.ts +5 -0
- package/dist/dropdown/index.d.ts.map +1 -0
- package/dist/dropdown/index.js +3 -0
- package/dist/dropdown/index.js.map +1 -0
- package/dist/forms/form-engine.d.ts +91 -0
- package/dist/forms/form-engine.d.ts.map +1 -0
- package/dist/forms/form-engine.js +228 -0
- package/dist/forms/form-engine.js.map +1 -0
- package/dist/forms/index.d.ts +3 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/validators.d.ts +20 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms/validators.js +82 -0
- package/dist/forms/validators.js.map +1 -0
- package/dist/gallery/gallery.d.ts +66 -0
- package/dist/gallery/gallery.d.ts.map +1 -0
- package/dist/gallery/gallery.js +347 -0
- package/dist/gallery/gallery.js.map +1 -0
- package/dist/gallery/index.d.ts +3 -0
- package/dist/gallery/index.d.ts.map +1 -0
- package/dist/gallery/index.js +2 -0
- package/dist/gallery/index.js.map +1 -0
- package/dist/gesture/gesture.d.ts +44 -0
- package/dist/gesture/gesture.d.ts.map +1 -0
- package/dist/gesture/gesture.js +152 -0
- package/dist/gesture/gesture.js.map +1 -0
- package/dist/gesture/index.d.ts +3 -0
- package/dist/gesture/index.d.ts.map +1 -0
- package/dist/gesture/index.js +2 -0
- package/dist/gesture/index.js.map +1 -0
- package/dist/http/http.d.ts +44 -0
- package/dist/http/http.d.ts.map +1 -0
- package/dist/http/http.js +135 -0
- package/dist/http/http.js.map +1 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +2 -0
- package/dist/http/index.js.map +1 -0
- package/dist/i18n/i18n.d.ts +28 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/i18n.js +84 -0
- package/dist/i18n/i18n.js.map +1 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/image/effects.d.ts +33 -0
- package/dist/image/effects.d.ts.map +1 -0
- package/dist/image/effects.js +236 -0
- package/dist/image/effects.js.map +1 -0
- package/dist/image/image.d.ts +83 -0
- package/dist/image/image.d.ts.map +1 -0
- package/dist/image/image.js +236 -0
- package/dist/image/image.js.map +1 -0
- package/dist/image/index.d.ts +5 -0
- package/dist/image/index.d.ts.map +1 -0
- package/dist/image/index.js +3 -0
- package/dist/image/index.js.map +1 -0
- package/dist/interaction/index.d.ts +3 -0
- package/dist/interaction/index.d.ts.map +1 -0
- package/dist/interaction/index.js +2 -0
- package/dist/interaction/index.js.map +1 -0
- package/dist/interaction/tilt.d.ts +30 -0
- package/dist/interaction/tilt.d.ts.map +1 -0
- package/dist/interaction/tilt.js +131 -0
- package/dist/interaction/tilt.js.map +1 -0
- package/dist/lazy/index.d.ts +3 -0
- package/dist/lazy/index.d.ts.map +1 -0
- package/dist/lazy/index.js +2 -0
- package/dist/lazy/index.js.map +1 -0
- package/dist/lazy/lazy.d.ts +42 -0
- package/dist/lazy/lazy.d.ts.map +1 -0
- package/dist/lazy/lazy.js +80 -0
- package/dist/lazy/lazy.js.map +1 -0
- package/dist/modal/index.d.ts +3 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +2 -0
- package/dist/modal/index.js.map +1 -0
- package/dist/modal/modal.d.ts +39 -0
- package/dist/modal/modal.d.ts.map +1 -0
- package/dist/modal/modal.js +174 -0
- package/dist/modal/modal.js.map +1 -0
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +2 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/router.d.ts +80 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/router.js +256 -0
- package/dist/router/router.js.map +1 -0
- package/dist/router/speculate.d.ts +28 -0
- package/dist/router/speculate.d.ts.map +1 -0
- package/dist/router/speculate.js +36 -0
- package/dist/router/speculate.js.map +1 -0
- package/dist/search/fuzzy.d.ts +16 -0
- package/dist/search/fuzzy.d.ts.map +1 -0
- package/dist/search/fuzzy.js +77 -0
- package/dist/search/fuzzy.js.map +1 -0
- package/dist/search/index.d.ts +5 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +3 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/search.d.ts +56 -0
- package/dist/search/search.d.ts.map +1 -0
- package/dist/search/search.js +540 -0
- package/dist/search/search.js.map +1 -0
- package/dist/search/wasm.d.ts +35 -0
- package/dist/search/wasm.d.ts.map +1 -0
- package/dist/search/wasm.js +51 -0
- package/dist/search/wasm.js.map +1 -0
- package/dist/security/cors.d.ts +61 -0
- package/dist/security/cors.d.ts.map +1 -0
- package/dist/security/cors.js +174 -0
- package/dist/security/cors.js.map +1 -0
- package/dist/security/csp.d.ts +49 -0
- package/dist/security/csp.d.ts.map +1 -0
- package/dist/security/csp.js +143 -0
- package/dist/security/csp.js.map +1 -0
- package/dist/security/csrf.d.ts +47 -0
- package/dist/security/csrf.d.ts.map +1 -0
- package/dist/security/csrf.js +122 -0
- package/dist/security/csrf.js.map +1 -0
- package/dist/security/encrypt.d.ts +64 -0
- package/dist/security/encrypt.d.ts.map +1 -0
- package/dist/security/encrypt.js +129 -0
- package/dist/security/encrypt.js.map +1 -0
- package/dist/security/index.d.ts +21 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +11 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/rate-limit.d.ts +57 -0
- package/dist/security/rate-limit.d.ts.map +1 -0
- package/dist/security/rate-limit.js +222 -0
- package/dist/security/rate-limit.js.map +1 -0
- package/dist/security/rbac.d.ts +84 -0
- package/dist/security/rbac.d.ts.map +1 -0
- package/dist/security/rbac.js +164 -0
- package/dist/security/rbac.js.map +1 -0
- package/dist/security/sanitize.d.ts +44 -0
- package/dist/security/sanitize.d.ts.map +1 -0
- package/dist/security/sanitize.js +230 -0
- package/dist/security/sanitize.js.map +1 -0
- package/dist/security/secure-store.d.ts +44 -0
- package/dist/security/secure-store.d.ts.map +1 -0
- package/dist/security/secure-store.js +164 -0
- package/dist/security/secure-store.js.map +1 -0
- package/dist/security/session.d.ts +76 -0
- package/dist/security/session.d.ts.map +1 -0
- package/dist/security/session.js +251 -0
- package/dist/security/session.js.map +1 -0
- package/dist/security/sri.d.ts +66 -0
- package/dist/security/sri.d.ts.map +1 -0
- package/dist/security/sri.js +159 -0
- package/dist/security/sri.js.map +1 -0
- package/dist/shortcuts/index.d.ts +3 -0
- package/dist/shortcuts/index.d.ts.map +1 -0
- package/dist/shortcuts/index.js +2 -0
- package/dist/shortcuts/index.js.map +1 -0
- package/dist/shortcuts/shortcuts.d.ts +43 -0
- package/dist/shortcuts/shortcuts.d.ts.map +1 -0
- package/dist/shortcuts/shortcuts.js +141 -0
- package/dist/shortcuts/shortcuts.js.map +1 -0
- package/dist/ssr/index.d.ts +3 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +2 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/ssr.d.ts +62 -0
- package/dist/ssr/ssr.d.ts.map +1 -0
- package/dist/ssr/ssr.js +132 -0
- package/dist/ssr/ssr.js.map +1 -0
- package/dist/state/index.d.ts +5 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +3 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/persistent.d.ts +31 -0
- package/dist/state/persistent.d.ts.map +1 -0
- package/dist/state/persistent.js +132 -0
- package/dist/state/persistent.js.map +1 -0
- package/dist/state/store.d.ts +31 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +107 -0
- package/dist/state/store.js.map +1 -0
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +2 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/store.d.ts +36 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +175 -0
- package/dist/store/store.js.map +1 -0
- package/dist/supabase/auth.d.ts +28 -0
- package/dist/supabase/auth.d.ts.map +1 -0
- package/dist/supabase/auth.js +47 -0
- package/dist/supabase/auth.js.map +1 -0
- package/dist/supabase/client.d.ts +18 -0
- package/dist/supabase/client.d.ts.map +1 -0
- package/dist/supabase/client.js +36 -0
- package/dist/supabase/client.js.map +1 -0
- package/dist/supabase/realtime.d.ts +22 -0
- package/dist/supabase/realtime.d.ts.map +1 -0
- package/dist/supabase/realtime.js +51 -0
- package/dist/supabase/realtime.js.map +1 -0
- package/dist/sw/index.d.ts +3 -0
- package/dist/sw/index.d.ts.map +1 -0
- package/dist/sw/index.js +2 -0
- package/dist/sw/index.js.map +1 -0
- package/dist/sw/sw.d.ts +49 -0
- package/dist/sw/sw.d.ts.map +1 -0
- package/dist/sw/sw.js +125 -0
- package/dist/sw/sw.js.map +1 -0
- package/dist/tabs/index.d.ts +3 -0
- package/dist/tabs/index.d.ts.map +1 -0
- package/dist/tabs/index.js +2 -0
- package/dist/tabs/index.js.map +1 -0
- package/dist/tabs/tabs.d.ts +34 -0
- package/dist/tabs/tabs.d.ts.map +1 -0
- package/dist/tabs/tabs.js +173 -0
- package/dist/tabs/tabs.js.map +1 -0
- package/dist/test/index.d.ts +3 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +2 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test/test.d.ts +37 -0
- package/dist/test/test.d.ts.map +1 -0
- package/dist/test/test.js +108 -0
- package/dist/test/test.js.map +1 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme.d.ts +40 -0
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/theme/theme.js +142 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/timeline/index.d.ts +3 -0
- package/dist/timeline/index.d.ts.map +1 -0
- package/dist/timeline/index.js +2 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/timeline.d.ts +44 -0
- package/dist/timeline/timeline.d.ts.map +1 -0
- package/dist/timeline/timeline.js +196 -0
- package/dist/timeline/timeline.js.map +1 -0
- package/dist/toast/index.d.ts +3 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +2 -0
- package/dist/toast/index.js.map +1 -0
- package/dist/toast/toast.d.ts +31 -0
- package/dist/toast/toast.d.ts.map +1 -0
- package/dist/toast/toast.js +198 -0
- package/dist/toast/toast.js.map +1 -0
- package/dist/tooltip/index.d.ts +3 -0
- package/dist/tooltip/index.d.ts.map +1 -0
- package/dist/tooltip/index.js +2 -0
- package/dist/tooltip/index.js.map +1 -0
- package/dist/tooltip/tooltip.d.ts +27 -0
- package/dist/tooltip/tooltip.d.ts.map +1 -0
- package/dist/tooltip/tooltip.js +229 -0
- package/dist/tooltip/tooltip.js.map +1 -0
- package/dist/transition/index.d.ts +3 -0
- package/dist/transition/index.d.ts.map +1 -0
- package/dist/transition/index.js +2 -0
- package/dist/transition/index.js.map +1 -0
- package/dist/transition/transition.d.ts +31 -0
- package/dist/transition/transition.d.ts.map +1 -0
- package/dist/transition/transition.js +95 -0
- package/dist/transition/transition.js.map +1 -0
- package/dist/webgl/index.d.ts +3 -0
- package/dist/webgl/index.d.ts.map +1 -0
- package/dist/webgl/index.js +2 -0
- package/dist/webgl/index.js.map +1 -0
- package/dist/webgl/webgl.d.ts +49 -0
- package/dist/webgl/webgl.d.ts.map +1 -0
- package/dist/webgl/webgl.js +401 -0
- package/dist/webgl/webgl.js.map +1 -0
- package/package.json +269 -0
- package/styles/base/global.css +47 -0
- package/styles/base/reset.css +73 -0
- package/styles/tokens/colors.css +50 -0
- package/styles/tokens/spacing.css +46 -0
- package/styles/tokens/typography.css +37 -0
- package/styles/utilities/layout.css +46 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nova Engine — Role-Based Access Control (RBAC)
|
|
3
|
+
*
|
|
4
|
+
* Permissions, roles, role hierarchies, resource-level guards,
|
|
5
|
+
* and UI visibility control. Works standalone or with the
|
|
6
|
+
* Nova router for route-level access control.
|
|
7
|
+
*/
|
|
8
|
+
/** Create an RBAC instance. */
|
|
9
|
+
export function createRBAC(options) {
|
|
10
|
+
const { denyByDefault = true, onDenied, } = options;
|
|
11
|
+
const roleMap = new Map();
|
|
12
|
+
let userRoles = new Set(options.userRoles ?? []);
|
|
13
|
+
const changeListeners = new Set();
|
|
14
|
+
const visibilityCleanups = [];
|
|
15
|
+
// Index roles
|
|
16
|
+
for (const role of options.roles) {
|
|
17
|
+
roleMap.set(role.name, role);
|
|
18
|
+
}
|
|
19
|
+
function notifyChange() {
|
|
20
|
+
for (const listener of changeListeners)
|
|
21
|
+
listener();
|
|
22
|
+
}
|
|
23
|
+
/** Resolve all permissions for a role, including inherited ones. */
|
|
24
|
+
function resolvePermissions(roleName, visited = new Set()) {
|
|
25
|
+
if (visited.has(roleName))
|
|
26
|
+
return []; // Prevent circular inheritance
|
|
27
|
+
visited.add(roleName);
|
|
28
|
+
const role = roleMap.get(roleName);
|
|
29
|
+
if (!role)
|
|
30
|
+
return [];
|
|
31
|
+
const permissions = [...role.permissions];
|
|
32
|
+
// Resolve inherited permissions
|
|
33
|
+
if (role.inherits) {
|
|
34
|
+
for (const parentName of role.inherits) {
|
|
35
|
+
permissions.push(...resolvePermissions(parentName, visited));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return permissions;
|
|
39
|
+
}
|
|
40
|
+
/** Get all permissions for current user across all roles. */
|
|
41
|
+
function getAllPermissions() {
|
|
42
|
+
const permissions = [];
|
|
43
|
+
for (const roleName of userRoles) {
|
|
44
|
+
permissions.push(...resolvePermissions(roleName));
|
|
45
|
+
}
|
|
46
|
+
return permissions;
|
|
47
|
+
}
|
|
48
|
+
/** Check if a permission matches a resource/action query. */
|
|
49
|
+
function matchesPermission(perm, resource, action, context) {
|
|
50
|
+
// Wildcard resource
|
|
51
|
+
const resourceMatch = perm.resource === '*'
|
|
52
|
+
|| perm.resource === resource
|
|
53
|
+
// Hierarchical: 'admin.*' matches 'admin.settings'
|
|
54
|
+
|| (perm.resource.endsWith('.*') && resource.startsWith(perm.resource.slice(0, -1)));
|
|
55
|
+
if (!resourceMatch)
|
|
56
|
+
return false;
|
|
57
|
+
// Wildcard action
|
|
58
|
+
const actionMatch = perm.action === '*' || perm.action === action;
|
|
59
|
+
if (!actionMatch)
|
|
60
|
+
return false;
|
|
61
|
+
// Condition check
|
|
62
|
+
if (perm.condition && context) {
|
|
63
|
+
return perm.condition(context);
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
const instance = {
|
|
68
|
+
can(resource, action, context) {
|
|
69
|
+
const permissions = getAllPermissions();
|
|
70
|
+
const allowed = permissions.some(p => matchesPermission(p, resource, action, context));
|
|
71
|
+
if (!allowed && denyByDefault) {
|
|
72
|
+
onDenied?.(resource, action);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return allowed || !denyByDefault;
|
|
76
|
+
},
|
|
77
|
+
canAll(checks) {
|
|
78
|
+
return checks.every(c => instance.can(c.resource, c.action));
|
|
79
|
+
},
|
|
80
|
+
canAny(checks) {
|
|
81
|
+
return checks.some(c => instance.can(c.resource, c.action));
|
|
82
|
+
},
|
|
83
|
+
setRoles(roles) {
|
|
84
|
+
userRoles = new Set(roles);
|
|
85
|
+
notifyChange();
|
|
86
|
+
},
|
|
87
|
+
addRole(role) {
|
|
88
|
+
userRoles.add(role);
|
|
89
|
+
notifyChange();
|
|
90
|
+
},
|
|
91
|
+
removeRole(role) {
|
|
92
|
+
userRoles.delete(role);
|
|
93
|
+
notifyChange();
|
|
94
|
+
},
|
|
95
|
+
getRoles() {
|
|
96
|
+
return [...userRoles];
|
|
97
|
+
},
|
|
98
|
+
getPermissions() {
|
|
99
|
+
return getAllPermissions();
|
|
100
|
+
},
|
|
101
|
+
defineRole(role) {
|
|
102
|
+
roleMap.set(role.name, role);
|
|
103
|
+
notifyChange();
|
|
104
|
+
},
|
|
105
|
+
removeRoleDefinition(name) {
|
|
106
|
+
roleMap.delete(name);
|
|
107
|
+
userRoles.delete(name);
|
|
108
|
+
notifyChange();
|
|
109
|
+
},
|
|
110
|
+
guard(resource, action, fn) {
|
|
111
|
+
if (instance.can(resource, action))
|
|
112
|
+
return fn();
|
|
113
|
+
return undefined;
|
|
114
|
+
},
|
|
115
|
+
async guardAsync(resource, action, fn) {
|
|
116
|
+
if (instance.can(resource, action))
|
|
117
|
+
return fn();
|
|
118
|
+
return undefined;
|
|
119
|
+
},
|
|
120
|
+
routeGuard(resource, action) {
|
|
121
|
+
return () => instance.can(resource, action);
|
|
122
|
+
},
|
|
123
|
+
onChange(handler) {
|
|
124
|
+
changeListeners.add(handler);
|
|
125
|
+
return () => changeListeners.delete(handler);
|
|
126
|
+
},
|
|
127
|
+
bindVisibility(element, resource, action) {
|
|
128
|
+
const el = element;
|
|
129
|
+
function update() {
|
|
130
|
+
el.style.display = instance.can(resource, action) ? '' : 'none';
|
|
131
|
+
}
|
|
132
|
+
update();
|
|
133
|
+
const unsub = instance.onChange(update);
|
|
134
|
+
const cleanup = () => {
|
|
135
|
+
unsub();
|
|
136
|
+
el.style.display = '';
|
|
137
|
+
};
|
|
138
|
+
visibilityCleanups.push(cleanup);
|
|
139
|
+
return cleanup;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
return instance;
|
|
143
|
+
}
|
|
144
|
+
// --- Utility: Permission string parser ---
|
|
145
|
+
/**
|
|
146
|
+
* Parse a permission string like "posts:write" or "admin.*:*"
|
|
147
|
+
* into a Permission object.
|
|
148
|
+
*/
|
|
149
|
+
export function parsePermission(str) {
|
|
150
|
+
const [resource, action = '*'] = str.split(':');
|
|
151
|
+
return { resource, action };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create a role from a simple list of permission strings.
|
|
155
|
+
* e.g., defineSimpleRole('editor', ['posts:read', 'posts:write', 'comments:*'])
|
|
156
|
+
*/
|
|
157
|
+
export function defineSimpleRole(name, permissions, inherits) {
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
permissions: permissions.map(parsePermission),
|
|
161
|
+
inherits,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=rbac.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/security/rbac.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nova Engine — Input Sanitization
|
|
3
|
+
*
|
|
4
|
+
* HTML sanitizer with tag/attribute allowlists, URL validation,
|
|
5
|
+
* and text cleaning utilities. Zero dependencies — uses the
|
|
6
|
+
* browser's native DOMParser for safe HTML parsing.
|
|
7
|
+
*/
|
|
8
|
+
export interface SanitizeOptions {
|
|
9
|
+
/** Allowed HTML tags. Default: common safe tags */
|
|
10
|
+
allowedTags?: string[];
|
|
11
|
+
/** Allowed attributes per tag. '*' key applies to all tags */
|
|
12
|
+
allowedAttributes?: Record<string, string[]>;
|
|
13
|
+
/** Allowed URL schemes. Default: ['http', 'https', 'mailto'] */
|
|
14
|
+
allowedSchemes?: string[];
|
|
15
|
+
/** Allow data: URIs for images. Default: false */
|
|
16
|
+
allowDataUrls?: boolean;
|
|
17
|
+
/** Strip all HTML (return plain text). Default: false */
|
|
18
|
+
stripAll?: boolean;
|
|
19
|
+
/** Max output length. Default: unlimited */
|
|
20
|
+
maxLength?: number;
|
|
21
|
+
/** Custom tag transformer */
|
|
22
|
+
transformTag?: (tag: string, attribs: Record<string, string>) => {
|
|
23
|
+
tag: string;
|
|
24
|
+
attribs: Record<string, string>;
|
|
25
|
+
} | null;
|
|
26
|
+
}
|
|
27
|
+
/** Sanitize HTML string, removing dangerous tags and attributes. */
|
|
28
|
+
export declare function sanitize(html: string, options?: SanitizeOptions): string;
|
|
29
|
+
/** Strip all HTML tags, returning plain text. */
|
|
30
|
+
export declare function stripTags(html: string): string;
|
|
31
|
+
/** Escape a string for safe use in HTML content. */
|
|
32
|
+
export declare function escapeHTML(text: string): string;
|
|
33
|
+
/** Validate and sanitize a URL. Returns null if unsafe. */
|
|
34
|
+
export declare function sanitizeURL(url: string, options?: {
|
|
35
|
+
allowedSchemes?: string[];
|
|
36
|
+
allowDataUrls?: boolean;
|
|
37
|
+
}): string | null;
|
|
38
|
+
/** Clean user input: trim, collapse whitespace, remove control chars. */
|
|
39
|
+
export declare function cleanInput(text: string): string;
|
|
40
|
+
/** Sanitize a filename: remove path traversal, special chars. */
|
|
41
|
+
export declare function sanitizeFilename(name: string): string;
|
|
42
|
+
/** Check if a string contains potential XSS payloads. */
|
|
43
|
+
export declare function detectXSS(input: string): boolean;
|
|
44
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kDAAkD;IAClD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;CAC1H;AAyJD,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CA0B5E;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/D,MAAM,GAAG,IAAI,CAKf;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS/C;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcrD;AAED,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgBhD"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nova Engine — Input Sanitization
|
|
3
|
+
*
|
|
4
|
+
* HTML sanitizer with tag/attribute allowlists, URL validation,
|
|
5
|
+
* and text cleaning utilities. Zero dependencies — uses the
|
|
6
|
+
* browser's native DOMParser for safe HTML parsing.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_ALLOWED_TAGS = [
|
|
9
|
+
'a', 'abbr', 'b', 'blockquote', 'br', 'code', 'dd', 'del', 'details',
|
|
10
|
+
'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr',
|
|
11
|
+
'i', 'img', 'ins', 'kbd', 'li', 'mark', 'ol', 'p', 'pre', 'q',
|
|
12
|
+
's', 'samp', 'small', 'span', 'strong', 'sub', 'summary', 'sup',
|
|
13
|
+
'table', 'tbody', 'td', 'th', 'thead', 'time', 'tr', 'u', 'ul', 'var',
|
|
14
|
+
];
|
|
15
|
+
const DEFAULT_ALLOWED_ATTRIBUTES = {
|
|
16
|
+
'*': ['class', 'id', 'title', 'lang', 'dir'],
|
|
17
|
+
'a': ['href', 'target', 'rel'],
|
|
18
|
+
'img': ['src', 'alt', 'width', 'height', 'loading'],
|
|
19
|
+
'blockquote': ['cite'],
|
|
20
|
+
'q': ['cite'],
|
|
21
|
+
'time': ['datetime'],
|
|
22
|
+
'ol': ['start', 'type'],
|
|
23
|
+
'td': ['colspan', 'rowspan'],
|
|
24
|
+
'th': ['colspan', 'rowspan', 'scope'],
|
|
25
|
+
'details': ['open'],
|
|
26
|
+
};
|
|
27
|
+
const DEFAULT_SCHEMES = ['http', 'https', 'mailto'];
|
|
28
|
+
const DANGEROUS_PROTOCOLS = ['javascript', 'vbscript', 'data'];
|
|
29
|
+
function getScheme(url) {
|
|
30
|
+
const match = url.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):/);
|
|
31
|
+
return match ? match[1].toLowerCase() : null;
|
|
32
|
+
}
|
|
33
|
+
function isURLSafe(url, allowedSchemes, allowDataUrls) {
|
|
34
|
+
const trimmed = url.trim().toLowerCase();
|
|
35
|
+
// Block javascript: and vbscript: regardless of encoding
|
|
36
|
+
for (const proto of DANGEROUS_PROTOCOLS) {
|
|
37
|
+
if (proto === 'data' && allowDataUrls)
|
|
38
|
+
continue;
|
|
39
|
+
// Check for obfuscation: j = j, j = j, etc.
|
|
40
|
+
const decoded = trimmed.replace(/&#x?[0-9a-f]+;?/gi, '').replace(/\s+/g, '');
|
|
41
|
+
if (decoded.startsWith(proto + ':'))
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const scheme = getScheme(trimmed);
|
|
45
|
+
if (!scheme)
|
|
46
|
+
return true; // Relative URL — safe
|
|
47
|
+
if (allowDataUrls && scheme === 'data') {
|
|
48
|
+
// Only allow image data URIs
|
|
49
|
+
return trimmed.startsWith('data:image/');
|
|
50
|
+
}
|
|
51
|
+
return allowedSchemes.includes(scheme);
|
|
52
|
+
}
|
|
53
|
+
function sanitizeNode(node, opts, output) {
|
|
54
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
55
|
+
output.push(escapeText(node.textContent ?? ''));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (node.nodeType !== Node.ELEMENT_NODE)
|
|
59
|
+
return;
|
|
60
|
+
const el = node;
|
|
61
|
+
const tag = el.tagName.toLowerCase();
|
|
62
|
+
// Skip disallowed tags but process their children
|
|
63
|
+
if (!opts.allowedTags.includes(tag)) {
|
|
64
|
+
for (const child of el.childNodes) {
|
|
65
|
+
sanitizeNode(child, opts, output);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// Collect allowed attributes
|
|
70
|
+
const attribs = {};
|
|
71
|
+
const globalAllowed = opts.allowedAttributes['*'] ?? [];
|
|
72
|
+
const tagAllowed = opts.allowedAttributes[tag] ?? [];
|
|
73
|
+
const allowed = new Set([...globalAllowed, ...tagAllowed]);
|
|
74
|
+
for (const attr of el.attributes) {
|
|
75
|
+
const name = attr.name.toLowerCase();
|
|
76
|
+
if (!allowed.has(name))
|
|
77
|
+
continue;
|
|
78
|
+
let value = attr.value;
|
|
79
|
+
// Validate URLs in href/src/cite
|
|
80
|
+
if (['href', 'src', 'cite'].includes(name)) {
|
|
81
|
+
if (!isURLSafe(value, opts.allowedSchemes, opts.allowDataUrls))
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Force rel="noopener noreferrer" on target="_blank" links
|
|
85
|
+
if (tag === 'a' && name === 'target' && value === '_blank') {
|
|
86
|
+
attribs['rel'] = 'noopener noreferrer';
|
|
87
|
+
}
|
|
88
|
+
attribs[name] = value;
|
|
89
|
+
}
|
|
90
|
+
// Custom transform
|
|
91
|
+
if (opts.transformTag) {
|
|
92
|
+
const result = opts.transformTag(tag, attribs);
|
|
93
|
+
if (result === null)
|
|
94
|
+
return; // Drop element and children
|
|
95
|
+
// Use transformed tag/attribs
|
|
96
|
+
const attrStr = Object.entries(result.attribs)
|
|
97
|
+
.map(([k, v]) => ` ${escapeAttrName(k)}="${escapeAttrValue(v)}"`)
|
|
98
|
+
.join('');
|
|
99
|
+
output.push(`<${result.tag}${attrStr}>`);
|
|
100
|
+
for (const child of el.childNodes) {
|
|
101
|
+
sanitizeNode(child, opts, output);
|
|
102
|
+
}
|
|
103
|
+
if (!isVoidElement(result.tag))
|
|
104
|
+
output.push(`</${result.tag}>`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const attrStr = Object.entries(attribs)
|
|
108
|
+
.map(([k, v]) => ` ${escapeAttrName(k)}="${escapeAttrValue(v)}"`)
|
|
109
|
+
.join('');
|
|
110
|
+
output.push(`<${tag}${attrStr}>`);
|
|
111
|
+
for (const child of el.childNodes) {
|
|
112
|
+
sanitizeNode(child, opts, output);
|
|
113
|
+
}
|
|
114
|
+
if (!isVoidElement(tag))
|
|
115
|
+
output.push(`</${tag}>`);
|
|
116
|
+
}
|
|
117
|
+
function isVoidElement(tag) {
|
|
118
|
+
return ['br', 'hr', 'img', 'input', 'meta', 'link', 'area', 'base', 'col', 'embed', 'source', 'track', 'wbr'].includes(tag);
|
|
119
|
+
}
|
|
120
|
+
function escapeText(text) {
|
|
121
|
+
return text
|
|
122
|
+
.replace(/&/g, '&')
|
|
123
|
+
.replace(/</g, '<')
|
|
124
|
+
.replace(/>/g, '>');
|
|
125
|
+
}
|
|
126
|
+
function escapeAttrValue(value) {
|
|
127
|
+
return value
|
|
128
|
+
.replace(/&/g, '&')
|
|
129
|
+
.replace(/"/g, '"')
|
|
130
|
+
.replace(/</g, '<')
|
|
131
|
+
.replace(/>/g, '>');
|
|
132
|
+
}
|
|
133
|
+
function escapeAttrName(name) {
|
|
134
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, '');
|
|
135
|
+
}
|
|
136
|
+
/** Sanitize HTML string, removing dangerous tags and attributes. */
|
|
137
|
+
export function sanitize(html, options = {}) {
|
|
138
|
+
if (options.stripAll)
|
|
139
|
+
return stripTags(html);
|
|
140
|
+
const parser = new DOMParser();
|
|
141
|
+
const doc = parser.parseFromString(`<div>${html}</div>`, 'text/html');
|
|
142
|
+
const root = doc.body.firstElementChild;
|
|
143
|
+
if (!root)
|
|
144
|
+
return '';
|
|
145
|
+
const output = [];
|
|
146
|
+
const opts = {
|
|
147
|
+
allowedTags: options.allowedTags ?? DEFAULT_ALLOWED_TAGS,
|
|
148
|
+
allowedAttributes: { ...DEFAULT_ALLOWED_ATTRIBUTES, ...options.allowedAttributes },
|
|
149
|
+
allowedSchemes: options.allowedSchemes ?? DEFAULT_SCHEMES,
|
|
150
|
+
allowDataUrls: options.allowDataUrls ?? false,
|
|
151
|
+
transformTag: options.transformTag,
|
|
152
|
+
};
|
|
153
|
+
for (const child of root.childNodes) {
|
|
154
|
+
sanitizeNode(child, opts, output);
|
|
155
|
+
}
|
|
156
|
+
let result = output.join('');
|
|
157
|
+
if (options.maxLength && result.length > options.maxLength) {
|
|
158
|
+
result = result.slice(0, options.maxLength);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
/** Strip all HTML tags, returning plain text. */
|
|
163
|
+
export function stripTags(html) {
|
|
164
|
+
const parser = new DOMParser();
|
|
165
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
166
|
+
return doc.body.textContent ?? '';
|
|
167
|
+
}
|
|
168
|
+
/** Escape a string for safe use in HTML content. */
|
|
169
|
+
export function escapeHTML(text) {
|
|
170
|
+
return text
|
|
171
|
+
.replace(/&/g, '&')
|
|
172
|
+
.replace(/</g, '<')
|
|
173
|
+
.replace(/>/g, '>')
|
|
174
|
+
.replace(/"/g, '"')
|
|
175
|
+
.replace(/'/g, ''');
|
|
176
|
+
}
|
|
177
|
+
/** Validate and sanitize a URL. Returns null if unsafe. */
|
|
178
|
+
export function sanitizeURL(url, options) {
|
|
179
|
+
const schemes = options?.allowedSchemes ?? DEFAULT_SCHEMES;
|
|
180
|
+
const allowData = options?.allowDataUrls ?? false;
|
|
181
|
+
if (!isURLSafe(url, schemes, allowData))
|
|
182
|
+
return null;
|
|
183
|
+
return url.trim();
|
|
184
|
+
}
|
|
185
|
+
/** Clean user input: trim, collapse whitespace, remove control chars. */
|
|
186
|
+
export function cleanInput(text) {
|
|
187
|
+
return text
|
|
188
|
+
.trim()
|
|
189
|
+
// Remove zero-width chars and control chars (except newline, tab)
|
|
190
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u200B-\u200D\uFEFF]/g, '')
|
|
191
|
+
// Collapse multiple spaces to one
|
|
192
|
+
.replace(/[ \t]+/g, ' ')
|
|
193
|
+
// Collapse multiple newlines to two
|
|
194
|
+
.replace(/\n{3,}/g, '\n\n');
|
|
195
|
+
}
|
|
196
|
+
/** Sanitize a filename: remove path traversal, special chars. */
|
|
197
|
+
export function sanitizeFilename(name) {
|
|
198
|
+
return name
|
|
199
|
+
// Remove path traversal
|
|
200
|
+
.replace(/\.\./g, '')
|
|
201
|
+
// Remove path separators
|
|
202
|
+
.replace(/[/\\]/g, '')
|
|
203
|
+
// Remove null bytes
|
|
204
|
+
.replace(/\0/g, '')
|
|
205
|
+
// Remove special characters except dash, underscore, dot
|
|
206
|
+
.replace(/[^a-zA-Z0-9._-]/g, '_')
|
|
207
|
+
// Remove leading dots (hidden files)
|
|
208
|
+
.replace(/^\.+/, '')
|
|
209
|
+
// Limit length
|
|
210
|
+
.slice(0, 255);
|
|
211
|
+
}
|
|
212
|
+
/** Check if a string contains potential XSS payloads. */
|
|
213
|
+
export function detectXSS(input) {
|
|
214
|
+
const lower = input.toLowerCase().replace(/\s+/g, '');
|
|
215
|
+
const patterns = [
|
|
216
|
+
/<script/i,
|
|
217
|
+
/javascript:/i,
|
|
218
|
+
/vbscript:/i,
|
|
219
|
+
/on\w+\s*=/i,
|
|
220
|
+
/expression\s*\(/i,
|
|
221
|
+
/url\s*\(\s*['"]?\s*javascript/i,
|
|
222
|
+
/<iframe/i,
|
|
223
|
+
/<object/i,
|
|
224
|
+
/<embed/i,
|
|
225
|
+
/<form/i,
|
|
226
|
+
/&#x?[0-9a-f]+;/i,
|
|
227
|
+
];
|
|
228
|
+
return patterns.some(p => p.test(lower) || p.test(input));
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/security/sanitize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nova Engine — Secure Storage
|
|
3
|
+
*
|
|
4
|
+
* Encrypted localStorage/sessionStorage wrapper using AES-GCM.
|
|
5
|
+
* All values are encrypted at rest with a derived key from a
|
|
6
|
+
* user-provided passphrase or auto-generated key.
|
|
7
|
+
*/
|
|
8
|
+
export interface SecureStoreOptions {
|
|
9
|
+
/** Passphrase for key derivation. If omitted, generates a random key. */
|
|
10
|
+
passphrase?: string;
|
|
11
|
+
/** Storage key prefix. Default: 'nova_secure' */
|
|
12
|
+
prefix?: string;
|
|
13
|
+
/** Use sessionStorage (true) or localStorage (false). Default: false */
|
|
14
|
+
sessionOnly?: boolean;
|
|
15
|
+
/** PBKDF2 iterations for key derivation. Default: 100000 */
|
|
16
|
+
iterations?: number;
|
|
17
|
+
/** Key length in bits. Default: 256 */
|
|
18
|
+
keyLength?: 128 | 192 | 256;
|
|
19
|
+
/** Auto-expire entries after ms. Default: 0 (no expiry) */
|
|
20
|
+
defaultTTL?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface SecureStoreInstance {
|
|
23
|
+
/** Initialize the store (must be called before get/set). */
|
|
24
|
+
init(): Promise<void>;
|
|
25
|
+
/** Store an encrypted value. */
|
|
26
|
+
set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
|
27
|
+
/** Retrieve and decrypt a value. */
|
|
28
|
+
get<T>(key: string): Promise<T | null>;
|
|
29
|
+
/** Check if a key exists and is not expired. */
|
|
30
|
+
has(key: string): boolean;
|
|
31
|
+
/** Remove a key. */
|
|
32
|
+
remove(key: string): void;
|
|
33
|
+
/** Clear all secure store entries. */
|
|
34
|
+
clear(): void;
|
|
35
|
+
/** List all keys (without prefix). */
|
|
36
|
+
keys(): string[];
|
|
37
|
+
/** Get number of stored entries. */
|
|
38
|
+
size(): number;
|
|
39
|
+
/** Destroy — clear keys from memory. */
|
|
40
|
+
destroy(): void;
|
|
41
|
+
}
|
|
42
|
+
/** Create an encrypted storage instance. */
|
|
43
|
+
export declare function createSecureStore(options?: SecureStoreOptions): SecureStoreInstance;
|
|
44
|
+
//# sourceMappingURL=secure-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-store.d.ts","sourceRoot":"","sources":["../../src/security/secure-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC5B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,gCAAgC;IAChC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,oCAAoC;IACpC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,gDAAgD;IAChD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,oBAAoB;IACpB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sCAAsC;IACtC,KAAK,IAAI,IAAI,CAAC;IACd,sCAAsC;IACtC,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,oCAAoC;IACpC,IAAI,IAAI,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB;AAsBD,4CAA4C;AAC5C,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,mBAAmB,CA8LvF"}
|