@lalternative/auth 0.4.1 → 0.4.3
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/README.md +3 -2
- package/dist/client.d.ts +1 -1
- package/dist/index.d.ts +19 -4
- package/dist/index.js +454 -74
- package/dist/index.js.map +1 -1
- package/dist/{invitation-DIZAb2BJ.d.ts → invitation-Bucmin-z.d.ts} +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/{types-DKEKNQkL.d.ts → types-BXyGxKtF.d.ts} +80 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Shared [Better Auth](https://better-auth.com) wrapper for L'Alternative apps.
|
|
4
4
|
|
|
5
5
|
Provides platform auth defaults (email-OTP + admin plugins), a React client,
|
|
6
|
-
and the auth UI forms (verify-email, forgot/reset password,
|
|
6
|
+
and the auth UI forms (login, register, verify-email, forgot/reset password,
|
|
7
|
+
auth layout).
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
|
|
@@ -32,7 +33,7 @@ export const authClient = createPlatformAuthClient({ baseURL })
|
|
|
32
33
|
|
|
33
34
|
```tsx
|
|
34
35
|
// UI + hooks
|
|
35
|
-
import { VerifyEmailForm, ForgotPasswordForm, ResetPasswordForm, AuthLayout, useSession, useLogout } from "@lalternative/auth"
|
|
36
|
+
import { LoginForm, RegisterForm, SocialButtons, VerifyEmailForm, ForgotPasswordForm, ResetPasswordForm, AuthLayout, useSession, useLogout } from "@lalternative/auth"
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
### Invitations
|
package/dist/client.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { V as VerifyEmailFormProps, F as ForgotPasswordFormProps,
|
|
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 } from './types-BXyGxKtF.js';
|
|
2
|
+
export { b as InvitationFailure, c as LoginFormLabels, P as PlatformAuthClientConfig, d as PlatformAuthConfig, e as PlatformAuthMailer, f as PlatformAuthMailerArgs, g as PlatformAuthMailerType, h as PlatformSession, i as PlatformSessionData, j as PlatformUser, k as RegisterFormLabels } from './types-BXyGxKtF.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
|
-
export { C as ClaimOutcome, i as isInvitationFailure } from './invitation-
|
|
7
|
+
export { C as ClaimOutcome, i as isInvitationFailure } from './invitation-Bucmin-z.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Returns a useSession hook bound to the given auth client.
|
|
@@ -45,6 +45,21 @@ declare function useSession(authClient: PlatformAuthClient): {
|
|
|
45
45
|
*/
|
|
46
46
|
declare function useLogout(authClient: PlatformAuthClient): () => Promise<void>;
|
|
47
47
|
|
|
48
|
+
declare function LoginForm({ onSuccess, registerUrl, forgotPasswordUrl, socialCallbackUrl, socialProviders, coreTokenUrl, labels, authClient, }: LoginFormProps): react.JSX.Element;
|
|
49
|
+
|
|
50
|
+
declare function RegisterForm({ onSuccess, loginUrl, legal, socialCallbackUrl, socialProviders, labels, authClient, }: RegisterFormProps): react.JSX.Element;
|
|
51
|
+
|
|
52
|
+
interface SocialButtonsProps {
|
|
53
|
+
providers: Array<"google" | "github">;
|
|
54
|
+
onSelect: (provider: "google" | "github") => void | Promise<void>;
|
|
55
|
+
disabled?: boolean;
|
|
56
|
+
/** Divider text between the password form and the providers */
|
|
57
|
+
separator?: string;
|
|
58
|
+
/** Per-provider button copy, merged over the French defaults */
|
|
59
|
+
labels?: Partial<Record<"google" | "github", string>>;
|
|
60
|
+
}
|
|
61
|
+
declare function SocialButtons({ providers, onSelect, disabled, separator, labels, }: SocialButtonsProps): react.JSX.Element | null;
|
|
62
|
+
|
|
48
63
|
declare function VerifyEmailForm({ email, onSuccess, authClient, }: VerifyEmailFormProps): react.JSX.Element;
|
|
49
64
|
|
|
50
65
|
declare function ForgotPasswordForm({ onSuccess, loginUrl, authClient, }: ForgotPasswordFormProps): react.JSX.Element;
|
|
@@ -67,4 +82,4 @@ declare function AuthLayout({ logo, title, subtitle, children, footer, }: AuthLa
|
|
|
67
82
|
*/
|
|
68
83
|
declare function InvitationNotice({ reason, supportEmail, title, action, }: InvitationNoticeProps): react.JSX.Element;
|
|
69
84
|
|
|
70
|
-
export { AuthLayout, AuthLayoutProps, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, ResetPasswordForm, ResetPasswordFormProps, VerifyEmailForm, VerifyEmailFormProps, useLogout, useSession };
|
|
85
|
+
export { AuthLayout, AuthLayoutProps, ForgotPasswordForm, ForgotPasswordFormProps, InvitationNotice, InvitationNoticeProps, LoginForm, LoginFormProps, RegisterForm, RegisterFormProps, ResetPasswordForm, ResetPasswordFormProps, SocialButtons, VerifyEmailForm, VerifyEmailFormProps, useLogout, useSession };
|
package/dist/index.js
CHANGED
|
@@ -13,19 +13,396 @@ function useLogout(authClient) {
|
|
|
13
13
|
return signOut;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
// src/components/
|
|
16
|
+
// src/components/login-form.tsx
|
|
17
17
|
import { useState } from "react";
|
|
18
|
-
|
|
18
|
+
|
|
19
|
+
// src/components/social-buttons.tsx
|
|
20
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
var LABELS = {
|
|
22
|
+
google: "Continuer avec Google",
|
|
23
|
+
github: "Continuer avec GitHub"
|
|
24
|
+
};
|
|
25
|
+
function SocialButtons({
|
|
26
|
+
providers,
|
|
27
|
+
onSelect,
|
|
28
|
+
disabled = false,
|
|
29
|
+
separator = "ou",
|
|
30
|
+
labels
|
|
31
|
+
}) {
|
|
32
|
+
if (providers.length === 0) return null;
|
|
33
|
+
const copy = { ...LABELS, ...labels };
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
35
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
36
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx("div", { className: "w-full border-t border-input" }) }),
|
|
37
|
+
/* @__PURE__ */ jsx("div", { className: "relative flex justify-center", children: /* @__PURE__ */ jsx("span", { className: "bg-background px-2 text-xs uppercase tracking-wider text-muted-foreground", children: separator }) })
|
|
38
|
+
] }),
|
|
39
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: providers.map((provider) => /* @__PURE__ */ jsx(
|
|
40
|
+
"button",
|
|
41
|
+
{
|
|
42
|
+
type: "button",
|
|
43
|
+
onClick: () => onSelect(provider),
|
|
44
|
+
disabled,
|
|
45
|
+
className: "inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50",
|
|
46
|
+
children: copy[provider] ?? provider
|
|
47
|
+
},
|
|
48
|
+
provider
|
|
49
|
+
)) })
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/components/login-form.tsx
|
|
54
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
55
|
+
var DEFAULTS = {
|
|
56
|
+
title: "Connexion",
|
|
57
|
+
subtitle: "Content de te revoir. Entre tes identifiants pour continuer.",
|
|
58
|
+
emailPlaceholder: "Adresse e-mail",
|
|
59
|
+
passwordPlaceholder: "Mot de passe",
|
|
60
|
+
forgotPassword: "Mot de passe oubli\xE9 ?",
|
|
61
|
+
submit: "Se connecter",
|
|
62
|
+
submitPending: "Connexion\u2026",
|
|
63
|
+
noAccount: "Pas encore de compte ?",
|
|
64
|
+
register: "Cr\xE9er un compte",
|
|
65
|
+
emailRequired: "Renseigne ton adresse e-mail",
|
|
66
|
+
passwordRequired: "Renseigne ton mot de passe",
|
|
67
|
+
invalidCredentials: "Adresse e-mail ou mot de passe incorrect",
|
|
68
|
+
// accountLinking is disabled in createPlatformAuth, so a social sign-in on an
|
|
69
|
+
// address already registered with a password is refused with this code.
|
|
70
|
+
// Without a message the button reads as broken rather than as a rejection.
|
|
71
|
+
accountNotLinked: "Cette adresse est d\xE9j\xE0 associ\xE9e \xE0 un mot de passe. Connecte-toi avec ton mot de passe.",
|
|
72
|
+
socialCancelled: "Connexion annul\xE9e.",
|
|
73
|
+
socialFailed: "La connexion a \xE9chou\xE9. R\xE9essaie."
|
|
74
|
+
};
|
|
75
|
+
function LoginForm({
|
|
76
|
+
onSuccess,
|
|
77
|
+
registerUrl = "/register",
|
|
78
|
+
forgotPasswordUrl = "/forgot-password",
|
|
79
|
+
socialCallbackUrl = "/",
|
|
80
|
+
socialProviders = [],
|
|
81
|
+
coreTokenUrl = "/api/auth/core-token",
|
|
82
|
+
labels,
|
|
83
|
+
authClient
|
|
84
|
+
}) {
|
|
85
|
+
const t = { ...DEFAULTS, ...labels };
|
|
86
|
+
const [email, setEmail] = useState("");
|
|
87
|
+
const [password, setPassword] = useState("");
|
|
88
|
+
const [error, setError] = useState();
|
|
89
|
+
const [isPending, setIsPending] = useState(false);
|
|
90
|
+
const handleSubmit = async (e) => {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
if (!email.trim()) {
|
|
93
|
+
setError(t.emailRequired);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!password) {
|
|
97
|
+
setError(t.passwordRequired);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setError(void 0);
|
|
101
|
+
setIsPending(true);
|
|
102
|
+
try {
|
|
103
|
+
const res = await authClient.signIn.email({
|
|
104
|
+
email: email.trim(),
|
|
105
|
+
password
|
|
106
|
+
});
|
|
107
|
+
if (res?.error) {
|
|
108
|
+
setError(res.error.message ?? t.invalidCredentials);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (coreTokenUrl) {
|
|
112
|
+
await fetch(coreTokenUrl, { credentials: "include" });
|
|
113
|
+
}
|
|
114
|
+
onSuccess?.();
|
|
115
|
+
} catch (err) {
|
|
116
|
+
setError(err instanceof Error ? err.message : t.invalidCredentials);
|
|
117
|
+
} finally {
|
|
118
|
+
setIsPending(false);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const handleSocial = async (provider) => {
|
|
122
|
+
setError(void 0);
|
|
123
|
+
try {
|
|
124
|
+
await authClient.signIn.social({
|
|
125
|
+
provider,
|
|
126
|
+
callbackURL: socialCallbackUrl
|
|
127
|
+
});
|
|
128
|
+
} catch (err) {
|
|
129
|
+
const code = err instanceof Error ? err.message : "";
|
|
130
|
+
setError(
|
|
131
|
+
code === "account_not_linked" ? t.accountNotLinked : code === "access_denied" ? t.socialCancelled : t.socialFailed
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
return /* @__PURE__ */ jsxs2("div", { className: "space-y-8", children: [
|
|
136
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
137
|
+
/* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight", children: t.title }),
|
|
138
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-muted-foreground", children: t.subtitle })
|
|
139
|
+
] }),
|
|
140
|
+
error && /* @__PURE__ */ jsx2(
|
|
141
|
+
"div",
|
|
142
|
+
{
|
|
143
|
+
role: "alert",
|
|
144
|
+
className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
145
|
+
children: error
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
/* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
149
|
+
/* @__PURE__ */ jsx2(
|
|
150
|
+
"input",
|
|
151
|
+
{
|
|
152
|
+
type: "email",
|
|
153
|
+
value: email,
|
|
154
|
+
onChange: (e) => setEmail(e.target.value),
|
|
155
|
+
placeholder: t.emailPlaceholder,
|
|
156
|
+
"aria-label": t.emailPlaceholder,
|
|
157
|
+
required: true,
|
|
158
|
+
disabled: isPending,
|
|
159
|
+
autoComplete: "email",
|
|
160
|
+
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
161
|
+
}
|
|
162
|
+
),
|
|
163
|
+
/* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
|
|
164
|
+
/* @__PURE__ */ jsx2(
|
|
165
|
+
"input",
|
|
166
|
+
{
|
|
167
|
+
type: "password",
|
|
168
|
+
value: password,
|
|
169
|
+
onChange: (e) => setPassword(e.target.value),
|
|
170
|
+
placeholder: t.passwordPlaceholder,
|
|
171
|
+
"aria-label": t.passwordPlaceholder,
|
|
172
|
+
required: true,
|
|
173
|
+
disabled: isPending,
|
|
174
|
+
autoComplete: "current-password",
|
|
175
|
+
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
176
|
+
}
|
|
177
|
+
),
|
|
178
|
+
/* @__PURE__ */ jsx2("div", { className: "text-right", children: /* @__PURE__ */ jsx2(
|
|
179
|
+
"a",
|
|
180
|
+
{
|
|
181
|
+
href: forgotPasswordUrl,
|
|
182
|
+
className: "text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground",
|
|
183
|
+
children: t.forgotPassword
|
|
184
|
+
}
|
|
185
|
+
) })
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ jsx2(
|
|
188
|
+
"button",
|
|
189
|
+
{
|
|
190
|
+
type: "submit",
|
|
191
|
+
disabled: isPending || !email.trim() || !password,
|
|
192
|
+
className: "inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50",
|
|
193
|
+
children: isPending ? t.submitPending : t.submit
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
] }),
|
|
197
|
+
/* @__PURE__ */ jsx2(
|
|
198
|
+
SocialButtons,
|
|
199
|
+
{
|
|
200
|
+
providers: socialProviders,
|
|
201
|
+
onSelect: handleSocial,
|
|
202
|
+
disabled: isPending
|
|
203
|
+
}
|
|
204
|
+
),
|
|
205
|
+
/* @__PURE__ */ jsxs2("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
206
|
+
t.noAccount,
|
|
207
|
+
" ",
|
|
208
|
+
/* @__PURE__ */ jsx2(
|
|
209
|
+
"a",
|
|
210
|
+
{
|
|
211
|
+
href: registerUrl,
|
|
212
|
+
className: "font-medium text-foreground underline underline-offset-4 hover:text-foreground/80",
|
|
213
|
+
children: t.register
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] })
|
|
217
|
+
] });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/components/register-form.tsx
|
|
221
|
+
import { useState as useState2 } from "react";
|
|
222
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
223
|
+
var MIN_PASSWORD_LENGTH = 8;
|
|
224
|
+
var DEFAULTS2 = {
|
|
225
|
+
title: "Cr\xE9er un compte",
|
|
226
|
+
subtitle: "Nous t'enverrons un code pour confirmer ton adresse e-mail.",
|
|
227
|
+
namePlaceholder: "Nom complet",
|
|
228
|
+
emailPlaceholder: "Adresse e-mail",
|
|
229
|
+
passwordPlaceholder: "Mot de passe",
|
|
230
|
+
passwordHint: `Au moins ${MIN_PASSWORD_LENGTH} caract\xE8res.`,
|
|
231
|
+
submit: "Cr\xE9er mon compte",
|
|
232
|
+
submitPending: "Cr\xE9ation\u2026",
|
|
233
|
+
haveAccount: "Tu as d\xE9j\xE0 un compte ?",
|
|
234
|
+
login: "Se connecter",
|
|
235
|
+
nameRequired: "Renseigne ton nom",
|
|
236
|
+
emailRequired: "Renseigne ton adresse e-mail",
|
|
237
|
+
passwordTooShort: `Le mot de passe doit faire au moins ${MIN_PASSWORD_LENGTH} caract\xE8res`,
|
|
238
|
+
signUpFailed: "La cr\xE9ation du compte a \xE9chou\xE9"
|
|
239
|
+
};
|
|
240
|
+
function RegisterForm({
|
|
241
|
+
onSuccess,
|
|
242
|
+
loginUrl = "/login",
|
|
243
|
+
legal,
|
|
244
|
+
socialCallbackUrl = "/",
|
|
245
|
+
socialProviders = [],
|
|
246
|
+
labels,
|
|
247
|
+
authClient
|
|
248
|
+
}) {
|
|
249
|
+
const t = { ...DEFAULTS2, ...labels };
|
|
250
|
+
const [name, setName] = useState2("");
|
|
251
|
+
const [email, setEmail] = useState2("");
|
|
252
|
+
const [password, setPassword] = useState2("");
|
|
253
|
+
const [error, setError] = useState2();
|
|
254
|
+
const [isPending, setIsPending] = useState2(false);
|
|
255
|
+
const handleSubmit = async (e) => {
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
if (!name.trim()) {
|
|
258
|
+
setError(t.nameRequired);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (!email.trim()) {
|
|
262
|
+
setError(t.emailRequired);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (password.length < MIN_PASSWORD_LENGTH) {
|
|
266
|
+
setError(t.passwordTooShort);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
setError(void 0);
|
|
270
|
+
setIsPending(true);
|
|
271
|
+
try {
|
|
272
|
+
const res = await authClient.signUp.email({
|
|
273
|
+
name: name.trim(),
|
|
274
|
+
email: email.trim(),
|
|
275
|
+
password
|
|
276
|
+
});
|
|
277
|
+
if (res?.error) {
|
|
278
|
+
setError(res.error.message ?? t.signUpFailed);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
onSuccess?.(email.trim());
|
|
282
|
+
} catch (err) {
|
|
283
|
+
setError(err instanceof Error ? err.message : t.signUpFailed);
|
|
284
|
+
} finally {
|
|
285
|
+
setIsPending(false);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
const handleSocial = async (provider) => {
|
|
289
|
+
setError(void 0);
|
|
290
|
+
try {
|
|
291
|
+
await authClient.signIn.social({
|
|
292
|
+
provider,
|
|
293
|
+
callbackURL: socialCallbackUrl
|
|
294
|
+
});
|
|
295
|
+
} catch (err) {
|
|
296
|
+
setError(err instanceof Error ? err.message : t.signUpFailed);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-8", children: [
|
|
300
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
301
|
+
/* @__PURE__ */ jsx3("h1", { className: "text-2xl font-bold tracking-tight", children: t.title }),
|
|
302
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-muted-foreground", children: t.subtitle })
|
|
303
|
+
] }),
|
|
304
|
+
error && /* @__PURE__ */ jsx3(
|
|
305
|
+
"div",
|
|
306
|
+
{
|
|
307
|
+
role: "alert",
|
|
308
|
+
className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
309
|
+
children: error
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
/* @__PURE__ */ jsxs3("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
313
|
+
/* @__PURE__ */ jsx3(
|
|
314
|
+
"input",
|
|
315
|
+
{
|
|
316
|
+
type: "text",
|
|
317
|
+
value: name,
|
|
318
|
+
onChange: (e) => setName(e.target.value),
|
|
319
|
+
placeholder: t.namePlaceholder,
|
|
320
|
+
"aria-label": t.namePlaceholder,
|
|
321
|
+
required: true,
|
|
322
|
+
disabled: isPending,
|
|
323
|
+
autoComplete: "name",
|
|
324
|
+
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
/* @__PURE__ */ jsx3(
|
|
328
|
+
"input",
|
|
329
|
+
{
|
|
330
|
+
type: "email",
|
|
331
|
+
value: email,
|
|
332
|
+
onChange: (e) => setEmail(e.target.value),
|
|
333
|
+
placeholder: t.emailPlaceholder,
|
|
334
|
+
"aria-label": t.emailPlaceholder,
|
|
335
|
+
required: true,
|
|
336
|
+
disabled: isPending,
|
|
337
|
+
autoComplete: "email",
|
|
338
|
+
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
339
|
+
}
|
|
340
|
+
),
|
|
341
|
+
/* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
|
|
342
|
+
/* @__PURE__ */ jsx3(
|
|
343
|
+
"input",
|
|
344
|
+
{
|
|
345
|
+
type: "password",
|
|
346
|
+
value: password,
|
|
347
|
+
onChange: (e) => setPassword(e.target.value),
|
|
348
|
+
placeholder: t.passwordPlaceholder,
|
|
349
|
+
"aria-label": t.passwordPlaceholder,
|
|
350
|
+
required: true,
|
|
351
|
+
disabled: isPending,
|
|
352
|
+
autoComplete: "new-password",
|
|
353
|
+
"aria-describedby": "register-password-hint",
|
|
354
|
+
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
355
|
+
}
|
|
356
|
+
),
|
|
357
|
+
/* @__PURE__ */ jsx3("p", { id: "register-password-hint", className: "text-xs text-muted-foreground", children: t.passwordHint })
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ jsx3(
|
|
360
|
+
"button",
|
|
361
|
+
{
|
|
362
|
+
type: "submit",
|
|
363
|
+
disabled: isPending,
|
|
364
|
+
className: "inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50",
|
|
365
|
+
children: isPending ? t.submitPending : t.submit
|
|
366
|
+
}
|
|
367
|
+
),
|
|
368
|
+
legal && /* @__PURE__ */ jsx3("div", { className: "text-center text-xs text-muted-foreground", children: legal })
|
|
369
|
+
] }),
|
|
370
|
+
/* @__PURE__ */ jsx3(
|
|
371
|
+
SocialButtons,
|
|
372
|
+
{
|
|
373
|
+
providers: socialProviders,
|
|
374
|
+
onSelect: handleSocial,
|
|
375
|
+
disabled: isPending
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
/* @__PURE__ */ jsxs3("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
379
|
+
t.haveAccount,
|
|
380
|
+
" ",
|
|
381
|
+
/* @__PURE__ */ jsx3(
|
|
382
|
+
"a",
|
|
383
|
+
{
|
|
384
|
+
href: loginUrl,
|
|
385
|
+
className: "font-medium text-foreground underline underline-offset-4 hover:text-foreground/80",
|
|
386
|
+
children: t.login
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
] })
|
|
390
|
+
] });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/components/verify-email-form.tsx
|
|
394
|
+
import { useState as useState3 } from "react";
|
|
395
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
19
396
|
function VerifyEmailForm({
|
|
20
397
|
email,
|
|
21
398
|
onSuccess,
|
|
22
399
|
authClient
|
|
23
400
|
}) {
|
|
24
|
-
const [otp, setOtp] =
|
|
25
|
-
const [isVerifying, setIsVerifying] =
|
|
26
|
-
const [isResending, setIsResending] =
|
|
27
|
-
const [resendMessage, setResendMessage] =
|
|
28
|
-
const [error, setError] =
|
|
401
|
+
const [otp, setOtp] = useState3("");
|
|
402
|
+
const [isVerifying, setIsVerifying] = useState3(false);
|
|
403
|
+
const [isResending, setIsResending] = useState3(false);
|
|
404
|
+
const [resendMessage, setResendMessage] = useState3();
|
|
405
|
+
const [error, setError] = useState3();
|
|
29
406
|
const handleVerify = async (e) => {
|
|
30
407
|
e.preventDefault();
|
|
31
408
|
if (!otp.trim() || otp.length < 6) {
|
|
@@ -68,19 +445,19 @@ function VerifyEmailForm({
|
|
|
68
445
|
setIsResending(false);
|
|
69
446
|
}
|
|
70
447
|
};
|
|
71
|
-
return /* @__PURE__ */
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
/* @__PURE__ */
|
|
74
|
-
/* @__PURE__ */
|
|
448
|
+
return /* @__PURE__ */ jsxs4("div", { className: "space-y-8", children: [
|
|
449
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
450
|
+
/* @__PURE__ */ jsx4("h1", { className: "text-2xl font-bold tracking-tight", children: "Verify your email" }),
|
|
451
|
+
/* @__PURE__ */ jsx4("p", { className: "mt-1 text-sm text-muted-foreground", children: email ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
75
452
|
"Enter the 6-digit code sent to",
|
|
76
453
|
" ",
|
|
77
|
-
/* @__PURE__ */
|
|
454
|
+
/* @__PURE__ */ jsx4("span", { className: "font-medium text-foreground", children: email })
|
|
78
455
|
] }) : "Enter the 6-digit code sent to your email" })
|
|
79
456
|
] }),
|
|
80
|
-
error && /* @__PURE__ */
|
|
81
|
-
resendMessage && /* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
/* @__PURE__ */
|
|
457
|
+
error && /* @__PURE__ */ jsx4("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
458
|
+
resendMessage && /* @__PURE__ */ jsx4("div", { className: "rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700", children: resendMessage }),
|
|
459
|
+
/* @__PURE__ */ jsxs4("form", { onSubmit: handleVerify, className: "space-y-4", noValidate: true, children: [
|
|
460
|
+
/* @__PURE__ */ jsx4(
|
|
84
461
|
"input",
|
|
85
462
|
{
|
|
86
463
|
type: "text",
|
|
@@ -96,7 +473,7 @@ function VerifyEmailForm({
|
|
|
96
473
|
className: "flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
97
474
|
}
|
|
98
475
|
),
|
|
99
|
-
/* @__PURE__ */
|
|
476
|
+
/* @__PURE__ */ jsx4(
|
|
100
477
|
"button",
|
|
101
478
|
{
|
|
102
479
|
type: "submit",
|
|
@@ -105,7 +482,7 @@ function VerifyEmailForm({
|
|
|
105
482
|
children: isVerifying ? "Verifying..." : "Verify email"
|
|
106
483
|
}
|
|
107
484
|
),
|
|
108
|
-
/* @__PURE__ */
|
|
485
|
+
/* @__PURE__ */ jsx4(
|
|
109
486
|
"button",
|
|
110
487
|
{
|
|
111
488
|
type: "button",
|
|
@@ -116,10 +493,10 @@ function VerifyEmailForm({
|
|
|
116
493
|
}
|
|
117
494
|
)
|
|
118
495
|
] }),
|
|
119
|
-
/* @__PURE__ */
|
|
496
|
+
/* @__PURE__ */ jsxs4("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
120
497
|
"Already verified?",
|
|
121
498
|
" ",
|
|
122
|
-
/* @__PURE__ */
|
|
499
|
+
/* @__PURE__ */ jsx4(
|
|
123
500
|
"a",
|
|
124
501
|
{
|
|
125
502
|
href: "/login",
|
|
@@ -132,16 +509,16 @@ function VerifyEmailForm({
|
|
|
132
509
|
}
|
|
133
510
|
|
|
134
511
|
// src/components/forgot-password-form.tsx
|
|
135
|
-
import { useState as
|
|
136
|
-
import { jsx as
|
|
512
|
+
import { useState as useState4 } from "react";
|
|
513
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
137
514
|
function ForgotPasswordForm({
|
|
138
515
|
onSuccess,
|
|
139
516
|
loginUrl = "/login",
|
|
140
517
|
authClient
|
|
141
518
|
}) {
|
|
142
|
-
const [email, setEmail] =
|
|
143
|
-
const [error, setError] =
|
|
144
|
-
const [isPending, setIsPending] =
|
|
519
|
+
const [email, setEmail] = useState4("");
|
|
520
|
+
const [error, setError] = useState4();
|
|
521
|
+
const [isPending, setIsPending] = useState4(false);
|
|
145
522
|
const handleSubmit = async (e) => {
|
|
146
523
|
e.preventDefault();
|
|
147
524
|
if (!email.trim()) {
|
|
@@ -166,14 +543,14 @@ function ForgotPasswordForm({
|
|
|
166
543
|
setIsPending(false);
|
|
167
544
|
}
|
|
168
545
|
};
|
|
169
|
-
return /* @__PURE__ */
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
-
/* @__PURE__ */
|
|
172
|
-
/* @__PURE__ */
|
|
546
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-8", children: [
|
|
547
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
548
|
+
/* @__PURE__ */ jsx5("h1", { className: "text-2xl font-bold tracking-tight", children: "Forgot your password?" }),
|
|
549
|
+
/* @__PURE__ */ jsx5("p", { className: "mt-1 text-sm text-muted-foreground", children: "Enter your email address and we'll send you a code to reset your password." })
|
|
173
550
|
] }),
|
|
174
|
-
error && /* @__PURE__ */
|
|
175
|
-
/* @__PURE__ */
|
|
176
|
-
/* @__PURE__ */
|
|
551
|
+
error && /* @__PURE__ */ jsx5("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
552
|
+
/* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
553
|
+
/* @__PURE__ */ jsx5(
|
|
177
554
|
"input",
|
|
178
555
|
{
|
|
179
556
|
type: "email",
|
|
@@ -186,7 +563,7 @@ function ForgotPasswordForm({
|
|
|
186
563
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
187
564
|
}
|
|
188
565
|
),
|
|
189
|
-
/* @__PURE__ */
|
|
566
|
+
/* @__PURE__ */ jsx5(
|
|
190
567
|
"button",
|
|
191
568
|
{
|
|
192
569
|
type: "submit",
|
|
@@ -196,10 +573,10 @@ function ForgotPasswordForm({
|
|
|
196
573
|
}
|
|
197
574
|
)
|
|
198
575
|
] }),
|
|
199
|
-
/* @__PURE__ */
|
|
576
|
+
/* @__PURE__ */ jsxs5("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
200
577
|
"Remember your password?",
|
|
201
578
|
" ",
|
|
202
|
-
/* @__PURE__ */
|
|
579
|
+
/* @__PURE__ */ jsx5(
|
|
203
580
|
"a",
|
|
204
581
|
{
|
|
205
582
|
href: loginUrl,
|
|
@@ -212,21 +589,21 @@ function ForgotPasswordForm({
|
|
|
212
589
|
}
|
|
213
590
|
|
|
214
591
|
// src/components/reset-password-form.tsx
|
|
215
|
-
import { useState as
|
|
216
|
-
import { jsx as
|
|
592
|
+
import { useState as useState5 } from "react";
|
|
593
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
217
594
|
function ResetPasswordForm({
|
|
218
595
|
email,
|
|
219
596
|
onSuccess,
|
|
220
597
|
loginUrl = "/login",
|
|
221
598
|
authClient
|
|
222
599
|
}) {
|
|
223
|
-
const [otp, setOtp] =
|
|
224
|
-
const [password, setPassword] =
|
|
225
|
-
const [confirmPassword, setConfirmPassword] =
|
|
226
|
-
const [error, setError] =
|
|
227
|
-
const [isResetting, setIsResetting] =
|
|
228
|
-
const [isResending, setIsResending] =
|
|
229
|
-
const [resendMessage, setResendMessage] =
|
|
600
|
+
const [otp, setOtp] = useState5("");
|
|
601
|
+
const [password, setPassword] = useState5("");
|
|
602
|
+
const [confirmPassword, setConfirmPassword] = useState5("");
|
|
603
|
+
const [error, setError] = useState5();
|
|
604
|
+
const [isResetting, setIsResetting] = useState5(false);
|
|
605
|
+
const [isResending, setIsResending] = useState5(false);
|
|
606
|
+
const [resendMessage, setResendMessage] = useState5();
|
|
230
607
|
const handleSubmit = async (e) => {
|
|
231
608
|
e.preventDefault();
|
|
232
609
|
if (!otp.trim() || otp.length < 6) {
|
|
@@ -279,20 +656,20 @@ function ResetPasswordForm({
|
|
|
279
656
|
setIsResending(false);
|
|
280
657
|
}
|
|
281
658
|
};
|
|
282
|
-
return /* @__PURE__ */
|
|
283
|
-
/* @__PURE__ */
|
|
284
|
-
/* @__PURE__ */
|
|
285
|
-
/* @__PURE__ */
|
|
659
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-8", children: [
|
|
660
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
661
|
+
/* @__PURE__ */ jsx6("h1", { className: "text-2xl font-bold tracking-tight", children: "Reset your password" }),
|
|
662
|
+
/* @__PURE__ */ jsxs6("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
286
663
|
"Enter the 6-digit code sent to",
|
|
287
664
|
" ",
|
|
288
|
-
/* @__PURE__ */
|
|
665
|
+
/* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground", children: email }),
|
|
289
666
|
" and your new password."
|
|
290
667
|
] })
|
|
291
668
|
] }),
|
|
292
|
-
error && /* @__PURE__ */
|
|
293
|
-
resendMessage && /* @__PURE__ */
|
|
294
|
-
/* @__PURE__ */
|
|
295
|
-
/* @__PURE__ */
|
|
669
|
+
error && /* @__PURE__ */ jsx6("div", { className: "rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error }),
|
|
670
|
+
resendMessage && /* @__PURE__ */ jsx6("div", { className: "rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700", children: resendMessage }),
|
|
671
|
+
/* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
672
|
+
/* @__PURE__ */ jsx6(
|
|
296
673
|
"input",
|
|
297
674
|
{
|
|
298
675
|
type: "text",
|
|
@@ -308,7 +685,7 @@ function ResetPasswordForm({
|
|
|
308
685
|
className: "flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
309
686
|
}
|
|
310
687
|
),
|
|
311
|
-
/* @__PURE__ */
|
|
688
|
+
/* @__PURE__ */ jsx6(
|
|
312
689
|
"input",
|
|
313
690
|
{
|
|
314
691
|
type: "password",
|
|
@@ -321,7 +698,7 @@ function ResetPasswordForm({
|
|
|
321
698
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
322
699
|
}
|
|
323
700
|
),
|
|
324
|
-
/* @__PURE__ */
|
|
701
|
+
/* @__PURE__ */ jsx6(
|
|
325
702
|
"input",
|
|
326
703
|
{
|
|
327
704
|
type: "password",
|
|
@@ -334,7 +711,7 @@ function ResetPasswordForm({
|
|
|
334
711
|
className: "flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed"
|
|
335
712
|
}
|
|
336
713
|
),
|
|
337
|
-
/* @__PURE__ */
|
|
714
|
+
/* @__PURE__ */ jsx6(
|
|
338
715
|
"button",
|
|
339
716
|
{
|
|
340
717
|
type: "submit",
|
|
@@ -343,7 +720,7 @@ function ResetPasswordForm({
|
|
|
343
720
|
children: isResetting ? "Resetting..." : "Reset password"
|
|
344
721
|
}
|
|
345
722
|
),
|
|
346
|
-
/* @__PURE__ */
|
|
723
|
+
/* @__PURE__ */ jsx6(
|
|
347
724
|
"button",
|
|
348
725
|
{
|
|
349
726
|
type: "button",
|
|
@@ -354,10 +731,10 @@ function ResetPasswordForm({
|
|
|
354
731
|
}
|
|
355
732
|
)
|
|
356
733
|
] }),
|
|
357
|
-
/* @__PURE__ */
|
|
734
|
+
/* @__PURE__ */ jsxs6("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
358
735
|
"Remember your password?",
|
|
359
736
|
" ",
|
|
360
|
-
/* @__PURE__ */
|
|
737
|
+
/* @__PURE__ */ jsx6(
|
|
361
738
|
"a",
|
|
362
739
|
{
|
|
363
740
|
href: loginUrl,
|
|
@@ -370,7 +747,7 @@ function ResetPasswordForm({
|
|
|
370
747
|
}
|
|
371
748
|
|
|
372
749
|
// src/components/auth-layout.tsx
|
|
373
|
-
import { jsx as
|
|
750
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
374
751
|
function AuthLayout({
|
|
375
752
|
logo,
|
|
376
753
|
title,
|
|
@@ -378,19 +755,19 @@ function AuthLayout({
|
|
|
378
755
|
children,
|
|
379
756
|
footer
|
|
380
757
|
}) {
|
|
381
|
-
return /* @__PURE__ */
|
|
382
|
-
/* @__PURE__ */
|
|
383
|
-
logo && /* @__PURE__ */
|
|
384
|
-
/* @__PURE__ */
|
|
385
|
-
subtitle && /* @__PURE__ */
|
|
758
|
+
return /* @__PURE__ */ jsx7("div", { className: "flex min-h-screen items-center justify-center bg-background", children: /* @__PURE__ */ jsxs7("div", { className: "w-full max-w-md", children: [
|
|
759
|
+
/* @__PURE__ */ jsxs7("div", { className: "mb-10 text-center", children: [
|
|
760
|
+
logo && /* @__PURE__ */ jsx7("div", { className: "mb-6 flex justify-center", children: logo }),
|
|
761
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-[32px] font-light tracking-tight", children: title }),
|
|
762
|
+
subtitle && /* @__PURE__ */ jsx7("p", { className: "mt-2 text-sm text-muted-foreground", children: subtitle })
|
|
386
763
|
] }),
|
|
387
|
-
/* @__PURE__ */
|
|
388
|
-
footer && /* @__PURE__ */
|
|
764
|
+
/* @__PURE__ */ jsx7("div", { className: "rounded-xl border bg-card p-8 shadow-sm", children }),
|
|
765
|
+
footer && /* @__PURE__ */ jsx7("div", { className: "mt-6 text-center text-xs text-muted-foreground", children: footer })
|
|
389
766
|
] }) });
|
|
390
767
|
}
|
|
391
768
|
|
|
392
769
|
// src/components/invitation-notice.tsx
|
|
393
|
-
import { jsx as
|
|
770
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
394
771
|
function defaultSupportEmail() {
|
|
395
772
|
if (typeof window === "undefined") return void 0;
|
|
396
773
|
const host = window.location.hostname;
|
|
@@ -410,15 +787,15 @@ function InvitationNotice({
|
|
|
410
787
|
action
|
|
411
788
|
}) {
|
|
412
789
|
const contact = supportEmail ?? defaultSupportEmail();
|
|
413
|
-
return /* @__PURE__ */
|
|
414
|
-
/* @__PURE__ */
|
|
415
|
-
/* @__PURE__ */
|
|
416
|
-
/* @__PURE__ */
|
|
790
|
+
return /* @__PURE__ */ jsxs8("div", { className: "space-y-8", children: [
|
|
791
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
792
|
+
/* @__PURE__ */ jsx8("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
793
|
+
/* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm text-muted-foreground", children: REASON_MESSAGE[reason] ?? REASON_MESSAGE.unknown })
|
|
417
794
|
] }),
|
|
418
|
-
contact ? /* @__PURE__ */
|
|
795
|
+
contact ? /* @__PURE__ */ jsxs8("p", { className: "text-sm text-muted-foreground", children: [
|
|
419
796
|
"\xC9crivez-nous \xE0",
|
|
420
797
|
" ",
|
|
421
|
-
/* @__PURE__ */
|
|
798
|
+
/* @__PURE__ */ jsx8(
|
|
422
799
|
"a",
|
|
423
800
|
{
|
|
424
801
|
href: `mailto:${contact}`,
|
|
@@ -436,7 +813,10 @@ export {
|
|
|
436
813
|
AuthLayout,
|
|
437
814
|
ForgotPasswordForm,
|
|
438
815
|
InvitationNotice,
|
|
816
|
+
LoginForm,
|
|
817
|
+
RegisterForm,
|
|
439
818
|
ResetPasswordForm,
|
|
819
|
+
SocialButtons,
|
|
440
820
|
VerifyEmailForm,
|
|
441
821
|
isInvitationFailure,
|
|
442
822
|
useLogout,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/verify-email-form.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx"],"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 { useState, type FormEvent } from \"react\"\nimport type { VerifyEmailFormProps } from \"../types\"\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n authClient,\n}: VerifyEmailFormProps) {\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.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n setError(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n console.log(\"[verify-email] response:\", JSON.stringify(res?.data), \"error:\", JSON.stringify(res?.error))\n if (res?.error) {\n setError(res.error.message ?? \"Invalid code. Please try again.\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Invalid code. Please try again.\")\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(\"Email address is not available. Please register again.\")\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(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Verify your email\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {email ? (\n <>\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span>\n </>\n ) : (\n \"Enter the 6-digit code sent to your email\"\n )}\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleVerify} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isVerifying}\n autoComplete=\"one-time-code\"\n className=\"flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isVerifying || otp.length < 6}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isVerifying ? \"Verifying...\" : \"Verify email\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Already verified?{\" \"}\n <a\n href=\"/login\"\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ForgotPasswordFormProps } from \"../types\"\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ForgotPasswordFormProps) {\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(\"Please enter your email address\")\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? \"Failed to send reset code\")\n return\n }\n onSuccess?.(email)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to send reset code\")\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Forgot your password?\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter your email address and we'll send you a code to reset your\n password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"Email address\"\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim()}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? \"Sending...\" : \"Send reset code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ResetPasswordFormProps } from \"../types\"\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ResetPasswordFormProps) {\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 handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n if (password.length < 8) {\n setError(\"Password must be at least 8 characters\")\n return\n }\n if (password !== confirmPassword) {\n setError(\"Passwords do not match\")\n return\n }\n setError(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 ?? \"Failed to reset password\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to reset password\",\n )\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(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Reset your password\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span> and your\n new password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isResetting}\n autoComplete=\"one-time-code\"\n className=\"flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"New password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n placeholder=\"Confirm new password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isResetting || otp.length < 6 || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResetting ? \"Resetting...\" : \"Reset password\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\n\nexport function AuthLayout({\n logo,\n title,\n subtitle,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background\">\n <div className=\"w-full max-w-md\">\n <div className=\"mb-10 text-center\">\n {logo && <div className=\"mb-6 flex justify-center\">{logo}</div>}\n <h1 className=\"text-[32px] font-light tracking-tight\">{title}</h1>\n {subtitle && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n )}\n </div>\n\n <div className=\"rounded-xl border bg-card p-8 shadow-sm\">\n {children}\n </div>\n\n {footer && (\n <div className=\"mt-6 text-center text-xs 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"],"mappings":"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","names":["useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-session.ts","../src/components/login-form.tsx","../src/components/social-buttons.tsx","../src/components/register-form.tsx","../src/components/verify-email-form.tsx","../src/components/forgot-password-form.tsx","../src/components/reset-password-form.tsx","../src/components/auth-layout.tsx","../src/components/invitation-notice.tsx"],"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 { useState, type FormEvent } from \"react\"\nimport type { LoginFormLabels, LoginFormProps } from \"../types\"\nimport { SocialButtons } from \"./social-buttons\"\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 authClient,\n}: LoginFormProps) {\n const t = { ...DEFAULTS, ...labels }\n const [email, setEmail] = useState(\"\")\n const [password, setPassword] = 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 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 callbackURL: socialCallbackUrl,\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-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t.title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">{t.subtitle}</p>\n </div>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t.emailPlaceholder}\n aria-label={t.emailPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <div className=\"space-y-1\">\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder={t.passwordPlaceholder}\n aria-label={t.passwordPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"current-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n <div className=\"text-right\">\n <a\n href={forgotPasswordUrl}\n className=\"text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground\"\n >\n {t.forgotPassword}\n </a>\n </div>\n </div>\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim() || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? t.submitPending : t.submit}\n </button>\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 <a\n href={registerUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {t.register}\n </a>\n </p>\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 <div className=\"relative\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-input\" />\n </div>\n <div className=\"relative flex justify-center\">\n <span className=\"bg-background px-2 text-xs uppercase tracking-wider text-muted-foreground\">\n {separator}\n </span>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n {providers.map((provider) => (\n <button\n key={provider}\n type=\"button\"\n onClick={() => onSelect(provider)}\n disabled={disabled}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {copy[provider] ?? provider}\n </button>\n ))}\n </div>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { RegisterFormLabels, RegisterFormProps } from \"../types\"\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 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 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 [error, setError] = useState<string | undefined>()\n const [isPending, setIsPending] = useState(false)\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 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 callbackURL: socialCallbackUrl,\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : t.signUpFailed)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t.title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">{t.subtitle}</p>\n </div>\n\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t.namePlaceholder}\n aria-label={t.namePlaceholder}\n required\n disabled={isPending}\n autoComplete=\"name\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t.emailPlaceholder}\n aria-label={t.emailPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <div className=\"space-y-1\">\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder={t.passwordPlaceholder}\n aria-label={t.passwordPlaceholder}\n required\n disabled={isPending}\n autoComplete=\"new-password\"\n aria-describedby=\"register-password-hint\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n <p id=\"register-password-hint\" className=\"text-xs text-muted-foreground\">\n {t.passwordHint}\n </p>\n </div>\n\n <button\n type=\"submit\"\n disabled={isPending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? t.submitPending : t.submit}\n </button>\n\n {legal && (\n <div className=\"text-center text-xs text-muted-foreground\">{legal}</div>\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 <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n {t.login}\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { VerifyEmailFormProps } from \"../types\"\n\nexport function VerifyEmailForm({\n email,\n onSuccess,\n authClient,\n}: VerifyEmailFormProps) {\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.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n setError(undefined)\n setIsVerifying(true)\n try {\n const res = await authClient.emailOtp.verifyEmail({ email, otp })\n console.log(\"[verify-email] response:\", JSON.stringify(res?.data), \"error:\", JSON.stringify(res?.error))\n if (res?.error) {\n setError(res.error.message ?? \"Invalid code. Please try again.\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Invalid code. Please try again.\")\n } finally {\n setIsVerifying(false)\n }\n }\n\n const handleResend = async () => {\n if (!email) {\n setError(\"Email address is not available. Please register again.\")\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(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Verify your email\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {email ? (\n <>\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span>\n </>\n ) : (\n \"Enter the 6-digit code sent to your email\"\n )}\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleVerify} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isVerifying}\n autoComplete=\"one-time-code\"\n className=\"flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isVerifying || otp.length < 6}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isVerifying ? \"Verifying...\" : \"Verify email\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Already verified?{\" \"}\n <a\n href=\"/login\"\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ForgotPasswordFormProps } from \"../types\"\n\nexport function ForgotPasswordForm({\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ForgotPasswordFormProps) {\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(\"Please enter your email address\")\n return\n }\n setError(undefined)\n setIsPending(true)\n try {\n const res = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"forget-password\",\n })\n if (res?.error) {\n setError(res.error.message ?? \"Failed to send reset code\")\n return\n }\n onSuccess?.(email)\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to send reset code\")\n } finally {\n setIsPending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Forgot your password?\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter your email address and we'll send you a code to reset your\n password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"Email address\"\n required\n disabled={isPending}\n autoComplete=\"email\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isPending || !email.trim()}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isPending ? \"Sending...\" : \"Send reset code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import { useState, type FormEvent } from \"react\"\nimport type { ResetPasswordFormProps } from \"../types\"\n\nexport function ResetPasswordForm({\n email,\n onSuccess,\n loginUrl = \"/login\",\n authClient,\n}: ResetPasswordFormProps) {\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 handleSubmit = async (e: FormEvent) => {\n e.preventDefault()\n if (!otp.trim() || otp.length < 6) {\n setError(\"Please enter the 6-digit code\")\n return\n }\n if (password.length < 8) {\n setError(\"Password must be at least 8 characters\")\n return\n }\n if (password !== confirmPassword) {\n setError(\"Passwords do not match\")\n return\n }\n setError(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 ?? \"Failed to reset password\")\n return\n }\n onSuccess?.()\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to reset password\",\n )\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(\"A new code has been sent to your inbox.\")\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code.\")\n } finally {\n setIsResending(false)\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">\n Reset your password\n </h1>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Enter the 6-digit code sent to{\" \"}\n <span className=\"font-medium text-foreground\">{email}</span> and your\n new password.\n </p>\n </div>\n\n {error && (\n <div className=\"rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {error}\n </div>\n )}\n\n {resendMessage && (\n <div className=\"rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-xs text-green-700\">\n {resendMessage}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"space-y-4\" noValidate>\n <input\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={6}\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, \"\"))}\n placeholder=\"000000\"\n required\n disabled={isResetting}\n autoComplete=\"one-time-code\"\n className=\"flex h-12 w-full rounded-md border border-input bg-background px-3 py-2 text-center text-lg tracking-[0.4em] font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <input\n type=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"New password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n placeholder=\"Confirm new password\"\n required\n disabled={isResetting}\n autoComplete=\"new-password\"\n className=\"flex h-11 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n\n <button\n type=\"submit\"\n disabled={isResetting || otp.length < 6 || !password}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResetting ? \"Resetting...\" : \"Reset password\"}\n </button>\n\n <button\n type=\"button\"\n onClick={handleResend}\n disabled={isResending}\n className=\"inline-flex h-11 w-full items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {isResending ? \"Sending...\" : \"Resend code\"}\n </button>\n </form>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n Remember your password?{\" \"}\n <a\n href={loginUrl}\n className=\"font-medium text-foreground underline underline-offset-4 hover:text-foreground/80\"\n >\n Sign in\n </a>\n </p>\n </div>\n )\n}\n","import type { AuthLayoutProps } from \"../types\"\n\nexport function AuthLayout({\n logo,\n title,\n subtitle,\n children,\n footer,\n}: AuthLayoutProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background\">\n <div className=\"w-full max-w-md\">\n <div className=\"mb-10 text-center\">\n {logo && <div className=\"mb-6 flex justify-center\">{logo}</div>}\n <h1 className=\"text-[32px] font-light tracking-tight\">{title}</h1>\n {subtitle && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{subtitle}</p>\n )}\n </div>\n\n <div className=\"rounded-xl border bg-card p-8 shadow-sm\">\n {children}\n </div>\n\n {footer && (\n <div className=\"mt-6 text-center text-xs 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"],"mappings":"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","names":["jsx","jsxs","useState","jsx","jsxs","DEFAULTS","useState","useState","jsx","jsxs","useState","jsx","jsxs","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 {
|
|
3
|
-
export {
|
|
4
|
-
export { a as ClaimInvitationOptions, C as ClaimOutcome, c as claimInvitation, b as completesSignup, d as invitationOutcomeCookie, e as inviteTokenFrom, i as isInvitationFailure } from './invitation-
|
|
2
|
+
import { d as PlatformAuthConfig } from './types-BXyGxKtF.js';
|
|
3
|
+
export { h as PlatformSession, i as PlatformSessionData, j as PlatformUser } from './types-BXyGxKtF.js';
|
|
4
|
+
export { a as ClaimInvitationOptions, C as ClaimOutcome, c as claimInvitation, b as completesSignup, d as invitationOutcomeCookie, e as inviteTokenFrom, i as isInvitationFailure } from './invitation-Bucmin-z.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a Better Auth instance with platform defaults.
|
|
@@ -125,6 +125,85 @@ interface InvitationNoticeProps {
|
|
|
125
125
|
/** Rendered under the contact line — typically a link back to the site. */
|
|
126
126
|
action?: React.ReactNode;
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Copy overrides for the sign-in screen. Every key is optional; what is not
|
|
130
|
+
* given falls back to the French defaults, matching InvitationNotice and the
|
|
131
|
+
* apps consuming this package. Pass a full set to render another language.
|
|
132
|
+
*/
|
|
133
|
+
interface LoginFormLabels {
|
|
134
|
+
title?: string;
|
|
135
|
+
subtitle?: string;
|
|
136
|
+
emailPlaceholder?: string;
|
|
137
|
+
passwordPlaceholder?: string;
|
|
138
|
+
forgotPassword?: string;
|
|
139
|
+
submit?: string;
|
|
140
|
+
submitPending?: string;
|
|
141
|
+
noAccount?: string;
|
|
142
|
+
register?: string;
|
|
143
|
+
emailRequired?: string;
|
|
144
|
+
passwordRequired?: string;
|
|
145
|
+
invalidCredentials?: string;
|
|
146
|
+
accountNotLinked?: string;
|
|
147
|
+
socialCancelled?: string;
|
|
148
|
+
socialFailed?: string;
|
|
149
|
+
}
|
|
150
|
+
interface RegisterFormLabels {
|
|
151
|
+
title?: string;
|
|
152
|
+
subtitle?: string;
|
|
153
|
+
namePlaceholder?: string;
|
|
154
|
+
emailPlaceholder?: string;
|
|
155
|
+
passwordPlaceholder?: string;
|
|
156
|
+
passwordHint?: string;
|
|
157
|
+
submit?: string;
|
|
158
|
+
submitPending?: string;
|
|
159
|
+
haveAccount?: string;
|
|
160
|
+
login?: string;
|
|
161
|
+
nameRequired?: string;
|
|
162
|
+
emailRequired?: string;
|
|
163
|
+
passwordTooShort?: string;
|
|
164
|
+
signUpFailed?: string;
|
|
165
|
+
}
|
|
166
|
+
interface LoginFormProps {
|
|
167
|
+
/** Callback once the session cookie is set and the core token minted */
|
|
168
|
+
onSuccess?: () => void;
|
|
169
|
+
/** Link to the registration page */
|
|
170
|
+
registerUrl?: string;
|
|
171
|
+
/** Link to the password recovery page */
|
|
172
|
+
forgotPasswordUrl?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Where Better Auth sends the browser back after a social sign-in. Social
|
|
175
|
+
* buttons are only rendered when at least one provider is passed.
|
|
176
|
+
*/
|
|
177
|
+
socialCallbackUrl?: string;
|
|
178
|
+
/** Social providers to offer, in display order */
|
|
179
|
+
socialProviders?: Array<"google" | "github">;
|
|
180
|
+
/**
|
|
181
|
+
* Endpoint trading the fresh better-auth session for the short-lived EdDSA
|
|
182
|
+
* token the Go core verifies. Called after a successful password sign-in;
|
|
183
|
+
* pass null to skip when the app has no core.
|
|
184
|
+
*/
|
|
185
|
+
coreTokenUrl?: string | null;
|
|
186
|
+
/** Copy overrides; anything omitted keeps the French default */
|
|
187
|
+
labels?: LoginFormLabels;
|
|
188
|
+
/** Auth client instance */
|
|
189
|
+
authClient: any;
|
|
190
|
+
}
|
|
191
|
+
interface RegisterFormProps {
|
|
192
|
+
/** Callback on successful sign-up, receives the email to verify */
|
|
193
|
+
onSuccess?: (email: string) => void;
|
|
194
|
+
/** Link to the login page */
|
|
195
|
+
loginUrl?: string;
|
|
196
|
+
/** Rendered under the submit button — typically terms and privacy links */
|
|
197
|
+
legal?: React.ReactNode;
|
|
198
|
+
/** Where Better Auth sends the browser back after a social sign-up */
|
|
199
|
+
socialCallbackUrl?: string;
|
|
200
|
+
/** Social providers to offer, in display order */
|
|
201
|
+
socialProviders?: Array<"google" | "github">;
|
|
202
|
+
/** Copy overrides; anything omitted keeps the French default */
|
|
203
|
+
labels?: RegisterFormLabels;
|
|
204
|
+
/** Auth client instance */
|
|
205
|
+
authClient: any;
|
|
206
|
+
}
|
|
128
207
|
interface ForgotPasswordFormProps {
|
|
129
208
|
/** Callback on successful OTP send, receives the email */
|
|
130
209
|
onSuccess?: (email: string) => void;
|
|
@@ -156,4 +235,4 @@ interface AuthLayoutProps {
|
|
|
156
235
|
footer?: React.ReactNode;
|
|
157
236
|
}
|
|
158
237
|
|
|
159
|
-
export type { AuthLayoutProps as A, ForgotPasswordFormProps as F, InvitationNoticeProps as I, PlatformAuthClientConfig as P,
|
|
238
|
+
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, InvitationFailure as b, LoginFormLabels as c, PlatformAuthConfig as d, PlatformAuthMailer as e, PlatformAuthMailerArgs as f, PlatformAuthMailerType as g, PlatformSession as h, PlatformSessionData as i, PlatformUser as j, RegisterFormLabels as k };
|