@nauth-toolkit/client 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -862,7 +862,9 @@ var NAuthClient = class {
862
862
  */
863
863
  async confirmForgotPassword(identifier, code, newPassword) {
864
864
  const payload = { identifier, code, newPassword };
865
- return this.post(this.config.endpoints.confirmForgotPassword, payload);
865
+ const result = await this.post(this.config.endpoints.confirmForgotPassword, payload);
866
+ await this.clearAuthState(false);
867
+ return result;
866
868
  }
867
869
  /**
868
870
  * Request password change (must change on next login).
@@ -998,11 +1000,9 @@ var NAuthClient = class {
998
1000
  const base = this.config.baseUrl.replace(/\/$/, "");
999
1001
  const startUrl = new URL(`${base}${startPath}`);
1000
1002
  const returnTo = options?.returnTo ?? this.config.redirects?.success ?? "/";
1001
- const action = options?.action ?? "login";
1002
1003
  startUrl.searchParams.set("returnTo", returnTo);
1003
- startUrl.searchParams.set("action", action);
1004
- if (options?.delivery === "cookies" || options?.delivery === "json") {
1005
- startUrl.searchParams.set("delivery", options.delivery);
1004
+ if (options?.action === "link") {
1005
+ startUrl.searchParams.set("action", "link");
1006
1006
  }
1007
1007
  if (typeof options?.appState === "string" && options.appState.trim() !== "") {
1008
1008
  startUrl.searchParams.set("appState", options.appState);
@@ -1213,7 +1213,9 @@ var NAuthClient = class {
1213
1213
  await this.setDeviceToken(response.deviceToken);
1214
1214
  }
1215
1215
  if (response.user) {
1216
- await this.setUser(response.user);
1216
+ const user = response.user;
1217
+ user.sessionAuthMethod = response.authMethod ?? null;
1218
+ await this.setUser(user);
1217
1219
  }
1218
1220
  await this.clearChallenge();
1219
1221
  }
@@ -1285,6 +1287,15 @@ var NAuthClient = class {
1285
1287
  headers["Authorization"] = `Bearer ${accessToken}`;
1286
1288
  }
1287
1289
  }
1290
+ if (this.config.tokenDelivery === "json") {
1291
+ try {
1292
+ const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);
1293
+ if (deviceToken) {
1294
+ headers[this.config.deviceTrust.headerName] = deviceToken;
1295
+ }
1296
+ } catch {
1297
+ }
1298
+ }
1288
1299
  if (this.config.tokenDelivery === "cookies" && hasWindow()) {
1289
1300
  const csrfToken = this.getCsrfToken();
1290
1301
  if (csrfToken) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types/auth.types.ts","../src/types/error.types.ts","../src/types/audit.types.ts","../src/core/config.ts","../src/core/errors.ts","../src/core/refresh.ts","../src/storage/browser.ts","../src/storage/memory.ts","../src/core/events.ts","../src/adapters/fetch-adapter.ts","../src/core/client.ts","../src/core/challenge-helpers.ts"],"sourcesContent":["export * from './types';\nexport * from './core/client';\nexport * from './core/config';\nexport * from './core/errors';\nexport * from './core/events';\nexport * from './core/http-adapter';\nexport * from './core/challenge-helpers';\nexport * from './storage/interface';\nexport * from './storage/browser';\nexport * from './storage/memory';\nexport * from './adapters/fetch-adapter';\n","/**\n * Authentication challenge types returned by the backend.\n */\nexport enum AuthChallenge {\n VERIFY_EMAIL = 'VERIFY_EMAIL',\n VERIFY_PHONE = 'VERIFY_PHONE',\n MFA_REQUIRED = 'MFA_REQUIRED',\n MFA_SETUP_REQUIRED = 'MFA_SETUP_REQUIRED',\n FORCE_CHANGE_PASSWORD = 'FORCE_CHANGE_PASSWORD',\n}\n\n/**\n * Auth response returned by backend for all auth operations.\n * Either contains tokens/user or a challenge to complete.\n */\nimport { MFAMethod, MFAChallengeMethod } from './mfa.types';\n\nexport interface AuthResponse {\n user?: AuthUserSummary;\n accessToken?: string;\n refreshToken?: string;\n accessTokenExpiresAt?: number;\n refreshTokenExpiresAt?: number;\n trusted?: boolean;\n deviceToken?: string;\n challengeName?: AuthChallenge;\n session?: string;\n challengeParameters?: Record<string, unknown>;\n userSub?: string;\n}\n\n/**\n * Minimal user information returned inside auth responses.\n */\nexport interface AuthUserSummary {\n sub: string;\n email: string;\n firstName?: string | null;\n lastName?: string | null;\n phone?: string | null;\n isEmailVerified: boolean;\n isPhoneVerified?: boolean;\n socialProviders?: string[] | null;\n hasPasswordHash?: boolean;\n}\n\n/**\n * Token response returned by refresh endpoint.\n */\nexport interface TokenResponse {\n accessToken: string;\n refreshToken: string;\n accessTokenExpiresAt: number;\n refreshTokenExpiresAt: number;\n}\n\n/**\n * Signup request payload.\n */\nexport interface SignupRequest {\n email: string;\n password: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Login request payload.\n */\nexport interface LoginRequest {\n identifier: string;\n password: string;\n}\n\n/**\n * Logout request payload.\n */\nexport interface LogoutRequest {\n sub?: string;\n forgetMe?: boolean;\n}\n\n/**\n * Logout all sessions request payload.\n */\nexport interface LogoutAllRequest {\n /**\n * Whether to also revoke all trusted devices\n * Default: false (devices remain trusted)\n */\n forgetDevices?: boolean;\n sub?: string;\n}\n\n/**\n * Resend code request payload.\n */\nexport interface ResendCodeRequest {\n session: string;\n}\n\n/**\n * MFA setup data request payload during challenge flows.\n */\nexport interface GetSetupDataRequest {\n session: string;\n method: MFAMethod;\n}\n\n/**\n * Challenge data request payload (e.g., passkey options).\n */\nexport interface GetChallengeDataRequest {\n session: string;\n method: MFAChallengeMethod;\n}\n\n/**\n * Unified challenge response discriminated union.\n */\nexport type ChallengeResponse =\n | VerifyEmailResponse\n | VerifyPhoneCollectResponse\n | VerifyPhoneCodeResponse\n | MFACodeResponse\n | MFAPasskeyResponse\n | MFASetupResponse\n | ForceChangePasswordResponse;\n\n/**\n * Base challenge response shape.\n */\nexport interface BaseChallengeResponse {\n session: string;\n}\n\nexport interface VerifyEmailResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_EMAIL;\n code: string;\n}\n\nexport interface VerifyPhoneCollectResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_PHONE;\n phone: string;\n}\n\nexport interface VerifyPhoneCodeResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_PHONE;\n code: string;\n}\n\nexport interface MFACodeResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_REQUIRED;\n method: MFAMethod;\n code: string;\n}\n\nexport interface MFAPasskeyResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_REQUIRED;\n method: 'passkey';\n credential: Record<string, unknown>;\n}\n\nexport interface MFASetupResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_SETUP_REQUIRED;\n method: MFAMethod;\n setupData: Record<string, unknown>;\n}\n\nexport interface ForceChangePasswordResponse extends BaseChallengeResponse {\n type: AuthChallenge.FORCE_CHANGE_PASSWORD;\n newPassword: string;\n}\n\n// MFAMethod and MFAChallengeMethod are imported from mfa.types\n","/**\n * Standardized error codes mirroring backend AuthErrorCode.\n */\nexport enum NAuthErrorCode {\n // Authentication Errors\n AUTH_INVALID_CREDENTIALS = 'AUTH_INVALID_CREDENTIALS',\n AUTH_ACCOUNT_LOCKED = 'AUTH_ACCOUNT_LOCKED',\n AUTH_ACCOUNT_INACTIVE = 'AUTH_ACCOUNT_INACTIVE',\n AUTH_TOKEN_EXPIRED = 'AUTH_TOKEN_EXPIRED',\n AUTH_TOKEN_INVALID = 'AUTH_TOKEN_INVALID',\n AUTH_BEARER_NOT_ALLOWED = 'AUTH_BEARER_NOT_ALLOWED',\n AUTH_COOKIES_NOT_ALLOWED = 'AUTH_COOKIES_NOT_ALLOWED',\n AUTH_CSRF_TOKEN_INVALID = 'AUTH_CSRF_TOKEN_INVALID',\n AUTH_CSRF_TOKEN_MISSING = 'AUTH_CSRF_TOKEN_MISSING',\n AUTH_TOKEN_REUSE_DETECTED = 'AUTH_TOKEN_REUSE_DETECTED',\n AUTH_SESSION_NOT_FOUND = 'AUTH_SESSION_NOT_FOUND',\n AUTH_SESSION_EXPIRED = 'AUTH_SESSION_EXPIRED',\n\n // Signup Errors\n SIGNUP_DISABLED = 'SIGNUP_DISABLED',\n SIGNUP_EMAIL_EXISTS = 'SIGNUP_EMAIL_EXISTS',\n SIGNUP_USERNAME_EXISTS = 'SIGNUP_USERNAME_EXISTS',\n SIGNUP_PHONE_EXISTS = 'SIGNUP_PHONE_EXISTS',\n SIGNUP_WEAK_PASSWORD = 'SIGNUP_WEAK_PASSWORD',\n SIGNUP_PHONE_REQUIRED = 'SIGNUP_PHONE_REQUIRED',\n SIGNUP_NOT_ALLOWED = 'SIGNUP_NOT_ALLOWED',\n\n // Verification Errors\n VERIFY_CODE_INVALID = 'VERIFY_CODE_INVALID',\n VERIFY_CODE_EXPIRED = 'VERIFY_CODE_EXPIRED',\n VERIFY_TOO_MANY_ATTEMPTS = 'VERIFY_TOO_MANY_ATTEMPTS',\n VERIFY_ALREADY_VERIFIED = 'VERIFY_ALREADY_VERIFIED',\n\n // MFA Errors\n MFA_SETUP_REQUIRED = 'MFA_SETUP_REQUIRED',\n\n // Rate Limit Errors\n RATE_LIMIT_SMS = 'RATE_LIMIT_SMS',\n RATE_LIMIT_EMAIL = 'RATE_LIMIT_EMAIL',\n RATE_LIMIT_LOGIN = 'RATE_LIMIT_LOGIN',\n RATE_LIMIT_RESEND = 'RATE_LIMIT_RESEND',\n\n // Social Auth Errors\n SOCIAL_TOKEN_INVALID = 'SOCIAL_TOKEN_INVALID',\n SOCIAL_ACCOUNT_LINKED = 'SOCIAL_ACCOUNT_LINKED',\n SOCIAL_CONFIG_MISSING = 'SOCIAL_CONFIG_MISSING',\n SOCIAL_EMAIL_REQUIRED = 'SOCIAL_EMAIL_REQUIRED',\n SOCIAL_ACCOUNT_NOT_FOUND = 'SOCIAL_ACCOUNT_NOT_FOUND',\n\n // Challenge Errors\n CHALLENGE_EXPIRED = 'CHALLENGE_EXPIRED',\n CHALLENGE_INVALID = 'CHALLENGE_INVALID',\n CHALLENGE_TYPE_MISMATCH = 'CHALLENGE_TYPE_MISMATCH',\n CHALLENGE_MAX_ATTEMPTS = 'CHALLENGE_MAX_ATTEMPTS',\n CHALLENGE_ALREADY_COMPLETED = 'CHALLENGE_ALREADY_COMPLETED',\n\n // Validation Errors\n VALIDATION_FAILED = 'VALIDATION_FAILED',\n VALIDATION_INVALID_PHONE = 'VALIDATION_INVALID_PHONE',\n VALIDATION_INVALID_EMAIL = 'VALIDATION_INVALID_EMAIL',\n VALIDATION_INVALID_PASSWORD = 'VALIDATION_INVALID_PASSWORD',\n\n // Password Errors\n PASSWORD_INCORRECT = 'PASSWORD_INCORRECT',\n PASSWORD_REUSED = 'PASSWORD_REUSED',\n PASSWORD_CHANGE_NOT_ALLOWED = 'PASSWORD_CHANGE_NOT_ALLOWED',\n WEAK_PASSWORD = 'SIGNUP_WEAK_PASSWORD',\n PASSWORD_RESET_CODE_INVALID = 'PASSWORD_RESET_CODE_INVALID',\n PASSWORD_RESET_CODE_EXPIRED = 'PASSWORD_RESET_CODE_EXPIRED',\n PASSWORD_RESET_MAX_ATTEMPTS = 'PASSWORD_RESET_MAX_ATTEMPTS',\n RATE_LIMIT_PASSWORD_RESET = 'RATE_LIMIT_PASSWORD_RESET',\n\n // Adaptive MFA\n SIGNIN_BLOCKED_HIGH_RISK = 'SIGNIN_BLOCKED_HIGH_RISK',\n\n // General Errors\n RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',\n FORBIDDEN = 'FORBIDDEN',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',\n}\n\n/**\n * Structured client error.\n */\nexport interface NAuthError {\n code: NAuthErrorCode;\n message: string;\n details?: Record<string, unknown>;\n timestamp?: string;\n statusCode?: number;\n}\n","/**\n * Audit event types.\n */\nexport enum AuthAuditEventType {\n // Authentication events\n LOGIN_SUCCESS = 'LOGIN_SUCCESS',\n LOGIN_FAILED = 'LOGIN_FAILED',\n LOGOUT = 'LOGOUT',\n TOKEN_REFRESH = 'TOKEN_REFRESH',\n TOKEN_REVOKED = 'TOKEN_REVOKED',\n\n // Registration events\n SIGNUP_SUCCESS = 'SIGNUP_SUCCESS',\n SIGNUP_FAILED = 'SIGNUP_FAILED',\n\n // Verification events\n EMAIL_VERIFIED = 'EMAIL_VERIFIED',\n PHONE_VERIFIED = 'PHONE_VERIFIED',\n VERIFICATION_FAILED = 'VERIFICATION_FAILED',\n\n // MFA events\n MFA_ENABLED = 'MFA_ENABLED',\n MFA_DISABLED = 'MFA_DISABLED',\n MFA_VERIFIED = 'MFA_VERIFIED',\n MFA_FAILED = 'MFA_FAILED',\n MFA_BACKUP_CODE_USED = 'MFA_BACKUP_CODE_USED',\n\n // Password events\n PASSWORD_CHANGED = 'PASSWORD_CHANGED',\n PASSWORD_RESET_REQUESTED = 'PASSWORD_RESET_REQUESTED',\n PASSWORD_RESET_COMPLETED = 'PASSWORD_RESET_COMPLETED',\n\n // Security events\n ACCOUNT_LOCKED = 'ACCOUNT_LOCKED',\n ACCOUNT_UNLOCKED = 'ACCOUNT_UNLOCKED',\n SUSPICIOUS_ACTIVITY = 'SUSPICIOUS_ACTIVITY',\n ADAPTIVE_MFA_TRIGGERED = 'ADAPTIVE_MFA_TRIGGERED',\n\n // Social auth events\n SOCIAL_LINK_SUCCESS = 'SOCIAL_LINK_SUCCESS',\n SOCIAL_LINK_FAILED = 'SOCIAL_LINK_FAILED',\n SOCIAL_UNLINK = 'SOCIAL_UNLINK',\n}\n\n/**\n * Audit event status.\n */\nexport type AuthAuditEventStatus = 'SUCCESS' | 'FAILURE' | 'INFO' | 'SUSPICIOUS';\n\n/**\n * Individual audit event record.\n */\nexport interface AuthAuditEvent {\n id: number;\n userId: number;\n eventType: AuthAuditEventType;\n eventStatus: AuthAuditEventStatus;\n riskFactor?: number | null;\n riskFactors?: string[] | null;\n adaptiveMfaTriggered?: boolean | null;\n ipAddress?: string | null;\n ipCountry?: string | null;\n ipCity?: string | null;\n ipLatitude?: number | null;\n ipLongitude?: number | null;\n userAgent?: string | null;\n platform?: string | null;\n browser?: string | null;\n deviceId?: string | null;\n deviceName?: string | null;\n deviceType?: string | null;\n sessionId?: number | null;\n challengeSessionId?: number | null;\n authMethod?: string | null;\n performedBy?: string | null;\n reason?: string | null;\n description?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: string | Date;\n}\n\n/**\n * Paginated audit history response.\n */\nexport interface AuditHistoryResponse {\n data: AuthAuditEvent[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n","import {\n NAuthClientConfig,\n NAuthEndpoints,\n NAuthStorageAdapter,\n TokenDeliveryMode,\n HttpAdapter,\n} from '../types/config.types';\n\n/**\n * Fully resolved configuration with all defaults applied.\n */\nexport type ResolvedNAuthClientConfig = Omit<\n NAuthClientConfig,\n 'endpoints' | 'storage' | 'tokenDelivery' | 'httpAdapter'\n> & {\n tokenDelivery: TokenDeliveryMode;\n endpoints: NAuthEndpoints;\n storage: NAuthStorageAdapter;\n httpAdapter: HttpAdapter;\n csrf: { cookieName: string; headerName: string };\n deviceTrust: { headerName: string; storageKey: string };\n headers: Record<string, string>;\n timeout: number;\n};\n\n/**\n * Default endpoint paths matching backend controller.\n */\nexport const defaultEndpoints: NAuthEndpoints = {\n login: '/login',\n signup: '/signup',\n logout: '/logout',\n logoutAll: '/logout/all',\n refresh: '/refresh',\n respondChallenge: '/respond-challenge',\n resendCode: '/challenge/resend',\n getSetupData: '/challenge/setup-data',\n getChallengeData: '/challenge/challenge-data',\n profile: '/profile',\n changePassword: '/change-password',\n requestPasswordChange: '/request-password-change',\n forgotPassword: '/forgot-password',\n confirmForgotPassword: '/forgot-password/confirm',\n mfaStatus: '/mfa/status',\n mfaDevices: '/mfa/devices',\n mfaSetupData: '/mfa/setup-data',\n mfaVerifySetup: '/mfa/verify-setup',\n mfaRemove: '/mfa/method',\n mfaPreferred: '/mfa/preferred-method',\n mfaBackupCodes: '/mfa/backup-codes/generate',\n mfaExemption: '/mfa/exemption',\n socialLinked: '/social/linked',\n socialLink: '/social/link',\n socialUnlink: '/social/unlink',\n socialVerify: '/social/:provider/verify',\n socialRedirectStart: '/social/:provider/redirect',\n socialExchange: '/social/exchange',\n trustDevice: '/trust-device',\n isTrustedDevice: '/is-trusted-device',\n auditHistory: '/audit/history',\n updateProfile: '/profile',\n};\n\n/**\n * Normalize user config with defaults.\n *\n * @param config - User supplied config\n * @param defaultAdapter - Default HTTP adapter (FetchAdapter for vanilla, AngularHttpAdapter for Angular)\n * @returns Resolved config with defaults applied\n */\nexport const resolveConfig = (config: NAuthClientConfig, defaultAdapter: HttpAdapter): ResolvedNAuthClientConfig => {\n const resolvedEndpoints: NAuthEndpoints = {\n ...defaultEndpoints,\n ...(config.endpoints ?? {}),\n };\n\n return {\n ...config,\n csrf: {\n cookieName: config.csrf?.cookieName ?? 'nauth_csrf_token',\n headerName: config.csrf?.headerName ?? 'x-csrf-token',\n },\n deviceTrust: {\n headerName: config.deviceTrust?.headerName ?? 'X-Device-Token',\n storageKey: config.deviceTrust?.storageKey ?? 'nauth_device_token',\n },\n headers: config.headers ?? {},\n timeout: config.timeout ?? 30000,\n endpoints: resolvedEndpoints,\n storage: config.storage as NAuthStorageAdapter,\n httpAdapter: config.httpAdapter ?? defaultAdapter,\n };\n};\n","import { NAuthError, NAuthErrorCode } from '../types/error.types';\n\n/**\n * Client-side error wrapper for SDK operations.\n *\n * Mirrors the backend NAuthException structure for consistent error handling.\n *\n * @example\n * ```typescript\n * try {\n * await client.login({ identifier: 'user@example.com', password: 'wrong' });\n * } catch (error) {\n * if (error instanceof NAuthClientError) {\n * console.log(error.code); // 'AUTH_INVALID_CREDENTIALS'\n * console.log(error.message); // 'Invalid credentials'\n * console.log(error.timestamp); // '2025-12-06T...'\n *\n * // Check specific error code\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_LOGIN)) {\n * const retryAfter = error.details?.retryAfter as number;\n * console.log(`Rate limited. Retry in ${retryAfter}s`);\n * }\n * }\n * }\n * ```\n */\nexport class NAuthClientError extends Error implements NAuthError {\n public readonly code: NAuthErrorCode;\n public readonly details?: Record<string, unknown>;\n public readonly statusCode?: number;\n public readonly timestamp: string;\n public readonly isNetworkError: boolean;\n\n /**\n * Create a new client error.\n *\n * @param code - Error code from NAuthErrorCode enum\n * @param message - Human-readable error message\n * @param options - Optional metadata including details, statusCode, timestamp, and network error flag\n */\n constructor(\n code: NAuthErrorCode,\n message: string,\n options?: {\n details?: Record<string, unknown>;\n statusCode?: number;\n timestamp?: string;\n isNetworkError?: boolean;\n },\n ) {\n super(message);\n this.code = code;\n this.details = options?.details;\n this.statusCode = options?.statusCode;\n this.timestamp = options?.timestamp || new Date().toISOString();\n this.isNetworkError = options?.isNetworkError ?? false;\n this.name = 'NAuthClientError';\n Object.setPrototypeOf(this, NAuthClientError.prototype);\n }\n\n /**\n * Check if error matches a specific error code.\n *\n * @param code - Error code to check against\n * @returns True if the error code matches\n *\n * @example\n * ```typescript\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_SMS)) {\n * // Handle SMS rate limit\n * }\n * ```\n */\n isCode(code: NAuthErrorCode): boolean {\n return this.code === code;\n }\n\n /**\n * Get error details/metadata.\n *\n * @returns Error details object or undefined\n *\n * @example\n * ```typescript\n * const details = error.getDetails();\n * if (details?.retryAfter) {\n * console.log(`Retry after ${details.retryAfter} seconds`);\n * }\n * ```\n */\n getDetails(): Record<string, unknown> | undefined {\n return this.details;\n }\n\n /**\n * Get the error code.\n *\n * @returns The error code enum value\n */\n getCode(): NAuthErrorCode {\n return this.code;\n }\n\n /**\n * Serialize error to JSON object.\n *\n * @returns Plain object representation\n *\n * @example\n * ```typescript\n * const errorJson = error.toJSON();\n * // { code: 'AUTH_INVALID_CREDENTIALS', message: '...', timestamp: '...', details: {...} }\n * ```\n */\n toJSON(): {\n code: string;\n message: string;\n timestamp: string;\n details?: Record<string, unknown>;\n statusCode?: number;\n } {\n return {\n code: this.code,\n message: this.message,\n timestamp: this.timestamp,\n details: this.details,\n statusCode: this.statusCode,\n };\n }\n}\n","import { TokenResponse } from '../types/auth.types';\nimport { NAuthStorageAdapter } from '../types/config.types';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\nconst ACCESS_TOKEN_KEY = 'nauth_access_token';\nconst REFRESH_TOKEN_KEY = 'nauth_refresh_token';\nconst ACCESS_EXPIRES_AT_KEY = 'nauth_access_token_expires_at';\nconst REFRESH_EXPIRES_AT_KEY = 'nauth_refresh_token_expires_at';\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\n\n/**\n * Token state persisted in storage.\n */\nexport interface TokenState {\n accessToken: string | null;\n refreshToken: string | null;\n accessTokenExpiresAt?: number | null;\n refreshTokenExpiresAt?: number | null;\n}\n\n/**\n * Manage token persistence and refresh queuing.\n */\nexport class TokenManager {\n private readonly storage: NAuthStorageAdapter;\n private refreshPromise: Promise<TokenResponse> | null = null;\n private readonly isBrowser = typeof window !== 'undefined';\n\n /**\n * @param storage - storage adapter\n */\n constructor(storage: NAuthStorageAdapter) {\n this.storage = storage;\n }\n\n /**\n * Load tokens from storage.\n */\n async getTokens(): Promise<TokenState> {\n const [accessToken, refreshToken, accessExpRaw, refreshExpRaw] = await Promise.all([\n this.storage.getItem(ACCESS_TOKEN_KEY),\n this.storage.getItem(REFRESH_TOKEN_KEY),\n this.storage.getItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.getItem(REFRESH_EXPIRES_AT_KEY),\n ]);\n return {\n accessToken,\n refreshToken,\n accessTokenExpiresAt: accessExpRaw ? Number(accessExpRaw) : null,\n refreshTokenExpiresAt: refreshExpRaw ? Number(refreshExpRaw) : null,\n };\n }\n\n /**\n * Persist tokens.\n *\n * @param tokens - new token pair\n */\n async setTokens(tokens: TokenResponse): Promise<void> {\n await Promise.all([\n this.storage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken),\n this.storage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken),\n this.storage.setItem(ACCESS_EXPIRES_AT_KEY, tokens.accessTokenExpiresAt.toString()),\n this.storage.setItem(REFRESH_EXPIRES_AT_KEY, tokens.refreshTokenExpiresAt.toString()),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Clear tokens and related auth state.\n */\n async clearTokens(): Promise<void> {\n await Promise.all([\n this.storage.removeItem(ACCESS_TOKEN_KEY),\n this.storage.removeItem(REFRESH_TOKEN_KEY),\n this.storage.removeItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.removeItem(REFRESH_EXPIRES_AT_KEY),\n this.storage.removeItem(USER_KEY),\n this.storage.removeItem(CHALLENGE_KEY),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Ensure only one refresh in flight.\n *\n * @param refreshFn - function performing refresh request\n */\n async refreshOnce(refreshFn: () => Promise<TokenResponse>): Promise<TokenResponse> {\n if (!this.refreshPromise) {\n this.refreshPromise = refreshFn()\n .then(async (tokens) => {\n await this.setTokens(tokens);\n return tokens;\n })\n .catch((error) => {\n throw error;\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /**\n * Validate that a refresh token exists before attempting refresh.\n */\n async assertHasRefreshToken(): Promise<void> {\n const state = await this.getTokens();\n if (!state.refreshToken) {\n throw new NAuthClientError(NAuthErrorCode.AUTH_SESSION_NOT_FOUND, 'No refresh token available');\n }\n }\n\n /**\n * Broadcast a no-op write to trigger storage listeners in other tabs.\n */\n private broadcastStorage(): void {\n if (!this.isBrowser) return;\n try {\n window.localStorage.setItem('nauth_sync', Date.now().toString());\n } catch {\n // Best-effort; ignore if storage unavailable\n }\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * Browser storage adapter wrapping localStorage or sessionStorage.\n */\nexport class BrowserStorage implements NAuthStorageAdapter {\n private readonly storage: Storage;\n\n /**\n * Create a browser storage adapter.\n *\n * @param storage - Storage implementation (localStorage by default)\n */\n constructor(storage: Storage = window.localStorage) {\n this.storage = storage;\n }\n\n async getItem(key: string): Promise<string | null> {\n return this.storage.getItem(key);\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.storage.setItem(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * In-memory storage adapter for SSR, tests, or environments without Web Storage.\n */\nexport class InMemoryStorage implements NAuthStorageAdapter {\n private readonly store = new Map<string, string>();\n\n async getItem(key: string): Promise<string | null> {\n return this.store.has(key) ? (this.store.get(key) as string) : null;\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.store.set(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n}\n","import type { AuthResponse } from '../types/auth.types';\nimport type { NAuthClientError } from './errors';\n\n/**\n * Authentication event types emitted by NAuthClient\n *\n * Events are emitted throughout the authentication lifecycle,\n * allowing applications to react to auth state changes.\n */\nexport type AuthEventType =\n | 'auth:login'\n | 'auth:signup'\n | 'auth:success'\n | 'auth:challenge'\n | 'auth:error'\n | 'auth:logout'\n | 'auth:refresh'\n | 'oauth:started'\n | 'oauth:callback'\n | 'oauth:completed'\n | 'oauth:error';\n\n/**\n * Discriminated union of all authentication events with type-safe payloads\n *\n * Each event has a specific payload type for better type safety.\n */\nexport type AuthEvent =\n | AuthLoginEvent\n | AuthSignupEvent\n | AuthSuccessEvent\n | AuthChallengeEvent\n | AuthErrorEvent\n | AuthLogoutEvent\n | AuthRefreshEvent\n | OAuthStartedEvent\n | OAuthCallbackEvent\n | OAuthCompletedEvent\n | OAuthErrorEvent;\n\n/**\n * Login initiated event\n */\nexport interface AuthLoginEvent {\n type: 'auth:login';\n data: {\n identifier: string;\n };\n timestamp: number;\n}\n\n/**\n * Signup initiated event\n */\nexport interface AuthSignupEvent {\n type: 'auth:signup';\n data: {\n email: string;\n };\n timestamp: number;\n}\n\n/**\n * Successful authentication event\n */\nexport interface AuthSuccessEvent {\n type: 'auth:success';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Challenge required event\n */\nexport interface AuthChallengeEvent {\n type: 'auth:challenge';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Authentication error event\n */\nexport interface AuthErrorEvent {\n type: 'auth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * User logged out event\n */\nexport interface AuthLogoutEvent {\n type: 'auth:logout';\n data: {\n forgetDevice?: boolean;\n global?: boolean;\n };\n timestamp: number;\n}\n\n/**\n * Token refreshed event\n */\nexport interface AuthRefreshEvent {\n type: 'auth:refresh';\n data: {\n success: boolean;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow started event\n */\nexport interface OAuthStartedEvent {\n type: 'oauth:started';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth callback received event\n */\nexport interface OAuthCallbackEvent {\n type: 'oauth:callback';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow completed event\n */\nexport interface OAuthCompletedEvent {\n type: 'oauth:completed';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * OAuth error event\n */\nexport interface OAuthErrorEvent {\n type: 'oauth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * Event listener callback function\n */\nexport type AuthEventListener = (event: AuthEvent) => void;\n\n/**\n * Internal event emitter for authentication events\n *\n * Provides pub/sub functionality for auth lifecycle events.\n *\n * @internal\n */\nexport class EventEmitter {\n private listeners = new Map<AuthEventType | '*', Set<AuthEventListener>>();\n\n /**\n * Subscribe to an authentication event\n *\n * @param event - Event type or '*' for all events\n * @param listener - Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = emitter.on('auth:success', (event) => {\n * console.log('User logged in:', event.data);\n * });\n *\n * // Later\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => this.off(event, listener);\n }\n\n /**\n * Unsubscribe from an authentication event\n *\n * @param event - Event type or '*'\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n /**\n * Emit an authentication event\n *\n * Notifies all listeners for the specific event type and wildcard listeners.\n *\n * @param event - Event to emit\n * @internal\n */\n emit(event: AuthEvent): void {\n const specificListeners = this.listeners.get(event.type);\n const wildcardListeners = this.listeners.get('*');\n\n // Emit to specific event listeners\n specificListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in ${event.type} event listener:`, error);\n }\n });\n\n // Emit to wildcard listeners\n wildcardListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in wildcard event listener:`, error);\n }\n });\n }\n\n /**\n * Remove all listeners\n *\n * @internal\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n","import { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter using native fetch API.\n *\n * Suitable for:\n * - Vanilla JavaScript/TypeScript\n * - Node.js (with fetch polyfill or Node 18+)\n * - Environments without framework-specific HTTP clients\n *\n * @example\n * ```typescript\n * import { NAuthClient } from '@nauth-toolkit/client';\n * import { FetchAdapter } from '@nauth-toolkit/client/adapters/fetch';\n *\n * const client = new NAuthClient({\n * baseUrl: 'https://api.example.com/auth',\n * httpAdapter: new FetchAdapter(),\n * });\n * ```\n */\nexport class FetchAdapter implements HttpAdapter {\n /**\n * Execute HTTP request using native fetch.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n const fetchOptions: RequestInit = {\n method: config.method,\n headers: config.headers,\n signal: config.signal,\n credentials: config.credentials,\n };\n\n if (config.body !== undefined) {\n fetchOptions.body = JSON.stringify(config.body);\n }\n\n let response: Response;\n try {\n response = await fetch(config.url, fetchOptions);\n } catch (error) {\n throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, 'Network request failed', {\n isNetworkError: true,\n details: { url: config.url, message: (error as Error).message },\n });\n }\n\n const status = response.status;\n let data: unknown = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n // Extract headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n if (!response.ok) {\n const errorData = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n const code =\n typeof errorData['code'] === 'string'\n ? (errorData['code'] as NAuthErrorCode)\n : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData['message'] as string)\n : `Request failed with status ${status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? (errorData['timestamp'] as string) : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: status,\n timestamp,\n details,\n });\n }\n\n return { data: data as T, status, headers };\n }\n}\n\n\n\n","import { resolveConfig, ResolvedNAuthClientConfig } from './config';\nimport { TokenManager } from './refresh';\nimport { BrowserStorage } from '../storage/browser';\nimport { InMemoryStorage } from '../storage/memory';\nimport { EventEmitter, AuthEventType, AuthEventListener } from './events';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\nimport { FetchAdapter } from '../adapters/fetch-adapter';\nimport {\n AuthChallenge,\n ChallengeResponse,\n GetChallengeDataRequest,\n GetSetupDataRequest,\n LoginRequest,\n LogoutAllRequest,\n AuthResponse,\n ResendCodeRequest,\n SignupRequest,\n TokenResponse,\n} from '../types/auth.types';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse, MFAStatus } from '../types/mfa.types';\nimport {\n LinkedAccountsResponse,\n SocialLoginOptions,\n SocialVerifyRequest,\n SocialProvider,\n} from '../types/social.types';\nimport {\n AuthUser,\n ChangePasswordRequest,\n ConfirmForgotPasswordRequest,\n ConfirmForgotPasswordResponse,\n ForgotPasswordRequest,\n ForgotPasswordResponse,\n UpdateProfileRequest,\n} from '../types/user.types';\nimport { AuditHistoryResponse } from '../types/audit.types';\n\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\nconst hasWindow = (): boolean =>\n typeof globalThis !== 'undefined' && typeof (globalThis as { window?: unknown }).window !== 'undefined';\n\n/**\n * Choose default storage implementation.\n */\nconst defaultStorage = () => {\n if (hasWindow() && typeof window.localStorage !== 'undefined') {\n return new BrowserStorage();\n }\n return new InMemoryStorage();\n};\n\n/**\n * Primary client for interacting with nauth-toolkit backend.\n */\nexport class NAuthClient {\n private readonly config: ResolvedNAuthClientConfig;\n private readonly tokenManager: TokenManager;\n private readonly eventEmitter: EventEmitter;\n private currentUser: AuthUser | null = null;\n\n /**\n * Create a new client instance.\n *\n * @param userConfig - Client configuration\n */\n constructor(userConfig: NAuthClientConfig) {\n const storage = userConfig.storage ?? defaultStorage();\n const defaultAdapter = userConfig.httpAdapter ?? new FetchAdapter();\n this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);\n this.tokenManager = new TokenManager(storage);\n this.eventEmitter = new EventEmitter();\n if (hasWindow()) {\n window.addEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (hasWindow()) {\n window.removeEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Login with identifier and password.\n */\n async login(identifier: string, password: string): Promise<AuthResponse> {\n const loginEvent = { type: 'auth:login' as const, data: { identifier }, timestamp: Date.now() };\n this.eventEmitter.emit(loginEvent);\n\n try {\n const body: LoginRequest = { identifier, password };\n const response = await this.post<AuthResponse>(this.config.endpoints.login, body);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Login failed');\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Signup with credentials.\n */\n async signup(payload: SignupRequest): Promise<AuthResponse> {\n this.eventEmitter.emit({ type: 'auth:signup', data: { email: payload.email }, timestamp: Date.now() });\n\n try {\n const response = await this.post<AuthResponse>(this.config.endpoints.signup, payload);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n this.eventEmitter.emit({ type: 'auth:challenge', data: response, timestamp: Date.now() });\n } else {\n this.eventEmitter.emit({ type: 'auth:success', data: response, timestamp: Date.now() });\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Signup failed');\n this.eventEmitter.emit({ type: 'auth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n }\n\n /**\n * Refresh tokens manually.\n */\n async refreshTokens(): Promise<TokenResponse> {\n const tokenDelivery = this.getTokenDeliveryMode();\n\n // Only check for refresh token in localStorage for JSON mode\n // In cookies mode, refresh token is in httpOnly cookie (backend manages it)\n if (tokenDelivery === 'json') {\n await this.tokenManager.assertHasRefreshToken();\n }\n\n const body =\n tokenDelivery === 'json'\n ? { refreshToken: (await this.tokenManager.getTokens()).refreshToken }\n : { refreshToken: '' };\n const refreshFn = async () => {\n // In cookies mode, refresh token is sent via httpOnly cookie (no access token needed, auth=false)\n // In JSON mode, refresh token is in body (no access token needed, auth=false)\n // Refresh endpoint is PUBLIC - it doesn't need an access token\n return this.post<TokenResponse>(this.config.endpoints.refresh, body, false);\n };\n const tokens = await this.tokenManager.refreshOnce(refreshFn);\n this.config.onTokenRefresh?.();\n this.eventEmitter.emit({ type: 'auth:refresh', data: { success: true }, timestamp: Date.now() });\n return tokens;\n }\n\n /**\n * Logout current session.\n *\n * Uses GET request to avoid CSRF token issues.\n *\n * @param forgetDevice - If true, also untrust the device (require MFA on next login)\n */\n async logout(forgetDevice?: boolean): Promise<void> {\n const queryParams = forgetDevice ? '?forgetMe=true' : '';\n try {\n await this.get(this.config.endpoints.logout + queryParams, true);\n } catch (error) {\n // Ignore logout errors (session might already be invalid)\n console.warn('[nauth] Logout request failed (session may already be invalid):', error);\n } finally {\n // Always clear local state even if request fails\n // Pass forgetDevice flag to clear device token in JSON mode\n await this.clearAuthState(forgetDevice);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevice, global: false },\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Number of sessions revoked\n */\n async logoutAll(forgetDevices?: boolean): Promise<{ revokedCount: number }> {\n try {\n const payload: LogoutAllRequest = {\n forgetDevices: forgetDevices ?? false,\n };\n const result = await this.post<{ message: string; revokedCount: number }>(\n this.config.endpoints.logoutAll,\n payload,\n true,\n );\n // Clear device token in JSON mode if forgetDevices is true\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n return { revokedCount: result.revokedCount };\n } catch (error) {\n // If request fails, still clear local state\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Respond to a challenge.\n *\n * Validates challenge response data before sending to backend.\n * Provides helpful error messages for common validation issues.\n *\n * @param response - Challenge response data\n * @returns Auth response from backend\n * @throws {NAuthClientError} If validation fails\n */\n async respondToChallenge(response: ChallengeResponse): Promise<AuthResponse> {\n // Validate TOTP setup requires both secret and code\n if (response.type === AuthChallenge.MFA_SETUP_REQUIRED && response.method === 'totp') {\n const setupData = response.setupData;\n if (!setupData || typeof setupData !== 'object') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires setupData with both secret and code',\n { details: { field: 'setupData' } },\n );\n }\n\n const secret = setupData['secret'];\n const code = setupData['code'];\n\n if (!secret || typeof secret !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires secret in setupData. Make sure to include the secret from getSetupData() response.',\n { details: { field: 'secret' } },\n );\n }\n\n if (!code || typeof code !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires code in setupData. Please enter the verification code from your authenticator app.',\n { details: { field: 'code' } },\n );\n }\n }\n\n try {\n const result = await this.post<AuthResponse>(this.config.endpoints.respondChallenge, response);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.CHALLENGE_INVALID,\n (error as Error).message || 'Challenge response failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Resend a challenge code.\n */\n async resendCode(session: string): Promise<{ destination: string }> {\n const payload: ResendCodeRequest = { session };\n return this.post<{ destination: string }>(this.config.endpoints.resendCode, payload);\n }\n\n /**\n * Get setup data for MFA.\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Setup data wrapped in GetSetupDataResponse\n */\n async getSetupData(session: string, method: GetSetupDataRequest['method']): Promise<GetSetupDataResponse> {\n const payload: GetSetupDataRequest = { session, method };\n return this.post<GetSetupDataResponse>(this.config.endpoints.getSetupData, payload);\n }\n\n /**\n * Get challenge data (e.g., WebAuthn options).\n *\n * Returns challenge-specific data for verification flows.\n *\n * @param session - Challenge session token\n * @param method - Challenge method to get data for\n * @returns Challenge data wrapped in GetChallengeDataResponse\n */\n async getChallengeData(\n session: string,\n method: GetChallengeDataRequest['method'],\n ): Promise<GetChallengeDataResponse> {\n const payload: GetChallengeDataRequest = { session, method };\n return this.post<GetChallengeDataResponse>(this.config.endpoints.getChallengeData, payload);\n }\n\n /**\n * Get current user profile.\n */\n async getProfile(): Promise<AuthUser> {\n const profile = await this.get<AuthUser>(this.config.endpoints.profile, true);\n await this.setUser(profile);\n return profile;\n }\n\n /**\n * Update user profile.\n */\n async updateProfile(updates: UpdateProfileRequest): Promise<AuthUser> {\n const updated = await this.put<AuthUser>(this.config.endpoints.updateProfile, updates, true);\n await this.setUser(updated);\n return updated;\n }\n\n /**\n * Change user password.\n */\n async changePassword(oldPassword: string, newPassword: string): Promise<void> {\n const payload: ChangePasswordRequest = { currentPassword: oldPassword, newPassword };\n await this.post(this.config.endpoints.changePassword, payload, true);\n }\n\n /**\n * Request a password reset code (forgot password).\n */\n async forgotPassword(identifier: string): Promise<ForgotPasswordResponse> {\n const payload: ForgotPasswordRequest = { identifier };\n return this.post<ForgotPasswordResponse>(this.config.endpoints.forgotPassword, payload);\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n async confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Promise<ConfirmForgotPasswordResponse> {\n const payload: ConfirmForgotPasswordRequest = { identifier, code, newPassword };\n return this.post<ConfirmForgotPasswordResponse>(this.config.endpoints.confirmForgotPassword, payload);\n }\n\n /**\n * Request password change (must change on next login).\n */\n async requestPasswordChange(): Promise<void> {\n await this.post(this.config.endpoints.requestPasswordChange, {}, true);\n }\n\n /**\n * Get MFA status.\n */\n async getMfaStatus(): Promise<MFAStatus> {\n return this.get<MFAStatus>(this.config.endpoints.mfaStatus, true);\n }\n\n /**\n * Get MFA devices.\n */\n async getMfaDevices(): Promise<unknown[]> {\n return this.get<unknown[]>(this.config.endpoints.mfaDevices, true);\n }\n\n /**\n * Setup MFA device (authenticated user).\n */\n async setupMfaDevice(method: string): Promise<unknown> {\n return this.post<unknown>(this.config.endpoints.mfaSetupData, { method }, true);\n }\n\n /**\n * Verify MFA setup (authenticated user).\n */\n async verifyMfaSetup(\n method: string,\n setupData: Record<string, unknown>,\n deviceName?: string,\n ): Promise<{ deviceId: number }> {\n return this.post<{ deviceId: number }>(\n this.config.endpoints.mfaVerifySetup,\n { method, setupData, deviceName },\n true,\n );\n }\n\n /**\n * Remove MFA method.\n */\n async removeMfaDevice(method: string): Promise<{ message: string }> {\n const path = `${this.config.endpoints.mfaRemove}/${method}`;\n return this.delete<{ message: string }>(path, true);\n }\n\n /**\n * Set preferred MFA method.\n *\n * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey'). Cannot be 'backup'.\n * @returns Success message\n */\n async setPreferredMfaMethod(method: 'totp' | 'sms' | 'email' | 'passkey'): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.mfaPreferred, { method }, true);\n }\n\n /**\n * Generate backup codes.\n */\n async generateBackupCodes(): Promise<string[]> {\n const result = await this.post<{ codes: string[] }>(this.config.endpoints.mfaBackupCodes, {}, true);\n return result.codes;\n }\n\n /**\n * Set MFA exemption (admin/test scenarios).\n */\n async setMfaExemption(exempt: boolean, reason?: string): Promise<void> {\n await this.post(this.config.endpoints.mfaExemption, { exempt, reason }, true);\n }\n\n // ============================================================================\n // Event System\n // ============================================================================\n\n /**\n * Subscribe to authentication events.\n *\n * Emits events throughout the auth lifecycle for custom logic, analytics, or UI updates.\n *\n * @param event - Event type to listen for, or '*' for all events\n * @param listener - Callback function to handle the event\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * // Listen to successful authentication\n * const unsubscribe = client.on('auth:success', (event) => {\n * console.log('User logged in:', event.data.user);\n * analytics.track('login_success');\n * });\n *\n * // Listen to all events\n * client.on('*', (event) => {\n * console.log('Auth event:', event.type, event.data);\n * });\n *\n * // Unsubscribe when done\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n return this.eventEmitter.on(event, listener);\n }\n\n /**\n * Unsubscribe from authentication events.\n *\n * @param event - Event type\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.eventEmitter.off(event, listener);\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Start redirect-first social OAuth flow (web).\n *\n * This performs a browser navigation to:\n * `GET {baseUrl}/social/:provider/redirect?returnTo=...&appState=...`\n *\n * The backend:\n * - generates and stores CSRF state (cluster-safe)\n * - redirects the user to the provider\n * - completes OAuth on callback and sets cookies (or issues an exchange token)\n * - redirects back to `returnTo` with `appState` (and `exchangeToken` for json/hybrid)\n *\n * @param provider - OAuth provider ('google', 'apple', 'facebook')\n * @param options - Optional redirect options\n *\n * @example\n * ```typescript\n * await client.loginWithSocial('google', { returnTo: '/auth/callback', appState: '12345' });\n * ```\n */\n async loginWithSocial(provider: SocialProvider, options?: SocialLoginOptions): Promise<void> {\n // Emit event\n this.eventEmitter.emit({ type: 'oauth:started', data: { provider }, timestamp: Date.now() });\n\n if (hasWindow()) {\n const startPath = this.config.endpoints.socialRedirectStart.replace(':provider', provider);\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const startUrl = new URL(`${base}${startPath}`);\n\n const returnTo = options?.returnTo ?? this.config.redirects?.success ?? '/';\n const action = options?.action ?? 'login';\n\n startUrl.searchParams.set('returnTo', returnTo);\n startUrl.searchParams.set('action', action);\n if (options?.delivery === 'cookies' || options?.delivery === 'json') {\n startUrl.searchParams.set('delivery', options.delivery);\n }\n if (typeof options?.appState === 'string' && options.appState.trim() !== '') {\n startUrl.searchParams.set('appState', options.appState);\n }\n\n window.location.href = startUrl.toString();\n }\n }\n\n /**\n * Exchange an `exchangeToken` (from redirect callback URL) into an AuthResponse.\n *\n * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back\n * with `exchangeToken` instead of setting cookies.\n *\n * @param exchangeToken - One-time exchange token from the callback URL\n * @returns AuthResponse\n */\n async exchangeSocialRedirect(exchangeToken: string): Promise<AuthResponse> {\n const token = exchangeToken?.trim();\n if (!token) {\n throw new NAuthClientError(NAuthErrorCode.CHALLENGE_INVALID, 'Missing exchangeToken');\n }\n const result = await this.post<AuthResponse>(this.config.endpoints.socialExchange, { exchangeToken: token });\n await this.handleAuthResponse(result);\n return result;\n }\n\n /**\n * Verify native social token (mobile).\n */\n async verifyNativeSocial(request: SocialVerifyRequest): Promise<AuthResponse> {\n try {\n const path = this.config.endpoints.socialVerify.replace(':provider', request.provider);\n const result = await this.post<AuthResponse>(path, request);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n (error as Error).message || 'Social verification failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Get linked accounts.\n */\n async getLinkedAccounts(): Promise<LinkedAccountsResponse> {\n return this.get<LinkedAccountsResponse>(this.config.endpoints.socialLinked, true);\n }\n\n /**\n * Link social account.\n */\n async linkSocialAccount(provider: string, code: string, state: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialLink, { provider, code, state }, true);\n }\n\n /**\n * Unlink social account.\n */\n async unlinkSocialAccount(provider: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialUnlink, { provider }, true);\n }\n\n /**\n * Trust current device.\n */\n async trustDevice(): Promise<{ deviceToken: string }> {\n const result = await this.post<{ deviceToken: string }>(this.config.endpoints.trustDevice, {}, true);\n await this.setDeviceToken(result.deviceToken);\n return result;\n }\n\n /**\n * Check if the current device is trusted.\n *\n * Returns whether the current device is trusted based on the device token\n * (from cookie in cookies mode, or header in JSON mode).\n *\n * This performs a server-side validation of the device token and checks:\n * - Device token exists and is valid\n * - Device token matches a trusted device record in the database\n * - Trust has not expired\n *\n * @returns Object with trusted status\n *\n * @example\n * ```typescript\n * const result = await client.isTrustedDevice();\n * if (result.trusted) {\n * console.log('This device is trusted');\n * }\n * ```\n */\n async isTrustedDevice(): Promise<{ trusted: boolean }> {\n return this.get<{ trusted: boolean }>(this.config.endpoints.isTrustedDevice, true);\n }\n\n /**\n * Get paginated audit history for the current user.\n *\n * Returns authentication and security events with full audit details including:\n * - Event type (login, logout, MFA, etc.)\n * - Event status (success, failure, suspicious)\n * - Device information, location, risk factors\n *\n * @param params - Query parameters for filtering and pagination\n * @returns Paginated audit history response\n *\n * @example\n * ```typescript\n * const history = await client.getAuditHistory({\n * page: 1,\n * limit: 20,\n * eventType: 'LOGIN_SUCCESS'\n * });\n * ```\n */\n async getAuditHistory(params?: Record<string, string | number | boolean>): Promise<AuditHistoryResponse> {\n const entries: [string, string][] = Object.entries(params ?? {}).map(([k, v]) => [k, String(v)]);\n const query = entries.length > 0 ? `?${new URLSearchParams(entries).toString()}` : '';\n const path = `${this.config.endpoints.auditHistory}${query}`;\n return this.get<AuditHistoryResponse>(path, true);\n }\n\n /**\n * Initialize client by hydrating state from storage.\n * Call this on app startup to restore auth state.\n */\n async initialize(): Promise<void> {\n const userJson = await this.config.storage.getItem(USER_KEY);\n if (userJson) {\n try {\n this.currentUser = JSON.parse(userJson) as AuthUser;\n this.config.onAuthStateChange?.(this.currentUser);\n } catch {\n // Invalid stored user - clear it\n await this.config.storage.removeItem(USER_KEY);\n }\n }\n }\n\n /**\n * Determine if user is authenticated (async - checks tokens).\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.tokenManager.getTokens();\n return Boolean(tokens.accessToken);\n }\n\n /**\n * Determine if user is authenticated (sync - checks cached user).\n * Use this for guards and sync checks. Use `isAuthenticated()` for definitive check.\n */\n isAuthenticatedSync(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current access token (may be null).\n */\n async getAccessToken(): Promise<string | null> {\n const tokens = await this.tokenManager.getTokens();\n return tokens.accessToken ?? null;\n }\n\n /**\n * Get current user (cached, sync).\n */\n getCurrentUser(): AuthUser | null {\n return this.currentUser;\n }\n\n /**\n * Get stored challenge session (for resuming challenge flows).\n */\n async getStoredChallenge(): Promise<AuthResponse | null> {\n const raw = await this.config.storage.getItem(CHALLENGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as AuthResponse;\n } catch {\n return null;\n }\n }\n\n /**\n * Clear stored challenge session.\n */\n async clearStoredChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Internal: handle auth response (tokens or challenge).\n *\n * In cookies mode: Tokens are set as httpOnly cookies by backend, not stored in client storage.\n * In JSON mode: Tokens are stored in tokenManager for Authorization header.\n */\n private async handleAuthResponse(response: AuthResponse): Promise<void> {\n if (response.challengeName) {\n await this.persistChallenge(response);\n return;\n }\n\n // Only store tokens in JSON mode (cookies mode uses httpOnly cookies set by backend)\n if (this.config.tokenDelivery === 'json' && response.accessToken && response.refreshToken) {\n await this.tokenManager.setTokens({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n accessTokenExpiresAt: response.accessTokenExpiresAt ?? 0,\n refreshTokenExpiresAt: response.refreshTokenExpiresAt ?? 0,\n });\n }\n\n // Device token handling (only for JSON mode - cookies mode uses httpOnly cookie)\n if (this.config.tokenDelivery === 'json' && response.deviceToken) {\n await this.setDeviceToken(response.deviceToken);\n }\n\n // Always store user info (needed for both modes)\n if (response.user) {\n await this.setUser(response.user as AuthUser);\n }\n\n await this.clearChallenge();\n }\n\n /**\n * Persist challenge state.\n */\n private async persistChallenge(challenge: AuthResponse): Promise<void> {\n await this.config.storage.setItem(CHALLENGE_KEY, JSON.stringify(challenge));\n }\n\n /**\n * Clear challenge state.\n */\n private async clearChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Persist user.\n */\n private async setUser(user: AuthUser): Promise<void> {\n this.currentUser = user;\n await this.config.storage.setItem(USER_KEY, JSON.stringify(user));\n this.config.onAuthStateChange?.(user);\n }\n\n /**\n * Clear all auth state.\n *\n * @param forgetDevice - If true, also clear device token (for JSON mode)\n */\n private async clearAuthState(forgetDevice?: boolean): Promise<void> {\n this.currentUser = null;\n await this.tokenManager.clearTokens();\n await this.config.storage.removeItem(USER_KEY);\n\n // Clear device token in JSON mode (cookies mode uses httpOnly cookie cleared by backend)\n if (forgetDevice && this.config.tokenDelivery === 'json') {\n await this.config.storage.removeItem(this.config.deviceTrust.storageKey);\n }\n\n this.config.onAuthStateChange?.(null);\n }\n\n /**\n * Persist device token (json mode mobile).\n */\n private async setDeviceToken(token: string): Promise<void> {\n await this.config.storage.setItem(this.config.deviceTrust.storageKey, token);\n }\n\n /**\n * Determine token delivery mode for this environment.\n */\n private getTokenDeliveryMode(): 'json' | 'cookies' {\n return this.config.tokenDelivery;\n }\n\n /**\n * Build request URL by combining baseUrl with path.\n * @private\n */\n private buildUrl(path: string): string {\n return `${this.config.baseUrl}${path}`;\n }\n\n /**\n * Build request headers for authentication.\n * @private\n */\n private async buildHeaders(auth: boolean): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n // Add access token in JSON mode\n if (auth && this.config.tokenDelivery === 'json') {\n const accessToken = (await this.tokenManager.getTokens()).accessToken;\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n }\n }\n\n // Add CSRF token for mutating requests in cookies mode\n if (this.config.tokenDelivery === 'cookies' && hasWindow()) {\n const csrfToken = this.getCsrfToken();\n if (csrfToken) {\n headers[this.config.csrf.headerName] = csrfToken;\n }\n }\n\n return headers;\n }\n\n /**\n * Get CSRF token from cookie (browser only).\n * @private\n */\n private getCsrfToken(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n }\n\n /**\n * Execute GET request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async get<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'GET',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute POST request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async post<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'POST',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute PUT request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async put<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'PUT',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute DELETE request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async delete<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'DELETE',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Handle cross-tab storage updates.\n */\n private readonly handleStorageEvent = (event: StorageEvent): void => {\n if (event.key === 'nauth_sync') {\n // Best-effort reload of user state\n this.config.storage\n .getItem(USER_KEY)\n .then((value: string | null) => (value ? (JSON.parse(value) as AuthUser) : null))\n .then((user: AuthUser | null) => {\n this.currentUser = user;\n this.config.onAuthStateChange?.(user);\n })\n .catch(() => {\n // ignore\n });\n }\n };\n}\n","import { AuthResponse, AuthChallenge } from '../types/auth.types';\nimport { MFAMethod } from '../types/mfa.types';\n\n/**\n * Helper utilities for working with authentication challenges.\n *\n * These utilities reduce boilerplate in consumer applications by providing\n * type-safe access to challenge parameters and state detection.\n */\n\n/**\n * Check if a challenge requires phone collection (user has no phone number).\n *\n * @param challenge - Auth response with challenge\n * @returns True if phone collection is required\n *\n * @example\n * ```typescript\n * const challenge = auth.getCurrentChallenge();\n * if (challenge && requiresPhoneCollection(challenge)) {\n * // Show phone input form\n * }\n * ```\n */\nexport function requiresPhoneCollection(challenge: AuthResponse): boolean {\n if (challenge.challengeName !== AuthChallenge.VERIFY_PHONE) {\n return false;\n }\n\n const params = challenge.challengeParameters;\n return (params?.['requiresPhoneCollection'] as string) === 'true';\n}\n\n/**\n * Get masked destination (email or phone) from challenge parameters.\n *\n * For VERIFY_EMAIL/VERIFY_PHONE challenges, returns `codeDeliveryDestination`.\n * For MFA_REQUIRED challenges, returns `maskedEmail` or `maskedPhone` based on method.\n *\n * @param challenge - Auth response with challenge\n * @returns Masked destination string or null if not available\n *\n * @example\n * ```typescript\n * const destination = getMaskedDestination(challenge);\n * if (destination) {\n * console.log(`Code sent to ${destination}`);\n * }\n * ```\n */\nexport function getMaskedDestination(challenge: AuthResponse): string | null {\n const params = challenge.challengeParameters;\n if (!params) {\n return null;\n }\n\n const challengeName = challenge.challengeName;\n\n if (challengeName === AuthChallenge.MFA_REQUIRED) {\n // MFA_REQUIRED uses maskedEmail or maskedPhone based on preferredMethod\n const method = (params?.['preferredMethod'] || params?.['method']) as MFAMethod | undefined;\n if (method === 'sms') {\n return (params['maskedPhone'] as string) || null;\n }\n if (method === 'email') {\n return (params['maskedEmail'] as string) || null;\n }\n // Fallback: try both if method is not specified\n return (params['maskedPhone'] as string) || (params['maskedEmail'] as string) || null;\n }\n\n // VERIFY_EMAIL and VERIFY_PHONE use codeDeliveryDestination\n return (params['codeDeliveryDestination'] as string) || null;\n}\n\n/**\n * Get preferred MFA method from challenge parameters.\n *\n * @param challenge - Auth response with MFA_REQUIRED challenge\n * @returns MFA method or undefined if not available\n *\n * @example\n * ```typescript\n * const method = getMFAMethod(challenge);\n * if (method === 'totp') {\n * // Show TOTP input\n * }\n * ```\n */\nexport function getMFAMethod(challenge: AuthResponse): MFAMethod | undefined {\n if (challenge.challengeName !== AuthChallenge.MFA_REQUIRED) {\n return undefined;\n }\n\n const params = challenge.challengeParameters;\n return (params?.['preferredMethod'] || params?.['method']) as MFAMethod | undefined;\n}\n\n/**\n * Get challenge instructions from challenge parameters.\n *\n * @param challenge - Auth response with challenge\n * @returns Instructions string or undefined if not available\n *\n * @example\n * ```typescript\n * const instructions = getChallengeInstructions(challenge);\n * if (instructions) {\n * console.log(instructions);\n * }\n * ```\n */\nexport function getChallengeInstructions(challenge: AuthResponse): string | undefined {\n const params = challenge.challengeParameters;\n return params?.['instructions'] as string | undefined;\n}\n\n/**\n * Check if challenge is OTP-based (requires code input).\n *\n * @param challenge - Auth response with challenge\n * @returns True if challenge requires OTP code\n *\n * @example\n * ```typescript\n * if (isOTPChallenge(challenge)) {\n * // Show OTP input component\n * }\n * ```\n */\nexport function isOTPChallenge(challenge: AuthResponse): boolean {\n const challengeName = challenge.challengeName;\n return (\n challengeName === AuthChallenge.VERIFY_EMAIL ||\n challengeName === AuthChallenge.VERIFY_PHONE ||\n challengeName === AuthChallenge.MFA_REQUIRED\n );\n}\n"],"mappings":"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","names":["AuthChallenge","NAuthErrorCode","AuthAuditEventType","USER_KEY","CHALLENGE_KEY"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types/auth.types.ts","../src/types/error.types.ts","../src/types/audit.types.ts","../src/core/config.ts","../src/core/errors.ts","../src/core/refresh.ts","../src/storage/browser.ts","../src/storage/memory.ts","../src/core/events.ts","../src/adapters/fetch-adapter.ts","../src/core/client.ts","../src/core/challenge-helpers.ts"],"sourcesContent":["export * from './types';\nexport * from './core/client';\nexport * from './core/config';\nexport * from './core/errors';\nexport * from './core/events';\nexport * from './core/http-adapter';\nexport * from './core/challenge-helpers';\nexport * from './storage/interface';\nexport * from './storage/browser';\nexport * from './storage/memory';\nexport * from './adapters/fetch-adapter';\n","/**\n * Authentication challenge types returned by the backend.\n */\nexport enum AuthChallenge {\n VERIFY_EMAIL = 'VERIFY_EMAIL',\n VERIFY_PHONE = 'VERIFY_PHONE',\n MFA_REQUIRED = 'MFA_REQUIRED',\n MFA_SETUP_REQUIRED = 'MFA_SETUP_REQUIRED',\n FORCE_CHANGE_PASSWORD = 'FORCE_CHANGE_PASSWORD',\n}\n\n/**\n * Auth response returned by backend for all auth operations.\n * Either contains tokens/user or a challenge to complete.\n */\nimport { MFAMethod, MFAChallengeMethod } from './mfa.types';\n\nexport interface AuthResponse {\n user?: AuthUserSummary;\n accessToken?: string;\n refreshToken?: string;\n accessTokenExpiresAt?: number;\n refreshTokenExpiresAt?: number;\n /**\n * Authentication method used to create the current session.\n *\n * Examples:\n * - `password`\n * - `google`\n * - `apple`\n * - `facebook`\n */\n authMethod?: string;\n trusted?: boolean;\n deviceToken?: string;\n challengeName?: AuthChallenge;\n session?: string;\n challengeParameters?: Record<string, unknown>;\n userSub?: string;\n}\n\n/**\n * Minimal user information returned inside auth responses.\n */\nexport interface AuthUserSummary {\n sub: string;\n email: string;\n firstName?: string | null;\n lastName?: string | null;\n phone?: string | null;\n isEmailVerified: boolean;\n isPhoneVerified?: boolean;\n socialProviders?: string[] | null;\n hasPasswordHash?: boolean;\n}\n\n/**\n * Token response returned by refresh endpoint.\n */\nexport interface TokenResponse {\n accessToken: string;\n refreshToken: string;\n accessTokenExpiresAt: number;\n refreshTokenExpiresAt: number;\n}\n\n/**\n * Signup request payload.\n */\nexport interface SignupRequest {\n email: string;\n password: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Login request payload.\n */\nexport interface LoginRequest {\n identifier: string;\n password: string;\n}\n\n/**\n * Logout request payload.\n */\nexport interface LogoutRequest {\n sub?: string;\n forgetMe?: boolean;\n}\n\n/**\n * Logout all sessions request payload.\n */\nexport interface LogoutAllRequest {\n /**\n * Whether to also revoke all trusted devices\n * Default: false (devices remain trusted)\n */\n forgetDevices?: boolean;\n sub?: string;\n}\n\n/**\n * Resend code request payload.\n */\nexport interface ResendCodeRequest {\n session: string;\n}\n\n/**\n * MFA setup data request payload during challenge flows.\n */\nexport interface GetSetupDataRequest {\n session: string;\n method: MFAMethod;\n}\n\n/**\n * Challenge data request payload (e.g., passkey options).\n */\nexport interface GetChallengeDataRequest {\n session: string;\n method: MFAChallengeMethod;\n}\n\n/**\n * Unified challenge response discriminated union.\n */\nexport type ChallengeResponse =\n | VerifyEmailResponse\n | VerifyPhoneCollectResponse\n | VerifyPhoneCodeResponse\n | MFACodeResponse\n | MFAPasskeyResponse\n | MFASetupResponse\n | ForceChangePasswordResponse;\n\n/**\n * Base challenge response shape.\n */\nexport interface BaseChallengeResponse {\n session: string;\n}\n\nexport interface VerifyEmailResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_EMAIL;\n code: string;\n}\n\nexport interface VerifyPhoneCollectResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_PHONE;\n phone: string;\n}\n\nexport interface VerifyPhoneCodeResponse extends BaseChallengeResponse {\n type: AuthChallenge.VERIFY_PHONE;\n code: string;\n}\n\nexport interface MFACodeResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_REQUIRED;\n method: MFAMethod;\n code: string;\n}\n\nexport interface MFAPasskeyResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_REQUIRED;\n method: 'passkey';\n credential: Record<string, unknown>;\n}\n\nexport interface MFASetupResponse extends BaseChallengeResponse {\n type: AuthChallenge.MFA_SETUP_REQUIRED;\n method: MFAMethod;\n setupData: Record<string, unknown>;\n}\n\nexport interface ForceChangePasswordResponse extends BaseChallengeResponse {\n type: AuthChallenge.FORCE_CHANGE_PASSWORD;\n newPassword: string;\n}\n\n// MFAMethod and MFAChallengeMethod are imported from mfa.types\n","/**\n * Standardized error codes mirroring backend AuthErrorCode.\n */\nexport enum NAuthErrorCode {\n // Authentication Errors\n AUTH_INVALID_CREDENTIALS = 'AUTH_INVALID_CREDENTIALS',\n AUTH_ACCOUNT_LOCKED = 'AUTH_ACCOUNT_LOCKED',\n AUTH_ACCOUNT_INACTIVE = 'AUTH_ACCOUNT_INACTIVE',\n AUTH_TOKEN_EXPIRED = 'AUTH_TOKEN_EXPIRED',\n AUTH_TOKEN_INVALID = 'AUTH_TOKEN_INVALID',\n AUTH_BEARER_NOT_ALLOWED = 'AUTH_BEARER_NOT_ALLOWED',\n AUTH_COOKIES_NOT_ALLOWED = 'AUTH_COOKIES_NOT_ALLOWED',\n AUTH_CSRF_TOKEN_INVALID = 'AUTH_CSRF_TOKEN_INVALID',\n AUTH_CSRF_TOKEN_MISSING = 'AUTH_CSRF_TOKEN_MISSING',\n AUTH_TOKEN_REUSE_DETECTED = 'AUTH_TOKEN_REUSE_DETECTED',\n AUTH_SESSION_NOT_FOUND = 'AUTH_SESSION_NOT_FOUND',\n AUTH_SESSION_EXPIRED = 'AUTH_SESSION_EXPIRED',\n\n // Signup Errors\n SIGNUP_DISABLED = 'SIGNUP_DISABLED',\n SIGNUP_EMAIL_EXISTS = 'SIGNUP_EMAIL_EXISTS',\n SIGNUP_USERNAME_EXISTS = 'SIGNUP_USERNAME_EXISTS',\n SIGNUP_PHONE_EXISTS = 'SIGNUP_PHONE_EXISTS',\n SIGNUP_WEAK_PASSWORD = 'SIGNUP_WEAK_PASSWORD',\n SIGNUP_PHONE_REQUIRED = 'SIGNUP_PHONE_REQUIRED',\n SIGNUP_NOT_ALLOWED = 'SIGNUP_NOT_ALLOWED',\n\n // Verification Errors\n VERIFY_CODE_INVALID = 'VERIFY_CODE_INVALID',\n VERIFY_CODE_EXPIRED = 'VERIFY_CODE_EXPIRED',\n VERIFY_TOO_MANY_ATTEMPTS = 'VERIFY_TOO_MANY_ATTEMPTS',\n VERIFY_ALREADY_VERIFIED = 'VERIFY_ALREADY_VERIFIED',\n\n // MFA Errors\n MFA_SETUP_REQUIRED = 'MFA_SETUP_REQUIRED',\n\n // Rate Limit Errors\n RATE_LIMIT_SMS = 'RATE_LIMIT_SMS',\n RATE_LIMIT_EMAIL = 'RATE_LIMIT_EMAIL',\n RATE_LIMIT_LOGIN = 'RATE_LIMIT_LOGIN',\n RATE_LIMIT_RESEND = 'RATE_LIMIT_RESEND',\n\n // Social Auth Errors\n SOCIAL_TOKEN_INVALID = 'SOCIAL_TOKEN_INVALID',\n SOCIAL_ACCOUNT_LINKED = 'SOCIAL_ACCOUNT_LINKED',\n SOCIAL_CONFIG_MISSING = 'SOCIAL_CONFIG_MISSING',\n SOCIAL_EMAIL_REQUIRED = 'SOCIAL_EMAIL_REQUIRED',\n SOCIAL_ACCOUNT_NOT_FOUND = 'SOCIAL_ACCOUNT_NOT_FOUND',\n\n // Challenge Errors\n CHALLENGE_EXPIRED = 'CHALLENGE_EXPIRED',\n CHALLENGE_INVALID = 'CHALLENGE_INVALID',\n CHALLENGE_TYPE_MISMATCH = 'CHALLENGE_TYPE_MISMATCH',\n CHALLENGE_MAX_ATTEMPTS = 'CHALLENGE_MAX_ATTEMPTS',\n CHALLENGE_ALREADY_COMPLETED = 'CHALLENGE_ALREADY_COMPLETED',\n\n // Validation Errors\n VALIDATION_FAILED = 'VALIDATION_FAILED',\n VALIDATION_INVALID_PHONE = 'VALIDATION_INVALID_PHONE',\n VALIDATION_INVALID_EMAIL = 'VALIDATION_INVALID_EMAIL',\n VALIDATION_INVALID_PASSWORD = 'VALIDATION_INVALID_PASSWORD',\n\n // Password Errors\n PASSWORD_INCORRECT = 'PASSWORD_INCORRECT',\n PASSWORD_REUSED = 'PASSWORD_REUSED',\n PASSWORD_CHANGE_NOT_ALLOWED = 'PASSWORD_CHANGE_NOT_ALLOWED',\n WEAK_PASSWORD = 'SIGNUP_WEAK_PASSWORD',\n PASSWORD_RESET_CODE_INVALID = 'PASSWORD_RESET_CODE_INVALID',\n PASSWORD_RESET_CODE_EXPIRED = 'PASSWORD_RESET_CODE_EXPIRED',\n PASSWORD_RESET_MAX_ATTEMPTS = 'PASSWORD_RESET_MAX_ATTEMPTS',\n RATE_LIMIT_PASSWORD_RESET = 'RATE_LIMIT_PASSWORD_RESET',\n\n // Adaptive MFA\n SIGNIN_BLOCKED_HIGH_RISK = 'SIGNIN_BLOCKED_HIGH_RISK',\n\n // General Errors\n RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',\n FORBIDDEN = 'FORBIDDEN',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',\n}\n\n/**\n * Structured client error.\n */\nexport interface NAuthError {\n code: NAuthErrorCode;\n message: string;\n details?: Record<string, unknown>;\n timestamp?: string;\n statusCode?: number;\n}\n","/**\n * Audit event types.\n */\nexport enum AuthAuditEventType {\n // Authentication events\n LOGIN_SUCCESS = 'LOGIN_SUCCESS',\n LOGIN_FAILED = 'LOGIN_FAILED',\n LOGOUT = 'LOGOUT',\n TOKEN_REFRESH = 'TOKEN_REFRESH',\n TOKEN_REVOKED = 'TOKEN_REVOKED',\n\n // Registration events\n SIGNUP_SUCCESS = 'SIGNUP_SUCCESS',\n SIGNUP_FAILED = 'SIGNUP_FAILED',\n\n // Verification events\n EMAIL_VERIFIED = 'EMAIL_VERIFIED',\n PHONE_VERIFIED = 'PHONE_VERIFIED',\n VERIFICATION_FAILED = 'VERIFICATION_FAILED',\n\n // MFA events\n MFA_ENABLED = 'MFA_ENABLED',\n MFA_DISABLED = 'MFA_DISABLED',\n MFA_VERIFIED = 'MFA_VERIFIED',\n MFA_FAILED = 'MFA_FAILED',\n MFA_BACKUP_CODE_USED = 'MFA_BACKUP_CODE_USED',\n\n // Password events\n PASSWORD_CHANGED = 'PASSWORD_CHANGED',\n PASSWORD_RESET_REQUESTED = 'PASSWORD_RESET_REQUESTED',\n PASSWORD_RESET_COMPLETED = 'PASSWORD_RESET_COMPLETED',\n\n // Security events\n ACCOUNT_LOCKED = 'ACCOUNT_LOCKED',\n ACCOUNT_UNLOCKED = 'ACCOUNT_UNLOCKED',\n SUSPICIOUS_ACTIVITY = 'SUSPICIOUS_ACTIVITY',\n ADAPTIVE_MFA_TRIGGERED = 'ADAPTIVE_MFA_TRIGGERED',\n\n // Social auth events\n SOCIAL_LINK_SUCCESS = 'SOCIAL_LINK_SUCCESS',\n SOCIAL_LINK_FAILED = 'SOCIAL_LINK_FAILED',\n SOCIAL_UNLINK = 'SOCIAL_UNLINK',\n}\n\n/**\n * Audit event status.\n */\nexport type AuthAuditEventStatus = 'SUCCESS' | 'FAILURE' | 'INFO' | 'SUSPICIOUS';\n\n/**\n * Individual audit event record.\n */\nexport interface AuthAuditEvent {\n id: number;\n userId: number;\n eventType: AuthAuditEventType;\n eventStatus: AuthAuditEventStatus;\n riskFactor?: number | null;\n riskFactors?: string[] | null;\n adaptiveMfaTriggered?: boolean | null;\n ipAddress?: string | null;\n ipCountry?: string | null;\n ipCity?: string | null;\n ipLatitude?: number | null;\n ipLongitude?: number | null;\n userAgent?: string | null;\n platform?: string | null;\n browser?: string | null;\n deviceId?: string | null;\n deviceName?: string | null;\n deviceType?: string | null;\n sessionId?: number | null;\n challengeSessionId?: number | null;\n authMethod?: string | null;\n performedBy?: string | null;\n reason?: string | null;\n description?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: string | Date;\n}\n\n/**\n * Paginated audit history response.\n */\nexport interface AuditHistoryResponse {\n data: AuthAuditEvent[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n","import {\n NAuthClientConfig,\n NAuthEndpoints,\n NAuthStorageAdapter,\n TokenDeliveryMode,\n HttpAdapter,\n} from '../types/config.types';\n\n/**\n * Fully resolved configuration with all defaults applied.\n */\nexport type ResolvedNAuthClientConfig = Omit<\n NAuthClientConfig,\n 'endpoints' | 'storage' | 'tokenDelivery' | 'httpAdapter'\n> & {\n tokenDelivery: TokenDeliveryMode;\n endpoints: NAuthEndpoints;\n storage: NAuthStorageAdapter;\n httpAdapter: HttpAdapter;\n csrf: { cookieName: string; headerName: string };\n deviceTrust: { headerName: string; storageKey: string };\n headers: Record<string, string>;\n timeout: number;\n};\n\n/**\n * Default endpoint paths matching backend controller.\n */\nexport const defaultEndpoints: NAuthEndpoints = {\n login: '/login',\n signup: '/signup',\n logout: '/logout',\n logoutAll: '/logout/all',\n refresh: '/refresh',\n respondChallenge: '/respond-challenge',\n resendCode: '/challenge/resend',\n getSetupData: '/challenge/setup-data',\n getChallengeData: '/challenge/challenge-data',\n profile: '/profile',\n changePassword: '/change-password',\n requestPasswordChange: '/request-password-change',\n forgotPassword: '/forgot-password',\n confirmForgotPassword: '/forgot-password/confirm',\n mfaStatus: '/mfa/status',\n mfaDevices: '/mfa/devices',\n mfaSetupData: '/mfa/setup-data',\n mfaVerifySetup: '/mfa/verify-setup',\n mfaRemove: '/mfa/method',\n mfaPreferred: '/mfa/preferred-method',\n mfaBackupCodes: '/mfa/backup-codes/generate',\n mfaExemption: '/mfa/exemption',\n socialLinked: '/social/linked',\n socialLink: '/social/link',\n socialUnlink: '/social/unlink',\n socialVerify: '/social/:provider/verify',\n socialRedirectStart: '/social/:provider/redirect',\n socialExchange: '/social/exchange',\n trustDevice: '/trust-device',\n isTrustedDevice: '/is-trusted-device',\n auditHistory: '/audit/history',\n updateProfile: '/profile',\n};\n\n/**\n * Normalize user config with defaults.\n *\n * @param config - User supplied config\n * @param defaultAdapter - Default HTTP adapter (FetchAdapter for vanilla, AngularHttpAdapter for Angular)\n * @returns Resolved config with defaults applied\n */\nexport const resolveConfig = (config: NAuthClientConfig, defaultAdapter: HttpAdapter): ResolvedNAuthClientConfig => {\n const resolvedEndpoints: NAuthEndpoints = {\n ...defaultEndpoints,\n ...(config.endpoints ?? {}),\n };\n\n return {\n ...config,\n csrf: {\n cookieName: config.csrf?.cookieName ?? 'nauth_csrf_token',\n headerName: config.csrf?.headerName ?? 'x-csrf-token',\n },\n deviceTrust: {\n headerName: config.deviceTrust?.headerName ?? 'X-Device-Token',\n storageKey: config.deviceTrust?.storageKey ?? 'nauth_device_token',\n },\n headers: config.headers ?? {},\n timeout: config.timeout ?? 30000,\n endpoints: resolvedEndpoints,\n storage: config.storage as NAuthStorageAdapter,\n httpAdapter: config.httpAdapter ?? defaultAdapter,\n };\n};\n","import { NAuthError, NAuthErrorCode } from '../types/error.types';\n\n/**\n * Client-side error wrapper for SDK operations.\n *\n * Mirrors the backend NAuthException structure for consistent error handling.\n *\n * @example\n * ```typescript\n * try {\n * await client.login({ identifier: 'user@example.com', password: 'wrong' });\n * } catch (error) {\n * if (error instanceof NAuthClientError) {\n * console.log(error.code); // 'AUTH_INVALID_CREDENTIALS'\n * console.log(error.message); // 'Invalid credentials'\n * console.log(error.timestamp); // '2025-12-06T...'\n *\n * // Check specific error code\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_LOGIN)) {\n * const retryAfter = error.details?.retryAfter as number;\n * console.log(`Rate limited. Retry in ${retryAfter}s`);\n * }\n * }\n * }\n * ```\n */\nexport class NAuthClientError extends Error implements NAuthError {\n public readonly code: NAuthErrorCode;\n public readonly details?: Record<string, unknown>;\n public readonly statusCode?: number;\n public readonly timestamp: string;\n public readonly isNetworkError: boolean;\n\n /**\n * Create a new client error.\n *\n * @param code - Error code from NAuthErrorCode enum\n * @param message - Human-readable error message\n * @param options - Optional metadata including details, statusCode, timestamp, and network error flag\n */\n constructor(\n code: NAuthErrorCode,\n message: string,\n options?: {\n details?: Record<string, unknown>;\n statusCode?: number;\n timestamp?: string;\n isNetworkError?: boolean;\n },\n ) {\n super(message);\n this.code = code;\n this.details = options?.details;\n this.statusCode = options?.statusCode;\n this.timestamp = options?.timestamp || new Date().toISOString();\n this.isNetworkError = options?.isNetworkError ?? false;\n this.name = 'NAuthClientError';\n Object.setPrototypeOf(this, NAuthClientError.prototype);\n }\n\n /**\n * Check if error matches a specific error code.\n *\n * @param code - Error code to check against\n * @returns True if the error code matches\n *\n * @example\n * ```typescript\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_SMS)) {\n * // Handle SMS rate limit\n * }\n * ```\n */\n isCode(code: NAuthErrorCode): boolean {\n return this.code === code;\n }\n\n /**\n * Get error details/metadata.\n *\n * @returns Error details object or undefined\n *\n * @example\n * ```typescript\n * const details = error.getDetails();\n * if (details?.retryAfter) {\n * console.log(`Retry after ${details.retryAfter} seconds`);\n * }\n * ```\n */\n getDetails(): Record<string, unknown> | undefined {\n return this.details;\n }\n\n /**\n * Get the error code.\n *\n * @returns The error code enum value\n */\n getCode(): NAuthErrorCode {\n return this.code;\n }\n\n /**\n * Serialize error to JSON object.\n *\n * @returns Plain object representation\n *\n * @example\n * ```typescript\n * const errorJson = error.toJSON();\n * // { code: 'AUTH_INVALID_CREDENTIALS', message: '...', timestamp: '...', details: {...} }\n * ```\n */\n toJSON(): {\n code: string;\n message: string;\n timestamp: string;\n details?: Record<string, unknown>;\n statusCode?: number;\n } {\n return {\n code: this.code,\n message: this.message,\n timestamp: this.timestamp,\n details: this.details,\n statusCode: this.statusCode,\n };\n }\n}\n","import { TokenResponse } from '../types/auth.types';\nimport { NAuthStorageAdapter } from '../types/config.types';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\nconst ACCESS_TOKEN_KEY = 'nauth_access_token';\nconst REFRESH_TOKEN_KEY = 'nauth_refresh_token';\nconst ACCESS_EXPIRES_AT_KEY = 'nauth_access_token_expires_at';\nconst REFRESH_EXPIRES_AT_KEY = 'nauth_refresh_token_expires_at';\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\n\n/**\n * Token state persisted in storage.\n */\nexport interface TokenState {\n accessToken: string | null;\n refreshToken: string | null;\n accessTokenExpiresAt?: number | null;\n refreshTokenExpiresAt?: number | null;\n}\n\n/**\n * Manage token persistence and refresh queuing.\n */\nexport class TokenManager {\n private readonly storage: NAuthStorageAdapter;\n private refreshPromise: Promise<TokenResponse> | null = null;\n private readonly isBrowser = typeof window !== 'undefined';\n\n /**\n * @param storage - storage adapter\n */\n constructor(storage: NAuthStorageAdapter) {\n this.storage = storage;\n }\n\n /**\n * Load tokens from storage.\n */\n async getTokens(): Promise<TokenState> {\n const [accessToken, refreshToken, accessExpRaw, refreshExpRaw] = await Promise.all([\n this.storage.getItem(ACCESS_TOKEN_KEY),\n this.storage.getItem(REFRESH_TOKEN_KEY),\n this.storage.getItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.getItem(REFRESH_EXPIRES_AT_KEY),\n ]);\n return {\n accessToken,\n refreshToken,\n accessTokenExpiresAt: accessExpRaw ? Number(accessExpRaw) : null,\n refreshTokenExpiresAt: refreshExpRaw ? Number(refreshExpRaw) : null,\n };\n }\n\n /**\n * Persist tokens.\n *\n * @param tokens - new token pair\n */\n async setTokens(tokens: TokenResponse): Promise<void> {\n await Promise.all([\n this.storage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken),\n this.storage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken),\n this.storage.setItem(ACCESS_EXPIRES_AT_KEY, tokens.accessTokenExpiresAt.toString()),\n this.storage.setItem(REFRESH_EXPIRES_AT_KEY, tokens.refreshTokenExpiresAt.toString()),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Clear tokens and related auth state.\n */\n async clearTokens(): Promise<void> {\n await Promise.all([\n this.storage.removeItem(ACCESS_TOKEN_KEY),\n this.storage.removeItem(REFRESH_TOKEN_KEY),\n this.storage.removeItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.removeItem(REFRESH_EXPIRES_AT_KEY),\n this.storage.removeItem(USER_KEY),\n this.storage.removeItem(CHALLENGE_KEY),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Ensure only one refresh in flight.\n *\n * @param refreshFn - function performing refresh request\n */\n async refreshOnce(refreshFn: () => Promise<TokenResponse>): Promise<TokenResponse> {\n if (!this.refreshPromise) {\n this.refreshPromise = refreshFn()\n .then(async (tokens) => {\n await this.setTokens(tokens);\n return tokens;\n })\n .catch((error) => {\n throw error;\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /**\n * Validate that a refresh token exists before attempting refresh.\n */\n async assertHasRefreshToken(): Promise<void> {\n const state = await this.getTokens();\n if (!state.refreshToken) {\n throw new NAuthClientError(NAuthErrorCode.AUTH_SESSION_NOT_FOUND, 'No refresh token available');\n }\n }\n\n /**\n * Broadcast a no-op write to trigger storage listeners in other tabs.\n */\n private broadcastStorage(): void {\n if (!this.isBrowser) return;\n try {\n window.localStorage.setItem('nauth_sync', Date.now().toString());\n } catch {\n // Best-effort; ignore if storage unavailable\n }\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * Browser storage adapter wrapping localStorage or sessionStorage.\n */\nexport class BrowserStorage implements NAuthStorageAdapter {\n private readonly storage: Storage;\n\n /**\n * Create a browser storage adapter.\n *\n * @param storage - Storage implementation (localStorage by default)\n */\n constructor(storage: Storage = window.localStorage) {\n this.storage = storage;\n }\n\n async getItem(key: string): Promise<string | null> {\n return this.storage.getItem(key);\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.storage.setItem(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * In-memory storage adapter for SSR, tests, or environments without Web Storage.\n */\nexport class InMemoryStorage implements NAuthStorageAdapter {\n private readonly store = new Map<string, string>();\n\n async getItem(key: string): Promise<string | null> {\n return this.store.has(key) ? (this.store.get(key) as string) : null;\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.store.set(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n}\n","import type { AuthResponse } from '../types/auth.types';\nimport type { NAuthClientError } from './errors';\n\n/**\n * Authentication event types emitted by NAuthClient\n *\n * Events are emitted throughout the authentication lifecycle,\n * allowing applications to react to auth state changes.\n */\nexport type AuthEventType =\n | 'auth:login'\n | 'auth:signup'\n | 'auth:success'\n | 'auth:challenge'\n | 'auth:error'\n | 'auth:logout'\n | 'auth:refresh'\n | 'oauth:started'\n | 'oauth:callback'\n | 'oauth:completed'\n | 'oauth:error';\n\n/**\n * Discriminated union of all authentication events with type-safe payloads\n *\n * Each event has a specific payload type for better type safety.\n */\nexport type AuthEvent =\n | AuthLoginEvent\n | AuthSignupEvent\n | AuthSuccessEvent\n | AuthChallengeEvent\n | AuthErrorEvent\n | AuthLogoutEvent\n | AuthRefreshEvent\n | OAuthStartedEvent\n | OAuthCallbackEvent\n | OAuthCompletedEvent\n | OAuthErrorEvent;\n\n/**\n * Login initiated event\n */\nexport interface AuthLoginEvent {\n type: 'auth:login';\n data: {\n identifier: string;\n };\n timestamp: number;\n}\n\n/**\n * Signup initiated event\n */\nexport interface AuthSignupEvent {\n type: 'auth:signup';\n data: {\n email: string;\n };\n timestamp: number;\n}\n\n/**\n * Successful authentication event\n */\nexport interface AuthSuccessEvent {\n type: 'auth:success';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Challenge required event\n */\nexport interface AuthChallengeEvent {\n type: 'auth:challenge';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Authentication error event\n */\nexport interface AuthErrorEvent {\n type: 'auth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * User logged out event\n */\nexport interface AuthLogoutEvent {\n type: 'auth:logout';\n data: {\n forgetDevice?: boolean;\n global?: boolean;\n };\n timestamp: number;\n}\n\n/**\n * Token refreshed event\n */\nexport interface AuthRefreshEvent {\n type: 'auth:refresh';\n data: {\n success: boolean;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow started event\n */\nexport interface OAuthStartedEvent {\n type: 'oauth:started';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth callback received event\n */\nexport interface OAuthCallbackEvent {\n type: 'oauth:callback';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow completed event\n */\nexport interface OAuthCompletedEvent {\n type: 'oauth:completed';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * OAuth error event\n */\nexport interface OAuthErrorEvent {\n type: 'oauth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * Event listener callback function\n */\nexport type AuthEventListener = (event: AuthEvent) => void;\n\n/**\n * Internal event emitter for authentication events\n *\n * Provides pub/sub functionality for auth lifecycle events.\n *\n * @internal\n */\nexport class EventEmitter {\n private listeners = new Map<AuthEventType | '*', Set<AuthEventListener>>();\n\n /**\n * Subscribe to an authentication event\n *\n * @param event - Event type or '*' for all events\n * @param listener - Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = emitter.on('auth:success', (event) => {\n * console.log('User logged in:', event.data);\n * });\n *\n * // Later\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => this.off(event, listener);\n }\n\n /**\n * Unsubscribe from an authentication event\n *\n * @param event - Event type or '*'\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n /**\n * Emit an authentication event\n *\n * Notifies all listeners for the specific event type and wildcard listeners.\n *\n * @param event - Event to emit\n * @internal\n */\n emit(event: AuthEvent): void {\n const specificListeners = this.listeners.get(event.type);\n const wildcardListeners = this.listeners.get('*');\n\n // Emit to specific event listeners\n specificListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in ${event.type} event listener:`, error);\n }\n });\n\n // Emit to wildcard listeners\n wildcardListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in wildcard event listener:`, error);\n }\n });\n }\n\n /**\n * Remove all listeners\n *\n * @internal\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n","import { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter using native fetch API.\n *\n * Suitable for:\n * - Vanilla JavaScript/TypeScript\n * - Node.js (with fetch polyfill or Node 18+)\n * - Environments without framework-specific HTTP clients\n *\n * @example\n * ```typescript\n * import { NAuthClient } from '@nauth-toolkit/client';\n * import { FetchAdapter } from '@nauth-toolkit/client/adapters/fetch';\n *\n * const client = new NAuthClient({\n * baseUrl: 'https://api.example.com/auth',\n * httpAdapter: new FetchAdapter(),\n * });\n * ```\n */\nexport class FetchAdapter implements HttpAdapter {\n /**\n * Execute HTTP request using native fetch.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n const fetchOptions: RequestInit = {\n method: config.method,\n headers: config.headers,\n signal: config.signal,\n credentials: config.credentials,\n };\n\n if (config.body !== undefined) {\n fetchOptions.body = JSON.stringify(config.body);\n }\n\n let response: Response;\n try {\n response = await fetch(config.url, fetchOptions);\n } catch (error) {\n throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, 'Network request failed', {\n isNetworkError: true,\n details: { url: config.url, message: (error as Error).message },\n });\n }\n\n const status = response.status;\n let data: unknown = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n // Extract headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n if (!response.ok) {\n const errorData = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n const code =\n typeof errorData['code'] === 'string'\n ? (errorData['code'] as NAuthErrorCode)\n : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData['message'] as string)\n : `Request failed with status ${status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? (errorData['timestamp'] as string) : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: status,\n timestamp,\n details,\n });\n }\n\n return { data: data as T, status, headers };\n }\n}\n\n\n\n","import { resolveConfig, ResolvedNAuthClientConfig } from './config';\nimport { TokenManager } from './refresh';\nimport { BrowserStorage } from '../storage/browser';\nimport { InMemoryStorage } from '../storage/memory';\nimport { EventEmitter, AuthEventType, AuthEventListener } from './events';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\nimport { FetchAdapter } from '../adapters/fetch-adapter';\nimport {\n AuthChallenge,\n ChallengeResponse,\n GetChallengeDataRequest,\n GetSetupDataRequest,\n LoginRequest,\n LogoutAllRequest,\n AuthResponse,\n ResendCodeRequest,\n SignupRequest,\n TokenResponse,\n} from '../types/auth.types';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse, MFAStatus } from '../types/mfa.types';\nimport { LinkedAccountsResponse, SocialLoginOptions, SocialVerifyRequest, SocialProvider } from '../types/social.types';\nimport {\n AuthUser,\n ChangePasswordRequest,\n ConfirmForgotPasswordRequest,\n ConfirmForgotPasswordResponse,\n ForgotPasswordRequest,\n ForgotPasswordResponse,\n UpdateProfileRequest,\n} from '../types/user.types';\nimport { AuditHistoryResponse } from '../types/audit.types';\n\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\nconst hasWindow = (): boolean =>\n typeof globalThis !== 'undefined' && typeof (globalThis as { window?: unknown }).window !== 'undefined';\n\n/**\n * Choose default storage implementation.\n */\nconst defaultStorage = () => {\n if (hasWindow() && typeof window.localStorage !== 'undefined') {\n return new BrowserStorage();\n }\n return new InMemoryStorage();\n};\n\n/**\n * Primary client for interacting with nauth-toolkit backend.\n */\nexport class NAuthClient {\n private readonly config: ResolvedNAuthClientConfig;\n private readonly tokenManager: TokenManager;\n private readonly eventEmitter: EventEmitter;\n private currentUser: AuthUser | null = null;\n\n /**\n * Create a new client instance.\n *\n * @param userConfig - Client configuration\n */\n constructor(userConfig: NAuthClientConfig) {\n const storage = userConfig.storage ?? defaultStorage();\n const defaultAdapter = userConfig.httpAdapter ?? new FetchAdapter();\n this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);\n this.tokenManager = new TokenManager(storage);\n this.eventEmitter = new EventEmitter();\n if (hasWindow()) {\n window.addEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (hasWindow()) {\n window.removeEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Login with identifier and password.\n */\n async login(identifier: string, password: string): Promise<AuthResponse> {\n const loginEvent = { type: 'auth:login' as const, data: { identifier }, timestamp: Date.now() };\n this.eventEmitter.emit(loginEvent);\n\n try {\n const body: LoginRequest = { identifier, password };\n const response = await this.post<AuthResponse>(this.config.endpoints.login, body);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Login failed');\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Signup with credentials.\n */\n async signup(payload: SignupRequest): Promise<AuthResponse> {\n this.eventEmitter.emit({ type: 'auth:signup', data: { email: payload.email }, timestamp: Date.now() });\n\n try {\n const response = await this.post<AuthResponse>(this.config.endpoints.signup, payload);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n this.eventEmitter.emit({ type: 'auth:challenge', data: response, timestamp: Date.now() });\n } else {\n this.eventEmitter.emit({ type: 'auth:success', data: response, timestamp: Date.now() });\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Signup failed');\n this.eventEmitter.emit({ type: 'auth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n }\n\n /**\n * Refresh tokens manually.\n */\n async refreshTokens(): Promise<TokenResponse> {\n const tokenDelivery = this.getTokenDeliveryMode();\n\n // Only check for refresh token in localStorage for JSON mode\n // In cookies mode, refresh token is in httpOnly cookie (backend manages it)\n if (tokenDelivery === 'json') {\n await this.tokenManager.assertHasRefreshToken();\n }\n\n const body =\n tokenDelivery === 'json'\n ? { refreshToken: (await this.tokenManager.getTokens()).refreshToken }\n : { refreshToken: '' };\n const refreshFn = async () => {\n // In cookies mode, refresh token is sent via httpOnly cookie (no access token needed, auth=false)\n // In JSON mode, refresh token is in body (no access token needed, auth=false)\n // Refresh endpoint is PUBLIC - it doesn't need an access token\n return this.post<TokenResponse>(this.config.endpoints.refresh, body, false);\n };\n const tokens = await this.tokenManager.refreshOnce(refreshFn);\n this.config.onTokenRefresh?.();\n this.eventEmitter.emit({ type: 'auth:refresh', data: { success: true }, timestamp: Date.now() });\n return tokens;\n }\n\n /**\n * Logout current session.\n *\n * Uses GET request to avoid CSRF token issues.\n *\n * @param forgetDevice - If true, also untrust the device (require MFA on next login)\n */\n async logout(forgetDevice?: boolean): Promise<void> {\n const queryParams = forgetDevice ? '?forgetMe=true' : '';\n try {\n await this.get(this.config.endpoints.logout + queryParams, true);\n } catch (error) {\n // Ignore logout errors (session might already be invalid)\n console.warn('[nauth] Logout request failed (session may already be invalid):', error);\n } finally {\n // Always clear local state even if request fails\n // Pass forgetDevice flag to clear device token in JSON mode\n await this.clearAuthState(forgetDevice);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevice, global: false },\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Number of sessions revoked\n */\n async logoutAll(forgetDevices?: boolean): Promise<{ revokedCount: number }> {\n try {\n const payload: LogoutAllRequest = {\n forgetDevices: forgetDevices ?? false,\n };\n const result = await this.post<{ message: string; revokedCount: number }>(\n this.config.endpoints.logoutAll,\n payload,\n true,\n );\n // Clear device token in JSON mode if forgetDevices is true\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n return { revokedCount: result.revokedCount };\n } catch (error) {\n // If request fails, still clear local state\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Respond to a challenge.\n *\n * Validates challenge response data before sending to backend.\n * Provides helpful error messages for common validation issues.\n *\n * @param response - Challenge response data\n * @returns Auth response from backend\n * @throws {NAuthClientError} If validation fails\n */\n async respondToChallenge(response: ChallengeResponse): Promise<AuthResponse> {\n // Validate TOTP setup requires both secret and code\n if (response.type === AuthChallenge.MFA_SETUP_REQUIRED && response.method === 'totp') {\n const setupData = response.setupData;\n if (!setupData || typeof setupData !== 'object') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires setupData with both secret and code',\n { details: { field: 'setupData' } },\n );\n }\n\n const secret = setupData['secret'];\n const code = setupData['code'];\n\n if (!secret || typeof secret !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires secret in setupData. Make sure to include the secret from getSetupData() response.',\n { details: { field: 'secret' } },\n );\n }\n\n if (!code || typeof code !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires code in setupData. Please enter the verification code from your authenticator app.',\n { details: { field: 'code' } },\n );\n }\n }\n\n try {\n const result = await this.post<AuthResponse>(this.config.endpoints.respondChallenge, response);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.CHALLENGE_INVALID,\n (error as Error).message || 'Challenge response failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Resend a challenge code.\n */\n async resendCode(session: string): Promise<{ destination: string }> {\n const payload: ResendCodeRequest = { session };\n return this.post<{ destination: string }>(this.config.endpoints.resendCode, payload);\n }\n\n /**\n * Get setup data for MFA.\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Setup data wrapped in GetSetupDataResponse\n */\n async getSetupData(session: string, method: GetSetupDataRequest['method']): Promise<GetSetupDataResponse> {\n const payload: GetSetupDataRequest = { session, method };\n return this.post<GetSetupDataResponse>(this.config.endpoints.getSetupData, payload);\n }\n\n /**\n * Get challenge data (e.g., WebAuthn options).\n *\n * Returns challenge-specific data for verification flows.\n *\n * @param session - Challenge session token\n * @param method - Challenge method to get data for\n * @returns Challenge data wrapped in GetChallengeDataResponse\n */\n async getChallengeData(\n session: string,\n method: GetChallengeDataRequest['method'],\n ): Promise<GetChallengeDataResponse> {\n const payload: GetChallengeDataRequest = { session, method };\n return this.post<GetChallengeDataResponse>(this.config.endpoints.getChallengeData, payload);\n }\n\n /**\n * Get current user profile.\n */\n async getProfile(): Promise<AuthUser> {\n const profile = await this.get<AuthUser>(this.config.endpoints.profile, true);\n await this.setUser(profile);\n return profile;\n }\n\n /**\n * Update user profile.\n */\n async updateProfile(updates: UpdateProfileRequest): Promise<AuthUser> {\n const updated = await this.put<AuthUser>(this.config.endpoints.updateProfile, updates, true);\n await this.setUser(updated);\n return updated;\n }\n\n /**\n * Change user password.\n */\n async changePassword(oldPassword: string, newPassword: string): Promise<void> {\n const payload: ChangePasswordRequest = { currentPassword: oldPassword, newPassword };\n await this.post(this.config.endpoints.changePassword, payload, true);\n }\n\n /**\n * Request a password reset code (forgot password).\n */\n async forgotPassword(identifier: string): Promise<ForgotPasswordResponse> {\n const payload: ForgotPasswordRequest = { identifier };\n return this.post<ForgotPasswordResponse>(this.config.endpoints.forgotPassword, payload);\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n async confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Promise<ConfirmForgotPasswordResponse> {\n const payload: ConfirmForgotPasswordRequest = { identifier, code, newPassword };\n const result = await this.post<ConfirmForgotPasswordResponse>(this.config.endpoints.confirmForgotPassword, payload);\n // ============================================================================\n // IMPORTANT: Password reset revokes all sessions\n // ============================================================================\n // WHY: The backend invalidates all sessions as a security measure. Clearing local auth state avoids\n // stale UI (e.g., still showing social-only/no-password state from cached user) and prevents the\n // client from attempting further authenticated calls with invalid tokens/cookies.\n await this.clearAuthState(false);\n return result;\n }\n\n /**\n * Request password change (must change on next login).\n */\n async requestPasswordChange(): Promise<void> {\n await this.post(this.config.endpoints.requestPasswordChange, {}, true);\n }\n\n /**\n * Get MFA status.\n */\n async getMfaStatus(): Promise<MFAStatus> {\n return this.get<MFAStatus>(this.config.endpoints.mfaStatus, true);\n }\n\n /**\n * Get MFA devices.\n */\n async getMfaDevices(): Promise<unknown[]> {\n return this.get<unknown[]>(this.config.endpoints.mfaDevices, true);\n }\n\n /**\n * Setup MFA device (authenticated user).\n */\n async setupMfaDevice(method: string): Promise<unknown> {\n return this.post<unknown>(this.config.endpoints.mfaSetupData, { method }, true);\n }\n\n /**\n * Verify MFA setup (authenticated user).\n */\n async verifyMfaSetup(\n method: string,\n setupData: Record<string, unknown>,\n deviceName?: string,\n ): Promise<{ deviceId: number }> {\n return this.post<{ deviceId: number }>(\n this.config.endpoints.mfaVerifySetup,\n { method, setupData, deviceName },\n true,\n );\n }\n\n /**\n * Remove MFA method.\n */\n async removeMfaDevice(method: string): Promise<{ message: string }> {\n const path = `${this.config.endpoints.mfaRemove}/${method}`;\n return this.delete<{ message: string }>(path, true);\n }\n\n /**\n * Set preferred MFA method.\n *\n * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey'). Cannot be 'backup'.\n * @returns Success message\n */\n async setPreferredMfaMethod(method: 'totp' | 'sms' | 'email' | 'passkey'): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.mfaPreferred, { method }, true);\n }\n\n /**\n * Generate backup codes.\n */\n async generateBackupCodes(): Promise<string[]> {\n const result = await this.post<{ codes: string[] }>(this.config.endpoints.mfaBackupCodes, {}, true);\n return result.codes;\n }\n\n /**\n * Set MFA exemption (admin/test scenarios).\n */\n async setMfaExemption(exempt: boolean, reason?: string): Promise<void> {\n await this.post(this.config.endpoints.mfaExemption, { exempt, reason }, true);\n }\n\n // ============================================================================\n // Event System\n // ============================================================================\n\n /**\n * Subscribe to authentication events.\n *\n * Emits events throughout the auth lifecycle for custom logic, analytics, or UI updates.\n *\n * @param event - Event type to listen for, or '*' for all events\n * @param listener - Callback function to handle the event\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * // Listen to successful authentication\n * const unsubscribe = client.on('auth:success', (event) => {\n * console.log('User logged in:', event.data.user);\n * analytics.track('login_success');\n * });\n *\n * // Listen to all events\n * client.on('*', (event) => {\n * console.log('Auth event:', event.type, event.data);\n * });\n *\n * // Unsubscribe when done\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n return this.eventEmitter.on(event, listener);\n }\n\n /**\n * Unsubscribe from authentication events.\n *\n * @param event - Event type\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.eventEmitter.off(event, listener);\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Start redirect-first social OAuth flow (web).\n *\n * This performs a browser navigation to:\n * `GET {baseUrl}/social/:provider/redirect?returnTo=...&appState=...`\n *\n * The backend:\n * - generates and stores CSRF state (cluster-safe)\n * - redirects the user to the provider\n * - completes OAuth on callback and sets cookies (or issues an exchange token)\n * - redirects back to `returnTo` with `appState` (and `exchangeToken` for json/hybrid)\n *\n * @param provider - OAuth provider ('google', 'apple', 'facebook')\n * @param options - Optional redirect options\n *\n * @example\n * ```typescript\n * await client.loginWithSocial('google', { returnTo: '/auth/callback', appState: '12345' });\n * ```\n */\n async loginWithSocial(provider: SocialProvider, options?: SocialLoginOptions): Promise<void> {\n // Emit event\n this.eventEmitter.emit({ type: 'oauth:started', data: { provider }, timestamp: Date.now() });\n\n if (hasWindow()) {\n const startPath = this.config.endpoints.socialRedirectStart.replace(':provider', provider);\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const startUrl = new URL(`${base}${startPath}`);\n\n const returnTo = options?.returnTo ?? this.config.redirects?.success ?? '/';\n\n startUrl.searchParams.set('returnTo', returnTo);\n // Only include action when deviating from the default ('login').\n if (options?.action === 'link') {\n startUrl.searchParams.set('action', 'link');\n }\n if (typeof options?.appState === 'string' && options.appState.trim() !== '') {\n startUrl.searchParams.set('appState', options.appState);\n }\n\n window.location.href = startUrl.toString();\n }\n }\n\n /**\n * Exchange an `exchangeToken` (from redirect callback URL) into an AuthResponse.\n *\n * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back\n * with `exchangeToken` instead of setting cookies.\n *\n * @param exchangeToken - One-time exchange token from the callback URL\n * @returns AuthResponse\n */\n async exchangeSocialRedirect(exchangeToken: string): Promise<AuthResponse> {\n const token = exchangeToken?.trim();\n if (!token) {\n throw new NAuthClientError(NAuthErrorCode.CHALLENGE_INVALID, 'Missing exchangeToken');\n }\n const result = await this.post<AuthResponse>(this.config.endpoints.socialExchange, { exchangeToken: token });\n await this.handleAuthResponse(result);\n return result;\n }\n\n /**\n * Verify native social token (mobile).\n */\n async verifyNativeSocial(request: SocialVerifyRequest): Promise<AuthResponse> {\n try {\n const path = this.config.endpoints.socialVerify.replace(':provider', request.provider);\n const result = await this.post<AuthResponse>(path, request);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n (error as Error).message || 'Social verification failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Get linked accounts.\n */\n async getLinkedAccounts(): Promise<LinkedAccountsResponse> {\n return this.get<LinkedAccountsResponse>(this.config.endpoints.socialLinked, true);\n }\n\n /**\n * Link social account.\n */\n async linkSocialAccount(provider: string, code: string, state: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialLink, { provider, code, state }, true);\n }\n\n /**\n * Unlink social account.\n */\n async unlinkSocialAccount(provider: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialUnlink, { provider }, true);\n }\n\n /**\n * Trust current device.\n */\n async trustDevice(): Promise<{ deviceToken: string }> {\n const result = await this.post<{ deviceToken: string }>(this.config.endpoints.trustDevice, {}, true);\n await this.setDeviceToken(result.deviceToken);\n return result;\n }\n\n /**\n * Check if the current device is trusted.\n *\n * Returns whether the current device is trusted based on the device token\n * (from cookie in cookies mode, or header in JSON mode).\n *\n * This performs a server-side validation of the device token and checks:\n * - Device token exists and is valid\n * - Device token matches a trusted device record in the database\n * - Trust has not expired\n *\n * @returns Object with trusted status\n *\n * @example\n * ```typescript\n * const result = await client.isTrustedDevice();\n * if (result.trusted) {\n * console.log('This device is trusted');\n * }\n * ```\n */\n async isTrustedDevice(): Promise<{ trusted: boolean }> {\n return this.get<{ trusted: boolean }>(this.config.endpoints.isTrustedDevice, true);\n }\n\n /**\n * Get paginated audit history for the current user.\n *\n * Returns authentication and security events with full audit details including:\n * - Event type (login, logout, MFA, etc.)\n * - Event status (success, failure, suspicious)\n * - Device information, location, risk factors\n *\n * @param params - Query parameters for filtering and pagination\n * @returns Paginated audit history response\n *\n * @example\n * ```typescript\n * const history = await client.getAuditHistory({\n * page: 1,\n * limit: 20,\n * eventType: 'LOGIN_SUCCESS'\n * });\n * ```\n */\n async getAuditHistory(params?: Record<string, string | number | boolean>): Promise<AuditHistoryResponse> {\n const entries: [string, string][] = Object.entries(params ?? {}).map(([k, v]) => [k, String(v)]);\n const query = entries.length > 0 ? `?${new URLSearchParams(entries).toString()}` : '';\n const path = `${this.config.endpoints.auditHistory}${query}`;\n return this.get<AuditHistoryResponse>(path, true);\n }\n\n /**\n * Initialize client by hydrating state from storage.\n * Call this on app startup to restore auth state.\n */\n async initialize(): Promise<void> {\n const userJson = await this.config.storage.getItem(USER_KEY);\n if (userJson) {\n try {\n this.currentUser = JSON.parse(userJson) as AuthUser;\n this.config.onAuthStateChange?.(this.currentUser);\n } catch {\n // Invalid stored user - clear it\n await this.config.storage.removeItem(USER_KEY);\n }\n }\n }\n\n /**\n * Determine if user is authenticated (async - checks tokens).\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.tokenManager.getTokens();\n return Boolean(tokens.accessToken);\n }\n\n /**\n * Determine if user is authenticated (sync - checks cached user).\n * Use this for guards and sync checks. Use `isAuthenticated()` for definitive check.\n */\n isAuthenticatedSync(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current access token (may be null).\n */\n async getAccessToken(): Promise<string | null> {\n const tokens = await this.tokenManager.getTokens();\n return tokens.accessToken ?? null;\n }\n\n /**\n * Get current user (cached, sync).\n */\n getCurrentUser(): AuthUser | null {\n return this.currentUser;\n }\n\n /**\n * Get stored challenge session (for resuming challenge flows).\n */\n async getStoredChallenge(): Promise<AuthResponse | null> {\n const raw = await this.config.storage.getItem(CHALLENGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as AuthResponse;\n } catch {\n return null;\n }\n }\n\n /**\n * Clear stored challenge session.\n */\n async clearStoredChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Internal: handle auth response (tokens or challenge).\n *\n * In cookies mode: Tokens are set as httpOnly cookies by backend, not stored in client storage.\n * In JSON mode: Tokens are stored in tokenManager for Authorization header.\n */\n private async handleAuthResponse(response: AuthResponse): Promise<void> {\n if (response.challengeName) {\n await this.persistChallenge(response);\n return;\n }\n\n // Only store tokens in JSON mode (cookies mode uses httpOnly cookies set by backend)\n if (this.config.tokenDelivery === 'json' && response.accessToken && response.refreshToken) {\n await this.tokenManager.setTokens({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n accessTokenExpiresAt: response.accessTokenExpiresAt ?? 0,\n refreshTokenExpiresAt: response.refreshTokenExpiresAt ?? 0,\n });\n }\n\n // Device token handling (only for JSON mode - cookies mode uses httpOnly cookie)\n if (this.config.tokenDelivery === 'json' && response.deviceToken) {\n await this.setDeviceToken(response.deviceToken);\n }\n\n // Always store user info (needed for both modes)\n if (response.user) {\n const user = response.user as AuthUser;\n // WHY: Consumers often need to know if the current session was created via password\n // or via a specific social provider (google/apple/facebook).\n user.sessionAuthMethod = response.authMethod ?? null;\n await this.setUser(user);\n }\n\n await this.clearChallenge();\n }\n\n /**\n * Persist challenge state.\n */\n private async persistChallenge(challenge: AuthResponse): Promise<void> {\n await this.config.storage.setItem(CHALLENGE_KEY, JSON.stringify(challenge));\n }\n\n /**\n * Clear challenge state.\n */\n private async clearChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Persist user.\n */\n private async setUser(user: AuthUser): Promise<void> {\n this.currentUser = user;\n await this.config.storage.setItem(USER_KEY, JSON.stringify(user));\n this.config.onAuthStateChange?.(user);\n }\n\n /**\n * Clear all auth state.\n *\n * @param forgetDevice - If true, also clear device token (for JSON mode)\n */\n private async clearAuthState(forgetDevice?: boolean): Promise<void> {\n this.currentUser = null;\n await this.tokenManager.clearTokens();\n await this.config.storage.removeItem(USER_KEY);\n\n // Clear device token in JSON mode (cookies mode uses httpOnly cookie cleared by backend)\n if (forgetDevice && this.config.tokenDelivery === 'json') {\n await this.config.storage.removeItem(this.config.deviceTrust.storageKey);\n }\n\n this.config.onAuthStateChange?.(null);\n }\n\n /**\n * Persist device token (json mode mobile).\n */\n private async setDeviceToken(token: string): Promise<void> {\n await this.config.storage.setItem(this.config.deviceTrust.storageKey, token);\n }\n\n /**\n * Determine token delivery mode for this environment.\n */\n private getTokenDeliveryMode(): 'json' | 'cookies' {\n return this.config.tokenDelivery;\n }\n\n /**\n * Build request URL by combining baseUrl with path.\n * @private\n */\n private buildUrl(path: string): string {\n return `${this.config.baseUrl}${path}`;\n }\n\n /**\n * Build request headers for authentication.\n * @private\n */\n private async buildHeaders(auth: boolean): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n // Add access token in JSON mode\n if (auth && this.config.tokenDelivery === 'json') {\n const accessToken = (await this.tokenManager.getTokens()).accessToken;\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n }\n }\n\n // ============================================================================\n // Trusted Device Header (JSON mode)\n // ============================================================================\n // In cookies mode the device token is sent automatically via httpOnly cookie.\n // In JSON mode the backend expects the device token via a header (default: X-Device-Token).\n //\n // This is required for:\n // - Checking trust status (`isTrustedDevice`)\n // - Skipping MFA on future logins when a device is trusted\n //\n // We intentionally send it on all requests in JSON mode so the backend can\n // consistently associate requests with a trusted device when present.\n if (this.config.tokenDelivery === 'json') {\n try {\n const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);\n if (deviceToken) {\n headers[this.config.deviceTrust.headerName] = deviceToken;\n }\n } catch {\n // Non-fatal: storage can fail in restricted environments (private mode, SSR, etc.).\n }\n }\n\n // Add CSRF token for mutating requests in cookies mode\n if (this.config.tokenDelivery === 'cookies' && hasWindow()) {\n const csrfToken = this.getCsrfToken();\n if (csrfToken) {\n headers[this.config.csrf.headerName] = csrfToken;\n }\n }\n\n return headers;\n }\n\n /**\n * Get CSRF token from cookie (browser only).\n * @private\n */\n private getCsrfToken(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n }\n\n /**\n * Execute GET request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async get<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'GET',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute POST request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async post<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'POST',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute PUT request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async put<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'PUT',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute DELETE request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async delete<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'DELETE',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Handle cross-tab storage updates.\n */\n private readonly handleStorageEvent = (event: StorageEvent): void => {\n if (event.key === 'nauth_sync') {\n // Best-effort reload of user state\n this.config.storage\n .getItem(USER_KEY)\n .then((value: string | null) => (value ? (JSON.parse(value) as AuthUser) : null))\n .then((user: AuthUser | null) => {\n this.currentUser = user;\n this.config.onAuthStateChange?.(user);\n })\n .catch(() => {\n // ignore\n });\n }\n };\n}\n","import { AuthResponse, AuthChallenge } from '../types/auth.types';\nimport { MFAMethod } from '../types/mfa.types';\n\n/**\n * Helper utilities for working with authentication challenges.\n *\n * These utilities reduce boilerplate in consumer applications by providing\n * type-safe access to challenge parameters and state detection.\n */\n\n/**\n * Check if a challenge requires phone collection (user has no phone number).\n *\n * @param challenge - Auth response with challenge\n * @returns True if phone collection is required\n *\n * @example\n * ```typescript\n * const challenge = auth.getCurrentChallenge();\n * if (challenge && requiresPhoneCollection(challenge)) {\n * // Show phone input form\n * }\n * ```\n */\nexport function requiresPhoneCollection(challenge: AuthResponse): boolean {\n if (challenge.challengeName !== AuthChallenge.VERIFY_PHONE) {\n return false;\n }\n\n const params = challenge.challengeParameters;\n return (params?.['requiresPhoneCollection'] as string) === 'true';\n}\n\n/**\n * Get masked destination (email or phone) from challenge parameters.\n *\n * For VERIFY_EMAIL/VERIFY_PHONE challenges, returns `codeDeliveryDestination`.\n * For MFA_REQUIRED challenges, returns `maskedEmail` or `maskedPhone` based on method.\n *\n * @param challenge - Auth response with challenge\n * @returns Masked destination string or null if not available\n *\n * @example\n * ```typescript\n * const destination = getMaskedDestination(challenge);\n * if (destination) {\n * console.log(`Code sent to ${destination}`);\n * }\n * ```\n */\nexport function getMaskedDestination(challenge: AuthResponse): string | null {\n const params = challenge.challengeParameters;\n if (!params) {\n return null;\n }\n\n const challengeName = challenge.challengeName;\n\n if (challengeName === AuthChallenge.MFA_REQUIRED) {\n // MFA_REQUIRED uses maskedEmail or maskedPhone based on preferredMethod\n const method = (params?.['preferredMethod'] || params?.['method']) as MFAMethod | undefined;\n if (method === 'sms') {\n return (params['maskedPhone'] as string) || null;\n }\n if (method === 'email') {\n return (params['maskedEmail'] as string) || null;\n }\n // Fallback: try both if method is not specified\n return (params['maskedPhone'] as string) || (params['maskedEmail'] as string) || null;\n }\n\n // VERIFY_EMAIL and VERIFY_PHONE use codeDeliveryDestination\n return (params['codeDeliveryDestination'] as string) || null;\n}\n\n/**\n * Get preferred MFA method from challenge parameters.\n *\n * @param challenge - Auth response with MFA_REQUIRED challenge\n * @returns MFA method or undefined if not available\n *\n * @example\n * ```typescript\n * const method = getMFAMethod(challenge);\n * if (method === 'totp') {\n * // Show TOTP input\n * }\n * ```\n */\nexport function getMFAMethod(challenge: AuthResponse): MFAMethod | undefined {\n if (challenge.challengeName !== AuthChallenge.MFA_REQUIRED) {\n return undefined;\n }\n\n const params = challenge.challengeParameters;\n return (params?.['preferredMethod'] || params?.['method']) as MFAMethod | undefined;\n}\n\n/**\n * Get challenge instructions from challenge parameters.\n *\n * @param challenge - Auth response with challenge\n * @returns Instructions string or undefined if not available\n *\n * @example\n * ```typescript\n * const instructions = getChallengeInstructions(challenge);\n * if (instructions) {\n * console.log(instructions);\n * }\n * ```\n */\nexport function getChallengeInstructions(challenge: AuthResponse): string | undefined {\n const params = challenge.challengeParameters;\n return params?.['instructions'] as string | undefined;\n}\n\n/**\n * Check if challenge is OTP-based (requires code input).\n *\n * @param challenge - Auth response with challenge\n * @returns True if challenge requires OTP code\n *\n * @example\n * ```typescript\n * if (isOTPChallenge(challenge)) {\n * // Show OTP input component\n * }\n * ```\n */\nexport function isOTPChallenge(challenge: AuthResponse): boolean {\n const challengeName = challenge.challengeName;\n return (\n challengeName === AuthChallenge.VERIFY_EMAIL ||\n challengeName === AuthChallenge.VERIFY_PHONE ||\n challengeName === AuthChallenge.MFA_REQUIRED\n );\n}\n"],"mappings":"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","names":["AuthChallenge","NAuthErrorCode","AuthAuditEventType","USER_KEY","CHALLENGE_KEY"]}
