@lalternative/auth 0.9.0 → 0.9.1
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.
- package/dist/client.d.ts +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/{invitation-D0TAHCHq.d.ts → invitation-0CfjrVjI.d.ts} +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/{types-8GKMVW7c.d.ts → types-DzG-qaSv.d.ts} +11 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAuthClient } from 'better-auth/react';
|
|
2
|
-
import { d as AuthClientSurface, P as PlatformAuthClientConfig } from './types-
|
|
2
|
+
import { d as AuthClientSurface, P as PlatformAuthClientConfig } from './types-DzG-qaSv.js';
|
|
3
3
|
import 'better-auth';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { L as LoginFormProps, R as RegisterFormProps, V as VerifyEmailFormProps, F as ForgotPasswordFormProps, a as ResetPasswordFormProps, A as AuthLayoutProps, I as InvitationNoticeProps, b as LinkComponent } from './types-
|
|
2
|
-
export {
|
|
1
|
+
import { L as LoginFormProps, R as RegisterFormProps, V as VerifyEmailFormProps, F as ForgotPasswordFormProps, a as ResetPasswordFormProps, A as AuthLayoutProps, I as InvitationNoticeProps, b as AuthClientResult, c as LinkComponent } from './types-DzG-qaSv.js';
|
|
2
|
+
export { d as AuthClientSurface, e as AuthInviteProps, f as AuthNavProps, g as AuthThemeProps, h as InvitationFailure, i as LoginFormLabels, P as PlatformAuthClientConfig, j as PlatformAuthConfig, k as PlatformAuthMailer, l as PlatformAuthMailerArgs, m as PlatformAuthMailerType, n as PlatformSession, o as PlatformSessionData, p as PlatformUser, q as RegisterFormLabels } from './types-DzG-qaSv.js';
|
|
3
3
|
import * as better_auth_react from 'better-auth/react';
|
|
4
4
|
import * as better_auth from 'better-auth';
|
|
5
5
|
import { PlatformAuthClient } from './client.js';
|
|
6
6
|
import * as react from 'react';
|
|
7
7
|
import { InputHTMLAttributes, ReactNode } from 'react';
|
|
8
|
-
export { C as ClaimOutcome, i as isInvitationFailure } from './invitation-
|
|
8
|
+
export { C as ClaimOutcome, i as isInvitationFailure } from './invitation-0CfjrVjI.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Returns a useSession hook bound to the given auth client.
|
|
@@ -101,7 +101,7 @@ interface AuthSubmitProps {
|
|
|
101
101
|
*/
|
|
102
102
|
declare function AuthSubmit({ pending, disabled, pendingLabel, children, className, spacedAbove, }: AuthSubmitProps): react.JSX.Element;
|
|
103
103
|
|
|
104
|
-
declare function LoginForm({ onSuccess, registerUrl, forgotPasswordUrl, socialCallbackUrl, socialProviders, coreTokenUrl, labels, submitClassName, fieldClassName, error: externalError, linkComponent, invite, authClient, }: LoginFormProps): react.JSX.Element;
|
|
104
|
+
declare function LoginForm({ onSuccess, onEmailNotVerified, registerUrl, forgotPasswordUrl, socialCallbackUrl, socialProviders, coreTokenUrl, labels, submitClassName, fieldClassName, error: externalError, linkComponent, invite, authClient, }: LoginFormProps): react.JSX.Element;
|
|
105
105
|
declare namespace LoginForm {
|
|
106
106
|
var defaults: {
|
|
107
107
|
title: string;
|
|
@@ -202,6 +202,16 @@ declare function normalizeInviteToken(value: unknown): string | undefined;
|
|
|
202
202
|
*/
|
|
203
203
|
declare function withInviteToken(href: string, token?: string): string;
|
|
204
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Whether a failed sign-in was refused for want of a confirmed address.
|
|
207
|
+
*
|
|
208
|
+
* Better Auth answers an unverified sign-in with EMAIL_NOT_VERIFIED, but only
|
|
209
|
+
* when built with its error codes exposed; otherwise the refusal arrives as a
|
|
210
|
+
* bare 403. No other credential failure on this route uses that status — a
|
|
211
|
+
* wrong password is a 401 — so the status alone is a safe fallback.
|
|
212
|
+
*/
|
|
213
|
+
declare function isEmailNotVerified(error: AuthClientResult["error"]): boolean;
|
|
214
|
+
|
|
205
215
|
type OAuthErrorLabels = {
|
|
206
216
|
accountNotLinked: string;
|
|
207
217
|
socialCancelled: string;
|
|
@@ -254,4 +264,4 @@ interface AuthLinkProps {
|
|
|
254
264
|
*/
|
|
255
265
|
declare function AuthLink({ to, as: Link, className, children }: AuthLinkProps): react.JSX.Element;
|
|
256
266
|
|
|
257
|
-
export { AuthField, type AuthFieldProps, AuthLayout, AuthLayoutProps, AuthLink, AuthSubmit, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, LinkComponent, LoginForm, LoginFormProps, type OAuthErrorLabels, RegisterForm, RegisterFormProps, ResetPasswordForm, ResetPasswordFormProps, SocialButtons, VerifyEmailForm, VerifyEmailFormProps, clearOAuthError, initialOAuthError, normalizeInviteToken, oauthErrorMessage, useLogout, useSession, withInviteToken };
|
|
267
|
+
export { AuthClientResult, AuthField, type AuthFieldProps, AuthLayout, AuthLayoutProps, AuthLink, AuthSubmit, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, LinkComponent, LoginForm, LoginFormProps, type OAuthErrorLabels, RegisterForm, RegisterFormProps, ResetPasswordForm, ResetPasswordFormProps, SocialButtons, VerifyEmailForm, VerifyEmailFormProps, clearOAuthError, initialOAuthError, isEmailNotVerified, normalizeInviteToken, oauthErrorMessage, useLogout, useSession, withInviteToken };
|
package/dist/index.js
CHANGED
|
@@ -150,6 +150,12 @@ function AuthSubmit({
|
|
|
150
150
|
// src/components/login-form.tsx
|
|
151
151
|
import { useState as useState2 } from "react";
|
|
152
152
|
|
|
153
|
+
// src/email-not-verified.ts
|
|
154
|
+
function isEmailNotVerified(error) {
|
|
155
|
+
if (!error) return false;
|
|
156
|
+
return error.code === "EMAIL_NOT_VERIFIED" || error.status === 403;
|
|
157
|
+
}
|
|
158
|
+
|
|
153
159
|
// src/components/auth-alert.tsx
|
|
154
160
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
155
161
|
function AuthAlert({ children, tone = "error" }) {
|
|
@@ -294,6 +300,7 @@ var DEFAULTS = {
|
|
|
294
300
|
emailRequired: "Renseigne ton adresse e-mail",
|
|
295
301
|
passwordRequired: "Renseigne ton mot de passe",
|
|
296
302
|
invalidCredentials: "Adresse e-mail ou mot de passe incorrect",
|
|
303
|
+
emailNotVerified: "Ton adresse e-mail n'est pas encore confirm\xE9e. V\xE9rifie ta bo\xEEte de r\xE9ception.",
|
|
297
304
|
// accountLinking is disabled in createPlatformAuth, so a social sign-in on an
|
|
298
305
|
// address already registered with a password is refused with this code.
|
|
299
306
|
// Without a message the button reads as broken rather than as a rejection.
|
|
@@ -303,6 +310,7 @@ var DEFAULTS = {
|
|
|
303
310
|
};
|
|
304
311
|
function LoginForm({
|
|
305
312
|
onSuccess,
|
|
313
|
+
onEmailNotVerified,
|
|
306
314
|
registerUrl = "/register",
|
|
307
315
|
forgotPasswordUrl = "/forgot-password",
|
|
308
316
|
socialCallbackUrl = "/",
|
|
@@ -341,7 +349,13 @@ function LoginForm({
|
|
|
341
349
|
password
|
|
342
350
|
});
|
|
343
351
|
if (res?.error) {
|
|
344
|
-
|
|
352
|
+
if (isEmailNotVerified(res.error) && onEmailNotVerified) {
|
|
353
|
+
onEmailNotVerified(email.trim());
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
setError(
|
|
357
|
+
isEmailNotVerified(res.error) ? t.emailNotVerified : res.error.message ?? t.invalidCredentials
|
|
358
|
+
);
|
|
345
359
|
return;
|
|
346
360
|
}
|
|
347
361
|
if (coreTokenUrl) {
|
|
@@ -1271,6 +1285,7 @@ export {
|
|
|
1271
1285
|
VerifyEmailForm,
|
|
1272
1286
|
clearOAuthError,
|
|
1273
1287
|
initialOAuthError,
|
|
1288
|
+
isEmailNotVerified,
|
|
1274
1289
|
isInvitationFailure,
|
|
1275
1290
|
normalizeInviteToken,
|
|
1276
1291
|
oauthErrorMessage,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/auth-field.tsx","../src/components/auth-submit.tsx","../src/components/login-form.tsx","../src/components/auth-alert.tsx","../src/components/social-buttons.tsx","../src/components/auth-link.tsx","../src/invite-token.ts","../src/components/register-form.tsx","../src/components/verify-email-form.tsx","../src/components/auth-otp-field.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-heading.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx","../src/oauth-error.ts"],"sourcesContent":["import type { PlatformAuthClient } from \"../client\"\n\n/**\n * Returns a useSession hook bound to the given auth client.\n * Usage: const { data: session, isPending } = useSession(authClient)\n */\nexport function useSession(authClient: PlatformAuthClient) {\n return authClient.useSession()\n}\n\n/**\n * Returns a logout function bound to the given auth client.\n * Usage: const logout = useLogout(authClient)\n */\nexport function useLogout(authClient: PlatformAuthClient) {\n const signOut = async () => {\n await authClient.signOut()\n }\n return signOut\n}\n","import { useId, useState, type InputHTMLAttributes, type ReactNode } from \"react\"\n\ntype NativeProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"id\" | \"className\">\n\nexport interface AuthFieldProps extends NativeProps {\n label: string\n /** Rendered on the right of the label row — typically a \"forgot password\" link */\n hint?: ReactNode\n /** Persistent helper text under the field, tied to it for screen readers */\n description?: string\n invalid?: boolean\n /** Replaces the default border and background utilities */\n fieldClassName?: string\n}\n\n/**\n * A single credential field.\n *\n * The label is a real <label>, always visible, never a placeholder standing in\n * for one: a placeholder disappears the moment someone types, which is exactly\n * when a person double-checking a long password needs to know what the box is.\n *\n * Touch targets are 52px tall on mobile and 44px from sm up. Below ~48px,\n * thumbs miss; on a pointer device the same height reads as oversized, so the\n * two are not one compromise value.\n *\n * The focus ring is a ring rather than an outline so it follows the rounded\n * corners exactly, and the border darkens at the same time — the border is what\n * survives forced-colors mode, where the ring is dropped.\n */\nexport function AuthField({\n label,\n hint,\n description,\n invalid = false,\n fieldClassName = \"border-foreground/30 bg-background\",\n ...props\n}: AuthFieldProps) {\n const id = useId()\n const descriptionId = description ? `${id}-description` : undefined\n const [revealed, setRevealed] = useState(false)\n\n const isPassword = props.type === \"password\"\n const type = isPassword && revealed ? \"text\" : props.type\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-baseline justify-between gap-3\">\n {/* Small caps with wide tracking: at this size the label reads as a\n field marker rather than as prose competing with the heading. */}\n <label\n htmlFor={id}\n className=\"text-[0.6875rem] font-semibold uppercase leading-none tracking-[0.09em] text-foreground/70\"\n >\n {label}\n </label>\n {hint}\n </div>\n\n <div className=\"relative\">\n <input\n {...props}\n id={id}\n type={type}\n aria-invalid={invalid || undefined}\n aria-describedby={descriptionId}\n className={[\n \"h-[52px] w-full rounded-md border px-3.5 text-base\",\n \"sm:h-[46px] sm:text-[0.9375rem]\",\n isPassword ? \"pr-12\" : \"\",\n \"text-foreground placeholder:text-muted-foreground/60\",\n // Focus reads as the border committing rather than as a halo\n // appearing beside it: the ring is tight and the border darkens to\n // full ink in the same 180ms, so the field answers the caret.\n \"transition-[border-color,box-shadow] duration-200 ease-out\",\n \"focus-visible:outline-none focus-visible:ring-2\",\n invalid\n ? \"border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/15\"\n // The default border is foreground/30, not border-input: the\n // latter against a white card lands near 1.3:1, well under the\n // 3:1 WCAG 1.4.11 asks of a control's boundary — the field reads\n // as a faint tint rather than as something to type in.\n : `${fieldClassName} focus-visible:border-foreground focus-visible:ring-foreground/10`,\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n ]\n .filter(Boolean)\n .join(\" \")}\n />\n\n {isPassword && (\n <button\n type=\"button\"\n onClick={() => setRevealed((v) => !v)}\n disabled={props.disabled}\n aria-pressed={revealed}\n aria-label={\n revealed ? \"Masquer le mot de passe\" : \"Afficher le mot de passe\"\n }\n className=\"absolute inset-y-0 right-0 flex w-12 items-center justify-center rounded-r-xl text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60\"\n >\n <EyeIcon open={revealed} />\n </button>\n )}\n </div>\n\n {description && (\n <p id={descriptionId} className=\"text-xs text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n )\n}\n\n// Inline rather than from lucide-react: the package would gain a dependency\n// consumers already have at a different version, for two paths.\nfunction EyeIcon({ open }: { open: boolean }) {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n {!open && <path d=\"m3 3 18 18\" />}\n </svg>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthSubmitProps {\n pending?: boolean\n disabled?: boolean\n pendingLabel: string\n children: ReactNode\n /** Replaces the default `bg-primary text-primary-foreground hover:bg-primary/90` */\n className?: string\n /**\n * Adds the step that detaches the action from the fields above it. The\n * inputs sit on a tighter rhythm so they read as one block to fill in; the\n * button is what you do once that block is done, and an even gap would put\n * it on the same footing as another field.\n */\n spacedAbove?: boolean\n}\n\n/**\n * The primary action of an auth screen.\n *\n * The label swaps to its pending form in place, with the spinner absolutely\n * positioned: a spinner inserted into the flow would widen the row and shift\n * the text sideways at the exact moment the person is watching it.\n *\n * The press feedback is a 1px translate rather than a scale — scaling a\n * full-width button visibly blurs its text mid-transform.\n */\nexport function AuthSubmit({\n pending = false,\n disabled = false,\n pendingLabel,\n children,\n className = \"bg-primary text-primary-foreground hover:bg-primary/90\",\n spacedAbove = false,\n}: AuthSubmitProps) {\n return (\n <button\n type=\"submit\"\n disabled={disabled || pending}\n aria-busy={pending || undefined}\n className={[\n spacedAbove ? \"!mt-7\" : \"\",\n \"relative flex h-[52px] w-full items-center justify-center rounded-md sm:h-[46px]\",\n // Slightly tracked at this weight: a wide solid button set in plain\n // medium reads as a slab, and the letterspacing is what makes it read\n // as typeset rather than filled in.\n \"text-[0.9375rem] font-medium tracking-[0.01em]\",\n className,\n \"transition-[background-color,transform,box-shadow] duration-200 ease-out\",\n \"shadow-[0_1px_2px_rgba(0,0,0,0.08)] hover:shadow-[0_2px_8px_rgba(0,0,0,0.12)]\",\n \"active:translate-y-px active:shadow-[0_1px_2px_rgba(0,0,0,0.08)]\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n {pending && (\n <span\n aria-hidden=\"true\"\n className=\"absolute left-4 size-4 animate-spin rounded-full border-2 border-current border-t-transparent opacity-70 motion-reduce:animate-none\"\n />\n )}\n {pending ? pendingLabel : children}\n </button>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { LoginFormLabels, LoginFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\nimport { AUTH_HINT_LINK_CLASS, AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport { withInviteToken } from \"../invite-token\"\n\nconst DEFAULTS: Required<LoginFormLabels> = {\n title: \"Connexion\",\n subtitle: \"Content de te revoir. Entre tes identifiants pour continuer.\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n forgotPassword: \"Mot de passe oublié ?\",\n submit: \"Se connecter\",\n submitPending: \"Connexion…\",\n noAccount: \"Pas encore de compte ?\",\n register: \"Créer un compte\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordRequired: \"Renseigne ton mot de passe\",\n invalidCredentials: \"Adresse e-mail ou mot de passe incorrect\",\n // accountLinking is disabled in createPlatformAuth, so a social sign-in on an\n // address already registered with a password is refused with this code.\n // Without a message the button reads as broken rather than as a rejection.\n accountNotLinked:\n \"Cette adresse est déjà associée à un mot de passe. Connecte-toi avec ton mot de passe.\",\n socialCancelled: \"Connexion annulée.\",\n socialFailed: \"La connexion a échoué. Réessaie.\",\n}\n\nexport function LoginForm({\n onSuccess,\n registerUrl = \"/register\",\n forgotPasswordUrl = \"/forgot-password\",\n socialCallbackUrl = \"/\",\n socialProviders = [],\n coreTokenUrl = \"/api/auth/core-token\",\n labels,\n submitClassName,\n fieldClassName,\n error: externalError,\n linkComponent,\n invite,\n authClient,\n}: LoginFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [ownError, setOwnError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n // What the person just did outranks what happened before they arrived.\n const error = ownError ?? externalError\n const setError = setOwnError\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (!password) {\n setError(t.passwordRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signIn.email({\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.invalidCredentials)\n return\n }\n // The better-auth session cookie alone does not authenticate a Go core:\n // it verifies the EdDSA JWT minted here against the issuer's JWKS.\n // Skipped when the app sets the token itself, or has no core at all.\n if (coreTokenUrl) {\n await fetch(coreTokenUrl, { credentials: \"include\" })\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCredentials)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n // The invitation rides the callback: an OAuth sign-up leaves the\n // browser, and the auth handler redeems the token on the way back.\n callbackURL: withInviteToken(socialCallbackUrl, invite),\n })\n } catch (err) {\n const code = err instanceof Error ? err.message : \"\"\n setError(\n code === \"account_not_linked\"\n ? t.accountNotLinked\n : code === \"access_denied\"\n ? t.socialCancelled\n : t.socialFailed,\n )\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n invalid={!!error}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"current-password\"\n invalid={!!error}\n fieldClassName={fieldClassName}\n hint={\n <AuthLink\n to={forgotPasswordUrl}\n as={linkComponent}\n className={AUTH_HINT_LINK_CLASS}\n >\n {t.forgotPassword}\n </AuthLink>\n }\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n disabled={!email.trim() || !password}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.noAccount}{\" \"}\n <AuthLink\n to={withInviteToken(registerUrl, invite)}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.register}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// The heading lives in AuthLayout, above the card, so the screen — not the\n// form — passes the copy. Exposing the defaults here keeps the wording in one\n// place: `<AuthLayout {...LoginForm.defaults}>` renders what the form used to.\nLoginForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","interface AuthAlertProps {\n children?: string\n tone?: \"error\" | \"success\"\n}\n\n/**\n * Inline feedback for an auth screen.\n *\n * `role=\"alert\"` on the wrapper is not enough on its own: the node has to be\n * in the tree before the text lands in it for the live region to fire, which\n * is why the element renders empty rather than being mounted with its message.\n *\n * The success tone uses the theme's own tokens rather than a fixed green,\n * which would sit on a dark surface as an unreadable pale block.\n */\nexport function AuthAlert({ children, tone = \"error\" }: AuthAlertProps) {\n return (\n <div\n role={tone === \"error\" ? \"alert\" : \"status\"}\n aria-live={tone === \"error\" ? \"assertive\" : \"polite\"}\n className={\n children\n ? [\n \"rounded-lg border px-3.5 py-3 text-sm leading-snug\",\n tone === \"error\"\n ? \"border-destructive/25 bg-destructive/10 text-destructive\"\n : \"border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400\",\n ].join(\" \")\n : undefined\n }\n >\n {children}\n </div>\n )\n}\n","const LABELS: Record<string, string> = {\n google: \"Continuer avec Google\",\n github: \"Continuer avec GitHub\",\n}\n\ninterface SocialButtonsProps {\n providers: Array<\"google\" | \"github\">\n onSelect: (provider: \"google\" | \"github\") => void | Promise<void>\n disabled?: boolean\n /** Divider text between the password form and the providers */\n separator?: string\n /** Per-provider button copy, merged over the French defaults */\n labels?: Partial<Record<\"google\" | \"github\", string>>\n}\n\nexport function SocialButtons({\n providers,\n onSelect,\n disabled = false,\n separator = \"ou\",\n labels,\n}: SocialButtonsProps) {\n if (providers.length === 0) return null\n\n const copy = { ...LABELS, ...labels }\n\n return (\n <div className=\"space-y-4\">\n {/* The rule is two flex segments rather than a line behind an opaque\n label: an opaque background only hides the rule when it matches the\n surface behind it, which breaks the moment this sits on a card. */}\n <div aria-hidden=\"true\" className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border\" />\n <span className=\"text-[11px] uppercase tracking-[0.14em] text-muted-foreground\">\n {separator}\n </span>\n <span className=\"h-px flex-1 bg-border\" />\n </div>\n\n {/* One per row while there is space for the wording, side by side once\n there are several: in a half-card the full label no longer fits, and\n a truncated \"Continuer avec…\" says less than the mark alone. The\n wording stays as the accessible name either way. */}\n <div\n className={\n providers.length > 1\n ? \"grid gap-2.5 sm:grid-cols-2\"\n : \"grid gap-2.5\"\n }\n >\n {providers.map((provider) => (\n <button\n key={provider}\n type=\"button\"\n onClick={() => onSelect(provider)}\n disabled={disabled}\n aria-label={copy[provider] ?? provider}\n className={[\n \"flex h-[52px] w-full items-center justify-center gap-2.5 rounded-lg sm:h-11\",\n \"border border-foreground/25 bg-background text-base font-medium text-foreground sm:text-sm\",\n \"transition-[background-color,border-color,transform] duration-150 ease-out\",\n \"hover:border-foreground/20 hover:bg-accent active:translate-y-px\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n <ProviderMark provider={provider} />\n <span className={providers.length > 1 ? \"sm:hidden\" : \"\"}>\n {copy[provider] ?? provider}\n </span>\n </button>\n ))}\n </div>\n </div>\n )\n}\n\n// Brand marks are inlined: they must keep their own colors (Google's mark is\n// unusable in monochrome) and adding an icon dependency to this package would\n// duplicate one every consumer already ships.\nfunction ProviderMark({ provider }: { provider: \"google\" | \"github\" }) {\n if (provider === \"google\") {\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <path\n fill=\"#4285F4\"\n d=\"M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.02-3.7H.96v2.33A9 9 0 0 0 9 18Z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M3.98 10.72a5.4 5.4 0 0 1 0-3.44V4.95H.96a9 9 0 0 0 0 8.1l3.02-2.33Z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.02 2.33C4.68 5.16 6.66 3.58 9 3.58Z\"\n />\n </svg>\n )\n }\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.38l-.01-1.49c-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.4 7.4 0 0 1 4 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48l-.01 2.2c0 .21.15.46.55.38A8 8 0 0 0 8 0Z\" />\n </svg>\n )\n}\n","import type { ReactNode } from \"react\"\nimport type { LinkComponent } from \"../types\"\n\ninterface AuthLinkProps {\n to: string\n as?: LinkComponent\n className?: string\n children: ReactNode\n}\n\n/**\n * A link between auth screens.\n *\n * Falls back to an anchor, which is right for an app without a router and wrong\n * for every app with one: the full page load it triggers restarts the app and\n * loses whatever the URL was carrying.\n */\nexport function AuthLink({ to, as: Link, className, children }: AuthLinkProps) {\n if (Link) {\n return (\n <Link to={to} className={className}>\n {children}\n </Link>\n )\n }\n return (\n <a href={to} className={className}>\n {children}\n </a>\n )\n}\n\nexport const AUTH_LINK_CLASS =\n \"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\nexport const AUTH_HINT_LINK_CLASS =\n \"rounded text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n","/**\n * An invitation token as it may appear in a URL, reduced to something safe to\n * carry through a route search schema.\n *\n * Callers pass raw search params (`Route.validateSearch`), so the input is\n * whatever the address bar held: an array when the param repeats, a number, or\n * a string long enough to be an attack rather than a token. Anything that is\n * not one plausible token collapses to undefined, which reads as \"no\n * invitation\" everywhere downstream.\n */\nconst MAX_TOKEN_LENGTH = 128\n\nexport function normalizeInviteToken(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined\n const trimmed = value.trim()\n if (!trimmed || trimmed.length > MAX_TOKEN_LENGTH) return undefined\n return trimmed\n}\n\n/**\n * Appends the invitation to a link between auth screens.\n *\n * An invitee who lands on /register and clicks through to /login must keep the\n * offer: the token lives only in the URL, so a plain href to the sibling screen\n * silently drops it and the account is created on the default tier.\n */\nexport function withInviteToken(href: string, token?: string): string {\n if (!token) return href\n const separator = href.includes(\"?\") ? \"&\" : \"?\"\n return `${href}${separator}invite=${encodeURIComponent(token)}`\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport { withInviteToken } from \"../invite-token\"\nimport type { RegisterFormLabels, RegisterFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<RegisterFormLabels> = {\n title: \"Créer un compte\",\n subtitle: \"Nous t'enverrons un code pour confirmer ton adresse e-mail.\",\n namePlaceholder: \"Nom complet\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n confirmPlaceholder: \"Confirme le mot de passe\",\n passwordMismatch: \"Les deux mots de passe ne correspondent pas\",\n submit: \"Créer mon compte\",\n submitPending: \"Création…\",\n haveAccount: \"Tu as déjà un compte ?\",\n login: \"Se connecter\",\n nameRequired: \"Renseigne ton nom\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n signUpFailed: \"La création du compte a échoué\",\n}\n\nexport function RegisterForm({\n onSuccess,\n loginUrl = \"/login\",\n legal,\n socialCallbackUrl = \"/\",\n socialProviders = [],\n labels,\n submitClassName,\n fieldClassName,\n error: externalError,\n linkComponent,\n invite,\n authClient,\n}: RegisterFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [name, setName] = useState(\"\")\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [ownError, setOwnError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n // What the person just did outranks what happened before they arrived.\n const error = ownError ?? externalError\n const setError = setOwnError\n\n const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH\n const mismatch = confirmPassword.length > 0 && confirmPassword !== password\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!name.trim()) {\n setError(t.nameRequired)\n return\n }\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n if (password !== confirmPassword) {\n setError(t.passwordMismatch)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signUp.email({\n name: name.trim(),\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.signUpFailed)\n return\n }\n // createPlatformAuth sets requireEmailVerification, so sign-up leaves the\n // account unverified and without a session: the caller routes to the OTP\n // step rather than into the app.\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n // The invitation rides the callback: an OAuth sign-up leaves the\n // browser, and the auth handler redeems the token on the way back.\n callbackURL: withInviteToken(socialCallbackUrl, invite),\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.namePlaceholder}\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"name\"\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n description={t.passwordHint}\n // Only once they have typed something: flagging an untouched field\n // red would scold someone for not having started yet.\n invalid={tooShort}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.confirmPlaceholder}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n invalid={mismatch}\n fieldClassName={fieldClassName}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n\n {legal && (\n <p className=\"text-center text-xs leading-relaxed text-muted-foreground\">\n {legal}\n </p>\n )}\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.haveAccount}{\" \"}\n <AuthLink\n to={withInviteToken(loginUrl, invite)}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nRegisterForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type { VerifyEmailFormLabels, VerifyEmailFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthOtpField, OTP_LENGTH } from \"./auth-otp-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst DEFAULTS: Required<VerifyEmailFormLabels> = {\n title: \"Vérifie ton adresse\",\n subtitle: \"Entre le code à 6 chiffres envoyé à\",\n subtitleNoEmail: \"Entre le code à 6 chiffres reçu par e-mail.\",\n codePlaceholder: \"Code de vérification\",\n submit: \"Vérifier\",\n submitPending: \"Vérification…\",\n resend: \"Renvoyer le code\",\n resendPending: \"Envoi…\",\n resent: \"Un nouveau code vient de t'être envoyé.\",\n alreadyVerified: \"Adresse déjà vérifiée ?\",\n login: \"Se connecter\",\n codeRequired: \"Entre le code à 6 chiffres\",\n invalidCode: \"Code invalide. Réessaie.\",\n resendFailed: \"L'envoi du code a échoué\",\n missingEmail: \"Adresse e-mail introuvable. Recommence l'inscription.\",\n}\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: VerifyEmailFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [otp, setOtp] = useState(\"\")\n const [isVerifying, setIsVerifying] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n const [error, setError] = useState<string | undefined>()\n\n const handleVerify = async (e: FormEvent) => {\n e.preventDefault()\n if (otp.length < OTP_LENGTH) {\n setError(t.codeRequired)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n if (res?.error) {\n setError(res.error.message ?? t.invalidCode)\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCode)\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(t.missingEmail)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"email-verification\",\n })\n setResendMessage(t.resent)\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resendFailed)\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n <AuthAlert tone=\"success\">{resendMessage}</AuthAlert>\n\n <form onSubmit={handleVerify} className=\"space-y-[1.125rem]\" noValidate>\n <AuthOtpField\n id=\"verify-email-otp\"\n label={t.codePlaceholder}\n value={otp}\n onChange={setOtp}\n disabled={isVerifying}\n fieldClassName={fieldClassName}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isVerifying}\n disabled={otp.length < OTP_LENGTH}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <div className=\"space-y-4 text-center text-sm text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55\"\n >\n {isResending ? t.resendPending : t.resend}\n </button>\n\n <p>\n {t.alreadyVerified}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nVerifyEmailForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","interface AuthOtpFieldProps {\n label: string\n value: string\n onChange: (value: string) => void\n disabled?: boolean\n invalid?: boolean\n id: string\n /** Replaces the default border and background utilities */\n fieldClassName?: string\n}\n\nexport const OTP_LENGTH = 6\n\n/**\n * The 6-digit code field.\n *\n * Not an AuthField: the value is a code being read off another screen, so it\n * is spaced and monospaced to be checked digit by digit, and non-digits are\n * dropped on the way in — pasting a code from a mail client routinely carries\n * a trailing space.\n */\nexport function AuthOtpField({\n label,\n value,\n onChange,\n disabled = false,\n invalid = false,\n id,\n fieldClassName = \"border-foreground/25 bg-background\",\n}: AuthOtpFieldProps) {\n return (\n <div className=\"space-y-2\">\n <label\n htmlFor={id}\n className=\"block text-sm font-medium leading-none text-foreground\"\n >\n {label}\n </label>\n <input\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={OTP_LENGTH}\n value={value}\n onChange={(e) => onChange(e.target.value.replace(/\\D/g, \"\"))}\n required\n disabled={disabled}\n autoComplete=\"one-time-code\"\n aria-invalid={invalid || undefined}\n className={[\n \"h-[52px] w-full rounded-lg border px-4 sm:h-11\",\n \"text-center font-mono text-lg tracking-[0.4em]\",\n \"text-foreground\",\n \"transition-[border-color,box-shadow] duration-150 ease-out\",\n \"focus-visible:outline-none focus-visible:ring-[3px]\",\n invalid\n ? \"border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/20\"\n : `${fieldClassName} focus-visible:border-ring focus-visible:ring-ring/15`,\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n ].join(\" \")}\n />\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type {\n ForgotPasswordFormLabels,\n ForgotPasswordFormProps,\n} from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst DEFAULTS: Required<ForgotPasswordFormLabels> = {\n title: \"Mot de passe oublié ?\",\n subtitle:\n \"Entre ton adresse e-mail et nous t'enverrons un code pour le réinitialiser.\",\n emailPlaceholder: \"Adresse e-mail\",\n submit: \"Envoyer le code\",\n submitPending: \"Envoi…\",\n rememberPassword: \"Tu t'en souviens finalement ?\",\n login: \"Se connecter\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n sendFailed: \"L'envoi du code a échoué\",\n}\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: ForgotPasswordFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email: email.trim(),\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? t.sendFailed)\n return\n }\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.sendFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n invalid={!!error}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n disabled={!email.trim()}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.rememberPassword}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nForgotPasswordForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type { ResetPasswordFormLabels, ResetPasswordFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthOtpField, OTP_LENGTH } from \"./auth-otp-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<ResetPasswordFormLabels> = {\n title: \"Nouveau mot de passe\",\n subtitle: \"Entre le code à 6 chiffres reçu par e-mail et ton nouveau mot de passe.\",\n codePlaceholder: \"Code de vérification\",\n passwordPlaceholder: \"Nouveau mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n confirmPlaceholder: \"Confirme le mot de passe\",\n submit: \"Réinitialiser\",\n submitPending: \"Réinitialisation…\",\n resend: \"Renvoyer le code\",\n resendPending: \"Envoi…\",\n resent: \"Un nouveau code vient de t'être envoyé.\",\n rememberPassword: \"Tu t'en souviens finalement ?\",\n login: \"Se connecter\",\n codeRequired: \"Entre le code à 6 chiffres\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n passwordMismatch: \"Les deux mots de passe ne correspondent pas\",\n resetFailed: \"La réinitialisation a échoué\",\n resendFailed: \"L'envoi du code a échoué\",\n}\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: ResetPasswordFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [otp, setOtp] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isResetting, setIsResetting] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n\n const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH\n const mismatch = confirmPassword.length > 0 && confirmPassword !== password\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (otp.length < OTP_LENGTH) {\n setError(t.codeRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n if (password !== confirmPassword) {\n setError(t.passwordMismatch)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResetting(true)\n try {\n const res = await fetch(\"/api/auth/email-otp/reset-password\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, otp, password }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => null)\n setError(body?.message ?? t.resetFailed)\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resetFailed)\n } finally {\n setIsResetting(false)\n }\n }\n\n const handleResend = async () => {\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n setResendMessage(t.resent)\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resendFailed)\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n <AuthAlert tone=\"success\">{resendMessage}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthOtpField\n id=\"reset-password-otp\"\n label={t.codePlaceholder}\n value={otp}\n onChange={setOtp}\n disabled={isResetting}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n description={t.passwordHint}\n invalid={tooShort}\n />\n\n <AuthField\n label={t.confirmPlaceholder}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n invalid={mismatch}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isResetting}\n disabled={otp.length < OTP_LENGTH || !password || !confirmPassword}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <div className=\"space-y-4 text-center text-sm text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55\"\n >\n {isResending ? t.resendPending : t.resend}\n </button>\n\n <p>\n {t.rememberPassword}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nResetPasswordForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","interface AuthHeadingProps {\n title: string\n subtitle?: string\n /** Replaces the default size and weight — pass the whole look */\n titleClassName?: string\n}\n\n/**\n * The heading of an auth screen.\n *\n * This screen is the only one someone sees before they have any reason to\n * trust the product, so the type carries it: the title is the screen's centre\n * of gravity, set large and tightly tracked, with the subtitle stepping well\n * back rather than competing.\n *\n * Optical sizing matters at this weight — `text-balance` keeps a two-line\n * subtitle from breaking into a lonely last word, which reads as an accident\n * where everything else is deliberate.\n */\nexport function AuthHeading({\n title,\n subtitle,\n titleClassName = \"text-[2rem] font-semibold leading-[1.1] tracking-[-0.03em] sm:text-[2.25rem]\",\n}: AuthHeadingProps) {\n return (\n <header className=\"space-y-2.5 text-center\">\n <h1 className={`text-foreground ${titleClassName}`}>{title}</h1>\n {subtitle && (\n <p className=\"text-balance text-[0.9375rem] leading-relaxed text-muted-foreground\">\n {subtitle}\n </p>\n )}\n </header>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\nimport { AuthHeading } from \"./auth-heading\"\n\n/**\n * The frame every auth screen sits in. It owns the ground, the heading and the\n * app's own marks (logo, illustration, legal footer); the card holds only the\n * fields and their actions.\n *\n * The heading sits ABOVE the card rather than inside it: the card is then\n * exactly the thing you fill in, and the mark reads as the app's rather than\n * as the form's first row.\n *\n * Mobile and desktop are two layouts, not one scaled down. On a phone the form\n * IS the page: no card, no border, edge-to-edge padding, top-aligned so the\n * fields stay above the keyboard instead of being pushed under it by vertical\n * centering. From sm up it becomes a bounded card on a tinted ground — a\n * full-width form on a 1440px display is unreadable.\n *\n * A `panel` is an app-supplied illustration and nothing else: without one the\n * card stays a single column rather than inventing decoration to fill a half\n * it has no content for. When given, it takes the LEFT half from md up and is\n * dropped below that width — a decorative half-screen above a form costs a\n * full swipe before the first field.\n *\n * min-h-dvh rather than min-h-screen: on mobile browsers 100vh includes the\n * retracting URL bar, so a screen-height container overflows by its height.\n */\nexport function AuthLayout({\n logo,\n panel,\n title,\n subtitle,\n titleClassName,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-dvh flex-col bg-background px-5 pb-12 pt-14 sm:items-center sm:bg-muted/30 sm:px-6 sm:py-20\">\n <div className={`mx-auto w-full ${panel ? \"max-w-4xl\" : \"max-w-[400px]\"}`}>\n {(logo || title) && (\n // The spacing is composed, not repeated: the mark sits close to the\n // title it introduces, and the gap down to the card is the largest\n // on the screen — that step is what separates \"who this is\" from\n // \"what you do here\".\n <div className=\"mb-10 space-y-6\">\n {logo && <div className=\"flex justify-center\">{logo}</div>}\n {title && (\n <AuthHeading\n title={title}\n subtitle={subtitle}\n titleClassName={titleClassName}\n />\n )}\n </div>\n )}\n\n <div\n className={[\n \"sm:rounded-xl sm:border sm:border-foreground/[0.08] sm:bg-card\",\n \"sm:shadow-[0_1px_2px_rgba(0,0,0,0.04),0_8px_24px_-12px_rgba(0,0,0,0.10)]\",\n panel ? \"sm:overflow-hidden md:grid md:grid-cols-2\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {panel && (\n // Decorative: it must never carry information the form does not,\n // so it is hidden from assistive tech rather than described.\n <div\n aria-hidden=\"true\"\n className=\"relative hidden overflow-hidden bg-muted md:block [&>*]:absolute [&>*]:inset-0 [&>*]:h-full [&>*]:w-full [&>img]:object-cover\"\n >\n {panel}\n </div>\n )}\n\n <div className=\"sm:px-7 sm:py-8\">{children}</div>\n </div>\n\n {footer && (\n <div className=\"mt-8 text-center text-xs leading-relaxed text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { InvitationNoticeProps } from \"../types\"\n\n/**\n * Every app is reachable at contact@ its own apex domain, so the address is\n * derived rather than configured. Sub-domains are stripped because the app is\n * routinely served from app./admin. while the mailbox lives on the apex;\n * multi-part public suffixes (.co.uk) would need a real suffix list and no app\n * using this is on one.\n */\nfunction defaultSupportEmail(): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const host = window.location.hostname\n if (!host || host === \"localhost\" || /^[\\d.]+$/.test(host)) return undefined\n const apex = host.split(\".\").slice(-2).join(\".\")\n return `contact@${apex}`\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: \"Cette invitation a expiré.\",\n claimed: \"Cette invitation a déjà été utilisée.\",\n unknown: \"Ce lien d'invitation n'est pas valide.\",\n}\n\n/**\n * What an invitee sees when their link does not work.\n *\n * It names the reason instead of merging the cases into one message: \"expired\"\n * tells someone their link was real and that asking for another one is worth\n * it, which \"invalid\" does not. Short TTLs make that distinction routine.\n *\n * The only way forward offered is a mailto, deliberately. A self-service\n * \"request a new invitation\" form would mean a public endpoint accepting dead\n * tokens, a queue to moderate, and a way to probe which tokens once existed —\n * for a flow where the operator already knows the person by name.\n */\nexport function InvitationNotice({\n reason = \"unknown\",\n supportEmail,\n title = \"Invitation indisponible\",\n action,\n}: InvitationNoticeProps) {\n const contact = supportEmail ?? defaultSupportEmail()\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown}\n </p>\n </div>\n\n {contact ? (\n <p className=\"text-sm text-muted-foreground\">\n Écrivez-nous à{\" \"}\n <a\n href={`mailto:${contact}`}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {contact}\n </a>{\" \"}\n pour en recevoir une nouvelle.\n </p>\n ) : null}\n\n {action}\n </div>\n )\n}\n","export type OAuthErrorLabels = {\n accountNotLinked: string\n socialCancelled: string\n socialFailed: string\n}\n\n/**\n * Turns Better Auth's machine-readable OAuth failure code into something an\n * invitee can act on.\n *\n * `account_not_linked` is the one worth naming: createPlatformAuth disables\n * account linking on purpose, so \"Continue with Google\" on an address already\n * registered with a password is REFUSED. Better Auth's default error route\n * bounces the browser back with nothing shown, so without this the button\n * simply looks broken.\n */\nexport function oauthErrorMessage(\n code: string | null | undefined,\n labels: OAuthErrorLabels,\n): string {\n switch (code) {\n case \"account_not_linked\":\n return labels.accountNotLinked\n case \"access_denied\":\n return labels.socialCancelled\n default:\n return labels.socialFailed\n }\n}\n\n/**\n * Reads the failure Better Auth redirected back with.\n *\n * A social sign-in leaves the app entirely, so component state does not survive\n * it: the only carrier left when the browser returns is the `?error=` Better\n * Auth appends to the errorCallbackURL. Read from the address bar rather than\n * from a typed route search, because the auth routes deliberately declare no\n * search schema — adding one would make `search` required on every navigate to\n * them across the app.\n */\nexport function initialOAuthError(\n labels: OAuthErrorLabels,\n param = \"error\",\n): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const code = new URLSearchParams(window.location.search).get(param)\n if (!code) return undefined\n return oauthErrorMessage(code, labels)\n}\n\n/**\n * Drops the failure from the address bar once it has been shown.\n *\n * Without this the message comes back on every reload, and outlives the retry\n * that succeeded. replaceState rather than a router navigate: these screens\n * have no typed search to navigate against, and the entry being rewritten is\n * the one the OAuth provider pushed, not one the person chose.\n */\nexport function clearOAuthError(param = \"error\"): void {\n if (typeof window === \"undefined\") return\n const url = new URL(window.location.href)\n if (!url.searchParams.has(param)) return\n url.searchParams.delete(param)\n window.history.replaceState({}, \"\", url.toString())\n}\n"],"mappings":";;;;;AAMO,SAAS,WAAW,YAAgC;AACzD,SAAO,WAAW,WAAW;AAC/B;AAMO,SAAS,UAAU,YAAgC;AACxD,QAAM,UAAU,YAAY;AAC1B,UAAM,WAAW,QAAQ;AAAA,EAC3B;AACA,SAAO;AACT;;;ACnBA,SAAS,OAAO,gBAA0D;AA+CpE,SAGE,KAHF;AAjBC,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,GAAG;AACL,GAAmB;AACjB,QAAM,KAAK,MAAM;AACjB,QAAM,gBAAgB,cAAc,GAAG,EAAE,iBAAiB;AAC1D,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,QAAM,aAAa,MAAM,SAAS;AAClC,QAAM,OAAO,cAAc,WAAW,SAAS,MAAM;AAErD,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,6CAGb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MACC;AAAA,OACH;AAAA,IAEA,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ;AAAA,UACA;AAAA,UACA,gBAAc,WAAW;AAAA,UACzB,oBAAkB;AAAA,UAClB,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA,aAAa,UAAU;AAAA,YACvB;AAAA;AAAA;AAAA;AAAA,YAIA;AAAA,YACA;AAAA,YACA,UACI,wGAKA,GAAG,cAAc;AAAA,YACrB;AAAA,UACF,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AAAA;AAAA,MACb;AAAA,MAEC,cACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,UACpC,UAAU,MAAM;AAAA,UAChB,gBAAc;AAAA,UACd,cACE,WAAW,4BAA4B;AAAA,UAEzC,WAAU;AAAA,UAEV,8BAAC,WAAQ,MAAM,UAAU;AAAA;AAAA,MAC3B;AAAA,OAEJ;AAAA,IAEC,eACC,oBAAC,OAAE,IAAI,eAAe,WAAU,iCAC7B,uBACH;AAAA,KAEJ;AAEJ;AAIA,SAAS,QAAQ,EAAE,KAAK,GAAsB;AAC5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ;AAAA,4BAAC,UAAK,GAAE,kGAAiG;AAAA,QACzG,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC7B,CAAC,QAAQ,oBAAC,UAAK,GAAE,cAAa;AAAA;AAAA;AAAA,EACjC;AAEJ;;;ACjGI,SAoBI,OAAAA,MApBJ,QAAAC,aAAA;AATG,SAAS,WAAW;AAAA,EACzB,UAAU;AAAA,EACV,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,cAAc;AAChB,GAAoB;AAClB,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,UAAU,YAAY;AAAA,MACtB,aAAW,WAAW;AAAA,MACtB,WAAW;AAAA,QACT,cAAc,UAAU;AAAA,QACxB;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,MAET;AAAA,mBACC,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA;AAAA,QACZ;AAAA,QAED,UAAU,eAAe;AAAA;AAAA;AAAA,EAC5B;AAEJ;;;ACjEA,SAAS,YAAAE,iBAAgC;;;ACiBrC,gBAAAC,YAAA;AAFG,SAAS,UAAU,EAAE,UAAU,OAAO,QAAQ,GAAmB;AACtE,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,SAAS,UAAU,UAAU;AAAA,MACnC,aAAW,SAAS,UAAU,cAAc;AAAA,MAC5C,WACE,WACI;AAAA,QACE;AAAA,QACA,SAAS,UACL,6DACA;AAAA,MACN,EAAE,KAAK,GAAG,IACV;AAAA,MAGL;AAAA;AAAA,EACH;AAEJ;;;ACHM,SACE,OAAAC,MADF,QAAAC,aAAA;AA/BN,IAAM,SAAiC;AAAA,EACrC,QAAQ;AAAA,EACR,QAAQ;AACV;AAYO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AACF,GAAuB;AACrB,MAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,QAAM,OAAO,EAAE,GAAG,QAAQ,GAAG,OAAO;AAEpC,SACE,gBAAAA,MAAC,SAAI,WAAU,aAIb;AAAA,oBAAAA,MAAC,SAAI,eAAY,QAAO,WAAU,2BAChC;AAAA,sBAAAD,KAAC,UAAK,WAAU,yBAAwB;AAAA,MACxC,gBAAAA,KAAC,UAAK,WAAU,iEACb,qBACH;AAAA,MACA,gBAAAA,KAAC,UAAK,WAAU,yBAAwB;AAAA,OAC1C;AAAA,IAMA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WACE,UAAU,SAAS,IACf,gCACA;AAAA,QAGL,oBAAU,IAAI,CAAC,aACd,gBAAAC;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,SAAS,QAAQ;AAAA,YAChC;AAAA,YACA,cAAY,KAAK,QAAQ,KAAK;AAAA,YAC9B,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF,EAAE,KAAK,GAAG;AAAA,YAEV;AAAA,8BAAAD,KAAC,gBAAa,UAAoB;AAAA,cAClC,gBAAAA,KAAC,UAAK,WAAW,UAAU,SAAS,IAAI,cAAc,IACnD,eAAK,QAAQ,KAAK,UACrB;AAAA;AAAA;AAAA,UAjBK;AAAA,QAkBP,CACD;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAKA,SAAS,aAAa,EAAE,SAAS,GAAsC;AACrE,MAAI,aAAa,UAAU;AACzB,WACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,eAAY,QAC1D;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,GAAE;AAAA;AAAA,MACJ;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,GAAE;AAAA;AAAA,MACJ;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,GAAE;AAAA;AAAA,MACJ;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,GAAE;AAAA;AAAA,MACJ;AAAA,OACF;AAAA,EAEJ;AACA,SACE,gBAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAAe,eAAY,QAC9E,0BAAAA,KAAC,UAAK,GAAE,0dAAyd,GACne;AAEJ;;;ACxFM,gBAAAE,YAAA;AAHC,SAAS,SAAS,EAAE,IAAI,IAAI,MAAM,WAAW,SAAS,GAAkB;AAC7E,MAAI,MAAM;AACR,WACE,gBAAAA,KAAC,QAAK,IAAQ,WACX,UACH;AAAA,EAEJ;AACA,SACE,gBAAAA,KAAC,OAAE,MAAM,IAAI,WACV,UACH;AAEJ;AAEO,IAAM,kBACX;AAEK,IAAM,uBACX;;;AC1BF,IAAM,mBAAmB;AAElB,SAAS,qBAAqB,OAAoC;AACvE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,WAAW,QAAQ,SAAS,iBAAkB,QAAO;AAC1D,SAAO;AACT;AASO,SAAS,gBAAgB,MAAc,OAAwB;AACpE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,KAAK,SAAS,GAAG,IAAI,MAAM;AAC7C,SAAO,GAAG,IAAI,GAAG,SAAS,UAAU,mBAAmB,KAAK,CAAC;AAC/D;;;AJoFM,gBAAAC,MAEA,QAAAC,aAFA;AAzGN,IAAM,WAAsC;AAAA,EAC1C,OAAO;AAAA,EACP,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,WAAW;AAAA,EACX,UAAU;AAAA,EACV,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,oBAAoB;AAAA;AAAA;AAAA;AAAA,EAIpB,kBACE;AAAA,EACF,iBAAiB;AAAA,EACjB,cAAc;AAChB;AAEO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,kBAAkB,CAAC;AAAA,EACnB,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,IAAI,EAAE,GAAG,UAAU,GAAG,OAAO;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE;AAC3C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA6B;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAGhD,QAAM,QAAQ,YAAY;AAC1B,QAAM,WAAW;AAEjB,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,eAAS,EAAE,aAAa;AACxB;AAAA,IACF;AACA,QAAI,CAAC,UAAU;AACb,eAAS,EAAE,gBAAgB;AAC3B;AAAA,IACF;AACA,aAAS,MAAS;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,MAAM,MAAM,WAAW,OAAO,MAAM;AAAA,QACxC,OAAO,MAAM,KAAK;AAAA,QAClB;AAAA,MACF,CAAC;AACD,UAAI,KAAK,OAAO;AACd,iBAAS,IAAI,MAAM,WAAW,EAAE,kBAAkB;AAClD;AAAA,MACF;AAIA,UAAI,cAAc;AAChB,cAAM,MAAM,cAAc,EAAE,aAAa,UAAU,CAAC;AAAA,MACtD;AACA,kBAAY;AAAA,IACd,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,kBAAkB;AAAA,IACpE,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,aAAkC;AAC5D,aAAS,MAAS;AAClB,QAAI;AACF,YAAM,WAAW,OAAO,OAAO;AAAA,QAC7B;AAAA;AAAA;AAAA,QAGA,aAAa,gBAAgB,mBAAmB,MAAM;AAAA,MACxD,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,OAAO,eAAe,QAAQ,IAAI,UAAU;AAClD;AAAA,QACE,SAAS,uBACL,EAAE,mBACF,SAAS,kBACP,EAAE,kBACF,EAAE;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SACE,gBAAAD,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,KAAC,aAAW,iBAAM;AAAA,IAElB,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,sBAAqB,YAAU,MACrE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,UACxC,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,gBAAe;AAAA,UACf,YAAY;AAAA,UACZ,SAAS,CAAC,CAAC;AAAA,UACX;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,UAC3C,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,SAAS,CAAC,CAAC;AAAA,UACX;AAAA,UACA,MACE,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,WAAW;AAAA,cAEV,YAAE;AAAA;AAAA,UACL;AAAA;AAAA,MAEJ;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAW;AAAA,UACX,SAAS;AAAA,UACT,UAAU,CAAC,MAAM,KAAK,KAAK,CAAC;AAAA,UAC5B,cAAc,EAAE;AAAA,UAChB,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX,UAAU;AAAA,QACV,UAAU;AAAA;AAAA,IACZ;AAAA,IAEA,gBAAAC,MAAC,OAAE,WAAU,6CACV;AAAA,QAAE;AAAA,MAAW;AAAA,MACd,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,gBAAgB,aAAa,MAAM;AAAA,UACvC,IAAI;AAAA,UACJ,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,KACF;AAEJ;AAKA,UAAU,WAAW;AAAA,EACnB,OAAO,SAAS;AAAA,EAChB,UAAU,SAAS;AACrB;;;AK9LA,SAAS,YAAAG,iBAAgC;AAoHnC,gBAAAC,MAEA,QAAAC,aAFA;AA3GN,IAAM,sBAAsB;AAE5B,IAAMC,YAAyC;AAAA,EAC7C,OAAO;AAAA,EACP,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,cAAc,YAAY,mBAAmB;AAAA,EAC7C,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,aAAa;AAAA,EACb,OAAO;AAAA,EACP,cAAc;AAAA,EACd,eAAe;AAAA,EACf,kBAAkB,uCAAuC,mBAAmB;AAAA,EAC5E,cAAc;AAChB;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,oBAAoB;AAAA,EACpB,kBAAkB,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,IAAI,EAAE,GAAGA,WAAU,GAAG,OAAO;AACnC,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE;AAC3C,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAS,EAAE;AACzD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA6B;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAGhD,QAAM,QAAQ,YAAY;AAC1B,QAAM,WAAW;AAEjB,QAAM,WAAW,SAAS,SAAS,KAAK,SAAS,SAAS;AAC1D,QAAM,WAAW,gBAAgB,SAAS,KAAK,oBAAoB;AAEnE,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,eAAS,EAAE,YAAY;AACvB;AAAA,IACF;AACA,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,eAAS,EAAE,aAAa;AACxB;AAAA,IACF;AACA,QAAI,SAAS,SAAS,qBAAqB;AACzC,eAAS,EAAE,gBAAgB;AAC3B;AAAA,IACF;AACA,QAAI,aAAa,iBAAiB;AAChC,eAAS,EAAE,gBAAgB;AAC3B;AAAA,IACF;AACA,aAAS,MAAS;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,MAAM,MAAM,WAAW,OAAO,MAAM;AAAA,QACxC,MAAM,KAAK,KAAK;AAAA,QAChB,OAAO,MAAM,KAAK;AAAA,QAClB;AAAA,MACF,CAAC;AACD,UAAI,KAAK,OAAO;AACd,iBAAS,IAAI,MAAM,WAAW,EAAE,YAAY;AAC5C;AAAA,MACF;AAIA,kBAAY,MAAM,KAAK,CAAC;AAAA,IAC1B,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,YAAY;AAAA,IAC9D,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,aAAkC;AAC5D,aAAS,MAAS;AAClB,QAAI;AACF,YAAM,WAAW,OAAO,OAAO;AAAA,QAC7B;AAAA;AAAA;AAAA,QAGA,aAAa,gBAAgB,mBAAmB,MAAM;AAAA,MACxD,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,YAAY;AAAA,IAC9D;AAAA,EACF;AAEA,SACE,gBAAAF,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,KAAC,aAAW,iBAAM;AAAA,IAElB,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,sBAAqB,YAAU,MACrE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,UACvC,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,UACxC,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,gBAAe;AAAA,UACf,YAAY;AAAA,UACZ;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,UAC3C,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,aAAa,EAAE;AAAA,UAGf,SAAS;AAAA,UACT;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,mBAAmB,EAAE,OAAO,KAAK;AAAA,UAClD,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,SAAS;AAAA,UACT;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAW;AAAA,UACX,SAAS;AAAA,UACT,cAAc,EAAE;AAAA,UAChB,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,MAEC,SACC,gBAAAA,KAAC,OAAE,WAAU,6DACV,iBACH;AAAA,OAEJ;AAAA,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX,UAAU;AAAA,QACV,UAAU;AAAA;AAAA,IACZ;AAAA,IAEA,gBAAAC,MAAC,OAAE,WAAU,6CACV;AAAA,QAAE;AAAA,MAAa;AAAA,MAChB,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,gBAAgB,UAAU,MAAM;AAAA,UACpC,IAAI;AAAA,UACJ,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,aAAa,WAAW;AAAA,EACtB,OAAOE,UAAS;AAAA,EAChB,UAAUA,UAAS;AACrB;;;ACnNA,SAAS,YAAAE,iBAAgC;;;AC+BrC,SACE,OAAAC,MADF,QAAAC,aAAA;AApBG,IAAM,aAAa;AAUnB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,UAAU;AAAA,EACV;AAAA,EACA,iBAAiB;AACnB,GAAsB;AACpB,SACE,gBAAAA,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAU;AAAA,QAET;AAAA;AAAA,IACH;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAQ;AAAA,QACR,WAAW;AAAA,QACX;AAAA,QACA,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,MAAM,QAAQ,OAAO,EAAE,CAAC;AAAA,QAC3D,UAAQ;AAAA,QACR;AAAA,QACA,cAAa;AAAA,QACb,gBAAc,WAAW;AAAA,QACzB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,UACI,wGACA,GAAG,cAAc;AAAA,UACrB;AAAA,QACF,EAAE,KAAK,GAAG;AAAA;AAAA,IACZ;AAAA,KACF;AAEJ;;;ADwBM,gBAAAE,MAGA,QAAAC,aAHA;AAjFN,IAAMC,YAA4C;AAAA,EAChD,OAAO;AAAA,EACP,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,cAAc;AAAA,EACd,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAChB;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,IAAI,EAAE,GAAGA,WAAU,GAAG,OAAO;AACnC,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAS,EAAE;AACjC,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAA6B;AACvE,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA6B;AAEvD,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,QAAI,IAAI,SAAS,YAAY;AAC3B,eAAS,EAAE,YAAY;AACvB;AAAA,IACF;AACA,aAAS,MAAS;AAClB,qBAAiB,MAAS;AAC1B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,MAAM,MAAM,WAAW,SAAS,YAAY,EAAE,OAAO,IAAI,CAAC;AAChE,UAAI,KAAK,OAAO;AACd,iBAAS,IAAI,MAAM,WAAW,EAAE,WAAW;AAC3C;AAAA,MACF;AACA,kBAAY;AAAA,IACd,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,WAAW;AAAA,IAC7D,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,eAAe,YAAY;AAC/B,QAAI,CAAC,OAAO;AACV,eAAS,EAAE,YAAY;AACvB;AAAA,IACF;AACA,aAAS,MAAS;AAClB,qBAAiB,MAAS;AAC1B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,WAAW,SAAS,oBAAoB;AAAA,QAC5C;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AACD,uBAAiB,EAAE,MAAM;AAAA,IAC3B,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,YAAY;AAAA,IAC9D,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,SACE,gBAAAF,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,KAAC,aAAW,iBAAM;AAAA,IAClB,gBAAAA,KAAC,aAAU,MAAK,WAAW,yBAAc;AAAA,IAEzC,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,sBAAqB,YAAU,MACrE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO,EAAE;AAAA,UACT,OAAO;AAAA,UACP,UAAU;AAAA,UACV,UAAU;AAAA,UACV;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAW;AAAA,UACX,SAAS;AAAA,UACT,UAAU,IAAI,SAAS;AAAA,UACvB,cAAc,EAAE;AAAA,UAChB,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,IAEA,gBAAAC,MAAC,SAAI,WAAU,uDACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAU;AAAA,UAET,wBAAc,EAAE,gBAAgB,EAAE;AAAA;AAAA,MACrC;AAAA,MAEA,gBAAAC,MAAC,OACE;AAAA,UAAE;AAAA,QAAiB;AAAA,QACpB,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,WAAW;AAAA,YAEV,YAAE;AAAA;AAAA,QACL;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,gBAAgB,WAAW;AAAA,EACzB,OAAOE,UAAS;AAAA,EAChB,UAAUA,UAAS;AACrB;;;AE7IA,SAAS,YAAAE,iBAAgC;AAgEnC,gBAAAC,OAEA,QAAAC,aAFA;AAtDN,IAAMC,YAA+C;AAAA,EACnD,OAAO;AAAA,EACP,UACE;AAAA,EACF,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,eAAe;AAAA,EACf,YAAY;AACd;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,IAAI,EAAE,GAAGA,WAAU,GAAG,OAAO;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA6B;AACvD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAEhD,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,eAAS,EAAE,aAAa;AACxB;AAAA,IACF;AACA,aAAS,MAAS;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,MAAM,MAAM,WAAW,SAAS,oBAAoB;AAAA,QACxD,OAAO,MAAM,KAAK;AAAA,QAClB,MAAM;AAAA,MACR,CAAC;AACD,UAAI,KAAK,OAAO;AACd,iBAAS,IAAI,MAAM,WAAW,EAAE,UAAU;AAC1C;AAAA,MACF;AACA,kBAAY,MAAM,KAAK,CAAC;AAAA,IAC1B,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,UAAU;AAAA,IAC5D,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,SACE,gBAAAF,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,MAAC,aAAW,iBAAM;AAAA,IAElB,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,sBAAqB,YAAU,MACrE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,WAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,UACxC,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,gBAAe;AAAA,UACf,YAAY;AAAA,UACZ,SAAS,CAAC,CAAC;AAAA;AAAA,MACb;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAW;AAAA,UACX,SAAS;AAAA,UACT,UAAU,CAAC,MAAM,KAAK;AAAA,UACtB,cAAc,EAAE;AAAA,UAChB,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,IAEA,gBAAAC,MAAC,OAAE,WAAU,6CACV;AAAA,QAAE;AAAA,MAAkB;AAAA,MACrB,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,mBAAmB,WAAW;AAAA,EAC5B,OAAOE,UAAS;AAAA,EAChB,UAAUA,UAAS;AACrB;;;AC9GA,SAAS,YAAAE,iBAAgC;AA4GnC,gBAAAC,OAGA,QAAAC,aAHA;AApGN,IAAMC,uBAAsB;AAE5B,IAAMC,YAA8C;AAAA,EAClD,OAAO;AAAA,EACP,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,cAAc,YAAYD,oBAAmB;AAAA,EAC7C,oBAAoB;AAAA,EACpB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,cAAc;AAAA,EACd,kBAAkB,uCAAuCA,oBAAmB;AAAA,EAC5E,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,cAAc;AAChB;AAEO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,IAAI,EAAE,GAAGC,WAAU,GAAG,OAAO;AACnC,QAAM,CAAC,KAAK,MAAM,IAAIC,UAAS,EAAE;AACjC,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE;AAC3C,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAS,EAAE;AACzD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAA6B;AACvD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAA6B;AAEvE,QAAM,WAAW,SAAS,SAAS,KAAK,SAAS,SAASF;AAC1D,QAAM,WAAW,gBAAgB,SAAS,KAAK,oBAAoB;AAEnE,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,QAAI,IAAI,SAAS,YAAY;AAC3B,eAAS,EAAE,YAAY;AACvB;AAAA,IACF;AACA,QAAI,SAAS,SAASA,sBAAqB;AACzC,eAAS,EAAE,gBAAgB;AAC3B;AAAA,IACF;AACA,QAAI,aAAa,iBAAiB;AAChC,eAAS,EAAE,gBAAgB;AAC3B;AAAA,IACF;AACA,aAAS,MAAS;AAClB,qBAAiB,MAAS;AAC1B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,sCAAsC;AAAA,QAC5D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,SAAS,CAAC;AAAA,MAC/C,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC9C,iBAAS,MAAM,WAAW,EAAE,WAAW;AACvC;AAAA,MACF;AACA,kBAAY;AAAA,IACd,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,WAAW;AAAA,IAC7D,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,eAAe,YAAY;AAC/B,aAAS,MAAS;AAClB,qBAAiB,MAAS;AAC1B,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,WAAW,SAAS,oBAAoB;AAAA,QAC5C;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AACD,uBAAiB,EAAE,MAAM;AAAA,IAC3B,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,YAAY;AAAA,IAC9D,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,SACE,gBAAAD,MAAC,SAAI,WAAU,aACb;AAAA,oBAAAD,MAAC,aAAW,iBAAM;AAAA,IAClB,gBAAAA,MAAC,aAAU,MAAK,WAAW,yBAAc;AAAA,IAEzC,gBAAAC,MAAC,UAAK,UAAU,cAAc,WAAU,sBAAqB,YAAU,MACrE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,OAAO,EAAE;AAAA,UACT,OAAO;AAAA,UACP,UAAU;AAAA,UACV,UAAU;AAAA,UACV;AAAA;AAAA,MACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,UAC3C,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,aAAa,EAAE;AAAA,UACf,SAAS;AAAA;AAAA,MACX;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE;AAAA,UACT,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,mBAAmB,EAAE,OAAO,KAAK;AAAA,UAClD,UAAQ;AAAA,UACR,UAAU;AAAA,UACV,cAAa;AAAA,UACb,SAAS;AAAA;AAAA,MACX;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAW;AAAA,UACX,SAAS;AAAA,UACT,UAAU,IAAI,SAAS,cAAc,CAAC,YAAY,CAAC;AAAA,UACnD,cAAc,EAAE;AAAA,UAChB,WAAW;AAAA,UAEV,YAAE;AAAA;AAAA,MACL;AAAA,OACF;AAAA,IAEA,gBAAAC,MAAC,SAAI,WAAU,uDACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAU;AAAA,UAET,wBAAc,EAAE,gBAAgB,EAAE;AAAA;AAAA,MACrC;AAAA,MAEA,gBAAAC,MAAC,OACE;AAAA,UAAE;AAAA,QAAkB;AAAA,QACrB,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,WAAW;AAAA,YAEV,YAAE;AAAA;AAAA,QACL;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,kBAAkB,WAAW;AAAA,EAC3B,OAAOG,UAAS;AAAA,EAChB,UAAUA,UAAS;AACrB;;;AC/JI,SACE,OAAAE,OADF,QAAAC,cAAA;AANG,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,iBAAiB;AACnB,GAAqB;AACnB,SACE,gBAAAA,OAAC,YAAO,WAAU,2BAChB;AAAA,oBAAAD,MAAC,QAAG,WAAW,mBAAmB,cAAc,IAAK,iBAAM;AAAA,IAC1D,YACC,gBAAAA,MAAC,OAAE,WAAU,uEACV,oBACH;AAAA,KAEJ;AAEJ;;;ACUU,SACW,OAAAE,OADX,QAAAC,cAAA;AAjBH,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,SACE,gBAAAD,MAAC,SAAI,WAAU,0GACb,0BAAAC,OAAC,SAAI,WAAW,kBAAkB,QAAQ,cAAc,eAAe,IACnE;AAAA,aAAQ;AAAA;AAAA;AAAA;AAAA,IAKR,gBAAAA,OAAC,SAAI,WAAU,mBACZ;AAAA,cAAQ,gBAAAD,MAAC,SAAI,WAAU,uBAAuB,gBAAK;AAAA,MACnD,SACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,OAEJ;AAAA,IAGF,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,QAAQ,8CAA8C;AAAA,QACxD,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,QAEV;AAAA;AAAA;AAAA,UAGC,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,eAAY;AAAA,cACZ,WAAU;AAAA,cAET;AAAA;AAAA,UACH;AAAA,UAGF,gBAAAA,MAAC,SAAI,WAAU,mBAAmB,UAAS;AAAA;AAAA;AAAA,IAC7C;AAAA,IAEC,UACC,gBAAAA,MAAC,SAAI,WAAU,kEACZ,kBACH;AAAA,KAEJ,GACF;AAEJ;;;AC1CM,SACE,OAAAE,OADF,QAAAC,cAAA;AApCN,SAAS,sBAA0C;AACjD,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,OAAO,OAAO,SAAS;AAC7B,MAAI,CAAC,QAAQ,SAAS,eAAe,WAAW,KAAK,IAAI,EAAG,QAAO;AACnE,QAAM,OAAO,KAAK,MAAM,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG;AAC/C,SAAO,WAAW,IAAI;AACxB;AAEA,IAAM,iBAAyC;AAAA,EAC7C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AACX;AAcO,SAAS,iBAAiB;AAAA,EAC/B,SAAS;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,EACR;AACF,GAA0B;AACxB,QAAM,UAAU,gBAAgB,oBAAoB;AAEpD,SACE,gBAAAA,OAAC,SAAI,WAAU,aACb;AAAA,oBAAAA,OAAC,SACC;AAAA,sBAAAD,MAAC,QAAG,WAAU,qCAAqC,iBAAM;AAAA,MACzD,gBAAAA,MAAC,OAAE,WAAU,sCACV,yBAAe,MAAM,KAAK,eAAe,SAC5C;AAAA,OACF;AAAA,IAEC,UACC,gBAAAC,OAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,MAC5B;AAAA,MACf,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,UAAU,OAAO;AAAA,UACvB,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MAAK;AAAA,MAAI;AAAA,OAEX,IACE;AAAA,IAEH;AAAA,KACH;AAEJ;;;ACpDO,SAAS,kBACd,MACA,QACQ;AACR,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO;AAAA,IAChB,KAAK;AACH,aAAO,OAAO;AAAA,IAChB;AACE,aAAO,OAAO;AAAA,EAClB;AACF;AAYO,SAAS,kBACd,QACA,QAAQ,SACY;AACpB,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,OAAO,IAAI,gBAAgB,OAAO,SAAS,MAAM,EAAE,IAAI,KAAK;AAClE,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,kBAAkB,MAAM,MAAM;AACvC;AAUO,SAAS,gBAAgB,QAAQ,SAAe;AACrD,MAAI,OAAO,WAAW,YAAa;AACnC,QAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,MAAI,CAAC,IAAI,aAAa,IAAI,KAAK,EAAG;AAClC,MAAI,aAAa,OAAO,KAAK;AAC7B,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AACpD;","names":["jsx","jsxs","useState","jsx","jsx","jsxs","jsx","jsx","jsxs","useState","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","MIN_PASSWORD_LENGTH","DEFAULTS","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/auth-field.tsx","../src/components/auth-submit.tsx","../src/components/login-form.tsx","../src/email-not-verified.ts","../src/components/auth-alert.tsx","../src/components/social-buttons.tsx","../src/components/auth-link.tsx","../src/invite-token.ts","../src/components/register-form.tsx","../src/components/verify-email-form.tsx","../src/components/auth-otp-field.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-heading.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx","../src/oauth-error.ts"],"sourcesContent":["import type { PlatformAuthClient } from \"../client\"\n\n/**\n * Returns a useSession hook bound to the given auth client.\n * Usage: const { data: session, isPending } = useSession(authClient)\n */\nexport function useSession(authClient: PlatformAuthClient) {\n return authClient.useSession()\n}\n\n/**\n * Returns a logout function bound to the given auth client.\n * Usage: const logout = useLogout(authClient)\n */\nexport function useLogout(authClient: PlatformAuthClient) {\n const signOut = async () => {\n await authClient.signOut()\n }\n return signOut\n}\n","import { useId, useState, type InputHTMLAttributes, type ReactNode } from \"react\"\n\ntype NativeProps = Omit<InputHTMLAttributes<HTMLInputElement>, \"id\" | \"className\">\n\nexport interface AuthFieldProps extends NativeProps {\n label: string\n /** Rendered on the right of the label row — typically a \"forgot password\" link */\n hint?: ReactNode\n /** Persistent helper text under the field, tied to it for screen readers */\n description?: string\n invalid?: boolean\n /** Replaces the default border and background utilities */\n fieldClassName?: string\n}\n\n/**\n * A single credential field.\n *\n * The label is a real <label>, always visible, never a placeholder standing in\n * for one: a placeholder disappears the moment someone types, which is exactly\n * when a person double-checking a long password needs to know what the box is.\n *\n * Touch targets are 52px tall on mobile and 44px from sm up. Below ~48px,\n * thumbs miss; on a pointer device the same height reads as oversized, so the\n * two are not one compromise value.\n *\n * The focus ring is a ring rather than an outline so it follows the rounded\n * corners exactly, and the border darkens at the same time — the border is what\n * survives forced-colors mode, where the ring is dropped.\n */\nexport function AuthField({\n label,\n hint,\n description,\n invalid = false,\n fieldClassName = \"border-foreground/30 bg-background\",\n ...props\n}: AuthFieldProps) {\n const id = useId()\n const descriptionId = description ? `${id}-description` : undefined\n const [revealed, setRevealed] = useState(false)\n\n const isPassword = props.type === \"password\"\n const type = isPassword && revealed ? \"text\" : props.type\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-baseline justify-between gap-3\">\n {/* Small caps with wide tracking: at this size the label reads as a\n field marker rather than as prose competing with the heading. */}\n <label\n htmlFor={id}\n className=\"text-[0.6875rem] font-semibold uppercase leading-none tracking-[0.09em] text-foreground/70\"\n >\n {label}\n </label>\n {hint}\n </div>\n\n <div className=\"relative\">\n <input\n {...props}\n id={id}\n type={type}\n aria-invalid={invalid || undefined}\n aria-describedby={descriptionId}\n className={[\n \"h-[52px] w-full rounded-md border px-3.5 text-base\",\n \"sm:h-[46px] sm:text-[0.9375rem]\",\n isPassword ? \"pr-12\" : \"\",\n \"text-foreground placeholder:text-muted-foreground/60\",\n // Focus reads as the border committing rather than as a halo\n // appearing beside it: the ring is tight and the border darkens to\n // full ink in the same 180ms, so the field answers the caret.\n \"transition-[border-color,box-shadow] duration-200 ease-out\",\n \"focus-visible:outline-none focus-visible:ring-2\",\n invalid\n ? \"border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/15\"\n // The default border is foreground/30, not border-input: the\n // latter against a white card lands near 1.3:1, well under the\n // 3:1 WCAG 1.4.11 asks of a control's boundary — the field reads\n // as a faint tint rather than as something to type in.\n : `${fieldClassName} focus-visible:border-foreground focus-visible:ring-foreground/10`,\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n ]\n .filter(Boolean)\n .join(\" \")}\n />\n\n {isPassword && (\n <button\n type=\"button\"\n onClick={() => setRevealed((v) => !v)}\n disabled={props.disabled}\n aria-pressed={revealed}\n aria-label={\n revealed ? \"Masquer le mot de passe\" : \"Afficher le mot de passe\"\n }\n className=\"absolute inset-y-0 right-0 flex w-12 items-center justify-center rounded-r-xl text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60\"\n >\n <EyeIcon open={revealed} />\n </button>\n )}\n </div>\n\n {description && (\n <p id={descriptionId} className=\"text-xs text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n )\n}\n\n// Inline rather than from lucide-react: the package would gain a dependency\n// consumers already have at a different version, for two paths.\nfunction EyeIcon({ open }: { open: boolean }) {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n {!open && <path d=\"m3 3 18 18\" />}\n </svg>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthSubmitProps {\n pending?: boolean\n disabled?: boolean\n pendingLabel: string\n children: ReactNode\n /** Replaces the default `bg-primary text-primary-foreground hover:bg-primary/90` */\n className?: string\n /**\n * Adds the step that detaches the action from the fields above it. The\n * inputs sit on a tighter rhythm so they read as one block to fill in; the\n * button is what you do once that block is done, and an even gap would put\n * it on the same footing as another field.\n */\n spacedAbove?: boolean\n}\n\n/**\n * The primary action of an auth screen.\n *\n * The label swaps to its pending form in place, with the spinner absolutely\n * positioned: a spinner inserted into the flow would widen the row and shift\n * the text sideways at the exact moment the person is watching it.\n *\n * The press feedback is a 1px translate rather than a scale — scaling a\n * full-width button visibly blurs its text mid-transform.\n */\nexport function AuthSubmit({\n pending = false,\n disabled = false,\n pendingLabel,\n children,\n className = \"bg-primary text-primary-foreground hover:bg-primary/90\",\n spacedAbove = false,\n}: AuthSubmitProps) {\n return (\n <button\n type=\"submit\"\n disabled={disabled || pending}\n aria-busy={pending || undefined}\n className={[\n spacedAbove ? \"!mt-7\" : \"\",\n \"relative flex h-[52px] w-full items-center justify-center rounded-md sm:h-[46px]\",\n // Slightly tracked at this weight: a wide solid button set in plain\n // medium reads as a slab, and the letterspacing is what makes it read\n // as typeset rather than filled in.\n \"text-[0.9375rem] font-medium tracking-[0.01em]\",\n className,\n \"transition-[background-color,transform,box-shadow] duration-200 ease-out\",\n \"shadow-[0_1px_2px_rgba(0,0,0,0.08)] hover:shadow-[0_2px_8px_rgba(0,0,0,0.12)]\",\n \"active:translate-y-px active:shadow-[0_1px_2px_rgba(0,0,0,0.08)]\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n {pending && (\n <span\n aria-hidden=\"true\"\n className=\"absolute left-4 size-4 animate-spin rounded-full border-2 border-current border-t-transparent opacity-70 motion-reduce:animate-none\"\n />\n )}\n {pending ? pendingLabel : children}\n </button>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { LoginFormLabels, LoginFormProps } from \"../types\"\nimport { isEmailNotVerified } from \"../email-not-verified\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\nimport { AUTH_HINT_LINK_CLASS, AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport { withInviteToken } from \"../invite-token\"\n\nconst DEFAULTS: Required<LoginFormLabels> = {\n title: \"Connexion\",\n subtitle: \"Content de te revoir. Entre tes identifiants pour continuer.\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n forgotPassword: \"Mot de passe oublié ?\",\n submit: \"Se connecter\",\n submitPending: \"Connexion…\",\n noAccount: \"Pas encore de compte ?\",\n register: \"Créer un compte\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordRequired: \"Renseigne ton mot de passe\",\n invalidCredentials: \"Adresse e-mail ou mot de passe incorrect\",\n emailNotVerified:\n \"Ton adresse e-mail n'est pas encore confirmée. Vérifie ta boîte de réception.\",\n // accountLinking is disabled in createPlatformAuth, so a social sign-in on an\n // address already registered with a password is refused with this code.\n // Without a message the button reads as broken rather than as a rejection.\n accountNotLinked:\n \"Cette adresse est déjà associée à un mot de passe. Connecte-toi avec ton mot de passe.\",\n socialCancelled: \"Connexion annulée.\",\n socialFailed: \"La connexion a échoué. Réessaie.\",\n}\n\nexport function LoginForm({\n onSuccess,\n onEmailNotVerified,\n registerUrl = \"/register\",\n forgotPasswordUrl = \"/forgot-password\",\n socialCallbackUrl = \"/\",\n socialProviders = [],\n coreTokenUrl = \"/api/auth/core-token\",\n labels,\n submitClassName,\n fieldClassName,\n error: externalError,\n linkComponent,\n invite,\n authClient,\n}: LoginFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [ownError, setOwnError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n // What the person just did outranks what happened before they arrived.\n const error = ownError ?? externalError\n const setError = setOwnError\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (!password) {\n setError(t.passwordRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signIn.email({\n email: email.trim(),\n password,\n })\n if (res?.error) {\n if (isEmailNotVerified(res.error) && onEmailNotVerified) {\n onEmailNotVerified(email.trim())\n return\n }\n setError(\n isEmailNotVerified(res.error)\n ? t.emailNotVerified\n : (res.error.message ?? t.invalidCredentials),\n )\n return\n }\n // The better-auth session cookie alone does not authenticate a Go core:\n // it verifies the EdDSA JWT minted here against the issuer's JWKS.\n // Skipped when the app sets the token itself, or has no core at all.\n if (coreTokenUrl) {\n await fetch(coreTokenUrl, { credentials: \"include\" })\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCredentials)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n // The invitation rides the callback: an OAuth sign-up leaves the\n // browser, and the auth handler redeems the token on the way back.\n callbackURL: withInviteToken(socialCallbackUrl, invite),\n })\n } catch (err) {\n const code = err instanceof Error ? err.message : \"\"\n setError(\n code === \"account_not_linked\"\n ? t.accountNotLinked\n : code === \"access_denied\"\n ? t.socialCancelled\n : t.socialFailed,\n )\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n invalid={!!error}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"current-password\"\n invalid={!!error}\n fieldClassName={fieldClassName}\n hint={\n <AuthLink\n to={forgotPasswordUrl}\n as={linkComponent}\n className={AUTH_HINT_LINK_CLASS}\n >\n {t.forgotPassword}\n </AuthLink>\n }\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n disabled={!email.trim() || !password}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.noAccount}{\" \"}\n <AuthLink\n to={withInviteToken(registerUrl, invite)}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.register}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// The heading lives in AuthLayout, above the card, so the screen — not the\n// form — passes the copy. Exposing the defaults here keeps the wording in one\n// place: `<AuthLayout {...LoginForm.defaults}>` renders what the form used to.\nLoginForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","import type { AuthClientResult } from \"./types\"\n\n/**\n * Whether a failed sign-in was refused for want of a confirmed address.\n *\n * Better Auth answers an unverified sign-in with EMAIL_NOT_VERIFIED, but only\n * when built with its error codes exposed; otherwise the refusal arrives as a\n * bare 403. No other credential failure on this route uses that status — a\n * wrong password is a 401 — so the status alone is a safe fallback.\n */\nexport function isEmailNotVerified(\n error: AuthClientResult[\"error\"],\n): boolean {\n if (!error) return false\n return error.code === \"EMAIL_NOT_VERIFIED\" || error.status === 403\n}\n","interface AuthAlertProps {\n children?: string\n tone?: \"error\" | \"success\"\n}\n\n/**\n * Inline feedback for an auth screen.\n *\n * `role=\"alert\"` on the wrapper is not enough on its own: the node has to be\n * in the tree before the text lands in it for the live region to fire, which\n * is why the element renders empty rather than being mounted with its message.\n *\n * The success tone uses the theme's own tokens rather than a fixed green,\n * which would sit on a dark surface as an unreadable pale block.\n */\nexport function AuthAlert({ children, tone = \"error\" }: AuthAlertProps) {\n return (\n <div\n role={tone === \"error\" ? \"alert\" : \"status\"}\n aria-live={tone === \"error\" ? \"assertive\" : \"polite\"}\n className={\n children\n ? [\n \"rounded-lg border px-3.5 py-3 text-sm leading-snug\",\n tone === \"error\"\n ? \"border-destructive/25 bg-destructive/10 text-destructive\"\n : \"border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400\",\n ].join(\" \")\n : undefined\n }\n >\n {children}\n </div>\n )\n}\n","const LABELS: Record<string, string> = {\n google: \"Continuer avec Google\",\n github: \"Continuer avec GitHub\",\n}\n\ninterface SocialButtonsProps {\n providers: Array<\"google\" | \"github\">\n onSelect: (provider: \"google\" | \"github\") => void | Promise<void>\n disabled?: boolean\n /** Divider text between the password form and the providers */\n separator?: string\n /** Per-provider button copy, merged over the French defaults */\n labels?: Partial<Record<\"google\" | \"github\", string>>\n}\n\nexport function SocialButtons({\n providers,\n onSelect,\n disabled = false,\n separator = \"ou\",\n labels,\n}: SocialButtonsProps) {\n if (providers.length === 0) return null\n\n const copy = { ...LABELS, ...labels }\n\n return (\n <div className=\"space-y-4\">\n {/* The rule is two flex segments rather than a line behind an opaque\n label: an opaque background only hides the rule when it matches the\n surface behind it, which breaks the moment this sits on a card. */}\n <div aria-hidden=\"true\" className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border\" />\n <span className=\"text-[11px] uppercase tracking-[0.14em] text-muted-foreground\">\n {separator}\n </span>\n <span className=\"h-px flex-1 bg-border\" />\n </div>\n\n {/* One per row while there is space for the wording, side by side once\n there are several: in a half-card the full label no longer fits, and\n a truncated \"Continuer avec…\" says less than the mark alone. The\n wording stays as the accessible name either way. */}\n <div\n className={\n providers.length > 1\n ? \"grid gap-2.5 sm:grid-cols-2\"\n : \"grid gap-2.5\"\n }\n >\n {providers.map((provider) => (\n <button\n key={provider}\n type=\"button\"\n onClick={() => onSelect(provider)}\n disabled={disabled}\n aria-label={copy[provider] ?? provider}\n className={[\n \"flex h-[52px] w-full items-center justify-center gap-2.5 rounded-lg sm:h-11\",\n \"border border-foreground/25 bg-background text-base font-medium text-foreground sm:text-sm\",\n \"transition-[background-color,border-color,transform] duration-150 ease-out\",\n \"hover:border-foreground/20 hover:bg-accent active:translate-y-px\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:pointer-events-none disabled:opacity-55\",\n ].join(\" \")}\n >\n <ProviderMark provider={provider} />\n <span className={providers.length > 1 ? \"sm:hidden\" : \"\"}>\n {copy[provider] ?? provider}\n </span>\n </button>\n ))}\n </div>\n </div>\n )\n}\n\n// Brand marks are inlined: they must keep their own colors (Google's mark is\n// unusable in monochrome) and adding an icon dependency to this package would\n// duplicate one every consumer already ships.\nfunction ProviderMark({ provider }: { provider: \"google\" | \"github\" }) {\n if (provider === \"google\") {\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 18 18\" aria-hidden=\"true\">\n <path\n fill=\"#4285F4\"\n d=\"M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z\"\n />\n <path\n fill=\"#34A853\"\n d=\"M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.02-3.7H.96v2.33A9 9 0 0 0 9 18Z\"\n />\n <path\n fill=\"#FBBC05\"\n d=\"M3.98 10.72a5.4 5.4 0 0 1 0-3.44V4.95H.96a9 9 0 0 0 0 8.1l3.02-2.33Z\"\n />\n <path\n fill=\"#EA4335\"\n d=\"M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.02 2.33C4.68 5.16 6.66 3.58 9 3.58Z\"\n />\n </svg>\n )\n }\n return (\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.38l-.01-1.49c-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.4 7.4 0 0 1 4 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48l-.01 2.2c0 .21.15.46.55.38A8 8 0 0 0 8 0Z\" />\n </svg>\n )\n}\n","import type { ReactNode } from \"react\"\nimport type { LinkComponent } from \"../types\"\n\ninterface AuthLinkProps {\n to: string\n as?: LinkComponent\n className?: string\n children: ReactNode\n}\n\n/**\n * A link between auth screens.\n *\n * Falls back to an anchor, which is right for an app without a router and wrong\n * for every app with one: the full page load it triggers restarts the app and\n * loses whatever the URL was carrying.\n */\nexport function AuthLink({ to, as: Link, className, children }: AuthLinkProps) {\n if (Link) {\n return (\n <Link to={to} className={className}>\n {children}\n </Link>\n )\n }\n return (\n <a href={to} className={className}>\n {children}\n </a>\n )\n}\n\nexport const AUTH_LINK_CLASS =\n \"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n\nexport const AUTH_HINT_LINK_CLASS =\n \"rounded text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n","/**\n * An invitation token as it may appear in a URL, reduced to something safe to\n * carry through a route search schema.\n *\n * Callers pass raw search params (`Route.validateSearch`), so the input is\n * whatever the address bar held: an array when the param repeats, a number, or\n * a string long enough to be an attack rather than a token. Anything that is\n * not one plausible token collapses to undefined, which reads as \"no\n * invitation\" everywhere downstream.\n */\nconst MAX_TOKEN_LENGTH = 128\n\nexport function normalizeInviteToken(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined\n const trimmed = value.trim()\n if (!trimmed || trimmed.length > MAX_TOKEN_LENGTH) return undefined\n return trimmed\n}\n\n/**\n * Appends the invitation to a link between auth screens.\n *\n * An invitee who lands on /register and clicks through to /login must keep the\n * offer: the token lives only in the URL, so a plain href to the sibling screen\n * silently drops it and the account is created on the default tier.\n */\nexport function withInviteToken(href: string, token?: string): string {\n if (!token) return href\n const separator = href.includes(\"?\") ? \"&\" : \"?\"\n return `${href}${separator}invite=${encodeURIComponent(token)}`\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport { withInviteToken } from \"../invite-token\"\nimport type { RegisterFormLabels, RegisterFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\nimport { SocialButtons } from \"./social-buttons\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<RegisterFormLabels> = {\n title: \"Créer un compte\",\n subtitle: \"Nous t'enverrons un code pour confirmer ton adresse e-mail.\",\n namePlaceholder: \"Nom complet\",\n emailPlaceholder: \"Adresse e-mail\",\n passwordPlaceholder: \"Mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n confirmPlaceholder: \"Confirme le mot de passe\",\n passwordMismatch: \"Les deux mots de passe ne correspondent pas\",\n submit: \"Créer mon compte\",\n submitPending: \"Création…\",\n haveAccount: \"Tu as déjà un compte ?\",\n login: \"Se connecter\",\n nameRequired: \"Renseigne ton nom\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n signUpFailed: \"La création du compte a échoué\",\n}\n\nexport function RegisterForm({\n onSuccess,\n loginUrl = \"/login\",\n legal,\n socialCallbackUrl = \"/\",\n socialProviders = [],\n labels,\n submitClassName,\n fieldClassName,\n error: externalError,\n linkComponent,\n invite,\n authClient,\n}: RegisterFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [name, setName] = useState(\"\")\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [ownError, setOwnError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n // What the person just did outranks what happened before they arrived.\n const error = ownError ?? externalError\n const setError = setOwnError\n\n const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH\n const mismatch = confirmPassword.length > 0 && confirmPassword !== password\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!name.trim()) {\n setError(t.nameRequired)\n return\n }\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n if (password !== confirmPassword) {\n setError(t.passwordMismatch)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.signUp.email({\n name: name.trim(),\n email: email.trim(),\n password,\n })\n if (res?.error) {\n setError(res.error.message ?? t.signUpFailed)\n return\n }\n // createPlatformAuth sets requireEmailVerification, so sign-up leaves the\n // account unverified and without a session: the caller routes to the OTP\n // step rather than into the app.\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n const handleSocial = async (provider: \"google\" | \"github\") => {\n setError(undefined)\n try {\n await authClient.signIn.social({\n provider,\n // The invitation rides the callback: an OAuth sign-up leaves the\n // browser, and the auth handler redeems the token on the way back.\n callbackURL: withInviteToken(socialCallbackUrl, invite),\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.namePlaceholder}\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"name\"\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n description={t.passwordHint}\n // Only once they have typed something: flagging an untouched field\n // red would scold someone for not having started yet.\n invalid={tooShort}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.confirmPlaceholder}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n invalid={mismatch}\n fieldClassName={fieldClassName}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n\n {legal && (\n <p className=\"text-center text-xs leading-relaxed text-muted-foreground\">\n {legal}\n </p>\n )}\n </form>\n\n <SocialButtons\n providers={socialProviders}\n onSelect={handleSocial}\n disabled={isPending}\n />\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.haveAccount}{\" \"}\n <AuthLink\n to={withInviteToken(loginUrl, invite)}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nRegisterForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type { VerifyEmailFormLabels, VerifyEmailFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthOtpField, OTP_LENGTH } from \"./auth-otp-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst DEFAULTS: Required<VerifyEmailFormLabels> = {\n title: \"Vérifie ton adresse\",\n subtitle: \"Entre le code à 6 chiffres envoyé à\",\n subtitleNoEmail: \"Entre le code à 6 chiffres reçu par e-mail.\",\n codePlaceholder: \"Code de vérification\",\n submit: \"Vérifier\",\n submitPending: \"Vérification…\",\n resend: \"Renvoyer le code\",\n resendPending: \"Envoi…\",\n resent: \"Un nouveau code vient de t'être envoyé.\",\n alreadyVerified: \"Adresse déjà vérifiée ?\",\n login: \"Se connecter\",\n codeRequired: \"Entre le code à 6 chiffres\",\n invalidCode: \"Code invalide. Réessaie.\",\n resendFailed: \"L'envoi du code a échoué\",\n missingEmail: \"Adresse e-mail introuvable. Recommence l'inscription.\",\n}\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: VerifyEmailFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [otp, setOtp] = useState(\"\")\n const [isVerifying, setIsVerifying] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n const [error, setError] = useState<string | undefined>()\n\n const handleVerify = async (e: FormEvent) => {\n e.preventDefault()\n if (otp.length < OTP_LENGTH) {\n setError(t.codeRequired)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n if (res?.error) {\n setError(res.error.message ?? t.invalidCode)\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.invalidCode)\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(t.missingEmail)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"email-verification\",\n })\n setResendMessage(t.resent)\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resendFailed)\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n <AuthAlert tone=\"success\">{resendMessage}</AuthAlert>\n\n <form onSubmit={handleVerify} className=\"space-y-[1.125rem]\" noValidate>\n <AuthOtpField\n id=\"verify-email-otp\"\n label={t.codePlaceholder}\n value={otp}\n onChange={setOtp}\n disabled={isVerifying}\n fieldClassName={fieldClassName}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isVerifying}\n disabled={otp.length < OTP_LENGTH}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <div className=\"space-y-4 text-center text-sm text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55\"\n >\n {isResending ? t.resendPending : t.resend}\n </button>\n\n <p>\n {t.alreadyVerified}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nVerifyEmailForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","interface AuthOtpFieldProps {\n label: string\n value: string\n onChange: (value: string) => void\n disabled?: boolean\n invalid?: boolean\n id: string\n /** Replaces the default border and background utilities */\n fieldClassName?: string\n}\n\nexport const OTP_LENGTH = 6\n\n/**\n * The 6-digit code field.\n *\n * Not an AuthField: the value is a code being read off another screen, so it\n * is spaced and monospaced to be checked digit by digit, and non-digits are\n * dropped on the way in — pasting a code from a mail client routinely carries\n * a trailing space.\n */\nexport function AuthOtpField({\n label,\n value,\n onChange,\n disabled = false,\n invalid = false,\n id,\n fieldClassName = \"border-foreground/25 bg-background\",\n}: AuthOtpFieldProps) {\n return (\n <div className=\"space-y-2\">\n <label\n htmlFor={id}\n className=\"block text-sm font-medium leading-none text-foreground\"\n >\n {label}\n </label>\n <input\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={OTP_LENGTH}\n value={value}\n onChange={(e) => onChange(e.target.value.replace(/\\D/g, \"\"))}\n required\n disabled={disabled}\n autoComplete=\"one-time-code\"\n aria-invalid={invalid || undefined}\n className={[\n \"h-[52px] w-full rounded-lg border px-4 sm:h-11\",\n \"text-center font-mono text-lg tracking-[0.4em]\",\n \"text-foreground\",\n \"transition-[border-color,box-shadow] duration-150 ease-out\",\n \"focus-visible:outline-none focus-visible:ring-[3px]\",\n invalid\n ? \"border-destructive bg-background focus-visible:border-destructive focus-visible:ring-destructive/20\"\n : `${fieldClassName} focus-visible:border-ring focus-visible:ring-ring/15`,\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n ].join(\" \")}\n />\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type {\n ForgotPasswordFormLabels,\n ForgotPasswordFormProps,\n} from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst DEFAULTS: Required<ForgotPasswordFormLabels> = {\n title: \"Mot de passe oublié ?\",\n subtitle:\n \"Entre ton adresse e-mail et nous t'enverrons un code pour le réinitialiser.\",\n emailPlaceholder: \"Adresse e-mail\",\n submit: \"Envoyer le code\",\n submitPending: \"Envoi…\",\n rememberPassword: \"Tu t'en souviens finalement ?\",\n login: \"Se connecter\",\n emailRequired: \"Renseigne ton adresse e-mail\",\n sendFailed: \"L'envoi du code a échoué\",\n}\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: ForgotPasswordFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!email.trim()) {\n setError(t.emailRequired)\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email: email.trim(),\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? t.sendFailed)\n return\n }\n onSuccess?.(email.trim())\n } catch (err) {\n setError(err instanceof Error ? err.message : t.sendFailed)\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthField\n label={t.emailPlaceholder}\n type=\"email\"\n inputMode=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isPending}\n autoComplete=\"email\"\n autoCapitalize=\"none\"\n spellCheck={false}\n invalid={!!error}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isPending}\n disabled={!email.trim()}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t.rememberPassword}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nForgotPasswordForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","import { useState, type FormEvent } from \"react\"\nimport { AUTH_LINK_CLASS, AuthLink } from \"./auth-link\"\nimport type { ResetPasswordFormLabels, ResetPasswordFormProps } from \"../types\"\nimport { AuthAlert } from \"./auth-alert\"\nimport { AuthField } from \"./auth-field\"\nimport { AuthOtpField, OTP_LENGTH } from \"./auth-otp-field\"\nimport { AuthSubmit } from \"./auth-submit\"\n\nconst MIN_PASSWORD_LENGTH = 8\n\nconst DEFAULTS: Required<ResetPasswordFormLabels> = {\n title: \"Nouveau mot de passe\",\n subtitle: \"Entre le code à 6 chiffres reçu par e-mail et ton nouveau mot de passe.\",\n codePlaceholder: \"Code de vérification\",\n passwordPlaceholder: \"Nouveau mot de passe\",\n passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caractères.`,\n confirmPlaceholder: \"Confirme le mot de passe\",\n submit: \"Réinitialiser\",\n submitPending: \"Réinitialisation…\",\n resend: \"Renvoyer le code\",\n resendPending: \"Envoi…\",\n resent: \"Un nouveau code vient de t'être envoyé.\",\n rememberPassword: \"Tu t'en souviens finalement ?\",\n login: \"Se connecter\",\n codeRequired: \"Entre le code à 6 chiffres\",\n passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caractères`,\n passwordMismatch: \"Les deux mots de passe ne correspondent pas\",\n resetFailed: \"La réinitialisation a échoué\",\n resendFailed: \"L'envoi du code a échoué\",\n}\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n labels,\n submitClassName,\n fieldClassName,\n linkComponent,\n authClient,\n}: ResetPasswordFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [otp, setOtp] = useState(\"\")\n const [password, setPassword] = useState(\"\")\n const [confirmPassword, setConfirmPassword] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n const [isResetting, setIsResetting] = useState(false)\n const [isResending, setIsResending] = useState(false)\n const [resendMessage, setResendMessage] = useState<string | undefined>()\n\n const tooShort = password.length > 0 && password.length < MIN_PASSWORD_LENGTH\n const mismatch = confirmPassword.length > 0 && confirmPassword !== password\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (otp.length < OTP_LENGTH) {\n setError(t.codeRequired)\n return\n }\n if (password.length < MIN_PASSWORD_LENGTH) {\n setError(t.passwordTooShort)\n return\n }\n if (password !== confirmPassword) {\n setError(t.passwordMismatch)\n return\n }\n setError(undefined)\n setResendMessage(undefined)\n setIsResetting(true)\n try {\n const res = await fetch(\"/api/auth/email-otp/reset-password\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email, otp, password }),\n })\n if (!res.ok) {\n const body = await res.json().catch(() => null)\n setError(body?.message ?? t.resetFailed)\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resetFailed)\n } finally {\n setIsResetting(false)\n }\n }\n\n const handleResend = async () => {\n setError(undefined)\n setResendMessage(undefined)\n setIsResending(true)\n try {\n await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n setResendMessage(t.resent)\n } catch (err) {\n setError(err instanceof Error ? err.message : t.resendFailed)\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-7\">\n <AuthAlert>{error}</AuthAlert>\n <AuthAlert tone=\"success\">{resendMessage}</AuthAlert>\n\n <form onSubmit={handleSubmit} className=\"space-y-[1.125rem]\" noValidate>\n <AuthOtpField\n id=\"reset-password-otp\"\n label={t.codePlaceholder}\n value={otp}\n onChange={setOtp}\n disabled={isResetting}\n fieldClassName={fieldClassName}\n />\n\n <AuthField\n label={t.passwordPlaceholder}\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n description={t.passwordHint}\n invalid={tooShort}\n />\n\n <AuthField\n label={t.confirmPlaceholder}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n invalid={mismatch}\n />\n\n <AuthSubmit\n spacedAbove\n pending={isResetting}\n disabled={otp.length < OTP_LENGTH || !password || !confirmPassword}\n pendingLabel={t.submitPending}\n className={submitClassName}\n >\n {t.submit}\n </AuthSubmit>\n </form>\n\n <div className=\"space-y-4 text-center text-sm text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"rounded font-medium text-foreground underline underline-offset-4 decoration-foreground/25 transition-colors hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-55\"\n >\n {isResending ? t.resendPending : t.resend}\n </button>\n\n <p>\n {t.rememberPassword}{\" \"}\n <AuthLink\n to={loginUrl}\n as={linkComponent}\n className={AUTH_LINK_CLASS}\n >\n {t.login}\n </AuthLink>\n </p>\n </div>\n </div>\n )\n}\n\n// See LoginForm.defaults.\nResetPasswordForm.defaults = {\n title: DEFAULTS.title,\n subtitle: DEFAULTS.subtitle,\n}\n","interface AuthHeadingProps {\n title: string\n subtitle?: string\n /** Replaces the default size and weight — pass the whole look */\n titleClassName?: string\n}\n\n/**\n * The heading of an auth screen.\n *\n * This screen is the only one someone sees before they have any reason to\n * trust the product, so the type carries it: the title is the screen's centre\n * of gravity, set large and tightly tracked, with the subtitle stepping well\n * back rather than competing.\n *\n * Optical sizing matters at this weight — `text-balance` keeps a two-line\n * subtitle from breaking into a lonely last word, which reads as an accident\n * where everything else is deliberate.\n */\nexport function AuthHeading({\n title,\n subtitle,\n titleClassName = \"text-[2rem] font-semibold leading-[1.1] tracking-[-0.03em] sm:text-[2.25rem]\",\n}: AuthHeadingProps) {\n return (\n <header className=\"space-y-2.5 text-center\">\n <h1 className={`text-foreground ${titleClassName}`}>{title}</h1>\n {subtitle && (\n <p className=\"text-balance text-[0.9375rem] leading-relaxed text-muted-foreground\">\n {subtitle}\n </p>\n )}\n </header>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\nimport { AuthHeading } from \"./auth-heading\"\n\n/**\n * The frame every auth screen sits in. It owns the ground, the heading and the\n * app's own marks (logo, illustration, legal footer); the card holds only the\n * fields and their actions.\n *\n * The heading sits ABOVE the card rather than inside it: the card is then\n * exactly the thing you fill in, and the mark reads as the app's rather than\n * as the form's first row.\n *\n * Mobile and desktop are two layouts, not one scaled down. On a phone the form\n * IS the page: no card, no border, edge-to-edge padding, top-aligned so the\n * fields stay above the keyboard instead of being pushed under it by vertical\n * centering. From sm up it becomes a bounded card on a tinted ground — a\n * full-width form on a 1440px display is unreadable.\n *\n * A `panel` is an app-supplied illustration and nothing else: without one the\n * card stays a single column rather than inventing decoration to fill a half\n * it has no content for. When given, it takes the LEFT half from md up and is\n * dropped below that width — a decorative half-screen above a form costs a\n * full swipe before the first field.\n *\n * min-h-dvh rather than min-h-screen: on mobile browsers 100vh includes the\n * retracting URL bar, so a screen-height container overflows by its height.\n */\nexport function AuthLayout({\n logo,\n panel,\n title,\n subtitle,\n titleClassName,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-dvh flex-col bg-background px-5 pb-12 pt-14 sm:items-center sm:bg-muted/30 sm:px-6 sm:py-20\">\n <div className={`mx-auto w-full ${panel ? \"max-w-4xl\" : \"max-w-[400px]\"}`}>\n {(logo || title) && (\n // The spacing is composed, not repeated: the mark sits close to the\n // title it introduces, and the gap down to the card is the largest\n // on the screen — that step is what separates \"who this is\" from\n // \"what you do here\".\n <div className=\"mb-10 space-y-6\">\n {logo && <div className=\"flex justify-center\">{logo}</div>}\n {title && (\n <AuthHeading\n title={title}\n subtitle={subtitle}\n titleClassName={titleClassName}\n />\n )}\n </div>\n )}\n\n <div\n className={[\n \"sm:rounded-xl sm:border sm:border-foreground/[0.08] sm:bg-card\",\n \"sm:shadow-[0_1px_2px_rgba(0,0,0,0.04),0_8px_24px_-12px_rgba(0,0,0,0.10)]\",\n panel ? \"sm:overflow-hidden md:grid md:grid-cols-2\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {panel && (\n // Decorative: it must never carry information the form does not,\n // so it is hidden from assistive tech rather than described.\n <div\n aria-hidden=\"true\"\n className=\"relative hidden overflow-hidden bg-muted md:block [&>*]:absolute [&>*]:inset-0 [&>*]:h-full [&>*]:w-full [&>img]:object-cover\"\n >\n {panel}\n </div>\n )}\n\n <div className=\"sm:px-7 sm:py-8\">{children}</div>\n </div>\n\n {footer && (\n <div className=\"mt-8 text-center text-xs leading-relaxed text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import type { InvitationNoticeProps } from \"../types\"\n\n/**\n * Every app is reachable at contact@ its own apex domain, so the address is\n * derived rather than configured. Sub-domains are stripped because the app is\n * routinely served from app./admin. while the mailbox lives on the apex;\n * multi-part public suffixes (.co.uk) would need a real suffix list and no app\n * using this is on one.\n */\nfunction defaultSupportEmail(): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const host = window.location.hostname\n if (!host || host === \"localhost\" || /^[\\d.]+$/.test(host)) return undefined\n const apex = host.split(\".\").slice(-2).join(\".\")\n return `contact@${apex}`\n}\n\nconst REASON_MESSAGE: Record<string, string> = {\n expired: \"Cette invitation a expiré.\",\n claimed: \"Cette invitation a déjà été utilisée.\",\n unknown: \"Ce lien d'invitation n'est pas valide.\",\n}\n\n/**\n * What an invitee sees when their link does not work.\n *\n * It names the reason instead of merging the cases into one message: \"expired\"\n * tells someone their link was real and that asking for another one is worth\n * it, which \"invalid\" does not. Short TTLs make that distinction routine.\n *\n * The only way forward offered is a mailto, deliberately. A self-service\n * \"request a new invitation\" form would mean a public endpoint accepting dead\n * tokens, a queue to moderate, and a way to probe which tokens once existed —\n * for a flow where the operator already knows the person by name.\n */\nexport function InvitationNotice({\n reason = \"unknown\",\n supportEmail,\n title = \"Invitation indisponible\",\n action,\n}: InvitationNoticeProps) {\n const contact = supportEmail ?? defaultSupportEmail()\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown}\n </p>\n </div>\n\n {contact ? (\n <p className=\"text-sm text-muted-foreground\">\n Écrivez-nous à{\" \"}\n <a\n href={`mailto:${contact}`}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {contact}\n </a>{\" \"}\n pour en recevoir une nouvelle.\n </p>\n ) : null}\n\n {action}\n </div>\n )\n}\n","export type OAuthErrorLabels = {\n accountNotLinked: string\n socialCancelled: string\n socialFailed: string\n}\n\n/**\n * Turns Better Auth's machine-readable OAuth failure code into something an\n * invitee can act on.\n *\n * `account_not_linked` is the one worth naming: createPlatformAuth disables\n * account linking on purpose, so \"Continue with Google\" on an address already\n * registered with a password is REFUSED. Better Auth's default error route\n * bounces the browser back with nothing shown, so without this the button\n * simply looks broken.\n */\nexport function oauthErrorMessage(\n code: string | null | undefined,\n labels: OAuthErrorLabels,\n): string {\n switch (code) {\n case \"account_not_linked\":\n return labels.accountNotLinked\n case \"access_denied\":\n return labels.socialCancelled\n default:\n return labels.socialFailed\n }\n}\n\n/**\n * Reads the failure Better Auth redirected back with.\n *\n * A social sign-in leaves the app entirely, so component state does not survive\n * it: the only carrier left when the browser returns is the `?error=` Better\n * Auth appends to the errorCallbackURL. Read from the address bar rather than\n * from a typed route search, because the auth routes deliberately declare no\n * search schema — adding one would make `search` required on every navigate to\n * them across the app.\n */\nexport function initialOAuthError(\n labels: OAuthErrorLabels,\n param = \"error\",\n): string | undefined {\n if (typeof window === \"undefined\") return undefined\n const code = new URLSearchParams(window.location.search).get(param)\n if (!code) return undefined\n return oauthErrorMessage(code, labels)\n}\n\n/**\n * Drops the failure from the address bar once it has been shown.\n *\n * Without this the message comes back on every reload, and outlives the retry\n * that succeeded. replaceState rather than a router navigate: these screens\n * have no typed search to navigate against, and the entry being rewritten is\n * the one the OAuth provider pushed, not one the person chose.\n */\nexport function clearOAuthError(param = \"error\"): void {\n if (typeof window === \"undefined\") return\n const url = new URL(window.location.href)\n if (!url.searchParams.has(param)) return\n url.searchParams.delete(param)\n window.history.replaceState({}, \"\", url.toString())\n}\n"],"mappings":"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","names":["jsx","jsxs","useState","jsx","jsx","jsxs","jsx","jsx","jsxs","useState","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","MIN_PASSWORD_LENGTH","DEFAULTS","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Auth, BetterAuthOptions } from 'better-auth';
|
|
2
|
-
import { j as PlatformAuthConfig } from './types-
|
|
3
|
-
export { n as PlatformSession, o as PlatformSessionData, p as PlatformUser } from './types-
|
|
4
|
-
export { a as ClaimInvitationOptions, C as ClaimOutcome, c as claimInvitation, b as completesSignup, h as holdInviteTokenCookie, d as invitationOutcomeCookie, e as inviteTokenFrom, i as isInvitationFailure, p as pinInviteToken, r as releaseInviteTokenCookie } from './invitation-
|
|
2
|
+
import { j as PlatformAuthConfig } from './types-DzG-qaSv.js';
|
|
3
|
+
export { n as PlatformSession, o as PlatformSessionData, p as PlatformUser } from './types-DzG-qaSv.js';
|
|
4
|
+
export { a as ClaimInvitationOptions, C as ClaimOutcome, c as claimInvitation, b as completesSignup, h as holdInviteTokenCookie, d as invitationOutcomeCookie, e as inviteTokenFrom, i as isInvitationFailure, p as pinInviteToken, r as releaseInviteTokenCookie } from './invitation-0CfjrVjI.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a Better Auth instance with platform defaults.
|
|
@@ -175,6 +175,7 @@ interface LoginFormLabels {
|
|
|
175
175
|
emailRequired?: string;
|
|
176
176
|
passwordRequired?: string;
|
|
177
177
|
invalidCredentials?: string;
|
|
178
|
+
emailNotVerified?: string;
|
|
178
179
|
accountNotLinked?: string;
|
|
179
180
|
socialCancelled?: string;
|
|
180
181
|
socialFailed?: string;
|
|
@@ -301,6 +302,15 @@ interface AuthInviteProps {
|
|
|
301
302
|
interface LoginFormProps extends AuthThemeProps, AuthNavProps, AuthInviteProps {
|
|
302
303
|
/** Callback once the session cookie is set and the core token minted */
|
|
303
304
|
onSuccess?: () => void;
|
|
305
|
+
/**
|
|
306
|
+
* Called with the typed address when the credentials are right but the
|
|
307
|
+
* account never confirmed its email — `createPlatformAuth` sets
|
|
308
|
+
* `requireEmailVerification`, so that sign-in is refused and no session is
|
|
309
|
+
* created. Route to the OTP screen, as `RegisterForm.onSuccess` does. Left
|
|
310
|
+
* unset, the refusal is rendered as an error like any other, which reads as
|
|
311
|
+
* a wrong password.
|
|
312
|
+
*/
|
|
313
|
+
onEmailNotVerified?: (email: string) => void;
|
|
304
314
|
/**
|
|
305
315
|
* Error raised outside the form — a failed OAuth round-trip coming back as
|
|
306
316
|
* `?error=`, a guard bouncing an unauthenticated visitor. Rendered in the
|
|
@@ -423,4 +433,4 @@ interface AuthLayoutProps extends AuthHeadingProps {
|
|
|
423
433
|
footer?: React.ReactNode;
|
|
424
434
|
}
|
|
425
435
|
|
|
426
|
-
export type { AuthLayoutProps as A, ForgotPasswordFormProps as F, InvitationNoticeProps as I, LoginFormProps as L, PlatformAuthClientConfig as P, RegisterFormProps as R, VerifyEmailFormProps as V, ResetPasswordFormProps as a,
|
|
436
|
+
export type { AuthLayoutProps as A, ForgotPasswordFormProps as F, InvitationNoticeProps as I, LoginFormProps as L, PlatformAuthClientConfig as P, RegisterFormProps as R, VerifyEmailFormProps as V, ResetPasswordFormProps as a, AuthClientResult as b, LinkComponent as c, AuthClientSurface as d, AuthInviteProps as e, AuthNavProps as f, AuthThemeProps as g, InvitationFailure as h, LoginFormLabels as i, PlatformAuthConfig as j, PlatformAuthMailer as k, PlatformAuthMailerArgs as l, PlatformAuthMailerType as m, PlatformSession as n, PlatformSessionData as o, PlatformUser as p, RegisterFormLabels as q };
|