{ "module": "react-auth", "content": { "path": "react-auth", "docstring": "# react-auth\r\n\r\nAuthentication UI and state for Khata front-ends: a JWT-backed\r\n`AuthProvider` context, a pluggable login/register `AuthPage`, profile\r\nscreens, and an axios factory that attaches bearer tokens and reacts to\r\n`401` responses.\r\n\r\n## What this library gives you\r\n\r\n- **`AuthProvider` + `useAuth`** - manages the current user, token, and\r\n loading/error state; persists the token in `localStorage` and re-fetches\r\n the current user whenever the token changes.\r\n- **`createApiClient`** - creates an axios instance whose request\r\n interceptor adds `Authorization: Bearer `, and whose response\r\n interceptor clears the token and dispatches a `auth:unauthorized` window\r\n event on `401`.\r\n- **`AuthPage`** - a ready-made login/register screen driven by the\r\n `useAuth` callbacks.\r\n- **`ProfileCreate` / `ProfileEdit` / `ProfileView`** - presentational\r\n profile screens that delegate persistence to callbacks you supply.\r\n- **`tokenStore`** - the raw `localStorage` accessor (`get`/`set`/`clear`).\r\n\r\n## Wiring\r\n\r\n```tsx\r\nimport { AuthProvider, useAuth, AuthPage } from \"react-auth\";\r\n\r\nfunction LoginGate() {\r\n const auth = useAuth();\r\n if (!auth.currentUser) {\r\n return (\r\n history.back()}\r\n onSwitchMode={() => setMode(\"register\")}\r\n login={auth.login}\r\n register={auth.register}\r\n loading={auth.loading}\r\n error={auth.error}\r\n currentUser={auth.currentUser}\r\n />\r\n );\r\n }\r\n return ;\r\n}\r\n\r\nexport default function Root() {\r\n return (\r\n \r\n \r\n \r\n );\r\n}\r\n```", "objects": { "AuthServerConfig": { "name": "AuthServerConfig", "kind": "interface", "path": "react-auth.AuthServerConfig", "signature": "AuthServerConfig", "docstring": "Endpoint configuration consumed by `AuthProvider`.\r\n\r\nEvery `*Path` value is resolved relative to `serverUrl`.", "members": { "introspectPath": { "name": "introspectPath", "kind": "property", "path": "react-auth.AuthServerConfig.introspectPath", "signature": "introspectPath: string", "docstring": "Token introspection endpoint (available to callers that need it)." }, "loginPath": { "name": "loginPath", "kind": "property", "path": "react-auth.AuthServerConfig.loginPath", "signature": "loginPath: string", "docstring": "`POST { username, password }` -> `{ access_token, user }`." }, "logoutPath": { "name": "logoutPath", "kind": "property", "path": "react-auth.AuthServerConfig.logoutPath", "signature": "logoutPath: string", "docstring": "Called on logout; failures are ignored (token is cleared locally)." }, "mePath": { "name": "mePath", "kind": "property", "path": "react-auth.AuthServerConfig.mePath", "signature": "mePath: string", "docstring": "Returns the current `AuthUser` for a valid bearer token." }, "registerPath": { "name": "registerPath", "kind": "property", "path": "react-auth.AuthServerConfig.registerPath", "signature": "registerPath: string", "docstring": "`POST { username, password }` to create an account." }, "serverUrl": { "name": "serverUrl", "kind": "property", "path": "react-auth.AuthServerConfig.serverUrl", "signature": "serverUrl: string", "docstring": "Base URL of the auth server, for example `\"https://api.example.com\"`." } } }, "AuthUser": { "name": "AuthUser", "kind": "interface", "path": "react-auth.AuthUser", "signature": "AuthUser", "docstring": "The authenticated user returned by the auth server (`/me` and login).\n\nThis is the shape produced by the backend user model; it is intentionally\npermissive so it can be spread into application state without loss.", "members": { "_id": { "name": "_id", "kind": "property", "path": "react-auth.AuthUser._id", "signature": "_id: null | string", "docstring": "Backend document id (may be absent before the record is persisted)." }, "created_at": { "name": "created_at", "kind": "property", "path": "react-auth.AuthUser.created_at", "signature": "created_at: string", "docstring": "ISO-8601 creation timestamp." }, "email": { "name": "email", "kind": "property", "path": "react-auth.AuthUser.email", "signature": "email: string", "docstring": "Contact email address." }, "is_active": { "name": "is_active", "kind": "property", "path": "react-auth.AuthUser.is_active", "signature": "is_active: boolean", "docstring": "Whether the account is allowed to authenticate." }, "updated_at": { "name": "updated_at", "kind": "property", "path": "react-auth.AuthUser.updated_at", "signature": "updated_at: string", "docstring": "ISO-8601 last-update timestamp." }, "username": { "name": "username", "kind": "property", "path": "react-auth.AuthUser.username", "signature": "username: string", "docstring": "Unique login handle." } } }, "ProfileCreateProps": { "name": "ProfileCreateProps", "kind": "interface", "path": "react-auth.ProfileCreateProps", "signature": "ProfileCreateProps", "docstring": "Props for `ProfileCreate`.", "members": { "defaultEmail": { "name": "defaultEmail", "kind": "property", "path": "react-auth.ProfileCreateProps.defaultEmail", "signature": "defaultEmail: string", "docstring": "Pre-filled email address." }, "defaultUsername": { "name": "defaultUsername", "kind": "property", "path": "react-auth.ProfileCreateProps.defaultUsername", "signature": "defaultUsername: string", "docstring": "Existing username to show (disabled) and to use as a name fallback." }, "error": { "name": "error", "kind": "property", "path": "react-auth.ProfileCreateProps.error", "signature": "error: null | string", "docstring": "Error message to display beneath the form." }, "loading": { "name": "loading", "kind": "property", "path": "react-auth.ProfileCreateProps.loading", "signature": "loading: boolean", "docstring": "Shows a spinner and disables the actions." }, "onBack": { "name": "onBack", "kind": "property", "path": "react-auth.ProfileCreateProps.onBack", "signature": "onBack: void", "docstring": "When provided, renders a \"Back\" button that calls this." }, "onSubmit": { "name": "onSubmit", "kind": "property", "path": "react-auth.ProfileCreateProps.onSubmit", "signature": "onSubmit: Promise", "docstring": "Called with the collected `{ name, email }` on submit." } } }, "ProfileEditProps": { "name": "ProfileEditProps", "kind": "interface", "path": "react-auth.ProfileEditProps", "signature": "ProfileEditProps", "docstring": "Props for `ProfileEdit`.", "members": { "email": { "name": "email", "kind": "property", "path": "react-auth.ProfileEditProps.email", "signature": "email: string", "docstring": "Initial email address." }, "error": { "name": "error", "kind": "property", "path": "react-auth.ProfileEditProps.error", "signature": "error: null | string", "docstring": "Error message to display beneath the form." }, "loading": { "name": "loading", "kind": "property", "path": "react-auth.ProfileEditProps.loading", "signature": "loading: boolean", "docstring": "Shows a spinner and disables the actions." }, "name": { "name": "name", "kind": "property", "path": "react-auth.ProfileEditProps.name", "signature": "name: string", "docstring": "Initial full name." }, "onBack": { "name": "onBack", "kind": "property", "path": "react-auth.ProfileEditProps.onBack", "signature": "onBack: void", "docstring": "When provided, renders a \"Cancel\" button that calls this." }, "onSubmit": { "name": "onSubmit", "kind": "property", "path": "react-auth.ProfileEditProps.onSubmit", "signature": "onSubmit: Promise", "docstring": "Called with the edited `{ name, email }` on submit." }, "username": { "name": "username", "kind": "property", "path": "react-auth.ProfileEditProps.username", "signature": "username: string", "docstring": "Username, rendered read-only." } } }, "ProfileViewProps": { "name": "ProfileViewProps", "kind": "interface", "path": "react-auth.ProfileViewProps", "signature": "ProfileViewProps", "docstring": "Props for `ProfileView`.", "members": { "email": { "name": "email", "kind": "property", "path": "react-auth.ProfileViewProps.email", "signature": "email: string", "docstring": "Email address to display." }, "loading": { "name": "loading", "kind": "property", "path": "react-auth.ProfileViewProps.loading", "signature": "loading: boolean", "docstring": "Shows a spinner inside the edit button and disables it." }, "name": { "name": "name", "kind": "property", "path": "react-auth.ProfileViewProps.name", "signature": "name: string", "docstring": "Full name to display (falls back to `username`)." }, "onEdit": { "name": "onEdit", "kind": "property", "path": "react-auth.ProfileViewProps.onEdit", "signature": "onEdit: void", "docstring": "When provided, renders an \"Edit Profile\" button that calls this." }, "username": { "name": "username", "kind": "property", "path": "react-auth.ProfileViewProps.username", "signature": "username: string", "docstring": "Username, shown as `@username`." } } }, "AuthMode": { "name": "AuthMode", "kind": "type-alias", "path": "react-auth.AuthMode", "signature": "AuthMode: \"login\" | \"register\"", "docstring": "Which form the `AuthPage` renders.\r\n\r\n- `\"login\"` - sign in with an existing account.\r\n- `\"register\"` - create a new account." }, "tokenStore": { "name": "tokenStore", "kind": "variable", "path": "react-auth.tokenStore", "signature": "tokenStore: { clear: unknown; get: unknown; set: unknown }", "docstring": "Persisted access-token accessor.\n\nThin wrapper over `localStorage` under the fixed key `\"token\"`. It is the\nsingle source of truth used by `AuthProvider` and by the axios\ninterceptors in `createApiClient`, so reading and writing tokens here keeps\nthe UI and the network layer in sync.\n\nNotes:\n- Stores the raw JWT string; it is not encrypted.\n- `get()` returns `null` when no token is present.\n\n**Example:**\n\n```ts\ntokenStore.set(\"eyJhbGciOi...\");\ntokenStore.get(); // \"eyJhbGciOi...\"\ntokenStore.clear();\ntokenStore.get(); // null\n```" }, "AuthPage": { "name": "AuthPage", "kind": "component", "path": "react-auth.AuthPage", "signature": "AuthPage(__namedParameters: AuthPageProps): React.JSX.Element", "docstring": "Split-screen login / register screen.\r\n\r\nA presentational page: it performs client-side validation (username >= 3\r\nchars, password >= 6 chars) and then calls the `login` or `register`\r\ncallback you pass in (typically the `useAuth` actions). When `currentUser`\r\nbecomes truthy it automatically calls `onBack`, so it can be rendered as a\r\nroute guard that redirects once authentication succeeds. The whole page is\r\ncontrolled by `mode`, which lets `onSwitchMode` toggle between sign in and\r\nsign up without unmounting.\r\n\r\nProps:\r\n- `mode` - `\"login\"` or `\"register\"`; selects the form.\r\n- `onBack` - called to leave the page (and automatically on success).\r\n- `onSwitchMode` - called to toggle between login and register.\r\n- `login` - `(username, password) => Promise` from `useAuth`.\r\n- `register` - `(username, password) => Promise` from `useAuth`.\r\n- `loading` - disables the submit button and shows a spinner.\r\n- `error` - server error message to display.\r\n- `currentUser` - when set, triggers `onBack`.\n\n**Example:**\n\n```tsx\r\n navigate(-1)}\r\n onSwitchMode={() => setMode(m => (m === \"login\" ? \"register\" : \"login\"))}\r\n login={auth.login}\r\n register={auth.register}\r\n loading={auth.loading}\r\n error={auth.error}\r\n currentUser={auth.currentUser}\r\n/>\r\n```" }, "AuthProvider": { "name": "AuthProvider", "kind": "component", "path": "react-auth.AuthProvider", "signature": "AuthProvider(__namedParameters: { authConfig: AuthServerConfig; children: React.ReactNode; onUnauthorized: void }): React.JSX.Element", "docstring": "Provide authentication state to the React tree.\r\n\r\nHolds the current user, token, loading and error state, and exposes\r\n`login` / `register` / `logout`. The token is persisted through `tokenStore`\r\n(so it survives reloads) and the current user is re-fetched from\r\n`authConfig.mePath` whenever the token changes. A `auth:unauthorized`\r\nwindow event (dispatched by `createApiClient` on any `401`) also clears the\r\nsession.\r\n\r\nNotes:\r\n- Must wrap any component that calls `useAuth`.\r\n- `login` stores `access_token` from the response and sets `currentUser`\r\n from the response `user`; failures set `error` from `detail` or a default\r\n message.\r\n- `register` creates the account then immediately logs in.\r\n- `logout` is best-effort on the server and always clears local state.\r\n\r\nProps:\r\n- `children` - the subtree that needs auth context.\r\n- `authConfig` - endpoint map; see `AuthServerConfig`.\r\n- `onUnauthorized` - optional callback invoked when the session is cleared.\n\n**Example:**\n\n```tsx\r\n\r\n \r\n\r\n```" }, "createApiClient": { "name": "createApiClient", "kind": "function", "path": "react-auth.createApiClient", "signature": "createApiClient(baseURL: string): AxiosInstance", "docstring": "Create an axios instance preconfigured for token-authenticated APIs.\r\n\r\nThe returned client sends JSON, attaches `Authorization: Bearer `\r\nfrom `tokenStore` to every request, and clears the token plus emits\r\n`auth:unauthorized` on any `401` response.\r\n\r\nUse this for any backend that shares the same login as the auth server; for\r\nunauthenticated endpoints a plain axios instance is fine.\n\n**Parameters:**\n\n- `baseURL` — Root URL prefixed to every request (for example `\"https://api.example.com\"`).\n\n**Returns:**\n\nA configured `AxiosInstance`.\n\n**Example:**\n\n```ts\r\nconst api = createApiClient(\"https://api.example.com\");\r\nconst { data } = await api.get(\"/expenses\"); // Authorization added automatically\r\n```" }, "ProfileCreate": { "name": "ProfileCreate", "kind": "component", "path": "react-auth.ProfileCreate", "signature": "ProfileCreate(__namedParameters: ProfileCreateProps): React.JSX.Element", "docstring": "Presentational \"complete your profile\" form.\r\n\r\nCollects a full name and email and hands them to `onSubmit`; it performs no\r\npersistence itself. When `defaultUsername` is supplied it is rendered as a\r\ndisabled field and used as the name fallback if the user leaves the name\r\nblank.\r\n\r\nProps: see `ProfileCreateProps`.\n\n**Example:**\n\n```tsx\r\n { await api.post(\"/profile\", { name, email }); }}\r\n onBack={() => navigate(-1)}\r\n/>\r\n```" }, "ProfileEdit": { "name": "ProfileEdit", "kind": "component", "path": "react-auth.ProfileEdit", "signature": "ProfileEdit(__namedParameters: ProfileEditProps): React.JSX.Element", "docstring": "Presentational \"edit profile\" form.\r\n\r\nEditable name and email plus a read-only username. The edited values are\r\nhanded to `onSubmit`; persistence is the caller's responsibility.\r\n\r\nProps: see `ProfileEditProps`.\n\n**Example:**\n\n```tsx\r\n { await api.patch(\"/profile\", { name, email }); }}\r\n onBack={() => navigate(-1)}\r\n/>\r\n```" }, "ProfileView": { "name": "ProfileView", "kind": "component", "path": "react-auth.ProfileView", "signature": "ProfileView(__namedParameters: ProfileViewProps): React.JSX.Element", "docstring": "Read-only profile card.\r\n\r\nRenders an avatar (derived initials), the display name, `@username` and the\r\nemail. If `onEdit` is provided it shows an \"Edit Profile\" button; otherwise\r\nthe card is purely informative.\r\n\r\nProps: see `ProfileViewProps`.\n\n**Example:**\n\n```tsx\r\n navigate(\"/profile/edit\")}\r\n/>\r\n```" }, "useAuth": { "name": "useAuth", "kind": "hook", "path": "react-auth.useAuth", "signature": "useAuth(): AuthContextModel", "docstring": "Read the authentication context.\n\n**Returns:**\n\nThe current auth state and actions:\r\n- `currentUser` - the signed-in `AuthUser`, or `null`.\r\n- `token` - the raw JWT string, or `null`.\r\n- `loading` - `true` while a login/register request is in flight.\r\n- `error` - the last error message, or `null`.\r\n- `login(username, password)` - authenticate and store the session.\r\n- `register(username, password)` - create an account, then log in.\r\n- `logout()` - clear the session (server call is best-effort).\n\n**Throws:**\n\nIf called outside of an `AuthProvider`.\n\n**Example:**\n\n```tsx\r\nconst { currentUser, login, logout } = useAuth();\r\n```" } } } }