fetchguard 2.1.2 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/error-codes.ts","../src/worker-post.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/normalize.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts","../src/provider/register-presets.ts","../src/utils/formdata.ts","../src/utils/binary.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n\nimport type { WorkerConfig, FetchEnvelope, TokenProvider, FetchGuardRequestInit, ProviderPresetConfig } from './types'\nimport type { MainToWorkerMessage } from './messages'\nimport { ok, err, type Result } from 'ts-micro-result'\nimport { MSG } from './messages'\nimport { DEFAULT_REFRESH_EARLY_MS } from './constants'\nimport {\n InitErrors,\n AuthErrors,\n DomainErrors,\n RequestErrors,\n GeneralErrors\n} from './errors'\nimport { sendAuthStateChanged, sendAuthCallResult, sendPong, sendReady, sendSetupError, sendError, sendFetchResult, sendFetchError, sendTokenRefreshed } from './worker-post'\nimport { getProvider } from './utils/registry'\nimport { buildProviderFromPreset } from './provider/register-presets'\nimport { deserializeFormData, isSerializedFormData } from './utils/formdata'\nimport { arrayBufferToBase64, isBinaryContentType } from './utils/binary'\n\n/**\n * IIFE Closure to protect sensitive tokens from external access\n * Inspired by api-worker.js security pattern\n */\n;(function () {\n let config: WorkerConfig | null = null\n let provider: TokenProvider | null = null\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let expiresAt: number | null = null\n let currentUser: unknown | undefined\n const pendingControllers = new Map<string, AbortController>()\n let refreshPromise: Promise<Result<string>> | null = null\n let authPromise: Promise<unknown> | null = null\n\n/**\n * Mutex wrapper for auth operations (login, logout, custom auth methods)\n * Prevents race conditions when multiple concurrent auth calls are made.\n *\n * Edge case: If authPromise rejects, we catch and ignore it so the next\n * operation can proceed. Without this, a failed login would block\n * subsequent login attempts.\n */\nasync function withAuthMutex<T>(operation: () => Promise<T>): Promise<T> {\n // Wait for any pending auth operation (ignore previous errors)\n if (authPromise) {\n try {\n await authPromise\n } catch {\n // Ignore previous auth error - allow new operation to proceed\n }\n }\n\n const promise = operation()\n authPromise = promise\n\n try {\n return await promise\n } finally {\n authPromise = null\n }\n}\n\n/**\n * Ensure we have a valid access token (not expired).\n * If token is missing or expired, refresh it.\n * Prevents concurrent refresh attempts.\n *\n * @returns Result<string> - access token on success, error on failure\n */\nasync function ensureValidToken(): Promise<Result<string>> {\n // Provider must be initialized via SETUP first\n if (!provider) {\n return err(InitErrors.NotInitialized())\n }\n\n // Determine refresh reason before checking if refresh is needed\n const refreshEarlyMs = config?.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS\n const now = Date.now()\n const timeLeft = expiresAt ? expiresAt - now : 0\n const isExpired = !accessToken || !expiresAt || timeLeft <= 0\n const isProactive = !isExpired && timeLeft <= refreshEarlyMs\n\n if (accessToken && expiresAt && timeLeft > refreshEarlyMs) {\n return ok(accessToken)\n }\n\n if (refreshPromise) {\n const result = await refreshPromise\n return result\n }\n\n refreshPromise = (async (): Promise<Result<string>> => {\n try {\n // Provider already checked above, TypeScript needs assertion\n if (!provider) {\n return err(InitErrors.NotInitialized())\n }\n\n const valueRes = await provider.refreshToken(refreshToken)\n\n if (!valueRes.ok) {\n setTokenState({ token: null, expiresAt: null, user: undefined, refreshToken: undefined })\n return err(valueRes.errors)\n }\n\n const tokenInfo = valueRes.data\n if (!tokenInfo) {\n return err(AuthErrors.TokenRefreshFailed({ message: 'Provider returned null token info' }))\n }\n\n setTokenState(tokenInfo)\n\n // Validate that we got a valid access token after refresh\n if (!accessToken) {\n return err(AuthErrors.TokenRefreshFailed({ message: 'Access token is null after refresh' }))\n }\n\n // Emit TOKEN_REFRESHED event for debug hooks\n sendTokenRefreshed(isProactive ? 'proactive' : 'expired')\n\n return ok(accessToken)\n } finally {\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n}\n\n/**\n * Validate domain against allowed domains\n */\nfunction validateDomain(url: string): boolean {\n if (!config?.allowedDomains?.length) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n const hostname = urlObj.hostname\n const port = urlObj.port\n\n for (const entry of config.allowedDomains) {\n const idx = entry.lastIndexOf(':')\n const hasPort = idx > -1 && entry.indexOf(':') === idx\n const pattern = hasPort ? entry.slice(0, idx) : entry\n const entryPort = hasPort ? entry.slice(idx + 1) : ''\n const isWildcard = pattern.startsWith('*.')\n const base = isWildcard ? pattern.slice(2) : pattern\n\n const hostnameMatch = isWildcard\n ? (hostname === base || hostname.endsWith('.' + base))\n : (hostname === base)\n \n if (!hostnameMatch) continue\n\n if (hasPort) {\n if (port === entryPort) return true\n continue\n }\n return true\n }\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Make API request with proactive token management\n */\nasync function makeApiRequest(url: string, options: FetchGuardRequestInit = {}): Promise<Result<FetchEnvelope>> {\n if (!config) {\n return err(InitErrors.NotInitialized())\n }\n\n if (!validateDomain(url)) {\n return err(DomainErrors.NotAllowed({ url }))\n }\n\n const requiresAuth = options.requiresAuth !== false\n const includeHeaders = options.includeHeaders === true\n // Extract FetchGuard-specific options and keep only standard RequestInit\n const { requiresAuth: _, includeHeaders: __, ...fetchOptions } = options\n\n // Deserialize FormData if present (inspired by api-worker.js:484-518)\n if (fetchOptions.body && isSerializedFormData(fetchOptions.body)) {\n fetchOptions.body = deserializeFormData(fetchOptions.body)\n }\n\n const headers: Record<string, string> = {\n ...(config.defaultHeaders || {}),\n ...(fetchOptions.headers as Record<string, string> || {})\n }\n\n // Don't set Content-Type for FormData - browser will set it with boundary\n if (!headers['Content-Type'] && !headers['content-type'] && fetchOptions.body) {\n if (typeof fetchOptions.body === 'object' && !(fetchOptions.body instanceof FormData) && !(fetchOptions.body instanceof URLSearchParams)) {\n headers['Content-Type'] = 'application/json'\n }\n }\n\n if (requiresAuth) {\n const tokenRes = await ensureValidToken()\n if (!tokenRes.ok) {\n // Propagate error - cast to correct return type\n return err(tokenRes.errors)\n }\n\n const token = tokenRes.data\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n }\n\n let response: Response\n try {\n response = await fetch(url, { ...fetchOptions, headers, credentials: 'include' })\n } catch (e) {\n const aborted = (e && (e as any).name === 'AbortError')\n return aborted\n ? err(RequestErrors.Cancelled())\n : err(RequestErrors.NetworkError({ message: String(e) }))\n }\n\n // Extract content-type (always needed for binary detection)\n const contentType = response.headers.get('content-type') || 'application/octet-stream'\n\n // Determine if response is binary\n const isBinary = isBinaryContentType(contentType)\n\n // Get body as text or base64\n let body: string\n try {\n if (isBinary) {\n const buffer = await response.arrayBuffer()\n body = arrayBufferToBase64(buffer)\n } else {\n body = await response.text()\n }\n } catch (e) {\n // Reading/parsing response body failed\n return err(RequestErrors.ResponseParseFailed({ message: String(e) }))\n }\n\n // Extract headers if requested\n const responseHeaders: Record<string, string> = {}\n if (includeHeaders) {\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value\n })\n }\n\n const responseData = { body, status: response.status, contentType, headers: responseHeaders }\n return ok(responseData)\n}\n\n/**\n * Update token state from TokenInfo and auto emit AUTH_STATE_CHANGED\n *\n * Smart update logic for ALL fields:\n * - Only update field if key exists in tokenInfo\n * - If key exists with value: update to that value (including null)\n * - If key doesn't exist: preserve existing value\n *\n * This allows flexible custom auth methods:\n * - Standard login/refresh: returns { token, user, expiresAt }\n * - Update user info: may only return { user: {...} } (no token change)\n * - Verify OTP: may return {} (just validation, no state change)\n * - Logout: returns { token: null, user: null, ... } to clear all\n */\nfunction setTokenState(tokenInfo: { token?: string | null; expiresAt?: number | null; user?: unknown; refreshToken?: string | null }, emitEvent: boolean = true) {\n // Apply smart preservation to ALL fields\n if ('token' in tokenInfo) {\n accessToken = tokenInfo.token ?? null\n }\n\n if ('expiresAt' in tokenInfo) {\n expiresAt = tokenInfo.expiresAt ?? null\n }\n\n if ('user' in tokenInfo) {\n currentUser = tokenInfo.user\n }\n\n if ('refreshToken' in tokenInfo) {\n refreshToken = tokenInfo.refreshToken ?? null\n }\n\n if (emitEvent) {\n postAuthChanged()\n }\n}\n\n/**\n * Emit AUTH_STATE_CHANGED event based on current state\n * authenticated = true if we have valid non-expired token\n */\nfunction postAuthChanged() {\n const now = Date.now()\n const authenticated = accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n sendAuthStateChanged({\n authenticated,\n expiresAt,\n user: currentUser\n })\n}\n\n/**\n * Main message handler\n * Each case has its own try-catch for better error isolation\n */\nself.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {\n const data = event.data\n switch (data.type) {\n case MSG.SETUP: {\n try {\n const payload = data.payload\n config = payload.config\n\n const providerConfig = payload.providerConfig\n\n // Build provider from config\n if (typeof providerConfig === 'string') {\n // Registry lookup\n provider = getProvider(providerConfig)\n } else if (providerConfig && typeof providerConfig === 'object' && 'type' in providerConfig) {\n // ProviderPresetConfig object - pass defaultHeaders for auth requests\n provider = buildProviderFromPreset(providerConfig as ProviderPresetConfig, config.defaultHeaders)\n } else {\n sendSetupError('Invalid provider config')\n break\n }\n\n // Validate provider was successfully created\n if (!provider) {\n sendSetupError('Provider initialization failed - provider is null')\n break\n }\n\n sendReady()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error('[FetchGuard Worker] Setup failed:', errorMessage)\n sendSetupError(errorMessage)\n }\n break\n }\n\n case MSG.FETCH: {\n const { id } = data\n try {\n const { url, options } = data.payload\n const controller = new AbortController()\n pendingControllers.set(id, controller)\n const merged: RequestInit = { ...(options || {}), signal: controller.signal }\n const result = await makeApiRequest(url, merged)\n\n if (result.ok) {\n sendFetchResult(id, result.data)\n } else {\n // Network/timeout/cancel error\n const error = result.errors[0]\n const message = error?.message || 'Unknown error'\n sendFetchError(id, message, undefined)\n }\n\n pendingControllers.delete(id)\n } catch (error) {\n pendingControllers.delete(id)\n sendFetchError(id, error instanceof Error ? error.message : String(error), undefined)\n }\n break\n }\n\n case MSG.AUTH_CALL: {\n const { id, payload } = data\n // Use mutex to prevent concurrent auth operations (login, logout, etc.)\n await withAuthMutex(async () => {\n try {\n const { method, args, emitEvent } = payload\n const shouldEmitEvent = emitEvent ?? true // Default: emit event\n\n if (!provider) {\n sendError(id, err(InitErrors.NotInitialized()))\n return\n }\n\n if (typeof provider[method] !== 'function') {\n sendError(id, err(GeneralErrors.Unexpected({ message: `Method '${method}' not found on provider` })))\n return\n }\n\n // Inject current access token for exchangeToken method\n let methodArgs = args\n if (method === 'exchangeToken') {\n methodArgs = [accessToken, ...args]\n }\n\n const result = await provider[method](...methodArgs)\n if (!result.ok) {\n sendError(id, result)\n return\n }\n\n const tokenInfo = result.data\n if (!tokenInfo) {\n sendError(id, err(GeneralErrors.Unexpected({ message: 'Provider returned null token info' })))\n return\n }\n\n // Update token state and optionally emit event\n setTokenState(tokenInfo, shouldEmitEvent)\n\n // Always send AuthResult back\n const now = Date.now()\n const authenticated =\n accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n\n sendAuthCallResult(id, {\n authenticated,\n expiresAt,\n user: currentUser\n })\n } catch (error) {\n sendError(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n })\n break\n }\n\n case MSG.CANCEL: {\n try {\n const { id } = data\n const controller = pendingControllers.get(id)\n if (controller) {\n controller.abort()\n pendingControllers.delete(id)\n }\n } catch (error) {\n // Silently ignore cancel errors\n }\n break\n }\n\n case MSG.PING: {\n const { id } = data\n try {\n const ts = data.payload?.timestamp ?? Date.now()\n sendPong(id, ts)\n } catch (error) {\n sendError(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n default: {\n const anyData: any = data\n sendError(anyData.id, err(GeneralErrors.UnknownMessage({ message: `Unknown message type: ${String(anyData.type)}` })))\n }\n }\n}\n\n})() // End IIFE - Immediately Invoked Function Expression\n","import type { ErrorDetail, Result, ResultMeta } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResult, FetchEnvelope, RefreshReason } from './types'\r\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\r\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\r\n FETCH: { url: string; options?: FetchGuardRequestInit }\r\n AUTH_CALL: { method: string; args: unknown[]; emitEvent?: boolean } // Generic auth method call (login, logout, loginWithPhone, etc.)\r\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n ERROR: { errors: ErrorDetail[]; meta?: ResultMeta, status?: number }\r\n READY: undefined\r\n SETUP_ERROR: { error: string }\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: AuthResult\r\n AUTH_CALL_RESULT: AuthResult\r\n FETCH_RESULT: FetchEnvelope\r\n FETCH_ERROR: { error: string; status?: number }\r\n TOKEN_REFRESHED: { reason: RefreshReason }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n ERROR: 'ERROR',\r\n READY: 'READY',\r\n SETUP_ERROR: 'SETUP_ERROR',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n AUTH_CALL_RESULT: 'AUTH_CALL_RESULT',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR',\r\n TOKEN_REFRESHED: 'TOKEN_REFRESHED'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\nimport { ERROR_CODES } from './error-codes'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError(ERROR_CODES.UNEXPECTED, 'Unexpected error'),\n UnknownMessage: defineError(ERROR_CODES.UNKNOWN_MESSAGE, 'Unknown message type'),\n ResultParse: defineError(ERROR_CODES.RESULT_PARSE_ERROR, 'Failed to parse result'),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError(ERROR_CODES.INIT_ERROR, 'Worker not initialized'),\n ProviderInitFailed: defineError(ERROR_CODES.PROVIDER_INIT_FAILED, 'Failed to initialize provider'),\n InitFailed: defineError(ERROR_CODES.INIT_FAILED, 'Initialization failed'),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError(ERROR_CODES.TOKEN_REFRESH_FAILED, 'Token refresh failed'),\n TokenExchangeFailed: defineError(ERROR_CODES.TOKEN_EXCHANGE_FAILED, 'Token exchange failed'),\n LoginFailed: defineError(ERROR_CODES.LOGIN_FAILED, 'Login failed'),\n LogoutFailed: defineError(ERROR_CODES.LOGOUT_FAILED, 'Logout failed'),\n NotAuthenticated: defineError(ERROR_CODES.NOT_AUTHENTICATED, 'User is not authenticated'),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced(ERROR_CODES.DOMAIN_NOT_ALLOWED, 'Domain not allowed: {url}'),\n} as const\n\n/**\n * Request/Response errors (network, HTTP, parsing)\n */\nexport const RequestErrors = {\n // Network errors (connection failed, no response)\n NetworkError: defineError(ERROR_CODES.NETWORK_ERROR, 'Network error'),\n Cancelled: defineError(ERROR_CODES.REQUEST_CANCELLED, 'Request was cancelled'),\n\n // HTTP errors (server responded with error status)\n HttpError: defineErrorAdvanced(ERROR_CODES.HTTP_ERROR, 'HTTP {status} error'),\n\n // Response parsing errors\n ResponseParseFailed: defineError(ERROR_CODES.RESPONSE_PARSE_FAILED, 'Failed to parse response body'),\n\n // Queue errors\n QueueFull: defineErrorAdvanced(ERROR_CODES.QUEUE_FULL, 'Request queue full ({size}/{maxSize})'),\n\n // Timeout errors\n Timeout: defineError(ERROR_CODES.REQUEST_TIMEOUT, 'Request timed out'),\n} as const\n","/**\r\n * Error codes as constants for type-safe error matching\r\n *\r\n * Usage:\r\n * ```typescript\r\n * import { ERROR_CODES } from 'fetchguard'\r\n *\r\n * if (result.errors[0]?.code === ERROR_CODES.NETWORK_ERROR) {\r\n * // Handle network error\r\n * }\r\n * ```\r\n */\r\n\r\nexport const ERROR_CODES = {\r\n // General\r\n UNEXPECTED: 'UNEXPECTED',\r\n UNKNOWN_MESSAGE: 'UNKNOWN_MESSAGE',\r\n RESULT_PARSE_ERROR: 'RESULT_PARSE_ERROR',\r\n\r\n // Init\r\n INIT_ERROR: 'INIT_ERROR',\r\n PROVIDER_INIT_FAILED: 'PROVIDER_INIT_FAILED',\r\n INIT_FAILED: 'INIT_FAILED',\r\n\r\n // Auth\r\n TOKEN_REFRESH_FAILED: 'TOKEN_REFRESH_FAILED',\r\n TOKEN_EXCHANGE_FAILED: 'TOKEN_EXCHANGE_FAILED',\r\n LOGIN_FAILED: 'LOGIN_FAILED',\r\n LOGOUT_FAILED: 'LOGOUT_FAILED',\r\n NOT_AUTHENTICATED: 'NOT_AUTHENTICATED',\r\n\r\n // Domain\r\n DOMAIN_NOT_ALLOWED: 'DOMAIN_NOT_ALLOWED',\r\n\r\n // Request\r\n NETWORK_ERROR: 'NETWORK_ERROR',\r\n REQUEST_CANCELLED: 'REQUEST_CANCELLED',\r\n HTTP_ERROR: 'HTTP_ERROR',\r\n RESPONSE_PARSE_FAILED: 'RESPONSE_PARSE_FAILED',\r\n QUEUE_FULL: 'QUEUE_FULL',\r\n REQUEST_TIMEOUT: 'REQUEST_TIMEOUT'\r\n} as const\r\n\r\n/**\r\n * Union type of all error code values\r\n */\r\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]\r\n\r\n/**\r\n * Union type of all error code keys (useful for telemetry mapping)\r\n */\r\nexport type ErrorCodeKey = keyof typeof ERROR_CODES\r\n","/**\r\n * Worker postMessage helpers\r\n * Utilities to send messages from worker thread to main thread\r\n */\r\n\r\nimport type { WorkerToMainMessage } from './messages'\r\nimport type { Result } from 'ts-micro-result'\r\nimport type { AuthResult, FetchEnvelope, RefreshReason } from './types'\r\nimport { MSG } from './messages'\r\n\r\n/**\r\n * Internal helper to post message to main thread\r\n */\r\nfunction post(message: WorkerToMainMessage): void {\r\n ;(self as DedicatedWorkerGlobalScope).postMessage(message)\r\n}\r\n\r\n/**\r\n * Send error result (generic errors for auth operations, etc.)\r\n * Passes complete Result object with errors and meta\r\n */\r\nexport function sendError(id: string, result: Result<unknown>): void {\r\n if (!result.ok) {\r\n post({\r\n type: MSG.ERROR,\r\n id,\r\n payload: { errors: result.errors, meta: result.meta }\r\n } as any)\r\n }\r\n}\r\n\r\n/**\r\n * Send fetch envelope (raw HTTP response, worker doesn't judge status)\r\n */\r\nexport function sendFetchResult(id: string, envelope: FetchEnvelope): void {\r\n post({\r\n type: MSG.FETCH_RESULT,\r\n id,\r\n payload: envelope\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send fetch error response\r\n */\r\nexport function sendFetchError(id: string, error: string, status?: number): void {\r\n post({\r\n type: MSG.FETCH_ERROR,\r\n id,\r\n payload: { error, status }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send READY event (worker initialized)\r\n */\r\nexport function sendReady(): void {\r\n post({\r\n type: MSG.READY,\r\n id: `evt_${Date.now()}`\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send SETUP_ERROR event (worker setup failed)\r\n */\r\nexport function sendSetupError(error: string): void {\r\n post({\r\n type: MSG.SETUP_ERROR,\r\n id: `evt_${Date.now()}`,\r\n payload: { error }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send PONG response to PING\r\n */\r\nexport function sendPong(id: string, timestamp: number): void {\r\n post({\r\n type: MSG.PONG,\r\n id,\r\n payload: { timestamp }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_STATE_CHANGED event\r\n */\r\nexport function sendAuthStateChanged(authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_STATE_CHANGED,\r\n id: `evt_${Date.now()}`,\r\n payload: authResult\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_CALL_RESULT (auth method result)\r\n */\r\nexport function sendAuthCallResult(id: string, authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_CALL_RESULT,\r\n id,\r\n payload: authResult\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send TOKEN_REFRESHED event (for debug hooks)\r\n */\r\nexport function sendTokenRefreshed(reason: RefreshReason): void {\r\n post({\r\n type: MSG.TOKEN_REFRESHED,\r\n id: `evt_${Date.now()}`,\r\n payload: { reason }\r\n } as any)\r\n}\r\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo,\r\n ExchangeTokenOptions\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, RequestErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: unknown[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout' | 'exchangeToken'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.TokenRefreshFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown, url?: string) {\r\n try {\r\n const response = await config.strategy.login(payload, url)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.LoginFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.LogoutFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: null // Explicitly clear user on logout\r\n })\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n if (!accessToken) {\r\n return err(AuthErrors.NotAuthenticated())\r\n }\r\n\r\n try {\r\n const response = await config.strategy.exchangeToken(accessToken, url, options)\r\n\r\n if (!response.ok) {\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.TokenExchangeFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenExchangeFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage, StorageErrorCallback } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage options\r\n */\r\nexport interface IndexedDBStorageOptions {\r\n /** Database name (default: 'FetchGuardDB') */\r\n dbName?: string\r\n /** Key for refresh token (default: 'refreshToken') */\r\n refreshTokenKey?: string\r\n /**\r\n * Error callback for debugging storage failures\r\n * Called when IndexedDB operations fail (quota exceeded, permission denied, etc.)\r\n * Storage still fails closed (returns null), but this allows logging/debugging.\r\n */\r\n onError?: StorageErrorCallback\r\n}\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n *\r\n * @param options - Storage options or legacy dbName string\r\n * @param legacyRefreshTokenKey - Legacy refreshTokenKey (for backward compatibility)\r\n */\r\nexport function createIndexedDBStorage(\r\n options: IndexedDBStorageOptions | string = 'FetchGuardDB',\r\n legacyRefreshTokenKey?: string\r\n): RefreshTokenStorage {\r\n // Support both new options object and legacy string arguments\r\n const config: Required<Omit<IndexedDBStorageOptions, 'onError'>> & Pick<IndexedDBStorageOptions, 'onError'> =\r\n typeof options === 'string'\r\n ? { dbName: options, refreshTokenKey: legacyRefreshTokenKey ?? 'refreshToken', onError: undefined }\r\n : {\r\n dbName: options.dbName ?? 'FetchGuardDB',\r\n refreshTokenKey: options.refreshTokenKey ?? 'refreshToken',\r\n onError: options.onError\r\n }\r\n\r\n const { dbName, refreshTokenKey, onError } = config\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n\r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n\r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n onError?.(error as Error, 'get')\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n onError?.(error as Error, token ? 'set' : 'delete')\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Normalize expiresAt to milliseconds timestamp\r\n * Supports: milliseconds, seconds, ISO string, null/undefined\r\n */\r\nexport function normalizeExpiresAt(value: unknown): number | undefined {\r\n if (value == null) return undefined\r\n\r\n if (typeof value === 'number') {\r\n // Detect seconds vs milliseconds:\r\n // - Milliseconds: 13+ digits (e.g., 1767860146000)\r\n // - Seconds: 10 digits (e.g., 1767860146)\r\n // Threshold: 10^12 (Sep 2001 in ms, year 33658 in seconds)\r\n return value < 1e12 ? value * 1000 : value\r\n }\r\n\r\n if (typeof value === 'string') {\r\n const ts = Date.parse(value)\r\n return isNaN(ts) ? undefined : ts\r\n }\r\n\r\n return undefined\r\n}\r\n","import type { TokenParser } from '../../types'\r\nimport { normalizeExpiresAt } from './normalize'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: normalizeExpiresAt(json.data.expiresAt),\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\nimport { normalizeExpiresAt } from './normalize'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: normalizeExpiresAt(json.data.expiresAt),\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy, ExchangeTokenOptions } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n *\r\n * Login URL can be:\r\n * - Configured once: loginUrl: 'https://api.example.com/auth/login'\r\n * - Passed per call: login(payload, 'https://...')\r\n *\r\n * Header priority (lowest to highest):\r\n * - defaultHeaders (from FetchGuardOptions)\r\n * - headers (from ProviderPresetConfig)\r\n * - Content-Type: application/json\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): AuthStrategy {\r\n const baseHeaders = {\r\n ...config.defaultHeaders,\r\n ...config.headers,\r\n 'Content-Type': 'application/json'\r\n }\r\n\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload, url) {\r\n return fetch(url || config.loginUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n const { method = 'POST', payload, headers } = options\r\n return fetch(url, {\r\n method,\r\n headers: {\r\n ...baseHeaders,\r\n ...headers,\r\n 'Authorization': `Bearer ${accessToken}`\r\n },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy, ExchangeTokenOptions } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n *\r\n * Login URL can be:\r\n * - Configured once: loginUrl: 'https://api.example.com/auth/login'\r\n * - Passed per call: login(payload, 'https://...')\r\n *\r\n * Header priority (lowest to highest):\r\n * - defaultHeaders (from FetchGuardOptions)\r\n * - headers (from ProviderPresetConfig)\r\n * - Content-Type: application/json\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): AuthStrategy {\r\n const baseHeaders = {\r\n ...config.defaultHeaders,\r\n ...config.headers,\r\n 'Content-Type': 'application/json'\r\n }\r\n\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload, url) {\r\n return fetch(url || config.loginUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n const { method = 'POST', payload, headers } = options\r\n return fetch(url, {\r\n method,\r\n headers: {\r\n ...baseHeaders,\r\n ...headers,\r\n 'Authorization': `Bearer ${accessToken}`\r\n },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n","import { createCookieProvider, createBodyProvider } from './presets'\r\nimport type { TokenProvider, ProviderPresetConfig } from '../types'\r\n\r\n/**\r\n * Build provider from preset config\r\n * This is called in worker when receiving SETUP message\r\n *\r\n * @param config - Provider preset config\r\n * @param defaultHeaders - Default headers from FetchGuardOptions (applied to all requests including auth)\r\n */\r\nexport function buildProviderFromPreset(config: ProviderPresetConfig, defaultHeaders?: Record<string, string>): TokenProvider {\r\n switch (config.type) {\r\n case 'cookie-auth':\r\n return createCookieProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n headers: config.headers,\r\n defaultHeaders\r\n })\r\n\r\n case 'body-auth':\r\n return createBodyProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n refreshTokenKey: config.refreshTokenKey,\r\n headers: config.headers,\r\n defaultHeaders\r\n })\r\n\r\n default:\r\n throw new Error(`Unknown provider type: ${String((config as { type?: unknown }).type)}`)\r\n }\r\n}\r\n","import type { SerializedFormData, SerializedFormDataEntry, SerializedFile, SerializedFormDataResult } from '../types'\r\n\r\n/**\r\n * Serialize FormData for transfer over postMessage\r\n *\r\n * FormData cannot be cloned via postMessage, so we need to serialize it first.\r\n * Files are converted to ArrayBuffer and returned as transferables for zero-copy transfer.\r\n *\r\n * IMPORTANT: Preserves original field order by using single-pass iteration.\r\n *\r\n * @returns SerializedFormDataResult with data and transferables array\r\n */\r\nexport async function serializeFormData(formData: FormData): Promise<SerializedFormDataResult> {\r\n const entries: Array<[string, SerializedFormDataEntry]> = []\r\n const transferables: ArrayBuffer[] = []\r\n\r\n // Single-pass iteration to preserve original field order\r\n // Collect all entries with their index for order preservation\r\n const orderedEntries: Array<{ index: number; key: string; value: FormDataEntryValue }> = []\r\n let index = 0\r\n formData.forEach((value, key) => {\r\n orderedEntries.push({ index, key, value })\r\n index++\r\n })\r\n\r\n // Process all entries in order, handling files async\r\n await Promise.all(\r\n orderedEntries.map(async ({ index: idx, key, value }) => {\r\n if (value instanceof File) {\r\n const buffer = await value.arrayBuffer()\r\n const serializedFile: SerializedFile = {\r\n name: value.name,\r\n type: value.type,\r\n buffer\r\n }\r\n // Store with index for sorting later\r\n entries[idx] = [key, serializedFile]\r\n transferables.push(buffer)\r\n } else {\r\n entries[idx] = [key, String(value)]\r\n }\r\n })\r\n )\r\n\r\n return {\r\n data: {\r\n _type: 'FormData',\r\n entries\r\n },\r\n transferables\r\n }\r\n}\r\n\r\n/**\r\n * Deserialize SerializedFormData back to FormData in worker\r\n * Reconstructs File objects from transferred ArrayBuffers\r\n */\r\nexport function deserializeFormData(serialized: SerializedFormData): FormData {\r\n const formData = new FormData()\r\n\r\n for (const [key, value] of serialized.entries) {\r\n if (typeof value === 'string') {\r\n formData.append(key, value)\r\n } else {\r\n // Reconstruct File from SerializedFile (ArrayBuffer already transferred)\r\n const file = new File([value.buffer], value.name, { type: value.type })\r\n formData.append(key, file)\r\n }\r\n }\r\n\r\n return formData\r\n}\r\n\r\n/**\r\n * Check if body is FormData\r\n */\r\nexport function isFormData(body: unknown): body is FormData {\r\n return body instanceof FormData\r\n}\r\n\r\n/**\r\n * Check if serialized body is SerializedFormData\r\n */\r\nexport function isSerializedFormData(body: unknown): body is SerializedFormData {\r\n return body !== null && typeof body === 'object' && (body as SerializedFormData)._type === 'FormData'\r\n}\r\n","/**\r\n * Binary data utilities for Worker\r\n * Handles ArrayBuffer <-> Base64 conversion for binary responses\r\n */\r\n\r\n/**\r\n * Convert ArrayBuffer to base64 string\r\n * Used in worker to encode binary responses for postMessage transfer\r\n */\r\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\r\n const bytes = new Uint8Array(buffer)\r\n let binary = ''\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i])\r\n }\r\n return btoa(binary)\r\n}\r\n\r\n/**\r\n * Convert base64 string to ArrayBuffer\r\n * Used in client to decode binary responses\r\n */\r\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\r\n const binary = atob(base64)\r\n const bytes = new Uint8Array(binary.length)\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i)\r\n }\r\n return bytes.buffer\r\n}\r\n\r\n/**\r\n * Check if content type is binary (should be base64 encoded)\r\n * Returns true for images, PDFs, videos, etc.\r\n */\r\nexport function isBinaryContentType(contentType: string): boolean {\r\n const normalized = contentType.toLowerCase()\r\n\r\n // Text types - NOT binary\r\n if (normalized.includes('text/')) return false\r\n if (normalized.includes('json')) return false\r\n if (normalized.includes('xml')) return false\r\n if (normalized.includes('javascript')) return false\r\n if (normalized.includes('ecmascript')) return false\r\n if (normalized.includes('html')) return false\r\n\r\n // Everything else is considered binary\r\n return true\r\n}\r\n"],"mappings":"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","names":["ok","err","err","ok"]}
1
+ {"version":3,"sources":["../src/worker.ts","../src/messages.ts","../src/constants.ts","../src/errors.ts","../src/error-codes.ts","../src/worker-post.ts","../src/utils/registry.ts","../src/provider/create-provider.ts","../src/provider/storage/indexeddb.ts","../src/provider/parser/normalize.ts","../src/provider/parser/body.ts","../src/provider/parser/cookie.ts","../src/provider/strategy/cookie.ts","../src/provider/strategy/body.ts","../src/provider/presets.ts","../src/provider/register-presets.ts","../src/utils/formdata.ts","../src/utils/binary.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\n\nimport type { WorkerConfig, FetchEnvelope, TokenProvider, FetchGuardRequestInit, ProviderPresetConfig } from './types'\nimport type { MainToWorkerMessage } from './messages'\nimport { ok, err, type Result } from 'ts-micro-result'\nimport { MSG } from './messages'\nimport { DEFAULT_REFRESH_EARLY_MS } from './constants'\nimport {\n InitErrors,\n AuthErrors,\n DomainErrors,\n RequestErrors,\n GeneralErrors\n} from './errors'\nimport { sendAuthStateChanged, sendAuthCallResult, sendPong, sendReady, sendSetupError, sendError, sendFetchResult, sendFetchError, sendTokenRefreshed } from './worker-post'\nimport { getProvider, registerProvider, unregisterProvider, hasProvider, listProviders, clearProviders } from './utils/registry'\nimport { buildProviderFromPreset } from './provider/register-presets'\n\n// Re-export registry functions for custom workers\n// This ensures custom workers use the SAME registry instance as the worker IIFE\nexport { registerProvider, unregisterProvider, hasProvider, listProviders, clearProviders }\n\n// Re-export provider utilities for custom workers\nexport { createProvider } from './provider/create-provider'\nexport { createBodyStrategy } from './provider/strategy/body'\nexport { createCookieStrategy } from './provider/strategy/cookie'\nexport { createIndexedDBStorage } from './provider/storage/indexeddb'\nexport { bodyParser } from './provider/parser/body'\nexport { cookieParser } from './provider/parser/cookie'\nexport type { TokenProvider, TokenParser, AuthStrategy, RefreshTokenStorage, ExchangeTokenOptions } from './types'\nimport { deserializeFormData, isSerializedFormData } from './utils/formdata'\nimport { arrayBufferToBase64, isBinaryContentType } from './utils/binary'\n\n/**\n * IIFE Closure to protect sensitive tokens from external access\n * Inspired by api-worker.js security pattern\n */\n;(function () {\n let config: WorkerConfig | null = null\n let provider: TokenProvider | null = null\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let expiresAt: number | null = null\n let currentUser: unknown | undefined\n const pendingControllers = new Map<string, AbortController>()\n let refreshPromise: Promise<Result<string>> | null = null\n let authPromise: Promise<unknown> | null = null\n\n/**\n * Mutex wrapper for auth operations (login, logout, custom auth methods)\n * Prevents race conditions when multiple concurrent auth calls are made.\n *\n * Edge case: If authPromise rejects, we catch and ignore it so the next\n * operation can proceed. Without this, a failed login would block\n * subsequent login attempts.\n */\nasync function withAuthMutex<T>(operation: () => Promise<T>): Promise<T> {\n // Wait for any pending auth operation (ignore previous errors)\n if (authPromise) {\n try {\n await authPromise\n } catch {\n // Ignore previous auth error - allow new operation to proceed\n }\n }\n\n const promise = operation()\n authPromise = promise\n\n try {\n return await promise\n } finally {\n authPromise = null\n }\n}\n\n/**\n * Ensure we have a valid access token (not expired).\n * If token is missing or expired, refresh it.\n * Prevents concurrent refresh attempts.\n *\n * @returns Result<string> - access token on success, error on failure\n */\nasync function ensureValidToken(): Promise<Result<string>> {\n // Provider must be initialized via SETUP first\n if (!provider) {\n return err(InitErrors.NotInitialized())\n }\n\n // Determine refresh reason before checking if refresh is needed\n const refreshEarlyMs = config?.refreshEarlyMs ?? DEFAULT_REFRESH_EARLY_MS\n const now = Date.now()\n const timeLeft = expiresAt ? expiresAt - now : 0\n const isExpired = !accessToken || !expiresAt || timeLeft <= 0\n const isProactive = !isExpired && timeLeft <= refreshEarlyMs\n\n if (accessToken && expiresAt && timeLeft > refreshEarlyMs) {\n return ok(accessToken)\n }\n\n if (refreshPromise) {\n const result = await refreshPromise\n return result\n }\n\n refreshPromise = (async (): Promise<Result<string>> => {\n try {\n // Provider already checked above, TypeScript needs assertion\n if (!provider) {\n return err(InitErrors.NotInitialized())\n }\n\n const valueRes = await provider.refreshToken(refreshToken)\n\n if (!valueRes.ok) {\n setTokenState({ token: null, expiresAt: null, user: undefined, refreshToken: undefined })\n return err(valueRes.errors)\n }\n\n const tokenInfo = valueRes.data\n if (!tokenInfo) {\n return err(AuthErrors.TokenRefreshFailed({ message: 'Provider returned null token info' }))\n }\n\n setTokenState(tokenInfo)\n\n // Validate that we got a valid access token after refresh\n if (!accessToken) {\n return err(AuthErrors.TokenRefreshFailed({ message: 'Access token is null after refresh' }))\n }\n\n // Emit TOKEN_REFRESHED event for debug hooks\n sendTokenRefreshed(isProactive ? 'proactive' : 'expired')\n\n return ok(accessToken)\n } finally {\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n}\n\n/**\n * Validate domain against allowed domains\n */\nfunction validateDomain(url: string): boolean {\n if (!config?.allowedDomains?.length) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n const hostname = urlObj.hostname\n const port = urlObj.port\n\n for (const entry of config.allowedDomains) {\n const idx = entry.lastIndexOf(':')\n const hasPort = idx > -1 && entry.indexOf(':') === idx\n const pattern = hasPort ? entry.slice(0, idx) : entry\n const entryPort = hasPort ? entry.slice(idx + 1) : ''\n const isWildcard = pattern.startsWith('*.')\n const base = isWildcard ? pattern.slice(2) : pattern\n\n const hostnameMatch = isWildcard\n ? (hostname === base || hostname.endsWith('.' + base))\n : (hostname === base)\n \n if (!hostnameMatch) continue\n\n if (hasPort) {\n if (port === entryPort) return true\n continue\n }\n return true\n }\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Make API request with proactive token management\n */\nasync function makeApiRequest(url: string, options: FetchGuardRequestInit = {}): Promise<Result<FetchEnvelope>> {\n if (!config) {\n return err(InitErrors.NotInitialized())\n }\n\n if (!validateDomain(url)) {\n return err(DomainErrors.NotAllowed({ url }))\n }\n\n const requiresAuth = options.requiresAuth !== false\n const includeHeaders = options.includeHeaders === true\n // Extract FetchGuard-specific options and keep only standard RequestInit\n const { requiresAuth: _, includeHeaders: __, ...fetchOptions } = options\n\n // Deserialize FormData if present (inspired by api-worker.js:484-518)\n if (fetchOptions.body && isSerializedFormData(fetchOptions.body)) {\n fetchOptions.body = deserializeFormData(fetchOptions.body)\n }\n\n const headers: Record<string, string> = {\n ...(config.defaultHeaders || {}),\n ...(fetchOptions.headers as Record<string, string> || {})\n }\n\n // Don't set Content-Type for FormData - browser will set it with boundary\n if (!headers['Content-Type'] && !headers['content-type'] && fetchOptions.body) {\n if (typeof fetchOptions.body === 'object' && !(fetchOptions.body instanceof FormData) && !(fetchOptions.body instanceof URLSearchParams)) {\n headers['Content-Type'] = 'application/json'\n }\n }\n\n if (requiresAuth) {\n const tokenRes = await ensureValidToken()\n if (!tokenRes.ok) {\n // Propagate error - cast to correct return type\n return err(tokenRes.errors)\n }\n\n const token = tokenRes.data\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n }\n\n let response: Response\n try {\n response = await fetch(url, { ...fetchOptions, headers, credentials: 'include' })\n } catch (e) {\n const aborted = (e && (e as any).name === 'AbortError')\n return aborted\n ? err(RequestErrors.Cancelled())\n : err(RequestErrors.NetworkError({ message: String(e) }))\n }\n\n // Extract content-type (always needed for binary detection)\n const contentType = response.headers.get('content-type') || 'application/octet-stream'\n\n // Determine if response is binary\n const isBinary = isBinaryContentType(contentType)\n\n // Get body as text or base64\n let body: string\n try {\n if (isBinary) {\n const buffer = await response.arrayBuffer()\n body = arrayBufferToBase64(buffer)\n } else {\n body = await response.text()\n }\n } catch (e) {\n // Reading/parsing response body failed\n return err(RequestErrors.ResponseParseFailed({ message: String(e) }))\n }\n\n // Extract headers if requested\n const responseHeaders: Record<string, string> = {}\n if (includeHeaders) {\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value\n })\n }\n\n const responseData = { body, status: response.status, contentType, headers: responseHeaders }\n return ok(responseData)\n}\n\n/**\n * Update token state from TokenInfo and auto emit AUTH_STATE_CHANGED\n *\n * Smart update logic for ALL fields:\n * - Only update field if key exists in tokenInfo\n * - If key exists with value: update to that value (including null)\n * - If key doesn't exist: preserve existing value\n *\n * This allows flexible custom auth methods:\n * - Standard login/refresh: returns { token, user, expiresAt }\n * - Update user info: may only return { user: {...} } (no token change)\n * - Verify OTP: may return {} (just validation, no state change)\n * - Logout: returns { token: null, user: null, ... } to clear all\n */\nfunction setTokenState(tokenInfo: { token?: string | null; expiresAt?: number | null; user?: unknown; refreshToken?: string | null }, emitEvent: boolean = true) {\n // Apply smart preservation to ALL fields\n if ('token' in tokenInfo) {\n accessToken = tokenInfo.token ?? null\n }\n\n if ('expiresAt' in tokenInfo) {\n expiresAt = tokenInfo.expiresAt ?? null\n }\n\n if ('user' in tokenInfo) {\n currentUser = tokenInfo.user\n }\n\n if ('refreshToken' in tokenInfo) {\n refreshToken = tokenInfo.refreshToken ?? null\n }\n\n if (emitEvent) {\n postAuthChanged()\n }\n}\n\n/**\n * Emit AUTH_STATE_CHANGED event based on current state\n * authenticated = true if we have valid non-expired token\n */\nfunction postAuthChanged() {\n const now = Date.now()\n const authenticated = accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n sendAuthStateChanged({\n authenticated,\n expiresAt,\n user: currentUser\n })\n}\n\n/**\n * Main message handler\n * Each case has its own try-catch for better error isolation\n */\nself.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {\n const data = event.data\n switch (data.type) {\n case MSG.SETUP: {\n try {\n const payload = data.payload\n config = payload.config\n\n const providerConfig = payload.providerConfig\n\n // Build provider from config\n if (typeof providerConfig === 'string') {\n // Registry lookup\n provider = getProvider(providerConfig)\n } else if (providerConfig && typeof providerConfig === 'object' && 'type' in providerConfig) {\n // ProviderPresetConfig object - pass defaultHeaders for auth requests\n provider = buildProviderFromPreset(providerConfig as ProviderPresetConfig, config.defaultHeaders)\n } else {\n sendSetupError('Invalid provider config')\n break\n }\n\n // Validate provider was successfully created\n if (!provider) {\n sendSetupError('Provider initialization failed - provider is null')\n break\n }\n\n sendReady()\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error('[FetchGuard Worker] Setup failed:', errorMessage)\n sendSetupError(errorMessage)\n }\n break\n }\n\n case MSG.FETCH: {\n const { id } = data\n try {\n const { url, options } = data.payload\n const controller = new AbortController()\n pendingControllers.set(id, controller)\n const merged: RequestInit = { ...(options || {}), signal: controller.signal }\n const result = await makeApiRequest(url, merged)\n\n if (result.ok) {\n sendFetchResult(id, result.data)\n } else {\n // Network/timeout/cancel error\n const error = result.errors[0]\n const message = error?.message || 'Unknown error'\n sendFetchError(id, message, undefined)\n }\n\n pendingControllers.delete(id)\n } catch (error) {\n pendingControllers.delete(id)\n sendFetchError(id, error instanceof Error ? error.message : String(error), undefined)\n }\n break\n }\n\n case MSG.AUTH_CALL: {\n const { id, payload } = data\n // Use mutex to prevent concurrent auth operations (login, logout, etc.)\n await withAuthMutex(async () => {\n try {\n const { method, args, emitEvent } = payload\n const shouldEmitEvent = emitEvent ?? true // Default: emit event\n\n if (!provider) {\n sendError(id, err(InitErrors.NotInitialized()))\n return\n }\n\n if (typeof provider[method] !== 'function') {\n sendError(id, err(GeneralErrors.Unexpected({ message: `Method '${method}' not found on provider` })))\n return\n }\n\n // Inject current access token for exchangeToken method\n let methodArgs = args\n if (method === 'exchangeToken') {\n methodArgs = [accessToken, ...args]\n }\n\n const result = await provider[method](...methodArgs)\n if (!result.ok) {\n sendError(id, result)\n return\n }\n\n const tokenInfo = result.data\n if (!tokenInfo) {\n sendError(id, err(GeneralErrors.Unexpected({ message: 'Provider returned null token info' })))\n return\n }\n\n // Update token state and optionally emit event\n setTokenState(tokenInfo, shouldEmitEvent)\n\n // Always send AuthResult back\n const now = Date.now()\n const authenticated =\n accessToken !== null && accessToken !== '' && (expiresAt === null || expiresAt > now)\n\n sendAuthCallResult(id, {\n authenticated,\n expiresAt,\n user: currentUser\n })\n } catch (error) {\n sendError(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n })\n break\n }\n\n case MSG.CANCEL: {\n try {\n const { id } = data\n const controller = pendingControllers.get(id)\n if (controller) {\n controller.abort()\n pendingControllers.delete(id)\n }\n } catch (error) {\n // Silently ignore cancel errors\n }\n break\n }\n\n case MSG.PING: {\n const { id } = data\n try {\n const ts = data.payload?.timestamp ?? Date.now()\n sendPong(id, ts)\n } catch (error) {\n sendError(id, err(GeneralErrors.Unexpected({ message: error instanceof Error ? error.message : String(error) })))\n }\n break\n }\n\n default: {\n const anyData: any = data\n sendError(anyData.id, err(GeneralErrors.UnknownMessage({ message: `Unknown message type: ${String(anyData.type)}` })))\n }\n }\n}\n\n})() // End IIFE - Immediately Invoked Function Expression\n","import type { ErrorDetail, Result, ResultMeta } from 'ts-micro-result'\r\nimport type { WorkerConfig, FetchGuardRequestInit, ProviderPresetConfig, AuthResult, FetchEnvelope, RefreshReason } from './types'\r\n\r\n/**\r\n * MESSAGE PAYLOADS - SINGLE SOURCE OF TRUTH\r\n *\r\n * Define all message payloads here. Type unions and MSG constants are auto-generated.\r\n *\r\n * USAGE:\r\n * - To add a new message: Just add one line to the appropriate interface\r\n * - Payload types are automatically inferred\r\n * - MSG constants are automatically generated\r\n *\r\n * EXAMPLE:\r\n * ```typescript\r\n * interface MainPayloads {\r\n * NEW_MESSAGE: { foo: string } // Add this line\r\n * }\r\n * // => Automatically get MainToWorkerMessage union with NEW_MESSAGE\r\n * // => Automatically get MSG.NEW_MESSAGE = 'NEW_MESSAGE'\r\n * ```\r\n */\r\n\r\n/**\r\n * Payloads for messages sent from Main thread → Worker thread\r\n */\r\nexport interface MainPayloads {\r\n SETUP: { config: WorkerConfig; providerConfig: ProviderPresetConfig | string | null }\r\n FETCH: { url: string; options?: FetchGuardRequestInit }\r\n AUTH_CALL: { method: string; args: unknown[]; emitEvent?: boolean } // Generic auth method call (login, logout, loginWithPhone, etc.)\r\n CANCEL: undefined\r\n PING: { timestamp: number }\r\n}\r\n\r\n/**\r\n * Payloads for messages sent from Worker thread → Main thread\r\n */\r\nexport interface WorkerPayloads {\r\n ERROR: { errors: ErrorDetail[]; meta?: ResultMeta, status?: number }\r\n READY: undefined\r\n SETUP_ERROR: { error: string }\r\n PONG: { timestamp: number }\r\n LOG: { level: 'info' | 'warn' | 'error'; message: string }\r\n AUTH_STATE_CHANGED: AuthResult\r\n AUTH_CALL_RESULT: AuthResult\r\n FETCH_RESULT: FetchEnvelope\r\n FETCH_ERROR: { error: string; status?: number }\r\n TOKEN_REFRESHED: { reason: RefreshReason }\r\n}\r\n\r\n/**\r\n * Generate message type from payload definition\r\n * Handles optional payloads (undefined) gracefully\r\n */\r\ntype MessageFromPayloads<P> = {\r\n [K in keyof P]: { id: string; type: K } & (\r\n P[K] extends undefined ? {} : { payload: P[K] }\r\n )\r\n}[keyof P]\r\n\r\n/**\r\n * Message type unions - auto-generated from payload interfaces\r\n */\r\nexport type MainToWorkerMessage = MessageFromPayloads<MainPayloads>\r\nexport type WorkerToMainMessage = MessageFromPayloads<WorkerPayloads>\r\n\r\n/**\r\n * Message type unions for compile-time type checking\r\n */\r\nexport type MainType = keyof MainPayloads\r\nexport type WorkerType = keyof WorkerPayloads\r\nexport type MessageType = MainType | WorkerType\r\n\r\n/**\r\n * MSG constants object\r\n * Usage: MSG.SETUP, MSG.FETCH, etc.\r\n */\r\nexport const MSG = Object.freeze({\r\n // Main -> Worker messages\r\n SETUP: 'SETUP',\r\n FETCH: 'FETCH',\r\n AUTH_CALL: 'AUTH_CALL',\r\n CANCEL: 'CANCEL',\r\n PING: 'PING',\r\n\r\n // Worker -> Main messages\r\n ERROR: 'ERROR',\r\n READY: 'READY',\r\n SETUP_ERROR: 'SETUP_ERROR',\r\n PONG: 'PONG',\r\n LOG: 'LOG',\r\n AUTH_STATE_CHANGED: 'AUTH_STATE_CHANGED',\r\n AUTH_CALL_RESULT: 'AUTH_CALL_RESULT',\r\n FETCH_RESULT: 'FETCH_RESULT',\r\n FETCH_ERROR: 'FETCH_ERROR',\r\n TOKEN_REFRESHED: 'TOKEN_REFRESHED'\r\n}) as { readonly [K in MessageType]: K }\r\n","/**\n * FetchGuard Default Configuration Values\n */\n\n/**\n * Default time (in milliseconds) to refresh token before expiry\n * @default 60000 (60 seconds)\n */\nexport const DEFAULT_REFRESH_EARLY_MS = 60_000\n","/**\n * Error definitions organized by domain\n * Using ts-micro-result's defineError for consistency\n */\n\nimport { defineError, defineErrorAdvanced } from 'ts-micro-result'\nimport { ERROR_CODES } from './error-codes'\n\n/**\n * General errors\n */\nexport const GeneralErrors = {\n Unexpected: defineError(ERROR_CODES.UNEXPECTED, 'Unexpected error'),\n UnknownMessage: defineError(ERROR_CODES.UNKNOWN_MESSAGE, 'Unknown message type'),\n ResultParse: defineError(ERROR_CODES.RESULT_PARSE_ERROR, 'Failed to parse result'),\n} as const\n\n/**\n * Initialization errors\n */\nexport const InitErrors = {\n NotInitialized: defineError(ERROR_CODES.INIT_ERROR, 'Worker not initialized'),\n ProviderInitFailed: defineError(ERROR_CODES.PROVIDER_INIT_FAILED, 'Failed to initialize provider'),\n InitFailed: defineError(ERROR_CODES.INIT_FAILED, 'Initialization failed'),\n} as const\n\n/**\n * Authentication & Token errors\n */\nexport const AuthErrors = {\n TokenRefreshFailed: defineError(ERROR_CODES.TOKEN_REFRESH_FAILED, 'Token refresh failed'),\n TokenExchangeFailed: defineError(ERROR_CODES.TOKEN_EXCHANGE_FAILED, 'Token exchange failed'),\n LoginFailed: defineError(ERROR_CODES.LOGIN_FAILED, 'Login failed'),\n LogoutFailed: defineError(ERROR_CODES.LOGOUT_FAILED, 'Logout failed'),\n NotAuthenticated: defineError(ERROR_CODES.NOT_AUTHENTICATED, 'User is not authenticated'),\n} as const\n\n/**\n * Domain validation errors\n */\nexport const DomainErrors = {\n NotAllowed: defineErrorAdvanced(ERROR_CODES.DOMAIN_NOT_ALLOWED, 'Domain not allowed: {url}'),\n} as const\n\n/**\n * Request/Response errors (network, HTTP, parsing)\n */\nexport const RequestErrors = {\n // Network errors (connection failed, no response)\n NetworkError: defineError(ERROR_CODES.NETWORK_ERROR, 'Network error'),\n Cancelled: defineError(ERROR_CODES.REQUEST_CANCELLED, 'Request was cancelled'),\n\n // HTTP errors (server responded with error status)\n HttpError: defineErrorAdvanced(ERROR_CODES.HTTP_ERROR, 'HTTP {status} error'),\n\n // Response parsing errors\n ResponseParseFailed: defineError(ERROR_CODES.RESPONSE_PARSE_FAILED, 'Failed to parse response body'),\n\n // Queue errors\n QueueFull: defineErrorAdvanced(ERROR_CODES.QUEUE_FULL, 'Request queue full ({size}/{maxSize})'),\n\n // Timeout errors\n Timeout: defineError(ERROR_CODES.REQUEST_TIMEOUT, 'Request timed out'),\n} as const\n","/**\r\n * Error codes as constants for type-safe error matching\r\n *\r\n * Usage:\r\n * ```typescript\r\n * import { ERROR_CODES } from 'fetchguard'\r\n *\r\n * if (result.errors[0]?.code === ERROR_CODES.NETWORK_ERROR) {\r\n * // Handle network error\r\n * }\r\n * ```\r\n */\r\n\r\nexport const ERROR_CODES = {\r\n // General\r\n UNEXPECTED: 'UNEXPECTED',\r\n UNKNOWN_MESSAGE: 'UNKNOWN_MESSAGE',\r\n RESULT_PARSE_ERROR: 'RESULT_PARSE_ERROR',\r\n\r\n // Init\r\n INIT_ERROR: 'INIT_ERROR',\r\n PROVIDER_INIT_FAILED: 'PROVIDER_INIT_FAILED',\r\n INIT_FAILED: 'INIT_FAILED',\r\n\r\n // Auth\r\n TOKEN_REFRESH_FAILED: 'TOKEN_REFRESH_FAILED',\r\n TOKEN_EXCHANGE_FAILED: 'TOKEN_EXCHANGE_FAILED',\r\n LOGIN_FAILED: 'LOGIN_FAILED',\r\n LOGOUT_FAILED: 'LOGOUT_FAILED',\r\n NOT_AUTHENTICATED: 'NOT_AUTHENTICATED',\r\n\r\n // Domain\r\n DOMAIN_NOT_ALLOWED: 'DOMAIN_NOT_ALLOWED',\r\n\r\n // Request\r\n NETWORK_ERROR: 'NETWORK_ERROR',\r\n REQUEST_CANCELLED: 'REQUEST_CANCELLED',\r\n HTTP_ERROR: 'HTTP_ERROR',\r\n RESPONSE_PARSE_FAILED: 'RESPONSE_PARSE_FAILED',\r\n QUEUE_FULL: 'QUEUE_FULL',\r\n REQUEST_TIMEOUT: 'REQUEST_TIMEOUT'\r\n} as const\r\n\r\n/**\r\n * Union type of all error code values\r\n */\r\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]\r\n\r\n/**\r\n * Union type of all error code keys (useful for telemetry mapping)\r\n */\r\nexport type ErrorCodeKey = keyof typeof ERROR_CODES\r\n","/**\r\n * Worker postMessage helpers\r\n * Utilities to send messages from worker thread to main thread\r\n */\r\n\r\nimport type { WorkerToMainMessage } from './messages'\r\nimport type { Result } from 'ts-micro-result'\r\nimport type { AuthResult, FetchEnvelope, RefreshReason } from './types'\r\nimport { MSG } from './messages'\r\n\r\n/**\r\n * Internal helper to post message to main thread\r\n */\r\nfunction post(message: WorkerToMainMessage): void {\r\n ;(self as DedicatedWorkerGlobalScope).postMessage(message)\r\n}\r\n\r\n/**\r\n * Send error result (generic errors for auth operations, etc.)\r\n * Passes complete Result object with errors and meta\r\n */\r\nexport function sendError(id: string, result: Result<unknown>): void {\r\n if (!result.ok) {\r\n post({\r\n type: MSG.ERROR,\r\n id,\r\n payload: { errors: result.errors, meta: result.meta }\r\n } as any)\r\n }\r\n}\r\n\r\n/**\r\n * Send fetch envelope (raw HTTP response, worker doesn't judge status)\r\n */\r\nexport function sendFetchResult(id: string, envelope: FetchEnvelope): void {\r\n post({\r\n type: MSG.FETCH_RESULT,\r\n id,\r\n payload: envelope\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send fetch error response\r\n */\r\nexport function sendFetchError(id: string, error: string, status?: number): void {\r\n post({\r\n type: MSG.FETCH_ERROR,\r\n id,\r\n payload: { error, status }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send READY event (worker initialized)\r\n */\r\nexport function sendReady(): void {\r\n post({\r\n type: MSG.READY,\r\n id: `evt_${Date.now()}`\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send SETUP_ERROR event (worker setup failed)\r\n */\r\nexport function sendSetupError(error: string): void {\r\n post({\r\n type: MSG.SETUP_ERROR,\r\n id: `evt_${Date.now()}`,\r\n payload: { error }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send PONG response to PING\r\n */\r\nexport function sendPong(id: string, timestamp: number): void {\r\n post({\r\n type: MSG.PONG,\r\n id,\r\n payload: { timestamp }\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_STATE_CHANGED event\r\n */\r\nexport function sendAuthStateChanged(authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_STATE_CHANGED,\r\n id: `evt_${Date.now()}`,\r\n payload: authResult\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send AUTH_CALL_RESULT (auth method result)\r\n */\r\nexport function sendAuthCallResult(id: string, authResult: AuthResult): void {\r\n post({\r\n type: MSG.AUTH_CALL_RESULT,\r\n id,\r\n payload: authResult\r\n } as any)\r\n}\r\n\r\n/**\r\n * Send TOKEN_REFRESHED event (for debug hooks)\r\n */\r\nexport function sendTokenRefreshed(reason: RefreshReason): void {\r\n post({\r\n type: MSG.TOKEN_REFRESHED,\r\n id: `evt_${Date.now()}`,\r\n payload: { reason }\r\n } as any)\r\n}\r\n","import type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Registry to manage token providers\r\n */\r\nconst registry = new Map<string, TokenProvider>()\r\n\r\n/**\r\n * Register a token provider with name\r\n */\r\nexport function registerProvider(name: string, provider: TokenProvider): void {\r\n if (typeof name !== 'string' || !name.trim()) {\r\n throw new Error('Provider name must be a non-empty string')\r\n }\r\n \r\n if (!provider || typeof provider.refreshToken !== 'function') {\r\n throw new Error('Provider must implement TokenProvider interface')\r\n }\r\n \r\n registry.set(name, provider)\r\n}\r\n\r\n/**\r\n * Get provider by name\r\n */\r\nexport function getProvider(name: string): TokenProvider {\r\n const provider = registry.get(name)\r\n if (!provider) {\r\n throw new Error(`Provider '${name}' not found. Available providers: ${Array.from(registry.keys()).join(', ')}`)\r\n }\r\n return provider\r\n}\r\n\r\n/**\r\n * Check if provider exists\r\n */\r\nexport function hasProvider(name: string): boolean {\r\n return registry.has(name)\r\n}\r\n\r\n/**\r\n * Get list of all provider names\r\n */\r\nexport function listProviders(): string[] {\r\n return Array.from(registry.keys())\r\n}\r\n\r\n/**\r\n * Remove provider\r\n */\r\nexport function unregisterProvider(name: string): boolean {\r\n return registry.delete(name)\r\n}\r\n\r\n/**\r\n * Remove all providers\r\n */\r\nexport function clearProviders(): void {\r\n registry.clear()\r\n}\r\n","import type {\r\n TokenProvider,\r\n RefreshTokenStorage,\r\n TokenParser,\r\n AuthStrategy,\r\n TokenInfo,\r\n ExchangeTokenOptions\r\n} from '../types'\r\nimport { ok, err, type Result } from 'ts-micro-result'\r\nimport { AuthErrors, RequestErrors } from '../errors'\r\n\r\n/**\r\n * Custom auth method type\r\n */\r\ntype CustomAuthMethod = (...args: unknown[]) => Promise<Result<TokenInfo>>\r\n\r\n/**\r\n * Configuration for creating provider\r\n *\r\n * refreshStorage: OPTIONAL - to load refresh token initially when worker starts\r\n * - undefined: cookie-based auth (httpOnly cookie, no need to load)\r\n * - RefreshTokenStorage: body-based auth (load from IndexedDB on startup)\r\n *\r\n * strategy: AuthStrategy with refresh (required), login/logout (required)\r\n *\r\n * customMethods: OPTIONAL - custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n */\r\nexport interface ProviderConfig {\r\n refreshStorage?: RefreshTokenStorage\r\n parser: TokenParser\r\n strategy: AuthStrategy\r\n customMethods?: Record<string, CustomAuthMethod>\r\n}\r\n\r\n/**\r\n * Factory function to create TokenProvider from modular components\r\n *\r\n * Provider automatically handles refresh token:\r\n * - If refreshToken is null and storage exists → load from storage initially\r\n * - If refreshToken exists → use token from worker memory\r\n * - Cookie-based (no storage) → always null\r\n *\r\n * Custom methods:\r\n * - User can add custom auth methods (loginWithPhone, loginWithGoogle, etc.)\r\n * - Custom methods will be spread into provider object\r\n */\r\nexport function createProvider(config: ProviderConfig): TokenProvider {\r\n const baseProvider: Pick<TokenProvider, 'refreshToken' | 'login' | 'logout' | 'exchangeToken'> = {\r\n async refreshToken(refreshToken: string | null) {\r\n let currentRefreshToken = refreshToken\r\n if (currentRefreshToken === null && config.refreshStorage) {\r\n currentRefreshToken = await config.refreshStorage.get()\r\n }\r\n\r\n try {\r\n const response = await config.strategy.refresh(currentRefreshToken)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.TokenRefreshFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenRefreshFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async login(payload: unknown, url?: string) {\r\n try {\r\n const response = await config.strategy.login(payload, url)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.LoginFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.LoginFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async logout(payload?: unknown) {\r\n try {\r\n const response = await config.strategy.logout(payload)\r\n\r\n if (!response.ok) {\r\n // Read response body for error details\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.LogoutFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n if (config.refreshStorage) {\r\n await config.refreshStorage.set(null)\r\n }\r\n\r\n return ok({\r\n token: '',\r\n refreshToken: undefined,\r\n expiresAt: undefined,\r\n user: null // Explicitly clear user on logout\r\n })\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n if (!accessToken) {\r\n return err(AuthErrors.NotAuthenticated())\r\n }\r\n\r\n try {\r\n const response = await config.strategy.exchangeToken(accessToken, url, options)\r\n\r\n if (!response.ok) {\r\n const body = await response.text().catch(() => '')\r\n return err(AuthErrors.TokenExchangeFailed(), { params: { body, status: response.status } })\r\n }\r\n\r\n const tokenInfo = await config.parser.parse(response)\r\n if (!tokenInfo.token) {\r\n return err(AuthErrors.TokenExchangeFailed({ message: 'No access token in response' }))\r\n }\r\n\r\n if (config.refreshStorage && tokenInfo.refreshToken) {\r\n await config.refreshStorage.set(tokenInfo.refreshToken)\r\n }\r\n\r\n return ok(tokenInfo)\r\n } catch (error) {\r\n return err(RequestErrors.NetworkError({ message: String(error) }))\r\n }\r\n }\r\n }\r\n\r\n // Merge custom methods if provided\r\n if (config.customMethods) {\r\n return {\r\n ...baseProvider,\r\n ...config.customMethods\r\n } as TokenProvider\r\n }\r\n\r\n return baseProvider as TokenProvider\r\n}\r\n","import type { RefreshTokenStorage, StorageErrorCallback } from '../../types'\r\n\r\n/**\r\n * IndexedDB storage options\r\n */\r\nexport interface IndexedDBStorageOptions {\r\n /** Database name (default: 'FetchGuardDB') */\r\n dbName?: string\r\n /** Key for refresh token (default: 'refreshToken') */\r\n refreshTokenKey?: string\r\n /**\r\n * Error callback for debugging storage failures\r\n * Called when IndexedDB operations fail (quota exceeded, permission denied, etc.)\r\n * Storage still fails closed (returns null), but this allows logging/debugging.\r\n */\r\n onError?: StorageErrorCallback\r\n}\r\n\r\n/**\r\n * IndexedDB storage - only stores refresh token in IndexedDB\r\n * Suitable for body-based refresh strategy\r\n * Persists refresh token for reuse after reload\r\n *\r\n * @param options - Storage options or legacy dbName string\r\n * @param legacyRefreshTokenKey - Legacy refreshTokenKey (for backward compatibility)\r\n */\r\nexport function createIndexedDBStorage(\r\n options: IndexedDBStorageOptions | string = 'FetchGuardDB',\r\n legacyRefreshTokenKey?: string\r\n): RefreshTokenStorage {\r\n // Support both new options object and legacy string arguments\r\n const config: Required<Omit<IndexedDBStorageOptions, 'onError'>> & Pick<IndexedDBStorageOptions, 'onError'> =\r\n typeof options === 'string'\r\n ? { dbName: options, refreshTokenKey: legacyRefreshTokenKey ?? 'refreshToken', onError: undefined }\r\n : {\r\n dbName: options.dbName ?? 'FetchGuardDB',\r\n refreshTokenKey: options.refreshTokenKey ?? 'refreshToken',\r\n onError: options.onError\r\n }\r\n\r\n const { dbName, refreshTokenKey, onError } = config\r\n const storeName = 'tokens'\r\n\r\n const openDB = (): Promise<IDBDatabase> => {\r\n return new Promise((resolve, reject) => {\r\n const request = indexedDB.open(dbName, 1)\r\n\r\n request.onerror = () => reject(request.error)\r\n request.onsuccess = () => resolve(request.result)\r\n\r\n request.onupgradeneeded = (event) => {\r\n const db = (event.target as IDBOpenDBRequest).result\r\n if (!db.objectStoreNames.contains(storeName)) {\r\n const store = db.createObjectStore(storeName, { keyPath: 'key' })\r\n store.createIndex('timestamp', 'timestamp', { unique: false })\r\n }\r\n }\r\n })\r\n }\r\n\r\n const promisifyRequest = <T>(request: IDBRequest<T>): Promise<T> => {\r\n return new Promise((resolve, reject) => {\r\n request.onsuccess = () => resolve(request.result)\r\n request.onerror = () => reject(request.error)\r\n })\r\n }\r\n\r\n return {\r\n async get() {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readonly')\r\n const store = transaction.objectStore(storeName)\r\n const result = await promisifyRequest(store.get(refreshTokenKey))\r\n return result?.value || null\r\n } catch (error) {\r\n onError?.(error as Error, 'get')\r\n return null\r\n }\r\n },\r\n async set(token) {\r\n try {\r\n const db = await openDB()\r\n const transaction = db.transaction([storeName], 'readwrite')\r\n const store = transaction.objectStore(storeName)\r\n\r\n if (token) {\r\n await promisifyRequest(store.put({ key: refreshTokenKey, value: token, timestamp: Date.now() }))\r\n } else {\r\n await promisifyRequest(store.delete(refreshTokenKey))\r\n }\r\n } catch (error) {\r\n onError?.(error as Error, token ? 'set' : 'delete')\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Normalize expiresAt to milliseconds timestamp\r\n * Supports: milliseconds, seconds, ISO string, null/undefined\r\n */\r\nexport function normalizeExpiresAt(value: unknown): number | undefined {\r\n if (value == null) return undefined\r\n\r\n if (typeof value === 'number') {\r\n // Detect seconds vs milliseconds:\r\n // - Milliseconds: 13+ digits (e.g., 1767860146000)\r\n // - Seconds: 10 digits (e.g., 1767860146)\r\n // Threshold: 10^12 (Sep 2001 in ms, year 33658 in seconds)\r\n return value < 1e12 ? value * 1000 : value\r\n }\r\n\r\n if (typeof value === 'string') {\r\n const ts = Date.parse(value)\r\n return isNaN(ts) ? undefined : ts\r\n }\r\n\r\n return undefined\r\n}\r\n","import type { TokenParser } from '../../types'\r\nimport { normalizeExpiresAt } from './normalize'\r\n\r\n/**\r\n * Body parser - parse token from response body (JSON)\r\n * Expects response format: { data: { accessToken, refreshToken, expiresAt?, user? } }\r\n */\r\nexport const bodyParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n refreshToken: json.data.refreshToken,\r\n expiresAt: normalizeExpiresAt(json.data.expiresAt),\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { TokenParser } from '../../types'\r\nimport { normalizeExpiresAt } from './normalize'\r\n\r\n/**\r\n * Cookie parser - parse access token from response body\r\n * Expects response format: { data: { accessToken, expiresAt?, user? } }\r\n * Refresh token is automatically set by backend into httpOnly cookie\r\n */\r\nexport const cookieParser: TokenParser = {\r\n async parse(response) {\r\n const json = await response.clone().json()\r\n return {\r\n token: json.data.accessToken,\r\n expiresAt: normalizeExpiresAt(json.data.expiresAt),\r\n user: json.data.user\r\n }\r\n }\r\n}\r\n","import type { AuthStrategy, ExchangeTokenOptions } from '../../types'\r\n\r\n/**\r\n * Cookie auth strategy - all auth operations via httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Refresh token is sent automatically via httpOnly cookie\r\n * Credentials are sent in request body\r\n *\r\n * Login URL can be:\r\n * - Configured once: loginUrl: 'https://api.example.com/auth/login'\r\n * - Passed per call: login(payload, 'https://...')\r\n *\r\n * Header priority (lowest to highest):\r\n * - defaultHeaders (from FetchGuardOptions)\r\n * - headers (from ProviderPresetConfig)\r\n * - Content-Type: application/json\r\n */\r\nexport function createCookieStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): AuthStrategy {\r\n const baseHeaders = {\r\n ...config.defaultHeaders,\r\n ...config.headers,\r\n 'Content-Type': 'application/json'\r\n }\r\n\r\n return {\r\n async refresh() {\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload, url) {\r\n return fetch(url || config.loginUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n const { method = 'POST', payload, headers } = options\r\n return fetch(url, {\r\n method,\r\n headers: {\r\n ...baseHeaders,\r\n ...headers,\r\n 'Authorization': `Bearer ${accessToken}`\r\n },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard cookie strategy\r\n */\r\nexport const cookieStrategy = createCookieStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import type { AuthStrategy, ExchangeTokenOptions } from '../../types'\r\n\r\n/**\r\n * Body auth strategy - all auth operations via request body\r\n * Suitable for SPA applications\r\n *\r\n * All tokens/credentials are sent in request body\r\n *\r\n * Login URL can be:\r\n * - Configured once: loginUrl: 'https://api.example.com/auth/login'\r\n * - Passed per call: login(payload, 'https://...')\r\n *\r\n * Header priority (lowest to highest):\r\n * - defaultHeaders (from FetchGuardOptions)\r\n * - headers (from ProviderPresetConfig)\r\n * - Content-Type: application/json\r\n */\r\nexport function createBodyStrategy(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): AuthStrategy {\r\n const baseHeaders = {\r\n ...config.defaultHeaders,\r\n ...config.headers,\r\n 'Content-Type': 'application/json'\r\n }\r\n\r\n return {\r\n async refresh(refreshToken) {\r\n if (!refreshToken) {\r\n throw new Error('No refresh token available')\r\n }\r\n\r\n return fetch(config.refreshUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify({ refreshToken }),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async login(payload, url) {\r\n return fetch(url || config.loginUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: JSON.stringify(payload),\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async logout(payload) {\r\n return fetch(config.logoutUrl, {\r\n method: 'POST',\r\n headers: baseHeaders,\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n },\r\n\r\n async exchangeToken(accessToken: string, url: string, options: ExchangeTokenOptions = {}) {\r\n const { method = 'POST', payload, headers } = options\r\n return fetch(url, {\r\n method,\r\n headers: {\r\n ...baseHeaders,\r\n ...headers,\r\n 'Authorization': `Bearer ${accessToken}`\r\n },\r\n body: payload ? JSON.stringify(payload) : undefined,\r\n credentials: 'include'\r\n })\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Standard body strategy\r\n */\r\nexport const bodyStrategy = createBodyStrategy({\r\n refreshUrl: '/auth/refresh',\r\n loginUrl: '/auth/login',\r\n logoutUrl: '/auth/logout'\r\n})\r\n","import { createProvider } from './create-provider'\r\nimport { createIndexedDBStorage } from './storage/indexeddb'\r\nimport { bodyParser } from './parser/body'\r\nimport { cookieParser } from './parser/cookie'\r\nimport { createCookieStrategy } from './strategy/cookie'\r\nimport { createBodyStrategy } from './strategy/body'\r\nimport type { TokenProvider } from '../types'\r\n\r\n/**\r\n * Cookie Provider - uses httpOnly cookies\r\n * Suitable for SSR and cross-domain authentication\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: httpOnly cookie (managed by backend)\r\n */\r\nexport function createCookieProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: undefined,\r\n parser: cookieParser,\r\n strategy: createCookieStrategy(config)\r\n })\r\n}\r\n\r\n/**\r\n * Body Provider - refresh token in response body, persisted to IndexedDB\r\n * Suitable for SPA applications\r\n *\r\n * Access token: Worker memory\r\n * Refresh token: IndexedDB (persists across reload)\r\n */\r\nexport function createBodyProvider(config: {\r\n refreshUrl: string\r\n loginUrl: string\r\n logoutUrl: string\r\n refreshTokenKey?: string\r\n headers?: Record<string, string>\r\n defaultHeaders?: Record<string, string>\r\n}): TokenProvider {\r\n return createProvider({\r\n refreshStorage: createIndexedDBStorage('FetchGuardDB', config.refreshTokenKey || 'refreshToken'),\r\n parser: bodyParser,\r\n strategy: createBodyStrategy(config)\r\n })\r\n}\r\n","import { createCookieProvider, createBodyProvider } from './presets'\r\nimport type { TokenProvider, ProviderPresetConfig } from '../types'\r\n\r\n/**\r\n * Build provider from preset config\r\n * This is called in worker when receiving SETUP message\r\n *\r\n * @param config - Provider preset config\r\n * @param defaultHeaders - Default headers from FetchGuardOptions (applied to all requests including auth)\r\n */\r\nexport function buildProviderFromPreset(config: ProviderPresetConfig, defaultHeaders?: Record<string, string>): TokenProvider {\r\n switch (config.type) {\r\n case 'cookie-auth':\r\n return createCookieProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n headers: config.headers,\r\n defaultHeaders\r\n })\r\n\r\n case 'body-auth':\r\n return createBodyProvider({\r\n refreshUrl: config.refreshUrl,\r\n loginUrl: config.loginUrl,\r\n logoutUrl: config.logoutUrl,\r\n refreshTokenKey: config.refreshTokenKey,\r\n headers: config.headers,\r\n defaultHeaders\r\n })\r\n\r\n default:\r\n throw new Error(`Unknown provider type: ${String((config as { type?: unknown }).type)}`)\r\n }\r\n}\r\n","import type { SerializedFormData, SerializedFormDataEntry, SerializedFile, SerializedFormDataResult } from '../types'\r\n\r\n/**\r\n * Serialize FormData for transfer over postMessage\r\n *\r\n * FormData cannot be cloned via postMessage, so we need to serialize it first.\r\n * Files are converted to ArrayBuffer and returned as transferables for zero-copy transfer.\r\n *\r\n * IMPORTANT: Preserves original field order by using single-pass iteration.\r\n *\r\n * @returns SerializedFormDataResult with data and transferables array\r\n */\r\nexport async function serializeFormData(formData: FormData): Promise<SerializedFormDataResult> {\r\n const entries: Array<[string, SerializedFormDataEntry]> = []\r\n const transferables: ArrayBuffer[] = []\r\n\r\n // Single-pass iteration to preserve original field order\r\n // Collect all entries with their index for order preservation\r\n const orderedEntries: Array<{ index: number; key: string; value: FormDataEntryValue }> = []\r\n let index = 0\r\n formData.forEach((value, key) => {\r\n orderedEntries.push({ index, key, value })\r\n index++\r\n })\r\n\r\n // Process all entries in order, handling files async\r\n await Promise.all(\r\n orderedEntries.map(async ({ index: idx, key, value }) => {\r\n if (value instanceof File) {\r\n const buffer = await value.arrayBuffer()\r\n const serializedFile: SerializedFile = {\r\n name: value.name,\r\n type: value.type,\r\n buffer\r\n }\r\n // Store with index for sorting later\r\n entries[idx] = [key, serializedFile]\r\n transferables.push(buffer)\r\n } else {\r\n entries[idx] = [key, String(value)]\r\n }\r\n })\r\n )\r\n\r\n return {\r\n data: {\r\n _type: 'FormData',\r\n entries\r\n },\r\n transferables\r\n }\r\n}\r\n\r\n/**\r\n * Deserialize SerializedFormData back to FormData in worker\r\n * Reconstructs File objects from transferred ArrayBuffers\r\n */\r\nexport function deserializeFormData(serialized: SerializedFormData): FormData {\r\n const formData = new FormData()\r\n\r\n for (const [key, value] of serialized.entries) {\r\n if (typeof value === 'string') {\r\n formData.append(key, value)\r\n } else {\r\n // Reconstruct File from SerializedFile (ArrayBuffer already transferred)\r\n const file = new File([value.buffer], value.name, { type: value.type })\r\n formData.append(key, file)\r\n }\r\n }\r\n\r\n return formData\r\n}\r\n\r\n/**\r\n * Check if body is FormData\r\n */\r\nexport function isFormData(body: unknown): body is FormData {\r\n return body instanceof FormData\r\n}\r\n\r\n/**\r\n * Check if serialized body is SerializedFormData\r\n */\r\nexport function isSerializedFormData(body: unknown): body is SerializedFormData {\r\n return body !== null && typeof body === 'object' && (body as SerializedFormData)._type === 'FormData'\r\n}\r\n","/**\r\n * Binary data utilities for Worker\r\n * Handles ArrayBuffer <-> Base64 conversion for binary responses\r\n */\r\n\r\n/**\r\n * Convert ArrayBuffer to base64 string\r\n * Used in worker to encode binary responses for postMessage transfer\r\n */\r\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\r\n const bytes = new Uint8Array(buffer)\r\n let binary = ''\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i])\r\n }\r\n return btoa(binary)\r\n}\r\n\r\n/**\r\n * Convert base64 string to ArrayBuffer\r\n * Used in client to decode binary responses\r\n */\r\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\r\n const binary = atob(base64)\r\n const bytes = new Uint8Array(binary.length)\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i)\r\n }\r\n return bytes.buffer\r\n}\r\n\r\n/**\r\n * Check if content type is binary (should be base64 encoded)\r\n * Returns true for images, PDFs, videos, etc.\r\n */\r\nexport function isBinaryContentType(contentType: string): boolean {\r\n const normalized = contentType.toLowerCase()\r\n\r\n // Text types - NOT binary\r\n if (normalized.includes('text/')) return false\r\n if (normalized.includes('json')) return false\r\n if (normalized.includes('xml')) return false\r\n if (normalized.includes('javascript')) return false\r\n if (normalized.includes('ecmascript')) return false\r\n if (normalized.includes('html')) return false\r\n\r\n // Everything else is considered binary\r\n return true\r\n}\r\n"],"mappings":"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","names":["ok","err","err","ok"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetchguard",
3
- "version": "2.1.2",
3
+ "version": "2.2.1",
4
4
  "description": "A secure fetch API library that runs in Web Workers with automatic token management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",