@lastshotlabs/snapshot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1598 -0
- package/dist/cli.js +4529 -0
- package/dist/index.cjs +1135 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +396 -0
- package/dist/index.d.ts +396 -0
- package/dist/index.js +1106 -0
- package/dist/index.js.map +1 -0
- package/dist/vite.cjs +1186 -0
- package/dist/vite.d.cts +18 -0
- package/dist/vite.d.ts +18 -0
- package/dist/vite.js +1174 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/create-snapshot.tsx","../src/api/error.ts","../src/auth/csrf.ts","../src/api/client.ts","../src/auth/storage.ts","../src/auth/hooks.ts","../src/types.ts","../src/auth/mfa-hooks.ts","../src/auth/account-hooks.ts","../src/auth/oauth-hooks.ts","../src/auth/webauthn-hooks.ts","../src/ws/manager.ts","../src/ws/atom.ts","../src/ws/hook.ts","../src/theme/hook.ts","../src/routing/loaders.ts","../src/providers/QueryProvider.tsx"],"sourcesContent":["import { QueryClient } from '@tanstack/react-query'\r\nimport { atom, useAtom, useAtomValue } from 'jotai'\r\nimport type { ReactNode } from 'react'\r\nimport { ApiClient } from './api/client'\r\nimport { createTokenStorage } from './auth/storage'\r\nimport { createAuthHooks } from './auth/hooks'\r\nimport { createMfaHooks } from './auth/mfa-hooks'\r\nimport { createAccountHooks } from './auth/account-hooks'\r\nimport { createOAuthHooks } from './auth/oauth-hooks'\r\nimport { createWebAuthnHooks } from './auth/webauthn-hooks'\r\nimport { isMfaChallenge } from './types'\r\nimport type { MfaChallenge } from './types'\r\nimport { WebSocketManager } from './ws/manager'\r\nimport { wsManagerAtom } from './ws/atom'\r\nimport { createWsHooks } from './ws/hook'\r\nimport { useTheme } from './theme/hook'\r\nimport { createLoaders } from './routing/loaders'\r\nimport { QueryProviderInner } from './providers/QueryProvider'\r\nimport type { SnapshotConfig, SnapshotInstance } from './types'\r\n\r\nexport function createSnapshot<TWSEvents extends Record<string, unknown> = Record<string, unknown>>(\r\n config: SnapshotConfig,\r\n): SnapshotInstance<TWSEvents> {\r\n // ── API client ──────────────────────────────────────────────────────────────\r\n const api = new ApiClient({\r\n apiUrl: config.apiUrl,\r\n auth: config.auth,\r\n bearerToken: config.bearerToken,\r\n onUnauthenticated: config.onUnauthenticated,\r\n onForbidden: config.onForbidden,\r\n onMfaSetupRequired: config.mfaSetupPath\r\n ? () => { window.location.href = config.mfaSetupPath! }\r\n : undefined,\r\n })\r\n\r\n // ── Token storage ───────────────────────────────────────────────────────────\r\n const tokenStorage = createTokenStorage({\r\n auth: config.auth,\r\n tokenStorage: config.tokenStorage,\r\n tokenKey: config.tokenKey,\r\n })\r\n api.setStorage(tokenStorage)\r\n\r\n // ── Query client (stable singleton) ────────────────────────────────────────\r\n const queryClient = new QueryClient({\r\n defaultOptions: {\r\n queries: {\r\n staleTime: config.staleTime ?? 5 * 60 * 1000,\r\n gcTime: config.gcTime ?? 10 * 60 * 1000,\r\n retry: config.retry ?? 1,\r\n },\r\n },\r\n })\r\n\r\n // ── WebSocket manager (created once if ws config present) ──────────────────\r\n let wsManager: WebSocketManager<TWSEvents> | null = null\r\n if (config.ws) {\r\n wsManager = new WebSocketManager<TWSEvents>(config.ws)\r\n }\r\n\r\n // ── Per-instance pending MFA challenge atom ──────────────────────────────────\r\n const pendingMfaChallengeAtom = atom<MfaChallenge | null>(null)\r\n\r\n function usePendingMfaChallenge(): MfaChallenge | null {\r\n return useAtomValue(pendingMfaChallengeAtom)\r\n }\r\n\r\n // ── WS hooks ────────────────────────────────────────────────────────────────\r\n const { useWebSocketManager, useSocket, useRoom, useRoomEvent } = createWsHooks<TWSEvents>()\r\n\r\n // Hook that initializes the atom on first render and returns the manager\r\n function useWebSocketManagerWithInit(): WebSocketManager<TWSEvents> | null {\r\n const [current, setManager] = useAtom(wsManagerAtom)\r\n // Initialize atom on first use\r\n if (wsManager !== null && current === null) {\r\n setManager(wsManager)\r\n }\r\n return current as WebSocketManager<TWSEvents> | null\r\n }\r\n\r\n // ── Auth hooks ──────────────────────────────────────────────────────────────\r\n const { useUser, useLogin, useLogout, useRegister, useForgotPassword } = createAuthHooks({\r\n api,\r\n storage: tokenStorage,\r\n config,\r\n pendingMfaChallengeAtom,\r\n onLoginSuccess: config.ws?.reconnectOnLogin !== false\r\n ? () => wsManager?.reconnect()\r\n : undefined,\r\n })\r\n\r\n // ── MFA hooks ──────────────────────────────────────────────────────────────\r\n const mfaHooks = createMfaHooks({\r\n api,\r\n storage: tokenStorage,\r\n config,\r\n pendingMfaChallengeAtom,\r\n onLoginSuccess: config.ws?.reconnectOnLogin !== false\r\n ? () => wsManager?.reconnect()\r\n : undefined,\r\n })\r\n\r\n // ── Account hooks ──────────────────────────────────────────────────────────\r\n const accountHooks = createAccountHooks({\r\n api,\r\n storage: tokenStorage,\r\n config,\r\n onUnauthenticated: config.onUnauthenticated,\r\n queryClient,\r\n })\r\n\r\n // ── OAuth hooks ─────────────────────────────────────────────────────────────\r\n const oauthHooks = createOAuthHooks({\r\n api,\r\n storage: tokenStorage,\r\n config,\r\n onLoginSuccess: config.ws?.reconnectOnLogin !== false\r\n ? () => wsManager?.reconnect()\r\n : undefined,\r\n })\r\n\r\n // ── WebAuthn hooks ──────────────────────────────────────────────────────────\r\n const webAuthnHooks = createWebAuthnHooks({\r\n api,\r\n storage: tokenStorage,\r\n config,\r\n pendingMfaChallengeAtom,\r\n onLoginSuccess: config.ws?.reconnectOnLogin !== false\r\n ? () => wsManager?.reconnect()\r\n : undefined,\r\n })\r\n\r\n // ── Routing ─────────────────────────────────────────────────────────────────\r\n const { protectedBeforeLoad, guestBeforeLoad } = createLoaders(config, api)\r\n\r\n // ── QueryProvider pre-bound to this instance's queryClient ─────────────────\r\n function QueryProvider({ children }: { children: ReactNode }) {\r\n return <QueryProviderInner client={queryClient}>{children}</QueryProviderInner>\r\n }\r\n\r\n return {\r\n // High-level hooks\r\n useUser,\r\n useLogin,\r\n useLogout,\r\n useRegister,\r\n useForgotPassword,\r\n useSocket,\r\n useRoom,\r\n useRoomEvent,\r\n useTheme,\r\n\r\n // MFA\r\n usePendingMfaChallenge,\r\n ...mfaHooks,\r\n isMfaChallenge,\r\n\r\n // Account\r\n ...accountHooks,\r\n\r\n // OAuth\r\n ...oauthHooks,\r\n\r\n // WebAuthn\r\n ...webAuthnHooks,\r\n\r\n // Primitives\r\n api,\r\n tokenStorage,\r\n queryClient,\r\n useWebSocketManager: useWebSocketManagerWithInit,\r\n\r\n // Routing\r\n protectedBeforeLoad,\r\n guestBeforeLoad,\r\n\r\n // Components\r\n QueryProvider,\r\n }\r\n}\r\n","function extractMessage(body: unknown): string | undefined {\n if (body && typeof body === 'object') {\n const b = body as Record<string, unknown>\n if (typeof b.message === 'string') return b.message\n if (typeof b.error === 'string') return b.error\n }\n}\n\nexport class ApiError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: unknown,\n message?: string,\n ) {\n super(message ?? extractMessage(body) ?? `HTTP ${status}`)\n this.name = 'ApiError'\n // Maintain proper prototype chain in transpiled environments\n Object.setPrototypeOf(this, ApiError.prototype)\n }\n}\n","const CSRF_COOKIE_NAME = 'csrf_token'\nconst MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\nexport function getCsrfToken(): string | null {\n if (typeof document === 'undefined') return null\n const match = document.cookie\n .split('; ')\n .find(row => row.startsWith(`${CSRF_COOKIE_NAME}=`))\n return match ? decodeURIComponent(match.split('=')[1]!) : null\n}\n\nexport function isMutatingMethod(method: string): boolean {\n return MUTATING_METHODS.has(method.toUpperCase())\n}\n","import { ApiError } from './error'\r\nimport { getCsrfToken, isMutatingMethod } from '../auth/csrf'\r\nimport type { RequestOptions } from '../types'\r\nimport type { TokenStorage } from '../auth/storage'\r\nimport type { SnapshotConfig } from '../types'\r\n\r\nexport class ApiClient {\r\n private readonly baseUrl: string\r\n private readonly authMode: 'cookie' | 'token'\r\n private readonly bearerToken: string | undefined\r\n private storage: TokenStorage | null = null\r\n private onUnauthenticated: (() => void) | undefined\r\n private onForbidden: (() => void) | undefined\r\n private onMfaSetupRequired: (() => void) | undefined\r\n\r\n constructor(config: Pick<SnapshotConfig, 'apiUrl' | 'auth' | 'bearerToken' | 'onUnauthenticated' | 'onForbidden'> & { onMfaSetupRequired?: () => void }) {\r\n this.baseUrl = config.apiUrl.replace(/\\/$/, '')\r\n this.authMode = config.auth ?? 'cookie'\r\n this.bearerToken = config.bearerToken\r\n this.onUnauthenticated = config.onUnauthenticated\r\n this.onForbidden = config.onForbidden\r\n this.onMfaSetupRequired = config.onMfaSetupRequired\r\n\r\n if (this.bearerToken && typeof window !== 'undefined') {\r\n console.warn(\r\n '[snapshot] bearerToken is a static API credential. ' +\r\n 'It should not be used in browser deployments. ' +\r\n 'See the snapshot security docs for the recommended cookie-auth model.'\r\n )\r\n }\r\n }\r\n\r\n setStorage(storage: TokenStorage) {\r\n this.storage = storage\r\n }\r\n\r\n private buildHeaders(method: string, overrides?: Record<string, string>): Record<string, string> {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...overrides,\r\n }\r\n\r\n // API-level bearer token (always sent, independent of user auth mode)\r\n if (this.bearerToken) {\r\n headers['Authorization'] = `Bearer ${this.bearerToken}`\r\n }\r\n\r\n if (this.authMode === 'cookie') {\r\n if (isMutatingMethod(method)) {\r\n const csrf = getCsrfToken()\r\n if (csrf) headers['x-csrf-token'] = csrf\r\n }\r\n return headers\r\n }\r\n\r\n const userToken = this.storage?.get()\r\n if (userToken) {\r\n headers['x-user-token'] = userToken\r\n }\r\n\r\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] !== 'production' && !this.bearerToken && !userToken) {\r\n console.warn(\r\n '[snapshot] No auth credentials attached to request. ' +\r\n 'Set bearerToken in createSnapshot config or ensure a user token is stored.',\r\n )\r\n }\r\n\r\n return headers\r\n }\r\n\r\n private async rawFetch(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<Response> {\r\n const url = `${this.baseUrl}${path}`\r\n const headers = this.buildHeaders(method, options?.headers)\r\n\r\n const init: RequestInit = { method, headers }\r\n if (this.authMode === 'cookie') init.credentials = 'include'\r\n if (body !== undefined) init.body = JSON.stringify(body)\r\n if (options?.signal) init.signal = options.signal\r\n\r\n return fetch(url, init)\r\n }\r\n\r\n private async handleResponse<T>(response: Response): Promise<T> {\r\n if (response.status === 403) {\r\n const body = await response.json().catch(() => null)\r\n if (body && typeof body === 'object' && 'code' in body && (body as Record<string, unknown>).code === 'MFA_SETUP_REQUIRED') {\r\n this.onMfaSetupRequired?.()\r\n } else {\r\n this.onForbidden?.()\r\n }\r\n throw new ApiError(403, body)\r\n }\r\n\r\n if (!response.ok) {\r\n const body = await response.json().catch(() => null)\r\n throw new ApiError(response.status, body)\r\n }\r\n\r\n // Handle empty responses (204 No Content etc.)\r\n const contentType = response.headers.get('content-type')\r\n if (!contentType?.includes('application/json')) {\r\n return undefined as T\r\n }\r\n\r\n return response.json() as Promise<T>\r\n }\r\n\r\n private async request<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n const response = await this.rawFetch(method, path, body, options)\r\n\r\n if (response.status === 401) {\r\n const refreshToken = this.storage?.getRefreshToken()\r\n\r\n if (refreshToken && path !== '/auth/refresh') {\r\n // Attempt token refresh using a raw fetch to avoid infinite loops\r\n try {\r\n const refreshResponse = await fetch(`${this.baseUrl}/auth/refresh`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include',\r\n })\r\n\r\n if (refreshResponse.ok) {\r\n const refreshData = await refreshResponse.json()\r\n this.storage?.set(refreshData.token)\r\n if (refreshData.refreshToken) {\r\n this.storage?.setRefreshToken(refreshData.refreshToken)\r\n }\r\n // Retry the original request once with the new token\r\n const retryResponse = await this.rawFetch(method, path, body, options)\r\n return this.handleResponse<T>(retryResponse)\r\n }\r\n } catch {\r\n // refresh failed — fall through to cleanup\r\n }\r\n }\r\n\r\n this.storage?.clear()\r\n this.storage?.clearRefreshToken()\r\n this.onUnauthenticated?.()\r\n const errBody = await response.json().catch(() => null)\r\n throw new ApiError(401, errBody)\r\n }\r\n\r\n return this.handleResponse<T>(response)\r\n }\r\n\r\n get<T>(path: string, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('GET', path, undefined, options)\r\n }\r\n\r\n post<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('POST', path, body, options)\r\n }\r\n\r\n put<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PUT', path, body, options)\r\n }\r\n\r\n patch<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PATCH', path, body, options)\r\n }\r\n\r\n delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('DELETE', path, body, options)\r\n }\r\n}\r\n","import type { SnapshotConfig } from '../types'\r\n\r\nexport interface TokenStorage {\r\n get: () => string | null\r\n set: (token: string) => void\r\n clear: () => void\r\n getRefreshToken: () => string | null\r\n setRefreshToken: (token: string) => void\r\n clearRefreshToken: () => void\r\n}\r\n\r\nfunction createLocalStorageStorage(key: string): TokenStorage {\r\n const refreshKey = `${key}-refresh`\r\n return {\r\n get: () => localStorage.getItem(key),\r\n set: (token) => localStorage.setItem(key, token),\r\n clear: () => localStorage.removeItem(key),\r\n getRefreshToken: () => localStorage.getItem(refreshKey),\r\n setRefreshToken: (token) => localStorage.setItem(refreshKey, token),\r\n clearRefreshToken: () => localStorage.removeItem(refreshKey),\r\n }\r\n}\r\n\r\nfunction createSessionStorageStorage(key: string): TokenStorage {\r\n const refreshKey = `${key}-refresh`\r\n return {\r\n get: () => sessionStorage.getItem(key),\r\n set: (token) => sessionStorage.setItem(key, token),\r\n clear: () => sessionStorage.removeItem(key),\r\n getRefreshToken: () => sessionStorage.getItem(refreshKey),\r\n setRefreshToken: (token) => sessionStorage.setItem(refreshKey, token),\r\n clearRefreshToken: () => sessionStorage.removeItem(refreshKey),\r\n }\r\n}\r\n\r\nfunction createMemoryStorage(): TokenStorage {\r\n let token: string | null = null\r\n let refreshValue: string | null = null\r\n return {\r\n get: () => token,\r\n set: (t) => { token = t },\r\n clear: () => { token = null },\r\n getRefreshToken: () => refreshValue,\r\n setRefreshToken: (t) => { refreshValue = t },\r\n clearRefreshToken: () => { refreshValue = null },\r\n }\r\n}\r\n\r\nfunction createNoopStorage(): TokenStorage {\r\n return {\r\n get: () => null,\r\n set: () => {},\r\n clear: () => {},\r\n getRefreshToken: () => null,\r\n setRefreshToken: () => {},\r\n clearRefreshToken: () => {},\r\n }\r\n}\r\n\r\nexport function createTokenStorage(config: Pick<SnapshotConfig, 'auth' | 'tokenStorage' | 'tokenKey'>): TokenStorage {\r\n if (config.auth === 'cookie') return createNoopStorage()\r\n\r\n const key = config.tokenKey ?? 'x-user-token'\r\n const type = config.tokenStorage ?? 'sessionStorage'\r\n\r\n switch (type) {\r\n case 'sessionStorage':\r\n return createSessionStorageStorage(key)\r\n case 'memory':\r\n return createMemoryStorage()\r\n case 'localStorage':\r\n default:\r\n return createLocalStorageStorage(key)\r\n }\r\n}\r\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\r\nimport { useNavigate } from '@tanstack/react-router'\r\nimport { useSetAtom } from 'jotai'\r\nimport type { WritableAtom } from 'jotai'\r\nimport type { ApiClient } from '../api/client'\r\nimport type { ApiError } from '../api/error'\r\nimport type { TokenStorage } from './storage'\r\nimport type {\r\n AuthUser,\r\n LoginBody,\r\n LoginVars,\r\n LoginResult,\r\n LoginResponse,\r\n LogoutVars,\r\n RegisterBody,\r\n RegisterVars,\r\n ForgotPasswordBody,\r\n MfaChallenge,\r\n SnapshotConfig,\r\n} from '../types'\r\nimport { isMfaChallenge } from '../types'\r\n\r\nconst AUTH_QUERY_KEY = ['auth', 'me'] as const\r\n\r\ninterface AuthHooksOptions {\r\n api: ApiClient\r\n storage: TokenStorage\r\n config: Pick<SnapshotConfig, 'auth' | 'staleTime' | 'onUnauthenticated' | 'loginPath' | 'homePath' | 'mfaPath'>\r\n pendingMfaChallengeAtom: WritableAtom<MfaChallenge | null, [MfaChallenge | null], void>\r\n onLoginSuccess?: () => void // called by createSnapshot to trigger WS reconnect\r\n}\r\n\r\nexport function createAuthHooks({ api, storage, config, pendingMfaChallengeAtom, onLoginSuccess }: AuthHooksOptions) {\r\n function useUser() {\r\n const { data: user = null, isLoading, isError } = useQuery<AuthUser | null, ApiError>({\r\n queryKey: AUTH_QUERY_KEY,\r\n queryFn: async () => {\r\n try {\r\n return await api.get<AuthUser>('/auth/me')\r\n } catch {\r\n return null\r\n }\r\n },\r\n staleTime: config.staleTime ?? 5 * 60 * 1000,\r\n retry: false,\r\n })\r\n return { user, isLoading, isError }\r\n }\r\n\r\n function useLogin() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n const setMfaChallenge = useSetAtom(pendingMfaChallengeAtom)\r\n return useMutation<LoginResult, ApiError, LoginVars>({\r\n mutationFn: async ({ redirectTo: _, ...body }) => {\r\n const res = await api.post<LoginResponse>('/auth/login', body)\r\n\r\n // MFA challenge — do NOT store token or fetch /auth/me\r\n if (res.mfaRequired) {\r\n return { mfaToken: res.mfaToken!, mfaMethods: res.mfaMethods ?? [] }\r\n }\r\n\r\n if (config.auth !== 'cookie') {\r\n if (res.token) {\r\n storage.set(res.token)\r\n }\r\n if (res.refreshToken) {\r\n storage.setRefreshToken(res.refreshToken)\r\n }\r\n }\r\n // Fetch the canonical user object from /auth/me\r\n return api.get<AuthUser>('/auth/me')\r\n },\r\n onSuccess: (result, vars) => {\r\n if (isMfaChallenge(result)) {\r\n setMfaChallenge({ mfaToken: result.mfaToken, mfaMethods: result.mfaMethods })\r\n if (config.mfaPath) navigate({ to: config.mfaPath })\r\n return\r\n }\r\n queryClient.setQueryData(AUTH_QUERY_KEY, result)\r\n onLoginSuccess?.()\r\n const to = vars.redirectTo ?? config.homePath\r\n if (to) navigate({ to })\r\n },\r\n })\r\n }\r\n\r\n function useLogout() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n const setMfaChallenge = useSetAtom(pendingMfaChallengeAtom)\r\n\r\n function cleanup(vars: LogoutVars | void) {\r\n storage.clear()\r\n storage.clearRefreshToken()\r\n queryClient.clear()\r\n config.onUnauthenticated?.()\r\n const to = (vars as LogoutVars | undefined)?.redirectTo ?? config.loginPath\r\n if (to) navigate({ to })\r\n }\r\n\r\n return useMutation<void, ApiError, LogoutVars | void>({\r\n mutationFn: () => api.post<void>('/auth/logout', {}),\r\n onSuccess: (_data, vars) => {\r\n setMfaChallenge(null)\r\n cleanup(vars)\r\n },\r\n onError: (_err, vars) => cleanup(vars),\r\n })\r\n }\r\n\r\n function useRegister() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n return useMutation<AuthUser, ApiError, RegisterVars>({\r\n mutationFn: async ({ redirectTo: _, ...body }) => {\r\n const res = await api.post<Record<string, unknown>>('/auth/register', body)\r\n if (config.auth !== 'cookie') {\r\n if (res && typeof res['token'] === 'string') {\r\n storage.set(res['token'])\r\n }\r\n if (typeof res['refreshToken'] === 'string') {\r\n storage.setRefreshToken(res['refreshToken'])\r\n }\r\n }\r\n return api.get<AuthUser>('/auth/me')\r\n },\r\n onSuccess: (user, vars) => {\r\n queryClient.setQueryData(AUTH_QUERY_KEY, user)\r\n onLoginSuccess?.()\r\n const to = vars.redirectTo ?? config.homePath\r\n if (to) navigate({ to })\r\n },\r\n })\r\n }\r\n\r\n function useForgotPassword() {\r\n return useMutation<void, ApiError, ForgotPasswordBody>({\r\n mutationFn: (body) => api.post<void>('/auth/forgot-password', body),\r\n })\r\n }\r\n\r\n return { useUser, useLogin, useLogout, useRegister, useForgotPassword }\r\n}\r\n","import type {\r\n UseMutationResult,\r\n QueryClient,\r\n} from '@tanstack/react-query'\r\nimport type React from 'react'\r\nimport type { ApiClient } from './api/client'\r\nimport type { ApiError } from './api/error'\r\nimport type { TokenStorage } from './auth/storage'\r\nimport type { WebSocketManager } from './ws/manager'\r\n\r\n// ── Auth types ────────────────────────────────────────────────────────────────\r\n\r\nexport interface AuthUser {\r\n id: string\r\n email: string\r\n [key: string]: unknown\r\n}\r\n\r\nexport interface LoginBody {\r\n email: string\r\n password: string\r\n}\r\n\r\nexport interface RegisterBody {\r\n email: string\r\n password: string\r\n [key: string]: unknown\r\n}\r\n\r\nexport interface ForgotPasswordBody {\r\n email: string\r\n}\r\n\r\nexport type LoginVars = LoginBody & { redirectTo?: string }\r\nexport type RegisterVars = RegisterBody & { redirectTo?: string }\r\nexport interface LogoutVars { redirectTo?: string }\r\n\r\n// ── MFA types ────────────────────────────────────────────────────────────────\r\n\r\nexport type MfaMethod = 'totp' | 'emailOtp' | 'webauthn'\r\n\r\n/** Raw login response shape from bunshot (includes MFA fields) */\r\nexport interface LoginResponse {\r\n token: string\r\n userId: string\r\n refreshToken?: string\r\n mfaRequired?: boolean\r\n mfaToken?: string\r\n mfaMethods?: MfaMethod[]\r\n}\r\n\r\n/** Returned by useLogin when mfaRequired is true */\r\nexport interface MfaChallenge {\r\n mfaToken: string\r\n mfaMethods: MfaMethod[]\r\n}\r\n\r\n/** useLogin resolves to either a user or an MFA challenge */\r\nexport type LoginResult = AuthUser | MfaChallenge\r\n\r\nexport function isMfaChallenge(result: LoginResult): result is MfaChallenge {\r\n return 'mfaToken' in result && !('id' in result)\r\n}\r\n\r\nexport interface MfaVerifyBody {\r\n mfaToken: string\r\n code?: string\r\n method?: MfaMethod\r\n webauthnResponse?: unknown\r\n}\r\n\r\nexport interface MfaSetupResponse { secret: string; uri: string }\r\nexport interface MfaVerifySetupBody { code: string }\r\nexport interface MfaVerifySetupResponse { message: string; recoveryCodes: string[] }\r\nexport interface MfaDisableBody { code: string }\r\nexport interface MfaRecoveryCodesBody { code: string }\r\nexport interface MfaRecoveryCodesResponse { recoveryCodes: string[] }\r\nexport interface MfaEmailOtpEnableResponse { message: string; setupToken: string }\r\nexport interface MfaEmailOtpVerifySetupBody { setupToken: string; code: string }\r\nexport interface MfaEmailOtpDisableBody { code?: string; password?: string }\r\nexport interface MfaResendBody { mfaToken: string }\r\nexport interface MfaMethodsResponse { methods: MfaMethod[] }\r\n\r\n// ── Account types ─────────────────────────────────────────────────────────────\r\n\r\nexport interface ResetPasswordBody { token: string; password: string }\r\nexport interface VerifyEmailBody { token: string }\r\nexport interface ResendVerificationBody { email: string }\r\nexport interface SetPasswordBody { password: string; currentPassword?: string }\r\nexport interface DeleteAccountBody { password?: string }\r\nexport interface RefreshTokenBody { refreshToken?: string }\r\nexport interface RefreshTokenResponse { token: string; refreshToken?: string; userId: string }\r\nexport interface Session {\r\n sessionId: string\r\n ipAddress?: string\r\n userAgent?: string\r\n createdAt: number\r\n lastActiveAt: number\r\n expiresAt: number\r\n isActive: boolean\r\n}\r\n\r\n// ── OAuth types ───────────────────────────────────────────────────────────────\r\n\r\nexport type OAuthProvider = 'google' | 'apple' | 'microsoft' | 'github'\r\nexport interface OAuthExchangeBody { code: string }\r\nexport interface OAuthExchangeResponse { token: string; userId: string; email?: string; refreshToken?: string }\r\n\r\n// ── WebAuthn types ────────────────────────────────────────────────────────────\r\n\r\nexport interface WebAuthnRegisterOptionsResponse { options: unknown; registrationToken: string }\r\nexport interface WebAuthnRegisterBody { registrationToken: string; attestationResponse: unknown; name?: string }\r\nexport interface WebAuthnCredential { credentialId: string; name?: string; createdAt: number; transports?: string[] }\r\nexport interface WebAuthnRemoveBody { credentialId: string }\r\n\r\n// ── Passkey types (passwordless first-factor login) ───────────────────────\r\n\r\nexport interface PasskeyLoginOptionsBody { email?: string }\r\nexport interface PasskeyLoginOptionsResponse {\r\n options: unknown\r\n passkeyToken: string\r\n}\r\nexport interface PasskeyLoginBody {\r\n passkeyToken: string\r\n assertionResponse: unknown\r\n}\r\n\r\n// ── API client types ──────────────────────────────────────────────────────────\r\n\r\nexport interface RequestOptions {\r\n headers?: Record<string, string>\r\n signal?: AbortSignal\r\n}\r\n\r\n// ── WebSocket types ───────────────────────────────────────────────────────────\r\n\r\nexport interface SocketHook<TEvents = Record<string, unknown>> {\r\n isConnected: boolean\r\n send: (type: string, payload: unknown) => void\r\n subscribe: (room: string) => void\r\n unsubscribe: (room: string) => void\r\n getRooms: () => string[]\r\n on: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => void\r\n off: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => void\r\n reconnect: () => void\r\n}\r\n\r\n// ── Config ────────────────────────────────────────────────────────────────────\r\n\r\nexport interface SnapshotConfig {\r\n apiUrl: string\r\n /** `'cookie'` is the default and is the recommended mode for browser apps. */\r\n auth?: 'cookie' | 'token'\r\n /**\r\n * Static API credential. Not a user session token. Do not use in browser\r\n * deployments — emits a runtime warning in browser contexts.\r\n */\r\n bearerToken?: string\r\n\r\n // Redirect paths — no hardcoded defaults\r\n loginPath?: string\r\n homePath?: string\r\n forbiddenPath?: string\r\n mfaPath?: string\r\n mfaSetupPath?: string\r\n\r\n // Route guard callbacks\r\n onUnauthenticated?: () => void\r\n onForbidden?: () => void\r\n\r\n /**\r\n * When `auth: 'token'` is used, `'sessionStorage'` is the default (tab-scoped, survives\r\n * refresh). `'memory'` is a stricter opt-in (loses state on page reload, does not share\r\n * across tabs). `'localStorage'` is not recommended for auth tokens.\r\n */\r\n tokenStorage?: 'localStorage' | 'sessionStorage' | 'memory'\r\n tokenKey?: string\r\n\r\n staleTime?: number\r\n gcTime?: number\r\n retry?: number\r\n\r\n // WebSocket — entire block optional\r\n ws?: {\r\n url: string\r\n\r\n autoReconnect?: boolean\r\n reconnectOnLogin?: boolean\r\n reconnectOnFocus?: boolean\r\n maxReconnectAttempts?: number\r\n reconnectBaseDelay?: number\r\n reconnectMaxDelay?: number\r\n\r\n onConnected?: () => void\r\n onDisconnected?: () => void\r\n onReconnecting?: (attempt: number) => void\r\n onReconnectFailed?: () => void\r\n }\r\n}\r\n\r\n// ── Instance ──────────────────────────────────────────────────────────────────\r\n\r\nexport interface SnapshotInstance<TWSEvents extends Record<string, unknown> = Record<string, unknown>> {\r\n // High-level hooks\r\n useUser: () => { user: AuthUser | null; isLoading: boolean; isError: boolean }\r\n useLogin: () => UseMutationResult<LoginResult, ApiError, LoginVars>\r\n useLogout: () => UseMutationResult<void, ApiError, LogoutVars | void>\r\n useRegister: () => UseMutationResult<AuthUser, ApiError, RegisterVars>\r\n useForgotPassword: () => UseMutationResult<void, ApiError, ForgotPasswordBody>\r\n useSocket: () => SocketHook<TWSEvents>\r\n useRoom: (room: string) => { isSubscribed: boolean }\r\n useRoomEvent: <T>(room: string, event: string, handler: (data: T) => void) => void\r\n useTheme: () => { theme: 'light' | 'dark'; toggle: () => void; set: (t: 'light' | 'dark') => void }\r\n\r\n // MFA hooks\r\n usePendingMfaChallenge: () => MfaChallenge | null\r\n useMfaVerify: () => UseMutationResult<AuthUser, ApiError, Omit<MfaVerifyBody, 'mfaToken'>>\r\n useMfaSetup: () => UseMutationResult<MfaSetupResponse, ApiError, void>\r\n useMfaVerifySetup: () => UseMutationResult<MfaVerifySetupResponse, ApiError, MfaVerifySetupBody>\r\n useMfaDisable: () => UseMutationResult<{ message: string }, ApiError, MfaDisableBody>\r\n useMfaRecoveryCodes: () => UseMutationResult<MfaRecoveryCodesResponse, ApiError, MfaRecoveryCodesBody>\r\n useMfaEmailOtpEnable: () => UseMutationResult<MfaEmailOtpEnableResponse, ApiError, void>\r\n useMfaEmailOtpVerifySetup: () => UseMutationResult<MfaVerifySetupResponse, ApiError, MfaEmailOtpVerifySetupBody>\r\n useMfaEmailOtpDisable: () => UseMutationResult<{ message: string }, ApiError, MfaEmailOtpDisableBody>\r\n useMfaResend: () => UseMutationResult<{ message: string }, ApiError, MfaResendBody>\r\n useMfaMethods: () => { methods: MfaMethod[] | null; isLoading: boolean; isError: boolean }\r\n isMfaChallenge: typeof isMfaChallenge\r\n\r\n // Account hooks\r\n useResetPassword: () => UseMutationResult<{ message: string }, ApiError, ResetPasswordBody>\r\n useVerifyEmail: () => UseMutationResult<{ message: string }, ApiError, VerifyEmailBody>\r\n useResendVerification: () => UseMutationResult<{ message: string }, ApiError, ResendVerificationBody>\r\n useSetPassword: () => UseMutationResult<{ message: string }, ApiError, SetPasswordBody>\r\n useDeleteAccount: () => UseMutationResult<void, ApiError, DeleteAccountBody | void>\r\n useCancelDeletion: () => UseMutationResult<{ message: string }, ApiError, void>\r\n useRefreshToken: () => UseMutationResult<RefreshTokenResponse, ApiError, RefreshTokenBody | void>\r\n useSessions: () => { sessions: Session[]; isLoading: boolean; isError: boolean }\r\n useRevokeSession: () => UseMutationResult<void, ApiError, string>\r\n\r\n // OAuth hooks\r\n useOAuthExchange: () => UseMutationResult<OAuthExchangeResponse, ApiError, OAuthExchangeBody>\r\n useOAuthUnlink: () => UseMutationResult<void, ApiError, OAuthProvider>\r\n getOAuthUrl: (provider: OAuthProvider) => string\r\n getLinkUrl: (provider: OAuthProvider) => string\r\n\r\n // WebAuthn hooks\r\n useWebAuthnRegisterOptions: () => UseMutationResult<WebAuthnRegisterOptionsResponse, ApiError, void>\r\n useWebAuthnRegister: () => UseMutationResult<{ message: string }, ApiError, WebAuthnRegisterBody>\r\n useWebAuthnCredentials: () => { credentials: WebAuthnCredential[]; isLoading: boolean; isError: boolean }\r\n useWebAuthnRemoveCredential: () => UseMutationResult<{ message: string }, ApiError, string>\r\n useWebAuthnDisable: () => UseMutationResult<{ message: string }, ApiError, void>\r\n usePasskeyLoginOptions: () => UseMutationResult<PasskeyLoginOptionsResponse, ApiError, PasskeyLoginOptionsBody>\r\n usePasskeyLogin: () => UseMutationResult<LoginResult, ApiError, PasskeyLoginBody>\r\n\r\n // Primitives for composition\r\n api: ApiClient\r\n tokenStorage: TokenStorage\r\n queryClient: QueryClient\r\n useWebSocketManager: () => WebSocketManager<TWSEvents> | null\r\n\r\n // Routing\r\n protectedBeforeLoad: (ctx: { context: { queryClient: QueryClient } }) => Promise<void>\r\n guestBeforeLoad: (ctx: { context: { queryClient: QueryClient } }) => Promise<void>\r\n\r\n // Scaffold component\r\n QueryProvider: React.FC<{ children: React.ReactNode }>\r\n}\r\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\r\nimport { useNavigate } from '@tanstack/react-router'\r\nimport { useAtomValue, useSetAtom } from 'jotai'\r\nimport type { WritableAtom } from 'jotai'\r\nimport type { ApiClient } from '../api/client'\r\nimport type { ApiError } from '../api/error'\r\nimport type { TokenStorage } from './storage'\r\nimport type {\r\n AuthUser,\r\n LoginResponse,\r\n SnapshotConfig,\r\n MfaChallenge,\r\n MfaMethod,\r\n MfaVerifyBody,\r\n MfaSetupResponse,\r\n MfaVerifySetupBody,\r\n MfaVerifySetupResponse,\r\n MfaDisableBody,\r\n MfaRecoveryCodesBody,\r\n MfaRecoveryCodesResponse,\r\n MfaEmailOtpEnableResponse,\r\n MfaEmailOtpVerifySetupBody,\r\n MfaEmailOtpDisableBody,\r\n MfaResendBody,\r\n MfaMethodsResponse,\r\n} from '../types'\r\n\r\nconst AUTH_QUERY_KEY = ['auth', 'me'] as const\r\n\r\ninterface MfaHooksOptions {\r\n api: ApiClient\r\n storage: TokenStorage\r\n config: Pick<SnapshotConfig, 'auth' | 'homePath' | 'staleTime'>\r\n pendingMfaChallengeAtom: WritableAtom<MfaChallenge | null, [MfaChallenge | null], void>\r\n onLoginSuccess?: () => void\r\n}\r\n\r\nexport function createMfaHooks({ api, storage, config, pendingMfaChallengeAtom, onLoginSuccess }: MfaHooksOptions) {\r\n function useMfaVerify() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n const pendingChallenge = useAtomValue(pendingMfaChallengeAtom)\r\n const setMfaChallenge = useSetAtom(pendingMfaChallengeAtom)\r\n return useMutation<AuthUser, ApiError, Omit<MfaVerifyBody, 'mfaToken'>>({\r\n mutationFn: async (body: Omit<MfaVerifyBody, 'mfaToken'>) => {\r\n if (!pendingChallenge) throw new Error('No pending MFA challenge')\r\n const res = await api.post<LoginResponse>('/auth/mfa/verify', {\r\n ...body,\r\n mfaToken: pendingChallenge.mfaToken,\r\n })\r\n if (config.auth !== 'cookie' && res.token) {\r\n storage.set(res.token)\r\n if (res.refreshToken) {\r\n storage.setRefreshToken(res.refreshToken)\r\n }\r\n }\r\n return api.get<AuthUser>('/auth/me')\r\n },\r\n onSuccess: (user) => {\r\n setMfaChallenge(null)\r\n queryClient.setQueryData(AUTH_QUERY_KEY, user)\r\n onLoginSuccess?.()\r\n if (config.homePath) navigate({ to: config.homePath })\r\n },\r\n })\r\n }\r\n\r\n function useMfaSetup() {\r\n return useMutation<MfaSetupResponse, ApiError, void>({\r\n mutationFn: () => api.post<MfaSetupResponse>('/auth/mfa/setup', {}),\r\n })\r\n }\r\n\r\n function useMfaVerifySetup() {\r\n return useMutation<MfaVerifySetupResponse, ApiError, MfaVerifySetupBody>({\r\n mutationFn: (body) => api.post<MfaVerifySetupResponse>('/auth/mfa/verify-setup', body),\r\n })\r\n }\r\n\r\n function useMfaDisable() {\r\n return useMutation<{ message: string }, ApiError, MfaDisableBody>({\r\n mutationFn: (body) => api.delete<{ message: string }>('/auth/mfa', body),\r\n })\r\n }\r\n\r\n function useMfaRecoveryCodes() {\r\n return useMutation<MfaRecoveryCodesResponse, ApiError, MfaRecoveryCodesBody>({\r\n mutationFn: (body) => api.post<MfaRecoveryCodesResponse>('/auth/mfa/recovery-codes', body),\r\n })\r\n }\r\n\r\n function useMfaEmailOtpEnable() {\r\n return useMutation<MfaEmailOtpEnableResponse, ApiError, void>({\r\n mutationFn: () => api.post<MfaEmailOtpEnableResponse>('/auth/mfa/email-otp/enable', {}),\r\n })\r\n }\r\n\r\n function useMfaEmailOtpVerifySetup() {\r\n return useMutation<MfaVerifySetupResponse, ApiError, MfaEmailOtpVerifySetupBody>({\r\n mutationFn: (body) => api.post<MfaVerifySetupResponse>('/auth/mfa/email-otp/verify-setup', body),\r\n })\r\n }\r\n\r\n function useMfaEmailOtpDisable() {\r\n return useMutation<{ message: string }, ApiError, MfaEmailOtpDisableBody>({\r\n mutationFn: (body) => api.delete<{ message: string }>('/auth/mfa/email-otp', body),\r\n })\r\n }\r\n\r\n function useMfaResend() {\r\n return useMutation<{ message: string }, ApiError, MfaResendBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/mfa/resend', body),\r\n })\r\n }\r\n\r\n function useMfaMethods() {\r\n const { data: methods = null, isLoading, isError } = useQuery<MfaMethod[] | null, ApiError>({\r\n queryKey: ['auth', 'mfa', 'methods'],\r\n queryFn: async () => {\r\n try {\r\n const res = await api.get<MfaMethodsResponse>('/auth/mfa/methods')\r\n return res.methods\r\n } catch {\r\n return null\r\n }\r\n },\r\n staleTime: config.staleTime ?? 5 * 60 * 1000,\r\n retry: false,\r\n })\r\n return { methods, isLoading, isError }\r\n }\r\n\r\n return {\r\n useMfaVerify,\r\n useMfaSetup,\r\n useMfaVerifySetup,\r\n useMfaDisable,\r\n useMfaRecoveryCodes,\r\n useMfaEmailOtpEnable,\r\n useMfaEmailOtpVerifySetup,\r\n useMfaEmailOtpDisable,\r\n useMfaResend,\r\n useMfaMethods,\r\n }\r\n}\r\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\r\nimport type { QueryClient } from '@tanstack/react-query'\r\nimport { useNavigate } from '@tanstack/react-router'\r\nimport type { ApiClient } from '../api/client'\r\nimport type { ApiError } from '../api/error'\r\nimport type { TokenStorage } from './storage'\r\nimport type {\r\n SnapshotConfig,\r\n ResetPasswordBody,\r\n VerifyEmailBody,\r\n ResendVerificationBody,\r\n SetPasswordBody,\r\n DeleteAccountBody,\r\n RefreshTokenBody,\r\n RefreshTokenResponse,\r\n Session,\r\n} from '../types'\r\n\r\ninterface AccountHooksOptions {\r\n api: ApiClient\r\n storage: TokenStorage\r\n config: Pick<SnapshotConfig, 'loginPath'>\r\n onUnauthenticated?: () => void\r\n queryClient: QueryClient\r\n}\r\n\r\nexport function createAccountHooks({ api, storage, config, onUnauthenticated, queryClient: qc }: AccountHooksOptions) {\r\n function useResetPassword() {\r\n return useMutation<{ message: string }, ApiError, ResetPasswordBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/reset-password', body),\r\n })\r\n }\r\n\r\n function useVerifyEmail() {\r\n return useMutation<{ message: string }, ApiError, VerifyEmailBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/verify-email', body),\r\n })\r\n }\r\n\r\n function useResendVerification() {\r\n return useMutation<{ message: string }, ApiError, ResendVerificationBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/resend-verification', body),\r\n })\r\n }\r\n\r\n function useSetPassword() {\r\n return useMutation<{ message: string }, ApiError, SetPasswordBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/set-password', body),\r\n })\r\n }\r\n\r\n function useDeleteAccount() {\r\n const navigate = useNavigate()\r\n return useMutation<void, ApiError, DeleteAccountBody | void>({\r\n mutationFn: (body) => api.delete<void>('/auth/me', body ?? {}),\r\n onSuccess: () => {\r\n storage.clear()\r\n qc.clear()\r\n onUnauthenticated?.()\r\n if (config.loginPath) navigate({ to: config.loginPath })\r\n },\r\n })\r\n }\r\n\r\n function useCancelDeletion() {\r\n return useMutation<{ message: string }, ApiError, void>({\r\n mutationFn: () => api.post<{ message: string }>('/auth/cancel-deletion', {}),\r\n })\r\n }\r\n\r\n function useRefreshToken() {\r\n return useMutation<RefreshTokenResponse, ApiError, RefreshTokenBody | void>({\r\n mutationFn: (body) => api.post<RefreshTokenResponse>('/auth/refresh', body ?? {}),\r\n onSuccess: (data) => {\r\n storage.set(data.token)\r\n if (data.refreshToken) {\r\n storage.setRefreshToken(data.refreshToken)\r\n }\r\n },\r\n })\r\n }\r\n\r\n function useSessions() {\r\n const { data, isLoading, isError } = useQuery<{ sessions: Session[] }, ApiError>({\r\n queryKey: ['auth', 'sessions'],\r\n queryFn: () => api.get<{ sessions: Session[] }>('/auth/sessions'),\r\n })\r\n return { sessions: data?.sessions ?? [], isLoading, isError }\r\n }\r\n\r\n function useRevokeSession() {\r\n const queryClient = useQueryClient()\r\n return useMutation<void, ApiError, string>({\r\n mutationFn: (sessionId) => api.delete<void>(`/auth/sessions/${sessionId}`, {}),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: ['auth', 'sessions'] })\r\n },\r\n })\r\n }\r\n\r\n return {\r\n useResetPassword,\r\n useVerifyEmail,\r\n useResendVerification,\r\n useSetPassword,\r\n useDeleteAccount,\r\n useCancelDeletion,\r\n useRefreshToken,\r\n useSessions,\r\n useRevokeSession,\r\n }\r\n}\r\n","import { useMutation, useQueryClient } from '@tanstack/react-query'\r\nimport { useNavigate } from '@tanstack/react-router'\r\nimport type { ApiClient } from '../api/client'\r\nimport type { ApiError } from '../api/error'\r\nimport type { TokenStorage } from './storage'\r\nimport type {\r\n SnapshotConfig,\r\n AuthUser,\r\n OAuthProvider,\r\n OAuthExchangeBody,\r\n OAuthExchangeResponse,\r\n} from '../types'\r\n\r\nconst AUTH_QUERY_KEY = ['auth', 'me'] as const\r\n\r\ninterface OAuthHooksOptions {\r\n api: ApiClient\r\n storage: TokenStorage\r\n config: Pick<SnapshotConfig, 'auth' | 'apiUrl' | 'homePath'>\r\n onLoginSuccess?: () => void\r\n}\r\n\r\nexport function createOAuthHooks({ api, storage, config, onLoginSuccess }: OAuthHooksOptions) {\r\n function getOAuthUrl(provider: OAuthProvider): string {\r\n return `${config.apiUrl}/auth/${provider}`\r\n }\r\n\r\n function getLinkUrl(provider: OAuthProvider): string {\r\n return `${config.apiUrl}/auth/${provider}/link`\r\n }\r\n\r\n /**\r\n * @deprecated Legacy OAuth code exchange. In the default Bunshot + snapshot browser\r\n * OAuth flow, Bunshot establishes the session cookie server-side during the provider\r\n * callback and redirects back with only success/error status. No client-side exchange\r\n * is needed. This hook will be removed in the next major version.\r\n */\r\n function useOAuthExchange() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n return useMutation<OAuthExchangeResponse, ApiError, OAuthExchangeBody>({\r\n mutationFn: (body) => api.post<OAuthExchangeResponse>('/auth/oauth/exchange', body),\r\n onSuccess: async (data) => {\r\n if (config.auth !== 'cookie' && data.token) {\r\n storage.set(data.token)\r\n if (data.refreshToken) {\r\n storage.setRefreshToken(data.refreshToken)\r\n }\r\n }\r\n const user = await api.get<AuthUser>('/auth/me')\r\n queryClient.setQueryData(AUTH_QUERY_KEY, user)\r\n onLoginSuccess?.()\r\n if (config.homePath) navigate({ to: config.homePath })\r\n },\r\n })\r\n }\r\n\r\n function useOAuthUnlink() {\r\n const queryClient = useQueryClient()\r\n return useMutation<void, ApiError, OAuthProvider>({\r\n mutationFn: (provider) => api.delete<void>(`/auth/${provider}/link`, {}),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: AUTH_QUERY_KEY })\r\n },\r\n })\r\n }\r\n\r\n return {\r\n getOAuthUrl,\r\n getLinkUrl,\r\n useOAuthExchange,\r\n useOAuthUnlink,\r\n }\r\n}\r\n","import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\r\nimport { useNavigate } from '@tanstack/react-router'\r\nimport { useSetAtom } from 'jotai'\r\nimport type { WritableAtom } from 'jotai'\r\nimport type { ApiClient } from '../api/client'\r\nimport type { ApiError } from '../api/error'\r\nimport type { TokenStorage } from '../auth/storage'\r\nimport type { SnapshotConfig } from '../types'\r\nimport type {\r\n WebAuthnRegisterOptionsResponse,\r\n WebAuthnRegisterBody,\r\n WebAuthnCredential,\r\n WebAuthnRemoveBody,\r\n PasskeyLoginOptionsBody,\r\n PasskeyLoginOptionsResponse,\r\n PasskeyLoginBody,\r\n LoginResult,\r\n LoginResponse,\r\n MfaChallenge,\r\n} from '../types'\r\nimport { isMfaChallenge } from '../types'\r\n\r\nconst WEBAUTHN_CREDENTIALS_KEY = ['auth', 'webauthn', 'credentials'] as const\r\n\r\ninterface WebAuthnHooksOptions {\r\n api: ApiClient\r\n storage?: TokenStorage\r\n config?: SnapshotConfig\r\n pendingMfaChallengeAtom: WritableAtom<MfaChallenge | null, [MfaChallenge | null], void>\r\n onLoginSuccess?: () => void\r\n}\r\n\r\nexport function createWebAuthnHooks({ api, storage, config, pendingMfaChallengeAtom, onLoginSuccess }: WebAuthnHooksOptions) {\r\n function useWebAuthnRegisterOptions() {\r\n return useMutation<WebAuthnRegisterOptionsResponse, ApiError, void>({\r\n mutationFn: () => api.post<WebAuthnRegisterOptionsResponse>('/auth/mfa/webauthn/register-options', {}),\r\n })\r\n }\r\n\r\n function useWebAuthnRegister() {\r\n const queryClient = useQueryClient()\r\n return useMutation<{ message: string }, ApiError, WebAuthnRegisterBody>({\r\n mutationFn: (body) => api.post<{ message: string }>('/auth/mfa/webauthn/register', body),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: WEBAUTHN_CREDENTIALS_KEY })\r\n },\r\n })\r\n }\r\n\r\n function useWebAuthnCredentials() {\r\n const { data, isLoading, isError } = useQuery<{ credentials: WebAuthnCredential[] }, ApiError>({\r\n queryKey: WEBAUTHN_CREDENTIALS_KEY,\r\n queryFn: () => api.get<{ credentials: WebAuthnCredential[] }>('/auth/mfa/webauthn/credentials'),\r\n })\r\n return { credentials: data?.credentials ?? [], isLoading, isError }\r\n }\r\n\r\n function useWebAuthnRemoveCredential() {\r\n const queryClient = useQueryClient()\r\n return useMutation<{ message: string }, ApiError, string>({\r\n mutationFn: (credentialId) => api.delete<{ message: string }>(`/auth/mfa/webauthn/credentials/${credentialId}`),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: WEBAUTHN_CREDENTIALS_KEY })\r\n },\r\n })\r\n }\r\n\r\n function useWebAuthnDisable() {\r\n return useMutation<{ message: string }, ApiError, void>({\r\n mutationFn: () => api.delete<{ message: string }>('/auth/mfa/webauthn', {}),\r\n })\r\n }\r\n\r\n function usePasskeyLoginOptions() {\r\n return useMutation<PasskeyLoginOptionsResponse, ApiError, PasskeyLoginOptionsBody>({\r\n mutationFn: (body) => api.post<PasskeyLoginOptionsResponse>('/auth/passkey/login-options', body),\r\n })\r\n }\r\n\r\n function usePasskeyLogin() {\r\n const queryClient = useQueryClient()\r\n const navigate = useNavigate()\r\n const setMfaChallenge = useSetAtom(pendingMfaChallengeAtom)\r\n return useMutation<LoginResult, ApiError, PasskeyLoginBody>({\r\n mutationFn: async (body) => {\r\n const response = await api.post<LoginResponse>('/auth/passkey/login', body)\r\n if (response.mfaRequired && response.mfaToken && response.mfaMethods) {\r\n return { mfaToken: response.mfaToken, mfaMethods: response.mfaMethods }\r\n }\r\n if (config?.auth !== 'cookie' && response.token && storage) {\r\n storage.set(response.token)\r\n if (response.refreshToken) {\r\n storage.setRefreshToken(response.refreshToken)\r\n }\r\n }\r\n return { id: response.userId, email: response.userId } as unknown as LoginResult\r\n },\r\n onSuccess: (result) => {\r\n if (isMfaChallenge(result)) {\r\n setMfaChallenge({ mfaToken: result.mfaToken, mfaMethods: result.mfaMethods })\r\n if (config?.mfaPath) navigate({ to: config.mfaPath })\r\n return\r\n }\r\n queryClient.invalidateQueries({ queryKey: ['auth', 'me'] })\r\n onLoginSuccess?.()\r\n if (config?.homePath) {\r\n window.location.href = config.homePath\r\n }\r\n },\r\n })\r\n }\r\n\r\n return {\r\n useWebAuthnRegisterOptions,\r\n useWebAuthnRegister,\r\n useWebAuthnCredentials,\r\n useWebAuthnRemoveCredential,\r\n useWebAuthnDisable,\r\n usePasskeyLoginOptions,\r\n usePasskeyLogin,\r\n }\r\n}\r\n","import type { SnapshotConfig } from '../types'\n\ntype WsConfig = NonNullable<SnapshotConfig['ws']>\ntype EventHandler<T = unknown> = (data: T) => void\n\nexport class WebSocketManager<TEvents extends Record<string, unknown> = Record<string, unknown>> {\n private ws: WebSocket | null = null\n private readonly rooms = new Set<string>()\n private readonly listeners = new Map<string, Set<EventHandler>>()\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private destroyed = false\n\n private readonly url: string\n private readonly autoReconnect: boolean\n private readonly reconnectOnFocus: boolean\n private readonly maxReconnectAttempts: number\n private readonly reconnectBaseDelay: number\n private readonly reconnectMaxDelay: number\n private readonly onConnected: (() => void) | undefined\n private readonly onDisconnected: (() => void) | undefined\n private readonly onReconnecting: ((attempt: number) => void) | undefined\n private readonly onReconnectFailed: (() => void) | undefined\n\n constructor(config: WsConfig) {\n this.url = config.url\n this.autoReconnect = config.autoReconnect ?? true\n this.reconnectOnFocus = config.reconnectOnFocus ?? true\n this.maxReconnectAttempts = config.maxReconnectAttempts ?? Infinity\n this.reconnectBaseDelay = config.reconnectBaseDelay ?? 1000\n this.reconnectMaxDelay = config.reconnectMaxDelay ?? 30000\n this.onConnected = config.onConnected\n this.onDisconnected = config.onDisconnected\n this.onReconnecting = config.onReconnecting\n this.onReconnectFailed = config.onReconnectFailed\n\n this.connect()\n\n if (this.reconnectOnFocus) {\n document.addEventListener('visibilitychange', this.handleVisibilityChange)\n }\n }\n\n get isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN\n }\n\n private handleVisibilityChange = () => {\n if (document.visibilityState === 'visible' && !this.isConnected && !this.destroyed) {\n this.reconnect()\n }\n }\n\n private connect() {\n if (this.destroyed) return\n\n try {\n this.ws = new WebSocket(this.url)\n } catch {\n this.scheduleReconnect()\n return\n }\n\n this.ws.onopen = () => {\n this.reconnectAttempts = 0\n this.clearReconnectTimer()\n this.onConnected?.()\n // Re-subscribe to all tracked rooms after reconnect\n this.rooms.forEach((room) => this.sendMessage({ type: 'subscribe', room }))\n }\n\n this.ws.onclose = () => {\n this.onDisconnected?.()\n if (this.autoReconnect && !this.destroyed) {\n this.scheduleReconnect()\n }\n }\n\n this.ws.onerror = () => {\n // onclose fires after onerror — reconnect logic is handled there\n }\n\n this.ws.onmessage = (event: MessageEvent) => {\n try {\n const message = JSON.parse(event.data as string) as { type: string; [key: string]: unknown }\n const handlers = this.listeners.get(message['type'])\n handlers?.forEach((h) => h(message))\n } catch {\n // Ignore unparseable messages\n }\n }\n }\n\n private sendMessage(message: Record<string, unknown>) {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(message))\n }\n }\n\n private scheduleReconnect() {\n if (this.destroyed || this.reconnectTimer !== null) return\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.onReconnectFailed?.()\n return\n }\n\n this.reconnectAttempts++\n const delay = Math.min(\n this.reconnectBaseDelay * Math.pow(2, this.reconnectAttempts - 1),\n this.reconnectMaxDelay,\n )\n\n this.onReconnecting?.(this.reconnectAttempts)\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.connect()\n }, delay)\n }\n\n private clearReconnectTimer() {\n if (this.reconnectTimer !== null) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n\n subscribe(room: string) {\n this.rooms.add(room)\n this.sendMessage({ type: 'subscribe', room })\n }\n\n unsubscribe(room: string) {\n this.rooms.delete(room)\n this.sendMessage({ type: 'unsubscribe', room })\n }\n\n getRooms(): string[] {\n return Array.from(this.rooms)\n }\n\n send(type: string, payload: unknown) {\n this.sendMessage({ type, payload })\n }\n\n on<K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) {\n const key = event as string\n if (!this.listeners.has(key)) {\n this.listeners.set(key, new Set())\n }\n this.listeners.get(key)!.add(handler as EventHandler)\n }\n\n off<K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) {\n const key = event as string\n this.listeners.get(key)?.delete(handler as EventHandler)\n }\n\n reconnect() {\n this.clearReconnectTimer()\n if (this.ws) {\n // Close without triggering auto-reconnect cycle — we'll connect immediately\n this.ws.onclose = null\n this.ws.close()\n this.ws = null\n }\n this.reconnectAttempts = 0\n this.connect()\n }\n\n disconnect() {\n this.destroyed = true\n this.clearReconnectTimer()\n document.removeEventListener('visibilitychange', this.handleVisibilityChange)\n if (this.ws) {\n this.ws.onclose = null\n this.ws.close()\n this.ws = null\n }\n }\n}\n","import { atom } from 'jotai'\nimport type { WebSocketManager } from './manager'\n\n// Singleton atom holding the WebSocketManager instance.\n// null when no ws config is provided or before initialization.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const wsManagerAtom = atom<WebSocketManager<any> | null>(null)\n","import { useAtomValue } from 'jotai'\nimport { useEffect, useState } from 'react'\nimport { wsManagerAtom } from './atom'\nimport type { SocketHook } from '../types'\nimport type { WebSocketManager } from './manager'\n\nexport function createWsHooks<TEvents extends Record<string, unknown>>() {\n function useWebSocketManager(): WebSocketManager<TEvents> | null {\n return useAtomValue(wsManagerAtom) as WebSocketManager<TEvents> | null\n }\n\n function useSocket(): SocketHook<TEvents> {\n const manager = useWebSocketManager()\n const [isConnected, setIsConnected] = useState(manager?.isConnected ?? false)\n\n useEffect(() => {\n if (!manager) return\n\n const interval = setInterval(() => {\n setIsConnected(manager.isConnected)\n }, 500)\n\n return () => clearInterval(interval)\n }, [manager])\n\n return {\n isConnected,\n send: (type, payload) => manager?.send(type, payload),\n subscribe: (room) => manager?.subscribe(room),\n unsubscribe: (room) => manager?.unsubscribe(room),\n getRooms: () => manager?.getRooms() ?? [],\n on: (event, handler) => manager?.on(event, handler),\n off: (event, handler) => manager?.off(event, handler),\n reconnect: () => manager?.reconnect(),\n }\n }\n\n function useRoom(room: string): { isSubscribed: boolean } {\n const manager = useWebSocketManager()\n const [isSubscribed, setIsSubscribed] = useState(false)\n\n useEffect(() => {\n if (!manager) return\n manager.subscribe(room)\n setIsSubscribed(true)\n return () => {\n manager.unsubscribe(room)\n setIsSubscribed(false)\n }\n }, [room, manager])\n\n return { isSubscribed }\n }\n\n function useRoomEvent<T>(\n room: string,\n event: string,\n handler: (data: T) => void,\n ): void {\n const manager = useWebSocketManager()\n\n useEffect(() => {\n if (!manager) return\n\n // Scoped: only handle events tagged to this room\n const scoped = (data: { room?: string; payload?: T } & Record<string, unknown>) => {\n if (data['room'] === room && data['payload'] !== undefined) {\n handler(data['payload'] as T)\n }\n }\n\n manager.on(event as keyof TEvents, scoped as (data: TEvents[keyof TEvents]) => void)\n return () => {\n manager.off(event as keyof TEvents, scoped as (data: TEvents[keyof TEvents]) => void)\n }\n }, [room, event, handler, manager])\n }\n\n return { useWebSocketManager, useSocket, useRoom, useRoomEvent }\n}\n","import { atomWithStorage } from 'jotai/utils'\nimport { useAtom } from 'jotai'\nimport { useEffect } from 'react'\n\ntype Theme = 'light' | 'dark'\n\nconst getInitialTheme = (): Theme => {\n if (typeof window === 'undefined') return 'light'\n const stored = localStorage.getItem('snapshot-theme') as Theme | null\n if (stored === 'light' || stored === 'dark') return stored\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nconst themeAtom = atomWithStorage<Theme>('snapshot-theme', getInitialTheme())\n\n// Inject a one-time style rule so we can suppress transitions during theme swap\nlet styleInjected = false\nfunction ensureNoTransitionStyle() {\n if (styleInjected || typeof document === 'undefined') return\n const style = document.createElement('style')\n style.textContent = '.no-transition, .no-transition * { transition: none !important; }'\n document.head.appendChild(style)\n styleInjected = true\n}\n\nexport function useTheme() {\n const [theme, setTheme] = useAtom(themeAtom)\n\n useEffect(() => {\n ensureNoTransitionStyle()\n const root = document.documentElement\n\n // Suppress CSS transitions so hundreds of elements don't animate at once\n root.classList.add('no-transition')\n\n if (theme === 'dark') {\n root.classList.add('dark')\n } else {\n root.classList.remove('dark')\n }\n\n // Re-enable after the browser has painted the new theme\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n root.classList.remove('no-transition')\n })\n })\n }, [theme])\n\n return {\n theme,\n toggle: () => setTheme((t) => (t === 'dark' ? 'light' : 'dark')),\n set: (t: Theme) => setTheme(t),\n }\n}\n","import { redirect } from '@tanstack/react-router'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { ApiClient } from '../api/client'\nimport type { AuthUser, SnapshotConfig } from '../types'\n\ninterface RouterContext {\n context: { queryClient: QueryClient }\n}\n\nconst AUTH_QUERY_KEY = ['auth', 'me'] as const\n\ntype LoaderConfig = Pick<\n SnapshotConfig,\n 'loginPath' | 'homePath' | 'forbiddenPath' | 'onUnauthenticated' | 'staleTime'\n>\n\nexport function createLoaders(config: LoaderConfig, api: ApiClient) {\n async function fetchUser(queryClient: QueryClient): Promise<AuthUser | null> {\n try {\n return await queryClient.ensureQueryData<AuthUser | null>({\n queryKey: AUTH_QUERY_KEY,\n queryFn: async () => {\n try {\n return await api.get<AuthUser>('/auth/me')\n } catch {\n return null\n }\n },\n staleTime: config.staleTime ?? 5 * 60 * 1000,\n })\n } catch {\n return null\n }\n }\n\n async function protectedBeforeLoad({ context }: RouterContext): Promise<void> {\n const user = await fetchUser(context.queryClient)\n\n if (!user) {\n config.onUnauthenticated?.()\n\n if (!config.loginPath) {\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] !== 'production') {\n throw new Error(\n '[snapshot] protectedBeforeLoad: no loginPath configured. ' +\n 'Set loginPath in createSnapshot config.',\n )\n }\n return\n }\n\n throw redirect({ to: config.loginPath })\n }\n }\n\n async function guestBeforeLoad({ context }: RouterContext): Promise<void> {\n const user = await fetchUser(context.queryClient)\n\n if (user) {\n if (!config.homePath) {\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] !== 'production') {\n throw new Error(\n '[snapshot] guestBeforeLoad: no homePath configured. ' +\n 'Set homePath in createSnapshot config.',\n )\n }\n return\n }\n\n throw redirect({ to: config.homePath })\n }\n }\n\n return { protectedBeforeLoad, guestBeforeLoad }\n}\n","import { QueryClientProvider } from '@tanstack/react-query'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { ReactNode } from 'react'\n\nexport interface QueryProviderProps {\n client: QueryClient\n children: ReactNode\n}\n\n// Internal component — apps use the pre-bound version returned by createSnapshot\nexport function QueryProviderInner({ client, children }: QueryProviderProps) {\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>\n}\n"],"mappings":"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","names":["atom","useAtom","useAtomValue","useQuery","useMutation","useQueryClient","useNavigate","useSetAtom","AUTH_QUERY_KEY","useQuery","useMutation","useQueryClient","useNavigate","useMutation","useQueryClient","useNavigate","AUTH_QUERY_KEY","useQuery","useMutation","useQueryClient","useNavigate","useSetAtom","useMutation","useQueryClient","useQuery","useNavigate","useSetAtom","useAtomValue","useAtomValue","useEffect","AUTH_QUERY_KEY","jsx","atom","useAtomValue","useAtom"]}
|