{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/transport.ts","../src/storage.ts"],"sourcesContent":["/**\n * @zyphr-dev/auth-react-native\n *\n * React Native bindings for Zyphr auth. Wrap your app in <ZyphrAuthProvider> and\n * read the session with useSession() / act with useAuth(). Same session engine as\n * the web binding (@zyphr-dev/auth-core), plus a secure-storage adapter and\n * refresh-on-foreground via React Native's AppState.\n */\n\nexport { ZyphrAuthProvider, useSession, useAuth } from './provider.js';\nexport type { ZyphrAuthProviderProps, UseAuthResult } from './provider.js';\n\nexport { createZyphrTransport } from './transport.js';\nexport { secureStoreAdapter, asyncStorageAdapter, keychainAdapter } from './storage.js';\nexport type { KeychainModule } from './storage.js';\n\nexport type { SessionState, SessionStatus, LoginParams, TokenStorage } from '@zyphr-dev/auth-core';\n","import {\n  createContext,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  type ReactElement,\n  type ReactNode,\n} from 'react';\nimport { AppState, type AppStateStatus } from 'react-native';\nimport type { ZyphrClient } from '@zyphr-dev/node-sdk';\nimport {\n  SessionManager,\n  type LoginParams,\n  type SessionState,\n  type TokenStorage,\n} from '@zyphr-dev/auth-core';\nimport { createZyphrTransport } from './transport.js';\n\nexport interface ZyphrAuthProviderProps {\n  /** A client-safe ZyphrClient (constructed with your publishable application key). */\n  client: ZyphrClient;\n  /**\n   * Where tokens persist. Strongly recommended in production — pass a secure\n   * store via `secureStoreAdapter(SecureStore)` (expo-secure-store) or\n   * `asyncStorageAdapter(AsyncStorage)`. Defaults to in-memory (tokens are lost\n   * on app restart), which is fine only for prototyping.\n   */\n  storage?: TokenStorage;\n  /**\n   * Namespace the storage key so multiple providers can share one storage\n   * adapter without colliding (e.g. one session per account for account\n   * switching). The effective key becomes `${keyPrefix}zyphr.session`. Default `''`.\n   */\n  keyPrefix?: string;\n  /** Refresh this many ms before the access token expires. Default 60_000. */\n  refreshSkewMs?: number;\n  /**\n   * Refresh the session when the app returns to the foreground (default true).\n   * A backgrounded app's scheduled refresh timer may not fire reliably, so we\n   * also refresh on foreground to keep the token fresh.\n   */\n  refreshOnForeground?: boolean;\n  children: ReactNode;\n}\n\ninterface ZyphrAuthContextValue {\n  manager: SessionManager;\n}\n\nconst ZyphrAuthContext = createContext<ZyphrAuthContextValue | null>(null);\n\n/**\n * Provides a reactive Zyphr auth session to a React Native app. Same session\n * engine as the web binding (@zyphr-dev/auth-core), plus refresh-on-foreground\n * via React Native's AppState. Read state with {@link useSession}, act with\n * {@link useAuth}.\n */\nexport function ZyphrAuthProvider({\n  client,\n  storage,\n  keyPrefix,\n  refreshSkewMs,\n  refreshOnForeground = true,\n  children,\n}: ZyphrAuthProviderProps): ReactElement {\n  const [manager] = useState(\n    () =>\n      new SessionManager({\n        transport: createZyphrTransport(client),\n        // Pass storage through as-is: auth-core applies the in-memory default\n        // AND emits the dev-mode \"no storage\" warning when it's omitted. Don't\n        // default it here or that warning would never fire for RN consumers.\n        storage,\n        keyPrefix,\n        refreshSkewMs,\n      }),\n  );\n\n  const initialized = useRef(false);\n  useEffect(() => {\n    if (!initialized.current) {\n      initialized.current = true;\n      void manager.initialize();\n    }\n    return () => {\n      manager.destroy();\n    };\n  }, [manager]);\n\n  // Refresh when the app returns to the foreground.\n  useEffect(() => {\n    if (!refreshOnForeground || !AppState?.addEventListener) return;\n    const onChange = (next: AppStateStatus) => {\n      if (next === 'active' && manager.getState().isAuthenticated) {\n        void manager.refresh();\n      }\n    };\n    const sub = AppState.addEventListener('change', onChange);\n    return () => {\n      // RN >= 0.65 returns a subscription with .remove(); older returns void.\n      (sub as { remove?: () => void } | undefined)?.remove?.();\n    };\n  }, [manager, refreshOnForeground]);\n\n  const value = useMemo(() => ({ manager }), [manager]);\n  return <ZyphrAuthContext.Provider value={value}>{children}</ZyphrAuthContext.Provider>;\n}\n\nfunction useManager(): SessionManager {\n  const ctx = useContext(ZyphrAuthContext);\n  if (!ctx) {\n    throw new Error('useSession/useAuth must be used within a <ZyphrAuthProvider>.');\n  }\n  return ctx.manager;\n}\n\n/** Reactive session state — re-renders on login, logout, refresh. */\nexport function useSession(): SessionState {\n  const manager = useManager();\n  return useSyncExternalStore(\n    (onChange) => manager.subscribe(() => onChange()),\n    () => manager.getState(),\n    () => manager.getState(),\n  );\n}\n\nexport interface UseAuthResult {\n  login: (params: LoginParams) => Promise<void>;\n  logout: () => Promise<void>;\n  refresh: () => Promise<void>;\n}\n\n/** Auth actions bound to the provider's session manager. */\nexport function useAuth(): UseAuthResult {\n  const manager = useManager();\n  return useMemo(\n    () => ({\n      login: (params) => manager.login(params),\n      logout: () => manager.logout(),\n      refresh: () => manager.refresh(),\n    }),\n    [manager],\n  );\n}\n","import type { ZyphrClient } from '@zyphr-dev/node-sdk';\nimport { type AuthTransport, type LoginParams, type SessionTokens, toSessionTokens } from '@zyphr-dev/auth-core';\n\n/**\n * An {@link AuthTransport} over the client-safe `ZyphrClient` (publishable\n * application key — no secret in the app bundle). Same transport the web binding\n * uses; re-implemented here so the React Native package doesn't depend on\n * `@zyphr-dev/auth-react` (which pulls web-React types).\n */\nexport function createZyphrTransport(client: ZyphrClient, now: () => number = Date.now): AuthTransport {\n  const extract = (tokens?: { accessToken?: string; refreshToken?: string; expiresIn?: number }): SessionTokens =>\n    toSessionTokens(\n      { accessToken: tokens?.accessToken, refreshToken: tokens?.refreshToken, expiresIn: tokens?.expiresIn },\n      now(),\n    );\n\n  return {\n    async login({ email, password }: LoginParams): Promise<SessionTokens> {\n      const res = await client.auth.login.loginEndUser({ email, password });\n      return extract(res.data?.tokens);\n    },\n    async refresh(refreshToken: string): Promise<SessionTokens> {\n      const res = await client.auth.sessions.refreshEndUserToken({ refreshToken });\n      return extract(res.data?.tokens);\n    },\n    async logout(refreshToken: string): Promise<void> {\n      await client.auth.sessions.revokeEndUserSession({ refreshToken });\n    },\n  };\n}\n","import type { TokenStorage } from '@zyphr-dev/auth-core';\n\n/**\n * The minimal async key/value shape common to React Native secure stores —\n * `expo-secure-store` (getItemAsync/setItemAsync/deleteItemAsync) and\n * `@react-native-async-storage/async-storage` (getItem/setItem/removeItem) both\n * fit one of these once wrapped. We keep the dependency OPTIONAL: the app passes\n * whichever it uses, so we don't force a native module on every consumer.\n */\n\n/** Adapt `expo-secure-store` (the recommended secure default). */\nexport function secureStoreAdapter(secureStore: {\n  getItemAsync(key: string): Promise<string | null>;\n  setItemAsync(key: string, value: string): Promise<void>;\n  deleteItemAsync(key: string): Promise<void>;\n}): TokenStorage {\n  return {\n    getItem: (key) => secureStore.getItemAsync(key),\n    setItem: (key, value) => secureStore.setItemAsync(key, value),\n    removeItem: (key) => secureStore.deleteItemAsync(key),\n  };\n}\n\n/**\n * Adapt `@react-native-async-storage/async-storage`. NOTE: AsyncStorage is NOT\n * encrypted — prefer {@link secureStoreAdapter} for tokens. Provided for apps\n * that already standardize on AsyncStorage and accept the tradeoff.\n */\nexport function asyncStorageAdapter(asyncStorage: {\n  getItem(key: string): Promise<string | null>;\n  setItem(key: string, value: string): Promise<void>;\n  removeItem(key: string): Promise<void>;\n}): TokenStorage {\n  return {\n    getItem: (key) => asyncStorage.getItem(key),\n    setItem: (key, value) => asyncStorage.setItem(key, value),\n    removeItem: (key) => asyncStorage.removeItem(key),\n  };\n}\n\n/** The subset of `react-native-keychain` this adapter uses. */\nexport interface KeychainModule {\n  setGenericPassword(\n    username: string,\n    password: string,\n    options?: { service?: string },\n  ): Promise<unknown>;\n  getGenericPassword(\n    options?: { service?: string },\n  ): Promise<false | { username: string; password: string }>;\n  resetGenericPassword(options?: { service?: string }): Promise<boolean>;\n}\n\n/** Fixed username — the session lives in the `password` field; only one entry per service. */\nconst KEYCHAIN_USER = 'zyphr';\n\n/**\n * Adapt `react-native-keychain` (iOS Keychain / Android Keystore) — the\n * recommended secure store for **bare** React Native (no Expo). Encrypted at the\n * OS level, appropriate for long-lived refresh tokens.\n *\n * Keychain's API is service-based rather than key/value, so each storage `key`\n * maps to its own keychain **service** (`setGenericPassword(user, value, { service: key })`).\n * The core only ever uses a single key (`zyphr.session`, or `${keyPrefix}zyphr.session`\n * for per-account isolation), so each session is one service entry.\n *\n * ```ts\n * import * as Keychain from 'react-native-keychain';\n * <ZyphrAuthProvider client={client} storage={keychainAdapter(Keychain)} />\n * ```\n *\n * `react-native-keychain` is an OPTIONAL peer dependency — install it only if\n * you use this adapter.\n */\nexport function keychainAdapter(keychain: KeychainModule): TokenStorage {\n  return {\n    getItem: async (key) => {\n      const result = await keychain.getGenericPassword({ service: key });\n      return result ? result.password : null;\n    },\n    setItem: (key, value) =>\n      keychain.setGenericPassword(KEYCHAIN_USER, value, { service: key }).then(() => undefined),\n    removeItem: (key) => keychain.resetGenericPassword({ service: key }).then(() => undefined),\n  };\n}\n"],"mappings":"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","names":["import_auth_core"]}