@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.
@@ -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, className: "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", variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
70
- react_1.default.createElement(message_1.Message, { message: state?.message, className: "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" }))) : null,
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] ecpauth:text-red-500" })),
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] ecpauth:text-red-500" }),
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-500"
14
- : "ecpauth:text-red-500", className) }, message));
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
- return (react_1.default.createElement(react_1.default.Fragment, null,
14
- react_1.default.createElement(dialog_1.DialogHeader, null,
15
- react_1.default.createElement(dialog_1.DialogTitle, null, "Authentication Error")),
16
- react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:items-center ecpauth:justify-center ecpauth:h-40" },
17
- react_1.default.createElement(message_1.Message, { message: "User not found. Make sure you are logged in.", variant: "error" })),
18
- react_1.default.createElement("div", { className: "ecpauth:flex ecpauth:justify-end ecpauth:gap-2" },
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, className: "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", variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
98
- react_1.default.createElement(message_1.Message, { message: state?.message, className: "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" }))) : null),
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, className: "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", variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
110
- react_1.default.createElement(message_1.Message, { message: state?.message, className: "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" }))) : null),
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, className: "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", variant: "success" })) : state?.message ? (react_1.default.createElement(message_1.Message, { message: state?.message, className: "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" })) : null,
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.id);
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, className: "ecpauth:font-medium ecpauth:text-sm ecpauth:p-3 ecpauth:rounded-xl 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", variant: "success" }))) : state?.message ? (react_1.default.createElement("div", { className: "ecpauth:mb-6" },
68
- react_1.default.createElement(message_1.Message, { message: state?.message, className: "ecpauth:font-medium ecpauth:text-sm ecpauth:p-3 ecpauth:rounded-xl 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" }))) : (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" },
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 [isAuthenticated, setIsAuthenticated] = (0, react_1.useState)(false);
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
- async function login(credentials) {
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
- async function sendPasswordResetRequest(email) {
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
- async function logout(reason = "", params) {
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
- const res = await (0, api_1.apiFactory)("/refresh", {
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);
@@ -18,6 +18,7 @@ async function apiServer(apiPath, options) {
18
18
  headers: {
19
19
  "Content-Type": "application/json",
20
20
  Authorization: `Bearer ${token}`,
21
+ "x-server-to-server": "true",
21
22
  "x-api-key": apiKey,
22
23
  "x-api-version": version,
23
24
  "x-workspace-id": workspaceId,
@@ -1,8 +1,2 @@
1
- import { User } from "../types";
2
- export declare function getServerSession(): Promise<(User & {
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 = 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 getServerSession() {
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
- const expiresAt = session.exp * 1000;
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
- ...session.user,
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 (error) {
33
- console.log(error);
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.1.2",
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
- "exports": {
10
- ".": {
11
- "default": "./dist/index.js"
12
- },
13
- "./ui": {
14
- "default": "./dist/ui/index.js"
15
- },
16
- "./server": {
17
- "default": "./dist/server/index.js"
18
- },
19
- "./styles.css": "./dist/styles.css"
20
- },
21
- "scripts": {
22
- "clean": "rimraf dist",
23
- "build": "npm run clean && tsc",
24
- "postbuild": "node src/misc/post-build.js",
25
- "prepublishOnly": "npm run build",
26
- "styles": "npx @tailwindcss/cli -i ./src/dev-styles.css -o ./src/styles.css --watch"
27
- },
28
- "keywords": [
29
- "auth",
30
- "authentication",
31
- "react",
32
- "session",
33
- "token",
34
- "otp"
35
- ],
36
- "devDependencies": {
37
- "@tailwindcss/cli": "^4.1.12",
38
- "@types/node": "^24.3.0",
39
- "@types/react": "^19.1.10",
40
- "@types/react-dom": "^19.1.7",
41
- "fs-extra": "^11.3.1",
42
- "rimraf": "^6.0.1",
43
- "tailwindcss": "^4.1.12",
44
- "typescript": "^5.9.2"
45
- },
46
- "dependencies": {
47
- "class-variance-authority": "^0.7.1"
48
- },
49
- "optionalDependencies": {
50
- "@explita/cloud-otp-client": "^0.1.1"
51
- },
52
- "peerDependencies": {
53
- "@radix-ui/react-dialog": "^1",
54
- "@radix-ui/react-dropdown-menu": "^2",
55
- "@radix-ui/react-slot": "^1",
56
- "@radix-ui/react-switch": "^1",
57
- "react": "^19",
58
- "react-dom": "^19"
59
- },
60
- "files": [
61
- "dist",
62
- "README.md",
63
- "LICENSE"
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
+ }