package/dist/index.d.mts CHANGED
@@ -85,6 +85,16 @@ interface AuthResponse {
85
85
  refreshToken?: string;
86
86
  accessTokenExpiresAt?: number;
87
87
  refreshTokenExpiresAt?: number;
88
+ /**
89
+ * Authentication method used to create the current session.
90
+ *
91
+ * Examples:
92
+ * - `password`
93
+ * - `google`
94
+ * - `apple`
95
+ * - `facebook`
96
+ */
97
+ authMethod?: string;
88
98
  trusted?: boolean;
89
99
  deviceToken?: string;
90
100
  challengeName?: AuthChallenge;
@@ -229,6 +239,13 @@ interface AuthUser {
229
239
  mfaEnabled?: boolean;
230
240
  socialProviders?: string[] | null;
231
241
  hasPasswordHash: boolean;
242
+ /**
243
+ * Authentication method used to create the current session.
244
+ *
245
+ * This is session-scoped (how the user logged in this time), not an account capability.
246
+ * Use `hasPasswordHash` and `socialProviders` to determine what login methods the account supports.
247
+ */
248
+ sessionAuthMethod?: string | null;
232
249
  createdAt?: string | Date;
233
250
  updatedAt?: string | Date;
234
251
  }
@@ -306,12 +323,6 @@ interface SocialLoginOptions {
306
323
  * Default: 'login'
307
324
  */
308
325
  action?: 'login' | 'link';
309
- /**
310
- * Optional delivery preference for redirect-first flows.
311
- *
312
- * Useful for hybrid deployments where provider callbacks do not contain a reliable `Origin`.
313
- */
314
- delivery?: 'cookies' | 'json';
315
326
  }
316
327
  /**
317
328
  * Linked social accounts response.
package/dist/index.d.ts CHANGED
@@ -85,6 +85,16 @@ interface AuthResponse {
85
85
  refreshToken?: string;
86
86
  accessTokenExpiresAt?: number;
87
87
  refreshTokenExpiresAt?: number;
88
+ /**
89
+ * Authentication method used to create the current session.
90
+ *
91
+ * Examples:
92
+ * - `password`
93
+ * - `google`
94
+ * - `apple`
95
+ * - `facebook`
96
+ */
97
+ authMethod?: string;
88
98
  trusted?: boolean;
89
99
  deviceToken?: string;
90
100
  challengeName?: AuthChallenge;
@@ -229,6 +239,13 @@ interface AuthUser {
229
239
  mfaEnabled?: boolean;
230
240
  socialProviders?: string[] | null;
231
241
  hasPasswordHash: boolean;
242
+ /**
243
+ * Authentication method used to create the current session.
244
+ *
245
+ * This is session-scoped (how the user logged in this time), not an account capability.
246
+ * Use `hasPasswordHash` and `socialProviders` to determine what login methods the account supports.
247
+ */
248
+ sessionAuthMethod?: string | null;
232
249
  createdAt?: string | Date;
233
250
  updatedAt?: string | Date;
234
251
  }
@@ -306,12 +323,6 @@ interface SocialLoginOptions {
306
323
  * Default: 'login'
307
324
  */
308
325
  action?: 'login' | 'link';
309
- /**
310
- * Optional delivery preference for redirect-first flows.
311
- *
312
- * Useful for hybrid deployments where provider callbacks do not contain a reliable `Origin`.
313
- */
314
- delivery?: 'cookies' | 'json';
315
326
  }
316
327
  /**
317
328
  * Linked social accounts response.