From 2d76a7291080e371073ee4574cfa8ef4d63d08dd Mon Sep 17 00:00:00 2001 From: mohiit1502 Date: Sun, 28 Dec 2025 19:20:52 +0530 Subject: [PATCH] Fixed build warnings --- dist/react.js | 8 +++++--- dist/react.js.map | 2 +- dist/react.mjs | 8 +++++--- dist/react.mjs.map | 2 +- package.json | 8 ++++---- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/dist/react.js b/dist/react.js index 5ba3f33..8ff3875 100644 --- a/dist/react.js +++ b/dist/react.js @@ -643,16 +643,18 @@ function useHasRole(roles) { function withAuth(WrappedComponent, options) { return function AuthenticatedComponent(props) { const { isAuthenticated, isLoading, user } = useAuth(); + const LoadingComp = options?.LoadingComponent; + const UnauthorizedComp = options?.UnauthorizedComponent; if (isLoading) { - return options?.LoadingComponent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(options.LoadingComponent, {}) : null; + return LoadingComp ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingComp, {}) : null; } if (!isAuthenticated) { - return options?.UnauthorizedComponent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(options.UnauthorizedComponent, {}) : null; + return UnauthorizedComp ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnauthorizedComp, {}) : null; } if (options?.roles && options.roles.length > 0) { const hasRequiredRole = options.roles.some((role) => user?.roles?.includes(role)); if (!hasRequiredRole) { - return options?.UnauthorizedComponent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(options.UnauthorizedComponent, {}) : null; + return UnauthorizedComp ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnauthorizedComp, {}) : null; } } return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { ...props }); diff --git a/dist/react.js.map b/dist/react.js.map index 5d45f57..b08866e 100644 --- a/dist/react.js.map +++ b/dist/react.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/react/index.tsx","../src/utils.ts","../src/storage.ts","../src/client.ts"],"sourcesContent":["/**\n * React bindings for Stuffle IAM SDK\n * \n * @example\n * ```tsx\n * import { StuffleIAMProvider, useAuth } from '@stuffle/iam-sdk/react';\n * \n * function App() {\n * return (\n * \n * \n * \n * );\n * }\n * \n * function MyApp() {\n * const { isAuthenticated, user, login, logout } = useAuth();\n * \n * if (!isAuthenticated) {\n * return ;\n * }\n * \n * return (\n *
\n *

Welcome, {user?.name}

\n * \n *
\n * );\n * }\n * ```\n */\n\nimport {\n createContext,\n useContext,\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n} from 'react';\nimport {\n StuffleIAMClient,\n createStuffleIAMClient,\n type StuffleIAMConfig,\n type AuthState,\n type User,\n type LoginOptions,\n type LogoutOptions,\n type CallbackResult,\n} from '../index';\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface StuffleIAMContextValue {\n client: StuffleIAMClient;\n isAuthenticated: boolean;\n isLoading: boolean;\n user: User | null;\n accessToken: string | null;\n error: Error | null;\n login: (options?: LoginOptions) => Promise;\n signup: (options?: Omit) => Promise;\n logout: (options?: LogoutOptions) => Promise;\n handleCallback: (url?: string) => Promise;\n getAccessToken: () => Promise;\n}\n\nconst StuffleIAMContext = createContext(null);\n\n// =============================================================================\n// Provider\n// =============================================================================\n\nexport interface StuffleIAMProviderProps extends StuffleIAMConfig {\n children: ReactNode;\n /** Called after successful login callback */\n onLoginSuccess?: (result: CallbackResult) => void;\n /** Called on login error */\n onLoginError?: (error: Error) => void;\n /** Auto-handle callback on mount if URL has code/error */\n autoHandleCallback?: boolean;\n}\n\nexport function StuffleIAMProvider({\n children,\n onLoginSuccess,\n onLoginError,\n autoHandleCallback = true,\n ...config\n}: StuffleIAMProviderProps) {\n const [client] = useState(() => createStuffleIAMClient(config));\n const [state, setState] = useState(() => ({\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n idToken: null,\n error: null,\n }));\n\n // Subscribe to auth state changes\n useEffect(() => {\n const unsubscribe = client.subscribe(setState);\n \n // Initialize state\n const initialState = client.getAuthState();\n setState({ ...initialState, isLoading: false });\n\n return unsubscribe;\n }, [client]);\n\n // Auto-handle callback\n useEffect(() => {\n if (!autoHandleCallback) return;\n\n const url = window.location.href;\n const hasCode = url.includes('code=');\n const hasError = url.includes('error=');\n\n if (hasCode || hasError) {\n setState(prev => ({ ...prev, isLoading: true }));\n \n client.handleCallback(url).then(result => {\n setState(prev => ({ ...prev, isLoading: false }));\n \n if (result.success) {\n onLoginSuccess?.(result);\n // Clean URL\n window.history.replaceState({}, '', window.location.pathname);\n } else {\n const error = new Error(result.errorDescription || result.error || 'Login failed');\n onLoginError?.(error);\n setState(prev => ({ ...prev, error }));\n }\n });\n }\n }, [client, autoHandleCallback, onLoginSuccess, onLoginError]);\n\n // Memoized methods\n const login = useCallback(\n (options?: LoginOptions) => client.login(options),\n [client]\n );\n\n const signup = useCallback(\n (options?: Omit) => client.signup(options),\n [client]\n );\n\n const logout = useCallback(\n (options?: LogoutOptions) => client.logout(options),\n [client]\n );\n\n const handleCallback = useCallback(\n (url?: string) => client.handleCallback(url),\n [client]\n );\n\n const getAccessToken = useCallback(\n () => client.getAccessToken(),\n [client]\n );\n\n const value = useMemo(\n () => ({\n client,\n isAuthenticated: state.isAuthenticated,\n isLoading: state.isLoading,\n user: state.user,\n accessToken: state.accessToken,\n error: state.error,\n login,\n signup,\n logout,\n handleCallback,\n getAccessToken,\n }),\n [client, state, login, signup, logout, handleCallback, getAccessToken]\n );\n\n return (\n \n {children}\n \n );\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * Hook to access auth state and methods\n */\nexport function useAuth() {\n const context = useContext(StuffleIAMContext);\n if (!context) {\n throw new Error('useAuth must be used within a StuffleIAMProvider');\n }\n return context;\n}\n\n/**\n * Hook to get current user\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n\n/**\n * Hook to check if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get access token (refreshes if needed)\n */\nexport function useAccessToken(): () => Promise {\n const { getAccessToken } = useAuth();\n return getAccessToken;\n}\n\n/**\n * Hook to check if user has specific role(s)\n */\nexport function useHasRole(roles: string | string[]): boolean {\n const { user } = useAuth();\n if (!user?.roles) return false;\n \n const requiredRoles = Array.isArray(roles) ? roles : [roles];\n return requiredRoles.some(role => user.roles?.includes(role));\n}\n\n/**\n * Higher-order component for protected routes\n */\nexport function withAuth

