@awsmbiz/inbis-auth-ui 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["errorMessage","errorMessage","errorMessage","errorMessage","errorMessage","failure","failure","failure","failure"],"sources":["../src/form-parts.tsx","../src/messages.ts","../src/shell.tsx","../src/turnstile.tsx","../src/use-public-auth-config.ts","../src/phone-sign-in.tsx","../src/accept-invitation-screen.tsx","../src/forgot-password-screen.tsx","../src/reset-password-screen.tsx","../src/two-factor-challenge.tsx","../src/sign-in-screen.tsx","../src/sign-up-screen.tsx","../src/verify-email-screen.tsx","../src/two-factor-steps.tsx","../src/two-factor-settings-screen.tsx","../src/delete-account-screen.tsx","../src/sessions-screen.tsx","../src/step-up-screen.tsx"],"sourcesContent":["import { Alert, AlertDescription, AlertTitle, Input, Label } from \"@awsmbiz/inbis-ui\";\n\n/** One labelled input of an auth form. */\nexport function TextField(props: {\n id: string;\n label: string;\n name: string;\n type: string;\n autoComplete: string;\n value: string;\n onChange: (value: string) => void;\n invalid: boolean;\n hint?: string;\n}) {\n return (\n <div className=\"grid gap-2\">\n <Label htmlFor={props.id}>{props.label}</Label>\n <Input\n id={props.id}\n name={props.name}\n type={props.type}\n autoComplete={props.autoComplete}\n required\n value={props.value}\n onChange={(event) => {\n props.onChange(event.target.value);\n }}\n aria-invalid={props.invalid ? true : undefined}\n aria-describedby={props.hint === undefined ? undefined : `${props.id}-hint`}\n />\n {props.hint === undefined ? null : (\n <p id={`${props.id}-hint`} className=\"text-xs text-muted-foreground\">\n {props.hint}\n </p>\n )}\n </div>\n );\n}\n\n/** A form-level error, announced to assistive technology. */\nexport function ErrorAlert({ title, message }: { title?: string; message: string }) {\n return (\n <Alert variant=\"destructive\" role=\"alert\">\n {title === undefined ? null : <AlertTitle>{title}</AlertTitle>}\n <AlertDescription>{message}</AlertDescription>\n </Alert>\n );\n}\n\n/** A confirmation, announced politely. */\nexport function Notice({ title, message }: { title?: string; message: string }) {\n return (\n <Alert role=\"status\">\n {title === undefined ? null : <AlertTitle>{title}</AlertTitle>}\n <AlertDescription>{message}</AlertDescription>\n </Alert>\n );\n}\n\n/** Reads one query parameter of the current page (browser only). */\nexport function queryParam(search: string | undefined, name: string): string | null {\n const source = search ?? (typeof window === \"undefined\" ? \"\" : window.location.search);\n return new URLSearchParams(source).get(name);\n}\n\n/** An absolute URL on the current page's origin, for links the server emails. */\nexport function onThisOrigin(path: string): string {\n return typeof window === \"undefined\" ? path : new URL(path, window.location.origin).toString();\n}\n","/**\n * Every user-facing string of `@awsmbiz/inbis-auth-ui`, by message key. English only\n * in the baseline; keys keep a later translation a data change.\n */\nexport const messages = {\n \"signIn.title\": \"Sign in\",\n \"signIn.description\": \"Sign in to {appName} with your email and password.\",\n \"signIn.descriptionPhone\": \"Sign in to {appName} with your phone number.\",\n \"signIn.email\": \"Email\",\n \"signIn.password\": \"Password\",\n \"signIn.submit\": \"Sign in\",\n \"signIn.submitting\": \"Signing in…\",\n \"signIn.failed\": \"Could not sign in\",\n \"signIn.invalidCredentials\": \"The email or password is incorrect.\",\n \"signIn.noMethods\": \"No sign-in method is enabled for this app.\",\n \"twoFactor.title\": \"Two-factor authentication\",\n \"twoFactor.challenge.description\": \"Enter the 6-digit code from your authenticator app.\",\n \"twoFactor.challenge.backupDescription\": \"Enter one of your backup codes. Each code works once.\",\n \"twoFactor.code\": \"6-digit code\",\n \"twoFactor.backupCode\": \"Backup code\",\n \"twoFactor.verify\": \"Verify\",\n \"twoFactor.verifying\": \"Verifying…\",\n \"twoFactor.useBackupCode\": \"Use a backup code\",\n \"twoFactor.useAuthenticator\": \"Use your authenticator app\",\n \"twoFactor.failed\": \"Could not verify\",\n \"twoFactor.invalidCode\": \"That code is not valid. Check your authenticator app and try again.\",\n \"twoFactor.invalidBackupCode\": \"That backup code is not valid or has already been used.\",\n \"twoFactor.challengeExpired\": \"This sign-in has expired. Sign in again.\",\n \"twoFactor.tooManyAttempts\": \"Too many attempts. Sign in again to get a new chance.\",\n \"twoFactor.locked\": \"Too many failed attempts. Try again later.\",\n \"twoFactor.settings.loading\": \"Loading…\",\n \"twoFactor.settings.unavailable\": \"Two-factor authentication is not available for this app.\",\n \"twoFactor.settings.on\": \"Two-factor authentication is on.\",\n \"twoFactor.settings.off\": \"Two-factor authentication is off.\",\n \"twoFactor.settings.explainer\": \"Protect your account with a code from an authenticator app each time you sign in.\",\n \"twoFactor.settings.setUp\": \"Set up authenticator app\",\n \"twoFactor.settings.regenerate\": \"Regenerate backup codes\",\n \"twoFactor.settings.disable\": \"Turn off two-factor authentication\",\n \"twoFactor.settings.failed\": \"Could not change two-factor authentication\",\n \"twoFactor.password\": \"Current password\",\n \"twoFactor.password.setUp\": \"Confirm your password to set up an authenticator app.\",\n \"twoFactor.password.regenerate\": \"Confirm your password to replace your backup codes. The old codes stop working.\",\n \"twoFactor.password.disable\": \"Confirm your password to turn off two-factor authentication.\",\n \"twoFactor.continue\": \"Continue\",\n \"twoFactor.regenerateSubmit\": \"Regenerate\",\n \"twoFactor.disableSubmit\": \"Turn off\",\n \"twoFactor.cancel\": \"Cancel\",\n \"twoFactor.working\": \"Working…\",\n \"twoFactor.invalidPassword\": \"The password is incorrect.\",\n \"twoFactor.notFresh\": \"For your security, sign in again before changing two-factor authentication.\",\n \"twoFactor.signInAgain\": \"Sign in again\",\n \"twoFactor.enrol.scan\": \"Scan this QR code with your authenticator app, then enter the 6-digit code it shows.\",\n \"twoFactor.enrol.qrAlt\": \"QR code for your authenticator app\",\n \"twoFactor.enrol.manual\": \"Can't scan it? Enter this key instead:\",\n \"twoFactor.enrol.submit\": \"Verify and turn on\",\n \"twoFactor.backupCodes.title\": \"Save your backup codes\",\n \"twoFactor.backupCodes.description\": \"Each code signs you in once if you lose your authenticator. Store them somewhere safe; they are not shown again.\",\n \"twoFactor.backupCodes.list\": \"Backup codes\",\n \"twoFactor.backupCodes.done\": \"I have saved my backup codes\",\n \"signIn.noAccount\": \"No account yet?\",\n \"signIn.createAccount\": \"Create an account\",\n \"signUp.title\": \"Create an account\",\n \"signUp.description\": \"Create your {appName} account.\",\n \"signUp.name\": \"Name\",\n \"signUp.email\": \"Email\",\n \"signUp.password\": \"Password\",\n \"signUp.passwordHint\": \"{minLength} to {maxLength} characters.\",\n \"signUp.submit\": \"Create account\",\n \"signUp.submitting\": \"Creating account…\",\n \"signUp.failed\": \"Could not create the account\",\n \"signUp.closedTitle\": \"Registration is not open\",\n \"signUp.closed\": \"{appName} does not accept new accounts here. Ask an administrator for an invitation.\",\n \"signUp.backToSignIn\": \"Back to sign in\",\n \"deleteAccount.title\": \"Delete account\",\n \"deleteAccount.unavailable\": \"Accounts cannot be deleted here. Contact {appName} to close your account.\",\n \"deleteAccount.warning\": \"This permanently deletes your {appName} account and signs you out everywhere. It cannot be undone.\",\n \"deleteAccount.warningGrace\":\n \"Your {appName} account will be permanently deleted after {graceDays} days, and you will be signed out everywhere. Signing in again before then cancels the deletion.\",\n \"deleteAccount.confirmLabel\": \"Type DELETE to confirm\",\n \"deleteAccount.confirmWord\": \"DELETE\",\n \"deleteAccount.submit\": \"Delete my account\",\n \"deleteAccount.submitting\": \"Deleting…\",\n \"deleteAccount.cancel\": \"Cancel\",\n \"deleteAccount.failed\": \"Could not delete the account\",\n \"deleteAccount.notFresh\": \"For your security, sign in again before deleting your account.\",\n \"deleteAccount.signInAgain\": \"Sign in again\",\n \"deleteAccount.deleted\": \"Your account has been deleted.\",\n \"deleteAccount.scheduled\": \"Your account will be deleted on {date}. Sign in before then to keep it.\",\n \"deleteAccount.done\": \"Done\",\n \"signIn.forgotPassword\": \"Forgot password?\",\n \"signIn.emailNotVerified\": \"Verify your email address before signing in. Check your inbox for the link.\",\n \"signIn.resendVerification\": \"Send a new verification link\",\n \"verifyEmail.title\": \"Verify your email\",\n \"verifyEmail.description\": \"Enter your email address and we will send you a new verification link.\",\n \"verifyEmail.email\": \"Email\",\n \"verifyEmail.submit\": \"Send verification link\",\n \"verifyEmail.submitting\": \"Sending…\",\n \"verifyEmail.sent\":\n \"If that email belongs to an account that still needs verifying, a new link is on its way. It works for a limited time.\",\n \"verifyEmail.checkInbox\": \"Check your inbox: we sent you a link to verify your email address.\",\n \"verifyEmail.verifiedTitle\": \"Email verified\",\n \"verifyEmail.verified\": \"Your email address is verified.\",\n \"verifyEmail.continue\": \"Continue to sign in\",\n \"verifyEmail.invalid\": \"This verification link is invalid or has expired. Request a new one below.\",\n \"verifyEmail.failed\": \"Could not send the link\",\n \"forgotPassword.title\": \"Reset your password\",\n \"forgotPassword.description\": \"Enter your email address and we will send you a link to choose a new password.\",\n \"forgotPassword.email\": \"Email\",\n \"forgotPassword.submit\": \"Send reset link\",\n \"forgotPassword.submitting\": \"Sending…\",\n \"forgotPassword.sent\": \"If an account exists for that email, we have sent a link to reset the password. It works for a limited time.\",\n \"forgotPassword.failed\": \"Could not send the link\",\n \"resetPassword.title\": \"Choose a new password\",\n \"resetPassword.newPassword\": \"New password\",\n \"resetPassword.confirmPassword\": \"Confirm new password\",\n \"resetPassword.submit\": \"Set new password\",\n \"resetPassword.submitting\": \"Saving…\",\n \"resetPassword.failed\": \"Could not change the password\",\n \"resetPassword.mismatch\": \"The passwords do not match.\",\n \"resetPassword.invalidLink\": \"This reset link has expired or was already used.\",\n \"resetPassword.compromised\":\n \"This password has appeared in a data breach, so it is not safe to use. Choose a different one.\",\n \"resetPassword.tooShort\": \"The password must be at least {minLength} characters.\",\n \"resetPassword.tooLong\": \"The password must be at most {maxLength} characters.\",\n \"resetPassword.done\": \"Your password has been changed. Sign in with your new password.\",\n \"resetPassword.requestNew\": \"Request a new link\",\n \"invitation.title\": \"Accept your invitation\",\n \"invitation.description\": \"Create your {appName} account for {email}.\",\n \"invitation.descriptionAdmin\": \"Create your {appName} administrator account for {email}.\",\n \"invitation.loading\": \"Checking your invitation…\",\n \"invitation.invalid\":\n \"This invitation link is invalid, has expired or was already used. Ask an administrator for a new invitation.\",\n \"invitation.phone\": \"This invitation is for a phone number. Sign in with your phone number to accept it.\",\n \"invitation.name\": \"Name\",\n \"invitation.password\": \"Password\",\n \"invitation.confirmPassword\": \"Confirm password\",\n \"invitation.submit\": \"Create account\",\n \"invitation.submitting\": \"Creating account…\",\n \"invitation.failed\": \"Could not create the account\",\n \"invitation.nameRequired\": \"Enter your name.\",\n \"invitation.exists\": \"An account with this email already exists. Sign in instead.\",\n \"invitation.notAllowed\": \"This app is not accepting new accounts right now. Ask an administrator.\",\n \"invitation.done\": \"Your account is ready. Sign in to continue.\",\n \"sessions.title\": \"Your sessions\",\n \"sessions.description\": \"Devices and browsers signed in to your account.\",\n \"sessions.loading\": \"Loading…\",\n \"sessions.loadFailed\": \"Could not load your sessions. Reload the page to try again.\",\n \"sessions.unknownDevice\": \"Unknown device\",\n \"sessions.signedInAt\": \"Signed in {date}\",\n \"sessions.thisDevice\": \"This device\",\n \"sessions.revoke\": \"Sign out\",\n \"sessions.revokeOthers\": \"Sign out all other sessions\",\n \"sessions.othersRevoked\": \"Signed out {count} other sessions.\",\n \"sessions.failed\": \"Could not sign out the session\",\n \"sessions.notFresh\": \"For your security, sign in again before signing out other sessions.\",\n \"sessions.notFound\": \"That session has already ended.\",\n \"sessions.signInAgain\": \"Sign in again\",\n \"signIn.withPhone\": \"Use a phone number instead\",\n \"phone.title\": \"Sign in with your phone\",\n \"phone.description\": \"We will text a sign-in code to your phone.\",\n \"phone.number\": \"Phone number\",\n \"phone.numberHint\": \"Include the country code, for example +44 7700 900123.\",\n \"phone.send\": \"Send code\",\n \"phone.sending\": \"Sending…\",\n \"phone.codeSent\": \"If {phoneNumber} can sign in here, a {codeLength}-digit code is on its way. It works for {minutes} minutes.\",\n \"phone.code\": \"6-digit code\",\n \"phone.verify\": \"Verify\",\n \"phone.verifying\": \"Verifying…\",\n \"phone.resend\": \"Send a new code\",\n \"phone.changeNumber\": \"Use a different number\",\n \"phone.failed\": \"Could not sign in\",\n \"phone.invalidNumber\": \"Enter the number in international format, starting with + and the country code.\",\n \"phone.invalidCode\": \"That code is not right. Check the SMS and try again.\",\n \"phone.expired\": \"That code has expired or was already used. Send a new code.\",\n \"phone.tooManyAttempts\": \"Too many wrong codes. Send a new code.\",\n \"phone.notAllowed\": \"This number cannot sign in here. Ask an administrator for an invitation.\",\n \"phone.banned\": \"This account is suspended. Contact an administrator.\",\n \"invitation.descriptionPhone\": \"Join {appName} with {phoneNumber}. We will text you a sign-in code.\",\n \"invitation.descriptionPhoneAdmin\": \"Join {appName} as an administrator with {phoneNumber}. We will text you a sign-in code.\",\n \"stepUp.setUp.title\": \"Set up two-factor authentication\",\n \"stepUp.setUp.description\": \"This area needs two-factor authentication. Set up an authenticator app to continue.\",\n \"stepUp.verify.title\": \"Verify it's you\",\n \"stepUp.verify.description\":\n \"This area needs a sign-in completed with your authenticator app. Sign in again with your password and code.\",\n \"stepUp.method.title\": \"Sign in again\",\n \"stepUp.method.description\": \"This area needs a sign-in with {methods}. Sign in again to continue.\",\n \"stepUp.method.password\": \"your email and password\",\n \"stepUp.method.phoneOtp\": \"a code sent to your phone\",\n \"stepUp.method.other\": \"another sign-in method\",\n \"stepUp.signInAgain\": \"Sign in again\",\n \"auth.backToSignIn\": \"Back to sign in\",\n \"auth.signIn\": \"Sign in\",\n \"config.loading\": \"Loading…\",\n \"config.failed\": \"Could not load the sign-in options. Reload the page to try again.\",\n \"error.network\": \"Could not reach the server. Check your connection and try again.\",\n \"error.generic\": \"Something went wrong. Try again.\",\n \"error.rateLimited\": \"Too many attempts. Wait a minute and try again.\",\n \"captcha.failed\": \"The security check could not run. Reload the page to try again.\",\n \"captcha.rejected\": \"The security check did not pass. Complete it again and retry.\",\n \"phone.countryNotAllowed\": \"Phone numbers from this country cannot be used here.\",\n \"phone.tooManyRequests\": \"Too many codes were requested. Wait a while before asking for another.\",\n \"phone.smsPaused\": \"Text messages are paused for today. Try again later or use another way to sign in.\",\n} as const;\n\nexport type MessageKey = keyof typeof messages;\n\n/** Looks up a message and fills `{name}` placeholders. */\nexport function t(key: MessageKey, values: Record<string, string> = {}): string {\n return messages[key].replace(/\\{(\\w+)\\}/g, (match, name: string) => values[name] ?? match);\n}\n","import type { PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@awsmbiz/inbis-ui\";\nimport type { ReactNode } from \"react\";\nimport { t } from \"./messages.js\";\nimport type { PublicAuthConfigState } from \"./use-public-auth-config.js\";\n\n/** The centred card every auth screen renders in. */\nexport function Shell({ title, description, children }: { title: string; description?: string; children: ReactNode }) {\n return (\n <main className=\"flex min-h-svh items-center justify-center bg-muted/40 p-4\">\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>\n <h1>{title}</h1>\n </CardTitle>\n {description === undefined ? null : <CardDescription>{description}</CardDescription>}\n </CardHeader>\n <CardContent>{children}</CardContent>\n </Card>\n </main>\n );\n}\n\n/**\n * Renders the loading and error states of the public config inside the shell,\n * and `ready(config)` once it has loaded.\n */\nexport function ConfigGate({\n state,\n title,\n ready,\n}: {\n state: PublicAuthConfigState;\n title: string;\n ready: (config: PublicAuthConfig) => ReactNode;\n}) {\n if (state.status === \"loading\") {\n return (\n <Shell title={title}>\n <p className=\"text-sm text-muted-foreground\" aria-live=\"polite\">\n {t(\"config.loading\")}\n </p>\n </Shell>\n );\n }\n if (state.status === \"error\") {\n return (\n <Shell title={title}>\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertDescription>{t(\"config.failed\")}</AlertDescription>\n </Alert>\n </Shell>\n );\n }\n return ready(state.config);\n}\n","import type { CaptchaAction, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { t } from \"./messages.js\";\n\n/**\n * Cloudflare Turnstile, rendered explicitly as Cloudflare documents it\n * (https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/):\n * the script is loaded once from Cloudflare, and each form renders its own\n * widget. A token works once, so forms reset the widget after every submit.\n * Pages with a Content-Security-Policy must allow `https://challenges.cloudflare.com`\n * in `script-src` and `frame-src`.\n */\nconst SCRIPT_URL = \"https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit\";\n\ninterface TurnstileApi {\n render(\n container: HTMLElement,\n options: {\n sitekey: string;\n action?: string;\n callback: (token: string) => void;\n \"expired-callback\": () => void;\n \"error-callback\": () => void;\n },\n ): string;\n reset(widgetId: string): void;\n remove(widgetId: string): void;\n}\n\ndeclare global {\n interface Window {\n turnstile?: TurnstileApi;\n }\n}\n\nlet loading: Promise<TurnstileApi> | undefined;\n\n/** Loads Cloudflare's widget script once per page. */\nfunction loadTurnstile(): Promise<TurnstileApi> {\n loading ??= new Promise<TurnstileApi>((resolve, reject) => {\n if (window.turnstile !== undefined) {\n resolve(window.turnstile);\n return;\n }\n const script = document.createElement(\"script\");\n script.src = SCRIPT_URL;\n script.async = true;\n script.defer = true;\n script.onload = () => {\n if (window.turnstile === undefined) reject(new Error(\"Turnstile did not load.\"));\n else resolve(window.turnstile);\n };\n script.onerror = () => {\n loading = undefined;\n reject(new Error(\"Turnstile could not be loaded.\"));\n };\n document.head.appendChild(script);\n });\n return loading;\n}\n\nexport interface TurnstileState {\n /** The widget to render inside the form; `null` when no check is needed. */\n widget: ReactNode;\n /** Whether the form may submit: no check is needed, or a token is ready. */\n ready: boolean;\n /** The token to send (`undefined` when no check is needed). */\n token: string | undefined;\n /** Call after every submit: a token works once. */\n reset: () => void;\n}\n\n/**\n * The Turnstile check for one form, when the public config's `captcha` covers\n * `action`; otherwise a no-op state.\n */\nexport function useTurnstile(captcha: PublicAuthConfig[\"captcha\"], action: CaptchaAction): TurnstileState {\n const siteKey = captcha?.endpoints.includes(action) === true ? captcha.siteKey : undefined;\n const container = useRef<HTMLDivElement | null>(null);\n const widgetId = useRef<string | null>(null);\n const [token, setToken] = useState<string | null>(null);\n const [failed, setFailed] = useState(false);\n\n useEffect(() => {\n if (siteKey === undefined) return undefined;\n let active = true;\n loadTurnstile().then(\n (turnstile) => {\n if (!active || container.current === null) return;\n widgetId.current = turnstile.render(container.current, {\n sitekey: siteKey,\n action,\n callback: (value) => {\n setFailed(false);\n setToken(value);\n },\n \"expired-callback\": () => {\n setToken(null);\n },\n \"error-callback\": () => {\n setToken(null);\n setFailed(true);\n },\n });\n },\n () => {\n if (active) setFailed(true);\n },\n );\n return () => {\n active = false;\n if (widgetId.current !== null) window.turnstile?.remove(widgetId.current);\n widgetId.current = null;\n };\n }, [siteKey, action]);\n\n const reset = useCallback(() => {\n setToken(null);\n if (widgetId.current !== null) window.turnstile?.reset(widgetId.current);\n }, []);\n\n if (siteKey === undefined) return { widget: null, ready: true, token: undefined, reset };\n return {\n widget: (\n <div className=\"grid gap-2\">\n <div ref={container} data-testid=\"turnstile\" />\n {failed ? (\n <p role=\"status\" className=\"text-sm text-destructive\">\n {t(\"captcha.failed\")}\n </p>\n ) : null}\n </div>\n ),\n ready: token !== null,\n token: token ?? undefined,\n reset,\n };\n}\n","import type { InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { useEffect, useState } from \"react\";\n\nexport type PublicAuthConfigState =\n | { status: \"loading\" }\n | { status: \"error\" }\n | { status: \"ready\"; config: PublicAuthConfig };\n\n/** Loads `GET {basePath}/public-config` once per client. */\nexport function usePublicAuthConfig(client: InbisAuthClient): PublicAuthConfigState {\n const [state, setState] = useState<PublicAuthConfigState>({ status: \"loading\" });\n\n useEffect(() => {\n let active = true;\n setState({ status: \"loading\" });\n client.getPublicConfig().then(\n (config) => {\n if (active) setState({ status: \"ready\", config });\n },\n () => {\n if (active) setState({ status: \"error\" });\n },\n );\n return () => {\n active = false;\n };\n }, [client]);\n\n return state;\n}\n","import type { AuthError, InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { ErrorAlert, Notice, TextField } from \"./form-parts.js\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { useTurnstile } from \"./turnstile.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nfunction phoneError(error: AuthError): string {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n return t(\"error.network\");\n case \"INVALID_PHONE_NUMBER\":\n return t(\"phone.invalidNumber\");\n case \"INVALID_OTP\":\n return t(\"phone.invalidCode\");\n case \"OTP_EXPIRED\":\n case \"OTP_NOT_FOUND\":\n return t(\"phone.expired\");\n case \"TOO_MANY_ATTEMPTS\":\n return t(\"phone.tooManyAttempts\");\n case \"REGISTRATION_NOT_ALLOWED\":\n return t(\"phone.notAllowed\");\n case \"BANNED_USER\":\n return t(\"phone.banned\");\n case \"PHONE_COUNTRY_NOT_ALLOWED\":\n return t(\"phone.countryNotAllowed\");\n case \"TOO_MANY_OTP_REQUESTS\":\n return t(\"phone.tooManyRequests\");\n case \"SMS_DAILY_CAP_REACHED\":\n return t(\"phone.smsPaused\");\n case \"RATE_LIMITED\":\n return t(\"error.rateLimited\");\n case \"MISSING_RESPONSE\":\n case \"VERIFICATION_FAILED\":\n return t(\"captcha.rejected\");\n default:\n return t(\"error.generic\");\n }\n}\n\ntype PhoneOtp = NonNullable<PublicAuthConfig[\"methods\"][\"phoneOtp\"]>;\n\nexport interface PhoneOtpVerificationProps {\n client: InbisAuthClient;\n /** The number the code was sent to (as entered; the server normalises it). */\n phoneNumber: string;\n /** Code length and lifetime, from the public config's `methods.phoneOtp`. */\n phoneOtp: PhoneOtp;\n /** Called once the code is accepted and the session exists. */\n onSignedIn: () => void;\n /** Asks for another code. */\n onResend: () => void;\n /** Goes back to entering a number; hidden when absent (e.g. a fixed, invited number). */\n onChangeNumber?: () => void;\n}\n\n/**\n * The second step of phone sign-in: the code from the SMS. Better Auth allows\n * a few attempts per code; after that, or once it expires, the user sends a new one.\n */\nexport function PhoneOtpVerification({ client, phoneNumber, phoneOtp, onSignedIn, onResend, onChangeNumber }: PhoneOtpVerificationProps) {\n const id = useId();\n const [code, setCode] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const result = await client.phone.verify({ phoneNumber, code: code.trim() });\n setSubmitting(false);\n if (result.ok) onSignedIn();\n else setError(phoneError(result.error));\n }\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <Notice\n message={t(\"phone.codeSent\", {\n phoneNumber,\n codeLength: String(phoneOtp.codeLength),\n minutes: String(phoneOtp.expiresInMinutes),\n })}\n />\n {error === null ? null : <ErrorAlert title={t(\"phone.failed\")} message={error} />}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-code`}>{t(\"phone.code\")}</Label>\n <Input\n id={`${id}-code`}\n name=\"code\"\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={phoneOtp.codeLength}\n required\n autoFocus\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n }}\n aria-invalid={error === null ? undefined : true}\n />\n </div>\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"phone.verifying\") : t(\"phone.verify\")}\n </Button>\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onResend}>\n {t(\"phone.resend\")}\n </Button>\n {onChangeNumber === undefined ? null : (\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onChangeNumber}>\n {t(\"phone.changeNumber\")}\n </Button>\n )}\n </form>\n );\n}\n\nexport interface PhoneSignInProps {\n client: InbisAuthClient;\n phoneOtp: PhoneOtp;\n onSignedIn: () => void;\n /** A number fixed by the caller (an invited number): no number field, sent as is. */\n phoneNumber?: string;\n /** The public config's `captcha`: when it covers `phoneOtp`, each code request needs a Turnstile token. */\n captcha?: PublicAuthConfig[\"captcha\"];\n}\n\n/** Phone sign-in as a form: the number (unless fixed), then the code. */\nexport function PhoneSignIn({ client, phoneOtp, onSignedIn, phoneNumber: fixed, captcha }: PhoneSignInProps) {\n const [phoneNumber, setPhoneNumber] = useState(fixed ?? \"\");\n const [sentTo, setSentTo] = useState<string | null>(null);\n const [sends, setSends] = useState(0);\n const [error, setError] = useState<string | null>(null);\n // A Turnstile token works once: a new code is asked for from the number step, with a new check.\n const needsCheck = captcha?.endpoints.includes(\"phoneOtp\") === true;\n\n async function send(number: string, captchaToken?: string) {\n setError(null);\n const result = await client.phone.sendOtp({ phoneNumber: number, ...(captchaToken === undefined ? {} : { captchaToken }) });\n if (result.ok) {\n setSentTo(number);\n setSends((count) => count + 1);\n } else {\n setSentTo(null);\n setError(phoneError(result.error));\n }\n }\n\n if (sentTo === null) {\n return (\n <PhoneNumberStep\n phoneNumber={phoneNumber}\n onPhoneNumberChange={setPhoneNumber}\n fixed={fixed !== undefined}\n captcha={captcha}\n error={error}\n onSend={send}\n />\n );\n }\n return (\n <PhoneOtpVerification\n // A new code gives a fresh form.\n key={sends}\n client={client}\n phoneNumber={sentTo}\n phoneOtp={phoneOtp}\n onSignedIn={onSignedIn}\n onResend={() => {\n if (needsCheck) setSentTo(null);\n else void send(sentTo);\n }}\n {...(fixed === undefined\n ? {\n onChangeNumber: () => {\n setSentTo(null);\n },\n }\n : {})}\n />\n );\n}\n\ninterface PhoneNumberStepProps {\n phoneNumber: string;\n onPhoneNumberChange: (value: string) => void;\n /** The number is fixed (an invitation): no field. */\n fixed: boolean;\n captcha: PublicAuthConfig[\"captcha\"];\n error: string | null;\n onSend: (phoneNumber: string, captchaToken?: string) => Promise<void>;\n}\n\n/** The first step: the number (unless fixed) and, when on, the Turnstile check. */\nfunction PhoneNumberStep({ phoneNumber, onPhoneNumberChange, fixed, captcha, error, onSend }: PhoneNumberStepProps) {\n const id = useId();\n const [sending, setSending] = useState(false);\n const check = useTurnstile(captcha, \"phoneOtp\");\n\n async function submit() {\n setSending(true);\n const token = check.token;\n check.reset();\n await onSend(phoneNumber.trim(), token);\n setSending(false);\n }\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : <ErrorAlert title={t(\"phone.failed\")} message={error} />}\n {fixed ? null : (\n <TextField\n id={`${id}-phone`}\n label={t(\"phone.number\")}\n name=\"phone\"\n type=\"tel\"\n autoComplete=\"tel\"\n value={phoneNumber}\n onChange={onPhoneNumberChange}\n invalid={error !== null}\n hint={t(\"phone.numberHint\")}\n />\n )}\n {check.widget}\n <Button type=\"submit\" disabled={sending || !check.ready}>\n {sending ? t(\"phone.sending\") : t(\"phone.send\")}\n </Button>\n </form>\n );\n}\n\nexport interface PhoneSignInScreenProps {\n client: InbisAuthClient;\n /** Called after a successful sign-in, e.g. to navigate to the protected area. */\n onSignedIn: () => void;\n /** Back to the other sign-in methods (e.g. the `SignInScreen`); hidden when absent. */\n onSignIn?: () => void;\n}\n\n/**\n * Phone sign-in screen (when the public config has `methods.phoneOtp`): enter\n * an international number, receive a code by SMS, enter it. A number's first\n * sign-in creates the account when registration is open or the number was\n * invited; the screen never reveals whether a number has an account.\n */\nexport function PhoneSignInScreen({ client, onSignedIn, onSignIn }: PhoneSignInScreenProps) {\n const state = usePublicAuthConfig(client);\n return (\n <ConfigGate\n state={state}\n title={t(\"phone.title\")}\n ready={(config) => (\n <Shell title={t(\"phone.title\")} description={t(\"phone.description\")}>\n <div className=\"grid gap-4\">\n {config.methods.phoneOtp === undefined ? (\n <p className=\"text-sm text-muted-foreground\">{t(\"signIn.noMethods\")}</p>\n ) : (\n <PhoneSignIn client={client} phoneOtp={config.methods.phoneOtp} onSignedIn={onSignedIn} captcha={config.captcha} />\n )}\n {onSignIn === undefined ? null : (\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onSignIn}>\n {t(\"auth.backToSignIn\")}\n </Button>\n </p>\n )}\n </div>\n </Shell>\n )}\n />\n );\n}\n","import type { AuthError, InbisAuthClient, InvitationDetails } from \"@awsmbiz/inbis-auth/client\";\nimport { Button } from \"@awsmbiz/inbis-ui\";\nimport { useEffect, useId, useState } from \"react\";\nimport { ErrorAlert, Notice, queryParam, TextField } from \"./form-parts.js\";\nimport { t } from \"./messages.js\";\nimport { PhoneSignIn } from \"./phone-sign-in.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface AcceptInvitationScreenProps {\n client: InbisAuthClient;\n /** Called to go to the sign-in screen (after accepting, or to give up). */\n onSignIn: () => void;\n /** The page's query string, which carries `token` from the emailed link. Defaults to `window.location.search`. */\n search?: string;\n /**\n * Called once an invited phone number has signed in. Phone invitations (sent\n * by SMS) are accepted by signing in with the number right on this screen;\n * without this callback the screen only points the invitee to phone sign-in.\n */\n onSignedIn?: () => void;\n}\n\ntype Bounds = { minLength: number; maxLength: number } | undefined;\n\ntype Lookup = { state: \"loading\" } | { state: \"invalid\" } | { state: \"ready\"; invitation: InvitationDetails };\n\nfunction errorMessage(error: AuthError, bounds: Bounds): string {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n return t(\"error.network\");\n case \"INVITATION_INVALID\":\n return t(\"invitation.invalid\");\n case \"INVALID_NAME\":\n return t(\"invitation.nameRequired\");\n case \"USER_ALREADY_EXISTS\":\n return t(\"invitation.exists\");\n case \"REGISTRATION_NOT_ALLOWED\":\n return t(\"invitation.notAllowed\");\n case \"PASSWORD_COMPROMISED\":\n return t(\"resetPassword.compromised\");\n case \"PASSWORD_TOO_SHORT\":\n return bounds === undefined ? error.message : t(\"resetPassword.tooShort\", { minLength: String(bounds.minLength) });\n case \"PASSWORD_TOO_LONG\":\n return bounds === undefined ? error.message : t(\"resetPassword.tooLong\", { maxLength: String(bounds.maxLength) });\n default:\n return error.message || t(\"error.generic\");\n }\n}\n\nfunction AcceptForm({ client, onSignIn, token, bounds }: AcceptInvitationScreenProps & { token: string; bounds: Bounds }) {\n const id = useId();\n const [name, setName] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [confirm, setConfirm] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [done, setDone] = useState(false);\n\n async function submit() {\n const invalid =\n name.trim() === \"\"\n ? t(\"invitation.nameRequired\")\n : bounds !== undefined && password !== confirm\n ? t(\"resetPassword.mismatch\")\n : null;\n setError(invalid);\n if (invalid !== null) return;\n setSubmitting(true);\n const result = await client.invitations.accept({ token, name: name.trim(), password });\n setSubmitting(false);\n if (result.ok) setDone(true);\n else setError(errorMessage(result.error, bounds));\n }\n\n if (done) {\n return (\n <div className=\"grid gap-4\">\n <Notice message={t(\"invitation.done\")} />\n <Button type=\"button\" onClick={onSignIn}>\n {t(\"auth.signIn\")}\n </Button>\n </div>\n );\n }\n\n const hint =\n bounds === undefined\n ? undefined\n : t(\"signUp.passwordHint\", { minLength: String(bounds.minLength), maxLength: String(bounds.maxLength) });\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : <ErrorAlert title={t(\"invitation.failed\")} message={error} />}\n <TextField\n id={`${id}-name`}\n label={t(\"invitation.name\")}\n name=\"name\"\n type=\"text\"\n autoComplete=\"name\"\n value={name}\n onChange={setName}\n invalid={error !== null}\n />\n {bounds === undefined ? null : (\n <>\n <TextField\n id={`${id}-password`}\n label={t(\"invitation.password\")}\n name=\"new-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={password}\n onChange={setPassword}\n invalid={error !== null}\n {...(hint === undefined ? {} : { hint })}\n />\n <TextField\n id={`${id}-confirm`}\n label={t(\"invitation.confirmPassword\")}\n name=\"confirm-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={confirm}\n onChange={setConfirm}\n invalid={error !== null}\n />\n </>\n )}\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"invitation.submitting\") : t(\"invitation.submit\")}\n </Button>\n </form>\n );\n}\n\n/**\n * Accepts an invitation from its emailed link (`?token=…`): shows who it is\n * for, asks for a name and (when the password method is on) a password, and\n * creates the account. Accepting does not sign in; it offers sign-in after.\n * An invalid, expired, revoked or used link says so and creates nothing.\n */\nexport function AcceptInvitationScreen(props: AcceptInvitationScreenProps) {\n const state = usePublicAuthConfig(props.client);\n const token = queryParam(props.search, \"token\") ?? \"\";\n const [lookup, setLookup] = useState<Lookup>(token === \"\" ? { state: \"invalid\" } : { state: \"loading\" });\n\n useEffect(() => {\n if (token === \"\") return undefined;\n let active = true;\n void props.client.invitations.get({ token }).then((result) => {\n if (active) setLookup(result.ok ? { state: \"ready\", invitation: result.data } : { state: \"invalid\" });\n });\n return () => {\n active = false;\n };\n }, [props.client, token]);\n\n return (\n <ConfigGate\n state={state}\n title={t(\"invitation.title\")}\n ready={(config) => {\n const invitation = lookup.state === \"ready\" ? lookup.invitation : undefined;\n const admin = invitation?.role === \"admin\";\n const description =\n invitation === undefined\n ? undefined\n : invitation.email !== null\n ? t(admin ? \"invitation.descriptionAdmin\" : \"invitation.description\", {\n appName: config.app.name,\n email: invitation.email,\n })\n : invitation.phoneNumber !== null\n ? t(admin ? \"invitation.descriptionPhoneAdmin\" : \"invitation.descriptionPhone\", {\n appName: config.app.name,\n phoneNumber: invitation.phoneNumber,\n })\n : undefined;\n const phoneOtp = config.methods.phoneOtp;\n const phoneNumber = invitation?.email === null ? invitation.phoneNumber : null;\n const { onSignedIn } = props;\n return (\n <Shell title={t(\"invitation.title\")} {...(description === undefined ? {} : { description })}>\n <div className=\"grid gap-4\">\n {lookup.state === \"loading\" ? <p className=\"text-sm text-muted-foreground\">{t(\"invitation.loading\")}</p> : null}\n {lookup.state === \"invalid\" ? <ErrorAlert message={t(\"invitation.invalid\")} /> : null}\n {phoneNumber !== null && phoneOtp !== undefined && onSignedIn !== undefined ? (\n <PhoneSignIn client={props.client} phoneOtp={phoneOtp} phoneNumber={phoneNumber} onSignedIn={onSignedIn} captcha={config.captcha} />\n ) : invitation?.email === null ? (\n <ErrorAlert message={t(\"invitation.phone\")} />\n ) : null}\n {invitation?.email == null ? null : <AcceptForm {...props} token={token} bounds={config.password} />}\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={props.onSignIn}>\n {t(\"auth.backToSignIn\")}\n </Button>\n </p>\n </div>\n </Shell>\n );\n }}\n />\n );\n}\n","import type { AuthError, InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Button } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { ErrorAlert, Notice, onThisOrigin, TextField } from \"./form-parts.js\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { useTurnstile } from \"./turnstile.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface ForgotPasswordScreenProps {\n client: InbisAuthClient;\n /** Called to go back to the sign-in screen. */\n onSignIn: () => void;\n /**\n * Where the emailed link sends the user (the `ResetPasswordScreen`), as a\n * relative path or a trusted-origin URL. Default `/reset-password` on this origin.\n */\n resetPasswordURL?: string;\n}\n\nfunction errorMessage(error: AuthError): string {\n if (error.code === \"NETWORK_ERROR\") return t(\"error.network\");\n if (error.code === \"MISSING_RESPONSE\" || error.code === \"VERIFICATION_FAILED\") return t(\"captcha.rejected\");\n return error.message || t(\"error.generic\");\n}\n\nfunction ForgotPasswordForm({\n client,\n resetPasswordURL,\n captcha,\n onSent,\n}: Pick<ForgotPasswordScreenProps, \"client\" | \"resetPasswordURL\"> & {\n /** The public config's `captcha` (Turnstile on the request when it lists `passwordReset`). */\n captcha: PublicAuthConfig[\"captcha\"];\n onSent: () => void;\n}) {\n const id = useId();\n const [email, setEmail] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const check = useTurnstile(captcha, \"passwordReset\");\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const captchaToken = check.token;\n // A token works once: the next attempt needs a new check.\n check.reset();\n const result = await client.requestPasswordReset({\n email,\n redirectTo: resetPasswordURL ?? onThisOrigin(\"/reset-password\"),\n ...(captchaToken === undefined ? {} : { captchaToken }),\n });\n setSubmitting(false);\n if (result.ok) onSent();\n else setError(errorMessage(result.error));\n }\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : <ErrorAlert title={t(\"forgotPassword.failed\")} message={error} />}\n <TextField\n id={`${id}-email`}\n label={t(\"forgotPassword.email\")}\n name=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n value={email}\n onChange={setEmail}\n invalid={error !== null}\n />\n {check.widget}\n <Button type=\"submit\" disabled={submitting || !check.ready}>\n {submitting ? t(\"forgotPassword.submitting\") : t(\"forgotPassword.submit\")}\n </Button>\n </form>\n );\n}\n\n/**\n * Asks for an email address and sends a password-reset link. Always confirms\n * in the same words, whether or not the address has an account. Renders the\n * Turnstile widget when the server's public config asks for it.\n */\nexport function ForgotPasswordScreen({ client, onSignIn, resetPasswordURL }: ForgotPasswordScreenProps) {\n const state = usePublicAuthConfig(client);\n const [sent, setSent] = useState(false);\n\n const back = (\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onSignIn}>\n {t(\"auth.backToSignIn\")}\n </Button>\n </p>\n );\n\n return (\n <ConfigGate\n state={state}\n title={t(\"forgotPassword.title\")}\n ready={(config) => (\n <Shell title={t(\"forgotPassword.title\")} description={t(\"forgotPassword.description\")}>\n <div className=\"grid gap-4\">\n {sent ? (\n <Notice message={t(\"forgotPassword.sent\")} />\n ) : (\n <ForgotPasswordForm\n client={client}\n captcha={config.captcha}\n onSent={() => {\n setSent(true);\n }}\n {...(resetPasswordURL === undefined ? {} : { resetPasswordURL })}\n />\n )}\n {back}\n </div>\n </Shell>\n )}\n />\n );\n}\n","import type { AuthError, InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Button } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { ErrorAlert, Notice, queryParam, TextField } from \"./form-parts.js\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface ResetPasswordScreenProps {\n client: InbisAuthClient;\n /** Called to go to the sign-in screen (after the change, or to give up). */\n onSignIn: () => void;\n /** Called to request a new link, e.g. to navigate to the `ForgotPasswordScreen`. */\n onRequestNewLink: () => void;\n /**\n * The page's query string, which carries `token` (or `error`) from the\n * emailed link. Defaults to `window.location.search`.\n */\n search?: string;\n}\n\ntype Bounds = { minLength: number; maxLength: number } | undefined;\n\nfunction errorMessage(error: AuthError, bounds: Bounds): string {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n return t(\"error.network\");\n case \"INVALID_TOKEN\":\n return t(\"resetPassword.invalidLink\");\n case \"PASSWORD_COMPROMISED\":\n return t(\"resetPassword.compromised\");\n case \"PASSWORD_TOO_SHORT\":\n return bounds === undefined ? error.message : t(\"resetPassword.tooShort\", { minLength: String(bounds.minLength) });\n case \"PASSWORD_TOO_LONG\":\n return bounds === undefined ? error.message : t(\"resetPassword.tooLong\", { maxLength: String(bounds.maxLength) });\n default:\n return error.message || t(\"error.generic\");\n }\n}\n\nfunction ResetForm({ client, onSignIn, onRequestNewLink, token, bounds }: ResetPasswordScreenProps & { token: string; bounds: Bounds }) {\n const id = useId();\n const [password, setPassword] = useState(\"\");\n const [confirm, setConfirm] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<{ message: string; invalidLink: boolean } | null>(null);\n const [done, setDone] = useState(false);\n\n async function submit() {\n if (password !== confirm) {\n setError({ message: t(\"resetPassword.mismatch\"), invalidLink: false });\n return;\n }\n setSubmitting(true);\n setError(null);\n const result = await client.resetPassword({ token, newPassword: password });\n setSubmitting(false);\n if (result.ok) setDone(true);\n else setError({ message: errorMessage(result.error, bounds), invalidLink: result.error.code === \"INVALID_TOKEN\" });\n }\n\n if (done) {\n return (\n <div className=\"grid gap-4\">\n <Notice message={t(\"resetPassword.done\")} />\n <Button type=\"button\" onClick={onSignIn}>\n {t(\"auth.signIn\")}\n </Button>\n </div>\n );\n }\n\n const hint =\n bounds === undefined\n ? undefined\n : t(\"signUp.passwordHint\", { minLength: String(bounds.minLength), maxLength: String(bounds.maxLength) });\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : <ErrorAlert title={t(\"resetPassword.failed\")} message={error.message} />}\n {error?.invalidLink === true ? (\n <Button type=\"button\" variant=\"outline\" onClick={onRequestNewLink}>\n {t(\"resetPassword.requestNew\")}\n </Button>\n ) : null}\n <TextField\n id={`${id}-password`}\n label={t(\"resetPassword.newPassword\")}\n name=\"new-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={password}\n onChange={setPassword}\n invalid={error !== null}\n {...(hint === undefined ? {} : { hint })}\n />\n <TextField\n id={`${id}-confirm`}\n label={t(\"resetPassword.confirmPassword\")}\n name=\"confirm-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={confirm}\n onChange={setConfirm}\n invalid={error !== null}\n />\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"resetPassword.submitting\") : t(\"resetPassword.submit\")}\n </Button>\n </form>\n );\n}\n\n/**\n * Sets a new password with the token from an emailed reset link\n * (`?token=…`). An expired or used link (`?error=INVALID_TOKEN`, or the\n * server rejecting the token) offers a new link instead.\n */\nexport function ResetPasswordScreen(props: ResetPasswordScreenProps) {\n const state = usePublicAuthConfig(props.client);\n const token = queryParam(props.search, \"token\");\n const linkError = queryParam(props.search, \"error\");\n\n return (\n <ConfigGate\n state={state}\n title={t(\"resetPassword.title\")}\n ready={(config) => (\n <Shell title={t(\"resetPassword.title\")}>\n <div className=\"grid gap-4\">\n {token === null || token === \"\" || linkError !== null ? (\n <>\n <ErrorAlert message={t(\"resetPassword.invalidLink\")} />\n <Button type=\"button\" onClick={props.onRequestNewLink}>\n {t(\"resetPassword.requestNew\")}\n </Button>\n </>\n ) : (\n <ResetForm {...props} token={token} bounds={config.password} />\n )}\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={props.onSignIn}>\n {t(\"auth.backToSignIn\")}\n </Button>\n </p>\n </div>\n </Shell>\n )}\n />\n );\n}\n","import type { AuthError, InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { t } from \"./messages.js\";\n\nexport interface TwoFactorChallengeProps {\n client: InbisAuthClient;\n /** Called once the second factor is accepted and the session exists. */\n onVerified: () => void;\n}\n\nfunction challengeError(error: AuthError, backup: boolean): string {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n return t(\"error.network\");\n case \"INVALID_CODE\":\n return t(\"twoFactor.invalidCode\");\n case \"INVALID_BACKUP_CODE\":\n return t(\"twoFactor.invalidBackupCode\");\n case \"INVALID_TWO_FACTOR_COOKIE\":\n return t(\"twoFactor.challengeExpired\");\n case \"TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE\":\n return t(\"twoFactor.tooManyAttempts\");\n case \"ACCOUNT_TEMPORARILY_LOCKED\":\n return t(\"twoFactor.locked\");\n default:\n if (error.status === 401) return backup ? t(\"twoFactor.invalidBackupCode\") : t(\"twoFactor.invalidCode\");\n return t(\"error.generic\");\n }\n}\n\n/**\n * The second step of a password sign-in for a user with 2FA on: a code from\n * the authenticator app, or a single-use backup code instead. Rendered by\n * `SignInScreen` after the password is accepted; usable on its own too.\n */\nexport function TwoFactorChallenge({ client, onVerified }: TwoFactorChallengeProps) {\n const id = useId();\n const [backup, setBackup] = useState(false);\n const [code, setCode] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const trimmed = code.trim();\n const result = backup\n ? await client.twoFactor.verifyBackupCode({ code: trimmed })\n : await client.twoFactor.verifyTotp({ code: trimmed });\n setSubmitting(false);\n if (result.ok) onVerified();\n else setError(challengeError(result.error, backup));\n }\n\n function switchMode() {\n setBackup(!backup);\n setCode(\"\");\n setError(null);\n }\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <p className=\"text-sm text-muted-foreground\">\n {backup ? t(\"twoFactor.challenge.backupDescription\") : t(\"twoFactor.challenge.description\")}\n </p>\n {error === null ? null : (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"twoFactor.failed\")}</AlertTitle>\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-code`}>{backup ? t(\"twoFactor.backupCode\") : t(\"twoFactor.code\")}</Label>\n <Input\n id={`${id}-code`}\n name=\"code\"\n autoComplete=\"one-time-code\"\n {...(backup ? {} : { inputMode: \"numeric\" as const, pattern: \"[0-9]*\", maxLength: 6 })}\n required\n autoFocus\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n }}\n aria-invalid={error === null ? undefined : true}\n />\n </div>\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"twoFactor.verifying\") : t(\"twoFactor.verify\")}\n </Button>\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={switchMode}>\n {backup ? t(\"twoFactor.useAuthenticator\") : t(\"twoFactor.useBackupCode\")}\n </Button>\n </form>\n );\n}\n","import type { AuthError, InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { PhoneSignIn } from \"./phone-sign-in.js\";\nimport { TwoFactorChallenge } from \"./two-factor-challenge.js\";\nimport { useTurnstile } from \"./turnstile.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface SignInScreenProps {\n client: InbisAuthClient;\n /** Called after a successful sign-in, e.g. to navigate to the protected area. */\n onSignedIn: () => void;\n /** Where the server may redirect after sign-in; must be relative or a trusted origin. */\n callbackURL?: string;\n /**\n * Called when the user chooses to create an account, e.g. to navigate to the\n * `SignUpScreen`. The link is shown only when registration is `open`.\n */\n onCreateAccount?: () => void;\n /**\n * Called when the user forgot their password, e.g. to navigate to the\n * `ForgotPasswordScreen`. Shown only when the server offers password reset.\n */\n onForgotPassword?: () => void;\n /**\n * Called when the user wants a new verification link after signing in with\n * an unverified address, e.g. to navigate to the `VerifyEmailScreen`.\n */\n onVerifyEmail?: () => void;\n /**\n * Called when the user chooses to sign in with a phone number, e.g. to\n * navigate to the `PhoneSignInScreen`. Shown only when the server offers phone OTP.\n */\n onPhoneSignIn?: () => void;\n}\n\nfunction errorMessage(error: AuthError): string {\n if (error.code === \"NETWORK_ERROR\") return t(\"error.network\");\n if (error.code === \"EMAIL_NOT_VERIFIED\") return t(\"signIn.emailNotVerified\");\n if (error.status === 401) return t(\"signIn.invalidCredentials\");\n if (error.code === \"RATE_LIMITED\") return t(\"error.rateLimited\");\n if (error.code === \"MISSING_RESPONSE\" || error.code === \"VERIFICATION_FAILED\") return t(\"captcha.rejected\");\n return error.message || t(\"error.generic\");\n}\n\ntype FormProps = Omit<SignInScreenProps, \"onCreateAccount\" | \"onForgotPassword\" | \"onPhoneSignIn\"> & {\n /** The password was right and the user has 2FA on: show the challenge. */\n onTwoFactorRequired: () => void;\n /** The public config's `captcha` (Turnstile on sign-in when it lists `signIn`). */\n captcha: PublicAuthConfig[\"captcha\"];\n};\n\nfunction EmailPasswordForm({ client, onSignedIn, callbackURL, onTwoFactorRequired, onVerifyEmail, captcha }: FormProps) {\n const id = useId();\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [unverified, setUnverified] = useState(false);\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const check = useTurnstile(captcha, \"signIn\");\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const captchaToken = check.token;\n // A token works once: the next attempt needs a new check.\n check.reset();\n const result = await client.signInWithEmail({\n email,\n password,\n ...(callbackURL === undefined ? {} : { callbackURL }),\n ...(captchaToken === undefined ? {} : { captchaToken }),\n });\n setSubmitting(false);\n if (!result.ok) {\n setError(errorMessage(result.error));\n setUnverified(result.error.code === \"EMAIL_NOT_VERIFIED\");\n } else if (result.twoFactor === undefined) onSignedIn();\n else onTwoFactorRequired();\n }\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"signIn.failed\")}</AlertTitle>\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n {unverified && onVerifyEmail !== undefined ? (\n <Button type=\"button\" variant=\"outline\" onClick={onVerifyEmail}>\n {t(\"signIn.resendVerification\")}\n </Button>\n ) : null}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-email`}>{t(\"signIn.email\")}</Label>\n <Input\n id={`${id}-email`}\n name=\"email\"\n type=\"email\"\n autoComplete=\"username\"\n required\n value={email}\n onChange={(event) => {\n setEmail(event.target.value);\n }}\n aria-invalid={error === null ? undefined : true}\n />\n </div>\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-password`}>{t(\"signIn.password\")}</Label>\n <Input\n id={`${id}-password`}\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n }}\n aria-invalid={error === null ? undefined : true}\n />\n </div>\n {check.widget}\n <Button type=\"submit\" disabled={submitting || !check.ready}>\n {submitting ? t(\"signIn.submitting\") : t(\"signIn.submit\")}\n </Button>\n </form>\n );\n}\n\nfunction SignInMethods(props: SignInScreenProps & { config: PublicAuthConfig; onTwoFactorRequired: () => void }) {\n const { config, onCreateAccount, onForgotPassword, onPhoneSignIn, ...formProps } = props;\n const phoneOtp = config.methods.phoneOtp;\n if (config.methods.emailPassword === undefined) {\n // A phone-only app signs in by phone right here.\n if (phoneOtp !== undefined) return <PhoneSignIn client={props.client} phoneOtp={phoneOtp} onSignedIn={props.onSignedIn} captcha={config.captcha} />;\n return <p className=\"text-sm text-muted-foreground\">{t(\"signIn.noMethods\")}</p>;\n }\n return (\n <div className=\"grid gap-4\">\n <EmailPasswordForm {...formProps} captcha={config.captcha} />\n {phoneOtp !== undefined && onPhoneSignIn !== undefined ? (\n <Button type=\"button\" variant=\"outline\" onClick={onPhoneSignIn}>\n {t(\"signIn.withPhone\")}\n </Button>\n ) : null}\n {config.email?.passwordReset === true && onForgotPassword !== undefined ? (\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onForgotPassword}>\n {t(\"signIn.forgotPassword\")}\n </Button>\n </p>\n ) : null}\n {/* Offered only when the server allows self sign-up; the server enforces it regardless. */}\n {config.registration.mode === \"open\" && onCreateAccount !== undefined ? (\n <p className=\"text-center text-sm text-muted-foreground\">\n {t(\"signIn.noAccount\")}{\" \"}\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onCreateAccount}>\n {t(\"signIn.createAccount\")}\n </Button>\n </p>\n ) : null}\n </div>\n );\n}\n\n/**\n * The sign-in screen. Renders only the methods the server's public config\n * enables (email + password, and phone OTP). For a user with 2FA on, the password is\n * followed by the 2FA challenge (authenticator code or backup code).\n */\nexport function SignInScreen(props: SignInScreenProps) {\n const state = usePublicAuthConfig(props.client);\n const [twoFactor, setTwoFactor] = useState(false);\n if (twoFactor) {\n return (\n <Shell title={t(\"twoFactor.title\")}>\n <TwoFactorChallenge client={props.client} onVerified={props.onSignedIn} />\n </Shell>\n );\n }\n return (\n <ConfigGate\n state={state}\n title={t(\"signIn.title\")}\n ready={(config) => (\n <Shell\n title={t(\"signIn.title\")}\n // A phone-only app signs in by phone on this screen (SignInMethods).\n description={t(config.methods.emailPassword === undefined && config.methods.phoneOtp !== undefined ? \"signIn.descriptionPhone\" : \"signIn.description\", {\n appName: config.app.name,\n })}\n >\n <SignInMethods\n {...props}\n config={config}\n onTwoFactorRequired={() => {\n setTwoFactor(true);\n }}\n />\n </Shell>\n )}\n />\n );\n}\n","import type { AuthError, InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { useTurnstile } from \"./turnstile.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface SignUpScreenProps {\n client: InbisAuthClient;\n /** Called after the account was created (Better Auth signs the new user in). */\n onSignedUp: () => void;\n /** Called to go back to the sign-in screen. */\n onSignIn: () => void;\n /** Where the server may redirect after sign-up; must be relative or a trusted origin. */\n callbackURL?: string;\n}\n\nfunction errorMessage(error: AuthError): string {\n if (error.code === \"NETWORK_ERROR\") return t(\"error.network\");\n if (error.code === \"MISSING_RESPONSE\" || error.code === \"VERIFICATION_FAILED\") return t(\"captcha.rejected\");\n return error.message || t(\"error.generic\");\n}\n\nfunction Field(props: {\n id: string;\n label: string;\n name: string;\n type: string;\n autoComplete: string;\n value: string;\n onChange: (value: string) => void;\n invalid: boolean;\n hint?: string;\n}) {\n return (\n <div className=\"grid gap-2\">\n <Label htmlFor={props.id}>{props.label}</Label>\n <Input\n id={props.id}\n name={props.name}\n type={props.type}\n autoComplete={props.autoComplete}\n required\n value={props.value}\n onChange={(event) => {\n props.onChange(event.target.value);\n }}\n aria-invalid={props.invalid ? true : undefined}\n aria-describedby={props.hint === undefined ? undefined : `${props.id}-hint`}\n />\n {props.hint === undefined ? null : (\n <p id={`${props.id}-hint`} className=\"text-xs text-muted-foreground\">\n {props.hint}\n </p>\n )}\n </div>\n );\n}\n\nfunction SignUpForm({ client, onSignedUp, callbackURL, config }: SignUpScreenProps & { config: PublicAuthConfig }) {\n const id = useId();\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const check = useTurnstile(config.captcha, \"signUp\");\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const captchaToken = check.token;\n // A token works once: the next attempt needs a new check.\n check.reset();\n const result = await client.signUpWithEmail({\n name,\n email,\n password,\n ...(callbackURL === undefined ? {} : { callbackURL }),\n ...(captchaToken === undefined ? {} : { captchaToken }),\n });\n setSubmitting(false);\n if (result.ok) onSignedUp();\n else setError(errorMessage(result.error));\n }\n\n const invalid = error !== null;\n const bounds = config.password;\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"signUp.failed\")}</AlertTitle>\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n <Field id={`${id}-name`} label={t(\"signUp.name\")} name=\"name\" type=\"text\" autoComplete=\"name\" value={name} onChange={setName} invalid={invalid} />\n <Field id={`${id}-email`} label={t(\"signUp.email\")} name=\"email\" type=\"email\" autoComplete=\"email\" value={email} onChange={setEmail} invalid={invalid} />\n <Field\n id={`${id}-password`}\n label={t(\"signUp.password\")}\n name=\"password\"\n type=\"password\"\n autoComplete=\"new-password\"\n value={password}\n onChange={setPassword}\n invalid={invalid}\n {...(bounds === undefined\n ? {}\n : { hint: t(\"signUp.passwordHint\", { minLength: String(bounds.minLength), maxLength: String(bounds.maxLength) }) })}\n />\n {check.widget}\n <Button type=\"submit\" disabled={submitting || !check.ready}>\n {submitting ? t(\"signUp.submitting\") : t(\"signUp.submit\")}\n </Button>\n </form>\n );\n}\n\n/**\n * The register screen. Shows the form only when the server's public config says\n * registration is `open` and email + password is enabled; otherwise it explains\n * that registration is not open. The server enforces the policy either way.\n */\nexport function SignUpScreen(props: SignUpScreenProps) {\n const state = usePublicAuthConfig(props.client);\n const backToSignIn = (\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={props.onSignIn}>\n {t(\"signUp.backToSignIn\")}\n </Button>\n );\n return (\n <ConfigGate\n state={state}\n title={t(\"signUp.title\")}\n ready={(config) =>\n config.registration.mode === \"open\" && config.methods.emailPassword !== undefined ? (\n <Shell title={t(\"signUp.title\")} description={t(\"signUp.description\", { appName: config.app.name })}>\n <div className=\"grid gap-4\">\n <SignUpForm {...props} config={config} />\n <p className=\"text-center text-sm\">{backToSignIn}</p>\n </div>\n </Shell>\n ) : (\n <Shell title={t(\"signUp.title\")}>\n <div className=\"grid gap-4\">\n <Alert>\n <AlertTitle>{t(\"signUp.closedTitle\")}</AlertTitle>\n <AlertDescription>{t(\"signUp.closed\", { appName: config.app.name })}</AlertDescription>\n </Alert>\n <p className=\"text-center text-sm\">{backToSignIn}</p>\n </div>\n </Shell>\n )\n }\n />\n );\n}\n","import type { AuthError, InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Button } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { ErrorAlert, Notice, onThisOrigin, queryParam, TextField } from \"./form-parts.js\";\nimport { t } from \"./messages.js\";\nimport { Shell } from \"./shell.js\";\n\nexport interface VerifyEmailScreenProps {\n client: InbisAuthClient;\n /** Called to go to the sign-in screen. */\n onSignIn: () => void;\n /**\n * Where verification links return to: this screen, with `verified=1`.\n * Relative path or trusted-origin URL. Default `/verify-email?verified=1` on this origin.\n * A failed link comes back with `&error=TOKEN_EXPIRED|INVALID_TOKEN`.\n */\n callbackURL?: string;\n /** The page's query string. Defaults to `window.location.search`. */\n search?: string;\n}\n\nfunction errorMessage(error: AuthError): string {\n if (error.code === \"NETWORK_ERROR\") return t(\"error.network\");\n return error.message || t(\"error.generic\");\n}\n\nfunction ResendForm({ client, callbackURL }: VerifyEmailScreenProps) {\n const id = useId();\n const [email, setEmail] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n async function submit() {\n setSubmitting(true);\n setError(null);\n const result = await client.sendVerificationEmail({\n email,\n callbackURL: callbackURL ?? onThisOrigin(\"/verify-email?verified=1\"),\n });\n setSubmitting(false);\n if (result.ok) setSent(true);\n else setError(errorMessage(result.error));\n }\n\n if (sent) return <Notice message={t(\"verifyEmail.sent\")} />;\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {error === null ? null : <ErrorAlert title={t(\"verifyEmail.failed\")} message={error} />}\n <TextField\n id={`${id}-email`}\n label={t(\"verifyEmail.email\")}\n name=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n value={email}\n onChange={setEmail}\n invalid={error !== null}\n />\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"verifyEmail.submitting\") : t(\"verifyEmail.submit\")}\n </Button>\n </form>\n );\n}\n\n/**\n * Where verification links land, and where to send users after sign-up\n * (`?sent=1`: \"check your inbox\"). Shows success (`?verified=1`), explains an\n * expired or invalid link (`?error=…`), and otherwise lets the user ask for a\n * new link. Requesting a link answers the same whether or not the address has\n * an account.\n */\nexport function VerifyEmailScreen(props: VerifyEmailScreenProps) {\n const linkError = queryParam(props.search, \"error\");\n const verified = queryParam(props.search, \"verified\") === \"1\";\n const justSent = queryParam(props.search, \"sent\") === \"1\";\n\n if (verified && linkError === null) {\n return (\n <Shell title={t(\"verifyEmail.verifiedTitle\")}>\n <div className=\"grid gap-4\">\n <Notice message={t(\"verifyEmail.verified\")} />\n <Button type=\"button\" onClick={props.onSignIn}>\n {t(\"verifyEmail.continue\")}\n </Button>\n </div>\n </Shell>\n );\n }\n\n return (\n <Shell title={t(\"verifyEmail.title\")} description={t(\"verifyEmail.description\")}>\n <div className=\"grid gap-4\">\n {linkError === null ? null : <ErrorAlert message={t(\"verifyEmail.invalid\")} />}\n {justSent && linkError === null ? <Notice message={t(\"verifyEmail.checkInbox\")} /> : null}\n <ResendForm {...props} />\n <p className=\"text-center text-sm\">\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={props.onSignIn}>\n {t(\"auth.backToSignIn\")}\n </Button>\n </p>\n </div>\n </Shell>\n );\n}\n","import type { AuthError } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useMemo, useState } from \"react\";\nimport { renderSVG } from \"uqr\";\nimport { t, type MessageKey } from \"./messages.js\";\n\n/* The steps of `TwoFactorSettingsScreen`. Package-internal. */\n\nexport type Purpose = \"setUp\" | \"regenerate\" | \"disable\";\n\nexport interface Failure {\n message: string;\n /** The server wants a recent sign-in. */\n notFresh: boolean;\n}\n\nexport function failure(error: AuthError, fallback: MessageKey = \"error.generic\"): Failure {\n if (error.code === \"SESSION_NOT_FRESH\") return { message: t(\"twoFactor.notFresh\"), notFresh: true };\n if (error.code === \"NETWORK_ERROR\") return { message: t(\"error.network\"), notFresh: false };\n if (error.code === \"INVALID_PASSWORD\") return { message: t(\"twoFactor.invalidPassword\"), notFresh: false };\n if (error.code === \"INVALID_CODE\") return { message: t(\"twoFactor.invalidCode\"), notFresh: false };\n return { message: t(fallback), notFresh: false };\n}\n\nfunction FailureAlert({ failed, onReauthenticate }: { failed: Failure; onReauthenticate?: (() => void) | undefined }) {\n return (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"twoFactor.settings.failed\")}</AlertTitle>\n <AlertDescription>\n {failed.message}\n {failed.notFresh && onReauthenticate !== undefined ? (\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onReauthenticate}>\n {t(\"twoFactor.signInAgain\")}\n </Button>\n ) : null}\n </AlertDescription>\n </Alert>\n );\n}\n\nconst PASSWORD_PROMPT: Record<Purpose, { prompt: MessageKey; submit: MessageKey }> = {\n setUp: { prompt: \"twoFactor.password.setUp\", submit: \"twoFactor.continue\" },\n regenerate: { prompt: \"twoFactor.password.regenerate\", submit: \"twoFactor.regenerateSubmit\" },\n disable: { prompt: \"twoFactor.password.disable\", submit: \"twoFactor.disableSubmit\" },\n};\n\n/** Asks for the current password before a 2FA change. */\nexport function PasswordStep({\n purpose,\n onSubmit,\n onCancel,\n onReauthenticate,\n}: {\n purpose: Purpose;\n onSubmit: (password: string) => Promise<Failure | null>;\n onCancel: () => void;\n onReauthenticate?: (() => void) | undefined;\n}) {\n const id = useId();\n const [password, setPassword] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [failed, setFailed] = useState<Failure | null>(null);\n const { prompt, submit } = PASSWORD_PROMPT[purpose];\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n setSubmitting(true);\n setFailed(null);\n void onSubmit(password).then((result) => {\n setSubmitting(false);\n setFailed(result);\n });\n }}\n >\n <p className=\"text-sm text-muted-foreground\">{t(prompt)}</p>\n {failed === null ? null : <FailureAlert failed={failed} onReauthenticate={onReauthenticate} />}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-password`}>{t(\"twoFactor.password\")}</Label>\n <Input\n id={`${id}-password`}\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n autoFocus\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n }}\n aria-invalid={failed === null ? undefined : true}\n />\n </div>\n <div className=\"flex gap-2\">\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"twoFactor.working\") : t(submit)}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={onCancel}>\n {t(\"twoFactor.cancel\")}\n </Button>\n </div>\n </form>\n );\n}\n\n/** QR code and manual key for the authenticator app, then the first code. */\nexport function VerifyStep({\n totpURI,\n onVerify,\n onCancel,\n}: {\n totpURI: string;\n onVerify: (code: string) => Promise<Failure | null>;\n onCancel: () => void;\n}) {\n const id = useId();\n const [code, setCode] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [failed, setFailed] = useState<Failure | null>(null);\n const qr = useMemo(\n () => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(renderSVG(totpURI, { border: 2 }))}`,\n [totpURI],\n );\n const secret = useMemo(() => new URL(totpURI).searchParams.get(\"secret\") ?? \"\", [totpURI]);\n\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n setSubmitting(true);\n setFailed(null);\n void onVerify(code.trim()).then((result) => {\n setSubmitting(false);\n setFailed(result);\n });\n }}\n >\n <p className=\"text-sm text-muted-foreground\">{t(\"twoFactor.enrol.scan\")}</p>\n <img src={qr} alt={t(\"twoFactor.enrol.qrAlt\")} width={192} height={192} className=\"mx-auto bg-white\" />\n <div className=\"grid gap-1 text-sm\">\n <span className=\"text-muted-foreground\">{t(\"twoFactor.enrol.manual\")}</span>\n <code className=\"break-all font-mono\" data-testid=\"totp-secret\">\n {secret}\n </code>\n </div>\n {failed === null ? null : <FailureAlert failed={failed} />}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-code`}>{t(\"twoFactor.code\")}</Label>\n <Input\n id={`${id}-code`}\n name=\"code\"\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n required\n value={code}\n onChange={(event) => {\n setCode(event.target.value);\n }}\n aria-invalid={failed === null ? undefined : true}\n />\n </div>\n <div className=\"flex gap-2\">\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? t(\"twoFactor.verifying\") : t(\"twoFactor.enrol.submit\")}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={onCancel}>\n {t(\"twoFactor.cancel\")}\n </Button>\n </div>\n </form>\n );\n}\n\nexport function BackupCodesStep({ backupCodes, onDone }: { backupCodes: string[]; onDone: () => void }) {\n return (\n <div className=\"grid gap-4\">\n <p className=\"text-sm text-muted-foreground\">{t(\"twoFactor.backupCodes.description\")}</p>\n <ul aria-label={t(\"twoFactor.backupCodes.list\")} className=\"grid grid-cols-2 gap-2 font-mono text-sm\">\n {backupCodes.map((code) => (\n <li key={code}>{code}</li>\n ))}\n </ul>\n <Button type=\"button\" onClick={onDone}>\n {t(\"twoFactor.backupCodes.done\")}\n </Button>\n </div>\n );\n}\n\nexport function StatusStep({ enabled, onChoose }: { enabled: boolean; onChoose: (purpose: Purpose) => void }) {\n return (\n <div className=\"grid gap-4\">\n <p className=\"text-sm font-medium\">{enabled ? t(\"twoFactor.settings.on\") : t(\"twoFactor.settings.off\")}</p>\n {enabled ? (\n <div className=\"grid gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n onChoose(\"regenerate\");\n }}\n >\n {t(\"twoFactor.settings.regenerate\")}\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n onClick={() => {\n onChoose(\"disable\");\n }}\n >\n {t(\"twoFactor.settings.disable\")}\n </Button>\n </div>\n ) : (\n <>\n <p className=\"text-sm text-muted-foreground\">{t(\"twoFactor.settings.explainer\")}</p>\n <Button\n type=\"button\"\n onClick={() => {\n onChoose(\"setUp\");\n }}\n >\n {t(\"twoFactor.settings.setUp\")}\n </Button>\n </>\n )}\n </div>\n );\n}\n","import type { InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription } from \"@awsmbiz/inbis-ui\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { BackupCodesStep, failure, PasswordStep, StatusStep, VerifyStep, type Purpose } from \"./two-factor-steps.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface TwoFactorSettingsScreenProps {\n client: InbisAuthClient;\n /**\n * Called when a change needs a recent sign-in (`SESSION_NOT_FRESH`) and the\n * user chooses to sign in again, e.g. sign out and navigate to sign-in.\n * Without it, the screen only explains why the change was refused.\n */\n onReauthenticate?: () => void;\n}\n\ntype Step =\n | { kind: \"status\" }\n | { kind: \"password\"; purpose: Purpose }\n | { kind: \"verify\"; totpURI: string; backupCodes: string[] }\n | { kind: \"codes\"; backupCodes: string[] };\n\n/** Loads whether the signed-in user has 2FA on (`null` while loading, `\"error\"` when unknown). */\nfunction useTwoFactorEnabled(client: InbisAuthClient): [boolean | null | \"error\", () => void] {\n const [enabled, setEnabled] = useState<boolean | null | \"error\">(null);\n const [version, setVersion] = useState(0);\n useEffect(() => {\n let active = true;\n client.getSession().then(\n (current) => {\n if (active) setEnabled(current === null ? \"error\" : current.user.twoFactorEnabled);\n },\n () => {\n if (active) setEnabled(\"error\");\n },\n );\n return () => {\n active = false;\n };\n }, [client, version]);\n const reload = useCallback(() => {\n setVersion((v) => v + 1);\n }, []);\n return [enabled, reload];\n}\n\nfunction TwoFactorSettings({ client, onReauthenticate }: TwoFactorSettingsScreenProps) {\n const [enabled, reload] = useTwoFactorEnabled(client);\n const [step, setStep] = useState<Step>({ kind: \"status\" });\n const backToStatus = () => {\n setStep({ kind: \"status\" });\n reload();\n };\n\n if (step.kind === \"codes\") {\n return (\n <Shell title={t(\"twoFactor.backupCodes.title\")}>\n <BackupCodesStep backupCodes={step.backupCodes} onDone={backToStatus} />\n </Shell>\n );\n }\n\n let body;\n if (step.kind === \"password\") {\n const purpose = step.purpose;\n body = (\n <PasswordStep\n key={purpose}\n purpose={purpose}\n onReauthenticate={onReauthenticate}\n onCancel={backToStatus}\n onSubmit={async (password) => {\n if (purpose === \"setUp\") {\n const result = await client.twoFactor.enable({ password });\n if (!result.ok) return failure(result.error);\n setStep({ kind: \"verify\", ...result.data });\n } else if (purpose === \"regenerate\") {\n const result = await client.twoFactor.regenerateBackupCodes({ password });\n if (!result.ok) return failure(result.error);\n setStep({ kind: \"codes\", backupCodes: result.data.backupCodes });\n } else {\n const result = await client.twoFactor.disable({ password });\n if (!result.ok) return failure(result.error);\n backToStatus();\n }\n return null;\n }}\n />\n );\n } else if (step.kind === \"verify\") {\n const { totpURI, backupCodes } = step;\n body = (\n <VerifyStep\n totpURI={totpURI}\n onCancel={backToStatus}\n onVerify={async (code) => {\n const result = await client.twoFactor.verifyTotp({ code });\n if (!result.ok) return failure(result.error.status === 401 ? { ...result.error, code: \"INVALID_CODE\" } : result.error);\n setStep({ kind: \"codes\", backupCodes });\n return null;\n }}\n />\n );\n } else if (enabled === null) {\n body = (\n <p className=\"text-sm text-muted-foreground\" aria-live=\"polite\">\n {t(\"twoFactor.settings.loading\")}\n </p>\n );\n } else if (enabled === \"error\") {\n body = (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertDescription>{t(\"error.generic\")}</AlertDescription>\n </Alert>\n );\n } else {\n body = (\n <StatusStep\n enabled={enabled}\n onChoose={(purpose) => {\n setStep({ kind: \"password\", purpose });\n }}\n />\n );\n }\n\n return <Shell title={t(\"twoFactor.title\")}>{body}</Shell>;\n}\n\n/**\n * Account security: shows whether 2FA is on and lets the signed-in user set up\n * an authenticator app (QR code, verify, backup codes), regenerate the backup\n * codes, or turn 2FA off. Every change asks for the current password, and\n * regenerating or turning off also needs a recent sign-in.\n */\nexport function TwoFactorSettingsScreen(props: TwoFactorSettingsScreenProps) {\n const state = usePublicAuthConfig(props.client);\n return (\n <ConfigGate\n state={state}\n title={t(\"twoFactor.title\")}\n ready={(config) =>\n config.twoFactor === undefined ? (\n <Shell title={t(\"twoFactor.title\")}>\n <p className=\"text-sm text-muted-foreground\">{t(\"twoFactor.settings.unavailable\")}</p>\n </Shell>\n ) : (\n <TwoFactorSettings {...props} />\n )\n }\n />\n );\n}\n","import type { AuthError, InbisAuthClient, PublicAuthConfig } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button, Input, Label } from \"@awsmbiz/inbis-ui\";\nimport { useId, useState } from \"react\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface DeleteAccountScreenProps {\n client: InbisAuthClient;\n /** Called from the confirmation shown after the deletion (the session has ended). */\n onDeleted: () => void;\n /** Called when the user backs out. */\n onCancel: () => void;\n /**\n * Called when deletion needs a recent sign-in (`SESSION_NOT_FRESH`) and the\n * user chooses to sign in again, e.g. sign out and navigate to sign-in.\n */\n onReauthenticate?: () => void;\n}\n\ninterface Failure {\n message: string;\n notFresh: boolean;\n}\n\nfunction failure(error: AuthError): Failure {\n if (error.code === \"SESSION_NOT_FRESH\") return { message: t(\"deleteAccount.notFresh\"), notFresh: true };\n if (error.code === \"NETWORK_ERROR\") return { message: t(\"error.network\"), notFresh: false };\n return { message: t(\"error.generic\"), notFresh: false };\n}\n\nfunction DeleteAccountForm({\n client,\n onDeleted,\n onCancel,\n onReauthenticate,\n config,\n graceDays,\n}: DeleteAccountScreenProps & { config: PublicAuthConfig; graceDays: number }) {\n const id = useId();\n const [confirmation, setConfirmation] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [failed, setFailed] = useState<Failure | null>(null);\n const [done, setDone] = useState<{ deleteAfter: string | null } | null>(null);\n\n if (done !== null) {\n return (\n <div className=\"grid gap-4\">\n <Alert role=\"status\">\n <AlertDescription>\n {done.deleteAfter === null\n ? t(\"deleteAccount.deleted\")\n : t(\"deleteAccount.scheduled\", { date: new Date(done.deleteAfter).toLocaleDateString() })}\n </AlertDescription>\n </Alert>\n <Button type=\"button\" onClick={onDeleted}>\n {t(\"deleteAccount.done\")}\n </Button>\n </div>\n );\n }\n\n async function submit() {\n setSubmitting(true);\n setFailed(null);\n const result = await client.deleteAccount();\n setSubmitting(false);\n if (result.ok) setDone(result.data);\n else setFailed(failure(result.error));\n }\n\n const appName = config.app.name;\n return (\n <form\n className=\"grid gap-4\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <p className=\"text-sm text-muted-foreground\">\n {graceDays === 0\n ? t(\"deleteAccount.warning\", { appName })\n : t(\"deleteAccount.warningGrace\", { appName, graceDays: String(graceDays) })}\n </p>\n {failed === null ? null : (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"deleteAccount.failed\")}</AlertTitle>\n <AlertDescription>\n {failed.message}\n {failed.notFresh && onReauthenticate !== undefined ? (\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onReauthenticate}>\n {t(\"deleteAccount.signInAgain\")}\n </Button>\n ) : null}\n </AlertDescription>\n </Alert>\n )}\n <div className=\"grid gap-2\">\n <Label htmlFor={`${id}-confirm`}>{t(\"deleteAccount.confirmLabel\")}</Label>\n <Input\n id={`${id}-confirm`}\n name=\"confirm\"\n autoComplete=\"off\"\n required\n value={confirmation}\n onChange={(event) => {\n setConfirmation(event.target.value);\n }}\n />\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"submit\"\n variant=\"destructive\"\n disabled={submitting || confirmation.trim() !== t(\"deleteAccount.confirmWord\")}\n >\n {submitting ? t(\"deleteAccount.submitting\") : t(\"deleteAccount.submit\")}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={onCancel}>\n {t(\"deleteAccount.cancel\")}\n </Button>\n </div>\n </form>\n );\n}\n\n/**\n * Lets the signed-in user delete their account, when the server's public\n * config allows it. The user confirms by typing a word; the server also\n * requires a recent sign-in and offers \"sign in again\" when it is not.\n */\nexport function DeleteAccountScreen(props: DeleteAccountScreenProps) {\n const state = usePublicAuthConfig(props.client);\n return (\n <ConfigGate\n state={state}\n title={t(\"deleteAccount.title\")}\n ready={(config) => (\n <Shell title={t(\"deleteAccount.title\")}>\n {config.accountDeletion === undefined ? (\n <p className=\"text-sm text-muted-foreground\">{t(\"deleteAccount.unavailable\", { appName: config.app.name })}</p>\n ) : (\n <DeleteAccountForm {...props} config={config} graceDays={config.accountDeletion.graceDays} />\n )}\n </Shell>\n )}\n />\n );\n}\n","import type { AuthError, ClientSessionSummary, InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, AlertTitle, Button } from \"@awsmbiz/inbis-ui\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { t } from \"./messages.js\";\nimport { ConfigGate, Shell } from \"./shell.js\";\nimport { usePublicAuthConfig } from \"./use-public-auth-config.js\";\n\nexport interface SessionsScreenProps {\n client: InbisAuthClient;\n /**\n * Called when signing a session out needs a recent sign-in\n * (`SESSION_NOT_FRESH`) and the user chooses to sign in again, e.g. sign out\n * and navigate to sign-in. Without it, the screen only explains why.\n */\n onReauthenticate?: () => void;\n}\n\ninterface Failure {\n message: string;\n notFresh: boolean;\n}\n\nfunction failure(error: AuthError): Failure {\n if (error.code === \"SESSION_NOT_FRESH\") return { message: t(\"sessions.notFresh\"), notFresh: true };\n if (error.code === \"SESSION_NOT_FOUND\") return { message: t(\"sessions.notFound\"), notFresh: false };\n if (error.code === \"NETWORK_ERROR\") return { message: t(\"error.network\"), notFresh: false };\n return { message: t(\"error.generic\"), notFresh: false };\n}\n\ntype Loaded = { status: \"loading\" } | { status: \"error\" } | { status: \"ready\"; sessions: ClientSessionSummary[] };\n\nfunction useSessions(client: InbisAuthClient): [Loaded, () => void] {\n const [loaded, setLoaded] = useState<Loaded>({ status: \"loading\" });\n const [version, setVersion] = useState(0);\n useEffect(() => {\n let active = true;\n void client.sessions.list().then((result) => {\n if (active) setLoaded(result.ok ? { status: \"ready\", sessions: result.data } : { status: \"error\" });\n });\n return () => {\n active = false;\n };\n }, [client, version]);\n const reload = useCallback(() => {\n setVersion((v) => v + 1);\n }, []);\n return [loaded, reload];\n}\n\nfunction SessionItem({\n session,\n busy,\n onRevoke,\n}: {\n session: ClientSessionSummary;\n busy: boolean;\n onRevoke: () => void;\n}) {\n return (\n <li className=\"flex items-start justify-between gap-2 py-3\">\n <div className=\"grid min-w-0 gap-0.5 text-sm\">\n <span className=\"truncate font-medium\">{session.userAgent ?? t(\"sessions.unknownDevice\")}</span>\n <span className=\"text-muted-foreground\">\n {t(\"sessions.signedInAt\", { date: new Date(session.createdAt).toLocaleString() })}\n {session.ipAddress === null ? \"\" : ` · ${session.ipAddress}`}\n </span>\n {session.current ? <span className=\"text-xs font-medium\">{t(\"sessions.thisDevice\")}</span> : null}\n </div>\n {session.current ? null : (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={busy} onClick={onRevoke}>\n {t(\"sessions.revoke\")}\n </Button>\n )}\n </li>\n );\n}\n\nfunction SessionList({ client, onReauthenticate }: SessionsScreenProps) {\n const [loaded, reload] = useSessions(client);\n const [busy, setBusy] = useState(false);\n const [failed, setFailed] = useState<Failure | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n\n async function run(action: () => Promise<{ ok: true; notice?: string } | { ok: false; error: AuthError }>) {\n setBusy(true);\n setFailed(null);\n setNotice(null);\n const result = await action();\n setBusy(false);\n if (result.ok) {\n setNotice(result.notice ?? null);\n reload();\n } else setFailed(failure(result.error));\n }\n\n const revoke = (sessionId: string) =>\n run(async () => {\n const result = await client.sessions.revoke({ sessionId });\n return result.ok ? { ok: true } : result;\n });\n const revokeOthers = () =>\n run(async () => {\n const result = await client.sessions.revokeOthers();\n return result.ok ? { ok: true, notice: t(\"sessions.othersRevoked\", { count: String(result.data.revoked) }) } : result;\n });\n\n if (loaded.status === \"loading\") {\n return (\n <p className=\"text-sm text-muted-foreground\" aria-live=\"polite\">\n {t(\"sessions.loading\")}\n </p>\n );\n }\n if (loaded.status === \"error\") {\n return (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertDescription>{t(\"sessions.loadFailed\")}</AlertDescription>\n </Alert>\n );\n }\n const hasOthers = loaded.sessions.some((session) => !session.current);\n return (\n <div className=\"grid gap-4\">\n {notice === null ? null : (\n <Alert role=\"status\">\n <AlertDescription>{notice}</AlertDescription>\n </Alert>\n )}\n {failed === null ? null : (\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertTitle>{t(\"sessions.failed\")}</AlertTitle>\n <AlertDescription>\n {failed.message}\n {failed.notFresh && onReauthenticate !== undefined ? (\n <Button type=\"button\" variant=\"link\" className=\"h-auto p-0\" onClick={onReauthenticate}>\n {t(\"sessions.signInAgain\")}\n </Button>\n ) : null}\n </AlertDescription>\n </Alert>\n )}\n <ul className=\"divide-y\" aria-label={t(\"sessions.title\")}>\n {loaded.sessions.map((session) => (\n <SessionItem key={session.id} session={session} busy={busy} onRevoke={() => void revoke(session.id)} />\n ))}\n </ul>\n {hasOthers ? (\n <Button type=\"button\" variant=\"destructive\" disabled={busy} onClick={() => void revokeOthers()}>\n {t(\"sessions.revokeOthers\")}\n </Button>\n ) : null}\n </div>\n );\n}\n\n/**\n * The signed-in user's sessions: where and when each one signed in, which one\n * is this device, \"Sign out\" for each other session and \"Sign out all other\n * sessions\". Signing out other sessions needs a recent sign-in; on\n * `SESSION_NOT_FRESH` the screen explains why and offers \"Sign in again\".\n */\nexport function SessionsScreen(props: SessionsScreenProps) {\n const state = usePublicAuthConfig(props.client);\n return (\n <ConfigGate\n state={state}\n title={t(\"sessions.title\")}\n ready={() => (\n <Shell title={t(\"sessions.title\")} description={t(\"sessions.description\")}>\n <SessionList {...props} />\n </Shell>\n )}\n />\n );\n}\n","import type { AccessRequirement, InbisAuthClient } from \"@awsmbiz/inbis-auth/client\";\nimport { Alert, AlertDescription, Button } from \"@awsmbiz/inbis-ui\";\nimport { useEffect, useState } from \"react\";\nimport { t, type MessageKey } from \"./messages.js\";\nimport { Shell } from \"./shell.js\";\nimport { BackupCodesStep, failure, PasswordStep, VerifyStep } from \"./two-factor-steps.js\";\n\nexport interface StepUpScreenProps {\n client: InbisAuthClient;\n /** What the protected route answered, from `accessRequirementOf(response)`. */\n requirement: AccessRequirement;\n /**\n * Called once the current session satisfies the requirement (after setting\n * up 2FA, which verifies the session): retry the protected page.\n */\n onSatisfied: () => void;\n /** Sign out and go to sign-in, where the next sign-in meets the policy. */\n onSignInAgain: () => void;\n}\n\nconst METHOD_LABELS: Record<string, MessageKey> = {\n password: \"stepUp.method.password\",\n \"phone-otp\": \"stepUp.method.phoneOtp\",\n};\n\nfunction methodsText(methods: string[]): string {\n const labels = [...new Set(methods.map((method) => t(METHOD_LABELS[method] ?? \"stepUp.method.other\")))];\n return labels.length === 0 ? t(\"stepUp.method.other\") : labels.join(\" or \");\n}\n\nfunction SignInAgain({ title, description, onSignInAgain }: { title: string; description: string; onSignInAgain: () => void }) {\n return (\n <Shell title={title} description={description}>\n <Button type=\"button\" className=\"w-full\" onClick={onSignInAgain}>\n {t(\"stepUp.signInAgain\")}\n </Button>\n </Shell>\n );\n}\n\ntype Step = { kind: \"password\" } | { kind: \"verify\"; totpURI: string; backupCodes: string[] } | { kind: \"codes\"; backupCodes: string[] };\n\n/** 2FA set-up for a signed-in user who has none yet: password, QR code and first code, backup codes. */\nfunction SetUpTwoFactor({ client, onSatisfied, onSignInAgain }: Omit<StepUpScreenProps, \"requirement\">) {\n const [step, setStep] = useState<Step>({ kind: \"password\" });\n const title = t(\"stepUp.setUp.title\");\n if (step.kind === \"codes\") {\n return (\n <Shell title={t(\"twoFactor.backupCodes.title\")}>\n <BackupCodesStep backupCodes={step.backupCodes} onDone={onSatisfied} />\n </Shell>\n );\n }\n if (step.kind === \"verify\") {\n const { totpURI, backupCodes } = step;\n return (\n <Shell title={title}>\n <VerifyStep\n totpURI={totpURI}\n onCancel={onSignInAgain}\n onVerify={async (code) => {\n const result = await client.twoFactor.verifyTotp({ code });\n if (!result.ok) return failure(result.error.status === 401 ? { ...result.error, code: \"INVALID_CODE\" } : result.error);\n setStep({ kind: \"codes\", backupCodes });\n return null;\n }}\n />\n </Shell>\n );\n }\n return (\n <Shell title={title} description={t(\"stepUp.setUp.description\")}>\n <PasswordStep\n purpose=\"setUp\"\n onCancel={onSignInAgain}\n onSubmit={async (password) => {\n const result = await client.twoFactor.enable({ password });\n if (!result.ok) return failure(result.error);\n setStep({ kind: \"verify\", ...result.data });\n return null;\n }}\n />\n </Shell>\n );\n}\n\n/**\n * Shown instead of a protected page that answered `403 TWO_FACTOR_REQUIRED`\n * or `403 STEP_UP_REQUIRED` (ADR-3), so the page's content never renders:\n * - 2FA required, none set up: sets up an authenticator app here (enrolment\n * verifies the session), then `onSatisfied()`.\n * - 2FA required, already set up: explains, and offers \"Sign in again\"\n * (password, then the authenticator code).\n * - Step-up: names the allowed methods and offers \"Sign in again\".\n */\nexport function StepUpScreen({ client, requirement, onSatisfied, onSignInAgain }: StepUpScreenProps) {\n const [enrolled, setEnrolled] = useState<boolean | null | \"error\">(null);\n const needsTwoFactor = requirement.kind === \"two-factor\";\n useEffect(() => {\n if (!needsTwoFactor) return;\n let active = true;\n client.getSession().then(\n (current) => {\n if (active) setEnrolled(current === null ? \"error\" : current.user.twoFactorEnabled);\n },\n () => {\n if (active) setEnrolled(\"error\");\n },\n );\n return () => {\n active = false;\n };\n }, [client, needsTwoFactor]);\n\n if (requirement.kind === \"step-up\") {\n return (\n <SignInAgain\n title={t(\"stepUp.method.title\")}\n description={t(\"stepUp.method.description\", { methods: methodsText(requirement.allowedMethods) })}\n onSignInAgain={onSignInAgain}\n />\n );\n }\n if (enrolled === null) {\n return (\n <Shell title={t(\"stepUp.verify.title\")}>\n <p className=\"text-sm text-muted-foreground\" aria-live=\"polite\">\n {t(\"twoFactor.settings.loading\")}\n </p>\n </Shell>\n );\n }\n if (enrolled === \"error\") {\n return (\n <Shell title={t(\"stepUp.verify.title\")}>\n <Alert variant=\"destructive\" role=\"alert\">\n <AlertDescription>{t(\"error.generic\")}</AlertDescription>\n </Alert>\n </Shell>\n );\n }\n if (enrolled) {\n return (\n <SignInAgain title={t(\"stepUp.verify.title\")} description={t(\"stepUp.verify.description\")} onSignInAgain={onSignInAgain} />\n );\n }\n return <SetUpTwoFactor client={client} onSatisfied={onSatisfied} onSignInAgain={onSignInAgain} />;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "@awsmbiz/inbis-auth-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "React authentication screens for Inbis apps, driven by the server's public auth config.",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/awsmbiz/inbis-platform.git",
9
+ "directory": "packages/auth-ui"
10
+ },
11
+ "publishConfig": {
12
+ "registry": "https://registry.npmjs.org/",
13
+ "access": "public"
14
+ },
15
+ "type": "module",
16
+ "sideEffects": [
17
+ "**/*.css"
18
+ ],
19
+ "files": [
20
+ "dist",
21
+ "styles"
22
+ ],
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "./styles.css": "./styles/styles.css",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "dependencies": {
32
+ "@awsmbiz/inbis-auth": "0.2.0",
33
+ "@awsmbiz/inbis-ui": "0.2.0",
34
+ "uqr": "0.1.3"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^19.3.1",
38
+ "react-dom": "^19.3.1"
39
+ },
40
+ "devDependencies": {
41
+ "@arethetypeswrong/cli": "0.18.5",
42
+ "@awsmbiz/inbis-eslint-config": "0.2.0",
43
+ "@awsmbiz/inbis-tsconfig": "0.2.0",
44
+ "@types/react": "19.3.0",
45
+ "@types/react-dom": "19.3.0",
46
+ "eslint": "10.14.0",
47
+ "publint": "0.3.25",
48
+ "react": "19.3.1",
49
+ "react-dom": "19.3.1",
50
+ "tsdown": "0.23.4",
51
+ "typescript": "6.0.3"
52
+ },
53
+ "scripts": {
54
+ "build": "tsdown",
55
+ "typecheck": "tsc",
56
+ "lint": "eslint . --max-warnings 0",
57
+ "check:exports": "publint --strict && attw --pack . --profile esm-only --exclude-entrypoints styles.css"
58
+ }
6
59
  }
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Lets Tailwind see the classes @awsmbiz/inbis-auth-ui's compiled screens use.
3
+ * Import after "@awsmbiz/inbis-ui/globals.css" in the app's stylesheet:
4
+ * @import "@awsmbiz/inbis-ui/globals.css";
5
+ * @import "@awsmbiz/inbis-auth-ui/styles.css";
6
+ */
7
+ @source "../dist";