@mesob/auth-react 0.0.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.
Files changed (46) hide show
  1. package/dist/components/auth-card.d.ts +9 -0
  2. package/dist/components/auth-card.js +11 -0
  3. package/dist/components/auth-card.js.map +1 -0
  4. package/dist/components/auth-page-layout.d.ts +14 -0
  5. package/dist/components/auth-page-layout.js +28 -0
  6. package/dist/components/auth-page-layout.js.map +1 -0
  7. package/dist/components/countdown.d.ts +10 -0
  8. package/dist/components/countdown.js +57 -0
  9. package/dist/components/countdown.js.map +1 -0
  10. package/dist/components/forgot-password.d.ts +13 -0
  11. package/dist/components/forgot-password.js +67 -0
  12. package/dist/components/forgot-password.js.map +1 -0
  13. package/dist/components/pages/forgot-password-page.d.ts +17 -0
  14. package/dist/components/pages/forgot-password-page.js +224 -0
  15. package/dist/components/pages/forgot-password-page.js.map +1 -0
  16. package/dist/components/pages/reset-password-page.d.ts +19 -0
  17. package/dist/components/pages/reset-password-page.js +357 -0
  18. package/dist/components/pages/reset-password-page.js.map +1 -0
  19. package/dist/components/pages/sign-in-page.d.ts +19 -0
  20. package/dist/components/pages/sign-in-page.js +343 -0
  21. package/dist/components/pages/sign-in-page.js.map +1 -0
  22. package/dist/components/pages/sign-up-page.d.ts +18 -0
  23. package/dist/components/pages/sign-up-page.js +360 -0
  24. package/dist/components/pages/sign-up-page.js.map +1 -0
  25. package/dist/components/pages/verify-email-page.d.ts +19 -0
  26. package/dist/components/pages/verify-email-page.js +356 -0
  27. package/dist/components/pages/verify-email-page.js.map +1 -0
  28. package/dist/components/pages/verify-phone-page.d.ts +20 -0
  29. package/dist/components/pages/verify-phone-page.js +368 -0
  30. package/dist/components/pages/verify-phone-page.js.map +1 -0
  31. package/dist/components/reset-password-form.d.ts +16 -0
  32. package/dist/components/reset-password-form.js +142 -0
  33. package/dist/components/reset-password-form.js.map +1 -0
  34. package/dist/components/sign-in.d.ts +16 -0
  35. package/dist/components/sign-in.js +128 -0
  36. package/dist/components/sign-in.js.map +1 -0
  37. package/dist/components/sign-up.d.ts +17 -0
  38. package/dist/components/sign-up.js +179 -0
  39. package/dist/components/sign-up.js.map +1 -0
  40. package/dist/components/verification-form.d.ts +15 -0
  41. package/dist/components/verification-form.js +155 -0
  42. package/dist/components/verification-form.js.map +1 -0
  43. package/dist/index.d.ts +222 -0
  44. package/dist/index.js +1640 -0
  45. package/dist/index.js.map +1 -0
  46. package/package.json +48 -0
