# `auth-context` _(no submodules)_ ## Purpose `auth-context.tsx` exposes the React Context surface for the auth flow. It defines `AuthContext`, the `AuthProvider` component, and the `useAuth()` hook. The provider owns an `AuthClient` instance (either injected or constructed from `config`) and a state block of `{ user, session, isLoading, isAuthenticated, error }`. On mount (unless `skipInitialCheck` is set) it fetches the current session, normalises it through `transformSessionResponse`, and settles the state. It exposes eleven action callbacks (`signIn`, `signUp`, `signOut`, `updateProfile`, `changePassword`, `forgotPassword`, `resetPassword`, `verifyEmail`, `resendVerificationEmail`, `deleteAccount`, `refreshSession`) — every action wraps `client` calls with loading/error state mutations, re-fetches the session where appropriate, records the corresponding OTel counter, and re-throws on failure so callers can `catch` for form-level UI handling. `useAuth()` outside an `AuthProvider` throws `ReactAuthContextMissingError` so the failure is immediate and typed rather than a downstream `undefined` access. ## Features - `AuthContext` + `AuthProvider` + `useAuth()` triple. - 11 typed action callbacks; each settles `isLoading` and surfaces `error` deterministically. - `skipInitialCheck` flag short-circuits the mount-time session fetch (test surface). - `onAuthStateChange` callback fires on every state transition (useful for analytics). - Re-throws action errors so form-level UI can render messages; never silently swallows. ## Usage: Basic ```tsx import { AuthProvider, useAuth } from "@suaveplan/react-auth"; function Inside() { const { user, signOut } = useAuth(); return user ? : null; } ; ``` ## Usage: Advanced Inject a pre-built client and observe state changes: ```tsx import { AuthProvider, createAuthClient, type AuthState, } from "@suaveplan/react-auth"; const client = createAuthClient({ baseURL: "https://auth.example.com", siteDomain: "tenant-a", }); function onAuthStateChange(state: AuthState) { analytics.track("auth_state", { authenticated: state.isAuthenticated }); } {/* ... */} ; ``` ## API Reference - `interface AuthState` — `{ user: User | null; session: Session | null; isLoading: boolean; isAuthenticated: boolean; error: Error | null }`. - `interface AuthContextValue extends AuthState` — adds `client: AuthClient` plus the 11 action callbacks. - `interface AuthProviderProps` — `{ children: ReactNode; config: AuthClientConfig; client?: AuthClient; onAuthStateChange?: (state: AuthState) => void; skipInitialCheck?: boolean }`. - `const AuthContext: React.Context` — context handle. - `function AuthProvider(props: AuthProviderProps): ReactNode` — wraps children with the context. - `function useAuth(): AuthContextValue` — reads the context; throws `ReactAuthContextMissingError` when outside an `AuthProvider`. ## Implementation Notes State is consolidated in a single `useState` block so transitions are atomic — callers never see a half-updated value. Every action wraps its critical section in `try`/`catch`/`finally`-style logic but with explicit `setState` calls rather than a `finally` clause, because the success and failure branches set different sets of fields. Caught values pass through `toError(value)` which wraps non-`Error` throwables so the `error` field is always a real `Error` (this avoids violating biome's `useThrowOnlyError` rule when a downstream surface re-throws from the context). Session fetches go through `timedSessionFetch` which records the wall-clock duration into the `react_auth.session_fetch.duration_ms` histogram with a `success`/`failure` label. The `mounted` ref guards the initial-load effect from setting state after unmount; React 19's `StrictMode` double-mount runs the cleanup before the second mount, so the first effect's `mounted = false` is honoured.