@rebasepro/auth 0.2.4 → 0.2.5
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/hooks/useBackendUserManagement.d.ts +2 -6
- package/dist/index.es.js +6 -71
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +6 -71
- package/dist/index.umd.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +4 -4
- package/src/hooks/useBackendUserManagement.ts +8 -108
- package/src/hooks/useRebaseAuthController.ts +4 -4
- package/src/types.ts +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import type { User } from "@rebasepro/types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* UserManagement interface - compatible with @rebasepro/user_management
|
|
@@ -23,13 +23,9 @@ export interface UserManagement<USER extends User = User> {
|
|
|
23
23
|
}>;
|
|
24
24
|
deleteUser: (user: USER) => Promise<void>;
|
|
25
25
|
|
|
26
|
-
roles: Role[];
|
|
27
|
-
saveRole: (role: Role) => Promise<void>;
|
|
28
|
-
deleteRole: (role: Role) => Promise<void>;
|
|
29
|
-
|
|
30
26
|
isAdmin?: boolean;
|
|
31
27
|
allowDefaultRolesCreation?: boolean;
|
|
32
|
-
defineRolesFor: (user: User) => Promise<
|
|
28
|
+
defineRolesFor: (user: User) => Promise<string[] | undefined> | string[] | undefined;
|
|
33
29
|
getUser: (uid: string) => User | null;
|
|
34
30
|
|
|
35
31
|
/**
|
|
@@ -47,7 +43,6 @@ export interface UserManagement<USER extends User = User> {
|
|
|
47
43
|
}) => Promise<{ users: USER[]; total: number }>;
|
|
48
44
|
|
|
49
45
|
usersError?: Error;
|
|
50
|
-
rolesError?: Error;
|
|
51
46
|
bootstrapAdmin?: () => Promise<void>;
|
|
52
47
|
}
|
|
53
48
|
|
|
@@ -83,17 +78,9 @@ interface ApiUser {
|
|
|
83
78
|
updatedAt?: string;
|
|
84
79
|
}
|
|
85
80
|
|
|
86
|
-
interface ApiRole {
|
|
87
|
-
id: string;
|
|
88
|
-
name: string;
|
|
89
|
-
isAdmin?: boolean;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
81
|
/** Response shapes from the admin API */
|
|
93
|
-
interface ApiRolesResponse { roles: ApiRole[] }
|
|
94
82
|
interface ApiUsersResponse { users: ApiUser[]; total: number }
|
|
95
83
|
interface ApiUserResponse { user: ApiUser; invitationSent?: boolean; temporaryPassword?: string }
|
|
96
|
-
interface ApiRoleResponse { role: ApiRole }
|
|
97
84
|
|
|
98
85
|
/**
|
|
99
86
|
* Convert API user to Rebase User
|
|
@@ -112,17 +99,6 @@ function convertUser(apiUser: ApiUser): User {
|
|
|
112
99
|
} as User;
|
|
113
100
|
}
|
|
114
101
|
|
|
115
|
-
/**
|
|
116
|
-
* Convert API role to Rebase Role
|
|
117
|
-
*/
|
|
118
|
-
function convertRole(apiRole: ApiRole): Role {
|
|
119
|
-
return {
|
|
120
|
-
id: apiRole.id,
|
|
121
|
-
name: apiRole.name,
|
|
122
|
-
isAdmin: apiRole.isAdmin ?? false
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
102
|
/**
|
|
127
103
|
* Hook to manage users and roles via backend API
|
|
128
104
|
* Compatible with Rebase UserManagement interface
|
|
@@ -134,7 +110,6 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
134
110
|
// individual API lookups. We never load ALL users into memory.
|
|
135
111
|
const [userCache, setUserCache] = useState<Map<string, User>>(new Map());
|
|
136
112
|
const [hasAdminUsers, setHasAdminUsers] = useState(false);
|
|
137
|
-
const [roles, setRoles] = useState<Role[]>([]);
|
|
138
113
|
const userRoles = currentUser?.roles ?? [];
|
|
139
114
|
const isUserAdmin = userRoles.some(r => r === "admin" || r === "schema-admin");
|
|
140
115
|
|
|
@@ -144,7 +119,6 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
144
119
|
return true;
|
|
145
120
|
});
|
|
146
121
|
const [usersError, setUsersError] = useState<Error | undefined>();
|
|
147
|
-
const [rolesError, setRolesError] = useState<Error | undefined>();
|
|
148
122
|
|
|
149
123
|
// Tracks the UID for which roles+users were last successfully loaded.
|
|
150
124
|
// Prevents redundant refetches on React StrictMode double-mounts.
|
|
@@ -261,20 +235,7 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
261
235
|
// Keep the ref in sync after every render.
|
|
262
236
|
apiRequestRef.current = apiRequest;
|
|
263
237
|
|
|
264
|
-
|
|
265
|
-
* Load roles from API
|
|
266
|
-
*/
|
|
267
|
-
const loadRoles = useCallback(async (signal?: AbortSignal) => {
|
|
268
|
-
try {
|
|
269
|
-
const data = await apiRequest<ApiRolesResponse>("/roles", "GET", undefined, 6, signal);
|
|
270
|
-
setRoles(data.roles.map(convertRole));
|
|
271
|
-
setRolesError(undefined);
|
|
272
|
-
} catch (error: unknown) {
|
|
273
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
274
|
-
console.error("Failed to load roles:", error);
|
|
275
|
-
setRolesError(error instanceof Error ? error : new Error(String(error)));
|
|
276
|
-
}
|
|
277
|
-
}, [apiRequest]);
|
|
238
|
+
|
|
278
239
|
|
|
279
240
|
/**
|
|
280
241
|
* Lightweight admin-existence check: fetch a single admin user.
|
|
@@ -334,27 +295,6 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
334
295
|
setLoading(true);
|
|
335
296
|
const request = apiRequestRef.current!;
|
|
336
297
|
|
|
337
|
-
// Load roles first
|
|
338
|
-
try {
|
|
339
|
-
const data = await request<ApiRolesResponse>("/roles", "GET", undefined, 6, abortController.signal);
|
|
340
|
-
setRoles(data.roles.map(convertRole));
|
|
341
|
-
setRolesError(undefined);
|
|
342
|
-
} catch (error: unknown) {
|
|
343
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
344
|
-
console.error("Failed to load roles:", error);
|
|
345
|
-
setRolesError(error instanceof Error ? error : new Error(String(error)));
|
|
346
|
-
|
|
347
|
-
// If the error is a permission issue (e.g. 403), skip the
|
|
348
|
-
// admin check — it will fail with the same error and we'd
|
|
349
|
-
// show a duplicate snackbar / error message.
|
|
350
|
-
const status = (error as { status?: number }).status;
|
|
351
|
-
if (status === 403 || status === 401) {
|
|
352
|
-
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
353
|
-
setLoading(false);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
298
|
// Lightweight admin-existence check (NOT loading all users)
|
|
359
299
|
if (!abortController.signal.aborted) {
|
|
360
300
|
try {
|
|
@@ -488,40 +428,7 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
488
428
|
});
|
|
489
429
|
}, [apiRequest]);
|
|
490
430
|
|
|
491
|
-
/**
|
|
492
|
-
* Save role (create or update)
|
|
493
|
-
*/
|
|
494
|
-
const saveRole = useCallback(async (role: Role): Promise<void> => {
|
|
495
|
-
// Check if role exists
|
|
496
|
-
const existingRole = roles.find(r => r.id === role.id);
|
|
497
|
-
|
|
498
|
-
if (existingRole) {
|
|
499
|
-
// Update
|
|
500
|
-
const data = await apiRequest<ApiRoleResponse>(`/roles/${role.id}`, "PUT", {
|
|
501
|
-
name: role.name,
|
|
502
|
-
isAdmin: role.isAdmin
|
|
503
|
-
});
|
|
504
|
-
const updated = convertRole(data.role);
|
|
505
|
-
setRoles(prev => prev.map(r => r.id === updated.id ? updated : r));
|
|
506
|
-
} else {
|
|
507
|
-
// Create
|
|
508
|
-
const data = await apiRequest<ApiRoleResponse>("/roles", "POST", {
|
|
509
|
-
id: role.id,
|
|
510
|
-
name: role.name,
|
|
511
|
-
isAdmin: role.isAdmin ?? false
|
|
512
|
-
});
|
|
513
|
-
const created = convertRole(data.role);
|
|
514
|
-
setRoles(prev => [...prev, created]);
|
|
515
|
-
}
|
|
516
|
-
}, [apiRequest, roles]);
|
|
517
431
|
|
|
518
|
-
/**
|
|
519
|
-
* Delete role
|
|
520
|
-
*/
|
|
521
|
-
const deleteRole = useCallback(async (role: Role): Promise<void> => {
|
|
522
|
-
await apiRequest(`/roles/${role.id}`, "DELETE");
|
|
523
|
-
setRoles(prev => prev.filter(r => r.id !== role.id));
|
|
524
|
-
}, [apiRequest]);
|
|
525
432
|
|
|
526
433
|
/**
|
|
527
434
|
* Get user by uid
|
|
@@ -533,7 +440,7 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
533
440
|
/**
|
|
534
441
|
* Define roles for a given user (for authController)
|
|
535
442
|
*/
|
|
536
|
-
const defineRolesFor = useCallback(async (user: User): Promise<
|
|
443
|
+
const defineRolesFor = useCallback(async (user: User): Promise<string[] | undefined> => {
|
|
537
444
|
// Check cache first
|
|
538
445
|
let existingUser = userCache.get(user.uid)
|
|
539
446
|
?? Array.from(userCache.values()).find(u => u.email === user.email);
|
|
@@ -549,10 +456,10 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
549
456
|
}
|
|
550
457
|
}
|
|
551
458
|
|
|
552
|
-
// Return
|
|
459
|
+
// Return role IDs as simple strings
|
|
553
460
|
const userRoleIds = existingUser.roles ?? [];
|
|
554
|
-
return
|
|
555
|
-
}, [userCache,
|
|
461
|
+
return userRoleIds;
|
|
462
|
+
}, [userCache, apiRequest, mergeIntoCache]);
|
|
556
463
|
|
|
557
464
|
/**
|
|
558
465
|
* Check if current user is admin
|
|
@@ -566,10 +473,7 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
566
473
|
const bootstrapAdmin = useCallback(async (): Promise<void> => {
|
|
567
474
|
try {
|
|
568
475
|
await apiRequest("/bootstrap", "POST");
|
|
569
|
-
//
|
|
570
|
-
const data = await apiRequest<ApiRolesResponse>("/roles");
|
|
571
|
-
const loadedRoles = data.roles.map(convertRole);
|
|
572
|
-
setRoles(loadedRoles);
|
|
476
|
+
// Re-check admin existence after successful bootstrap
|
|
573
477
|
await checkAdminExists();
|
|
574
478
|
} catch (error) {
|
|
575
479
|
console.error("Failed to bootstrap admin:", error);
|
|
@@ -589,16 +493,12 @@ export function useBackendUserManagement(config: BackendUserManagementConfig): U
|
|
|
589
493
|
createUser,
|
|
590
494
|
resetPassword,
|
|
591
495
|
deleteUser,
|
|
592
|
-
roles,
|
|
593
|
-
saveRole,
|
|
594
|
-
deleteRole,
|
|
595
496
|
isAdmin,
|
|
596
497
|
allowDefaultRolesCreation: isAdmin,
|
|
597
498
|
defineRolesFor,
|
|
598
499
|
getUser,
|
|
599
500
|
searchUsers,
|
|
600
501
|
usersError,
|
|
601
|
-
rolesError,
|
|
602
502
|
bootstrapAdmin
|
|
603
503
|
};
|
|
604
504
|
}
|
|
@@ -313,7 +313,7 @@ export function useRebaseAuthController(
|
|
|
313
313
|
if (defineRolesFor) {
|
|
314
314
|
const customRoles = await defineRolesFor(convertedUser);
|
|
315
315
|
if (customRoles) {
|
|
316
|
-
convertedUser = { ...convertedUser, roles: customRoles
|
|
316
|
+
convertedUser = { ...convertedUser, roles: customRoles };
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
|
|
@@ -479,7 +479,7 @@ export function useRebaseAuthController(
|
|
|
479
479
|
const customRoles = await defineRolesFor(convertedUser);
|
|
480
480
|
if (customRoles) {
|
|
481
481
|
convertedUser = { ...convertedUser,
|
|
482
|
-
roles: customRoles
|
|
482
|
+
roles: customRoles };
|
|
483
483
|
}
|
|
484
484
|
}
|
|
485
485
|
|
|
@@ -575,7 +575,7 @@ roles: customRoles.map(r => r.id) };
|
|
|
575
575
|
const customRoles = await defineRolesFor(userToSet);
|
|
576
576
|
if (customRoles) {
|
|
577
577
|
userToSet = { ...userToSet,
|
|
578
|
-
roles: customRoles
|
|
578
|
+
roles: customRoles };
|
|
579
579
|
}
|
|
580
580
|
}
|
|
581
581
|
|
|
@@ -619,7 +619,7 @@ roles: customRoles.map(r => r.id) };
|
|
|
619
619
|
if (!isMountedRef.current) return;
|
|
620
620
|
if (customRoles) {
|
|
621
621
|
userToSet = { ...userToSet,
|
|
622
|
-
roles: customRoles
|
|
622
|
+
roles: customRoles };
|
|
623
623
|
}
|
|
624
624
|
}
|
|
625
625
|
} catch (meError: unknown) {
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthController,
|
|
1
|
+
import { AuthController, User } from "@rebasepro/types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Auth controller that extends the base AuthController
|
|
@@ -64,7 +64,7 @@ export interface RebaseAuthControllerProps {
|
|
|
64
64
|
/** Callback when user signs out */
|
|
65
65
|
onSignOut?: () => void;
|
|
66
66
|
/** Define roles for a user after login */
|
|
67
|
-
defineRolesFor?: (user: User) => Promise<
|
|
67
|
+
defineRolesFor?: (user: User) => Promise<string[] | undefined> | string[] | undefined;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|