(\n WrappedComponent: React.ComponentType

,\n options?: {\n /** Component to show while loading */\n LoadingComponent?: React.ComponentType;\n /** Component to show if not authenticated */\n UnauthorizedComponent?: React.ComponentType;\n /** Required roles */\n roles?: string[];\n }\n) {\n return function AuthenticatedComponent(props: P) {\n const { isAuthenticated, isLoading, user } = useAuth();\n\n if (isLoading) {\n return options?.LoadingComponent ? : null;\n }\n\n if (!isAuthenticated) {\n return options?.UnauthorizedComponent ? : null;\n }\n\n if (options?.roles && options.roles.length > 0) {\n const hasRequiredRole = options.roles.some(role => user?.roles?.includes(role));\n if (!hasRequiredRole) {\n return options?.UnauthorizedComponent ? : null;\n }\n }\n\n return ;\n };\n}\n\n// Re-export types\nexport type { StuffleIAMConfig, AuthState, User, LoginOptions, LogoutOptions, CallbackResult };\n","/**\n * Utility functions for PKCE and crypto operations\n */\n\n/**\n * Generate a random string for state/nonce\n */\nexport function generateRandomString(length: number = 32): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generate PKCE code verifier (43-128 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate PKCE code challenge from verifier\n */\nexport async function generateCodeChallenge(verifier: string): Promise {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(digest));\n}\n\n/**\n * Base64 URL encode (no padding, URL-safe characters)\n */\nexport function base64UrlEncode(buffer: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < buffer.length; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Decode JWT payload (without verification)\n */\nexport function decodeJwtPayload>(token: string): T | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded) as T;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string, thresholdSeconds: number = 0): boolean {\n const payload = decodeJwtPayload<{ exp?: number }>(token);\n if (!payload?.exp) return true;\n \n const now = Math.floor(Date.now() / 1000);\n return payload.exp - thresholdSeconds <= now;\n}\n\n/**\n * Parse URL hash or query parameters\n */\nexport function parseUrlParams(url: string): Record {\n const params: Record = {};\n \n // Check hash first (implicit flow), then query (code flow)\n const hashIndex = url.indexOf('#');\n const queryIndex = url.indexOf('?');\n \n let paramString = '';\n if (hashIndex !== -1) {\n paramString = url.substring(hashIndex + 1);\n } else if (queryIndex !== -1) {\n paramString = url.substring(queryIndex + 1);\n }\n \n if (!paramString) return params;\n \n const searchParams = new URLSearchParams(paramString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n \n return params;\n}\n\n/**\n * Build URL with query parameters\n */\nexport function buildUrl(base: string, params: Record): string {\n const url = new URL(base);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n return url.toString();\n}\n","/**\n * Token storage abstraction\n */\n\nexport interface TokenStorage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n clear(): void;\n}\n\nconst STORAGE_PREFIX = 'stuffle_iam_';\n\n/**\n * LocalStorage implementation\n */\nexport class LocalStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('LocalStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(localStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => localStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * SessionStorage implementation\n */\nexport class SessionStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return sessionStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n sessionStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('SessionStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n sessionStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(sessionStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => sessionStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * In-memory storage (for SSR or when storage is unavailable)\n */\nexport class MemoryStorageAdapter implements TokenStorage {\n private store = new Map();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n\n/**\n * Get storage adapter based on type\n */\nexport function getStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n switch (type) {\n case 'localStorage':\n return new LocalStorageAdapter();\n case 'sessionStorage':\n return new SessionStorageAdapter();\n case 'memory':\n return new MemoryStorageAdapter();\n default:\n return new SessionStorageAdapter();\n }\n}\n","/**\n * Stuffle IAM Client\n * \n * OIDC/OAuth2 client for browser-based applications.\n * Supports authorization code flow with PKCE.\n */\n\nimport type {\n StuffleIAMConfig,\n TokenResponse,\n User,\n AuthState,\n LoginOptions,\n LogoutOptions,\n CallbackResult,\n OIDCDiscovery,\n} from './types';\nimport {\n generateRandomString,\n generateCodeVerifier,\n generateCodeChallenge,\n decodeJwtPayload,\n isTokenExpired,\n parseUrlParams,\n buildUrl,\n} from './utils';\nimport { getStorage, type TokenStorage } from './storage';\n\nconst STORAGE_KEYS = {\n ACCESS_TOKEN: 'access_token',\n REFRESH_TOKEN: 'refresh_token',\n ID_TOKEN: 'id_token',\n CODE_VERIFIER: 'code_verifier',\n STATE: 'state',\n NONCE: 'nonce',\n USER: 'user',\n EXPIRES_AT: 'expires_at',\n};\n\nexport class StuffleIAMClient {\n private config: Required;\n private storage: TokenStorage;\n private discovery: OIDCDiscovery | null = null;\n private refreshTimer: ReturnType | null = null;\n private listeners: Set<(state: AuthState) => void> = new Set();\n\n constructor(config: StuffleIAMConfig) {\n this.config = {\n issuer: config.issuer.replace(/\\/$/, ''), // Remove trailing slash\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n scopes: config.scopes ?? ['openid', 'profile', 'email'],\n postLogoutRedirectUri: config.postLogoutRedirectUri ?? config.redirectUri,\n usePkce: config.usePkce ?? true,\n storage: config.storage ?? 'sessionStorage',\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? 60,\n };\n\n this.storage = getStorage(this.config.storage);\n }\n\n /**\n * Fetch OIDC discovery document\n */\n async getDiscovery(): Promise {\n if (this.discovery) return this.discovery;\n\n const response = await fetch(\n `${this.config.issuer}/.well-known/openid-configuration`\n );\n\n if (!response.ok) {\n throw new Error(`Failed to fetch OIDC discovery: ${response.status}`);\n }\n\n this.discovery = await response.json();\n return this.discovery!;\n }\n\n /**\n * Start login flow - redirects to authorization endpoint\n */\n async login(options: LoginOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n\n const state = options.state ?? generateRandomString();\n const nonce = options.nonce ?? generateRandomString();\n const scopes = [...this.config.scopes, ...(options.scopes ?? [])];\n\n // Store state and nonce for callback validation\n this.storage.set(STORAGE_KEYS.STATE, state);\n this.storage.set(STORAGE_KEYS.NONCE, nonce);\n\n const params: Record = {\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n state,\n nonce,\n prompt: options.prompt,\n login_hint: options.loginHint,\n };\n\n // Add PKCE if enabled\n if (this.config.usePkce) {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n this.storage.set(STORAGE_KEYS.CODE_VERIFIER, codeVerifier);\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Use signup endpoint if requested\n const endpoint = options.signup\n ? discovery.authorization_endpoint.replace('/authorize', '/authorize/signup')\n : discovery.authorization_endpoint;\n\n const authUrl = buildUrl(endpoint, params);\n window.location.href = authUrl;\n }\n\n /**\n * Alias for login({ signup: true })\n */\n async signup(options: Omit = {}): Promise {\n return this.login({ ...options, signup: true });\n }\n\n /**\n * Handle callback from authorization server\n */\n async handleCallback(url?: string): Promise {\n const callbackUrl = url ?? window.location.href;\n const params = parseUrlParams(callbackUrl);\n\n // Check for errors\n if (params.error) {\n return {\n success: false,\n error: params.error,\n errorDescription: params.error_description,\n };\n }\n\n // Validate state\n const storedState = this.storage.get(STORAGE_KEYS.STATE);\n if (!storedState || storedState !== params.state) {\n return {\n success: false,\n error: 'invalid_state',\n errorDescription: 'State mismatch - possible CSRF attack',\n };\n }\n\n // Exchange code for tokens\n if (!params.code) {\n return {\n success: false,\n error: 'missing_code',\n errorDescription: 'No authorization code received',\n };\n }\n\n try {\n const tokens = await this.exchangeCode(params.code);\n \n // Validate nonce in ID token\n if (tokens.id_token) {\n const payload = decodeJwtPayload<{ nonce?: string }>(tokens.id_token);\n const storedNonce = this.storage.get(STORAGE_KEYS.NONCE);\n if (payload?.nonce !== storedNonce) {\n return {\n success: false,\n error: 'invalid_nonce',\n errorDescription: 'Nonce mismatch - possible replay attack',\n };\n }\n }\n\n // Store tokens\n this.storeTokens(tokens);\n\n // Clear temporary storage\n this.storage.remove(STORAGE_KEYS.STATE);\n this.storage.remove(STORAGE_KEYS.NONCE);\n this.storage.remove(STORAGE_KEYS.CODE_VERIFIER);\n\n // Get user info\n const user = await this.fetchUserInfo(tokens.access_token);\n\n // Setup auto-refresh\n if (this.config.autoRefresh && tokens.refresh_token) {\n this.setupAutoRefresh();\n }\n\n // Notify listeners\n this.notifyListeners();\n\n return {\n success: true,\n user: user || undefined,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token,\n };\n } catch (error) {\n return {\n success: false,\n error: 'token_exchange_failed',\n errorDescription: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCode(code: string): Promise {\n const discovery = await this.getDiscovery();\n\n const body: Record = {\n grant_type: 'authorization_code',\n client_id: this.config.clientId,\n code,\n redirect_uri: this.config.redirectUri,\n };\n\n // Add PKCE code verifier\n if (this.config.usePkce) {\n const codeVerifier = this.storage.get(STORAGE_KEYS.CODE_VERIFIER);\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n }\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error_description || error.error || 'Token exchange failed');\n }\n\n return response.json();\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshToken(): Promise {\n const refreshToken = this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);\n if (!refreshToken) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n refresh_token: refreshToken,\n }),\n });\n\n if (!response.ok) {\n // Refresh failed - clear tokens\n this.clearTokens();\n this.notifyListeners();\n return null;\n }\n\n const tokens: TokenResponse = await response.json();\n this.storeTokens(tokens);\n this.notifyListeners();\n\n return tokens;\n }\n\n /**\n * Logout - end session\n */\n async logout(options: LogoutOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n\n // Clear local tokens first\n this.clearTokens();\n this.notifyListeners();\n\n // Redirect to end session endpoint if available\n if (discovery.end_session_endpoint) {\n const params: Record = {\n post_logout_redirect_uri: options.returnTo ?? this.config.postLogoutRedirectUri,\n id_token_hint: options.idTokenHint ?? idToken ?? undefined,\n client_id: this.config.clientId,\n };\n\n const logoutUrl = buildUrl(discovery.end_session_endpoint, params);\n window.location.href = logoutUrl;\n }\n }\n\n /**\n * Get current access token (refreshes if needed)\n */\n async getAccessToken(): Promise {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n \n if (!accessToken) return null;\n\n // Check if token needs refresh\n if (isTokenExpired(accessToken, this.config.refreshThreshold)) {\n const tokens = await this.refreshToken();\n return tokens?.access_token ?? null;\n }\n\n return accessToken;\n }\n\n /**\n * Get current user from stored ID token\n */\n getUser(): User | null {\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n if (!idToken) return null;\n\n return decodeJwtPayload(idToken);\n }\n\n /**\n * Fetch user info from userinfo endpoint\n */\n async fetchUserInfo(accessToken?: string): Promise {\n const token = accessToken ?? await this.getAccessToken();\n if (!token) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.userinfo_endpoint, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) return null;\n\n const user: User = await response.json();\n this.storage.set(STORAGE_KEYS.USER, JSON.stringify(user));\n return user;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n if (!accessToken) return false;\n\n // Consider authenticated if token exists and not expired\n return !isTokenExpired(accessToken);\n }\n\n /**\n * Get current auth state\n */\n getAuthState(): AuthState {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n const user = this.getUser();\n\n return {\n isAuthenticated: this.isAuthenticated(),\n isLoading: false,\n user,\n accessToken,\n idToken,\n error: null,\n };\n }\n\n /**\n * Subscribe to auth state changes\n */\n subscribe(listener: (state: AuthState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Store tokens in storage\n */\n private storeTokens(tokens: TokenResponse): void {\n this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, tokens.access_token);\n \n if (tokens.refresh_token) {\n this.storage.set(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh_token);\n }\n \n if (tokens.id_token) {\n this.storage.set(STORAGE_KEYS.ID_TOKEN, tokens.id_token);\n }\n\n // Store expiry time\n const expiresAt = Date.now() + (tokens.expires_in * 1000);\n this.storage.set(STORAGE_KEYS.EXPIRES_AT, expiresAt.toString());\n }\n\n /**\n * Clear all stored tokens\n */\n private clearTokens(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n this.storage.clear();\n }\n\n /**\n * Setup auto-refresh timer\n */\n private setupAutoRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n const expiresAt = this.storage.get(STORAGE_KEYS.EXPIRES_AT);\n if (!expiresAt) return;\n\n const expiresAtMs = parseInt(expiresAt, 10);\n const refreshAt = expiresAtMs - (this.config.refreshThreshold * 1000);\n const delay = refreshAt - Date.now();\n\n if (delay > 0) {\n this.refreshTimer = setTimeout(async () => {\n await this.refreshToken();\n this.setupAutoRefresh();\n }, delay);\n }\n }\n\n /**\n * Notify all listeners of state change\n */\n private notifyListeners(): void {\n const state = this.getAuthState();\n this.listeners.forEach(listener => listener(state));\n }\n}\n\n/**\n * Create a new Stuffle IAM client instance\n */\nexport function createStuffleIAMClient(config: StuffleIAMConfig): StuffleIAMClient {\n return new StuffleIAMClient(config);\n}\n"],"mappings":"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","names":[]} \ No newline at end of file +{"version":3,"sources":["../src/react/index.tsx","../src/utils.ts","../src/storage.ts","../src/client.ts"],"sourcesContent":["/**\n * React bindings for Stuffle IAM SDK\n * \n * @example\n * ```tsx\n * import { StuffleIAMProvider, useAuth } from '@stuffle/iam-sdk/react';\n * \n * function App() {\n * return (\n * \n * \n * \n * );\n * }\n * \n * function MyApp() {\n * const { isAuthenticated, user, login, logout } = useAuth();\n * \n * if (!isAuthenticated) {\n * return ;\n * }\n * \n * return (\n *

\n *

Welcome, {user?.name}

