@explita/cloud-auth-client 0.1.3 → 0.2.1

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.
@@ -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,7 +90,7 @@ 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" },
@@ -96,7 +96,7 @@ function ResetPassword({ className, onChangePassword, logo, ...props }) {
96
96
  state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
97
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
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:px-12" },
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"),
@@ -108,7 +108,7 @@ function Signup({ className, onSubmit, groupId, metadata, acceptUsername = true,
108
108
  state?.status === "success" ? (react_1.default.createElement("div", { className: "ecpauth:mt-3" },
109
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
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:px-12" },
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" },
@@ -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,4 +1,4 @@
1
- import { AuthConfig, QueryOpts, User } from "../types";
1
+ import { AuthConfig, QueryOpts, TokenSession, User } from "../types";
2
2
  export declare function cn(...classes: (string | false | null | undefined)[]): string;
3
3
  export declare function unstuckPointerEvents(): void;
4
4
  export declare function buildRouteContext(config?: AuthConfig, currentPath?: string): {
@@ -13,7 +13,7 @@ export declare function buildRouteContext(config?: AuthConfig, currentPath?: str
13
13
  isExcluded: boolean;
14
14
  };
15
15
  export declare function getClientToken(): string;
16
- export declare function hasPermission(user: User | null, permission: string): boolean;
16
+ export declare function hasPermission(session: User | TokenSession | null, permission: string): boolean;
17
17
  export declare function parseMessage(message: string): string;
18
18
  export declare function parseGroupId(data?: QueryOpts["groupIds"]): string;
19
19
  export declare function parseJwt(token: string): any;
package/dist/lib/utils.js CHANGED
@@ -102,10 +102,10 @@ function getClientToken() {
102
102
  ? localStorage.getItem(constants_1.AUTH_TOKEN_KEY) || ""
103
103
  : "";
104
104
  }
105
- function hasPermission(user, permission) {
106
- if (!user)
105
+ function hasPermission(session, permission) {
106
+ if (!session)
107
107
  return false;
108
- return user.role.permissions?.includes(permission) || user.isSuperAdmin;
108
+ return session.role.permissions?.includes(permission) || session.isSuperAdmin;
109
109
  }
110
110
  function parseMessage(message) {
111
111
  return message == "fetch failed" || message == "Failed to fetch"
@@ -3,6 +3,7 @@ export * from "./reset-password";
3
3
  export * from "./user";
4
4
  export * from "./next-cookie-override";
5
5
  export * from "./server-session";
6
+ export * from "./token-session";
6
7
  export * from "./server-token";
7
8
  export * from "./role";
8
9
  export { hasPermission } from "../lib/utils";
@@ -20,6 +20,7 @@ __exportStar(require("./reset-password"), exports);
20
20
  __exportStar(require("./user"), exports);
21
21
  __exportStar(require("./next-cookie-override"), exports);
22
22
  __exportStar(require("./server-session"), exports);
23
+ __exportStar(require("./token-session"), exports);
23
24
  __exportStar(require("./server-token"), exports);
24
25
  __exportStar(require("./role"), exports);
25
26
  var utils_1 = require("../lib/utils");
@@ -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
+ });
@@ -0,0 +1,7 @@
1
+ import { TokenSession } from "../types";
2
+ /**
3
+ * Reads session from JWT in cookies.
4
+ * No network call. No server validation.
5
+ * Intended for middleware / edge usage.
6
+ */
7
+ export declare function getTokenSession<T extends Record<string, any>>(): Promise<TokenSession<T> | null>;
@@ -0,0 +1,36 @@
1
+ "use server";
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.getTokenSession = getTokenSession;
5
+ const utils_1 = require("../lib/utils");
6
+ const server_token_1 = require("./server-token");
7
+ /**
8
+ * Reads session from JWT in cookies.
9
+ * No network call. No server validation.
10
+ * Intended for middleware / edge usage.
11
+ */
12
+ async function getTokenSession() {
13
+ try {
14
+ const token = await (0, server_token_1.getServerToken)();
15
+ if (!token)
16
+ return null;
17
+ const session = (0, utils_1.parseJwt)(token);
18
+ if (!session)
19
+ return null;
20
+ const now = Date.now();
21
+ if (now > session.exp * 1000 - 5000)
22
+ return null; // 5s buffer
23
+ return {
24
+ ...session.user,
25
+ meta: {
26
+ sessionId: session.sessionId,
27
+ exp: session.exp,
28
+ iat: session.iat,
29
+ },
30
+ };
31
+ }
32
+ catch (err) {
33
+ console.error("[getTokenSession] Failed:", err);
34
+ return null;
35
+ }
36
+ }