@explita/cloud-auth-client 0.1.2 → 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/change-password.js +2 -2
- package/dist/components/login-form.js +3 -4
- package/dist/components/message.js +2 -2
- package/dist/components/must-login.js +20 -8
- package/dist/components/reset-password.js +3 -3
- package/dist/components/signup-form.js +3 -3
- package/dist/components/toggle-2fa.js +1 -1
- package/dist/components/toggle-account-status.js +5 -4
- package/dist/contexts/auth-provider.js +37 -36
- package/dist/lib/api-server.js +1 -0
- package/dist/server/server-session.d.ts +2 -8
- package/dist/server/server-session.js +16 -15
- package/dist/styles.css +5 -47
- package/dist/types.d.ts +7 -0
- package/package.json +66 -65
|
@@ -66,8 +66,8 @@ function ChangePassword({ user, open, onOpenChange, onSubmit, onSuccess, }) {
|
|
|
66
66
|
user?.email)))),
|
|
67
67
|
react_1.default.createElement("div", { className: "ecpauth:px-6 ecpauth:pb-8" },
|
|
68
68
|
state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
|
|
69
|
-
react_1.default.createElement(message_1.Message, { message: state?.message,
|
|
70
|
-
react_1.default.createElement(message_1.Message, { message: state?.message
|
|
69
|
+
react_1.default.createElement(message_1.Message, { message: state?.message, variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
|
|
70
|
+
react_1.default.createElement(message_1.Message, { message: state?.message }))) : null,
|
|
71
71
|
react_1.default.createElement("div", { className: "ecpauth:space-y-5" },
|
|
72
72
|
react_1.default.createElement("div", { className: "ecpauth:space-y-2" },
|
|
73
73
|
react_1.default.createElement(label_1.Label, { htmlFor: "password", className: "ecpauth:text-sm ecpauth:font-semibold ecpauth:text-gray-700 ecpauth:dark:text-gray-300 ecpauth:ml-0.5" }, "New Password"),
|
|
@@ -77,7 +77,6 @@ function Login({ className, logo, ...props }) {
|
|
|
77
77
|
setIsAuthenticated(true);
|
|
78
78
|
}
|
|
79
79
|
setIsPending(false);
|
|
80
|
-
// return { email: formData.get("email") as string };
|
|
81
80
|
}
|
|
82
81
|
return (react_1.default.createElement("div", { className: (0, utils_1.cn)("ecpauth:relative ecpauth:flex ecpauth:flex-col ecpauth:items-center ecpauth:justify-center ecpauth:w-full ecpauth:mx-auto ecpauth:px-4", className), ...props },
|
|
83
82
|
isAuthenticated && react_1.default.createElement(loader_1.Loader, null),
|
|
@@ -91,18 +90,18 @@ function Login({ className, logo, ...props }) {
|
|
|
91
90
|
react_1.default.createElement(card_1.CardTitle, { className: "ecpauth:text-2xl ecpauth:font-black ecpauth:tracking-tight ecpauth:text-gray-900 ecpauth:dark:text-white" }, "Welcome Back"),
|
|
92
91
|
react_1.default.createElement(card_1.CardDescription, { className: "ecpauth:text-sm ecpauth:text-gray-500 ecpauth:dark:text-gray-400" }, "Enter your credentials to access the dashboard.")),
|
|
93
92
|
error?.message && (react_1.default.createElement("p", { className: "ecpauth:text-red-500 ecpauth:mt-3 ecpauth:text-sm ecpauth:font-medium" }, error.message))),
|
|
94
|
-
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:px-12" },
|
|
93
|
+
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:lg:px-12" },
|
|
95
94
|
react_1.default.createElement("form", { onSubmit: handleSubmit, className: "ecpauth:space-y-6" },
|
|
96
95
|
react_1.default.createElement("div", { className: "ecpauth:space-y-4" },
|
|
97
96
|
react_1.default.createElement("div", { className: "ecpauth:space-y-2" },
|
|
98
97
|
react_1.default.createElement(label_1.Label, { htmlFor: "email", className: "ecpauth:text-sm ecpauth:font-medium ecpauth:text-gray-700 ecpauth:dark:text-gray-300" }, "Email Address or Username"),
|
|
99
98
|
react_1.default.createElement(input_1.Input, { id: "email", type: "text", placeholder: "e.g. user@example.com", name: "email" }),
|
|
100
|
-
react_1.default.createElement(message_1.Message, { message: error?.errors?.email, className: "ecpauth:mt-1 ecpauth:text-[11px]
|
|
99
|
+
react_1.default.createElement(message_1.Message, { message: error?.errors?.email, className: "ecpauth:mt-1 ecpauth:text-[11px]" })),
|
|
101
100
|
react_1.default.createElement("div", { className: "ecpauth:space-y-2" },
|
|
102
101
|
react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:items-center ecpauth:justify-between" },
|
|
103
102
|
react_1.default.createElement(label_1.Label, { htmlFor: "password", className: "ecpauth:text-sm ecpauth:font-medium ecpauth:text-gray-700 ecpauth:dark:text-gray-300" }, "Password")),
|
|
104
103
|
react_1.default.createElement(input_1.Input, { id: "password", type: "password", name: "password", placeholder: "Enter your password" }),
|
|
105
|
-
react_1.default.createElement(message_1.Message, { message: error?.errors?.password, className: "ecpauth:mt-1 ecpauth:text-[11px]
|
|
104
|
+
react_1.default.createElement(message_1.Message, { message: error?.errors?.password, className: "ecpauth:mt-1 ecpauth:text-[11px]" }),
|
|
106
105
|
react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:justify-end" }, resetPasswordUrl && (react_1.default.createElement("a", { href: resetPasswordUrl, className: "ecpauth:text-xs ecpauth:font-semibold ecpauth:text-blue-600 ecpauth:hover:text-blue-700 ecpauth:hover:underline" }, "Forgot Password?"))))),
|
|
107
106
|
react_1.default.createElement(button_1.Button, { type: "submit", className: "ecpauth:w-full ecpauth:h-11 ecpauth:bg-blue-600! ecpauth:hover:bg-blue-700! ecpauth:text-white! ecpauth:font-semibold ecpauth:text-base ecpauth:shadow-lg ecpauth:shadow-blue-600/20 ecpauth:rounded-lg ecpauth:transition-all ecpauth:active:scale-[0.98]", disabled: isPending || isAuthenticated }, isPending ? "Logging In..." : "Log In")),
|
|
108
107
|
signupUrl && (react_1.default.createElement("div", { className: "ecpauth:text-center ecpauth:text-sm ecpauth:text-gray-500 ecpauth:border-t ecpauth:border-gray-100 ecpauth:dark:border-gray-800 ecpauth:pt-6" },
|
|
@@ -10,6 +10,6 @@ function Message({ message, variant = "error", className = "ecpauth:-mt-2", }) {
|
|
|
10
10
|
if (!message)
|
|
11
11
|
return null;
|
|
12
12
|
return (react_1.default.createElement("div", { className: (0, utils_1.cn)("ecpauth:text-sm", variant === "success"
|
|
13
|
-
? "ecpauth:text-green-
|
|
14
|
-
: "ecpauth:text-red-
|
|
13
|
+
? "ecpauth:font-medium ecpauth:text-sm ecpauth:p-3 ecpauth:rounded-lg ecpauth:bg-green-50 ecpauth:dark:bg-green-900/10 ecpauth:border ecpauth:border-green-100 ecpauth:dark:border-green-800/30 ecpauth:text-green-700 ecpauth:dark:text-green-400"
|
|
14
|
+
: "ecpauth:font-medium ecpauth:text-sm ecpauth:p-3 ecpauth:rounded-lg ecpauth:bg-red-50 ecpauth:dark:bg-red-900/10 ecpauth:border ecpauth:border-red-100 ecpauth:dark:border-red-800/30 ecpauth:text-red-700 ecpauth:dark:text-red-400", className) }, message));
|
|
15
15
|
}
|
|
@@ -6,18 +6,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.MustLogin = MustLogin;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const button_1 = require("./ui/button");
|
|
9
|
-
const message_1 = require("./message");
|
|
10
9
|
const dialog_1 = require("./ui/dialog");
|
|
11
10
|
const utils_1 = require("../lib/utils");
|
|
11
|
+
const lock_1 = require("./icons/lock");
|
|
12
|
+
const auth_provider_1 = require("../contexts/auth-provider");
|
|
12
13
|
function MustLogin({ onOpenChange, }) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
react_1.default.createElement("div", { className: "ecpauth:
|
|
17
|
-
react_1.default.createElement(
|
|
18
|
-
|
|
14
|
+
const { computedRouteContext } = (0, auth_provider_1.useAuth)();
|
|
15
|
+
const { loginUrl } = computedRouteContext;
|
|
16
|
+
return (react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:flex-col" },
|
|
17
|
+
react_1.default.createElement("div", { className: "ecpauth:relative ecpauth:px-6 ecpauth:pt-8 ecpauth:pb-6 ecpauth:text-center" },
|
|
18
|
+
react_1.default.createElement("div", { className: "ecpauth:relative ecpauth:z-10 ecpauth:flex ecpauth:flex-col ecpauth:items-center ecpauth:justify-center" },
|
|
19
|
+
react_1.default.createElement("div", { className: "ecpauth:size-12 ecpauth:rounded-xl ecpauth:bg-blue-50 ecpauth:dark:bg-blue-900/20 ecpauth:text-blue-600 ecpauth:dark:text-blue-400 ecpauth:border ecpauth:border-blue-100 ecpauth:dark:border-blue-800/50 ecpauth:flex ecpauth:items-center ecpauth:justify-center ecpauth:mb-4 ecpauth:shadow-sm" },
|
|
20
|
+
react_1.default.createElement(lock_1.LockIcon, { size: 24 })),
|
|
21
|
+
react_1.default.createElement(dialog_1.DialogHeader, { className: "ecpauth:space-y-1" },
|
|
22
|
+
react_1.default.createElement(dialog_1.DialogTitle, { className: "ecpauth:text-xl ecpauth:font-bold ecpauth:text-gray-900 ecpauth:dark:text-white ecpauth:text-center" }, "Session Required"),
|
|
23
|
+
react_1.default.createElement(dialog_1.DialogDescription, { className: "ecpauth:text-gray-500 ecpauth:dark:text-gray-400 ecpauth:text-center" }, "Please log in to continue")))),
|
|
24
|
+
react_1.default.createElement("div", { className: "ecpauth:px-8 ecpauth:pb-6" },
|
|
25
|
+
react_1.default.createElement("div", { className: "ecpauth:p-4 ecpauth:rounded-xl ecpauth:bg-gray-50 ecpauth:dark:bg-white/5 ecpauth:border ecpauth:border-gray-100 ecpauth:dark:border-white/10" },
|
|
26
|
+
react_1.default.createElement("p", { className: "ecpauth:text-sm ecpauth:leading-relaxed ecpauth:text-gray-600 ecpauth:dark:text-gray-300 ecpauth:text-center" }, "Your current session has expired or authentication is required for this action. Please sign in to your account."))),
|
|
27
|
+
react_1.default.createElement(dialog_1.DialogFooter, { className: "ecpauth:p-6 ecpauth:pt-0 ecpauth:flex ecpauth:flex-row ecpauth:justify-center ecpauth:gap-3" },
|
|
19
28
|
react_1.default.createElement(button_1.Button, { type: "button", variant: "outline", onClick: () => {
|
|
20
29
|
onOpenChange(false);
|
|
21
30
|
(0, utils_1.unstuckPointerEvents)();
|
|
22
|
-
} }, "Close")
|
|
31
|
+
}, className: "ecpauth:flex-1 ecpauth:h-11 ecpauth:rounded-xl ecpauth:font-semibold ecpauth:border-gray-200 ecpauth:dark:border-gray-800 ecpauth:hover:bg-gray-50 ecpauth:dark:hover:bg-white/5 ecpauth:transition-all" }, "Close"),
|
|
32
|
+
react_1.default.createElement(button_1.Button, { type: "button", onClick: () => {
|
|
33
|
+
window.location.href = loginUrl;
|
|
34
|
+
}, className: "ecpauth:flex-1 ecpauth:h-11 ecpauth:rounded-xl ecpauth:font-bold ecpauth:text-white! ecpauth:bg-blue-600! ecpauth:hover:bg-blue-700! ecpauth:shadow-lg ecpauth:shadow-blue-600/20 ecpauth:transition-all ecpauth:active:scale-[0.98]" }, "Login Now"))));
|
|
23
35
|
}
|
|
@@ -94,9 +94,9 @@ function ResetPassword({ className, onChangePassword, logo, ...props }) {
|
|
|
94
94
|
? "Enter your new password below."
|
|
95
95
|
: "Provide your email to receive a reset link.")),
|
|
96
96
|
state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
|
|
97
|
-
react_1.default.createElement(message_1.Message, { message: state?.message,
|
|
98
|
-
react_1.default.createElement(message_1.Message, { message: state?.message
|
|
99
|
-
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:px-12" },
|
|
97
|
+
react_1.default.createElement(message_1.Message, { message: state?.message, variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
|
|
98
|
+
react_1.default.createElement(message_1.Message, { message: state?.message }))) : null),
|
|
99
|
+
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:lg:px-12" },
|
|
100
100
|
!token ? (react_1.default.createElement("form", { onSubmit: handleSubmit, className: "ecpauth:space-y-6" },
|
|
101
101
|
react_1.default.createElement("div", { className: "ecpauth:space-y-2" },
|
|
102
102
|
react_1.default.createElement(label_1.Label, { htmlFor: "email", className: "ecpauth:text-sm ecpauth:font-medium ecpauth:text-gray-700 ecpauth:dark:text-gray-300" }, "Email Address"),
|
|
@@ -106,9 +106,9 @@ function Signup({ className, onSubmit, groupId, metadata, acceptUsername = true,
|
|
|
106
106
|
react_1.default.createElement(card_1.CardTitle, { className: "ecpauth:text-2xl ecpauth:font-black ecpauth:tracking-tight ecpauth:text-gray-900 ecpauth:dark:text-white" }, "Create Account"),
|
|
107
107
|
react_1.default.createElement(card_1.CardDescription, { className: "ecpauth:text-sm ecpauth:text-gray-500 ecpauth:dark:text-gray-400" }, "Provide your details to sign up for your account.")),
|
|
108
108
|
state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
|
|
109
|
-
react_1.default.createElement(message_1.Message, { message: state?.message,
|
|
110
|
-
react_1.default.createElement(message_1.Message, { message: state?.message
|
|
111
|
-
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:px-12" },
|
|
109
|
+
react_1.default.createElement(message_1.Message, { message: state?.message, variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
|
|
110
|
+
react_1.default.createElement(message_1.Message, { message: state?.message }))) : null),
|
|
111
|
+
react_1.default.createElement(card_1.CardContent, { className: "ecpauth:space-y-6 ecpauth:p-8 ecpauth:lg:px-12" },
|
|
112
112
|
react_1.default.createElement("form", { onSubmit: handleSubmit, className: "ecpauth:space-y-6" },
|
|
113
113
|
react_1.default.createElement("div", { className: "ecpauth:grid ecpauth:grid-cols-1 ecpauth:md:grid-cols-2 ecpauth:gap-4" },
|
|
114
114
|
react_1.default.createElement("div", { className: "ecpauth:space-y-2" },
|
|
@@ -75,7 +75,7 @@ function Toggle2FA({ onSubmit }) {
|
|
|
75
75
|
react_1.default.createElement(shield_1.ShieldIcon, { size: 18, className: "ecpauth:text-blue-600 ecpauth:dark:text-blue-400" }),
|
|
76
76
|
"Two-Factor Authentication"),
|
|
77
77
|
react_1.default.createElement("p", { className: "ecpauth:text-sm ecpauth:text-gray-500 ecpauth:dark:text-gray-400" }, "Add an extra layer of security to your account by requiring a verification code.")),
|
|
78
|
-
state?.status === "success" ? (react_1.default.createElement(message_1.Message, { message: state?.message,
|
|
78
|
+
state?.status === "success" ? (react_1.default.createElement(message_1.Message, { message: state?.message, variant: "success" })) : state?.message ? (react_1.default.createElement(message_1.Message, { message: state?.message })) : null,
|
|
79
79
|
react_1.default.createElement("div", { className: "ecpauth:group ecpauth:relative ecpauth:p-4 ecpauth:rounded-xl ecpauth:border ecpauth:border-gray-200 ecpauth:dark:border-gray-800 ecpauth:bg-gray-50/50 ecpauth:dark:bg-white/5 ecpauth:transition-all ecpauth:hover:border-blue-200 ecpauth:dark:hover:border-blue-900/30" },
|
|
80
80
|
react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:items-start ecpauth:justify-between ecpauth:gap-4" },
|
|
81
81
|
react_1.default.createElement("div", { className: "ecpauth:space-y-1" },
|
|
@@ -20,7 +20,8 @@ function ToggleAccountStatus({ user, open, onOpenChange, onSuccess, onSubmit, })
|
|
|
20
20
|
//@ts-ignore
|
|
21
21
|
status: "",
|
|
22
22
|
});
|
|
23
|
-
async function handleSubmit() {
|
|
23
|
+
async function handleSubmit(e) {
|
|
24
|
+
e.preventDefault();
|
|
24
25
|
if (!user) {
|
|
25
26
|
return {
|
|
26
27
|
message: "Please provide a user to toggle account status.",
|
|
@@ -34,7 +35,7 @@ function ToggleAccountStatus({ user, open, onOpenChange, onSuccess, onSubmit, })
|
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
setIsPending(true);
|
|
37
|
-
const result = await onSubmit(user.
|
|
38
|
+
const result = await onSubmit(user.subId);
|
|
38
39
|
setIsPending(false);
|
|
39
40
|
if (result.status !== "failure") {
|
|
40
41
|
onSuccess?.();
|
|
@@ -64,8 +65,8 @@ function ToggleAccountStatus({ user, open, onOpenChange, onSuccess, onSubmit, })
|
|
|
64
65
|
" ",
|
|
65
66
|
user?.lastName)))),
|
|
66
67
|
react_1.default.createElement("div", { className: "ecpauth:px-8 ecpauth:pb-6" }, state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
|
|
67
|
-
react_1.default.createElement(message_1.Message, { message: state?.message,
|
|
68
|
-
react_1.default.createElement(message_1.Message, { message: state?.message
|
|
68
|
+
react_1.default.createElement(message_1.Message, { message: state?.message, variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
|
|
69
|
+
react_1.default.createElement(message_1.Message, { message: state?.message }))) : (react_1.default.createElement("div", { className: "ecpauth:p-4 ecpauth:rounded-xl ecpauth:bg-gray-50 ecpauth:dark:bg-white/5 ecpauth:border ecpauth:border-gray-100 ecpauth:dark:border-white/10" },
|
|
69
70
|
react_1.default.createElement("p", { className: "ecpauth:text-sm ecpauth:leading-relaxed ecpauth:text-gray-600 ecpauth:dark:text-gray-300 ecpauth:text-center" },
|
|
70
71
|
"Are you sure you want to",
|
|
71
72
|
" ",
|
|
@@ -49,8 +49,7 @@ function AuthProvider({ children, config }) {
|
|
|
49
49
|
const [user, setUser] = (0, react_1.useState)(null);
|
|
50
50
|
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
51
51
|
const [error, setError] = (0, react_1.useState)(null);
|
|
52
|
-
const [
|
|
53
|
-
const [transition, startTransition] = (0, react_1.useTransition)();
|
|
52
|
+
const [_, startTransition] = (0, react_1.useTransition)();
|
|
54
53
|
const withFullObject = (0, utils_1.shouldPassFullUserObject)();
|
|
55
54
|
const computedRouteContext = (0, utils_1.buildRouteContext)(config);
|
|
56
55
|
const { loginUrl, resetPasswordUrl, dashboardUrl, returnPathRaw, isExcluded, } = computedRouteContext;
|
|
@@ -69,14 +68,6 @@ function AuthProvider({ children, config }) {
|
|
|
69
68
|
if (!token)
|
|
70
69
|
return;
|
|
71
70
|
if (!navigator.onLine) {
|
|
72
|
-
try {
|
|
73
|
-
const payload = (0, utils_1.parseJwt)(token);
|
|
74
|
-
setUser(payload?.user);
|
|
75
|
-
setIsAuthenticated(true);
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
console.warn("[ecp-auth] Invalid token format:", e);
|
|
79
|
-
}
|
|
80
71
|
console.warn("[ecp-auth] Offline — skipping fetchCurrentUser()");
|
|
81
72
|
return;
|
|
82
73
|
}
|
|
@@ -84,10 +75,8 @@ function AuthProvider({ children, config }) {
|
|
|
84
75
|
try {
|
|
85
76
|
const res = await (0, api_1.apiFactory)("/me", { method: "GET" });
|
|
86
77
|
setUser(res.user);
|
|
87
|
-
setIsAuthenticated(true);
|
|
88
78
|
}
|
|
89
79
|
catch (err) {
|
|
90
|
-
console.warn("[ecp-auth] Failed to fetch user:", err);
|
|
91
80
|
await logout("server_unavailable");
|
|
92
81
|
}
|
|
93
82
|
finally {
|
|
@@ -97,7 +86,7 @@ function AuthProvider({ children, config }) {
|
|
|
97
86
|
(0, react_1.useEffect)(() => {
|
|
98
87
|
fetchCurrentUser();
|
|
99
88
|
}, []);
|
|
100
|
-
|
|
89
|
+
const login = (0, react_1.useCallback)(async (credentials) => {
|
|
101
90
|
setError(null);
|
|
102
91
|
setLoading(true);
|
|
103
92
|
try {
|
|
@@ -109,7 +98,6 @@ function AuthProvider({ children, config }) {
|
|
|
109
98
|
});
|
|
110
99
|
const { authToken, user, with2fa } = res;
|
|
111
100
|
if (authToken && !with2fa) {
|
|
112
|
-
setIsAuthenticated(true);
|
|
113
101
|
await redirectAfterLogin(authToken, res.tempRefreshToken);
|
|
114
102
|
return null;
|
|
115
103
|
}
|
|
@@ -126,8 +114,8 @@ function AuthProvider({ children, config }) {
|
|
|
126
114
|
finally {
|
|
127
115
|
setLoading(false);
|
|
128
116
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
117
|
+
}, []);
|
|
118
|
+
const sendPasswordResetRequest = (0, react_1.useCallback)(async (email) => {
|
|
131
119
|
try {
|
|
132
120
|
const res = await (0, api_1.apiFactory)("/reset-password", {
|
|
133
121
|
body: { email, passwordResetLink: resetPasswordUrl },
|
|
@@ -140,8 +128,8 @@ function AuthProvider({ children, config }) {
|
|
|
140
128
|
}
|
|
141
129
|
return { message: err.message, status: "failure" };
|
|
142
130
|
}
|
|
143
|
-
}
|
|
144
|
-
|
|
131
|
+
}, []);
|
|
132
|
+
const logout = (0, react_1.useCallback)(async (reason = "", params) => {
|
|
145
133
|
let logoutSucceeded = false;
|
|
146
134
|
try {
|
|
147
135
|
await (0, api_1.apiFactory)("/logout");
|
|
@@ -151,7 +139,6 @@ function AuthProvider({ children, config }) {
|
|
|
151
139
|
if ([401, 403].includes(err.status)) {
|
|
152
140
|
logoutSucceeded = true;
|
|
153
141
|
}
|
|
154
|
-
console.error("Logout failed:", err);
|
|
155
142
|
}
|
|
156
143
|
const forceLogout = ["user_logout", "server_unavailable"].includes(reason);
|
|
157
144
|
if (logoutSucceeded || forceLogout) {
|
|
@@ -168,42 +155,56 @@ function AuthProvider({ children, config }) {
|
|
|
168
155
|
window.location.href = `${loginUrl}?${fullParams}`;
|
|
169
156
|
}
|
|
170
157
|
}
|
|
171
|
-
}
|
|
158
|
+
}, [loginUrl, returnPathRaw, config]);
|
|
172
159
|
(0, use_token_refresher_1.useTokenRefresher)({
|
|
173
160
|
config,
|
|
174
161
|
refreshTokenRequest: async () => {
|
|
175
|
-
|
|
162
|
+
return await (0, api_1.apiFactory)("/refresh", {
|
|
176
163
|
body: {
|
|
177
164
|
withFullObject,
|
|
178
165
|
},
|
|
179
166
|
});
|
|
180
|
-
return res;
|
|
181
167
|
},
|
|
182
168
|
onTokenRefreshed: (authToken, tempRefreshToken) => {
|
|
183
169
|
localStorage.setItem(constants_1.AUTH_TOKEN_KEY, authToken);
|
|
184
170
|
config?.cookieOverride?.(tempRefreshToken);
|
|
185
171
|
},
|
|
186
|
-
revalidateUserWhenOnline: fetchCurrentUser,
|
|
172
|
+
// revalidateUserWhenOnline: fetchCurrentUser,
|
|
187
173
|
onRefreshFailed: async () => await logout("session_expired"),
|
|
188
174
|
});
|
|
175
|
+
const userLogout = (0, react_1.useCallback)((params) => logout("user_logout", params), [logout]);
|
|
176
|
+
const revalidate = (0, react_1.useCallback)(() => startTransition(fetchCurrentUser), [fetchCurrentUser]);
|
|
177
|
+
const contextValue = (0, react_1.useMemo)(() => {
|
|
178
|
+
return {
|
|
179
|
+
user,
|
|
180
|
+
isLoading: loading,
|
|
181
|
+
isAuthenticated: !!user,
|
|
182
|
+
error,
|
|
183
|
+
computedRouteContext,
|
|
184
|
+
login,
|
|
185
|
+
sendPasswordResetRequest,
|
|
186
|
+
logout: userLogout,
|
|
187
|
+
hasPermission: (permission) => (0, utils_1.hasPermission)(user, permission),
|
|
188
|
+
revalidate,
|
|
189
|
+
getToken: () => (0, utils_1.getClientToken)(),
|
|
190
|
+
};
|
|
191
|
+
}, [
|
|
192
|
+
user,
|
|
193
|
+
loading,
|
|
194
|
+
error,
|
|
195
|
+
computedRouteContext,
|
|
196
|
+
login,
|
|
197
|
+
sendPasswordResetRequest,
|
|
198
|
+
fetchCurrentUser,
|
|
199
|
+
userLogout,
|
|
200
|
+
revalidate,
|
|
201
|
+
]);
|
|
189
202
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
190
203
|
react_1.default.createElement(optional_otp_wrapper_1.OptionalOTPWrapper, { user: twoFAData, onVerified: redirectAfterLogin, onCanceled: () => {
|
|
191
204
|
setTwoFAData(null);
|
|
192
205
|
} }),
|
|
193
206
|
!disableLoading && loading && react_1.default.createElement(loader_1.Loader, null),
|
|
194
|
-
react_1.default.createElement(AuthContext.Provider, { value:
|
|
195
|
-
user,
|
|
196
|
-
isLoading: loading,
|
|
197
|
-
isAuthenticated,
|
|
198
|
-
error,
|
|
199
|
-
computedRouteContext,
|
|
200
|
-
login,
|
|
201
|
-
sendPasswordResetRequest,
|
|
202
|
-
logout: (params) => logout("user_logout", params),
|
|
203
|
-
hasPermission: (permission) => (0, utils_1.hasPermission)(user, permission),
|
|
204
|
-
revalidate: () => startTransition(fetchCurrentUser),
|
|
205
|
-
getToken: () => (0, utils_1.getClientToken)(),
|
|
206
|
-
} }, children)));
|
|
207
|
+
react_1.default.createElement(AuthContext.Provider, { value: contextValue }, children)));
|
|
207
208
|
}
|
|
208
209
|
function useAuth() {
|
|
209
210
|
const ctx = (0, react_1.useContext)(AuthContext);
|
package/dist/lib/api-server.js
CHANGED
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare
|
|
3
|
-
meta: {
|
|
4
|
-
sessionId: string;
|
|
5
|
-
exp: number;
|
|
6
|
-
iat: number;
|
|
7
|
-
};
|
|
8
|
-
}) | null>;
|
|
1
|
+
import { ServerSession } from "../types";
|
|
2
|
+
export declare const getServerSession: () => Promise<ServerSession | null>;
|
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.getServerSession =
|
|
4
|
+
exports.getServerSession = void 0;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const api_1 = require("../lib/api");
|
|
5
7
|
const utils_1 = require("../lib/utils");
|
|
6
8
|
const server_token_1 = require("./server-token");
|
|
7
|
-
async function
|
|
9
|
+
exports.getServerSession = (0, react_1.cache)(async function () {
|
|
8
10
|
try {
|
|
9
11
|
const token = await (0, server_token_1.getServerToken)();
|
|
10
12
|
if (!token)
|
|
11
13
|
return null;
|
|
12
14
|
const session = (0, utils_1.parseJwt)(token);
|
|
13
|
-
|
|
14
|
-
const now = Date.now();
|
|
15
|
-
if (now > expiresAt) {
|
|
15
|
+
if (!session)
|
|
16
16
|
return null;
|
|
17
|
-
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
if (now > session.exp * 1000 - 1000)
|
|
19
|
+
return null; // 1s buffer
|
|
20
|
+
const res = await (0, api_1.apiFactory)("/me-server", {
|
|
21
|
+
method: "GET",
|
|
22
|
+
cache: "no-store",
|
|
23
|
+
});
|
|
18
24
|
return {
|
|
19
|
-
...
|
|
25
|
+
...res.user,
|
|
20
26
|
meta: {
|
|
21
27
|
sessionId: session.sessionId,
|
|
22
28
|
exp: session.exp,
|
|
23
29
|
iat: session.iat,
|
|
24
30
|
},
|
|
25
31
|
};
|
|
26
|
-
// const res = await apiFactory("/me-server", {
|
|
27
|
-
// method: "GET",
|
|
28
|
-
// cache: "no-store",
|
|
29
|
-
// });
|
|
30
|
-
// return res.user;
|
|
31
32
|
}
|
|
32
|
-
catch (
|
|
33
|
-
console.
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error("[getServerSession] Failed to fetch user:", err);
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
36
|
-
}
|
|
37
|
+
});
|
package/dist/styles.css
CHANGED
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
--ecpauth-color-black: #000;
|
|
59
59
|
--ecpauth-color-white: #fff;
|
|
60
60
|
--ecpauth-spacing: 0.25rem;
|
|
61
|
-
--ecpauth-container-sm: 24rem;
|
|
62
61
|
--ecpauth-container-md: 28rem;
|
|
63
62
|
--ecpauth-container-lg: 32rem;
|
|
64
63
|
--ecpauth-container-xl: 36rem;
|
|
@@ -313,9 +312,6 @@
|
|
|
313
312
|
.ecpauth\:my-1 {
|
|
314
313
|
margin-block: calc(var(--ecpauth-spacing) * 1);
|
|
315
314
|
}
|
|
316
|
-
.ecpauth\:my-2 {
|
|
317
|
-
margin-block: calc(var(--ecpauth-spacing) * 2);
|
|
318
|
-
}
|
|
319
315
|
.ecpauth\:-mt-2 {
|
|
320
316
|
margin-top: calc(var(--ecpauth-spacing) * -2);
|
|
321
317
|
}
|
|
@@ -328,9 +324,6 @@
|
|
|
328
324
|
.ecpauth\:mt-3 {
|
|
329
325
|
margin-top: calc(var(--ecpauth-spacing) * 3);
|
|
330
326
|
}
|
|
331
|
-
.ecpauth\:mt-4 {
|
|
332
|
-
margin-top: calc(var(--ecpauth-spacing) * 4);
|
|
333
|
-
}
|
|
334
327
|
.ecpauth\:mt-10 {
|
|
335
328
|
margin-top: calc(var(--ecpauth-spacing) * 10);
|
|
336
329
|
}
|
|
@@ -404,9 +397,6 @@
|
|
|
404
397
|
.ecpauth\:h-24 {
|
|
405
398
|
height: calc(var(--ecpauth-spacing) * 24);
|
|
406
399
|
}
|
|
407
|
-
.ecpauth\:h-40 {
|
|
408
|
-
height: calc(var(--ecpauth-spacing) * 40);
|
|
409
|
-
}
|
|
410
400
|
.ecpauth\:h-\[1\.15rem\] {
|
|
411
401
|
height: 1.15rem;
|
|
412
402
|
}
|
|
@@ -701,9 +691,6 @@
|
|
|
701
691
|
.ecpauth\:bg-amber-50 {
|
|
702
692
|
background-color: var(--ecpauth-color-amber-50);
|
|
703
693
|
}
|
|
704
|
-
.ecpauth\:bg-amber-600 {
|
|
705
|
-
background-color: var(--ecpauth-color-amber-600);
|
|
706
|
-
}
|
|
707
694
|
.ecpauth\:bg-amber-600\! {
|
|
708
695
|
background-color: var(--ecpauth-color-amber-600) !important;
|
|
709
696
|
}
|
|
@@ -722,9 +709,6 @@
|
|
|
722
709
|
.ecpauth\:bg-blue-100 {
|
|
723
710
|
background-color: var(--ecpauth-color-blue-100);
|
|
724
711
|
}
|
|
725
|
-
.ecpauth\:bg-blue-600 {
|
|
726
|
-
background-color: var(--ecpauth-color-blue-600);
|
|
727
|
-
}
|
|
728
712
|
.ecpauth\:bg-blue-600\! {
|
|
729
713
|
background-color: var(--ecpauth-color-blue-600) !important;
|
|
730
714
|
}
|
|
@@ -837,9 +821,6 @@
|
|
|
837
821
|
.ecpauth\:px-8 {
|
|
838
822
|
padding-inline: calc(var(--ecpauth-spacing) * 8);
|
|
839
823
|
}
|
|
840
|
-
.ecpauth\:px-12 {
|
|
841
|
-
padding-inline: calc(var(--ecpauth-spacing) * 12);
|
|
842
|
-
}
|
|
843
824
|
.ecpauth\:py-0\.5 {
|
|
844
825
|
padding-block: calc(var(--ecpauth-spacing) * 0.5);
|
|
845
826
|
}
|
|
@@ -990,9 +971,6 @@
|
|
|
990
971
|
.ecpauth\:text-gray-900 {
|
|
991
972
|
color: var(--ecpauth-color-gray-900);
|
|
992
973
|
}
|
|
993
|
-
.ecpauth\:text-green-500 {
|
|
994
|
-
color: var(--ecpauth-color-green-500);
|
|
995
|
-
}
|
|
996
974
|
.ecpauth\:text-green-700 {
|
|
997
975
|
color: var(--ecpauth-color-green-700);
|
|
998
976
|
}
|
|
@@ -1095,12 +1073,6 @@
|
|
|
1095
1073
|
--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--ecpauth-color-amber-600) 20%, transparent) var(--tw-shadow-alpha), transparent);
|
|
1096
1074
|
}
|
|
1097
1075
|
}
|
|
1098
|
-
.ecpauth\:shadow-blue-500\/20 {
|
|
1099
|
-
--tw-shadow-color: var(--ecpauth-color-blue-500);
|
|
1100
|
-
@supports (color: color-mix(in lab, red, red)) {
|
|
1101
|
-
--tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--ecpauth-color-blue-500) 20%, transparent) var(--tw-shadow-alpha), transparent);
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
1076
|
.ecpauth\:shadow-blue-600\/20 {
|
|
1105
1077
|
--tw-shadow-color: var(--ecpauth-color-blue-600);
|
|
1106
1078
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1258,13 +1230,6 @@
|
|
|
1258
1230
|
}
|
|
1259
1231
|
}
|
|
1260
1232
|
}
|
|
1261
|
-
.ecpauth\:hover\:bg-amber-700 {
|
|
1262
|
-
&:hover {
|
|
1263
|
-
@media (hover: hover) {
|
|
1264
|
-
background-color: var(--ecpauth-color-amber-700);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
1233
|
.ecpauth\:hover\:bg-amber-700\! {
|
|
1269
1234
|
&:hover {
|
|
1270
1235
|
@media (hover: hover) {
|
|
@@ -1272,13 +1237,6 @@
|
|
|
1272
1237
|
}
|
|
1273
1238
|
}
|
|
1274
1239
|
}
|
|
1275
|
-
.ecpauth\:hover\:bg-blue-700 {
|
|
1276
|
-
&:hover {
|
|
1277
|
-
@media (hover: hover) {
|
|
1278
|
-
background-color: var(--ecpauth-color-blue-700);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
1240
|
.ecpauth\:hover\:bg-blue-700\! {
|
|
1283
1241
|
&:hover {
|
|
1284
1242
|
@media (hover: hover) {
|
|
@@ -1670,6 +1628,11 @@
|
|
|
1670
1628
|
line-height: var(--tw-leading, var(--ecpauth-text-sm--line-height));
|
|
1671
1629
|
}
|
|
1672
1630
|
}
|
|
1631
|
+
.ecpauth\:lg\:px-12 {
|
|
1632
|
+
@media (width >= 64rem) {
|
|
1633
|
+
padding-inline: calc(var(--ecpauth-spacing) * 12);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1673
1636
|
.ecpauth\:lg\:shadow-xl {
|
|
1674
1637
|
@media (width >= 64rem) {
|
|
1675
1638
|
--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
@@ -1901,11 +1864,6 @@
|
|
|
1901
1864
|
color: var(--ecpauth-color-blue-400);
|
|
1902
1865
|
}
|
|
1903
1866
|
}
|
|
1904
|
-
.ecpauth\:dark\:text-gray-50 {
|
|
1905
|
-
&:is(.dark *) {
|
|
1906
|
-
color: var(--ecpauth-color-gray-50);
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
1867
|
.ecpauth\:dark\:text-gray-200 {
|
|
1910
1868
|
&:is(.dark *) {
|
|
1911
1869
|
color: var(--ecpauth-color-gray-200);
|
package/dist/types.d.ts
CHANGED
|
@@ -225,6 +225,13 @@ export type UseTokenRefresherOptions = {
|
|
|
225
225
|
revalidateUserWhenOnline?: () => void;
|
|
226
226
|
config?: AuthConfig;
|
|
227
227
|
};
|
|
228
|
+
export type ServerSession = User & {
|
|
229
|
+
meta: {
|
|
230
|
+
sessionId: string;
|
|
231
|
+
iat: number;
|
|
232
|
+
exp: number;
|
|
233
|
+
};
|
|
234
|
+
};
|
|
228
235
|
export type QueryOpts = {
|
|
229
236
|
groupIds?: (string | number | null)[];
|
|
230
237
|
};
|
package/package.json
CHANGED
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@explita/cloud-auth-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"author": "Explita",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"description": "A simple authentication library for React",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"types": "./dist/types.d.ts",
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"@
|
|
39
|
-
"@types/
|
|
40
|
-
"@types/react
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"@radix-ui/react-
|
|
55
|
-
"@radix-ui/react-
|
|
56
|
-
"@radix-ui/react-
|
|
57
|
-
"react": "^
|
|
58
|
-
"react
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@explita/cloud-auth-client",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"author": "Explita",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "A simple authentication library for React",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/types.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./ui": {
|
|
15
|
+
"default": "./dist/ui/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./server": {
|
|
18
|
+
"default": "./dist/server/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./styles.css": "./dist/styles.css"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"clean": "rimraf dist",
|
|
24
|
+
"build": "npm run clean && tsc",
|
|
25
|
+
"postbuild": "node src/misc/post-build.js",
|
|
26
|
+
"prepublishOnly": "npm run build",
|
|
27
|
+
"styles": "npx @tailwindcss/cli -i ./src/dev-styles.css -o ./src/styles.css --watch"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"auth",
|
|
31
|
+
"authentication",
|
|
32
|
+
"react",
|
|
33
|
+
"session",
|
|
34
|
+
"token",
|
|
35
|
+
"otp"
|
|
36
|
+
],
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@tailwindcss/cli": "^4.1.12",
|
|
39
|
+
"@types/node": "^24.3.0",
|
|
40
|
+
"@types/react": "^19.1.10",
|
|
41
|
+
"@types/react-dom": "^19.1.7",
|
|
42
|
+
"fs-extra": "^11.3.1",
|
|
43
|
+
"rimraf": "^6.0.1",
|
|
44
|
+
"tailwindcss": "^4.1.12",
|
|
45
|
+
"typescript": "^5.9.2"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"class-variance-authority": "^0.7.1"
|
|
49
|
+
},
|
|
50
|
+
"optionalDependencies": {
|
|
51
|
+
"@explita/cloud-otp-client": "^0.1.1"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@radix-ui/react-dialog": "^1",
|
|
55
|
+
"@radix-ui/react-dropdown-menu": "^2",
|
|
56
|
+
"@radix-ui/react-slot": "^1",
|
|
57
|
+
"@radix-ui/react-switch": "^1",
|
|
58
|
+
"react": "^19",
|
|
59
|
+
"react-dom": "^19"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist",
|
|
63
|
+
"README.md",
|
|
64
|
+
"LICENSE"
|
|
65
|
+
]
|
|
66
|
+
}
|