@strands.gg/accui 2.8.1 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/index.cjs.js +1 -1
  2. package/dist/index.d.ts +7 -1
  3. package/dist/index.es.js +5 -5
  4. package/dist/nuxt/module.d.ts +4 -1
  5. package/dist/nuxt/runtime/composables/useAuthenticatedFetch.d.ts +20 -1
  6. package/dist/nuxt/runtime/composables/useStrandsAuth.cjs.js +1 -1
  7. package/dist/nuxt/runtime/composables/useStrandsAuth.d.ts +65 -1
  8. package/dist/nuxt/runtime/composables/useStrandsAuth.es.js +1 -1
  9. package/dist/nuxt/runtime/middleware/auth.d.ts +6 -0
  10. package/dist/nuxt/runtime/middleware/auth.global.d.ts +2 -1
  11. package/dist/nuxt/runtime/middleware/guest.d.ts +6 -0
  12. package/dist/nuxt/runtime/plugin.client.d.ts +2 -1
  13. package/dist/nuxt/runtime/plugin.server.d.ts +2 -1
  14. package/dist/nuxt/runtime/plugins/auth-interceptor.client.d.ts +2 -1
  15. package/dist/nuxt/types.d.ts +45 -0
  16. package/dist/nuxt.d.ts +4 -1
  17. package/dist/shared/defaults.d.ts +2 -0
  18. package/dist/types/composables.d.ts +96 -0
  19. package/dist/types/index.d.ts +242 -0
  20. package/dist/useStrandsAuth-Bp5aTR3h.cjs.js +1 -0
  21. package/dist/{useStrandsAuth-jI_X_wiK.es.js → useStrandsAuth-Xz8lnhv7.es.js} +1 -1
  22. package/dist/utils/colors.d.ts +10 -0
  23. package/dist/utils/index.d.ts +2 -0
  24. package/dist/utils/slots.d.ts +1 -0
  25. package/dist/utils/validation.d.ts +12 -0
  26. package/dist/vue/components/StrandsNav/index.d.ts +8 -0
  27. package/dist/vue/components/StrandsNav/types.d.ts +12 -0
  28. package/dist/vue/components/icons/index.d.ts +2 -0
  29. package/dist/vue/components/index.d.ts +27 -0
  30. package/dist/vue/composables/useAuthenticatedFetch.d.ts +20 -0
  31. package/dist/vue/composables/useDarkMode.d.ts +48 -0
  32. package/dist/vue/composables/useFloatingPosition.d.ts +22 -0
  33. package/dist/vue/composables/useModalStack.d.ts +86 -0
  34. package/dist/vue/composables/useOAuthProviders.d.ts +73 -0
  35. package/dist/vue/composables/useStrandsAuth.d.ts +2 -0
  36. package/dist/vue/composables/useStrandsConfig.d.ts +5 -0
  37. package/dist/vue/composables/useStrandsMfa.d.ts +36 -0
  38. package/dist/vue/composables/useTheme.d.ts +18 -0
  39. package/dist/vue/index.d.ts +16 -0
  40. package/dist/vue/plugins/StrandsUIPlugin.d.ts +20 -0
  41. package/dist/vue/ui/UiButton/index.d.ts +13 -0
  42. package/dist/vue/ui/index.d.ts +54 -0
  43. package/dist/vue/utils/contrast.d.ts +75 -0
  44. package/dist/vue/utils/debounce.d.ts +12 -0
  45. package/dist/vue/utils/fontPreloader.d.ts +11 -0
  46. package/dist/vue/utils/iconProps.d.ts +9 -0
  47. package/dist/vue/utils/lazyComponents.d.ts +4 -0
  48. package/dist/vue/utils/levels.d.ts +27 -0
  49. package/dist/vue/utils/modalStack.d.ts +31 -0
  50. package/dist/vue/utils/performanceInit.d.ts +40 -0
  51. package/dist/vue/utils/requestCache.d.ts +49 -0
  52. package/dist/vue/utils/sounds.d.ts +57 -0
  53. package/package.json +2 -3
  54. package/dist/auth-interceptor.client.d.ts +0 -1
  55. package/dist/auth.global.d.ts +0 -1
  56. package/dist/module.d.ts +0 -1
  57. package/dist/plugin.client.d.ts +0 -1
  58. package/dist/plugin.server.d.ts +0 -1
  59. package/dist/useAuthenticatedFetch.d.ts +0 -1
  60. package/dist/useStrandsAuth-Ca9Zqmfy.cjs.js +0 -1
  61. package/dist/useStrandsAuth.d.ts +0 -1
package/dist/index.d.ts CHANGED
@@ -1 +1,7 @@
1
- export { }
1
+ import './styles/base.css';
2
+ export * from './vue/components';
3
+ export * from './vue/ui';
4
+ export { default as StrandsUIPlugin } from './vue/plugins/StrandsUIPlugin';
5
+ export { useStrandsAuth, useStrandsConfig, setStrandsConfig, provideStrandsConfig, useOAuthProviders, useAuthenticatedFetch, $authFetch, useTheme, useFloatingPosition, useModalStack, useModalTeleport, useGlobalModalStack } from './vue';
6
+ export * from './utils';
7
+ export type * from './types/index';
package/dist/index.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineComponent, computed, provide, onMounted, onUnmounted, createElementBlock, openBlock, normalizeClass, createElementVNode, createBlock, renderSlot, Teleport, createCommentVNode, toDisplayString, createTextVNode, unref, normalizeStyle, useSlots, createVNode, Fragment as Fragment$1, withCtx, resolveComponent, resolveDynamicComponent, createSlots, useAttrs, h as h$1, ref, nextTick, withModifiers, renderList, watch, toRefs, withDirectives, vModelSelect, getCurrentInstance, watchEffect, onBeforeUnmount, shallowRef, markRaw, customRef, useCssVars, mergeProps, reactive, createStaticVNode, vModelText, Transition, inject, withKeys, isMemoSame } from "vue";
2
2
  import { u as useStrandsConfig, p as provideStrandsConfig } from "./useStrandsConfig-XmPqJn_B.es.js";
