{"_id":"@alphinex/auth-ui","_rev":"4-10ad08c7fcb20d6a598621d86eee9aa5","name":"@alphinex/auth-ui","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@alphinex/auth-ui","version":"0.1.0","license":"UNLICENSED","_id":"@alphinex/auth-ui@0.1.0","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"dist":{"shasum":"b1e828440df2ab8ed8c0919cd7835a292135b80f","tarball":"https://registry.npmjs.org/@alphinex/auth-ui/-/auth-ui-0.1.0.tgz","fileCount":5,"integrity":"sha512-tXZ2TdN1DuDrT0T64gq+mI4yIhJq7nrRF14X+vmZH0VgGVlLiC0icpp0pU6Ohg5IPvYIB6NckCcpbGn5yjpuIw==","signatures":[{"sig":"MEUCIA3RfWOxL4GpdhYYcjVSvR2/PBT5RdtVuwP5L/8UXd5vAiEAxZO7EFJv3tgYk95Q6d+79Faq2EVUqVwI0mTgL6XjtDI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51589},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"private":false,"scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build","clean":"rimraf dist .turbo","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"description":"Reusable authentication pages (Login, and more to follow) built on @alphinex/auth, @alphinex/api-laravel, @alphinex/forms, and @alphinex/layouts.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"@alphinex/ui":"2.7.0","@alphinex/api":"1.1.0","@alphinex/auth":"1.0.1","@alphinex/core":"1.0.0","@alphinex/forms":"1.4.1","@alphinex/icons":"1.2.0","@alphinex/theme":"1.1.0","@alphinex/utils":"1.1.0","@alphinex/layouts":"2.2.0","@alphinex/api-laravel":"1.1.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.1","vite":"^6.0.5","jsdom":"^25.0.1","react":"^19.0.0","eslint":"^9.17.0","vitest":"^2.1.8","react-dom":"^19.0.0","typescript":"^5.7.2","@types/react":"^19.0.2","react-hook-form":"^7.54.0","@types/react-dom":"^19.0.2","@vitejs/plugin-react":"^4.3.4","@alphinex/build-config":"0.0.0","@testing-library/react":"^16.1.0","@alphinex/eslint-config":"1.0.1","@testing-library/jest-dom":"^6.6.3","@alphinex/typescript-config":"0.0.0","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"zod":"^3.24.1","react":"^19.0.0","react-dom":"^19.0.0","react-hook-form":"^7.54.0"},"peerDependenciesMeta":{"zod":{"optional":false},"react":{"optional":false},"react-dom":{"optional":false},"react-hook-form":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/auth-ui_0.1.0_1786717162203_0.9197801036915327","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alphinex/auth-ui","version":"0.2.0","license":"UNLICENSED","_id":"@alphinex/auth-ui@0.2.0","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"dist":{"shasum":"d4d4db29d63bb5edf264e7c7b42251e2accb5dde","tarball":"https://registry.npmjs.org/@alphinex/auth-ui/-/auth-ui-0.2.0.tgz","fileCount":5,"integrity":"sha512-L/FQMT5zyIoFtzZgUe0q1oxcBH6Smiv+odDMHrF6GqV57PI2gYrBY4lRhtbiUOLgkC235pdCw7nNJtlY5XYzyg==","signatures":[{"sig":"MEUCIQDmoeUbtYT7tPvwBxlwdoMvdSLDhmtSnFb0581xDCrSOAIgKk9ed9GY+Kje02NBxnfLxmSYlgW/T7o9yBMU1RxfhN8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":161016},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"private":false,"scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build","clean":"rimraf dist .turbo","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"description":"Reusable authentication pages (Login, and more to follow) built on @alphinex/auth, @alphinex/api-laravel, @alphinex/forms, and @alphinex/layouts.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"@alphinex/ui":"2.7.0","@alphinex/api":"1.1.0","@alphinex/auth":"1.0.1","@alphinex/core":"1.0.0","@alphinex/forms":"1.4.1","@alphinex/icons":"1.2.0","@alphinex/theme":"1.1.0","@alphinex/utils":"1.1.0","@alphinex/layouts":"2.2.0","@alphinex/api-laravel":"1.1.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.1","vite":"^6.0.5","jsdom":"^25.0.1","react":"^19.0.0","eslint":"^9.17.0","vitest":"^2.1.8","react-dom":"^19.0.0","typescript":"^5.7.2","@types/react":"^19.0.2","react-hook-form":"^7.54.0","@types/react-dom":"^19.0.2","@vitejs/plugin-react":"^4.3.4","@alphinex/build-config":"0.0.0","@testing-library/react":"^16.1.0","@alphinex/eslint-config":"1.0.1","@testing-library/jest-dom":"^6.6.3","@alphinex/typescript-config":"0.0.0","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"zod":"^3.24.1","react":"^19.0.0","react-dom":"^19.0.0","react-hook-form":"^7.54.0"},"peerDependenciesMeta":{"zod":{"optional":false},"react":{"optional":false},"react-dom":{"optional":false},"react-hook-form":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/auth-ui_0.2.0_1786720668344_0.5003316102002615","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@alphinex/auth-ui","version":"0.3.0","license":"UNLICENSED","_id":"@alphinex/auth-ui@0.3.0","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"dist":{"shasum":"56832cbe0fe598d7971e4c0ea48bf0ce06ec1480","tarball":"https://registry.npmjs.org/@alphinex/auth-ui/-/auth-ui-0.3.0.tgz","fileCount":5,"integrity":"sha512-6W6o+EpEVE2w/zLC0Y9r3RJccZ6vCDrCkl8wnEX1DRLkVkUqHtCrDBla/gow6y3OGZHNrTF8iZsxGlYtLp6d/w==","signatures":[{"sig":"MEUCIQCmKvcYvjBY9wwgm44qHdaGXM6R0/lc74mhGXUZkKuATQIgJBa8lV6P1VexrGa7AtJtGik8W6FVVVksfskzibQqETA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":200708},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"private":false,"scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build","clean":"rimraf dist .turbo","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"description":"Reusable authentication pages (Login, and more to follow) built on @alphinex/auth, @alphinex/api-laravel, @alphinex/forms, and @alphinex/layouts.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"@alphinex/ui":"2.7.0","@alphinex/api":"1.1.0","@alphinex/auth":"1.0.1","@alphinex/core":"1.0.0","@alphinex/forms":"1.4.1","@alphinex/icons":"1.2.0","@alphinex/table":"1.2.1","@alphinex/theme":"1.1.0","@alphinex/utils":"1.1.0","@alphinex/layouts":"2.2.0","@alphinex/api-laravel":"1.1.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.1","vite":"^6.0.5","jsdom":"^25.0.1","react":"^19.0.0","eslint":"^9.17.0","vitest":"^2.1.8","react-dom":"^19.0.0","typescript":"^5.7.2","@types/react":"^19.0.2","react-hook-form":"^7.54.0","@types/react-dom":"^19.0.2","@vitejs/plugin-react":"^4.3.4","@alphinex/build-config":"0.0.0","@testing-library/react":"^16.1.0","@alphinex/eslint-config":"1.0.1","@testing-library/jest-dom":"^6.6.3","@alphinex/typescript-config":"0.0.0","@testing-library/user-event":"^14.5.2"},"peerDependencies":{"zod":"^3.24.1","react":"^19.0.0","react-dom":"^19.0.0","react-hook-form":"^7.54.0"},"peerDependenciesMeta":{"zod":{"optional":false},"react":{"optional":false},"react-dom":{"optional":false},"react-hook-form":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/auth-ui_0.3.0_1786740646000_0.6970178713775366","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@alphinex/auth-ui","version":"0.4.0","private":false,"description":"Reusable authentication pages (Login, and more to follow) built on @alphinex/auth, @alphinex/api-laravel, @alphinex/forms, and @alphinex/layouts.","license":"UNLICENSED","type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"dependencies":{"@alphinex/api":"1.1.0","@alphinex/auth":"1.0.1","@alphinex/forms":"1.4.1","@alphinex/api-laravel":"1.1.0","@alphinex/core":"1.0.0","@alphinex/table":"1.2.1","@alphinex/layouts":"2.2.0","@alphinex/theme":"1.1.0","@alphinex/ui":"2.7.0","@alphinex/utils":"1.1.0","@alphinex/icons":"1.2.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0","react-hook-form":"^7.54.0","zod":"^3.24.1"},"peerDependenciesMeta":{"react":{"optional":false},"react-dom":{"optional":false},"react-hook-form":{"optional":false},"zod":{"optional":false}},"devDependencies":{"typescript":"^5.7.2","vite":"^6.0.5","vitest":"^2.1.8","react":"^19.0.0","react-dom":"^19.0.0","react-hook-form":"^7.54.0","zod":"^3.24.1","@types/react":"^19.0.2","@types/react-dom":"^19.0.2","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.3","@testing-library/user-event":"^14.5.2","@vitejs/plugin-react":"^4.3.4","jsdom":"^25.0.1","eslint":"^9.17.0","@alphinex/build-config":"0.0.0","@alphinex/typescript-config":"0.0.0","@alphinex/eslint-config":"1.0.1"},"scripts":{"build":"vite build","dev":"vite build --watch","lint":"eslint .","typecheck":"tsc --noEmit","test":"vitest run","clean":"rimraf dist .turbo"},"_nodeVersion":"22.14.0","_id":"@alphinex/auth-ui@0.4.0","dist":{"integrity":"sha512-v9iEEzHg6S9ZnzNkRl5bb8RYUmx+EM/nCQcvesdt02pG6TGNB2dki6uVMIx9kYh8rykxzwIR7MrRpol32td93w==","shasum":"732c2f8b4d932b1f1e57b65c0a8897bca45c19e5","tarball":"https://registry.npmjs.org/@alphinex/auth-ui/-/auth-ui-0.4.0.tgz","fileCount":5,"unpackedSize":248107,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFbiHs+6SGC5vp3Tc8Q76apQLBH9zSZ0LKoSOgb7gwygAiEA9xrOONMU0pr6osFfMi+tnxOD1vwpMGlr93FDRjSqm50="}]},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"directories":{},"maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/auth-ui_0.4.0_1786804191273_0.04241857299185958"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-14T14:19:22.050Z","modified":"2026-08-15T14:29:51.726Z","0.1.0":"2026-08-14T14:19:22.344Z","0.2.0":"2026-08-14T15:17:48.499Z","0.3.0":"2026-08-14T20:50:46.151Z","0.4.0":"2026-08-15T14:29:51.454Z"},"license":"UNLICENSED","description":"Reusable authentication pages (Login, and more to follow) built on @alphinex/auth, @alphinex/api-laravel, @alphinex/forms, and @alphinex/layouts.","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"readme":"# @alphinex/auth-ui\n\nReusable authentication pages built on `@alphinex/auth`, `@alphinex/api-laravel`,\n`@alphinex/forms`, and `@alphinex/layouts` — so projects on the platform never hand-build\nLogin/Register/Verify/Forgot/Reset screens from scratch. Compose pre-built pages, override only\nwhat differs for your project, and get the rest for free.\n\n## Status\n\n`v0.4.0` ships all five self-service auth pages (`<LoginPage/>`, `<RegisterPage/>`,\n`<VerifyEmailPage/>`, `<ForgotPasswordPage/>`, `<ResetPasswordPage/>`), admin user-management\n(`<UsersPage/>`, `UserFormDrawer`), self-service `<AccountSettingsPage/>`, and optional OAuth\n(Google/GitHub) buttons on Login/Register.\n\n## Three layers of reuse\n\n1. **Full pages** (`<LoginPage/>`, `<RegisterPage/>`, `<VerifyEmailPage/>`,\n   `<ForgotPasswordPage/>`, `<ResetPasswordPage/>`, `<UsersPage/>`, `<AccountSettingsPage/>`) —\n   zero-config drop-in for a project that matches the defaults closely.\n2. **Composable building blocks** (`PasswordField`, `OnboardingSteps`, `Recaptcha`,\n   `OAuthButtons`, `UserFormDrawer`, `createUserActionsColumn`,\n   `createLoginSchema`/`createRegisterSchema`/`createForgotPasswordSchema`/\n   `createResetPasswordSchema`/`createResendVerificationSchema`/`createUserFormSchema`,\n   `getAuthErrorMessage`, `isSlugError`, `applyServerFieldErrors`, `getWebmailInboxUrl`) — for a\n   project that wants the same visual language but a different field set or flow.\n3. **Headless hooks + adapters** (`@alphinex/auth`'s `useAuth`/`AuthAdapter`,\n   `@alphinex/api-laravel`'s `ErrorEnvelopeParser`/`TokenStore`, `@alphinex/table`'s\n   `mode: \"cursor\"` `DataGrid`) — auth-ui builds on these, it doesn't duplicate them.\n\nEvery page's actual backend call (`login` via `AuthAdapter`, `register`, `verify`,\n`forgotPassword`, `resetPassword`, `resendVerification`) is a prop you supply — auth-ui has no\nopinion on your API paths, only on the page flow around them. Route params for\n`VerifyEmailPage`/`ResetPasswordPage` (`userId`/`hash`/`search`) are passed in as plain props too,\nso this package has no dependency on any particular router.\n\n## Usage\n\n```tsx\nimport {\n  AuthUIProvider,\n  LoginPage,\n  RegisterPage,\n  createSwitchableTokenStore,\n} from \"@alphinex/auth-ui\";\nimport { authAdapter } from \"./platform/authentication/auth-adapter\";\nimport { apiClient } from \"./platform/api/client\";\n\nconst tokenStore = createSwitchableTokenStore(\"myapp.auth.token\");\n\nfunction App() {\n  return (\n    <AuthUIProvider\n      authAdapter={authAdapter}\n      tokenStore={tokenStore}\n      recaptcha={{ siteKey: import.meta.env.VITE_RECAPTCHA_SITE_KEY }}\n      shell={{ logo: <img src=\"/logo.png\" alt=\"My App\" className=\"mx-auto h-12 w-auto\" /> }}\n    >\n      <LoginPage forgotPasswordHref=\"/forgot-password\" onSuccess={() => navigate(\"/\")} />\n    </AuthUIProvider>\n  );\n}\n\nfunction Register() {\n  return (\n    <RegisterPage\n      register={(values) => apiClient.post(\"/authentication/register\", values)}\n      resendVerification={(email) =>\n        apiClient.post(\"/authentication/resend-verification\", { email })\n      }\n      tenancy={{ resolveRootDomain: () => window.location.hostname }}\n      loginHref=\"/login\"\n    />\n  );\n}\n```\n\n`tokenStore` must be the same instance passed to your `createLaravelApiClient({ bearer: {\ntokenStore, ... } })` call — `AuthUIProvider` only toggles its persistence mode via the\n\"remember me\" checkbox, it doesn't own request auth itself.\n\n### OAuth (Google/GitHub) — off by default, opt in per project or per page\n\nEvery page ships the capability; nothing renders unless you configure it. `AuthUIProvider`'s\n`oauth` prop sets an app-wide default (omit it — the default — and no page shows OAuth buttons\nat all); either `<LoginPage/>` or `<RegisterPage/>` can override that with their own `oauth` prop,\nincluding `oauth={[]}` to turn OAuth off on just that one page even if the provider has it\nconfigured. `auth-ui` never talks to Google/GitHub itself — each button is a plain link to a URL\nyour own backend owns (the redirect-start endpoint), not a client-side OAuth SDK:\n\n```tsx\n<AuthUIProvider\n  authAdapter={authAdapter}\n  oauth={[\n    { provider: \"google\", href: \"/api/auth/google/redirect\" },\n    { provider: \"github\", href: \"/api/auth/github/redirect\" },\n  ]}\n>\n  <LoginPage /> {/* shows both buttons, \"Or continue with email\", then the form */}\n  <RegisterPage oauth={[]} /> {/* email/password only, even though the provider has oauth set */}\n</AuthUIProvider>\n```\n\n`\"google\"`/`\"github\"` get a built-in icon and label; any other `provider` string is a custom\nprovider — supply your own `label`/`icon` for those.\n\n## Page-by-page overrides\n\nEvery page accepts `copy` (merged over defaults), `onError` (return `true` to suppress the\ndefault error banner), and `Shell` (defaults to `AuthLayout` wired to the provider's `shell`\nconfig). See each page's `*Props` type for the full list; highlights:\n\n- **`<LoginPage/>`** — `extraFields`, `schema` (prefer `createLoginSchema({ extraFields })`),\n  `onSuccess`, `recaptcha`, `forgotPasswordHref`, `oauth` (overrides the provider default).\n- **`<RegisterPage/>`** — `register` (required), `tenancy` (required —\n  `resolveRootDomain`/`previewWorkspaceUrl`/`reservedSlugs`, since the tenancy model has no\n  universal default), `resendVerification`, `extraFields`, `schema`, `loginHref`,\n  `showOnboardingSteps`, `oauth` (overrides the provider default).\n- **`<VerifyEmailPage/>`** — `verify` (required), `params` (required —\n  `{ userId, hash, search }`, extracted from your router and passed in), `forwardQueryString`\n  (defaults `true` — correctness requirement for signed routes, not a style choice),\n  `resendVerification`, `loginHref`.\n- **`<ForgotPasswordPage/>`** — `forgotPassword` (required), `loginHref`,\n  `resendCooldownSeconds`. Always shows the same success state regardless of whether the account\n  exists — see \"no user enumeration\" below.\n- **`<ResetPasswordPage/>`** — `resetPassword` (required), `params` (required),\n  `forwardQueryString`, `invalidLinkErrorCode` (defaults `\"AUTH_RESET_LINK_INVALID\"`),\n  `loginHref`, `forgotPasswordHref`.\n- **`<UsersPage/>`** — `columns` and `data` (required — cursor mode, so you own fetching/cursor\n  state, same as `@alphinex/table`'s `mode: \"cursor\"`), `fields` (required — the create/edit\n  drawer's field-set config, since a \"user\" shape varies too much per project to assume one),\n  `onCreate`/`onUpdate`/`onDelete` (each optional — omitting one hides its corresponding\n  UI: no `onCreate` means no \"Add user\" button, no `onDelete` means no delete action, etc.),\n  `canCreate`/`canEdit`/`canDelete` for permission gating (pass your own `usePermission()`\n  check), `hasNextPage`/`hasPreviousPage`/`onLoadMore`/`onLoadPrevious`/`onQueryChange`\n  (forwarded straight to the underlying `DataGrid`).\n\n```tsx\nimport { UsersPage, createUserFormSchema } from \"@alphinex/auth-ui\";\nimport { usePermission } from \"@alphinex/permissions\";\n\nfunction Users() {\n  const [cursor, setCursor] = useState<CursorState>();\n  return (\n    <UsersPage\n      columns={[\n        { accessorKey: \"name\", header: \"Name\" },\n        { accessorKey: \"email\", header: \"Email\" },\n        { accessorKey: \"role\", header: \"Role\" },\n      ]}\n      data={cursor?.rows ?? []}\n      hasNextPage={cursor?.hasNextPage}\n      hasPreviousPage={cursor?.hasPreviousPage}\n      onLoadMore={() => fetchUsers(cursor?.nextCursor)}\n      onLoadPrevious={() => fetchUsers(cursor?.previousCursor)}\n      fields={[\n        { name: \"name\", label: \"Name\", required: true },\n        { name: \"email\", label: \"Email\", type: \"email\", required: true },\n        {\n          name: \"role\",\n          label: \"Role\",\n          type: \"select\",\n          required: true,\n          options: [\n            { label: \"Admin\", value: \"admin\" },\n            { label: \"Member\", value: \"member\" },\n          ],\n        },\n      ]}\n      onCreate={(values) => apiClient.post(\"/authentication/users\", values)}\n      onUpdate={(id, values) => apiClient.patch(`/authentication/users/${id}`, values)}\n      onDelete={(user) => apiClient.delete(`/authentication/users/${user.id}`)}\n      canCreate={usePermission(\"authentication.users.manage\")}\n    />\n  );\n}\n```\n\n- **`<AccountSettingsPage/>`** — three independent sections (profile, change password, change\n  email), each shown only when its `on*` callback is provided; there is no default backend call\n  for any of them since what \"change my email\" means (re-verification? a confirmation email? a\n  current-password check?) is too backend-specific to assume.\n\n```tsx\nimport { AccountSettingsPage } from \"@alphinex/auth-ui\";\n\nfunction Settings() {\n  const { user } = useAuth();\n  return (\n    <AccountSettingsPage\n      user={user}\n      profileFields={[{ name: \"name\", label: \"Name\", required: true }]}\n      onUpdateProfile={(values) => apiClient.patch(\"/authentication/me\", values)}\n      onChangePassword={(values) => apiClient.post(\"/authentication/change-password\", values)}\n      onChangeEmail={(values) => apiClient.post(\"/authentication/change-email\", values)}\n    />\n  );\n}\n```\n\n## What's intentionally not overridable\n\n- Error handling always branches on `error.code`, never HTTP status or message text —\n  `errorMessages` may only add/replace copy for a code, not change this.\n- `<ForgotPasswordPage/>` never introduces a way to leak whether an account exists — the success\n  state is identical either way, matching your backend's own (expected) identical response.\n- `forwardQueryString` on `<VerifyEmailPage/>`/`<ResetPasswordPage/>` defaults to `true` and is\n  documented as \"only turn off if your backend doesn't sign links this way\" — signed-URL query\n  strings must be forwarded verbatim, not re-serialized.\n","readmeFilename":""}