@@ -0,0 +1,343 @@
1
+ "use client";
2
+
3
+ // src/components/pages/sign-in-page.tsx
4
+ import { useTranslations as useTranslations2 } from "next-intl";
5
+ import { useState as useState3 } from "react";
6
+
7
+ // src/context/auth-provider.tsx
8
+ import {
9
+ createContext,
10
+ useCallback,
11
+ useContext,
12
+ useEffect,
13
+ useState
14
+ } from "react";
15
+ import { jsx } from "react/jsx-runtime";
16
+ var AuthContext = createContext(null);
17
+ var useAuth = () => {
18
+ const context = useContext(AuthContext);
19
+ if (!context) {
20
+ throw new Error("useAuth must be used within AuthProvider");
21
+ }
22
+ return context;
23
+ };
24
+
25
+ // src/client.ts
26
+ var AuthError = class extends Error {
27
+ code;
28
+ status;
29
+ details;
30
+ constructor(message, code, status, details) {
31
+ super(message);
32
+ this.name = "AuthError";
33
+ this.code = code;
34
+ this.status = status;
35
+ this.details = details;
36
+ }
37
+ };
38
+
39
+ // src/constants/auth.error.codes.ts
40
+ var validCodes = [
41
+ "USER_NOT_FOUND",
42
+ "INVALID_PASSWORD",
43
+ "USER_EXISTS",
44
+ "VERIFICATION_EXPIRED",
45
+ "VERIFICATION_MISMATCH",
46
+ "VERIFICATION_NOT_FOUND",
47
+ "TOO_MANY_ATTEMPTS",
48
+ "REQUIRES_VERIFICATION",
49
+ "UNAUTHORIZED",
50
+ "ACCESS_DENIED",
51
+ "HAS_NO_PASSWORD"
52
+ ];
53
+
54
+ // src/utils/handle-error.ts
55
+ var handleError = (err, setError, t) => {
56
+ if (err instanceof AuthError) {
57
+ let errorKey = "errors.fallback";
58
+ if (err.code) {
59
+ errorKey = `errors.${err.code.toLowerCase()}`;
60
+ } else if (err.message) {
61
+ const messageUpper = err.message.toUpperCase().trim();
62
+ if (validCodes.includes(messageUpper)) {
63
+ errorKey = `errors.${messageUpper.toLowerCase()}`;
64
+ }
65
+ }
66
+ setError(t(errorKey, { defaultValue: err.message }));
67
+ } else {
68
+ setError(err instanceof Error ? err.message : t("errors.fallback"));
69
+ }
70
+ };
71
+
72
+ // src/components/auth-page-layout.tsx
73
+ import { Alert, AlertDescription } from "@mesob/ui/components/alert";
74
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
75
+ var AuthPageLayout = ({
76
+ title,
77
+ description,
78
+ children,
79
+ error,
80
+ footer,
81
+ logoImage
82
+ }) => {
83
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
84
+ /* @__PURE__ */ jsx2("div", { className: "flex size-8 mb-6 w-full items-center justify-center rounded-md", children: /* @__PURE__ */ jsx2("img", { src: logoImage || "", alt: "Jiret", width: 42, height: 42 }) }),
85
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
86
+ /* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
87
+ description && /* @__PURE__ */ jsx2("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
88
+ ] }),
89
+ children,
90
+ error && /* @__PURE__ */ jsx2(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx2(AlertDescription, { children: error }) }),
91
+ /* @__PURE__ */ jsx2("div", { className: "mt-2 w-full", children: footer && /* @__PURE__ */ jsx2("div", { className: "w-full text-center text-sm text-muted-foreground", children: footer }) })
92
+ ] });
93
+ };
94
+
95
+ // src/components/sign-in.tsx
96
+ import { zodResolver } from "@hookform/resolvers/zod";
97
+ import { Button } from "@mesob/ui/components/button";
98
+ import {
99
+ Form,
100
+ FormControl,
101
+ FormField,
102
+ FormItem,
103
+ FormLabel,
104
+ FormMessage
105
+ } from "@mesob/ui/components/form";
106
+ import { Input } from "@mesob/ui/components/input";
107
+ import { Eye, EyeOff } from "lucide-react";
108
+ import { useTranslations } from "next-intl";
109
+ import { useMemo, useState as useState2 } from "react";
110
+ import { useForm } from "react-hook-form";
111
+ import { z } from "zod";
112
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
113
+ var SignIn = ({
114
+ onSubmit,
115
+ isLoading = false,
116
+ identifier = "",
117
+ step = "identifier",
118
+ onBack: _onBack
119
+ }) => {
120
+ const t = useTranslations("Auth.signIn");
121
+ const [showPassword, setShowPassword] = useState2(false);
122
+ const identifierSchema = useMemo(
123
+ () => z.object({
124
+ account: z.string().min(1, t("errors.accountRequired")).email(t("errors.invalidEmail"))
125
+ }),
126
+ [t]
127
+ );
128
+ const passwordSchema = useMemo(
129
+ () => z.object({
130
+ password: z.string().min(8, t("errors.passwordLength")).max(128, t("errors.longPasswordError"))
131
+ }),
132
+ [t]
133
+ );
134
+ const identifierForm = useForm({
135
+ resolver: zodResolver(identifierSchema),
136
+ defaultValues: {
137
+ account: identifier
138
+ }
139
+ });
140
+ const passwordForm = useForm({
141
+ resolver: zodResolver(passwordSchema),
142
+ defaultValues: {
143
+ password: ""
144
+ }
145
+ });
146
+ const handleIdentifierSubmit = identifierForm.handleSubmit(async (values) => {
147
+ await onSubmit({ account: values.account, password: "" }, "identifier");
148
+ });
149
+ const handlePasswordSubmit = passwordForm.handleSubmit(async (values) => {
150
+ await onSubmit(
151
+ { account: identifier, password: values.password },
152
+ "password"
153
+ );
154
+ });
155
+ if (step === "password") {
156
+ return /* @__PURE__ */ jsx3(Form, { ...passwordForm, children: /* @__PURE__ */ jsxs2("form", { onSubmit: handlePasswordSubmit, className: "space-y-4", children: [
157
+ /* @__PURE__ */ jsxs2("div", { className: "text-center", children: [
158
+ /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground mb-2", children: t("form.enterPasswordFor") }),
159
+ /* @__PURE__ */ jsx3("p", { className: "font-bold", children: identifier })
160
+ ] }),
161
+ /* @__PURE__ */ jsx3(
162
+ FormField,
163
+ {
164
+ control: passwordForm.control,
165
+ name: "password",
166
+ render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
167
+ /* @__PURE__ */ jsx3(FormLabel, { children: t("form.passwordLabel") }),
168
+ /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
169
+ /* @__PURE__ */ jsx3(
170
+ Input,
171
+ {
172
+ type: showPassword ? "text" : "password",
173
+ placeholder: t("form.passwordPlaceholder"),
174
+ ...field
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsx3(
178
+ "button",
179
+ {
180
+ type: "button",
181
+ onClick: () => setShowPassword(!showPassword),
182
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
183
+ children: showPassword ? /* @__PURE__ */ jsx3(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(Eye, { className: "h-4 w-4" })
184
+ }
185
+ )
186
+ ] }) }),
187
+ /* @__PURE__ */ jsx3(FormMessage, {})
188
+ ] })
189
+ }
190
+ ),
191
+ /* @__PURE__ */ jsx3(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.submit") })
192
+ ] }) });
193
+ }
194
+ return /* @__PURE__ */ jsx3(Form, { ...identifierForm, children: /* @__PURE__ */ jsxs2("form", { onSubmit: handleIdentifierSubmit, className: "space-y-4", children: [
195
+ /* @__PURE__ */ jsx3(
196
+ FormField,
197
+ {
198
+ control: identifierForm.control,
199
+ name: "account",
200
+ render: ({ field }) => /* @__PURE__ */ jsxs2(FormItem, { children: [
201
+ /* @__PURE__ */ jsx3(FormLabel, { children: t("form.accountLabel") }),
202
+ /* @__PURE__ */ jsx3(FormControl, { children: /* @__PURE__ */ jsx3(
203
+ Input,
204
+ {
205
+ type: "text",
206
+ placeholder: t("form.accountPlaceholder"),
207
+ ...field
208
+ }
209
+ ) }),
210
+ /* @__PURE__ */ jsx3(FormMessage, {})
211
+ ] })
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsx3(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? t("form.submitting") : t("form.continue") })
215
+ ] }) });
216
+ };
217
+
218
+ // src/components/pages/sign-in-page.tsx
219
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
220
+ var isPhone = (s) => /^\+?[0-9()[\]\s-]{6,}$/.test(s);
221
+ var SignInPage = ({
222
+ redirectUrl,
223
+ onNavigate,
224
+ linkComponent: Link,
225
+ links,
226
+ logoImage
227
+ }) => {
228
+ const t = useTranslations2("Auth.signIn");
229
+ const { client, setAuth } = useAuth();
230
+ const [isLoading, setIsLoading] = useState3(false);
231
+ const [error, setError] = useState3(null);
232
+ const [step, setStep] = useState3("identifier");
233
+ const [identifier, setIdentifier] = useState3("");
234
+ const defaultRedirect = redirectUrl || "/dashboard";
235
+ const forgotPasswordLink = links?.forgotPassword || "/auth/forgot-password";
236
+ const signUpLink = links?.signUp || "/auth/sign-up";
237
+ const handleSubmit = async (values, currentStep) => {
238
+ setIsLoading(true);
239
+ setError(null);
240
+ try {
241
+ if (currentStep === "identifier") {
242
+ const checkResult = await client.checkUser({
243
+ identifier: values.account
244
+ });
245
+ if (checkResult.exists) {
246
+ setIdentifier(values.account);
247
+ setStep("password");
248
+ } else {
249
+ const email = isPhone(values.account) ? "" : values.account;
250
+ if (email) {
251
+ onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);
252
+ } else {
253
+ onNavigate(
254
+ `${signUpLink}?phone=${encodeURIComponent(values.account)}`
255
+ );
256
+ }
257
+ return;
258
+ }
259
+ } else {
260
+ const res = await client.signInWithPassword({
261
+ identifier,
262
+ password: values.password
263
+ });
264
+ if ("verificationId" in res && res.verificationId) {
265
+ const verifyPath = isPhone(identifier) ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(identifier)}` : `/auth/verify-email?verificationId=${res.verificationId}`;
266
+ onNavigate(verifyPath);
267
+ return;
268
+ }
269
+ if ("user" in res && "session" in res) {
270
+ setAuth(res);
271
+ }
272
+ onNavigate(defaultRedirect);
273
+ }
274
+ } catch (err) {
275
+ handleError(err, setError, t);
276
+ } finally {
277
+ setIsLoading(false);
278
+ }
279
+ };
280
+ const handleBack = () => {
281
+ setStep("identifier");
282
+ setIdentifier("");
283
+ setError(null);
284
+ };
285
+ const isStepPassword = step === "password";
286
+ return /* @__PURE__ */ jsx4("div", { className: "space-y-4", children: /* @__PURE__ */ jsx4(
287
+ AuthPageLayout,
288
+ {
289
+ title: t("title"),
290
+ description: isStepPassword ? void 0 : t("description"),
291
+ error,
292
+ logoImage,
293
+ footer: /* @__PURE__ */ jsxs3(
294
+ "div",
295
+ {
296
+ className: "flex items-center justify-center w-full gap-2",
297
+ style: {
298
+ justifyContent: isStepPassword ? "space-between" : "center"
299
+ },
300
+ children: [
301
+ isStepPassword && // biome-ignore lint/a11y/useKeyWithClickEvents: change account
302
+ /* @__PURE__ */ jsx4(
303
+ "p",
304
+ {
305
+ className: "text-primary inline-block cursor-pointer hover:underline",
306
+ onClick: handleBack,
307
+ children: t("changeAccount")
308
+ }
309
+ ),
310
+ Link ? /* @__PURE__ */ jsx4(
311
+ Link,
312
+ {
313
+ href: forgotPasswordLink,
314
+ className: "text-primary inline-block hover:underline",
315
+ children: t("footer.forgotPassword")
316
+ }
317
+ ) : /* @__PURE__ */ jsx4(
318
+ "a",
319
+ {
320
+ href: forgotPasswordLink,
321
+ className: "text-primary inline-block hover:underline",
322
+ children: t("footer.forgotPassword")
323
+ }
324
+ )
325
+ ]
326
+ }
327
+ ),
328
+ children: /* @__PURE__ */ jsx4(
329
+ SignIn,
330
+ {
331
+ onSubmit: handleSubmit,
332
+ isLoading,
333
+ identifier,
334
+ step
335
+ }
336
+ )
337
+ }
338
+ ) });
339
+ };
340
+ export {
341
+ SignInPage
342
+ };
343
+ //# sourceMappingURL=sign-in-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/pages/sign-in-page.tsx","../../../src/context/auth-provider.tsx","../../../src/client.ts","../../../src/constants/auth.error.codes.ts","../../../src/utils/handle-error.ts","../../../src/components/auth-page-layout.tsx","../../../src/components/sign-in.tsx"],"sourcesContent":["'use client';\n\nimport { useTranslations } from 'next-intl';\nimport type { ComponentProps } from 'react';\nimport { useState } from 'react';\nimport { useAuth } from '../../context/auth-provider';\nimport { handleError } from '../../utils/handle-error';\nimport { AuthPageLayout } from '../auth-page-layout';\nimport { SignIn } from '../sign-in';\n\nconst isPhone = (s: string) => /^\\+?[0-9()[\\]\\s-]{6,}$/.test(s);\n\ntype SignInPageProps = {\n locale?: string;\n redirectUrl?: string;\n onNavigate: (path: string) => void;\n linkComponent?: React.ComponentType<ComponentProps<'a'> & { href: string }>;\n links?: {\n forgotPassword?: string;\n signUp?: string;\n };\n logoImage?: string;\n};\n\nexport const SignInPage = ({\n redirectUrl,\n onNavigate,\n linkComponent: Link,\n links,\n logoImage,\n}: SignInPageProps) => {\n const t = useTranslations('Auth.signIn');\n const { client, setAuth } = useAuth();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [step, setStep] = useState<'identifier' | 'password'>('identifier');\n const [identifier, setIdentifier] = useState<string>('');\n\n const defaultRedirect = redirectUrl || '/dashboard';\n const forgotPasswordLink = links?.forgotPassword || '/auth/forgot-password';\n const signUpLink = links?.signUp || '/auth/sign-up';\n\n const handleSubmit = async (\n values: { account: string; password: string },\n currentStep: 'identifier' | 'password',\n ) => {\n setIsLoading(true);\n setError(null);\n\n try {\n if (currentStep === 'identifier') {\n const checkResult = await client.checkUser({\n identifier: values.account,\n });\n\n if (checkResult.exists) {\n setIdentifier(values.account);\n setStep('password');\n } else {\n const email = isPhone(values.account) ? '' : values.account;\n if (email) {\n onNavigate(`${signUpLink}?email=${encodeURIComponent(email)}`);\n } else {\n onNavigate(\n `${signUpLink}?phone=${encodeURIComponent(values.account)}`,\n );\n }\n return;\n }\n } else {\n const res = await client.signInWithPassword({\n identifier,\n password: values.password,\n });\n\n if ('verificationId' in res && res.verificationId) {\n const verifyPath = isPhone(identifier)\n ? `/auth/verify-phone?context=sign-in&verificationId=${res.verificationId}&identifier=${encodeURIComponent(identifier)}`\n : `/auth/verify-email?verificationId=${res.verificationId}`;\n onNavigate(verifyPath);\n return;\n }\n\n if ('user' in res && 'session' in res) {\n setAuth(res);\n }\n onNavigate(defaultRedirect);\n }\n } catch (err) {\n handleError(err, setError, t);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleBack = () => {\n setStep('identifier');\n setIdentifier('');\n setError(null);\n };\n\n const isStepPassword = step === 'password';\n\n return (\n <div className=\"space-y-4\">\n <AuthPageLayout\n title={t('title')}\n description={isStepPassword ? undefined : t('description')}\n error={error}\n logoImage={logoImage}\n footer={\n <div\n className=\"flex items-center justify-center w-full gap-2\"\n style={{\n justifyContent: isStepPassword ? 'space-between' : 'center',\n }}\n >\n {isStepPassword && (\n // biome-ignore lint/a11y/useKeyWithClickEvents: change account\n <p\n className=\"text-primary inline-block cursor-pointer hover:underline\"\n onClick={handleBack}\n >\n {t('changeAccount')}\n </p>\n )}\n\n {Link ? (\n <Link\n href={forgotPasswordLink}\n className=\"text-primary inline-block hover:underline\"\n >\n {t('footer.forgotPassword')}\n </Link>\n ) : (\n <a\n href={forgotPasswordLink}\n className=\"text-primary inline-block hover:underline\"\n >\n {t('footer.forgotPassword')}\n </a>\n )}\n </div>\n }\n >\n <SignIn\n onSubmit={handleSubmit}\n isLoading={isLoading}\n identifier={identifier}\n step={step}\n />\n </AuthPageLayout>\n </div>\n );\n};\n","'use client';\n\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport type { AuthClient } from '../client';\nimport type { AuthResponse, Session, User } from '../types';\n\ntype AuthContextValue = {\n user: User | null;\n session: Session | null;\n loading: boolean;\n error: Error | null;\n client: AuthClient;\n refresh: () => Promise<void>;\n setAuth: (data: AuthResponse) => void;\n};\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\nexport const useAuth = () => {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuth must be used within AuthProvider');\n }\n return context;\n};\n\ntype AuthProviderProps = {\n client: AuthClient;\n children: ReactNode;\n};\n\nexport const AuthProvider = ({ client, children }: AuthProviderProps) => {\n const [user, setUser] = useState<User | null>(null);\n const [session, setSession] = useState<Session | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n const data = await client.getSession();\n setUser(data.user);\n setSession(data.session);\n } catch (err) {\n setError(\n err instanceof Error ? err : new Error('Failed to fetch session'),\n );\n setUser(null);\n setSession(null);\n } finally {\n setLoading(false);\n }\n }, [client]);\n\n const setAuth = useCallback((data: AuthResponse) => {\n setUser(data.user);\n setSession(data.session);\n setError(null);\n setLoading(false);\n }, []);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return (\n <AuthContext.Provider\n value={{\n user,\n session,\n loading,\n error,\n client,\n refresh,\n setAuth,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n","import type {\n AuthErrorCode,\n AuthErrorResponse,\n AuthResponse,\n SessionResponse,\n User,\n VerificationResponse,\n} from './types';\n\n// Backend returns error code in 'error' field (AUTH_ERRORS values)\n// or in 'code' field, message in 'message' or 'error' field\nconst validErrorCodes: readonly AuthErrorCode[] = [\n 'USER_NOT_FOUND',\n 'INVALID_PASSWORD',\n 'USER_EXISTS',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'REQUIRES_VERIFICATION',\n 'UNAUTHORIZED',\n 'ACCESS_DENIED',\n 'HAS_NO_PASSWORD',\n] as const;\n\nexport class AuthError extends Error {\n code?: AuthErrorCode;\n status?: number;\n details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code?: AuthErrorCode,\n status?: number,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport type AuthClientConfig = {\n baseURL: string;\n};\n\nexport class AuthClient {\n private baseURL: string;\n\n constructor(config: AuthClientConfig) {\n this.baseURL = config.baseURL.replace(/\\/$/, '');\n }\n\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseURL}${endpoint}`;\n const response = await fetch(url, {\n ...options,\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n if (!response.ok) {\n const text = await response.text();\n let errorData: AuthErrorResponse;\n try {\n errorData = JSON.parse(text);\n } catch {\n errorData = { error: 'Unknown error', message: text };\n }\n\n // Extract error code from code, error, or message field\n // Backend returns error codes in 'error' field (e.g., { error: 'INVALID_PASSWORD' })\n const potentialCode =\n errorData.code ||\n (typeof errorData.error === 'string' ? errorData.error : null) ||\n (typeof errorData.message === 'string' ? errorData.message : null);\n const upperCode = potentialCode?.toUpperCase().trim();\n const errorCode =\n upperCode && validErrorCodes.includes(upperCode as AuthErrorCode)\n ? (upperCode as AuthErrorCode)\n : undefined;\n const errorMessage =\n errorData.message || errorData.error || 'Request failed';\n\n throw new AuthError(\n errorMessage,\n errorCode as AuthErrorCode | undefined,\n response.status,\n errorData.details,\n );\n }\n\n const data = await response.json();\n return data;\n }\n\n signUpWithEmail(data: {\n email: string;\n password: string;\n fullName: string;\n handle?: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-up', {\n method: 'POST',\n body: JSON.stringify({\n email: data.email,\n password: data.password,\n fullName: data.fullName,\n handle: data.handle,\n }),\n });\n }\n\n signUpWithPhone(data: {\n phone: string;\n password: string;\n fullName: string;\n handle?: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-up', {\n method: 'POST',\n body: JSON.stringify({\n phone: data.phone,\n password: data.password,\n fullName: data.fullName,\n handle: data.handle,\n }),\n });\n }\n\n checkUser(data: { identifier: string }): Promise<{ exists: boolean }> {\n return this.request<{ exists: boolean }>('/check-user', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n signInWithPassword(data: {\n identifier: string;\n password: string;\n }): Promise<AuthResponse | VerificationResponse> {\n return this.request<AuthResponse | VerificationResponse>('/sign-in', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n signOut(): Promise<{ message: string }> {\n return this.request<{ message: string }>('/sign-out', {\n method: 'POST',\n });\n }\n\n requestEmailVerification(data?: {\n email?: string;\n }): Promise<{ verificationId: string }> {\n return this.request<{ verificationId: string }>(\n '/email/verification/request',\n {\n method: 'POST',\n body: JSON.stringify(data || {}),\n },\n );\n }\n\n verifyEmail(data: {\n verificationId: string;\n code: string;\n }): Promise<AuthResponse> {\n return this.request<AuthResponse>('/email/verification/confirm', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n resendVerification(_verificationId: string): Promise<{\n verificationId: string;\n }> {\n // For email, request new verification\n return this.requestEmailVerification();\n }\n\n requestPhoneOtp(data: {\n phone: string;\n context: 'sign-up' | 'sign-in' | 'change-phone';\n }): Promise<{ verificationId: string }> {\n return this.request<{ verificationId: string }>(\n '/phone/verification/request',\n {\n method: 'POST',\n body: JSON.stringify(data),\n },\n );\n }\n\n verifyPhoneOtp(data: {\n verificationId: string;\n code: string;\n context: 'sign-up' | 'sign-in' | 'change-phone';\n }): Promise<\n AuthResponse | { user: User | null; session: null; verified: boolean }\n > {\n return this.request('/phone/verification/confirm', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n forgotPassword(data: { identifier: string }): Promise<{\n message: string;\n }> {\n return this.request<{ message: string }>('/password/forgot', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n resetPassword(data: {\n verificationId: string;\n code: string;\n password: string;\n }): Promise<AuthResponse> {\n return this.request<AuthResponse>('/password/reset', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n changePassword(data: {\n currentPassword: string;\n newPassword: string;\n }): Promise<{ message: string }> {\n return this.request<{ message: string }>('/password/change', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n getSession(): Promise<SessionResponse> {\n return this.request<SessionResponse>('/session', {\n method: 'GET',\n });\n }\n}\n","export const validCodes = [\n 'USER_NOT_FOUND',\n 'INVALID_PASSWORD',\n 'USER_EXISTS',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'REQUIRES_VERIFICATION',\n 'UNAUTHORIZED',\n 'ACCESS_DENIED',\n 'HAS_NO_PASSWORD',\n];\n","import type { _Translator } from 'next-intl';\nimport { AuthError } from '../client';\nimport { validCodes } from '../constants/auth.error.codes';\n\nexport const handleError = (\n err: any,\n setError: (error: string | null) => void,\n t: _Translator<Record<string, any>, string>,\n) => {\n if (err instanceof AuthError) {\n let errorKey = 'errors.fallback';\n if (err.code) {\n errorKey = `errors.${err.code.toLowerCase()}`;\n } else if (err.message) {\n // Fallback: try to extract error code from message\n const messageUpper = err.message.toUpperCase().trim();\n\n if (validCodes.includes(messageUpper)) {\n errorKey = `errors.${messageUpper.toLowerCase()}`;\n }\n }\n setError(t(errorKey, { defaultValue: err.message }));\n } else {\n setError(err instanceof Error ? err.message : t('errors.fallback'));\n }\n};\n","'use client';\n\nimport { Alert, AlertDescription } from '@mesob/ui/components/alert';\nimport type { ReactNode } from 'react';\n\ntype AuthPageLayoutProps = {\n title: string;\n description?: string;\n children: ReactNode;\n error?: string | null;\n footer?: ReactNode;\n logoImage?: string;\n};\n\nexport const AuthPageLayout = ({\n title,\n description,\n children,\n error,\n footer,\n logoImage,\n}: AuthPageLayoutProps) => {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex size-8 mb-6 w-full items-center justify-center rounded-md\">\n {/** biome-ignore lint/performance/noImgElement: logo image */}\n <img src={logoImage || ''} alt=\"Jiret\" width={42} height={42} />\n </div>\n <div className=\"text-center\">\n <h1 className=\"text-2xl font-bold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n\n {children}\n\n {error && (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n <div className=\"mt-2 w-full\">\n {footer && (\n <div className=\"w-full text-center text-sm text-muted-foreground\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n","'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@mesob/ui/components/form';\nimport { Input } from '@mesob/ui/components/input';\nimport { Eye, EyeOff } from 'lucide-react';\nimport { useTranslations } from 'next-intl';\nimport { useMemo, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\n\ntype SignInFormValues = {\n account: string;\n password: string;\n};\n\ntype SignInProps = {\n onSubmit: (\n values: SignInFormValues,\n step: 'identifier' | 'password',\n ) => Promise<void> | void;\n isLoading?: boolean;\n identifier?: string;\n step?: 'identifier' | 'password';\n onBack?: () => void;\n};\n\nexport const SignIn = ({\n onSubmit,\n isLoading = false,\n identifier = '',\n step = 'identifier',\n onBack: _onBack,\n}: SignInProps) => {\n const t = useTranslations('Auth.signIn');\n const [showPassword, setShowPassword] = useState(false);\n\n const identifierSchema = useMemo(\n () =>\n z.object({\n account: z\n .string()\n .min(1, t('errors.accountRequired'))\n .email(t('errors.invalidEmail')),\n }),\n [t],\n );\n\n const passwordSchema = useMemo(\n () =>\n z.object({\n password: z\n .string()\n .min(8, t('errors.passwordLength'))\n .max(128, t('errors.longPasswordError')),\n }),\n [t],\n );\n\n const identifierForm = useForm<{ account: string }>({\n resolver: zodResolver(identifierSchema),\n defaultValues: {\n account: identifier,\n },\n });\n\n const passwordForm = useForm<{ password: string }>({\n resolver: zodResolver(passwordSchema),\n defaultValues: {\n password: '',\n },\n });\n\n const handleIdentifierSubmit = identifierForm.handleSubmit(async (values) => {\n await onSubmit({ account: values.account, password: '' }, 'identifier');\n });\n\n const handlePasswordSubmit = passwordForm.handleSubmit(async (values) => {\n await onSubmit(\n { account: identifier, password: values.password },\n 'password',\n );\n });\n\n if (step === 'password') {\n return (\n <Form {...passwordForm}>\n <form onSubmit={handlePasswordSubmit} className=\"space-y-4\">\n <div className=\"text-center\">\n <p className=\"text-sm text-muted-foreground mb-2\">\n {t('form.enterPasswordFor')}\n </p>\n <p className=\"font-bold\">{identifier}</p>\n </div>\n <FormField\n control={passwordForm.control}\n name=\"password\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.passwordLabel')}</FormLabel>\n <FormControl>\n <div className=\"relative\">\n <Input\n type={showPassword ? 'text' : 'password'}\n placeholder={t('form.passwordPlaceholder')}\n {...field}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showPassword ? (\n <EyeOff className=\"h-4 w-4\" />\n ) : (\n <Eye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n {isLoading ? t('form.submitting') : t('form.submit')}\n </Button>\n </form>\n </Form>\n );\n }\n\n return (\n <Form {...identifierForm}>\n <form onSubmit={handleIdentifierSubmit} className=\"space-y-4\">\n <FormField\n control={identifierForm.control}\n name=\"account\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{t('form.accountLabel')}</FormLabel>\n <FormControl>\n <Input\n type=\"text\"\n placeholder={t('form.accountPlaceholder')}\n {...field}\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n {isLoading ? t('form.submitting') : t('form.continue')}\n </Button>\n </form>\n </Form>\n );\n};\n"],"mappings":";;;AAEA,SAAS,mBAAAA,wBAAuB;AAEhC,SAAS,YAAAC,iBAAgB;;;ACFzB;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiEH;AAnDJ,IAAM,cAAc,cAAuC,IAAI;AAExD,IAAM,UAAU,MAAM;AAC3B,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,SAAO;AACT;;;ACNO,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACE,SACA,MACA,QACA,SACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AAAA,EACjB;AACF;;;AC1CO,IAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACRO,IAAM,cAAc,CACzB,KACA,UACA,MACG;AACH,MAAI,eAAe,WAAW;AAC5B,QAAI,WAAW;AACf,QAAI,IAAI,MAAM;AACZ,iBAAW,UAAU,IAAI,KAAK,YAAY,CAAC;AAAA,IAC7C,WAAW,IAAI,SAAS;AAEtB,YAAM,eAAe,IAAI,QAAQ,YAAY,EAAE,KAAK;AAEpD,UAAI,WAAW,SAAS,YAAY,GAAG;AACrC,mBAAW,UAAU,aAAa,YAAY,CAAC;AAAA,MACjD;AAAA,IACF;AACA,aAAS,EAAE,UAAU,EAAE,cAAc,IAAI,QAAQ,CAAC,CAAC;AAAA,EACrD,OAAO;AACL,aAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,iBAAiB,CAAC;AAAA,EACpE;AACF;;;ACvBA,SAAS,OAAO,wBAAwB;AAwBhC,gBAAAC,MAEF,YAFE;AAZD,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA2B;AACzB,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,oBAAAA,KAAC,SAAI,WAAU,kEAEb,0BAAAA,KAAC,SAAI,KAAK,aAAa,IAAI,KAAI,SAAQ,OAAO,IAAI,QAAQ,IAAI,GAChE;AAAA,IACA,qBAAC,SAAI,WAAU,eACb;AAAA,sBAAAA,KAAC,QAAG,WAAU,qCAAqC,iBAAM;AAAA,MACxD,eACC,gBAAAA,KAAC,OAAE,WAAU,sCAAsC,uBAAY;AAAA,OAEnE;AAAA,IAEC;AAAA,IAEA,SACC,gBAAAA,KAAC,SAAM,SAAQ,eACb,0BAAAA,KAAC,oBAAkB,iBAAM,GAC3B;AAAA,IAEF,gBAAAA,KAAC,SAAI,WAAU,eACZ,oBACC,gBAAAA,KAAC,SAAI,WAAU,oDACZ,kBACH,GAEJ;AAAA,KACF;AAEJ;;;ACjDA,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,KAAK,cAAc;AAC5B,SAAS,uBAAuB;AAChC,SAAS,SAAS,YAAAC,iBAAgB;AAClC,SAAS,eAAe;AACxB,SAAS,SAAS;AA+ER,SACE,OAAAC,MADF,QAAAC,aAAA;AA7DH,IAAM,SAAS,CAAC;AAAA,EACrB;AAAA,EACA,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,OAAO;AAAA,EACP,QAAQ;AACV,MAAmB;AACjB,QAAM,IAAI,gBAAgB,aAAa;AACvC,QAAM,CAAC,cAAc,eAAe,IAAIF,UAAS,KAAK;AAEtD,QAAM,mBAAmB;AAAA,IACvB,MACE,EAAE,OAAO;AAAA,MACP,SAAS,EACN,OAAO,EACP,IAAI,GAAG,EAAE,wBAAwB,CAAC,EAClC,MAAM,EAAE,qBAAqB,CAAC;AAAA,IACnC,CAAC;AAAA,IACH,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,iBAAiB;AAAA,IACrB,MACE,EAAE,OAAO;AAAA,MACP,UAAU,EACP,OAAO,EACP,IAAI,GAAG,EAAE,uBAAuB,CAAC,EACjC,IAAI,KAAK,EAAE,0BAA0B,CAAC;AAAA,IAC3C,CAAC;AAAA,IACH,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,iBAAiB,QAA6B;AAAA,IAClD,UAAU,YAAY,gBAAgB;AAAA,IACtC,eAAe;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,QAAM,eAAe,QAA8B;AAAA,IACjD,UAAU,YAAY,cAAc;AAAA,IACpC,eAAe;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AAED,QAAM,yBAAyB,eAAe,aAAa,OAAO,WAAW;AAC3E,UAAM,SAAS,EAAE,SAAS,OAAO,SAAS,UAAU,GAAG,GAAG,YAAY;AAAA,EACxE,CAAC;AAED,QAAM,uBAAuB,aAAa,aAAa,OAAO,WAAW;AACvE,UAAM;AAAA,MACJ,EAAE,SAAS,YAAY,UAAU,OAAO,SAAS;AAAA,MACjD;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,SAAS,YAAY;AACvB,WACE,gBAAAC,KAAC,QAAM,GAAG,cACR,0BAAAC,MAAC,UAAK,UAAU,sBAAsB,WAAU,aAC9C;AAAA,sBAAAA,MAAC,SAAI,WAAU,eACb;AAAA,wBAAAD,KAAC,OAAE,WAAU,sCACV,YAAE,uBAAuB,GAC5B;AAAA,QACA,gBAAAA,KAAC,OAAE,WAAU,aAAa,sBAAW;AAAA,SACvC;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,aAAa;AAAA,UACtB,MAAK;AAAA,UACL,QAAQ,CAAC,EAAE,MAAM,MACf,gBAAAC,MAAC,YACC;AAAA,4BAAAD,KAAC,aAAW,YAAE,oBAAoB,GAAE;AAAA,YACpC,gBAAAA,KAAC,eACC,0BAAAC,MAAC,SAAI,WAAU,YACb;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAM,eAAe,SAAS;AAAA,kBAC9B,aAAa,EAAE,0BAA0B;AAAA,kBACxC,GAAG;AAAA;AAAA,cACN;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,MAAM,gBAAgB,CAAC,YAAY;AAAA,kBAC5C,WAAU;AAAA,kBAET,yBACC,gBAAAA,KAAC,UAAO,WAAU,WAAU,IAE5B,gBAAAA,KAAC,OAAI,WAAU,WAAU;AAAA;AAAA,cAE7B;AAAA,eACF,GACF;AAAA,YACA,gBAAAA,KAAC,eAAY;AAAA,aACf;AAAA;AAAA,MAEJ;AAAA,MACA,gBAAAA,KAAC,UAAO,MAAK,UAAS,WAAU,UAAS,UAAU,WAChD,sBAAY,EAAE,iBAAiB,IAAI,EAAE,aAAa,GACrD;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE,gBAAAA,KAAC,QAAM,GAAG,gBACR,0BAAAC,MAAC,UAAK,UAAU,wBAAwB,WAAU,aAChD;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,eAAe;AAAA,QACxB,MAAK;AAAA,QACL,QAAQ,CAAC,EAAE,MAAM,MACf,gBAAAC,MAAC,YACC;AAAA,0BAAAD,KAAC,aAAW,YAAE,mBAAmB,GAAE;AAAA,UACnC,gBAAAA,KAAC,eACC,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAa,EAAE,yBAAyB;AAAA,cACvC,GAAG;AAAA;AAAA,UACN,GACF;AAAA,UACA,gBAAAA,KAAC,eAAY;AAAA,WACf;AAAA;AAAA,IAEJ;AAAA,IACA,gBAAAA,KAAC,UAAO,MAAK,UAAS,WAAU,UAAS,UAAU,WAChD,sBAAY,EAAE,iBAAiB,IAAI,EAAE,eAAe,GACvD;AAAA,KACF,GACF;AAEJ;;;ANvDU,SAQI,OAAAE,MARJ,QAAAC,aAAA;AArGV,IAAM,UAAU,CAAC,MAAc,yBAAyB,KAAK,CAAC;AAcvD,IAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AACF,MAAuB;AACrB,QAAM,IAAIC,iBAAgB,aAAa;AACvC,QAAM,EAAE,QAAQ,QAAQ,IAAI,QAAQ;AACpC,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAoC,YAAY;AACxE,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAiB,EAAE;AAEvD,QAAM,kBAAkB,eAAe;AACvC,QAAM,qBAAqB,OAAO,kBAAkB;AACpD,QAAM,aAAa,OAAO,UAAU;AAEpC,QAAM,eAAe,OACnB,QACA,gBACG;AACH,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,UAAI,gBAAgB,cAAc;AAChC,cAAM,cAAc,MAAM,OAAO,UAAU;AAAA,UACzC,YAAY,OAAO;AAAA,QACrB,CAAC;AAED,YAAI,YAAY,QAAQ;AACtB,wBAAc,OAAO,OAAO;AAC5B,kBAAQ,UAAU;AAAA,QACpB,OAAO;AACL,gBAAM,QAAQ,QAAQ,OAAO,OAAO,IAAI,KAAK,OAAO;AACpD,cAAI,OAAO;AACT,uBAAW,GAAG,UAAU,UAAU,mBAAmB,KAAK,CAAC,EAAE;AAAA,UAC/D,OAAO;AACL;AAAA,cACE,GAAG,UAAU,UAAU,mBAAmB,OAAO,OAAO,CAAC;AAAA,YAC3D;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,MAAM,MAAM,OAAO,mBAAmB;AAAA,UAC1C;AAAA,UACA,UAAU,OAAO;AAAA,QACnB,CAAC;AAED,YAAI,oBAAoB,OAAO,IAAI,gBAAgB;AACjD,gBAAM,aAAa,QAAQ,UAAU,IACjC,qDAAqD,IAAI,cAAc,eAAe,mBAAmB,UAAU,CAAC,KACpH,qCAAqC,IAAI,cAAc;AAC3D,qBAAW,UAAU;AACrB;AAAA,QACF;AAEA,YAAI,UAAU,OAAO,aAAa,KAAK;AACrC,kBAAQ,GAAG;AAAA,QACb;AACA,mBAAW,eAAe;AAAA,MAC5B;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,KAAK,UAAU,CAAC;AAAA,IAC9B,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,YAAQ,YAAY;AACpB,kBAAc,EAAE;AAChB,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,iBAAiB,SAAS;AAEhC,SACE,gBAAAH,KAAC,SAAI,WAAU,aACb,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,OAAO;AAAA,MAChB,aAAa,iBAAiB,SAAY,EAAE,aAAa;AAAA,MACzD;AAAA,MACA;AAAA,MACA,QACE,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,gBAAgB,iBAAiB,kBAAkB;AAAA,UACrD;AAAA,UAEC;AAAA;AAAA,YAEC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS;AAAA,gBAER,YAAE,eAAe;AAAA;AAAA,YACpB;AAAA,YAGD,OACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,WAAU;AAAA,gBAET,YAAE,uBAAuB;AAAA;AAAA,YAC5B,IAEA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,WAAU;AAAA,gBAET,YAAE,uBAAuB;AAAA;AAAA,YAC5B;AAAA;AAAA;AAAA,MAEJ;AAAA,MAGF,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":["useTranslations","useState","jsx","useState","jsx","jsxs","jsx","jsxs","useTranslations","useState"]}
@@ -0,0 +1,18 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ComponentProps } from 'react';
3
+
4
+ type SignUpPageProps = {
5
+ locale?: string;
6
+ onNavigate: (path: string) => void;
7
+ linkComponent?: React.ComponentType<ComponentProps<'a'> & {
8
+ href: string;
9
+ }>;
10
+ links?: {
11
+ signIn?: string;
12
+ };
13
+ initialIdentifier?: string;
14
+ logoImage?: string;
15
+ };
16
+ declare const SignUpPage: ({ onNavigate, linkComponent: Link, links, initialIdentifier, logoImage, }: SignUpPageProps) => react_jsx_runtime.JSX.Element;
17
+
18
+ export { SignUpPage };