\n * \n *
\n * );\n * }\n * ```\n */\n\nimport {\n createContext,\n useContext,\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n} from 'react';\nimport {\n StuffleIAMClient,\n createStuffleIAMClient,\n type StuffleIAMConfig,\n type AuthState,\n type User,\n type LoginOptions,\n type LogoutOptions,\n type CallbackResult,\n} from '../index';\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface StuffleIAMContextValue {\n client: StuffleIAMClient;\n isAuthenticated: boolean;\n isLoading: boolean;\n user: User | null;\n accessToken: string | null;\n error: Error | null;\n login: (options?: LoginOptions) => Promise;\n signup: (options?: Omit) => Promise;\n logout: (options?: LogoutOptions) => Promise;\n handleCallback: (url?: string) => Promise;\n getAccessToken: () => Promise;\n}\n\nconst StuffleIAMContext = createContext(null);\n\n// =============================================================================\n// Provider\n// =============================================================================\n\nexport interface StuffleIAMProviderProps extends StuffleIAMConfig {\n children: ReactNode;\n /** Called after successful login callback */\n onLoginSuccess?: (result: CallbackResult) => void;\n /** Called on login error */\n onLoginError?: (error: Error) => void;\n /** Auto-handle callback on mount if URL has code/error */\n autoHandleCallback?: boolean;\n}\n\nexport function StuffleIAMProvider({\n children,\n onLoginSuccess,\n onLoginError,\n autoHandleCallback = true,\n ...config\n}: StuffleIAMProviderProps) {\n const [client] = useState(() => createStuffleIAMClient(config));\n const [state, setState] = useState(() => ({\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n idToken: null,\n error: null,\n }));\n\n // Subscribe to auth state changes\n useEffect(() => {\n const unsubscribe = client.subscribe(setState);\n\n // Initialize state\n const initialState = client.getAuthState();\n setState({ ...initialState, isLoading: false });\n\n return unsubscribe;\n }, [client]);\n\n // Auto-handle callback\n useEffect(() => {\n if (!autoHandleCallback) return;\n\n const url = window.location.href;\n const hasCode = url.includes('code=');\n const hasError = url.includes('error=');\n\n if (hasCode || hasError) {\n setState(prev => ({ ...prev, isLoading: true }));\n\n client.handleCallback(url).then(result => {\n setState(prev => ({ ...prev, isLoading: false }));\n\n if (result.success) {\n onLoginSuccess?.(result);\n // Clean URL\n window.history.replaceState({}, '', window.location.pathname);\n } else {\n const error = new Error(result.errorDescription || result.error || 'Login failed');\n onLoginError?.(error);\n setState(prev => ({ ...prev, error }));\n }\n });\n }\n }, [client, autoHandleCallback, onLoginSuccess, onLoginError]);\n\n // Memoized methods\n const login = useCallback(\n (options?: LoginOptions) => client.login(options),\n [client]\n );\n\n const signup = useCallback(\n (options?: Omit) => client.signup(options),\n [client]\n );\n\n const logout = useCallback(\n (options?: LogoutOptions) => client.logout(options),\n [client]\n );\n\n const handleCallback = useCallback(\n (url?: string) => client.handleCallback(url),\n [client]\n );\n\n const getAccessToken = useCallback(\n () => client.getAccessToken(),\n [client]\n );\n\n const value = useMemo(\n () => ({\n client,\n isAuthenticated: state.isAuthenticated,\n isLoading: state.isLoading,\n user: state.user,\n accessToken: state.accessToken,\n error: state.error,\n login,\n signup,\n logout,\n handleCallback,\n getAccessToken,\n }),\n [client, state, login, signup, logout, handleCallback, getAccessToken]\n );\n\n return (\n \n {children}\n \n );\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * Hook to access auth state and methods\n */\nexport function useAuth() {\n const context = useContext(StuffleIAMContext);\n if (!context) {\n throw new Error('useAuth must be used within a StuffleIAMProvider');\n }\n return context;\n}\n\n/**\n * Hook to get current user\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n\n/**\n * Hook to check if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get access token (refreshes if needed)\n */\nexport function useAccessToken(): () => Promise {\n const { getAccessToken } = useAuth();\n return getAccessToken;\n}\n\n/**\n * Hook to check if user has specific role(s)\n */\nexport function useHasRole(roles: string | string[]): boolean {\n const { user } = useAuth();\n if (!user?.roles) return false;\n\n const requiredRoles = Array.isArray(roles) ? roles : [roles];\n return requiredRoles.some(role => user.roles?.includes(role));\n}\n\n/**\n * Higher-order component for protected routes\n */\nexport function withAuth

(\n WrappedComponent: React.ComponentType

,\n options?: {\n /** Component to show while loading */\n LoadingComponent?: React.ComponentType;\n /** Component to show if not authenticated */\n UnauthorizedComponent?: React.ComponentType;\n /** Required roles */\n roles?: string[];\n }\n) {\n return function AuthenticatedComponent(props: P) {\n const { isAuthenticated, isLoading, user } = useAuth();\n\n const LoadingComp = options?.LoadingComponent;\n const UnauthorizedComp = options?.UnauthorizedComponent;\n\n if (isLoading) {\n return LoadingComp ? : null;\n }\n\n if (!isAuthenticated) {\n return UnauthorizedComp ? : null;\n }\n\n if (options?.roles && options.roles.length > 0) {\n const hasRequiredRole = options.roles.some(role => user?.roles?.includes(role));\n if (!hasRequiredRole) {\n return UnauthorizedComp ? : null;\n }\n }\n\n return ;\n };\n}\n\n// Re-export types\nexport type { StuffleIAMConfig, AuthState, User, LoginOptions, LogoutOptions, CallbackResult };\n","/**\n * Utility functions for PKCE and crypto operations\n */\n\n/**\n * Generate a random string for state/nonce\n */\nexport function generateRandomString(length: number = 32): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generate PKCE code verifier (43-128 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate PKCE code challenge from verifier\n */\nexport async function generateCodeChallenge(verifier: string): Promise {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(digest));\n}\n\n/**\n * Base64 URL encode (no padding, URL-safe characters)\n */\nexport function base64UrlEncode(buffer: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < buffer.length; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Decode JWT payload (without verification)\n */\nexport function decodeJwtPayload>(token: string): T | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded) as T;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string, thresholdSeconds: number = 0): boolean {\n const payload = decodeJwtPayload<{ exp?: number }>(token);\n if (!payload?.exp) return true;\n \n const now = Math.floor(Date.now() / 1000);\n return payload.exp - thresholdSeconds <= now;\n}\n\n/**\n * Parse URL hash or query parameters\n */\nexport function parseUrlParams(url: string): Record {\n const params: Record = {};\n \n // Check hash first (implicit flow), then query (code flow)\n const hashIndex = url.indexOf('#');\n const queryIndex = url.indexOf('?');\n \n let paramString = '';\n if (hashIndex !== -1) {\n paramString = url.substring(hashIndex + 1);\n } else if (queryIndex !== -1) {\n paramString = url.substring(queryIndex + 1);\n }\n \n if (!paramString) return params;\n \n const searchParams = new URLSearchParams(paramString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n \n return params;\n}\n\n/**\n * Build URL with query parameters\n */\nexport function buildUrl(base: string, params: Record): string {\n const url = new URL(base);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n return url.toString();\n}\n","/**\n * Token storage abstraction\n */\n\nexport interface TokenStorage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n clear(): void;\n}\n\nconst STORAGE_PREFIX = 'stuffle_iam_';\n\n/**\n * LocalStorage implementation\n */\nexport class LocalStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('LocalStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(localStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => localStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * SessionStorage implementation\n */\nexport class SessionStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return sessionStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n sessionStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('SessionStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n sessionStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(sessionStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => sessionStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * In-memory storage (for SSR or when storage is unavailable)\n */\nexport class MemoryStorageAdapter implements TokenStorage {\n private store = new Map();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n\n/**\n * Get storage adapter based on type\n */\nexport function getStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n switch (type) {\n case 'localStorage':\n return new LocalStorageAdapter();\n case 'sessionStorage':\n return new SessionStorageAdapter();\n case 'memory':\n return new MemoryStorageAdapter();\n default:\n return new SessionStorageAdapter();\n }\n}\n","/**\n * Stuffle IAM Client\n * \n * OIDC/OAuth2 client for browser-based applications.\n * Supports authorization code flow with PKCE.\n */\n\nimport type {\n StuffleIAMConfig,\n TokenResponse,\n User,\n AuthState,\n LoginOptions,\n LogoutOptions,\n CallbackResult,\n OIDCDiscovery,\n} from './types';\nimport {\n generateRandomString,\n generateCodeVerifier,\n generateCodeChallenge,\n decodeJwtPayload,\n isTokenExpired,\n parseUrlParams,\n buildUrl,\n} from './utils';\nimport { getStorage, type TokenStorage } from './storage';\n\nconst STORAGE_KEYS = {\n ACCESS_TOKEN: 'access_token',\n REFRESH_TOKEN: 'refresh_token',\n ID_TOKEN: 'id_token',\n CODE_VERIFIER: 'code_verifier',\n STATE: 'state',\n NONCE: 'nonce',\n USER: 'user',\n EXPIRES_AT: 'expires_at',\n};\n\nexport class StuffleIAMClient {\n private config: Required;\n private storage: TokenStorage;\n private discovery: OIDCDiscovery | null = null;\n private refreshTimer: ReturnType | null = null;\n private listeners: Set<(state: AuthState) => void> = new Set();\n\n constructor(config: StuffleIAMConfig) {\n this.config = {\n issuer: config.issuer.replace(/\\/$/, ''), // Remove trailing slash\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n scopes: config.scopes ?? ['openid', 'profile', 'email'],\n postLogoutRedirectUri: config.postLogoutRedirectUri ?? config.redirectUri,\n usePkce: config.usePkce ?? true,\n storage: config.storage ?? 'sessionStorage',\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? 60,\n };\n\n this.storage = getStorage(this.config.storage);\n }\n\n /**\n * Fetch OIDC discovery document\n */\n async getDiscovery(): Promise {\n if (this.discovery) return this.discovery;\n\n const response = await fetch(\n `${this.config.issuer}/.well-known/openid-configuration`\n );\n\n if (!response.ok) {\n throw new Error(`Failed to fetch OIDC discovery: ${response.status}`);\n }\n\n this.discovery = await response.json();\n return this.discovery!;\n }\n\n /**\n * Start login flow - redirects to authorization endpoint\n */\n async login(options: LoginOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n\n const state = options.state ?? generateRandomString();\n const nonce = options.nonce ?? generateRandomString();\n const scopes = [...this.config.scopes, ...(options.scopes ?? [])];\n\n // Store state and nonce for callback validation\n this.storage.set(STORAGE_KEYS.STATE, state);\n this.storage.set(STORAGE_KEYS.NONCE, nonce);\n\n const params: Record = {\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n state,\n nonce,\n prompt: options.prompt,\n login_hint: options.loginHint,\n };\n\n // Add PKCE if enabled\n if (this.config.usePkce) {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n this.storage.set(STORAGE_KEYS.CODE_VERIFIER, codeVerifier);\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Use signup endpoint if requested\n const endpoint = options.signup\n ? discovery.authorization_endpoint.replace('/authorize', '/authorize/signup')\n : discovery.authorization_endpoint;\n\n const authUrl = buildUrl(endpoint, params);\n window.location.href = authUrl;\n }\n\n /**\n * Alias for login({ signup: true })\n */\n async signup(options: Omit = {}): Promise {\n return this.login({ ...options, signup: true });\n }\n\n /**\n * Handle callback from authorization server\n */\n async handleCallback(url?: string): Promise {\n const callbackUrl = url ?? window.location.href;\n const params = parseUrlParams(callbackUrl);\n\n // Check for errors\n if (params.error) {\n return {\n success: false,\n error: params.error,\n errorDescription: params.error_description,\n };\n }\n\n // Validate state\n const storedState = this.storage.get(STORAGE_KEYS.STATE);\n if (!storedState || storedState !== params.state) {\n return {\n success: false,\n error: 'invalid_state',\n errorDescription: 'State mismatch - possible CSRF attack',\n };\n }\n\n // Exchange code for tokens\n if (!params.code) {\n return {\n success: false,\n error: 'missing_code',\n errorDescription: 'No authorization code received',\n };\n }\n\n try {\n const tokens = await this.exchangeCode(params.code);\n \n // Validate nonce in ID token\n if (tokens.id_token) {\n const payload = decodeJwtPayload<{ nonce?: string }>(tokens.id_token);\n const storedNonce = this.storage.get(STORAGE_KEYS.NONCE);\n if (payload?.nonce !== storedNonce) {\n return {\n success: false,\n error: 'invalid_nonce',\n errorDescription: 'Nonce mismatch - possible replay attack',\n };\n }\n }\n\n // Store tokens\n this.storeTokens(tokens);\n\n // Clear temporary storage\n this.storage.remove(STORAGE_KEYS.STATE);\n this.storage.remove(STORAGE_KEYS.NONCE);\n this.storage.remove(STORAGE_KEYS.CODE_VERIFIER);\n\n // Get user info\n const user = await this.fetchUserInfo(tokens.access_token);\n\n // Setup auto-refresh\n if (this.config.autoRefresh && tokens.refresh_token) {\n this.setupAutoRefresh();\n }\n\n // Notify listeners\n this.notifyListeners();\n\n return {\n success: true,\n user: user || undefined,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token,\n };\n } catch (error) {\n return {\n success: false,\n error: 'token_exchange_failed',\n errorDescription: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCode(code: string): Promise {\n const discovery = await this.getDiscovery();\n\n const body: Record = {\n grant_type: 'authorization_code',\n client_id: this.config.clientId,\n code,\n redirect_uri: this.config.redirectUri,\n };\n\n // Add PKCE code verifier\n if (this.config.usePkce) {\n const codeVerifier = this.storage.get(STORAGE_KEYS.CODE_VERIFIER);\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n }\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error_description || error.error || 'Token exchange failed');\n }\n\n return response.json();\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshToken(): Promise {\n const refreshToken = this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);\n if (!refreshToken) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n refresh_token: refreshToken,\n }),\n });\n\n if (!response.ok) {\n // Refresh failed - clear tokens\n this.clearTokens();\n this.notifyListeners();\n return null;\n }\n\n const tokens: TokenResponse = await response.json();\n this.storeTokens(tokens);\n this.notifyListeners();\n\n return tokens;\n }\n\n /**\n * Logout - end session\n */\n async logout(options: LogoutOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n\n // Clear local tokens first\n this.clearTokens();\n this.notifyListeners();\n\n // Redirect to end session endpoint if available\n if (discovery.end_session_endpoint) {\n const params: Record = {\n post_logout_redirect_uri: options.returnTo ?? this.config.postLogoutRedirectUri,\n id_token_hint: options.idTokenHint ?? idToken ?? undefined,\n client_id: this.config.clientId,\n };\n\n const logoutUrl = buildUrl(discovery.end_session_endpoint, params);\n window.location.href = logoutUrl;\n }\n }\n\n /**\n * Get current access token (refreshes if needed)\n */\n async getAccessToken(): Promise {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n \n if (!accessToken) return null;\n\n // Check if token needs refresh\n if (isTokenExpired(accessToken, this.config.refreshThreshold)) {\n const tokens = await this.refreshToken();\n return tokens?.access_token ?? null;\n }\n\n return accessToken;\n }\n\n /**\n * Get current user from stored ID token\n */\n getUser(): User | null {\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n if (!idToken) return null;\n\n return decodeJwtPayload(idToken);\n }\n\n /**\n * Fetch user info from userinfo endpoint\n */\n async fetchUserInfo(accessToken?: string): Promise {\n const token = accessToken ?? await this.getAccessToken();\n if (!token) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.userinfo_endpoint, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) return null;\n\n const user: User = await response.json();\n this.storage.set(STORAGE_KEYS.USER, JSON.stringify(user));\n return user;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n if (!accessToken) return false;\n\n // Consider authenticated if token exists and not expired\n return !isTokenExpired(accessToken);\n }\n\n /**\n * Get current auth state\n */\n getAuthState(): AuthState {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n const user = this.getUser();\n\n return {\n isAuthenticated: this.isAuthenticated(),\n isLoading: false,\n user,\n accessToken,\n idToken,\n error: null,\n };\n }\n\n /**\n * Subscribe to auth state changes\n */\n subscribe(listener: (state: AuthState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Store tokens in storage\n */\n private storeTokens(tokens: TokenResponse): void {\n this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, tokens.access_token);\n \n if (tokens.refresh_token) {\n this.storage.set(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh_token);\n }\n \n if (tokens.id_token) {\n this.storage.set(STORAGE_KEYS.ID_TOKEN, tokens.id_token);\n }\n\n // Store expiry time\n const expiresAt = Date.now() + (tokens.expires_in * 1000);\n this.storage.set(STORAGE_KEYS.EXPIRES_AT, expiresAt.toString());\n }\n\n /**\n * Clear all stored tokens\n */\n private clearTokens(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n this.storage.clear();\n }\n\n /**\n * Setup auto-refresh timer\n */\n private setupAutoRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n const expiresAt = this.storage.get(STORAGE_KEYS.EXPIRES_AT);\n if (!expiresAt) return;\n\n const expiresAtMs = parseInt(expiresAt, 10);\n const refreshAt = expiresAtMs - (this.config.refreshThreshold * 1000);\n const delay = refreshAt - Date.now();\n\n if (delay > 0) {\n this.refreshTimer = setTimeout(async () => {\n await this.refreshToken();\n this.setupAutoRefresh();\n }, delay);\n }\n }\n\n /**\n * Notify all listeners of state change\n */\n private notifyListeners(): void {\n const state = this.getAuthState();\n this.listeners.forEach(listener => listener(state));\n }\n}\n\n/**\n * Create a new Stuffle IAM client instance\n */\nexport function createStuffleIAMClient(config: StuffleIAMConfig): StuffleIAMClient {\n return new StuffleIAMClient(config);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCA,mBAQO;;;ACrCA,SAAS,qBAAqB,SAAiB,IAAY;AAChE,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,OAAO,UAAQ,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC9E;AAKO,SAAS,uBAA+B;AAC7C,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,SAAO,gBAAgB,KAAK;AAC9B;AAKA,eAAsB,sBAAsB,UAAmC;AAC7E,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,OAAO,QAAQ,OAAO,QAAQ;AACpC,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,SAAO,gBAAgB,IAAI,WAAW,MAAM,CAAC;AAC/C;AAKO,SAAS,gBAAgB,QAA4B;AAC1D,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAU,OAAO,aAAa,OAAO,CAAC,CAAC;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EACf,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AACtB;AAKO,SAAS,iBAA8C,OAAyB;AACrF,MAAI;AACF,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,UAAU,KAAK,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC;AAClE,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,eAAe,OAAe,mBAA2B,GAAY;AACnF,QAAM,UAAU,iBAAmC,KAAK;AACxD,MAAI,CAAC,SAAS,IAAK,QAAO;AAE1B,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,SAAO,QAAQ,MAAM,oBAAoB;AAC3C;AAKO,SAAS,eAAe,KAAqC;AAClE,QAAM,SAAiC,CAAC;AAGxC,QAAM,YAAY,IAAI,QAAQ,GAAG;AACjC,QAAM,aAAa,IAAI,QAAQ,GAAG;AAElC,MAAI,cAAc;AAClB,MAAI,cAAc,IAAI;AACpB,kBAAc,IAAI,UAAU,YAAY,CAAC;AAAA,EAC3C,WAAW,eAAe,IAAI;AAC5B,kBAAc,IAAI,UAAU,aAAa,CAAC;AAAA,EAC5C;AAEA,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,eAAe,IAAI,gBAAgB,WAAW;AACpD,eAAa,QAAQ,CAAC,OAAO,QAAQ;AACnC,WAAO,GAAG,IAAI;AAAA,EAChB,CAAC;AAED,SAAO;AACT;AAKO,SAAS,SAAS,MAAc,QAAoD;AACzF,QAAM,MAAM,IAAI,IAAI,IAAI;AACxB,SAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAC/C,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC,UAAI,aAAa,OAAO,KAAK,KAAK;AAAA,IACpC;AAAA,EACF,CAAC;AACD,SAAO,IAAI,SAAS;AACtB;;;ACpGA,IAAM,iBAAiB;AAKhB,IAAM,sBAAN,MAAkD;AAAA,EACvD,IAAI,KAA4B;AAC9B,QAAI;AACF,aAAO,aAAa,QAAQ,iBAAiB,GAAG;AAAA,IAClD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,IAAI,KAAa,OAAqB;AACpC,QAAI;AACF,mBAAa,QAAQ,iBAAiB,KAAK,KAAK;AAAA,IAClD,QAAQ;AACN,cAAQ,KAAK,4BAA4B;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,OAAO,KAAmB;AACxB,QAAI;AACF,mBAAa,WAAW,iBAAiB,GAAG;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI;AACF,aAAO,KAAK,YAAY,EACrB,OAAO,OAAK,EAAE,WAAW,cAAc,CAAC,EACxC,QAAQ,OAAK,aAAa,WAAW,CAAC,CAAC;AAAA,IAC5C,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAKO,IAAM,wBAAN,MAAoD;AAAA,EACzD,IAAI,KAA4B;AAC9B,QAAI;AACF,aAAO,eAAe,QAAQ,iBAAiB,GAAG;AAAA,IACpD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,IAAI,KAAa,OAAqB;AACpC,QAAI;AACF,qBAAe,QAAQ,iBAAiB,KAAK,KAAK;AAAA,IACpD,QAAQ;AACN,cAAQ,KAAK,8BAA8B;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,OAAO,KAAmB;AACxB,QAAI;AACF,qBAAe,WAAW,iBAAiB,GAAG;AAAA,IAChD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI;AACF,aAAO,KAAK,cAAc,EACvB,OAAO,OAAK,EAAE,WAAW,cAAc,CAAC,EACxC,QAAQ,OAAK,eAAe,WAAW,CAAC,CAAC;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAKO,IAAM,uBAAN,MAAmD;AAAA,EAAnD;AACL,SAAQ,QAAQ,oBAAI,IAAoB;AAAA;AAAA,EAExC,IAAI,KAA4B;AAC9B,WAAO,KAAK,MAAM,IAAI,GAAG,KAAK;AAAA,EAChC;AAAA,EAEA,IAAI,KAAa,OAAqB;AACpC,SAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,OAAO,KAAmB;AACxB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;AAKO,SAAS,WAAW,MAAkE;AAC3F,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,IAAI,oBAAoB;AAAA,IACjC,KAAK;AACH,aAAO,IAAI,sBAAsB;AAAA,IACnC,KAAK;AACH,aAAO,IAAI,qBAAqB;AAAA,IAClC;AACE,aAAO,IAAI,sBAAsB;AAAA,EACrC;AACF;;;ACpGA,IAAM,eAAe;AAAA,EACnB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AAAA,EACV,eAAe;AAAA,EACf,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,YAAY;AACd;AAEO,IAAM,mBAAN,MAAuB;AAAA,EAO5B,YAAY,QAA0B;AAJtC,SAAQ,YAAkC;AAC1C,SAAQ,eAAqD;AAC7D,SAAQ,YAA6C,oBAAI,IAAI;AAG3D,SAAK,SAAS;AAAA,MACZ,QAAQ,OAAO,OAAO,QAAQ,OAAO,EAAE;AAAA;AAAA,MACvC,UAAU,OAAO;AAAA,MACjB,aAAa,OAAO;AAAA,MACpB,QAAQ,OAAO,UAAU,CAAC,UAAU,WAAW,OAAO;AAAA,MACtD,uBAAuB,OAAO,yBAAyB,OAAO;AAAA,MAC9D,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS,OAAO,WAAW;AAAA,MAC3B,aAAa,OAAO,eAAe;AAAA,MACnC,kBAAkB,OAAO,oBAAoB;AAAA,IAC/C;AAEA,SAAK,UAAU,WAAW,KAAK,OAAO,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAuC;AAC3C,QAAI,KAAK,UAAW,QAAO,KAAK;AAEhC,UAAM,WAAW,MAAM;AAAA,MACrB,GAAG,KAAK,OAAO,MAAM;AAAA,IACvB;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mCAAmC,SAAS,MAAM,EAAE;AAAA,IACtE;AAEA,SAAK,YAAY,MAAM,SAAS,KAAK;AACrC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,UAAwB,CAAC,GAAkB;AACrD,UAAM,YAAY,MAAM,KAAK,aAAa;AAE1C,UAAM,QAAQ,QAAQ,SAAS,qBAAqB;AACpD,UAAM,QAAQ,QAAQ,SAAS,qBAAqB;AACpD,UAAM,SAAS,CAAC,GAAG,KAAK,OAAO,QAAQ,GAAI,QAAQ,UAAU,CAAC,CAAE;AAGhE,SAAK,QAAQ,IAAI,aAAa,OAAO,KAAK;AAC1C,SAAK,QAAQ,IAAI,aAAa,OAAO,KAAK;AAE1C,UAAM,SAA6C;AAAA,MACjD,WAAW,KAAK,OAAO;AAAA,MACvB,cAAc,KAAK,OAAO;AAAA,MAC1B,eAAe;AAAA,MACf,OAAO,OAAO,KAAK,GAAG;AAAA,MACtB;AAAA,MACA;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,IACtB;AAGA,QAAI,KAAK,OAAO,SAAS;AACvB,YAAM,eAAe,qBAAqB;AAC1C,YAAM,gBAAgB,MAAM,sBAAsB,YAAY;AAE9D,WAAK,QAAQ,IAAI,aAAa,eAAe,YAAY;AACzD,aAAO,iBAAiB;AACxB,aAAO,wBAAwB;AAAA,IACjC;AAGA,UAAM,WAAW,QAAQ,SACrB,UAAU,uBAAuB,QAAQ,cAAc,mBAAmB,IAC1E,UAAU;AAEd,UAAM,UAAU,SAAS,UAAU,MAAM;AACzC,WAAO,SAAS,OAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,UAAwC,CAAC,GAAkB;AACtE,WAAO,KAAK,MAAM,EAAE,GAAG,SAAS,QAAQ,KAAK,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,KAAuC;AAC1D,UAAM,cAAc,OAAO,OAAO,SAAS;AAC3C,UAAM,SAAS,eAAe,WAAW;AAGzC,QAAI,OAAO,OAAO;AAChB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,OAAO;AAAA,QACd,kBAAkB,OAAO;AAAA,MAC3B;AAAA,IACF;AAGA,UAAM,cAAc,KAAK,QAAQ,IAAI,aAAa,KAAK;AACvD,QAAI,CAAC,eAAe,gBAAgB,OAAO,OAAO;AAChD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,kBAAkB;AAAA,MACpB;AAAA,IACF;AAGA,QAAI,CAAC,OAAO,MAAM;AAChB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,kBAAkB;AAAA,MACpB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa,OAAO,IAAI;AAGlD,UAAI,OAAO,UAAU;AACnB,cAAM,UAAU,iBAAqC,OAAO,QAAQ;AACpE,cAAM,cAAc,KAAK,QAAQ,IAAI,aAAa,KAAK;AACvD,YAAI,SAAS,UAAU,aAAa;AAClC,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAO;AAAA,YACP,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAGA,WAAK,YAAY,MAAM;AAGvB,WAAK,QAAQ,OAAO,aAAa,KAAK;AACtC,WAAK,QAAQ,OAAO,aAAa,KAAK;AACtC,WAAK,QAAQ,OAAO,aAAa,aAAa;AAG9C,YAAM,OAAO,MAAM,KAAK,cAAc,OAAO,YAAY;AAGzD,UAAI,KAAK,OAAO,eAAe,OAAO,eAAe;AACnD,aAAK,iBAAiB;AAAA,MACxB;AAGA,WAAK,gBAAgB;AAErB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,QAAQ;AAAA,QACd,aAAa,OAAO;AAAA,QACpB,SAAS,OAAO;AAAA,QAChB,cAAc,OAAO;AAAA,MACvB;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAa,MAAsC;AAC/D,UAAM,YAAY,MAAM,KAAK,aAAa;AAE1C,UAAM,OAA+B;AAAA,MACnC,YAAY;AAAA,MACZ,WAAW,KAAK,OAAO;AAAA,MACvB;AAAA,MACA,cAAc,KAAK,OAAO;AAAA,IAC5B;AAGA,QAAI,KAAK,OAAO,SAAS;AACvB,YAAM,eAAe,KAAK,QAAQ,IAAI,aAAa,aAAa;AAChE,UAAI,cAAc;AAChB,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,MAAM,UAAU,gBAAgB;AAAA,MACrD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,IAAI,gBAAgB,IAAI;AAAA,IAChC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACpD,YAAM,IAAI,MAAM,MAAM,qBAAqB,MAAM,SAAS,uBAAuB;AAAA,IACnF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAA8C;AAClD,UAAM,eAAe,KAAK,QAAQ,IAAI,aAAa,aAAa;AAChE,QAAI,CAAC,aAAc,QAAO;AAE1B,UAAM,YAAY,MAAM,KAAK,aAAa;AAE1C,UAAM,WAAW,MAAM,MAAM,UAAU,gBAAgB;AAAA,MACrD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,IAAI,gBAAgB;AAAA,QACxB,YAAY;AAAA,QACZ,WAAW,KAAK,OAAO;AAAA,QACvB,eAAe;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAEhB,WAAK,YAAY;AACjB,WAAK,gBAAgB;AACrB,aAAO;AAAA,IACT;AAEA,UAAM,SAAwB,MAAM,SAAS,KAAK;AAClD,SAAK,YAAY,MAAM;AACvB,SAAK,gBAAgB;AAErB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,UAAyB,CAAC,GAAkB;AACvD,UAAM,YAAY,MAAM,KAAK,aAAa;AAC1C,UAAM,UAAU,KAAK,QAAQ,IAAI,aAAa,QAAQ;AAGtD,SAAK,YAAY;AACjB,SAAK,gBAAgB;AAGrB,QAAI,UAAU,sBAAsB;AAClC,YAAM,SAA6C;AAAA,QACjD,0BAA0B,QAAQ,YAAY,KAAK,OAAO;AAAA,QAC1D,eAAe,QAAQ,eAAe,WAAW;AAAA,QACjD,WAAW,KAAK,OAAO;AAAA,MACzB;AAEA,YAAM,YAAY,SAAS,UAAU,sBAAsB,MAAM;AACjE,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAyC;AAC7C,UAAM,cAAc,KAAK,QAAQ,IAAI,aAAa,YAAY;AAE9D,QAAI,CAAC,YAAa,QAAO;AAGzB,QAAI,eAAe,aAAa,KAAK,OAAO,gBAAgB,GAAG;AAC7D,YAAM,SAAS,MAAM,KAAK,aAAa;AACvC,aAAO,QAAQ,gBAAgB;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAuB;AACrB,UAAM,UAAU,KAAK,QAAQ,IAAI,aAAa,QAAQ;AACtD,QAAI,CAAC,QAAS,QAAO;AAErB,WAAO,iBAAuB,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,aAA4C;AAC9D,UAAM,QAAQ,eAAe,MAAM,KAAK,eAAe;AACvD,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,YAAY,MAAM,KAAK,aAAa;AAE1C,UAAM,WAAW,MAAM,MAAM,UAAU,mBAAmB;AAAA,MACxD,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,MAChC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,UAAM,OAAa,MAAM,SAAS,KAAK;AACvC,SAAK,QAAQ,IAAI,aAAa,MAAM,KAAK,UAAU,IAAI,CAAC;AACxD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA2B;AACzB,UAAM,cAAc,KAAK,QAAQ,IAAI,aAAa,YAAY;AAC9D,QAAI,CAAC,YAAa,QAAO;AAGzB,WAAO,CAAC,eAAe,WAAW;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,eAA0B;AACxB,UAAM,cAAc,KAAK,QAAQ,IAAI,aAAa,YAAY;AAC9D,UAAM,UAAU,KAAK,QAAQ,IAAI,aAAa,QAAQ;AACtD,UAAM,OAAO,KAAK,QAAQ;AAE1B,WAAO;AAAA,MACL,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAkD;AAC1D,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,QAA6B;AAC/C,SAAK,QAAQ,IAAI,aAAa,cAAc,OAAO,YAAY;AAE/D,QAAI,OAAO,eAAe;AACxB,WAAK,QAAQ,IAAI,aAAa,eAAe,OAAO,aAAa;AAAA,IACnE;AAEA,QAAI,OAAO,UAAU;AACnB,WAAK,QAAQ,IAAI,aAAa,UAAU,OAAO,QAAQ;AAAA,IACzD;AAGA,UAAM,YAAY,KAAK,IAAI,IAAK,OAAO,aAAa;AACpD,SAAK,QAAQ,IAAI,aAAa,YAAY,UAAU,SAAS,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAoB;AAC1B,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAAA,IAChC;AAEA,UAAM,YAAY,KAAK,QAAQ,IAAI,aAAa,UAAU;AAC1D,QAAI,CAAC,UAAW;AAEhB,UAAM,cAAc,SAAS,WAAW,EAAE;AAC1C,UAAM,YAAY,cAAe,KAAK,OAAO,mBAAmB;AAChE,UAAM,QAAQ,YAAY,KAAK,IAAI;AAEnC,QAAI,QAAQ,GAAG;AACb,WAAK,eAAe,WAAW,YAAY;AACzC,cAAM,KAAK,aAAa;AACxB,aAAK,iBAAiB;AAAA,MACxB,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAwB;AAC9B,UAAM,QAAQ,KAAK,aAAa;AAChC,SAAK,UAAU,QAAQ,cAAY,SAAS,KAAK,CAAC;AAAA,EACpD;AACF;AAKO,SAAS,uBAAuB,QAA4C;AACjF,SAAO,IAAI,iBAAiB,MAAM;AACpC;;;AHtRI;AAnHJ,IAAM,wBAAoB,4BAA6C,IAAI;AAgBpE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,GAAG;AACL,GAA4B;AAC1B,QAAM,CAAC,MAAM,QAAI,uBAAS,MAAM,uBAAuB,MAAM,CAAC;AAC9D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAoB,OAAO;AAAA,IACnD,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,EACT,EAAE;AAGF,8BAAU,MAAM;AACd,UAAM,cAAc,OAAO,UAAU,QAAQ;AAG7C,UAAM,eAAe,OAAO,aAAa;AACzC,aAAS,EAAE,GAAG,cAAc,WAAW,MAAM,CAAC;AAE9C,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAGX,8BAAU,MAAM;AACd,QAAI,CAAC,mBAAoB;AAEzB,UAAM,MAAM,OAAO,SAAS;AAC5B,UAAM,UAAU,IAAI,SAAS,OAAO;AACpC,UAAM,WAAW,IAAI,SAAS,QAAQ;AAEtC,QAAI,WAAW,UAAU;AACvB,eAAS,WAAS,EAAE,GAAG,MAAM,WAAW,KAAK,EAAE;AAE/C,aAAO,eAAe,GAAG,EAAE,KAAK,YAAU;AACxC,iBAAS,WAAS,EAAE,GAAG,MAAM,WAAW,MAAM,EAAE;AAEhD,YAAI,OAAO,SAAS;AAClB,2BAAiB,MAAM;AAEvB,iBAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,OAAO,SAAS,QAAQ;AAAA,QAC9D,OAAO;AACL,gBAAM,QAAQ,IAAI,MAAM,OAAO,oBAAoB,OAAO,SAAS,cAAc;AACjF,yBAAe,KAAK;AACpB,mBAAS,WAAS,EAAE,GAAG,MAAM,MAAM,EAAE;AAAA,QACvC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,QAAQ,oBAAoB,gBAAgB,YAAY,CAAC;AAG7D,QAAM,YAAQ;AAAA,IACZ,CAAC,YAA2B,OAAO,MAAM,OAAO;AAAA,IAChD,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,YAA2C,OAAO,OAAO,OAAO;AAAA,IACjE,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAS;AAAA,IACb,CAAC,YAA4B,OAAO,OAAO,OAAO;AAAA,IAClD,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,qBAAiB;AAAA,IACrB,CAAC,QAAiB,OAAO,eAAe,GAAG;AAAA,IAC3C,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,qBAAiB;AAAA,IACrB,MAAM,OAAO,eAAe;AAAA,IAC5B,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,YAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,iBAAiB,MAAM;AAAA,MACvB,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,OAAO,MAAM;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,OAAO,OAAO,QAAQ,QAAQ,gBAAgB,cAAc;AAAA,EACvE;AAEA,SACE,4CAAC,kBAAkB,UAAlB,EAA2B,OACzB,UACH;AAEJ;AASO,SAAS,UAAU;AACxB,QAAM,cAAU,yBAAW,iBAAiB;AAC5C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,SAAO;AACT;AAKO,SAAS,UAAuB;AACrC,QAAM,EAAE,KAAK,IAAI,QAAQ;AACzB,SAAO;AACT;AAKO,SAAS,qBAA8B;AAC5C,QAAM,EAAE,gBAAgB,IAAI,QAAQ;AACpC,SAAO;AACT;AAKO,SAAS,iBAA+C;AAC7D,QAAM,EAAE,eAAe,IAAI,QAAQ;AACnC,SAAO;AACT;AAKO,SAAS,WAAW,OAAmC;AAC5D,QAAM,EAAE,KAAK,IAAI,QAAQ;AACzB,MAAI,CAAC,MAAM,MAAO,QAAO;AAEzB,QAAM,gBAAgB,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC3D,SAAO,cAAc,KAAK,UAAQ,KAAK,OAAO,SAAS,IAAI,CAAC;AAC9D;AAKO,SAAS,SACd,kBACA,SAQA;AACA,SAAO,SAAS,uBAAuB,OAAU;AAC/C,UAAM,EAAE,iBAAiB,WAAW,KAAK,IAAI,QAAQ;AAErD,UAAM,cAAc,SAAS;AAC7B,UAAM,mBAAmB,SAAS;AAElC,QAAI,WAAW;AACb,aAAO,cAAc,4CAAC,eAAY,IAAK;AAAA,IACzC;AAEA,QAAI,CAAC,iBAAiB;AACpB,aAAO,mBAAmB,4CAAC,oBAAiB,IAAK;AAAA,IACnD;AAEA,QAAI,SAAS,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC9C,YAAM,kBAAkB,QAAQ,MAAM,KAAK,UAAQ,MAAM,OAAO,SAAS,IAAI,CAAC;AAC9E,UAAI,CAAC,iBAAiB;AACpB,eAAO,mBAAmB,4CAAC,oBAAiB,IAAK;AAAA,MACnD;AAAA,IACF;AAEA,WAAO,4CAAC,oBAAkB,GAAG,OAAO;AAAA,EACtC;AACF;","names":[]} \ No newline at end of file diff --git a/dist/react.mjs b/dist/react.mjs index dcda85c..03e3df5 100644 --- a/dist/react.mjs +++ b/dist/react.mjs @@ -620,16 +620,18 @@ function useHasRole(roles) { function withAuth(WrappedComponent, options) { return function AuthenticatedComponent(props) { const { isAuthenticated, isLoading, user } = useAuth(); + const LoadingComp = options?.LoadingComponent; + const UnauthorizedComp = options?.UnauthorizedComponent; if (isLoading) { - return options?.LoadingComponent ? /* @__PURE__ */ jsx(options.LoadingComponent, {}) : null; + return LoadingComp ? /* @__PURE__ */ jsx(LoadingComp, {}) : null; } if (!isAuthenticated) { - return options?.UnauthorizedComponent ? /* @__PURE__ */ jsx(options.UnauthorizedComponent, {}) : null; + return UnauthorizedComp ? /* @__PURE__ */ jsx(UnauthorizedComp, {}) : null; } if (options?.roles && options.roles.length > 0) { const hasRequiredRole = options.roles.some((role) => user?.roles?.includes(role)); if (!hasRequiredRole) { - return options?.UnauthorizedComponent ? /* @__PURE__ */ jsx(options.UnauthorizedComponent, {}) : null; + return UnauthorizedComp ? /* @__PURE__ */ jsx(UnauthorizedComp, {}) : null; } } return /* @__PURE__ */ jsx(WrappedComponent, { ...props }); diff --git a/dist/react.mjs.map b/dist/react.mjs.map index a7fb073..2fed42c 100644 --- a/dist/react.mjs.map +++ b/dist/react.mjs.map @@ -1 +1 @@ -{"version":3,"sources":["../src/react/index.tsx","../src/utils.ts","../src/storage.ts","../src/client.ts"],"sourcesContent":["/**\n * React bindings for Stuffle IAM SDK\n * \n * @example\n * ```tsx\n * import { StuffleIAMProvider, useAuth } from '@stuffle/iam-sdk/react';\n * \n * function App() {\n * return (\n * \n * \n * \n * );\n * }\n * \n * function MyApp() {\n * const { isAuthenticated, user, login, logout } = useAuth();\n * \n * if (!isAuthenticated) {\n * return ;\n * }\n * \n * return (\n *

\n *

Welcome, {user?.name}

\n * \n *
\n * );\n * }\n * ```\n */\n\nimport {\n createContext,\n useContext,\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n} from 'react';\nimport {\n StuffleIAMClient,\n createStuffleIAMClient,\n type StuffleIAMConfig,\n type AuthState,\n type User,\n type LoginOptions,\n type LogoutOptions,\n type CallbackResult,\n} from '../index';\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface StuffleIAMContextValue {\n client: StuffleIAMClient;\n isAuthenticated: boolean;\n isLoading: boolean;\n user: User | null;\n accessToken: string | null;\n error: Error | null;\n login: (options?: LoginOptions) => Promise;\n signup: (options?: Omit) => Promise;\n logout: (options?: LogoutOptions) => Promise;\n handleCallback: (url?: string) => Promise;\n getAccessToken: () => Promise;\n}\n\nconst StuffleIAMContext = createContext(null);\n\n// =============================================================================\n// Provider\n// =============================================================================\n\nexport interface StuffleIAMProviderProps extends StuffleIAMConfig {\n children: ReactNode;\n /** Called after successful login callback */\n onLoginSuccess?: (result: CallbackResult) => void;\n /** Called on login error */\n onLoginError?: (error: Error) => void;\n /** Auto-handle callback on mount if URL has code/error */\n autoHandleCallback?: boolean;\n}\n\nexport function StuffleIAMProvider({\n children,\n onLoginSuccess,\n onLoginError,\n autoHandleCallback = true,\n ...config\n}: StuffleIAMProviderProps) {\n const [client] = useState(() => createStuffleIAMClient(config));\n const [state, setState] = useState(() => ({\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n idToken: null,\n error: null,\n }));\n\n // Subscribe to auth state changes\n useEffect(() => {\n const unsubscribe = client.subscribe(setState);\n \n // Initialize state\n const initialState = client.getAuthState();\n setState({ ...initialState, isLoading: false });\n\n return unsubscribe;\n }, [client]);\n\n // Auto-handle callback\n useEffect(() => {\n if (!autoHandleCallback) return;\n\n const url = window.location.href;\n const hasCode = url.includes('code=');\n const hasError = url.includes('error=');\n\n if (hasCode || hasError) {\n setState(prev => ({ ...prev, isLoading: true }));\n \n client.handleCallback(url).then(result => {\n setState(prev => ({ ...prev, isLoading: false }));\n \n if (result.success) {\n onLoginSuccess?.(result);\n // Clean URL\n window.history.replaceState({}, '', window.location.pathname);\n } else {\n const error = new Error(result.errorDescription || result.error || 'Login failed');\n onLoginError?.(error);\n setState(prev => ({ ...prev, error }));\n }\n });\n }\n }, [client, autoHandleCallback, onLoginSuccess, onLoginError]);\n\n // Memoized methods\n const login = useCallback(\n (options?: LoginOptions) => client.login(options),\n [client]\n );\n\n const signup = useCallback(\n (options?: Omit) => client.signup(options),\n [client]\n );\n\n const logout = useCallback(\n (options?: LogoutOptions) => client.logout(options),\n [client]\n );\n\n const handleCallback = useCallback(\n (url?: string) => client.handleCallback(url),\n [client]\n );\n\n const getAccessToken = useCallback(\n () => client.getAccessToken(),\n [client]\n );\n\n const value = useMemo(\n () => ({\n client,\n isAuthenticated: state.isAuthenticated,\n isLoading: state.isLoading,\n user: state.user,\n accessToken: state.accessToken,\n error: state.error,\n login,\n signup,\n logout,\n handleCallback,\n getAccessToken,\n }),\n [client, state, login, signup, logout, handleCallback, getAccessToken]\n );\n\n return (\n \n {children}\n \n );\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * Hook to access auth state and methods\n */\nexport function useAuth() {\n const context = useContext(StuffleIAMContext);\n if (!context) {\n throw new Error('useAuth must be used within a StuffleIAMProvider');\n }\n return context;\n}\n\n/**\n * Hook to get current user\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n\n/**\n * Hook to check if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get access token (refreshes if needed)\n */\nexport function useAccessToken(): () => Promise {\n const { getAccessToken } = useAuth();\n return getAccessToken;\n}\n\n/**\n * Hook to check if user has specific role(s)\n */\nexport function useHasRole(roles: string | string[]): boolean {\n const { user } = useAuth();\n if (!user?.roles) return false;\n \n const requiredRoles = Array.isArray(roles) ? roles : [roles];\n return requiredRoles.some(role => user.roles?.includes(role));\n}\n\n/**\n * Higher-order component for protected routes\n */\nexport function withAuth

(\n WrappedComponent: React.ComponentType

,\n options?: {\n /** Component to show while loading */\n LoadingComponent?: React.ComponentType;\n /** Component to show if not authenticated */\n UnauthorizedComponent?: React.ComponentType;\n /** Required roles */\n roles?: string[];\n }\n) {\n return function AuthenticatedComponent(props: P) {\n const { isAuthenticated, isLoading, user } = useAuth();\n\n if (isLoading) {\n return options?.LoadingComponent ? : null;\n }\n\n if (!isAuthenticated) {\n return options?.UnauthorizedComponent ? : null;\n }\n\n if (options?.roles && options.roles.length > 0) {\n const hasRequiredRole = options.roles.some(role => user?.roles?.includes(role));\n if (!hasRequiredRole) {\n return options?.UnauthorizedComponent ? : null;\n }\n }\n\n return ;\n };\n}\n\n// Re-export types\nexport type { StuffleIAMConfig, AuthState, User, LoginOptions, LogoutOptions, CallbackResult };\n","/**\n * Utility functions for PKCE and crypto operations\n */\n\n/**\n * Generate a random string for state/nonce\n */\nexport function generateRandomString(length: number = 32): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generate PKCE code verifier (43-128 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate PKCE code challenge from verifier\n */\nexport async function generateCodeChallenge(verifier: string): Promise {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(digest));\n}\n\n/**\n * Base64 URL encode (no padding, URL-safe characters)\n */\nexport function base64UrlEncode(buffer: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < buffer.length; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Decode JWT payload (without verification)\n */\nexport function decodeJwtPayload>(token: string): T | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded) as T;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string, thresholdSeconds: number = 0): boolean {\n const payload = decodeJwtPayload<{ exp?: number }>(token);\n if (!payload?.exp) return true;\n \n const now = Math.floor(Date.now() / 1000);\n return payload.exp - thresholdSeconds <= now;\n}\n\n/**\n * Parse URL hash or query parameters\n */\nexport function parseUrlParams(url: string): Record {\n const params: Record = {};\n \n // Check hash first (implicit flow), then query (code flow)\n const hashIndex = url.indexOf('#');\n const queryIndex = url.indexOf('?');\n \n let paramString = '';\n if (hashIndex !== -1) {\n paramString = url.substring(hashIndex + 1);\n } else if (queryIndex !== -1) {\n paramString = url.substring(queryIndex + 1);\n }\n \n if (!paramString) return params;\n \n const searchParams = new URLSearchParams(paramString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n \n return params;\n}\n\n/**\n * Build URL with query parameters\n */\nexport function buildUrl(base: string, params: Record): string {\n const url = new URL(base);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n return url.toString();\n}\n","/**\n * Token storage abstraction\n */\n\nexport interface TokenStorage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n clear(): void;\n}\n\nconst STORAGE_PREFIX = 'stuffle_iam_';\n\n/**\n * LocalStorage implementation\n */\nexport class LocalStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('LocalStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(localStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => localStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * SessionStorage implementation\n */\nexport class SessionStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return sessionStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n sessionStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('SessionStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n sessionStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(sessionStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => sessionStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * In-memory storage (for SSR or when storage is unavailable)\n */\nexport class MemoryStorageAdapter implements TokenStorage {\n private store = new Map();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n\n/**\n * Get storage adapter based on type\n */\nexport function getStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n switch (type) {\n case 'localStorage':\n return new LocalStorageAdapter();\n case 'sessionStorage':\n return new SessionStorageAdapter();\n case 'memory':\n return new MemoryStorageAdapter();\n default:\n return new SessionStorageAdapter();\n }\n}\n","/**\n * Stuffle IAM Client\n * \n * OIDC/OAuth2 client for browser-based applications.\n * Supports authorization code flow with PKCE.\n */\n\nimport type {\n StuffleIAMConfig,\n TokenResponse,\n User,\n AuthState,\n LoginOptions,\n LogoutOptions,\n CallbackResult,\n OIDCDiscovery,\n} from './types';\nimport {\n generateRandomString,\n generateCodeVerifier,\n generateCodeChallenge,\n decodeJwtPayload,\n isTokenExpired,\n parseUrlParams,\n buildUrl,\n} from './utils';\nimport { getStorage, type TokenStorage } from './storage';\n\nconst STORAGE_KEYS = {\n ACCESS_TOKEN: 'access_token',\n REFRESH_TOKEN: 'refresh_token',\n ID_TOKEN: 'id_token',\n CODE_VERIFIER: 'code_verifier',\n STATE: 'state',\n NONCE: 'nonce',\n USER: 'user',\n EXPIRES_AT: 'expires_at',\n};\n\nexport class StuffleIAMClient {\n private config: Required;\n private storage: TokenStorage;\n private discovery: OIDCDiscovery | null = null;\n private refreshTimer: ReturnType | null = null;\n private listeners: Set<(state: AuthState) => void> = new Set();\n\n constructor(config: StuffleIAMConfig) {\n this.config = {\n issuer: config.issuer.replace(/\\/$/, ''), // Remove trailing slash\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n scopes: config.scopes ?? ['openid', 'profile', 'email'],\n postLogoutRedirectUri: config.postLogoutRedirectUri ?? config.redirectUri,\n usePkce: config.usePkce ?? true,\n storage: config.storage ?? 'sessionStorage',\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? 60,\n };\n\n this.storage = getStorage(this.config.storage);\n }\n\n /**\n * Fetch OIDC discovery document\n */\n async getDiscovery(): Promise {\n if (this.discovery) return this.discovery;\n\n const response = await fetch(\n `${this.config.issuer}/.well-known/openid-configuration`\n );\n\n if (!response.ok) {\n throw new Error(`Failed to fetch OIDC discovery: ${response.status}`);\n }\n\n this.discovery = await response.json();\n return this.discovery!;\n }\n\n /**\n * Start login flow - redirects to authorization endpoint\n */\n async login(options: LoginOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n\n const state = options.state ?? generateRandomString();\n const nonce = options.nonce ?? generateRandomString();\n const scopes = [...this.config.scopes, ...(options.scopes ?? [])];\n\n // Store state and nonce for callback validation\n this.storage.set(STORAGE_KEYS.STATE, state);\n this.storage.set(STORAGE_KEYS.NONCE, nonce);\n\n const params: Record = {\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n state,\n nonce,\n prompt: options.prompt,\n login_hint: options.loginHint,\n };\n\n // Add PKCE if enabled\n if (this.config.usePkce) {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n this.storage.set(STORAGE_KEYS.CODE_VERIFIER, codeVerifier);\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Use signup endpoint if requested\n const endpoint = options.signup\n ? discovery.authorization_endpoint.replace('/authorize', '/authorize/signup')\n : discovery.authorization_endpoint;\n\n const authUrl = buildUrl(endpoint, params);\n window.location.href = authUrl;\n }\n\n /**\n * Alias for login({ signup: true })\n */\n async signup(options: Omit = {}): Promise {\n return this.login({ ...options, signup: true });\n }\n\n /**\n * Handle callback from authorization server\n */\n async handleCallback(url?: string): Promise {\n const callbackUrl = url ?? window.location.href;\n const params = parseUrlParams(callbackUrl);\n\n // Check for errors\n if (params.error) {\n return {\n success: false,\n error: params.error,\n errorDescription: params.error_description,\n };\n }\n\n // Validate state\n const storedState = this.storage.get(STORAGE_KEYS.STATE);\n if (!storedState || storedState !== params.state) {\n return {\n success: false,\n error: 'invalid_state',\n errorDescription: 'State mismatch - possible CSRF attack',\n };\n }\n\n // Exchange code for tokens\n if (!params.code) {\n return {\n success: false,\n error: 'missing_code',\n errorDescription: 'No authorization code received',\n };\n }\n\n try {\n const tokens = await this.exchangeCode(params.code);\n \n // Validate nonce in ID token\n if (tokens.id_token) {\n const payload = decodeJwtPayload<{ nonce?: string }>(tokens.id_token);\n const storedNonce = this.storage.get(STORAGE_KEYS.NONCE);\n if (payload?.nonce !== storedNonce) {\n return {\n success: false,\n error: 'invalid_nonce',\n errorDescription: 'Nonce mismatch - possible replay attack',\n };\n }\n }\n\n // Store tokens\n this.storeTokens(tokens);\n\n // Clear temporary storage\n this.storage.remove(STORAGE_KEYS.STATE);\n this.storage.remove(STORAGE_KEYS.NONCE);\n this.storage.remove(STORAGE_KEYS.CODE_VERIFIER);\n\n // Get user info\n const user = await this.fetchUserInfo(tokens.access_token);\n\n // Setup auto-refresh\n if (this.config.autoRefresh && tokens.refresh_token) {\n this.setupAutoRefresh();\n }\n\n // Notify listeners\n this.notifyListeners();\n\n return {\n success: true,\n user: user || undefined,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token,\n };\n } catch (error) {\n return {\n success: false,\n error: 'token_exchange_failed',\n errorDescription: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCode(code: string): Promise {\n const discovery = await this.getDiscovery();\n\n const body: Record = {\n grant_type: 'authorization_code',\n client_id: this.config.clientId,\n code,\n redirect_uri: this.config.redirectUri,\n };\n\n // Add PKCE code verifier\n if (this.config.usePkce) {\n const codeVerifier = this.storage.get(STORAGE_KEYS.CODE_VERIFIER);\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n }\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error_description || error.error || 'Token exchange failed');\n }\n\n return response.json();\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshToken(): Promise {\n const refreshToken = this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);\n if (!refreshToken) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n refresh_token: refreshToken,\n }),\n });\n\n if (!response.ok) {\n // Refresh failed - clear tokens\n this.clearTokens();\n this.notifyListeners();\n return null;\n }\n\n const tokens: TokenResponse = await response.json();\n this.storeTokens(tokens);\n this.notifyListeners();\n\n return tokens;\n }\n\n /**\n * Logout - end session\n */\n async logout(options: LogoutOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n\n // Clear local tokens first\n this.clearTokens();\n this.notifyListeners();\n\n // Redirect to end session endpoint if available\n if (discovery.end_session_endpoint) {\n const params: Record = {\n post_logout_redirect_uri: options.returnTo ?? this.config.postLogoutRedirectUri,\n id_token_hint: options.idTokenHint ?? idToken ?? undefined,\n client_id: this.config.clientId,\n };\n\n const logoutUrl = buildUrl(discovery.end_session_endpoint, params);\n window.location.href = logoutUrl;\n }\n }\n\n /**\n * Get current access token (refreshes if needed)\n */\n async getAccessToken(): Promise {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n \n if (!accessToken) return null;\n\n // Check if token needs refresh\n if (isTokenExpired(accessToken, this.config.refreshThreshold)) {\n const tokens = await this.refreshToken();\n return tokens?.access_token ?? null;\n }\n\n return accessToken;\n }\n\n /**\n * Get current user from stored ID token\n */\n getUser(): User | null {\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n if (!idToken) return null;\n\n return decodeJwtPayload(idToken);\n }\n\n /**\n * Fetch user info from userinfo endpoint\n */\n async fetchUserInfo(accessToken?: string): Promise {\n const token = accessToken ?? await this.getAccessToken();\n if (!token) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.userinfo_endpoint, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) return null;\n\n const user: User = await response.json();\n this.storage.set(STORAGE_KEYS.USER, JSON.stringify(user));\n return user;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n if (!accessToken) return false;\n\n // Consider authenticated if token exists and not expired\n return !isTokenExpired(accessToken);\n }\n\n /**\n * Get current auth state\n */\n getAuthState(): AuthState {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n const user = this.getUser();\n\n return {\n isAuthenticated: this.isAuthenticated(),\n isLoading: false,\n user,\n accessToken,\n idToken,\n error: null,\n };\n }\n\n /**\n * Subscribe to auth state changes\n */\n subscribe(listener: (state: AuthState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Store tokens in storage\n */\n private storeTokens(tokens: TokenResponse): void {\n this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, tokens.access_token);\n \n if (tokens.refresh_token) {\n this.storage.set(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh_token);\n }\n \n if (tokens.id_token) {\n this.storage.set(STORAGE_KEYS.ID_TOKEN, tokens.id_token);\n }\n\n // Store expiry time\n const expiresAt = Date.now() + (tokens.expires_in * 1000);\n this.storage.set(STORAGE_KEYS.EXPIRES_AT, expiresAt.toString());\n }\n\n /**\n * Clear all stored tokens\n */\n private clearTokens(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n this.storage.clear();\n }\n\n /**\n * Setup auto-refresh timer\n */\n private setupAutoRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n const expiresAt = this.storage.get(STORAGE_KEYS.EXPIRES_AT);\n if (!expiresAt) return;\n\n const expiresAtMs = parseInt(expiresAt, 10);\n const refreshAt = expiresAtMs - (this.config.refreshThreshold * 1000);\n const delay = refreshAt - Date.now();\n\n if (delay > 0) {\n this.refreshTimer = setTimeout(async () => {\n await this.refreshToken();\n this.setupAutoRefresh();\n }, delay);\n }\n }\n\n /**\n * Notify all listeners of state change\n */\n private notifyListeners(): void {\n const state = this.getAuthState();\n this.listeners.forEach(listener => listener(state));\n }\n}\n\n/**\n * Create a new Stuffle IAM client instance\n */\nexport function createStuffleIAMClient(config: StuffleIAMConfig): StuffleIAMClient {\n return new StuffleIAMClient(config);\n}\n"],"mappings":"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","names":[]} \ No newline at end of file +{"version":3,"sources":["../src/react/index.tsx","../src/utils.ts","../src/storage.ts","../src/client.ts"],"sourcesContent":["/**\n * React bindings for Stuffle IAM SDK\n * \n * @example\n * ```tsx\n * import { StuffleIAMProvider, useAuth } from '@stuffle/iam-sdk/react';\n * \n * function App() {\n * return (\n * \n * \n * \n * );\n * }\n * \n * function MyApp() {\n * const { isAuthenticated, user, login, logout } = useAuth();\n * \n * if (!isAuthenticated) {\n * return ;\n * }\n * \n * return (\n *

\n *

Welcome, {user?.name}

\n * \n *
\n * );\n * }\n * ```\n */\n\nimport {\n createContext,\n useContext,\n useState,\n useEffect,\n useCallback,\n useMemo,\n type ReactNode,\n} from 'react';\nimport {\n StuffleIAMClient,\n createStuffleIAMClient,\n type StuffleIAMConfig,\n type AuthState,\n type User,\n type LoginOptions,\n type LogoutOptions,\n type CallbackResult,\n} from '../index';\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface StuffleIAMContextValue {\n client: StuffleIAMClient;\n isAuthenticated: boolean;\n isLoading: boolean;\n user: User | null;\n accessToken: string | null;\n error: Error | null;\n login: (options?: LoginOptions) => Promise;\n signup: (options?: Omit) => Promise;\n logout: (options?: LogoutOptions) => Promise;\n handleCallback: (url?: string) => Promise;\n getAccessToken: () => Promise;\n}\n\nconst StuffleIAMContext = createContext(null);\n\n// =============================================================================\n// Provider\n// =============================================================================\n\nexport interface StuffleIAMProviderProps extends StuffleIAMConfig {\n children: ReactNode;\n /** Called after successful login callback */\n onLoginSuccess?: (result: CallbackResult) => void;\n /** Called on login error */\n onLoginError?: (error: Error) => void;\n /** Auto-handle callback on mount if URL has code/error */\n autoHandleCallback?: boolean;\n}\n\nexport function StuffleIAMProvider({\n children,\n onLoginSuccess,\n onLoginError,\n autoHandleCallback = true,\n ...config\n}: StuffleIAMProviderProps) {\n const [client] = useState(() => createStuffleIAMClient(config));\n const [state, setState] = useState(() => ({\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n idToken: null,\n error: null,\n }));\n\n // Subscribe to auth state changes\n useEffect(() => {\n const unsubscribe = client.subscribe(setState);\n\n // Initialize state\n const initialState = client.getAuthState();\n setState({ ...initialState, isLoading: false });\n\n return unsubscribe;\n }, [client]);\n\n // Auto-handle callback\n useEffect(() => {\n if (!autoHandleCallback) return;\n\n const url = window.location.href;\n const hasCode = url.includes('code=');\n const hasError = url.includes('error=');\n\n if (hasCode || hasError) {\n setState(prev => ({ ...prev, isLoading: true }));\n\n client.handleCallback(url).then(result => {\n setState(prev => ({ ...prev, isLoading: false }));\n\n if (result.success) {\n onLoginSuccess?.(result);\n // Clean URL\n window.history.replaceState({}, '', window.location.pathname);\n } else {\n const error = new Error(result.errorDescription || result.error || 'Login failed');\n onLoginError?.(error);\n setState(prev => ({ ...prev, error }));\n }\n });\n }\n }, [client, autoHandleCallback, onLoginSuccess, onLoginError]);\n\n // Memoized methods\n const login = useCallback(\n (options?: LoginOptions) => client.login(options),\n [client]\n );\n\n const signup = useCallback(\n (options?: Omit) => client.signup(options),\n [client]\n );\n\n const logout = useCallback(\n (options?: LogoutOptions) => client.logout(options),\n [client]\n );\n\n const handleCallback = useCallback(\n (url?: string) => client.handleCallback(url),\n [client]\n );\n\n const getAccessToken = useCallback(\n () => client.getAccessToken(),\n [client]\n );\n\n const value = useMemo(\n () => ({\n client,\n isAuthenticated: state.isAuthenticated,\n isLoading: state.isLoading,\n user: state.user,\n accessToken: state.accessToken,\n error: state.error,\n login,\n signup,\n logout,\n handleCallback,\n getAccessToken,\n }),\n [client, state, login, signup, logout, handleCallback, getAccessToken]\n );\n\n return (\n \n {children}\n \n );\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * Hook to access auth state and methods\n */\nexport function useAuth() {\n const context = useContext(StuffleIAMContext);\n if (!context) {\n throw new Error('useAuth must be used within a StuffleIAMProvider');\n }\n return context;\n}\n\n/**\n * Hook to get current user\n */\nexport function useUser(): User | null {\n const { user } = useAuth();\n return user;\n}\n\n/**\n * Hook to check if user is authenticated\n */\nexport function useIsAuthenticated(): boolean {\n const { isAuthenticated } = useAuth();\n return isAuthenticated;\n}\n\n/**\n * Hook to get access token (refreshes if needed)\n */\nexport function useAccessToken(): () => Promise {\n const { getAccessToken } = useAuth();\n return getAccessToken;\n}\n\n/**\n * Hook to check if user has specific role(s)\n */\nexport function useHasRole(roles: string | string[]): boolean {\n const { user } = useAuth();\n if (!user?.roles) return false;\n\n const requiredRoles = Array.isArray(roles) ? roles : [roles];\n return requiredRoles.some(role => user.roles?.includes(role));\n}\n\n/**\n * Higher-order component for protected routes\n */\nexport function withAuth

(\n WrappedComponent: React.ComponentType

,\n options?: {\n /** Component to show while loading */\n LoadingComponent?: React.ComponentType;\n /** Component to show if not authenticated */\n UnauthorizedComponent?: React.ComponentType;\n /** Required roles */\n roles?: string[];\n }\n) {\n return function AuthenticatedComponent(props: P) {\n const { isAuthenticated, isLoading, user } = useAuth();\n\n const LoadingComp = options?.LoadingComponent;\n const UnauthorizedComp = options?.UnauthorizedComponent;\n\n if (isLoading) {\n return LoadingComp ? : null;\n }\n\n if (!isAuthenticated) {\n return UnauthorizedComp ? : null;\n }\n\n if (options?.roles && options.roles.length > 0) {\n const hasRequiredRole = options.roles.some(role => user?.roles?.includes(role));\n if (!hasRequiredRole) {\n return UnauthorizedComp ? : null;\n }\n }\n\n return ;\n };\n}\n\n// Re-export types\nexport type { StuffleIAMConfig, AuthState, User, LoginOptions, LogoutOptions, CallbackResult };\n","/**\n * Utility functions for PKCE and crypto operations\n */\n\n/**\n * Generate a random string for state/nonce\n */\nexport function generateRandomString(length: number = 32): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generate PKCE code verifier (43-128 characters)\n */\nexport function generateCodeVerifier(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64UrlEncode(array);\n}\n\n/**\n * Generate PKCE code challenge from verifier\n */\nexport async function generateCodeChallenge(verifier: string): Promise {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n return base64UrlEncode(new Uint8Array(digest));\n}\n\n/**\n * Base64 URL encode (no padding, URL-safe characters)\n */\nexport function base64UrlEncode(buffer: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < buffer.length; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Decode JWT payload (without verification)\n */\nexport function decodeJwtPayload>(token: string): T | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n \n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded) as T;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string, thresholdSeconds: number = 0): boolean {\n const payload = decodeJwtPayload<{ exp?: number }>(token);\n if (!payload?.exp) return true;\n \n const now = Math.floor(Date.now() / 1000);\n return payload.exp - thresholdSeconds <= now;\n}\n\n/**\n * Parse URL hash or query parameters\n */\nexport function parseUrlParams(url: string): Record {\n const params: Record = {};\n \n // Check hash first (implicit flow), then query (code flow)\n const hashIndex = url.indexOf('#');\n const queryIndex = url.indexOf('?');\n \n let paramString = '';\n if (hashIndex !== -1) {\n paramString = url.substring(hashIndex + 1);\n } else if (queryIndex !== -1) {\n paramString = url.substring(queryIndex + 1);\n }\n \n if (!paramString) return params;\n \n const searchParams = new URLSearchParams(paramString);\n searchParams.forEach((value, key) => {\n params[key] = value;\n });\n \n return params;\n}\n\n/**\n * Build URL with query parameters\n */\nexport function buildUrl(base: string, params: Record): string {\n const url = new URL(base);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, value);\n }\n });\n return url.toString();\n}\n","/**\n * Token storage abstraction\n */\n\nexport interface TokenStorage {\n get(key: string): string | null;\n set(key: string, value: string): void;\n remove(key: string): void;\n clear(): void;\n}\n\nconst STORAGE_PREFIX = 'stuffle_iam_';\n\n/**\n * LocalStorage implementation\n */\nexport class LocalStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return localStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('LocalStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n localStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(localStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => localStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * SessionStorage implementation\n */\nexport class SessionStorageAdapter implements TokenStorage {\n get(key: string): string | null {\n try {\n return sessionStorage.getItem(STORAGE_PREFIX + key);\n } catch {\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n sessionStorage.setItem(STORAGE_PREFIX + key, value);\n } catch {\n console.warn('SessionStorage not available');\n }\n }\n\n remove(key: string): void {\n try {\n sessionStorage.removeItem(STORAGE_PREFIX + key);\n } catch {\n // Ignore\n }\n }\n\n clear(): void {\n try {\n Object.keys(sessionStorage)\n .filter(k => k.startsWith(STORAGE_PREFIX))\n .forEach(k => sessionStorage.removeItem(k));\n } catch {\n // Ignore\n }\n }\n}\n\n/**\n * In-memory storage (for SSR or when storage is unavailable)\n */\nexport class MemoryStorageAdapter implements TokenStorage {\n private store = new Map();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n\n/**\n * Get storage adapter based on type\n */\nexport function getStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n switch (type) {\n case 'localStorage':\n return new LocalStorageAdapter();\n case 'sessionStorage':\n return new SessionStorageAdapter();\n case 'memory':\n return new MemoryStorageAdapter();\n default:\n return new SessionStorageAdapter();\n }\n}\n","/**\n * Stuffle IAM Client\n * \n * OIDC/OAuth2 client for browser-based applications.\n * Supports authorization code flow with PKCE.\n */\n\nimport type {\n StuffleIAMConfig,\n TokenResponse,\n User,\n AuthState,\n LoginOptions,\n LogoutOptions,\n CallbackResult,\n OIDCDiscovery,\n} from './types';\nimport {\n generateRandomString,\n generateCodeVerifier,\n generateCodeChallenge,\n decodeJwtPayload,\n isTokenExpired,\n parseUrlParams,\n buildUrl,\n} from './utils';\nimport { getStorage, type TokenStorage } from './storage';\n\nconst STORAGE_KEYS = {\n ACCESS_TOKEN: 'access_token',\n REFRESH_TOKEN: 'refresh_token',\n ID_TOKEN: 'id_token',\n CODE_VERIFIER: 'code_verifier',\n STATE: 'state',\n NONCE: 'nonce',\n USER: 'user',\n EXPIRES_AT: 'expires_at',\n};\n\nexport class StuffleIAMClient {\n private config: Required;\n private storage: TokenStorage;\n private discovery: OIDCDiscovery | null = null;\n private refreshTimer: ReturnType | null = null;\n private listeners: Set<(state: AuthState) => void> = new Set();\n\n constructor(config: StuffleIAMConfig) {\n this.config = {\n issuer: config.issuer.replace(/\\/$/, ''), // Remove trailing slash\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n scopes: config.scopes ?? ['openid', 'profile', 'email'],\n postLogoutRedirectUri: config.postLogoutRedirectUri ?? config.redirectUri,\n usePkce: config.usePkce ?? true,\n storage: config.storage ?? 'sessionStorage',\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? 60,\n };\n\n this.storage = getStorage(this.config.storage);\n }\n\n /**\n * Fetch OIDC discovery document\n */\n async getDiscovery(): Promise {\n if (this.discovery) return this.discovery;\n\n const response = await fetch(\n `${this.config.issuer}/.well-known/openid-configuration`\n );\n\n if (!response.ok) {\n throw new Error(`Failed to fetch OIDC discovery: ${response.status}`);\n }\n\n this.discovery = await response.json();\n return this.discovery!;\n }\n\n /**\n * Start login flow - redirects to authorization endpoint\n */\n async login(options: LoginOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n\n const state = options.state ?? generateRandomString();\n const nonce = options.nonce ?? generateRandomString();\n const scopes = [...this.config.scopes, ...(options.scopes ?? [])];\n\n // Store state and nonce for callback validation\n this.storage.set(STORAGE_KEYS.STATE, state);\n this.storage.set(STORAGE_KEYS.NONCE, nonce);\n\n const params: Record = {\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: scopes.join(' '),\n state,\n nonce,\n prompt: options.prompt,\n login_hint: options.loginHint,\n };\n\n // Add PKCE if enabled\n if (this.config.usePkce) {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = await generateCodeChallenge(codeVerifier);\n \n this.storage.set(STORAGE_KEYS.CODE_VERIFIER, codeVerifier);\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Use signup endpoint if requested\n const endpoint = options.signup\n ? discovery.authorization_endpoint.replace('/authorize', '/authorize/signup')\n : discovery.authorization_endpoint;\n\n const authUrl = buildUrl(endpoint, params);\n window.location.href = authUrl;\n }\n\n /**\n * Alias for login({ signup: true })\n */\n async signup(options: Omit = {}): Promise {\n return this.login({ ...options, signup: true });\n }\n\n /**\n * Handle callback from authorization server\n */\n async handleCallback(url?: string): Promise {\n const callbackUrl = url ?? window.location.href;\n const params = parseUrlParams(callbackUrl);\n\n // Check for errors\n if (params.error) {\n return {\n success: false,\n error: params.error,\n errorDescription: params.error_description,\n };\n }\n\n // Validate state\n const storedState = this.storage.get(STORAGE_KEYS.STATE);\n if (!storedState || storedState !== params.state) {\n return {\n success: false,\n error: 'invalid_state',\n errorDescription: 'State mismatch - possible CSRF attack',\n };\n }\n\n // Exchange code for tokens\n if (!params.code) {\n return {\n success: false,\n error: 'missing_code',\n errorDescription: 'No authorization code received',\n };\n }\n\n try {\n const tokens = await this.exchangeCode(params.code);\n \n // Validate nonce in ID token\n if (tokens.id_token) {\n const payload = decodeJwtPayload<{ nonce?: string }>(tokens.id_token);\n const storedNonce = this.storage.get(STORAGE_KEYS.NONCE);\n if (payload?.nonce !== storedNonce) {\n return {\n success: false,\n error: 'invalid_nonce',\n errorDescription: 'Nonce mismatch - possible replay attack',\n };\n }\n }\n\n // Store tokens\n this.storeTokens(tokens);\n\n // Clear temporary storage\n this.storage.remove(STORAGE_KEYS.STATE);\n this.storage.remove(STORAGE_KEYS.NONCE);\n this.storage.remove(STORAGE_KEYS.CODE_VERIFIER);\n\n // Get user info\n const user = await this.fetchUserInfo(tokens.access_token);\n\n // Setup auto-refresh\n if (this.config.autoRefresh && tokens.refresh_token) {\n this.setupAutoRefresh();\n }\n\n // Notify listeners\n this.notifyListeners();\n\n return {\n success: true,\n user: user || undefined,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token,\n };\n } catch (error) {\n return {\n success: false,\n error: 'token_exchange_failed',\n errorDescription: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCode(code: string): Promise {\n const discovery = await this.getDiscovery();\n\n const body: Record = {\n grant_type: 'authorization_code',\n client_id: this.config.clientId,\n code,\n redirect_uri: this.config.redirectUri,\n };\n\n // Add PKCE code verifier\n if (this.config.usePkce) {\n const codeVerifier = this.storage.get(STORAGE_KEYS.CODE_VERIFIER);\n if (codeVerifier) {\n body.code_verifier = codeVerifier;\n }\n }\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error_description || error.error || 'Token exchange failed');\n }\n\n return response.json();\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshToken(): Promise {\n const refreshToken = this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);\n if (!refreshToken) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.token_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n refresh_token: refreshToken,\n }),\n });\n\n if (!response.ok) {\n // Refresh failed - clear tokens\n this.clearTokens();\n this.notifyListeners();\n return null;\n }\n\n const tokens: TokenResponse = await response.json();\n this.storeTokens(tokens);\n this.notifyListeners();\n\n return tokens;\n }\n\n /**\n * Logout - end session\n */\n async logout(options: LogoutOptions = {}): Promise {\n const discovery = await this.getDiscovery();\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n\n // Clear local tokens first\n this.clearTokens();\n this.notifyListeners();\n\n // Redirect to end session endpoint if available\n if (discovery.end_session_endpoint) {\n const params: Record = {\n post_logout_redirect_uri: options.returnTo ?? this.config.postLogoutRedirectUri,\n id_token_hint: options.idTokenHint ?? idToken ?? undefined,\n client_id: this.config.clientId,\n };\n\n const logoutUrl = buildUrl(discovery.end_session_endpoint, params);\n window.location.href = logoutUrl;\n }\n }\n\n /**\n * Get current access token (refreshes if needed)\n */\n async getAccessToken(): Promise {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n \n if (!accessToken) return null;\n\n // Check if token needs refresh\n if (isTokenExpired(accessToken, this.config.refreshThreshold)) {\n const tokens = await this.refreshToken();\n return tokens?.access_token ?? null;\n }\n\n return accessToken;\n }\n\n /**\n * Get current user from stored ID token\n */\n getUser(): User | null {\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n if (!idToken) return null;\n\n return decodeJwtPayload(idToken);\n }\n\n /**\n * Fetch user info from userinfo endpoint\n */\n async fetchUserInfo(accessToken?: string): Promise {\n const token = accessToken ?? await this.getAccessToken();\n if (!token) return null;\n\n const discovery = await this.getDiscovery();\n\n const response = await fetch(discovery.userinfo_endpoint, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) return null;\n\n const user: User = await response.json();\n this.storage.set(STORAGE_KEYS.USER, JSON.stringify(user));\n return user;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n if (!accessToken) return false;\n\n // Consider authenticated if token exists and not expired\n return !isTokenExpired(accessToken);\n }\n\n /**\n * Get current auth state\n */\n getAuthState(): AuthState {\n const accessToken = this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);\n const idToken = this.storage.get(STORAGE_KEYS.ID_TOKEN);\n const user = this.getUser();\n\n return {\n isAuthenticated: this.isAuthenticated(),\n isLoading: false,\n user,\n accessToken,\n idToken,\n error: null,\n };\n }\n\n /**\n * Subscribe to auth state changes\n */\n subscribe(listener: (state: AuthState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Store tokens in storage\n */\n private storeTokens(tokens: TokenResponse): void {\n this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, tokens.access_token);\n \n if (tokens.refresh_token) {\n this.storage.set(STORAGE_KEYS.REFRESH_TOKEN, tokens.refresh_token);\n }\n \n if (tokens.id_token) {\n this.storage.set(STORAGE_KEYS.ID_TOKEN, tokens.id_token);\n }\n\n // Store expiry time\n const expiresAt = Date.now() + (tokens.expires_in * 1000);\n this.storage.set(STORAGE_KEYS.EXPIRES_AT, expiresAt.toString());\n }\n\n /**\n * Clear all stored tokens\n */\n private clearTokens(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n this.storage.clear();\n }\n\n /**\n * Setup auto-refresh timer\n */\n private setupAutoRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n const expiresAt = this.storage.get(STORAGE_KEYS.EXPIRES_AT);\n if (!expiresAt) return;\n\n const expiresAtMs = parseInt(expiresAt, 10);\n const refreshAt = expiresAtMs - (this.config.refreshThreshold * 1000);\n const delay = refreshAt - Date.now();\n\n if (delay > 0) {\n this.refreshTimer = setTimeout(async () => {\n await this.refreshToken();\n this.setupAutoRefresh();\n }, delay);\n }\n }\n\n /**\n * Notify all listeners of state change\n */\n private notifyListeners(): void {\n const state = this.getAuthState();\n this.listeners.forEach(listener => listener(state));\n }\n}\n\n/**\n * Create a new Stuffle IAM client instance\n */\nexport function createStuffleIAMClient(config: StuffleIAMConfig): StuffleIAMClient {\n return new StuffleIAMClient(config);\n}\n"],"mappings":"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","names":[]} \ No newline at end of file diff --git a/package.json b/package.json index 1b3d2e9..33c6b0c 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,14 @@ "types": "dist/index.d.ts", "exports": { ".": { + "types": "./dist/index.d.ts", "import": "./dist/index.mjs", - "require": "./dist/index.js", - "types": "./dist/index.d.ts" + "require": "./dist/index.js" }, "./react": { + "types": "./dist/react.d.ts", "import": "./dist/react.mjs", - "require": "./dist/react.js", - "types": "./dist/react.d.ts" + "require": "./dist/react.js" } }, "files": [