@netlify/identity 0.4.1 → 0.4.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/README.md +29 -15
- package/dist/index.cjs +63 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -47
- package/dist/index.d.ts +34 -47
- package/dist/index.js +63 -88
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -86,17 +86,17 @@ interface AdminUserUpdates {
|
|
|
86
86
|
password?: string;
|
|
87
87
|
/** The user's role (e.g., `'admin'`, `'editor'`). */
|
|
88
88
|
role?: string;
|
|
89
|
+
/** The user's audience (rarely needed; defaults to the site's audience). */
|
|
90
|
+
aud?: string;
|
|
89
91
|
/** Set to `true` to force-confirm the user's email without sending a confirmation email. */
|
|
90
92
|
confirm?: boolean;
|
|
91
93
|
/** Server-managed metadata. Only writable via admin operations. */
|
|
92
94
|
app_metadata?: Record<string, unknown>;
|
|
93
95
|
/** User-managed metadata (display name, avatar, preferences, etc.). */
|
|
94
96
|
user_metadata?: Record<string, unknown>;
|
|
95
|
-
[key: string]: unknown;
|
|
96
97
|
}
|
|
97
98
|
/**
|
|
98
|
-
*
|
|
99
|
-
* pagination is ignored in the browser (gotrue-js limitation).
|
|
99
|
+
* Pagination options for {@link admin.listUsers}.
|
|
100
100
|
*/
|
|
101
101
|
interface ListUsersOptions {
|
|
102
102
|
/** 1-based page number. */
|
|
@@ -107,9 +107,10 @@ interface ListUsersOptions {
|
|
|
107
107
|
/**
|
|
108
108
|
* Parameters for {@link admin.createUser}.
|
|
109
109
|
*
|
|
110
|
-
* The optional `data` fields are
|
|
111
|
-
* request body
|
|
112
|
-
* `user_metadata
|
|
110
|
+
* The optional `data` fields are forwarded as top-level attributes in the GoTrue
|
|
111
|
+
* request body. Only these keys are accepted: `role`, `aud`, `app_metadata`,
|
|
112
|
+
* `user_metadata`. Any other keys are silently ignored. `data` cannot override
|
|
113
|
+
* `email`, `password`, or `confirm`.
|
|
113
114
|
*
|
|
114
115
|
* @example
|
|
115
116
|
* ```ts
|
|
@@ -123,7 +124,7 @@ interface ListUsersOptions {
|
|
|
123
124
|
interface CreateUserParams {
|
|
124
125
|
email: string;
|
|
125
126
|
password: string;
|
|
126
|
-
/**
|
|
127
|
+
/** GoTrue user fields: `role`, `aud`, `app_metadata`, `user_metadata`. Other keys are ignored. */
|
|
127
128
|
data?: Record<string, unknown>;
|
|
128
129
|
}
|
|
129
130
|
|
|
@@ -426,75 +427,61 @@ declare class MissingIdentityError extends Error {
|
|
|
426
427
|
|
|
427
428
|
/**
|
|
428
429
|
* The admin namespace for privileged user management operations.
|
|
429
|
-
* All methods
|
|
430
|
+
* All methods are server-only and require the operator token
|
|
431
|
+
* (automatically available in Netlify Functions and Edge Functions).
|
|
430
432
|
*
|
|
431
|
-
*
|
|
432
|
-
* **Browser:** requires a logged-in user with an admin role.
|
|
433
|
+
* Calling any admin method from a browser environment throws an `AuthError`.
|
|
433
434
|
*/
|
|
434
435
|
interface Admin {
|
|
435
436
|
/**
|
|
436
|
-
* Lists all users.
|
|
437
|
+
* Lists all users. Server-only.
|
|
437
438
|
*
|
|
438
|
-
*
|
|
439
|
+
* Calls GoTrue `GET /admin/users` with the operator token. Pagination
|
|
439
440
|
* options (`page`, `perPage`) are forwarded as query parameters.
|
|
440
441
|
*
|
|
441
|
-
*
|
|
442
|
-
* have an admin role. Pagination options are ignored (gotrue-js does not support them).
|
|
443
|
-
*
|
|
444
|
-
* @throws {AuthError} If the operator token is missing (server) or no admin user is logged in (browser).
|
|
442
|
+
* @throws {AuthError} If called from a browser, or if the operator token is missing.
|
|
445
443
|
*/
|
|
446
444
|
listUsers: (options?: ListUsersOptions) => Promise<User[]>;
|
|
447
445
|
/**
|
|
448
|
-
* Gets a single user by ID.
|
|
449
|
-
*
|
|
450
|
-
* **Server:** calls GoTrue `GET /admin/users/:id` with the operator token.
|
|
446
|
+
* Gets a single user by ID. Server-only.
|
|
451
447
|
*
|
|
452
|
-
*
|
|
453
|
-
* have an admin role.
|
|
448
|
+
* Calls GoTrue `GET /admin/users/:id` with the operator token.
|
|
454
449
|
*
|
|
455
|
-
* @throws {AuthError} If
|
|
456
|
-
* or
|
|
450
|
+
* @throws {AuthError} If called from a browser, the user is not found,
|
|
451
|
+
* or the operator token is missing.
|
|
457
452
|
*/
|
|
458
453
|
getUser: (userId: string) => Promise<User>;
|
|
459
454
|
/**
|
|
460
455
|
* Creates a new user. The user is auto-confirmed (no confirmation email is sent).
|
|
461
|
-
*
|
|
456
|
+
* Server-only.
|
|
462
457
|
*
|
|
463
|
-
* The optional `data` fields are
|
|
464
|
-
* request body
|
|
465
|
-
*
|
|
458
|
+
* The optional `data` fields are forwarded as top-level attributes in the GoTrue
|
|
459
|
+
* request body. Accepted fields: `role`, `aud`, `app_metadata`, `user_metadata`.
|
|
460
|
+
* Any other keys in `data` are silently ignored. `data` cannot override `email`,
|
|
461
|
+
* `password`, or `confirm`.
|
|
466
462
|
*
|
|
467
|
-
*
|
|
463
|
+
* Calls GoTrue `POST /admin/users` with the operator token.
|
|
468
464
|
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
* @throws {AuthError} If the email already exists, the operator token is missing (server),
|
|
473
|
-
* or no admin user is logged in (browser).
|
|
465
|
+
* @throws {AuthError} If called from a browser, the email already exists,
|
|
466
|
+
* or the operator token is missing.
|
|
474
467
|
*/
|
|
475
468
|
createUser: (params: CreateUserParams) => Promise<User>;
|
|
476
469
|
/**
|
|
477
|
-
* Updates an existing user by ID.
|
|
478
|
-
*
|
|
479
|
-
* **Server:** calls GoTrue `PUT /admin/users/:id` with the operator token.
|
|
470
|
+
* Updates an existing user by ID. Server-only.
|
|
480
471
|
*
|
|
481
|
-
*
|
|
482
|
-
* have an admin role.
|
|
472
|
+
* Calls GoTrue `PUT /admin/users/:id` with the operator token.
|
|
483
473
|
*
|
|
484
|
-
* @throws {AuthError} If the user is not found,
|
|
485
|
-
*
|
|
474
|
+
* @throws {AuthError} If called from a browser, the user is not found,
|
|
475
|
+
* the update fails, or the operator token is missing.
|
|
486
476
|
*/
|
|
487
477
|
updateUser: (userId: string, attributes: AdminUserUpdates) => Promise<User>;
|
|
488
478
|
/**
|
|
489
|
-
* Deletes a user by ID.
|
|
490
|
-
*
|
|
491
|
-
* **Server:** calls GoTrue `DELETE /admin/users/:id` with the operator token.
|
|
479
|
+
* Deletes a user by ID. Server-only.
|
|
492
480
|
*
|
|
493
|
-
*
|
|
494
|
-
* have an admin role.
|
|
481
|
+
* Calls GoTrue `DELETE /admin/users/:id` with the operator token.
|
|
495
482
|
*
|
|
496
|
-
* @throws {AuthError} If the user is not found,
|
|
497
|
-
*
|
|
483
|
+
* @throws {AuthError} If called from a browser, the user is not found,
|
|
484
|
+
* the deletion fails, or the operator token is missing.
|
|
498
485
|
*/
|
|
499
486
|
deleteUser: (userId: string) => Promise<void>;
|
|
500
487
|
}
|
package/dist/index.js
CHANGED
|
@@ -876,6 +876,19 @@ var updateUser = async (updates) => {
|
|
|
876
876
|
};
|
|
877
877
|
|
|
878
878
|
// src/admin.ts
|
|
879
|
+
var SERVER_ONLY_MESSAGE = "Admin operations are server-only. Call admin methods from a Netlify Function or Edge Function, not from browser code.";
|
|
880
|
+
var sanitizeUserId = (userId) => {
|
|
881
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
882
|
+
if (!uuidRegex.test(userId)) {
|
|
883
|
+
throw new AuthError("User ID is not a valid UUID");
|
|
884
|
+
}
|
|
885
|
+
return encodeURIComponent(userId);
|
|
886
|
+
};
|
|
887
|
+
var assertServer = () => {
|
|
888
|
+
if (isBrowser()) {
|
|
889
|
+
throw new AuthError(SERVER_ONLY_MESSAGE);
|
|
890
|
+
}
|
|
891
|
+
};
|
|
879
892
|
var getAdminAuth = () => {
|
|
880
893
|
const ctx = getIdentityContext();
|
|
881
894
|
if (!ctx?.url) {
|
|
@@ -907,105 +920,67 @@ var adminFetch = async (path, options = {}) => {
|
|
|
907
920
|
}
|
|
908
921
|
return res;
|
|
909
922
|
};
|
|
910
|
-
var getAdminUser = () => {
|
|
911
|
-
const client = getClient();
|
|
912
|
-
const user = client.currentUser();
|
|
913
|
-
if (!user) {
|
|
914
|
-
throw new AuthError("Admin operations require a logged-in user with admin role");
|
|
915
|
-
}
|
|
916
|
-
return user;
|
|
917
|
-
};
|
|
918
923
|
var listUsers = async (options) => {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
try {
|
|
930
|
-
const user = getAdminUser();
|
|
931
|
-
const users = await user.admin.listUsers("");
|
|
932
|
-
return users.map(toUser);
|
|
933
|
-
} catch (error) {
|
|
934
|
-
if (error instanceof AuthError) throw error;
|
|
935
|
-
throw new AuthError(error.message, void 0, { cause: error });
|
|
936
|
-
}
|
|
924
|
+
assertServer();
|
|
925
|
+
const params = new URLSearchParams();
|
|
926
|
+
if (options?.page != null) params.set("page", String(options.page));
|
|
927
|
+
if (options?.perPage != null) params.set("per_page", String(options.perPage));
|
|
928
|
+
const query = params.toString();
|
|
929
|
+
const path = `/admin/users${query ? `?${query}` : ""}`;
|
|
930
|
+
const res = await adminFetch(path);
|
|
931
|
+
const body = await res.json();
|
|
932
|
+
return body.users.map(toUser);
|
|
937
933
|
};
|
|
938
934
|
var getUser2 = async (userId) => {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
try {
|
|
945
|
-
const user = getAdminUser();
|
|
946
|
-
const userData = await user.admin.getUser({ id: userId });
|
|
947
|
-
return toUser(userData);
|
|
948
|
-
} catch (error) {
|
|
949
|
-
if (error instanceof AuthError) throw error;
|
|
950
|
-
throw new AuthError(error.message, void 0, { cause: error });
|
|
951
|
-
}
|
|
935
|
+
assertServer();
|
|
936
|
+
const sanitizedUserId = sanitizeUserId(userId);
|
|
937
|
+
const res = await adminFetch(`/admin/users/${sanitizedUserId}`);
|
|
938
|
+
const userData = await res.json();
|
|
939
|
+
return toUser(userData);
|
|
952
940
|
};
|
|
953
941
|
var createUser = async (params) => {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
try {
|
|
968
|
-
const user = getAdminUser();
|
|
969
|
-
const userData = await user.admin.createUser(params.email, params.password, {
|
|
970
|
-
...params.data,
|
|
971
|
-
confirm: true
|
|
972
|
-
});
|
|
973
|
-
return toUser(userData);
|
|
974
|
-
} catch (error) {
|
|
975
|
-
if (error instanceof AuthError) throw error;
|
|
976
|
-
throw new AuthError(error.message, void 0, { cause: error });
|
|
942
|
+
assertServer();
|
|
943
|
+
const body = {
|
|
944
|
+
email: params.email,
|
|
945
|
+
password: params.password,
|
|
946
|
+
confirm: true
|
|
947
|
+
};
|
|
948
|
+
if (params.data) {
|
|
949
|
+
const allowedKeys = ["role", "aud", "app_metadata", "user_metadata"];
|
|
950
|
+
for (const key of allowedKeys) {
|
|
951
|
+
if (key in params.data) {
|
|
952
|
+
body[key] = params.data[key];
|
|
953
|
+
}
|
|
954
|
+
}
|
|
977
955
|
}
|
|
956
|
+
const res = await adminFetch("/admin/users", {
|
|
957
|
+
method: "POST",
|
|
958
|
+
body: JSON.stringify(body)
|
|
959
|
+
});
|
|
960
|
+
const userData = await res.json();
|
|
961
|
+
return toUser(userData);
|
|
978
962
|
};
|
|
979
963
|
var updateUser2 = async (userId, attributes) => {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
try {
|
|
989
|
-
const user = getAdminUser();
|
|
990
|
-
const userData = await user.admin.updateUser({ id: userId }, attributes);
|
|
991
|
-
return toUser(userData);
|
|
992
|
-
} catch (error) {
|
|
993
|
-
if (error instanceof AuthError) throw error;
|
|
994
|
-
throw new AuthError(error.message, void 0, { cause: error });
|
|
964
|
+
assertServer();
|
|
965
|
+
const sanitizedUserId = sanitizeUserId(userId);
|
|
966
|
+
const body = {};
|
|
967
|
+
const allowedKeys = ["email", "password", "role", "aud", "confirm", "app_metadata", "user_metadata"];
|
|
968
|
+
for (const key of allowedKeys) {
|
|
969
|
+
if (key in attributes) {
|
|
970
|
+
body[key] = attributes[key];
|
|
971
|
+
}
|
|
995
972
|
}
|
|
973
|
+
const res = await adminFetch(`/admin/users/${sanitizedUserId}`, {
|
|
974
|
+
method: "PUT",
|
|
975
|
+
body: JSON.stringify(body)
|
|
976
|
+
});
|
|
977
|
+
const userData = await res.json();
|
|
978
|
+
return toUser(userData);
|
|
996
979
|
};
|
|
997
980
|
var deleteUser = async (userId) => {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
try {
|
|
1003
|
-
const user = getAdminUser();
|
|
1004
|
-
await user.admin.deleteUser({ id: userId });
|
|
1005
|
-
} catch (error) {
|
|
1006
|
-
if (error instanceof AuthError) throw error;
|
|
1007
|
-
throw new AuthError(error.message, void 0, { cause: error });
|
|
1008
|
-
}
|
|
981
|
+
assertServer();
|
|
982
|
+
const sanitizedUserId = sanitizeUserId(userId);
|
|
983
|
+
await adminFetch(`/admin/users/${sanitizedUserId}`, { method: "DELETE" });
|
|
1009
984
|
};
|
|
1010
985
|
var admin = { listUsers, getUser: getUser2, createUser, updateUser: updateUser2, deleteUser };
|
|
1011
986
|
export {
|