328 lines
20 KiB
JSON
328 lines
20 KiB
JSON
{
|
|
"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 <token>`, 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 <AuthPage\r\n mode=\"login\"\r\n onBack={() => 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 <App />;\r\n}\r\n\r\nexport default function Root() {\r\n return (\r\n <AuthProvider\r\n authConfig={{\r\n serverUrl: \"https://api.example.com\",\r\n loginPath: \"/auth/login\",\r\n registerPath: \"/auth/register\",\r\n logoutPath: \"/auth/logout\",\r\n mePath: \"/auth/me\",\r\n introspectPath: \"/auth/introspect\",\r\n }}\r\n >\r\n <LoginGate />\r\n </AuthProvider>\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<void>",
|
|
"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<void>",
|
|
"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<void>` from `useAuth`.\r\n- `register` - `(username, password) => Promise<void>` 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<AuthPage\r\n mode=\"login\"\r\n onBack={() => 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<AuthProvider authConfig={authConfig}>\r\n <App />\r\n</AuthProvider>\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 <token>`\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<ProfileCreate\r\n defaultUsername={user.username}\r\n defaultEmail={user.email}\r\n onSubmit={async ({ name, email }) => { 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<ProfileEdit\r\n name={user.name}\r\n username={user.username}\r\n email={user.email}\r\n onSubmit={async ({ name, email }) => { 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<ProfileView\r\n name={user.name}\r\n username={user.username}\r\n email={user.email}\r\n onEdit={() => 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```"
|
|
}
|
|
}
|
|
}
|
|
}
|