3
3
  import { s } from "./useStrandsConfig-XmPqJn_B.es.js";
4
- import { u as useStrandsAuth } from "./useStrandsAuth-jI_X_wiK.es.js";
4
+ import { u as useStrandsAuth } from "./useStrandsAuth-Xz8lnhv7.es.js";
5
5
  const _hoisted_1$U = { class: "app-content" };
6
6
  const _hoisted_2$L = {
7
7
  key: 0,
@@ -1770,14 +1770,14 @@ function useFloatingPosition(options) {
1770
1770
  ...width ? { width: `${width}px` } : {}
1771
1771
  };
1772
1772
  if (flippedToTop) {
1773
- style2.bottom = `${viewportHeight - y - floatingRect.height}px`;
1773
+ style2["bottom"] = `${viewportHeight - y - floatingRect.height}px`;
1774
1774
  } else {
1775
- style2.top = `${y}px`;
1775
+ style2["top"] = `${y}px`;
1776
1776
  }
1777
1777
  if (flippedToLeft) {
1778
- style2.right = `${viewportWidth - x - floatingRect.width}px`;
1778
+ style2["right"] = `${viewportWidth - x - floatingRect.width}px`;
1779
1779
  } else {
1780
- style2.left = `${x}px`;
1780
+ style2["left"] = `${x}px`;
1781
1781
  }
1782
1782
  floatingStyle.value = style2;
1783
1783
  };
@@ -1 +1,4 @@
1
- export {}
1
+ export type { StrandsAuthConfig, StrandsAuthEndpoints } from '../types';
2
+ import type { StrandsAuthConfig } from '../types';
3
+ declare const _default: import("@nuxt/schema").NuxtModule<StrandsAuthConfig, StrandsAuthConfig, false>;
4
+ export default _default;
@@ -1 +1,20 @@
1
- export {}
1
+ import type { AuthenticatedFetchOptions } from '../../../types';
2
+ /**
3
+ * Enhanced fetch composable that automatically includes auth headers
4
+ * and handles token refresh for API requests
5
+ */
6
+ export declare function useAuthenticatedFetch(): {
7
+ authenticatedFetch: (url: string | URL, options?: AuthenticatedFetchOptions) => Promise<Response>;
8
+ get: (url: string | URL, options?: AuthenticatedFetchOptions) => Promise<Response>;
9
+ post: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
10
+ put: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
11
+ delete: (url: string | URL, options?: AuthenticatedFetchOptions) => Promise<Response>;
12
+ patch: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
13
+ };
14
+ export declare const $authFetch: {
15
+ get: (url: string | URL, options?: AuthenticatedFetchOptions) => Promise<Response>;
16
+ post: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
17
+ put: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
18
+ delete: (url: string | URL, options?: AuthenticatedFetchOptions) => Promise<Response>;
19
+ patch: (url: string | URL, body?: any, options?: AuthenticatedFetchOptions) => Promise<Response>;
20
+ };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("nuxt/app"),s=require("../../../useStrandsAuth-Ca9Zqmfy.cjs.js"),a=()=>{const a=t.useRuntimeConfig().public.strandsAuth,e=s.useStrandsAuth();return{...e,initialize:async()=>{await e.initialize()},signIn:async s=>{const i=await e.signIn(s);return i&&a.onSignInUrl&&await t.navigateTo(a.onSignInUrl),i},signUp:async t=>await e.signUp({email:t.email,password:"",firstName:"",lastName:""}),signOut:async()=>{await e.signOut(),a.onSignOutUrl&&await t.navigateTo(a.onSignOutUrl)}}};exports.useAuthState=()=>{const{isAuthenticated:t,isLoading:s}=a();return{isAuthenticated:t,isLoading:s}},exports.useAuthUser=()=>{const{user:t}=a();return{user:t}},exports.useStrandsAuth=a;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("nuxt/app"),s=require("../../../useStrandsAuth-Bp5aTR3h.cjs.js"),a=()=>{const a=t.useRuntimeConfig().public.strandsAuth,e=s.useStrandsAuth();return{...e,initialize:async()=>{await e.initialize()},signIn:async s=>{const i=await e.signIn(s);return i&&a.onSignInUrl&&await t.navigateTo(a.onSignInUrl),i},signUp:async t=>await e.signUp({email:t.email,password:"",firstName:"",lastName:""}),signOut:async()=>{await e.signOut(),a.onSignOutUrl&&await t.navigateTo(a.onSignOutUrl)}}};exports.useAuthState=()=>{const{isAuthenticated:t,isLoading:s}=a();return{isAuthenticated:t,isLoading:s}},exports.useAuthUser=()=>{const{user:t}=a();return{user:t}},exports.useStrandsAuth=a;
@@ -1 +1,65 @@
1
- export {}
1
+ import type { ComputedRef } from 'vue';
2
+ import type { User } from '../../../types';
3
+ export declare const useStrandsAuth: () => {
4
+ initialize: () => Promise<void>;
5
+ signIn: (credentials: {
6
+ email: string;
7
+ password: string;
8
+ }) => Promise<any>;
9
+ signUp: (userData: {
10
+ email: string;
11
+ }) => Promise<void>;
12
+ signOut: () => Promise<void>;
13
+ user: ComputedRef<User | null>;
14
+ currentUser: ComputedRef<User | null>;
15
+ currentSession: ComputedRef<import("../../..").Session | null>;
16
+ isAuthenticated: ComputedRef<boolean>;
17
+ isLoading: ComputedRef<boolean>;
18
+ loading: ComputedRef<boolean>;
19
+ loadingMessage: ComputedRef<string>;
20
+ isInitializing: ComputedRef<boolean>;
21
+ isSigningIn: ComputedRef<boolean>;
22
+ isSigningUp: ComputedRef<boolean>;
23
+ isSigningOut: ComputedRef<boolean>;
24
+ isRefreshingToken: ComputedRef<boolean>;
25
+ isSendingMfaEmail: ComputedRef<boolean>;
26
+ isVerifyingMfa: ComputedRef<boolean>;
27
+ mfaRequired: ComputedRef<boolean>;
28
+ mfaSessionId: ComputedRef<string | null>;
29
+ availableMfaMethods: ComputedRef<import("../../..").MfaDevice[]>;
30
+ refreshToken: () => Promise<boolean>;
31
+ fetchProfile: () => Promise<User>;
32
+ updateProfile: (updates: Partial<User>) => Promise<User>;
33
+ updateUserSettings: (settings: any) => Promise<User>;
34
+ changeEmail: (newEmail: string, password: string) => Promise<void>;
35
+ changeUsername: (newUsername: string) => Promise<void>;
36
+ getUsernameCooldown: () => Promise<{
37
+ canChange: boolean;
38
+ cooldownEndsAt?: Date;
39
+ }>;
40
+ checkUsernameAvailability: (username: string) => Promise<{
41
+ available: boolean;
42
+ suggestion?: string;
43
+ }>;
44
+ getUserSessions: () => Promise<import("../../..").SessionInfo[]>;
45
+ getSessionStats: () => Promise<import("../../..").SessionStats>;
46
+ revokeSession: (sessionId: string) => Promise<boolean>;
47
+ revokeAllOtherSessions: () => Promise<boolean>;
48
+ forceReInit: () => void;
49
+ setAuthData: (authData: any) => Promise<void>;
50
+ verifyMfa: (code: string, method?: string) => Promise<any>;
51
+ sendMfaEmailCode: (deviceId: string) => Promise<any>;
52
+ getMfaWebAuthnChallenge: (deviceId: string) => Promise<any>;
53
+ registerHardwareKey: (deviceName: string, accessToken: string, deviceType?: "hardware" | "passkey") => Promise<any>;
54
+ completeHardwareKeyRegistration: (deviceId: string, credential: any, accessToken: string) => Promise<any>;
55
+ startTokenRefreshTimer: () => void;
56
+ stopTokenRefreshTimer: () => void;
57
+ getAuthHeaders: () => Record<string, string>;
58
+ };
59
+ export declare const useAuthUser: () => {
60
+ user: ComputedRef<User | null>;
61
+ };
62
+ export declare const useAuthState: () => {
63
+ isAuthenticated: ComputedRef<boolean>;
64
+ isLoading: ComputedRef<boolean>;
65
+ };
@@ -1,5 +1,5 @@
1
1
  import { useRuntimeConfig, navigateTo } from "nuxt/app";
