@mesob/auth-react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/auth/{auth-page-layout.d.ts → auth-layout.d.ts} +3 -3
- package/dist/components/auth/{auth-page-layout.js → auth-layout.js} +4 -4
- package/dist/components/auth/auth-layout.js.map +1 -0
- package/dist/components/auth/countdown.js +15 -6
- package/dist/components/auth/countdown.js.map +1 -1
- package/dist/components/auth/forgot-password.d.ts +1 -9
- package/dist/components/auth/forgot-password.js +267 -43
- package/dist/components/auth/forgot-password.js.map +1 -1
- package/dist/components/auth/reset-password-form.d.ts +2 -10
- package/dist/components/auth/reset-password-form.js +366 -118
- package/dist/components/auth/reset-password-form.js.map +1 -1
- package/dist/components/auth/sign-in.d.ts +2 -10
- package/dist/components/auth/sign-in.js +358 -130
- package/dist/components/auth/sign-in.js.map +1 -1
- package/dist/components/auth/sign-up.d.ts +2 -10
- package/dist/components/auth/sign-up.js +379 -131
- package/dist/components/auth/sign-up.js.map +1 -1
- package/dist/components/auth/verification-form.d.ts +2 -16
- package/dist/components/auth/verification-form.js +15 -6
- package/dist/components/auth/verification-form.js.map +1 -1
- package/dist/components/auth/verify-email.d.ts +10 -0
- package/dist/components/auth/{pages/verify-email-page.js → verify-email.js} +54 -34
- package/dist/components/auth/verify-email.js.map +1 -0
- package/dist/components/auth/verify-phone.d.ts +11 -0
- package/dist/components/auth/{pages/verify-phone-page.js → verify-phone.js} +53 -46
- package/dist/components/auth/verify-phone.js.map +1 -0
- package/dist/components/error-boundary.d.ts +2 -2
- package/dist/components/iam/permissions.d.ts +5 -0
- package/dist/components/iam/{permissions/permissions-page.js → permissions.js} +29 -13
- package/dist/components/iam/permissions.js.map +1 -0
- package/dist/components/iam/roles.d.ts +5 -0
- package/dist/components/iam/{roles/roles-page.js → roles.js} +29 -13
- package/dist/components/iam/roles.js.map +1 -0
- package/dist/components/iam/sessions.d.ts +5 -0
- package/dist/components/iam/{sessions/sessions-page.js → sessions.js} +13 -11
- package/dist/components/iam/sessions.js.map +1 -0
- package/dist/components/iam/tenants.d.ts +5 -0
- package/dist/components/iam/{tenants/tenants-page.js → tenants.js} +13 -11
- package/dist/components/iam/tenants.js.map +1 -0
- package/dist/components/iam/users.d.ts +5 -0
- package/dist/components/iam/{users/users-page.js → users.js} +13 -11
- package/dist/components/iam/users.js.map +1 -0
- package/dist/components/profile/account.d.ts +5 -0
- package/dist/components/profile/account.js +66 -0
- package/dist/components/profile/account.js.map +1 -0
- package/dist/components/profile/change-email-form.d.ts +5 -0
- package/dist/components/profile/change-email-form.js +721 -0
- package/dist/components/profile/change-email-form.js.map +1 -0
- package/dist/components/profile/change-password-form.d.ts +5 -0
- package/dist/components/profile/change-password-form.js +256 -0
- package/dist/components/profile/change-password-form.js.map +1 -0
- package/dist/components/profile/change-phone-form.d.ts +5 -0
- package/dist/components/profile/change-phone-form.js +758 -0
- package/dist/components/profile/change-phone-form.js.map +1 -0
- package/dist/components/profile/change-profile.d.ts +9 -0
- package/dist/components/profile/change-profile.js +37 -0
- package/dist/components/profile/change-profile.js.map +1 -0
- package/dist/components/profile/otp-verification-modal.d.ts +15 -0
- package/dist/components/profile/otp-verification-modal.js +261 -0
- package/dist/components/profile/otp-verification-modal.js.map +1 -0
- package/dist/components/profile/request-change-email-form.d.ts +10 -0
- package/dist/components/profile/request-change-email-form.js +293 -0
- package/dist/components/profile/request-change-email-form.js.map +1 -0
- package/dist/components/profile/request-change-phone-form.d.ts +10 -0
- package/dist/components/profile/request-change-phone-form.js +331 -0
- package/dist/components/profile/request-change-phone-form.js.map +1 -0
- package/dist/components/profile/security.d.ts +5 -0
- package/dist/components/profile/security.js +1439 -0
- package/dist/components/profile/security.js.map +1 -0
- package/dist/components/profile/verify-change-email-form.d.ts +11 -0
- package/dist/components/profile/verify-change-email-form.js +402 -0
- package/dist/components/profile/verify-change-email-form.js.map +1 -0
- package/dist/components/profile/verify-change-phone-form.d.ts +11 -0
- package/dist/components/profile/verify-change-phone-form.js +406 -0
- package/dist/components/profile/verify-change-phone-form.js.map +1 -0
- package/dist/components/shared/{data-table/data-table.js → data-table.js} +2 -2
- package/dist/components/shared/data-table.js.map +1 -0
- package/dist/index.d.ts +42 -88
- package/dist/index.js +2297 -1299
- package/dist/index.js.map +1 -1
- package/dist/types-D3s9oE-5.d.ts +75 -0
- package/dist/verification-form-ipSRTtQB.d.ts +22 -0
- package/package.json +3 -2
- package/dist/components/auth/auth-page-layout.js.map +0 -1
- package/dist/components/auth/pages/forgot-password-page.d.ts +0 -6
- package/dist/components/auth/pages/forgot-password-page.js +0 -362
- package/dist/components/auth/pages/forgot-password-page.js.map +0 -1
- package/dist/components/auth/pages/reset-password-page.d.ts +0 -9
- package/dist/components/auth/pages/reset-password-page.js +0 -514
- package/dist/components/auth/pages/reset-password-page.js.map +0 -1
- package/dist/components/auth/pages/sign-in-page.d.ts +0 -8
- package/dist/components/auth/pages/sign-in-page.js +0 -565
- package/dist/components/auth/pages/sign-in-page.js.map +0 -1
- package/dist/components/auth/pages/sign-up-page.d.ts +0 -9
- package/dist/components/auth/pages/sign-up-page.js +0 -518
- package/dist/components/auth/pages/sign-up-page.js.map +0 -1
- package/dist/components/auth/pages/verify-email-page.d.ts +0 -10
- package/dist/components/auth/pages/verify-email-page.js.map +0 -1
- package/dist/components/auth/pages/verify-phone-page.d.ts +0 -11
- package/dist/components/auth/pages/verify-phone-page.js.map +0 -1
- package/dist/components/iam/permissions/permissions-page.d.ts +0 -5
- package/dist/components/iam/permissions/permissions-page.js.map +0 -1
- package/dist/components/iam/roles/roles-page.d.ts +0 -5
- package/dist/components/iam/roles/roles-page.js.map +0 -1
- package/dist/components/iam/sessions/sessions-page.d.ts +0 -5
- package/dist/components/iam/sessions/sessions-page.js.map +0 -1
- package/dist/components/iam/tenants/tenants-page.d.ts +0 -5
- package/dist/components/iam/tenants/tenants-page.js.map +0 -1
- package/dist/components/iam/users/users-page.d.ts +0 -5
- package/dist/components/iam/users/users-page.js.map +0 -1
- package/dist/components/profile/profile-page.d.ts +0 -8
- package/dist/components/profile/profile-page.js +0 -163
- package/dist/components/profile/profile-page.js.map +0 -1
- package/dist/components/shared/data-table/data-table.js.map +0 -1
- package/dist/handle-error-BqDMxnQZ.d.ts +0 -8
- /package/dist/components/shared/{data-table/data-table.d.ts → data-table.d.ts} +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/profile/request-change-email-form.tsx
|
|
4
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
|
+
import { Button } from "@mesob/ui/components/button";
|
|
6
|
+
import { Input } from "@mesob/ui/components/input";
|
|
7
|
+
import { Label } from "@mesob/ui/components/label";
|
|
8
|
+
import { Spinner } from "@mesob/ui/components/spinner";
|
|
9
|
+
import { IconEye, IconEyeOff } from "@tabler/icons-react";
|
|
10
|
+
import { useEffect, useState as useState2 } from "react";
|
|
11
|
+
import { useForm } from "react-hook-form";
|
|
12
|
+
import { toast } from "sonner";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
|
|
15
|
+
// src/provider.tsx
|
|
16
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
17
|
+
import { deepmerge } from "deepmerge-ts";
|
|
18
|
+
import createFetchClient from "openapi-fetch";
|
|
19
|
+
import createClient from "openapi-react-query";
|
|
20
|
+
import { createContext, useContext, useMemo, useState } from "react";
|
|
21
|
+
|
|
22
|
+
// src/utils/cookie.ts
|
|
23
|
+
var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
|
|
24
|
+
|
|
25
|
+
// src/provider.tsx
|
|
26
|
+
import { jsx } from "react/jsx-runtime";
|
|
27
|
+
var SessionContext = createContext(null);
|
|
28
|
+
var ApiContext = createContext(null);
|
|
29
|
+
var ConfigContext = createContext(null);
|
|
30
|
+
var queryClient = new QueryClient({
|
|
31
|
+
defaultOptions: {
|
|
32
|
+
queries: {
|
|
33
|
+
refetchOnWindowFocus: false
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
function useSession() {
|
|
38
|
+
const context = useContext(SessionContext);
|
|
39
|
+
if (!context) {
|
|
40
|
+
throw new Error("useSession must be used within MesobAuthProvider");
|
|
41
|
+
}
|
|
42
|
+
return context;
|
|
43
|
+
}
|
|
44
|
+
function useApi() {
|
|
45
|
+
const context = useContext(ApiContext);
|
|
46
|
+
if (!context) {
|
|
47
|
+
throw new Error("useApi must be used within MesobAuthProvider");
|
|
48
|
+
}
|
|
49
|
+
return context;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/components/profile/request-change-email-form.tsx
|
|
53
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
54
|
+
var emailPasswordSchema = z.object({
|
|
55
|
+
email: z.string().email("Invalid email address"),
|
|
56
|
+
password: z.string().min(8, "Password must be at least 8 characters").max(128, "Password too long")
|
|
57
|
+
});
|
|
58
|
+
function isAuthError(error) {
|
|
59
|
+
return typeof error === "object" && error !== null && ("code" in error || "message" in error || "name" in error);
|
|
60
|
+
}
|
|
61
|
+
function getErrorCode(error) {
|
|
62
|
+
if (error.code) {
|
|
63
|
+
return error.code;
|
|
64
|
+
}
|
|
65
|
+
if (error.message) {
|
|
66
|
+
const upperMessage = error.message.toUpperCase().trim();
|
|
67
|
+
const validCodes = [
|
|
68
|
+
"USER_NOT_FOUND",
|
|
69
|
+
"USER_EXISTS",
|
|
70
|
+
"INVALID_PASSWORD",
|
|
71
|
+
"VERIFICATION_EXPIRED",
|
|
72
|
+
"VERIFICATION_MISMATCH",
|
|
73
|
+
"VERIFICATION_NOT_FOUND",
|
|
74
|
+
"TOO_MANY_ATTEMPTS",
|
|
75
|
+
"UNAUTHORIZED"
|
|
76
|
+
];
|
|
77
|
+
if (validCodes.includes(upperMessage)) {
|
|
78
|
+
return upperMessage;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
function getErrorMessage(error) {
|
|
84
|
+
if (isAuthError(error)) {
|
|
85
|
+
const errorCode = getErrorCode(error);
|
|
86
|
+
switch (errorCode) {
|
|
87
|
+
case "USER_EXISTS":
|
|
88
|
+
return "This email is already taken. Please use a different email.";
|
|
89
|
+
case "VERIFICATION_EXPIRED":
|
|
90
|
+
return "Verification code has expired. Please request a new one.";
|
|
91
|
+
case "VERIFICATION_MISMATCH":
|
|
92
|
+
return "Invalid verification code. Please try again.";
|
|
93
|
+
case "VERIFICATION_NOT_FOUND":
|
|
94
|
+
return "Verification not found. Please request a new code.";
|
|
95
|
+
default:
|
|
96
|
+
return error.message || "An error occurred. Please try again.";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (error instanceof Error) {
|
|
100
|
+
return error.message;
|
|
101
|
+
}
|
|
102
|
+
return "An error occurred. Please try again.";
|
|
103
|
+
}
|
|
104
|
+
function RequestChangeEmailForm({
|
|
105
|
+
onSuccess,
|
|
106
|
+
onCancel,
|
|
107
|
+
buttonText
|
|
108
|
+
}) {
|
|
109
|
+
const { user } = useSession();
|
|
110
|
+
const { hooks } = useApi();
|
|
111
|
+
const [isSubmitting, setIsSubmitting] = useState2(false);
|
|
112
|
+
const [isChecking, setIsChecking] = useState2(true);
|
|
113
|
+
const [showPassword, setShowPassword] = useState2(false);
|
|
114
|
+
const getPendingAccountChangeQuery = hooks.useQuery(
|
|
115
|
+
"get",
|
|
116
|
+
"/account-change/pending",
|
|
117
|
+
{},
|
|
118
|
+
{ enabled: false }
|
|
119
|
+
);
|
|
120
|
+
const verifyPasswordMutation = hooks.useMutation("post", "/password/verify");
|
|
121
|
+
const checkUserMutation = hooks.useMutation("post", "/check-account");
|
|
122
|
+
const requestEmailVerificationMutation = hooks.useMutation(
|
|
123
|
+
"post",
|
|
124
|
+
"/email/verification/request"
|
|
125
|
+
);
|
|
126
|
+
const emailPasswordForm = useForm({
|
|
127
|
+
resolver: zodResolver(emailPasswordSchema),
|
|
128
|
+
defaultValues: {
|
|
129
|
+
email: "",
|
|
130
|
+
password: ""
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const {
|
|
134
|
+
register,
|
|
135
|
+
handleSubmit,
|
|
136
|
+
getValues,
|
|
137
|
+
setValue,
|
|
138
|
+
formState: { errors }
|
|
139
|
+
} = emailPasswordForm;
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
let active = true;
|
|
142
|
+
const run = async () => {
|
|
143
|
+
try {
|
|
144
|
+
const data = await getPendingAccountChangeQuery.refetch();
|
|
145
|
+
if (!active) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const accountChange = data.data?.accountChange;
|
|
149
|
+
const verificationId = data.data?.verificationId;
|
|
150
|
+
if (accountChange?.changeType !== "email") {
|
|
151
|
+
setIsChecking(false);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!accountChange.newEmail) {
|
|
155
|
+
setIsChecking(false);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (getValues("email")) {
|
|
159
|
+
setIsChecking(false);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
setValue("email", accountChange.newEmail, { shouldValidate: true });
|
|
163
|
+
if (verificationId) {
|
|
164
|
+
toast.message("Resuming verification\u2026");
|
|
165
|
+
onSuccess(verificationId, accountChange.newEmail);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
setIsChecking(false);
|
|
169
|
+
} catch {
|
|
170
|
+
setIsChecking(false);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
run().catch(() => void 0);
|
|
174
|
+
return () => {
|
|
175
|
+
active = false;
|
|
176
|
+
};
|
|
177
|
+
}, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);
|
|
178
|
+
const onEmailPasswordSubmit = async (data) => {
|
|
179
|
+
if (!user) {
|
|
180
|
+
toast.error("User not found");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
setIsSubmitting(true);
|
|
185
|
+
await verifyPasswordMutation.mutateAsync({
|
|
186
|
+
body: { password: data.password }
|
|
187
|
+
});
|
|
188
|
+
const checkResult = await checkUserMutation.mutateAsync({
|
|
189
|
+
body: { identifier: data.email }
|
|
190
|
+
});
|
|
191
|
+
if (checkResult.data?.exists) {
|
|
192
|
+
if (user?.email?.toLowerCase() === data.email.toLowerCase()) {
|
|
193
|
+
toast.error("This is already your current email address.");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
toast.error(
|
|
197
|
+
"This email is already taken. Please use a different email."
|
|
198
|
+
);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const verification = await requestEmailVerificationMutation.mutateAsync({
|
|
202
|
+
body: { email: data.email }
|
|
203
|
+
});
|
|
204
|
+
toast.success("Verification code sent to your email");
|
|
205
|
+
onSuccess(verification.data?.verificationId ?? "", data.email);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
const errorMessage = getErrorMessage(error);
|
|
208
|
+
if (isAuthError(error)) {
|
|
209
|
+
const errorCode = getErrorCode(error);
|
|
210
|
+
if (errorCode === "INVALID_PASSWORD" || errorCode === "USER_NOT_FOUND") {
|
|
211
|
+
toast.error("Incorrect password. Please try again.");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
toast.error(errorMessage);
|
|
216
|
+
} finally {
|
|
217
|
+
setIsSubmitting(false);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const isLoading = isSubmitting || isChecking;
|
|
221
|
+
return /* @__PURE__ */ jsxs(
|
|
222
|
+
"form",
|
|
223
|
+
{
|
|
224
|
+
onSubmit: handleSubmit(onEmailPasswordSubmit),
|
|
225
|
+
className: "p-4 space-y-4 border-t",
|
|
226
|
+
children: [
|
|
227
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 w-full md:w-1/2", children: [
|
|
228
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
229
|
+
/* @__PURE__ */ jsx2(Label, { htmlFor: "email", children: "New Email Address" }),
|
|
230
|
+
/* @__PURE__ */ jsx2(
|
|
231
|
+
Input,
|
|
232
|
+
{
|
|
233
|
+
id: "email",
|
|
234
|
+
type: "email",
|
|
235
|
+
placeholder: "Enter your new email",
|
|
236
|
+
...register("email"),
|
|
237
|
+
disabled: isLoading
|
|
238
|
+
}
|
|
239
|
+
),
|
|
240
|
+
errors.email && /* @__PURE__ */ jsx2("p", { className: "text-sm text-destructive", children: errors.email.message })
|
|
241
|
+
] }),
|
|
242
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
243
|
+
/* @__PURE__ */ jsx2(Label, { htmlFor: "password", children: "Password" }),
|
|
244
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
245
|
+
/* @__PURE__ */ jsx2(
|
|
246
|
+
Input,
|
|
247
|
+
{
|
|
248
|
+
id: "password",
|
|
249
|
+
type: showPassword ? "text" : "password",
|
|
250
|
+
autoComplete: "current-password",
|
|
251
|
+
placeholder: "Enter your password",
|
|
252
|
+
...register("password"),
|
|
253
|
+
disabled: isLoading
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
/* @__PURE__ */ jsx2(
|
|
257
|
+
"button",
|
|
258
|
+
{
|
|
259
|
+
type: "button",
|
|
260
|
+
onClick: () => setShowPassword(!showPassword),
|
|
261
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
262
|
+
disabled: isLoading,
|
|
263
|
+
children: showPassword ? /* @__PURE__ */ jsx2(IconEyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx2(IconEye, { className: "h-4 w-4" })
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] }),
|
|
267
|
+
errors.password && /* @__PURE__ */ jsx2("p", { className: "text-sm text-destructive", children: errors.password.message })
|
|
268
|
+
] })
|
|
269
|
+
] }),
|
|
270
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
271
|
+
/* @__PURE__ */ jsx2(
|
|
272
|
+
Button,
|
|
273
|
+
{
|
|
274
|
+
type: "button",
|
|
275
|
+
variant: "outline",
|
|
276
|
+
onClick: onCancel,
|
|
277
|
+
disabled: isLoading,
|
|
278
|
+
children: "Cancel"
|
|
279
|
+
}
|
|
280
|
+
),
|
|
281
|
+
/* @__PURE__ */ jsxs(Button, { type: "submit", disabled: isLoading, children: [
|
|
282
|
+
isLoading && /* @__PURE__ */ jsx2(Spinner, { className: "mr-2 h-4 w-4" }),
|
|
283
|
+
isChecking ? "Checking\u2026" : buttonText
|
|
284
|
+
] })
|
|
285
|
+
] })
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
export {
|
|
291
|
+
RequestChangeEmailForm
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=request-change-email-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/profile/request-change-email-form.tsx","../../../src/provider.tsx","../../../src/utils/cookie.ts"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { Button } from '@mesob/ui/components/button';\nimport { Input } from '@mesob/ui/components/input';\nimport { Label } from '@mesob/ui/components/label';\nimport { Spinner } from '@mesob/ui/components/spinner';\nimport { IconEye, IconEyeOff } from '@tabler/icons-react';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\nimport { useApi, useSession } from '../../provider';\n\nconst emailPasswordSchema = z.object({\n email: z.string().email('Invalid email address'),\n password: z\n .string()\n .min(8, 'Password must be at least 8 characters')\n .max(128, 'Password too long'),\n});\n\ntype EmailPasswordFormData = z.infer<typeof emailPasswordSchema>;\n\ntype AuthErrorLike = {\n code?: string;\n message?: string;\n name?: string;\n};\n\nfunction isAuthError(error: unknown): error is AuthErrorLike {\n return (\n typeof error === 'object' &&\n error !== null &&\n ('code' in error || 'message' in error || 'name' in error)\n );\n}\n\nfunction getErrorCode(error: AuthErrorLike): string | undefined {\n if (error.code) {\n return error.code;\n }\n if (error.message) {\n const upperMessage = error.message.toUpperCase().trim();\n const validCodes = [\n 'USER_NOT_FOUND',\n 'USER_EXISTS',\n 'INVALID_PASSWORD',\n 'VERIFICATION_EXPIRED',\n 'VERIFICATION_MISMATCH',\n 'VERIFICATION_NOT_FOUND',\n 'TOO_MANY_ATTEMPTS',\n 'UNAUTHORIZED',\n ];\n if (validCodes.includes(upperMessage)) {\n return upperMessage;\n }\n }\n return undefined;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n switch (errorCode) {\n case 'USER_EXISTS':\n return 'This email is already taken. Please use a different email.';\n case 'VERIFICATION_EXPIRED':\n return 'Verification code has expired. Please request a new one.';\n case 'VERIFICATION_MISMATCH':\n return 'Invalid verification code. Please try again.';\n case 'VERIFICATION_NOT_FOUND':\n return 'Verification not found. Please request a new code.';\n default:\n return error.message || 'An error occurred. Please try again.';\n }\n }\n if (error instanceof Error) {\n return error.message;\n }\n return 'An error occurred. Please try again.';\n}\n\ninterface RequestChangeEmailFormProps {\n onSuccess: (verificationId: string, email: string) => void;\n onCancel: () => void;\n buttonText: string;\n}\n\nexport function RequestChangeEmailForm({\n onSuccess,\n onCancel,\n buttonText,\n}: RequestChangeEmailFormProps) {\n const { user } = useSession();\n const { hooks } = useApi();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isChecking, setIsChecking] = useState(true);\n const [showPassword, setShowPassword] = useState(false);\n\n const getPendingAccountChangeQuery = hooks.useQuery(\n 'get',\n '/account-change/pending',\n {},\n { enabled: false },\n );\n const verifyPasswordMutation = hooks.useMutation('post', '/password/verify');\n const checkUserMutation = hooks.useMutation('post', '/check-account');\n const requestEmailVerificationMutation = hooks.useMutation(\n 'post',\n '/email/verification/request',\n );\n\n const emailPasswordForm = useForm<EmailPasswordFormData>({\n resolver: zodResolver(emailPasswordSchema),\n defaultValues: {\n email: '',\n password: '',\n },\n });\n\n const {\n register,\n handleSubmit,\n getValues,\n setValue,\n formState: { errors },\n } = emailPasswordForm;\n\n useEffect(() => {\n let active = true;\n const run = async () => {\n try {\n const data = await getPendingAccountChangeQuery.refetch();\n if (!active) {\n return;\n }\n const accountChange = data.data?.accountChange;\n const verificationId = data.data?.verificationId;\n if (accountChange?.changeType !== 'email') {\n setIsChecking(false);\n return;\n }\n if (!accountChange.newEmail) {\n setIsChecking(false);\n return;\n }\n if (getValues('email')) {\n setIsChecking(false);\n return;\n }\n setValue('email', accountChange.newEmail, { shouldValidate: true });\n\n if (verificationId) {\n toast.message('Resuming verification…');\n onSuccess(verificationId, accountChange.newEmail);\n return;\n }\n\n setIsChecking(false);\n } catch {\n setIsChecking(false);\n }\n };\n run().catch(() => undefined);\n return () => {\n active = false;\n };\n }, [getPendingAccountChangeQuery.refetch, getValues, onSuccess, setValue]);\n\n const onEmailPasswordSubmit = async (data: EmailPasswordFormData) => {\n if (!user) {\n toast.error('User not found');\n return;\n }\n\n try {\n setIsSubmitting(true);\n\n // Verify password first\n await verifyPasswordMutation.mutateAsync({\n body: { password: data.password },\n });\n\n // Check if email exists\n const checkResult = await checkUserMutation.mutateAsync({\n body: { identifier: data.email },\n });\n if (checkResult.data?.exists) {\n // Check if it belongs to current user\n if (user?.email?.toLowerCase() === data.email.toLowerCase()) {\n toast.error('This is already your current email address.');\n return;\n }\n toast.error(\n 'This email is already taken. Please use a different email.',\n );\n return;\n }\n\n // Request verification\n const verification = await requestEmailVerificationMutation.mutateAsync({\n body: { email: data.email },\n });\n\n toast.success('Verification code sent to your email');\n onSuccess(verification.data?.verificationId ?? '', data.email);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n if (isAuthError(error)) {\n const errorCode = getErrorCode(error);\n if (\n errorCode === 'INVALID_PASSWORD' ||\n errorCode === 'USER_NOT_FOUND'\n ) {\n toast.error('Incorrect password. Please try again.');\n return;\n }\n }\n toast.error(errorMessage);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const isLoading = isSubmitting || isChecking;\n\n return (\n <form\n onSubmit={handleSubmit(onEmailPasswordSubmit)}\n className=\"p-4 space-y-4 border-t\"\n >\n <div className=\"space-y-4 w-full md:w-1/2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">New Email Address</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"Enter your new email\"\n {...register('email')}\n disabled={isLoading}\n />\n {errors.email && (\n <p className=\"text-sm text-destructive\">{errors.email.message}</p>\n )}\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <div className=\"relative\">\n <Input\n id=\"password\"\n type={showPassword ? 'text' : 'password'}\n autoComplete=\"current-password\"\n placeholder=\"Enter your password\"\n {...register('password')}\n disabled={isLoading}\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 disabled={isLoading}\n >\n {showPassword ? (\n <IconEyeOff className=\"h-4 w-4\" />\n ) : (\n <IconEye className=\"h-4 w-4\" />\n )}\n </button>\n </div>\n {errors.password && (\n <p className=\"text-sm text-destructive\">\n {errors.password.message}\n </p>\n )}\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onCancel}\n disabled={isLoading}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={isLoading}>\n {isLoading && <Spinner className=\"mr-2 h-4 w-4\" />}\n {isChecking ? 'Checking…' : buttonText}\n </Button>\n </div>\n </form>\n );\n}\n","'use client';\n\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { deepmerge } from 'deepmerge-ts';\nimport createFetchClient from 'openapi-fetch';\nimport createClient from 'openapi-react-query';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useMemo, useState } from 'react';\nimport type { paths } from './data/openapi';\nimport { createTranslator } from './lib/translations';\nimport {\n type AuthClientConfig,\n type AuthResponse,\n defaultAuthClientConfig,\n type Session,\n type User,\n} from './types';\nimport { getSessionCookieName } from './utils/cookie';\nimport { createCustomFetch } from './utils/custom-fetch';\n\n// biome-ignore lint/suspicious/noExplicitAny: OpenAPI hooks type\ntype OpenApiHooks = any;\n\n// --- Utility: Check if running on server ---\nfunction isServer(): boolean {\n return typeof document === 'undefined';\n}\n\n/**\n * @deprecated Cookie is httpOnly and cannot be read client-side.\n * Use `useSession().isAuthenticated` instead.\n * This function always returns false on client.\n */\nexport function hasAuthCookie(_cookieName: string): boolean {\n // Cookie is httpOnly, can't check client-side\n // Always return false - use useSession() for auth status\n return false;\n}\n\n// --- Types ---\nexport type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\ntype AuthState = {\n user: User | null;\n session: Session | null;\n status: AuthStatus;\n error: Error | null;\n};\n\ntype SessionContextValue = AuthState & {\n isLoading: boolean;\n isAuthenticated: boolean;\n refresh: () => Promise<void>;\n signOut: () => Promise<void>;\n};\n\ntype ApiContextValue = {\n hooks: OpenApiHooks;\n setAuth: (auth: AuthResponse) => void;\n clearAuth: () => void;\n refresh: () => Promise<void>;\n};\n\ntype ConfigContextValue = {\n config: AuthClientConfig;\n cookieName: string;\n t: (key: string, params?: Record<string, string | number>) => string;\n};\n\nconst SessionContext = createContext<SessionContextValue | null>(null);\nconst ApiContext = createContext<ApiContextValue | null>(null);\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n },\n },\n});\n\n// --- Hooks ---\n\n/**\n * Get session state including user, session, and auth status.\n * - `status`: 'loading' | 'authenticated' | 'unauthenticated'\n * - `isLoading`: true while fetching session\n * - `isAuthenticated`: true if user and session exist\n */\nexport function useSession(): SessionContextValue {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error('useSession must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useApi(): ApiContextValue {\n const context = useContext(ApiContext);\n if (!context) {\n throw new Error('useApi must be used within MesobAuthProvider');\n }\n return context;\n}\n\nexport function useConfig(): ConfigContextValue {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error('useConfig must be used within MesobAuthProvider');\n }\n return context;\n}\n\n/**\n * @deprecated Cookie is httpOnly, can't be checked client-side.\n * Use `useSession().isAuthenticated` instead.\n */\nexport function useHasAuthCookie(): boolean {\n const { status } = useSession();\n return status === 'authenticated' || status === 'loading';\n}\n\n// --- Provider ---\n\ntype MesobAuthProviderProps = {\n config: AuthClientConfig;\n children: ReactNode;\n};\n\nexport function MesobAuthProvider({\n config,\n children,\n}: MesobAuthProviderProps) {\n const mergedConfig = useMemo(\n () =>\n deepmerge(\n { ...defaultAuthClientConfig } as Partial<AuthClientConfig>,\n config,\n ) as AuthClientConfig,\n [config],\n );\n\n const api = useMemo(\n () =>\n createFetchClient<paths>({\n baseUrl: mergedConfig.baseURL,\n fetch: createCustomFetch(mergedConfig),\n }),\n [mergedConfig],\n );\n\n const hooks = useMemo(() => createClient(api), [api]);\n const cookieName = useMemo(\n () => getSessionCookieName(mergedConfig),\n [mergedConfig],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <AuthStateProvider\n config={mergedConfig}\n hooks={hooks}\n cookieName={cookieName}\n >\n {children}\n </AuthStateProvider>\n </QueryClientProvider>\n );\n}\n\ntype AuthStateProviderProps = {\n config: AuthClientConfig;\n hooks: OpenApiHooks;\n cookieName: string;\n children: ReactNode;\n};\n\nfunction AuthStateProvider({\n config,\n hooks,\n cookieName,\n children,\n}: AuthStateProviderProps) {\n // Manual override for sign-out / sign-in\n const [override, setOverride] = useState<AuthState | null>(null);\n\n // Always fetch session - cookie is httpOnly, can't check client-side\n // Server will read the cookie and return user/session if valid\n const {\n data: sessionData,\n isLoading,\n isFetched,\n error: sessionError,\n refetch,\n } = hooks.useQuery(\n 'get',\n '/session',\n {},\n {\n enabled: !(override || isServer()),\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n gcTime: 0,\n staleTime: 0,\n },\n );\n\n // Derive state directly - no useEffect\n const user = override?.user ?? sessionData?.user ?? null;\n const session = override?.session ?? sessionData?.session ?? null;\n const error = override?.error ?? (sessionError as Error | null);\n\n // Check error status code\n const errorStatus = (() => {\n if (!sessionError) {\n return null;\n }\n const err = sessionError as { status?: number };\n return err.status ?? null;\n })();\n\n // Check if error is a network/connection error\n const isNetworkError = (() => {\n if (!sessionError) {\n return false;\n }\n const error = sessionError as Error & { cause?: unknown; data?: unknown };\n const errorMessage =\n error.message || String(error) || JSON.stringify(error);\n // Network errors: TypeError, DOMException, or fetch failures\n if (\n error instanceof TypeError ||\n error instanceof DOMException ||\n error.name === 'TypeError' ||\n errorMessage.includes('Failed to fetch') ||\n errorMessage.includes('ERR_CONNECTION_REFUSED') ||\n errorMessage.includes('NetworkError') ||\n errorMessage.includes('Network request failed') ||\n errorMessage.includes('fetch failed')\n ) {\n return true;\n }\n // Check error cause\n if (error.cause) {\n const causeStr = String(error.cause);\n if (\n causeStr.includes('Failed to fetch') ||\n causeStr.includes('ERR_CONNECTION_REFUSED') ||\n causeStr.includes('NetworkError')\n ) {\n return true;\n }\n }\n return false;\n })();\n\n // Compute status\n // biome-ignore lint: Status determination requires multiple checks\n const status: AuthStatus = (() => {\n if (override) {\n return override.status;\n }\n if (isServer()) {\n return 'loading';\n }\n if (user && session) {\n return 'authenticated';\n }\n // Check for network errors or auth errors first - allow auth page to show\n if (isNetworkError || errorStatus === 401) {\n return 'unauthenticated';\n }\n // If we have an error but it's not a network error, still check loading state\n if (sessionError && !isNetworkError && errorStatus !== 401) {\n if (errorStatus && errorStatus >= 500) {\n return 'authenticated';\n }\n // Other errors mean unauthenticated\n if (isFetched) {\n return 'unauthenticated';\n }\n }\n if (isLoading || !isFetched) {\n return 'loading';\n }\n if (isFetched && !user && !session) {\n return 'unauthenticated';\n }\n return 'unauthenticated';\n })();\n\n const signOutMutation = hooks.useMutation('post', '/sign-out');\n const t = createTranslator(config.messages || {});\n\n const setAuth = (auth: AuthResponse) => {\n setOverride({\n user: auth.user,\n session: auth.session,\n status: 'authenticated',\n error: null,\n });\n };\n\n const clearAuth = () => {\n setOverride({\n user: null,\n session: null,\n status: 'unauthenticated',\n error: null,\n });\n };\n\n const refresh = async () => {\n setOverride(null);\n await refetch();\n };\n\n const signOut = async () => {\n try {\n await signOutMutation.mutateAsync({});\n } finally {\n clearAuth();\n }\n };\n\n return (\n <ConfigContext.Provider value={{ config, cookieName, t }}>\n <ApiContext.Provider value={{ hooks, setAuth, clearAuth, refresh }}>\n <SessionContext.Provider\n value={{\n user,\n session,\n status,\n error,\n isLoading: status === 'loading',\n isAuthenticated: status === 'authenticated',\n refresh,\n signOut,\n }}\n >\n {children}\n </SessionContext.Provider>\n </ApiContext.Provider>\n </ConfigContext.Provider>\n );\n}\n","import type { AuthClientConfig } from '../types';\n\nconst isProduction =\n typeof process !== 'undefined' && process.env.NODE_ENV === 'production';\n\nexport const getSessionCookieName = (config: AuthClientConfig): string => {\n const prefix = config.cookiePrefix || '';\n const baseName = 'session_token';\n if (prefix) {\n return `${prefix}_${baseName}`;\n }\n return isProduction ? '__Host-session_token' : baseName;\n};\n"],"mappings":"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","names":["useState","jsx","useState"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface RequestChangePhoneFormProps {
|
|
4
|
+
onSuccess: (verificationId: string, phone: string) => void;
|
|
5
|
+
onCancel: () => void;
|
|
6
|
+
buttonText: string;
|
|
7
|
+
}
|
|
8
|
+
declare function RequestChangePhoneForm({ onSuccess, onCancel, buttonText, }: RequestChangePhoneFormProps): react_jsx_runtime.JSX.Element;
|
|
9
|
+
|
|
10
|
+
export { RequestChangePhoneForm };
|