@rebasepro/auth 0.0.1-canary.f81da60 → 0.1.2
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/api.d.ts +20 -2
- package/dist/components/RebaseLoginView.d.ts +22 -0
- package/dist/index.es.js +82 -37
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +81 -36
- package/dist/index.umd.js.map +1 -1
- package/dist/types.d.ts +8 -2
- package/package.json +4 -4
- package/src/api.ts +49 -9
- package/src/components/AdminViews.tsx +1 -3
- package/src/components/RebaseLoginView.tsx +48 -18
- package/src/hooks/useBackendUserManagement.ts +53 -8
- package/src/hooks/useRebaseAuthController.ts +11 -3
- package/src/types.ts +5 -2
package/dist/index.umd.js
CHANGED
|
@@ -71,11 +71,12 @@
|
|
|
71
71
|
});
|
|
72
72
|
return handleResponse(response);
|
|
73
73
|
}
|
|
74
|
-
async function googleLogin(
|
|
74
|
+
async function googleLogin(tokenOrPayload, tokenType = "idToken") {
|
|
75
|
+
const body = typeof tokenOrPayload === "string" ? { [tokenType]: tokenOrPayload } : tokenOrPayload;
|
|
75
76
|
const response = await fetchWithHandling(`${baseApiUrl}/api/auth/google`, {
|
|
76
77
|
method: "POST",
|
|
77
78
|
headers: { "Content-Type": "application/json" },
|
|
78
|
-
body: JSON.stringify(
|
|
79
|
+
body: JSON.stringify(body)
|
|
79
80
|
});
|
|
80
81
|
return handleResponse(response);
|
|
81
82
|
}
|
|
@@ -195,12 +196,23 @@
|
|
|
195
196
|
});
|
|
196
197
|
return handleResponse(response);
|
|
197
198
|
}
|
|
199
|
+
let authConfigInflight = null;
|
|
198
200
|
async function fetchAuthConfig() {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
if (authConfigInflight) {
|
|
202
|
+
return authConfigInflight;
|
|
203
|
+
}
|
|
204
|
+
authConfigInflight = (async () => {
|
|
205
|
+
const response = await fetchWithHandling(`${baseApiUrl}/api/auth/config`, {
|
|
206
|
+
method: "GET",
|
|
207
|
+
headers: { "Content-Type": "application/json" }
|
|
208
|
+
});
|
|
209
|
+
return handleResponse(response);
|
|
210
|
+
})();
|
|
211
|
+
try {
|
|
212
|
+
return await authConfigInflight;
|
|
213
|
+
} finally {
|
|
214
|
+
authConfigInflight = null;
|
|
215
|
+
}
|
|
204
216
|
}
|
|
205
217
|
const STORAGE_KEY = "rebase_auth";
|
|
206
218
|
const TOKEN_REFRESH_BUFFER_MS = 2 * 60 * 1e3;
|
|
@@ -411,6 +423,7 @@
|
|
|
411
423
|
}
|
|
412
424
|
}, [client, getAuthToken, refreshAccessToken$1, clearSessionAndSignOut]);
|
|
413
425
|
const handleAuthSuccess = react.useCallback(async (userInfo, tokens) => {
|
|
426
|
+
console.log("[Auth] handleAuthSuccess called, user:", userInfo.email, "uid:", userInfo.uid);
|
|
414
427
|
tokensRef.current = tokens;
|
|
415
428
|
let convertedUser = convertToUser(userInfo);
|
|
416
429
|
if (defineRolesFor) {
|
|
@@ -423,11 +436,13 @@
|
|
|
423
436
|
}
|
|
424
437
|
}
|
|
425
438
|
saveAuthToStorage(tokens, userInfo);
|
|
439
|
+
console.log("[Auth] Calling setUser, roles:", convertedUser.roles);
|
|
426
440
|
setUser(convertedUser);
|
|
427
441
|
setAuthError(null);
|
|
428
442
|
setAuthProviderError(null);
|
|
429
443
|
setLoginSkipped(false);
|
|
430
444
|
scheduleTokenRefresh(tokens);
|
|
445
|
+
console.log("[Auth] handleAuthSuccess completed");
|
|
431
446
|
}, [scheduleTokenRefresh, defineRolesFor]);
|
|
432
447
|
const emailPasswordLogin = react.useCallback(async (email, password) => {
|
|
433
448
|
setAuthLoading(true);
|
|
@@ -455,11 +470,11 @@
|
|
|
455
470
|
setAuthLoading(false);
|
|
456
471
|
}
|
|
457
472
|
}, [handleAuthSuccess]);
|
|
458
|
-
const googleLogin$1 = react.useCallback(async (
|
|
473
|
+
const googleLogin$1 = react.useCallback(async (tokenOrPayload, tokenType) => {
|
|
459
474
|
setAuthLoading(true);
|
|
460
475
|
setAuthProviderError(null);
|
|
461
476
|
try {
|
|
462
|
-
const response = await googleLogin(
|
|
477
|
+
const response = typeof tokenOrPayload === "string" ? await googleLogin(tokenOrPayload, tokenType ?? "idToken") : await googleLogin(tokenOrPayload);
|
|
463
478
|
await handleAuthSuccess(response.user, response.tokens);
|
|
464
479
|
} catch (error) {
|
|
465
480
|
setAuthProviderError(error);
|
|
@@ -794,6 +809,8 @@
|
|
|
794
809
|
const [loading, setLoading] = react.useState(true);
|
|
795
810
|
const [usersError, setUsersError] = react.useState();
|
|
796
811
|
const [rolesError, setRolesError] = react.useState();
|
|
812
|
+
const lastLoadedUidRef = react.useRef(null);
|
|
813
|
+
const apiRequestRef = react.useRef(null);
|
|
797
814
|
const apiRequest = react.useCallback(async (endpoint, method = "GET", body, retryCount = 6, signal) => {
|
|
798
815
|
let lastError = null;
|
|
799
816
|
for (let attempt = 0; attempt < retryCount; attempt++) {
|
|
@@ -861,6 +878,7 @@
|
|
|
861
878
|
}
|
|
862
879
|
throw lastError;
|
|
863
880
|
}, [apiUrl, getAuthToken]);
|
|
881
|
+
apiRequestRef.current = apiRequest;
|
|
864
882
|
react.useCallback(async (signal) => {
|
|
865
883
|
try {
|
|
866
884
|
const data = await apiRequest("/roles", "GET", void 0, 6, signal);
|
|
@@ -889,23 +907,43 @@
|
|
|
889
907
|
setLoading(false);
|
|
890
908
|
return;
|
|
891
909
|
}
|
|
910
|
+
if (lastLoadedUidRef.current === currentUser.uid) {
|
|
911
|
+
setLoading(false);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
892
914
|
const abortController = new AbortController();
|
|
893
915
|
const load = async () => {
|
|
894
916
|
setLoading(true);
|
|
917
|
+
const request = apiRequestRef.current;
|
|
895
918
|
try {
|
|
896
|
-
const data = await
|
|
919
|
+
const data = await request("/roles", "GET", void 0, 6, abortController.signal);
|
|
897
920
|
setRoles(data.roles.map(convertRole));
|
|
898
921
|
setRolesError(void 0);
|
|
899
922
|
} catch (error) {
|
|
900
|
-
if (error instanceof Error && error.name
|
|
901
|
-
|
|
902
|
-
|
|
923
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
924
|
+
console.error("Failed to load roles:", error);
|
|
925
|
+
setRolesError(error instanceof Error ? error : new Error(String(error)));
|
|
926
|
+
const status = error.status;
|
|
927
|
+
if (status === 403 || status === 401) {
|
|
928
|
+
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
929
|
+
setLoading(false);
|
|
930
|
+
return;
|
|
903
931
|
}
|
|
904
932
|
}
|
|
905
933
|
if (!abortController.signal.aborted) {
|
|
906
|
-
|
|
934
|
+
try {
|
|
935
|
+
const data = await request("/users", "GET", void 0, 6, abortController.signal);
|
|
936
|
+
const allUsers = data.users.map((u) => convertUser(u));
|
|
937
|
+
setUsers(allUsers);
|
|
938
|
+
setUsersError(void 0);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
941
|
+
console.error("Failed to load users:", error);
|
|
942
|
+
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
943
|
+
}
|
|
907
944
|
}
|
|
908
945
|
if (!abortController.signal.aborted) {
|
|
946
|
+
lastLoadedUidRef.current = currentUser.uid;
|
|
909
947
|
setLoading(false);
|
|
910
948
|
}
|
|
911
949
|
};
|
|
@@ -913,7 +951,7 @@
|
|
|
913
951
|
return () => {
|
|
914
952
|
abortController.abort();
|
|
915
953
|
};
|
|
916
|
-
}, [currentUser
|
|
954
|
+
}, [currentUser?.uid]);
|
|
917
955
|
const searchUsers = react.useCallback(async (options) => {
|
|
918
956
|
const params = new URLSearchParams();
|
|
919
957
|
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
@@ -1192,17 +1230,22 @@
|
|
|
1192
1230
|
authController
|
|
1193
1231
|
}
|
|
1194
1232
|
),
|
|
1195
|
-
showRegistration && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1233
|
+
showRegistration && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "body2", color: "secondary", children: [
|
|
1234
|
+
"Don't have an account?",
|
|
1235
|
+
" ",
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1237
|
+
"button",
|
|
1238
|
+
{
|
|
1239
|
+
type: "button",
|
|
1240
|
+
className: ui.cls(
|
|
1241
|
+
"font-semibold hover:underline cursor-pointer",
|
|
1242
|
+
"text-primary-600 dark:text-primary-400"
|
|
1243
|
+
),
|
|
1244
|
+
onClick: () => switchMode("register"),
|
|
1245
|
+
children: "Create one"
|
|
1246
|
+
}
|
|
1247
|
+
)
|
|
1248
|
+
] }) })
|
|
1206
1249
|
] }),
|
|
1207
1250
|
mode === "login" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1208
1251
|
LoginForm,
|
|
@@ -1298,20 +1341,24 @@
|
|
|
1298
1341
|
googleClientId,
|
|
1299
1342
|
authController
|
|
1300
1343
|
}) {
|
|
1301
|
-
const
|
|
1344
|
+
const codeClientRef = react.useRef(null);
|
|
1302
1345
|
react.useEffect(() => {
|
|
1303
1346
|
const google = window.google;
|
|
1304
|
-
if (!google ||
|
|
1305
|
-
|
|
1347
|
+
if (!google || codeClientRef.current) return;
|
|
1348
|
+
codeClientRef.current = google.accounts.oauth2.initCodeClient({
|
|
1306
1349
|
client_id: googleClientId,
|
|
1307
1350
|
scope: "openid email profile",
|
|
1351
|
+
ux_mode: "popup",
|
|
1308
1352
|
callback: async (response) => {
|
|
1309
|
-
if (response.error || !response.
|
|
1353
|
+
if (response.error || !response.code) {
|
|
1310
1354
|
console.error("Google login error:", response.error);
|
|
1311
1355
|
return;
|
|
1312
1356
|
}
|
|
1313
1357
|
try {
|
|
1314
|
-
await authController.googleLogin(
|
|
1358
|
+
await authController.googleLogin({
|
|
1359
|
+
code: response.code,
|
|
1360
|
+
redirectUri: "postmessage"
|
|
1361
|
+
});
|
|
1315
1362
|
} catch (err) {
|
|
1316
1363
|
console.error("Google login error:", err);
|
|
1317
1364
|
}
|
|
@@ -1319,11 +1366,11 @@
|
|
|
1319
1366
|
});
|
|
1320
1367
|
}, [googleClientId, authController]);
|
|
1321
1368
|
const handleClick = () => {
|
|
1322
|
-
if (!
|
|
1369
|
+
if (!codeClientRef.current) {
|
|
1323
1370
|
console.error("Google Sign-In not loaded");
|
|
1324
1371
|
return;
|
|
1325
1372
|
}
|
|
1326
|
-
|
|
1373
|
+
codeClientRef.current.requestCode();
|
|
1327
1374
|
};
|
|
1328
1375
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1329
1376
|
LoginButton,
|
|
@@ -1602,14 +1649,12 @@
|
|
|
1602
1649
|
{
|
|
1603
1650
|
slug: "dev/users",
|
|
1604
1651
|
name: "CMS Users",
|
|
1605
|
-
group: "Admin",
|
|
1606
1652
|
icon: "face",
|
|
1607
1653
|
view: /* @__PURE__ */ jsxRuntime.jsx(UsersView, { userManagement, apiUrl, getAuthToken })
|
|
1608
1654
|
},
|
|
1609
1655
|
{
|
|
1610
1656
|
slug: "dev/roles",
|
|
1611
1657
|
name: "Roles",
|
|
1612
|
-
group: "Admin",
|
|
1613
1658
|
icon: "gpp_good",
|
|
1614
1659
|
view: /* @__PURE__ */ jsxRuntime.jsx(RolesView, { userManagement, collections })
|
|
1615
1660
|
}
|
|
@@ -1707,7 +1752,7 @@
|
|
|
1707
1752
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.CenteredView, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, {}) });
|
|
1708
1753
|
}
|
|
1709
1754
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "w-full flex flex-col py-4 gap-4", maxWidth: "6xl", children: [
|
|
1710
|
-
!hasAdmin &&
|
|
1755
|
+
!hasAdmin && loggedInUser && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-yellow-100 dark:bg-yellow-900 border border-yellow-400 dark:border-yellow-700 rounded p-4 flex items-center justify-between", children: [
|
|
1711
1756
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "label", className: "text-yellow-800 dark:text-yellow-200", children: "No admin users exist. You can make yourself an admin." }) }),
|
|
1712
1757
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1713
1758
|
ui.Button,
|