2
- import { u as useStrandsAuth$1 } from "../../../useStrandsAuth-jI_X_wiK.es.js";
2
+ import { u as useStrandsAuth$1 } from "../../../useStrandsAuth-Xz8lnhv7.es.js";
3
3
  const useStrandsAuth = () => {
4
4
  const config = useRuntimeConfig().public["strandsAuth"];
5
5
  const vueAuth = useStrandsAuth$1();
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Middleware to protect routes - requires authentication
3
+ * Usage: Add `middleware: 'auth'` to your page
4
+ */
5
+ declare const _default: import("nuxt/app").RouteMiddleware;
6
+ export default _default;
@@ -1 +1,2 @@
1
- export {}
1
+ declare const _default: import("nuxt/app").RouteMiddleware;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Middleware for guest-only routes - redirects if authenticated
3
+ * Usage: Add `middleware: 'guest'` to your page
4
+ */
5
+ declare const _default: import("nuxt/app").RouteMiddleware;
6
+ export default _default;
@@ -1 +1,2 @@
1
- export {}
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
+ export default _default;
@@ -1 +1,2 @@
1
- export {}
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
+ export default _default;
@@ -1 +1,2 @@
1
- export {}
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
+ export default _default;
@@ -0,0 +1,45 @@
1
+ export interface StrandsUser {
2
+ id: string;
3
+ email: string;
4
+ firstName: string;
5
+ lastName: string;
6
+ avatar?: string;
7
+ mfaEnabled: boolean;
8
+ emailVerified: boolean;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ }
12
+ export interface StrandsSession {
13
+ accessToken: string;
14
+ refreshToken: string;
15
+ expiresAt: Date;
16
+ user: StrandsUser;
17
+ }
18
+ declare module '@nuxt/schema' {
19
+ interface PublicRuntimeConfig {
20
+ strandsAuth?: {
21
+ baseUrl?: string;
22
+ applicationId?: string;
23
+ publicKey?: string;
24
+ accentColor?: string;
25
+ redirectUrl?: string;
26
+ onSignInUrl?: string;
27
+ onSignOutUrl?: string;
28
+ /** @deprecated OAuth providers are now dynamically fetched from API */
29
+ oauthProviders?: string[];
30
+ autoRefresh?: boolean;
31
+ refreshInterval?: number;
32
+ protectedRoutes?: string[];
33
+ guestOnlyRoutes?: string[];
34
+ devMode?: boolean;
35
+ };
36
+ }
37
+ }
38
+ declare module 'nuxt/app' {
39
+ interface NuxtApp {
40
+ $strandsAuth: {
41
+ accentColor: string;
42
+ };
43
+ }
44
+ }
45
+ export {};
package/dist/nuxt.d.ts CHANGED
@@ -1 +1,4 @@
1
- export { }
1
+ export { default } from './nuxt/module';
2
+ export type { StrandsAuthConfig, StrandsAuthEndpoints } from './types';
3
+ export { useStrandsAuth, useAuthUser, useAuthState } from './nuxt/runtime/composables/useStrandsAuth';
4
+ export { useAuthenticatedFetch, $authFetch } from './nuxt/runtime/composables/useAuthenticatedFetch';
@@ -0,0 +1,2 @@
1
+ import type { StrandsAuthConfig } from '../types';
2
+ export declare const STRANDS_AUTH_DEFAULTS: Required<Omit<StrandsAuthConfig, 'clientId' | 'supportEmail' | 'oauth2RedirectUrl'>>;
@@ -0,0 +1,96 @@
1
+ import type { ComputedRef, Ref } from 'vue';
2
+ import type { User, Session, SignInCredentials, SignUpData, SessionInfo, SessionStats, MfaDevice, StrandsAuthConfig, StrandsAuthEndpoints, AuthenticatedFetchOptions } from './index';
3
+ export interface UseStrandsAuthReturn {
4
+ user: ComputedRef<User | null>;
5
+ currentUser: ComputedRef<User | null>;
6
+ currentSession: ComputedRef<Session | null>;
7
+ isAuthenticated: ComputedRef<boolean>;
8
+ isLoading: ComputedRef<boolean>;
9
+ loading: ComputedRef<boolean>;
10
+ loadingMessage: ComputedRef<string>;
11
+ isInitializing: ComputedRef<boolean>;
12
+ isSigningIn: ComputedRef<boolean>;
13
+ isSigningUp: ComputedRef<boolean>;
14
+ isSigningOut: ComputedRef<boolean>;
15
+ isRefreshingToken: ComputedRef<boolean>;
16
+ isSendingMfaEmail: ComputedRef<boolean>;
17
+ isVerifyingMfa: ComputedRef<boolean>;
18
+ mfaRequired: ComputedRef<boolean>;
19
+ mfaSessionId: ComputedRef<string | null>;
20
+ availableMfaMethods: ComputedRef<MfaDevice[]>;
21
+ signIn: (credentials: SignInCredentials) => Promise<any>;
22
+ signUp: (userData: SignUpData) => Promise<void>;
23
+ signOut: () => Promise<void>;
24
+ refreshToken: () => Promise<boolean>;
25
+ fetchProfile: () => Promise<User>;
26
+ updateProfile: (updates: Partial<User>) => Promise<User>;
27
+ updateUserSettings: (settings: any) => Promise<User>;
28
+ changeEmail: (newEmail: string, password: string) => Promise<void>;
29
+ changeUsername: (newUsername: string) => Promise<void>;
30
+ getUsernameCooldown: () => Promise<{
31
+ canChange: boolean;
32
+ cooldownEndsAt?: Date;
33
+ }>;
34
+ checkUsernameAvailability: (username: string) => Promise<{
35
+ available: boolean;
36
+ suggestion?: string;
37
+ }>;
38
+ getUserSessions: () => Promise<SessionInfo[]>;
39
+ getSessionStats: () => Promise<SessionStats>;
40
+ revokeSession: (sessionId: string) => Promise<boolean>;
41
+ revokeAllOtherSessions: () => Promise<boolean>;
42
+ initialize: () => Promise<void>;
43
+ forceReInit: () => void;
44
+ setAuthData: (authData: any) => Promise<void>;
45
+ verifyMfa: (code: string, method?: string) => Promise<any>;
46
+ sendMfaEmailCode: (deviceId: string) => Promise<any>;
47
+ getMfaWebAuthnChallenge: (deviceId: string) => Promise<any>;
48
+ registerHardwareKey: (deviceName: string, accessToken: string, deviceType?: 'hardware' | 'passkey') => Promise<any>;
49
+ completeHardwareKeyRegistration: (deviceId: string, credential: any, accessToken: string) => Promise<any>;
50
+ startTokenRefreshTimer: () => void;
51
+ stopTokenRefreshTimer: () => void;
52
+ getAuthHeaders: () => Record<string, string>;
53
+ }
54
+ export interface UseStrandsConfigReturn {
55
+ config: ComputedRef<StrandsAuthConfig>;
56
+ endpoints: ComputedRef<StrandsAuthEndpoints>;
57
+ getUrl: (endpoint: keyof StrandsAuthEndpoints | string) => string;
58
+ getSupportEmail: () => string | null;
59
+ }
60
+ export interface UseAuthenticatedFetchReturn {
61
+ $fetch: <T = any>(url: string, options?: AuthenticatedFetchOptions) => Promise<T>;
62
+ isLoading: Ref<boolean>;
63
+ error: Ref<Error | null>;
64
+ }
65
+ export interface UseOAuthProvidersReturn {
66
+ providers: ComputedRef<any[]>;
67
+ loading: Ref<boolean>;
68
+ fetchProviders: () => Promise<void>;
69
+ }
70
+ export interface UseThemeReturn {
71
+ isDark: Ref<boolean>;
72
+ toggleTheme: () => void;
73
+ setTheme: (dark: boolean) => void;
74
+ }
75
+ export interface UseFloatingPositionReturn {
76
+ x: Ref<number>;
77
+ y: Ref<number>;
78
+ placement: Ref<string>;
79
+ update: () => void;
80
+ }
81
+ export interface UseModalStackReturn {
82
+ modalStack: Ref<string[]>;
83
+ pushModal: (id: string) => void;
84
+ popModal: () => void;
85
+ isTopModal: (id: string) => boolean;
86
+ }
87
+ export interface UseModalTeleportReturn {
88
+ teleportTarget: Ref<string>;
89
+ updateTeleportTarget: () => void;
90
+ }
91
+ export interface UseGlobalModalStackReturn {
92
+ globalModalStack: Ref<string[]>;
93
+ addModal: (id: string) => void;
94
+ removeModal: (id: string) => void;
95
+ isTopModal: (id: string) => boolean;
96
+ }
@@ -0,0 +1,242 @@
1
+ export interface User {
2
+ id: string;
3
+ email: string;
4
+ firstName: string;
5
+ lastName: string;
6
+ avatar?: string;
7
+ mfaEnabled: boolean;
8
+ emailVerified: boolean;
9
+ passwordUpdatedAt?: string | Date;
10
+ settings?: any;
11
+ xp: number;
12
+ level: number;
13
+ next_level_xp: number;
14
+ username?: string;
15
+ usernameLastChangedAt?: string | Date;
16
+ createdAt: string | Date;
17
+ updatedAt: string | Date;
18
+ }
19
+ export interface AuthenticatedFetchOptions extends RequestInit {
20
+ /**
21
+ * Whether to automatically refresh token if the request fails with 401
22
+ * @default true
23
+ */
24
+ autoRefresh?: boolean;
25
+ /**
26
+ * Whether to throw an error if user is not authenticated
27
+ * @default true
28
+ */
29
+ requireAuth?: boolean;
30
+ /**
31
+ * Base URL for the API requests
32
+ * If not provided, will use the current origin
33
+ */
34
+ baseURL?: string;
35
+ }
36
+ export interface Session {
37
+ id?: string;
38
+ userId?: string;
39
+ accessToken: string;
40
+ refreshToken: string;
41
+ expiresAt: Date;
42
+ createdAt?: Date;
43
+ }
44
+ export interface SessionInfo {
45
+ id: string;
46
+ device_name?: string;
47
+ device_type?: string;
48
+ ip_address?: string;
49
+ country?: string;
50
+ city?: string;
51
+ application_domain?: string;
52
+ application_name?: string;
53
+ created_at: string | Date;
54
+ last_activity_at?: string | Date;
55
+ is_current: boolean;
56
+ }
57
+ export interface SessionStats {
58
+ total_sessions: number;
59
+ active_sessions: number;
60
+ devices_by_type: Record<string, number>;
61
+ unique_locations: string[];
62
+ }
63
+ export interface AuthConfig {
64
+ apiUrl: string;
65
+ applicationId: string;
66
+ publicKey: string;
67
+ autoRefresh?: boolean;
68
+ redirectUrl?: string;
69
+ }
70
+ export interface SignInCredentials {
71
+ email: string;
72
+ password: string;
73
+ }
74
+ export interface SignUpData {
75
+ email: string;
76
+ password: string;
77
+ firstName: string;
78
+ lastName: string;
79
+ }
80
+ export interface OAuthProvider {
81
+ id: string;
82
+ name: string;
83
+ enabled: boolean;
84
+ clientId?: string;
85
+ scopes?: string[];
86
+ }
87
+ export interface StrandsAuthConfig {
88
+ /**
89
+ * Base URL for the Strands Auth API
90
+ * @default 'https://your-api.example.com'
91
+ */
92
+ baseUrl?: string;
93
+ /**
94
+ * Client ID for authentication (optional - authentication is now based on domain)
95
+ */
96
+ clientId?: string;
97
+ /**
98
+ * Primary accent color for the auth components
99
+ * @default '#EA00A8'
100
+ */
101
+ accentColor?: string;
102
+ /**
103
+ * Default redirect URL after successful authentication
104
+ * @default '/'
105
+ */
106
+ redirectUrl?: string;
107
+ /**
108
+ * URL to redirect to after successful sign in
109
+ * @default '/dashboard'
110
+ */
111
+ onSignInUrl?: string;
112
+ /**
113
+ * URL to redirect to after successful sign out
114
+ * @default '/'
115
+ */
116
+ onSignOutUrl?: string;
117
+ /**
118
+ * Enable automatic token refresh
119
+ * @default true
120
+ */
121
+ autoRefresh?: boolean;
122
+ /**
123
+ * Token refresh interval in minutes
124
+ * @default 4
125
+ */
126
+ refreshInterval?: number;
127
+ /**
128
+ * Pages that should redirect to sign in if user is not authenticated
129
+ * @default []
130
+ */
131
+ protectedRoutes?: string[];
132
+ /**
133
+ * Pages that should redirect away if user IS authenticated
134
+ * @default ['/auth', '/login', '/register']
135
+ */
136
+ guestOnlyRoutes?: string[];
137
+ /**
138
+ * Enable development mode (shows debug info)
139
+ * @default false
140
+ */
141
+ devMode?: boolean;
142
+ /**
143
+ * Support email address for contact links
144
+ * @optional
145
+ */
146
+ supportEmail?: string;
147
+ /**
148
+ * OAuth2 redirect URL for OAuth providers
149
+ * If not specified, will use {origin}/auth/callback
150
+ * @optional
151
+ */
152
+ oauth2RedirectUrl?: string;
153
+ /**
154
+ * Automatically import CSS styles
155
+ * Set to false if you want to manually import styles or use custom styling
156
+ * @default true
157
+ */
158
+ styles?: boolean;
159
+ /**
160
+ * Custom API endpoints
161
+ */
162
+ endpoints?: Partial<StrandsAuthEndpoints>;
163
+ /**
164
+ * Enable squircle corners for UI components
165
+ * @default true
166
+ */
167
+ useSquircle?: boolean;
168
+ }
169
+ export interface StrandsAuthEndpoints {
170
+ signIn: string;
171
+ signUp: string;
172
+ signOut: string;
173
+ refresh: string;
174
+ passwordReset: string;
175
+ passwordResetConfirm: string;
176
+ completeRegistration: string;
177
+ profile: string;
178
+ verifyEmail: string;
179
+ oauthProviders: string;
180
+ oauthProvider: string;
181
+ changeEmail: string;
182
+ avatar: string;
183
+ settings: string;
184
+ changeUsername: string;
185
+ usernameCooldown: string;
186
+ checkUsernameAvailability: string;
187
+ mfaDevices: string;
188
+ mfaTotpSetup: string;
189
+ mfaTotpVerify: string;
190
+ mfaEmailSetup: string;
191
+ mfaEmailSend: string;
192
+ mfaEmailVerify: string;
193
+ mfaDeviceDisable: string;
194
+ mfaBackupCodes: string;
195
+ mfaHardwareStartRegistration: string;
196
+ mfaHardwareCompleteRegistration: string;
197
+ mfaSigninSendEmail: string;
198
+ mfaSigninVerify: string;
199
+ mfaBackupCodeVerify: string;
200
+ mfaWebAuthnChallenge: string;
201
+ sessions: string;
202
+ sessionsStats: string;
203
+ sessionRevoke: string;
204
+ sessionsRevokeAll: string;
205
+ }
206
+ export interface AuthResponse {
207
+ access_token: string;
208
+ refresh_token: string;
209
+ user: User;
210
+ mfa_required?: boolean;
211
+ mfa_session_id?: string;
212
+ available_mfa_methods?: MfaDevice[];
213
+ }
214
+ export type MfaDeviceType = 'totp' | 'email' | 'hardware' | 'passkey';
215
+ export interface MfaDevice {
216
+ id: string;
217
+ device_type: MfaDeviceType;
218
+ device_name: string;
219
+ is_active: boolean;
220
+ last_used_at?: string | Date;
221
+ created_at: string | Date;
222
+ }
223
+ export interface MfaDevicesResponse {
224
+ devices: MfaDevice[];
225
+ mfa_enabled: boolean;
226
+ }
227
+ export interface TotpSetupResponse {
228
+ device_id: string;
229
+ secret: string;
230
+ qr_code_url: string;
231
+ backup_codes: string[];
232
+ }
233
+ export interface BackupCodesResponse {
234
+ backup_codes: string[];
235
+ }
236
+ export interface MfaErrorResponse {
237
+ code: string;
238
+ message: string;
239
+ mfa_session_id?: string;
240
+ available_methods?: string[];
241
+ }
242
+ export type * from './composables';
@@ -0,0 +1 @@
1
+ "use strict";const e=require("vue"),t=require("./useStrandsConfig-CLSzvTvE.cjs.js"),n=new class{cache=new Map;DEFAULT_TTL=3e5;async fetch(e,t,n=this.DEFAULT_TTL){const a=Date.now(),i=this.cache.get(e);if(i&&a-i.timestamp<i.ttl)return i.promise;this.cleanExpired();const r=t().finally(()=>{setTimeout(()=>{this.cache.delete(e)},n)});return this.cache.set(e,{promise:r,timestamp:a,ttl:n}),r}clear(){this.cache.clear()}invalidate(e){this.cache.delete(e)}cleanExpired(){const e=Date.now();for(const[t,n]of this.cache.entries())e-n.timestamp>n.ttl&&this.cache.delete(t)}getStats(){return{size:this.cache.size,entries:Array.from(this.cache.keys())}}},a=function(){let e=null;return(...t)=>{e&&clearTimeout(e),e=setTimeout(()=>{((e,t)=>{"undefined"!=typeof window&&localStorage.setItem(e,t)})(...t)},300)}}(),i=e=>({id:e.id,email:e.email,firstName:e.first_name||e.firstName||"",lastName:e.last_name||e.lastName||"",avatar:e.avatar_url||e.avatar,mfaEnabled:e.mfa_enabled??e.mfaEnabled??0,emailVerified:e.email_verified??e.emailVerified??0,passwordUpdatedAt:e.password_updated_at||e.passwordUpdatedAt,settings:e.settings||{},xp:e.xp||0,level:e.level||1,next_level_xp:e.next_level_xp||e.next_level_xp||4,username:e.username,usernameLastChangedAt:e.username_last_changed_at||e.usernameLastChangedAt,createdAt:e.created_at||e.createdAt,updatedAt:e.updated_at||e.updatedAt||(new Date).toISOString()}),r={currentUser:e.ref(null),currentSession:e.ref(null),loadingStates:e.ref({initializing:1,signingIn:0,signingUp:0,signingOut:0,refreshingToken:0,sendingMfaEmail:0,verifyingMfa:0,loadingProfile:0}),isInitialized:e.ref(0),mfaRequired:e.ref(0),mfaSessionId:e.ref(null),availableMfaMethods:e.ref([])};let o=null,s=null;exports.useStrandsAuth=function(){const{getUrl:d,config:c}=t.useStrandsConfig(),{fetch:l,clear:u,invalidate:h}={fetch:n.fetch.bind(n),clear:n.clear.bind(n),invalidate:n.invalidate.bind(n),getStats:n.getStats.bind(n)},{currentUser:f,currentSession:w,loadingStates:y,isInitialized:g,mfaRequired:m,mfaSessionId:p,availableMfaMethods:S}=r,_=()=>{if(f.value=null,w.value=null,m.value=0,p.value=null,S.value=[],"undefined"!=typeof window&&(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user")),D(),s=null,u(),"undefined"!=typeof window&&c.value?.onSignOutUrl){const e=window.location.pathname+window.location.search,t=c.value.onSignOutUrl;e!==t&&(window.location.href=t)}},T=e.computed(()=>y.value.initializing),E=e.computed(()=>y.value.signingIn),O=e.computed(()=>y.value.signingUp),v=e.computed(()=>y.value.signingOut),A=e.computed(()=>y.value.refreshingToken),$=e.computed(()=>y.value.sendingMfaEmail),N=e.computed(()=>y.value.verifyingMfa);e.computed(()=>y.value.loadingProfile);const b=e.computed(()=>y.value.signingIn||y.value.signingUp||y.value.signingOut||y.value.refreshingToken||y.value.sendingMfaEmail||y.value.verifyingMfa||y.value.loadingProfile),k=e.computed(()=>y.value.initializing||b.value),C=e.computed(()=>{const e=y.value;return e.initializing?"Checking authentication...":e.signingIn?"Signing you in...":e.signingUp?"Creating your account...":e.signingOut?"Signing you out...":e.refreshingToken?"Refreshing session...":e.sendingMfaEmail?"Sending verification code...":e.verifyingMfa?"Verifying code...":e.loadingProfile?"Loading profile...":"Loading..."}),J=()=>{const e={};return w.value?.accessToken&&(e.Authorization=`Bearer ${w.value.accessToken}`),w.value?.refreshToken&&(e["x-refresh-token"]=w.value.refreshToken),e},P=e.computed(()=>null!==f.value),F=async()=>{if(!w.value?.refreshToken)return 0;if(s)return await s;s=(async()=>{y.value.refreshingToken=1;try{const e=await fetch(d("refresh"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:w.value.refreshToken})});if(!e.ok){if(401===e.status)return _(),0;throw new Error(`Token refresh failed: ${e.status} ${e.statusText}`)}const t=await e.json();t.user&&(f.value=i(t.user),f.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value)));const n={accessToken:t.access_token,refreshToken:t.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:t.user?.id||f.value?.id};return w.value=n,"undefined"!=typeof window&&localStorage.setItem("strands_auth_session",JSON.stringify(n)),U(),h(`sessions:${w.value.accessToken.slice(0,20)}`),1}catch(e){return _(),0}finally{y.value.refreshingToken=0}})();const e=await s;return s=null,e},M=async e=>{try{e.user&&(f.value=i(e.user));const t={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:new Date(Date.now()+3e5),userId:f.value?.id||e.user?.id};w.value=t,"undefined"!=typeof window&&(localStorage.setItem("strands_auth_session",JSON.stringify(t)),f.value&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),U()}catch(t){}},U=()=>{if(o&&clearTimeout(o),!w.value)return;if("undefined"!=typeof document&&"hidden"===document.visibilityState)return;const e=new Date,t=w.value.expiresAt.getTime()-e.getTime()-6e4;t<=0?F():o=setTimeout(async()=>{"undefined"!=typeof document&&"visible"!==document.visibilityState||await F()&&U()},t)},D=()=>{o&&(clearTimeout(o),o=null)},I=async()=>{if(!g.value){y.value.initializing=1;try{if("undefined"!=typeof window){const t=localStorage.getItem("strands_auth_session"),n=localStorage.getItem("strands_auth_user");if(t&&n)try{const e=JSON.parse(t),a=JSON.parse(n);e.expiresAt=new Date(e.expiresAt),e.expiresAt<=new Date&&e.refreshToken?(w.value=e,f.value=a,await F()||_()):e.expiresAt>new Date?(w.value=e,f.value=a,U()):(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}catch(e){localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user")}}g.value=1,await new Promise(e=>setTimeout(e,50))}catch(e){}finally{y.value.initializing=0}}};"undefined"!=typeof document&&document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&w.value?(U(),j()):"hidden"===document.visibilityState&&D()}),"undefined"!=typeof window&&window.addEventListener("storage",e=>{"strands_auth_session"!==e.key&&"strands_auth_user"!==e.key||!e.newValue&&f.value&&_()});const j=()=>{if("undefined"!=typeof window&&f.value&&w.value){const e=localStorage.getItem("strands_auth_session"),t=localStorage.getItem("strands_auth_user");e&&t||_()}},R=()=>{D(),u()};try{e.getCurrentInstance()&&e.onUnmounted(R)}catch(z){}return g.value||I(),{user:e.computed(()=>f.value),currentUser:e.computed(()=>f.value),currentSession:e.computed(()=>w.value),isAuthenticated:P,isLoading:e.computed(()=>k.value||!g.value),loading:b,loadingMessage:C,isInitializing:T,isSigningIn:E,isSigningUp:O,isSigningOut:v,isRefreshingToken:A,isSendingMfaEmail:$,isVerifyingMfa:N,mfaRequired:e.computed(()=>m.value),mfaSessionId:e.computed(()=>p.value),availableMfaMethods:e.computed(()=>S.value),signIn:async e=>{y.value.signingIn=1;try{m.value=0,p.value=null,S.value=[];const t={"Content-Type":"application/json"};"undefined"!=typeof window&&window.location&&(t.Origin=window.location.origin);const n=await fetch(d("signIn"),{method:"POST",headers:t,body:JSON.stringify(e)});if(!n.ok)throw 401===n.status?new Error("Invalid email or password"):403===n.status?new Error("Please verify your email address before signing in"):new Error(`Sign in failed: ${n.status} ${n.statusText}`);const a=await n.json();if(a.mfa_required){m.value=1,p.value=a.mfa_session_id||null;const e=(a.available_mfa_methods||[]).map(e=>{let t=`${e.device_type.charAt(0).toUpperCase()+e.device_type.slice(1)} Authentication`;return"hardware"===e.device_type?t=e.device_name||"Security Key":"totp"===e.device_type?t=e.device_name||"Authenticator App":"email"===e.device_type&&(t=e.device_name||"Email Verification"),{id:e.device_id,device_type:e.device_type,device_name:e.device_name||t,is_active:1,created_at:(new Date).toISOString(),last_used_at:e.last_used_at,credential_id:e.credential_id,device_info:e.device_info}});return S.value=e,y.value.signingIn=0,a}return await M(a),a}catch(t){throw t}finally{y.value.signingIn=0}},signUp:async e=>{y.value.signingUp=1;try{throw new Error("Sign up not implemented - please integrate with auth SDK")}finally{y.value.signingUp=0}},signOut:async()=>{y.value.signingOut=1;try{D(),s=null,u(),f.value=null,w.value=null,m.value=0,p.value=null,S.value=[],"undefined"!=typeof window&&(localStorage.removeItem("strands_auth_session"),localStorage.removeItem("strands_auth_user"))}finally{y.value.signingOut=0}},refreshToken:F,fetchProfile:async()=>{const e=`profile:${w.value.accessToken.slice(0,20)}`;y.value.loadingProfile=1;try{return await l(e,async()=>{const e=await fetch(d("profile"),{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value?.accessToken}`}});if(!e.ok)throw 401===e.status?new Error("Authentication expired. Please sign in again."):new Error(`Failed to fetch profile: ${e.status} ${e.statusText}`);const t=await e.json();return f.value=i(t),f.value&&"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value)),f.value})}finally{y.value.loadingProfile=0}},updateProfile:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("profile"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({first_name:e.firstName,last_name:e.lastName})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Profile update failed: ${t.status} ${t.statusText}`);const n=await t.json();return f.value=i(n),f.value&&a("strands_auth_user",JSON.stringify(f.value)),f.value}finally{y.value.loadingProfile=0}},updateUserSettings:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("settings"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({settings:e})});if(!t.ok)throw 401===t.status?new Error("Authentication expired. Please sign in again."):new Error(`Settings update failed: ${t.status} ${t.statusText}`);const n=await t.json();return f.value=i(n),f.value&&a("strands_auth_user",JSON.stringify(f.value)),f.value}finally{y.value.loadingProfile=0}},changeEmail:async(e,t)=>{y.value.loadingProfile=1;try{const n=await fetch(d("changeEmail"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({new_email:e,password:t})});if(!n.ok){if(401===n.status)throw new Error("Authentication expired. Please sign in again.");{const e=await n.json().catch(()=>({}));throw new Error(e.message||`Email change failed: ${n.status} ${n.statusText}`)}}const a=await n.json();return f.value&&(f.value={...f.value,email:e,emailVerified:0,updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),a}finally{y.value.loadingProfile=0}},changeUsername:async e=>{y.value.loadingProfile=1;try{const t=await fetch(d("changeUsername"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({username:e})});if(!t.ok){const e=await t.json().catch(()=>({}));if(409===t.status)throw new Error("Username is already taken");if(e.cooldown_end)throw new Error(`You can only change your username once every 30 days. You can change it again on ${new Date(e.cooldown_end).toLocaleDateString()}`);throw new Error(e.message||`Username change failed: ${t.status} ${t.statusText}`)}const n=await t.json();return f.value&&(f.value={...f.value,username:e,usernameLastChangedAt:(new Date).toISOString(),updatedAt:(new Date).toISOString()},"undefined"!=typeof window&&localStorage.setItem("strands_auth_user",JSON.stringify(f.value))),n}finally{y.value.loadingProfile=0}},getUsernameCooldown:async()=>{const e=await fetch(d("usernameCooldown"),{method:"GET",headers:{Authorization:`Bearer ${w.value.accessToken}`}});if(!e.ok)throw new Error(`Failed to get username cooldown: ${e.status} ${e.statusText}`);return e.json()},checkUsernameAvailability:async e=>{const t=d("checkUsernameAvailability").replace("{username}",encodeURIComponent(e)),n=await fetch(t,{method:"GET",headers:{"Content-Type":"application/json"}});if(!n.ok)throw new Error(`Failed to check username availability: ${n.status} ${n.statusText}`);return n.json()},getUserSessions:async()=>{const e=`sessions:${w.value?.accessToken?.slice(0,20)||"no-token"}`;try{return await l(e,async()=>{const e=J(),t=await fetch(d("sessions"),{method:"GET",headers:e});if(!t.ok)throw await t.text(),new Error(`Failed to get user sessions: ${t.status} ${t.statusText}`);return t.json()},12e4)}catch(t){throw t}},getSessionStats:async()=>{const e=await fetch(d("sessionsStats"),{method:"GET",headers:J()});if(!e.ok)throw new Error(`Failed to get session stats: ${e.status} ${e.statusText}`);return e.json()},revokeSession:async e=>{const t=d("sessionRevoke").replace("{session_id}",encodeURIComponent(e)),n=await fetch(t,{method:"POST",headers:J()});if(!n.ok)throw new Error(`Failed to revoke session: ${n.status} ${n.statusText}`);return 200===n.status},revokeAllOtherSessions:async()=>{const e=await fetch(d("sessionsRevokeAll"),{method:"POST",headers:J()});if(!e.ok)throw new Error(`Failed to revoke all other sessions: ${e.status} ${e.statusText}`);return 200===e.status},initialize:I,setAuthData:M,verifyMfa:async(e,t,n=0)=>{if(!p.value)throw new Error("No MFA session available");y.value.verifyingMfa=1;try{const a=d(n?"mfaBackupCodeVerify":"mfaSigninVerify"),i=n?{mfa_session_id:p.value,backup_code:t}:{mfa_session_id:p.value,device_id:e,code:t},r=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok){const e=await r.text();let t="MFA verification failed";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"MFA verification failed"}throw new Error(t)}const o=await r.json();return m.value=0,p.value=null,S.value=[],await M(o),o}finally{y.value.verifyingMfa=0}},sendMfaEmailCode:async e=>{if(!p.value)throw new Error("No MFA session available");y.value.sendingMfaEmail=1;try{const t=await fetch(d("mfaSigninSendEmail"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:p.value,device_id:e})});if(!t.ok){const e=await t.text();let n="Failed to send MFA email code";try{const t=JSON.parse(e);n=t.message||t.error||e}catch{n=e||"Failed to send MFA email code"}throw new Error(n)}return await t.json()}finally{y.value.sendingMfaEmail=0}},getMfaWebAuthnChallenge:async e=>{if(!p.value)throw new Error("No MFA session available");const t=await fetch(d("mfaWebAuthnChallenge"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mfa_session_id:p.value,device_id:e})});if(!t.ok){const e=await t.text();let n="Failed to get WebAuthn challenge";try{const t=JSON.parse(e);n=t.message||t.error||e}catch{n=e||n}throw new Error(n)}return t.json()},registerHardwareKey:async(e,t,n="hardware")=>{const a=await fetch(d("mfaHardwareStartRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({device_name:e,device_type:n})});if(!a.ok){const e=await a.text();let t="Failed to start hardware key registration";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"Failed to start hardware key registration"}throw new Error(t)}return a.json()},completeHardwareKeyRegistration:async(e,t,n)=>{const a=await fetch(d("mfaHardwareCompleteRegistration"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w.value.accessToken}`},body:JSON.stringify({device_id:e,credential:t})});if(!a.ok){const e=await a.text();let t="Failed to complete hardware key registration";try{const n=JSON.parse(e);t=n.message||n.error||e}catch{t=e||"Failed to complete hardware key registration"}throw new Error(t)}return a.json()},startTokenRefreshTimer:U,stopTokenRefreshTimer:D,getAuthHeaders:J,forceReInit:()=>{g.value=0,y.value.initializing=1,I()}}};
@@ -861,7 +861,7 @@ function useStrandsAuth() {
861
861
  currentSession: computed(() => currentSession.value),
862
862
  isAuthenticated,
863
863
  isLoading: computed(() => isLoading.value || !isInitialized.value),
864
- loading: computed(() => loading.value),
864
+ loading,
865
865
  loadingMessage,
866
866
  // Specific loading states
867
867
  isInitializing,
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Complete Tailwind CSS color palette with shades
3
+ * Provides all 22 Tailwind colors with their full shade ranges (50-950)
4
+ */
5
+ interface SwatchConfig {
6
+ label?: string;
7
+ shades?: string[];
8
+ }
9
+ export declare const tailwindColors: Record<string, SwatchConfig>;
10
+ export type { SwatchConfig };
@@ -0,0 +1,2 @@
1
+ export * from './validation';
2
+ export * from './colors';
@@ -0,0 +1 @@
1
+ export declare const slotHasContent: (slotName: string, slots: any) => boolean;