@netlify/identity 0.4.1 → 1.0.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.
package/README.md CHANGED
@@ -3,23 +3,24 @@
3
3
  A lightweight, no-config headless authentication library for projects using Netlify Identity. Works in both browser and server contexts.
4
4
  This is NOT the Netlify Identity Widget. This library exports standalone async functions (e.g., import { login, getUser } from '@netlify/identity'). There is no class to instantiate and no .init() call. Just import the functions you need and call them.
5
5
 
6
- > **Status:** Beta. The API may change before 1.0.
7
-
8
6
  **Prerequisites:**
9
7
 
10
- - [Netlify Identity](https://docs.netlify.com/security/secure-access-to-sites/identity/) must be enabled on your Netlify project
8
+ - [Netlify Identity](https://docs.netlify.com/security/secure-access-to-sites/identity/) must be enabled on your Netlify project. This happens automatically when running within a [Netlify Agent Runner](https://docs.netlify.com/agent-runner/overview/)
11
9
  - **Server-side** functions (`getUser`, `login`, `admin.*`, etc.) require [Netlify Functions](https://docs.netlify.com/build/functions/get-started/) (modern/v2, with `export default`) or [Edge Functions](https://docs.netlify.com/edge-functions/overview/). [Lambda-compatible functions](https://docs.netlify.com/build/functions/lambda-compatibility/) (v1, with `export { handler }`) are **not supported**
12
10
  - For local development, use [`netlify dev`](https://docs.netlify.com/cli/local-development/) so the Identity endpoint is available
13
11
 
14
12
  ## How this library relates to other Netlify auth packages
15
13
 
16
- | Package | What it is | When to use it |
17
- | ------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ |
18
- | **`@netlify/identity`** (this library) | Headless TypeScript API for browser and server | You want full control over your auth UI and need server-side auth (SSR, Netlify Functions) |
19
- | [`netlify-identity-widget`](https://github.com/netlify/netlify-identity-widget) | Pre-built login/signup modal (HTML + CSS) | You want a drop-in UI component with no custom design |
20
- | [`gotrue-js`](https://github.com/netlify/gotrue-js) | Low-level GoTrue HTTP client (browser only) | You're building your own auth wrapper and need direct API access |
14
+ `@netlify/identity` is the recommended library for all new projects. It works in both browser and server contexts, handles cookie management, and normalizes the user object.
15
+
16
+ You may encounter two older packages in existing code or documentation:
17
+
18
+ | Package | Status | What it was |
19
+ | ------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------- |
20
+ | [`netlify-identity-widget`](https://github.com/netlify/netlify-identity-widget) | Not recommended for new projects | Pre-built login/signup modal with built-in UI |
21
+ | [`gotrue-js`](https://github.com/netlify/gotrue-js) | Not recommended for new projects | Low-level GoTrue HTTP client (browser only) |
21
22
 
22
- This library provides a unified API that works in both browser and server contexts, handles cookie management, and normalizes the user object. You do not need to install `gotrue-js` or the widget separately.
23
+ If you need a pre-built login UI, the widget still works. For everything else (custom UI, server-side auth, admin operations, framework integration), use `@netlify/identity`.
23
24
 
24
25
  ## Table of contents
25
26
 
@@ -38,6 +39,7 @@ This library provides a unified API that works in both browser and server contex
38
39
  - [Password recovery](#password-recovery)
39
40
  - [Invite acceptance](#invite-acceptance)
40
41
  - [Session lifetime](#session-lifetime)
42
+ - [Caching and authenticated content](#caching-and-authenticated-content)
41
43
 
42
44
  ## Installation
43
45
 
@@ -96,7 +98,7 @@ export default async (req: Request, context: Context) => {
96
98
  getUser(): Promise<User | null>
97
99
  ```
98
100
 
99
- Returns the current authenticated user, or `null` if not logged in. Returns the best available normalized `User` from the current context. In the browser or when the server can reach the Identity API, all fields are populated. When falling back to JWT claims (e.g., Identity API unreachable), fields like `createdAt`, `updatedAt`, `emailVerified`, and `rawGoTrueData` may be missing. Never throws.
101
+ Returns the current authenticated user, or `null` if not logged in. Returns the best available normalized `User` from the current context. When the Identity API is reachable, most persisted and profile fields are populated, but state-dependent fields (invite, recovery, email-change) may still be `undefined` if the user is not in that state. When falling back to JWT claims (e.g., Identity API unreachable), only `id`, `email`, `provider`, `name`, `pictureUrl`, `roles`, `userMetadata`, and `appMetadata` are available. Never throws.
100
102
 
101
103
  > **Next.js note:** Calling `getUser()` in a Server Component opts the page into [dynamic rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#dynamic-rendering) because it reads cookies. This is expected and correct for authenticated pages. Next.js handles the internal dynamic rendering signal automatically.
102
104
 
@@ -172,7 +174,7 @@ oauthLogin(provider: string): never
172
174
 
173
175
  Redirects to an OAuth provider. The page navigates away, so this function never returns normally. Browser only.
174
176
 
175
- The `provider` argument should be one of the `AuthProvider` values: `'google'`, `'github'`, `'gitlab'`, `'bitbucket'`, `'facebook'`, or `'saml'`.
177
+ The `provider` argument should be one of the `AuthProvider` values: `'google'`, `'github'`, `'gitlab'`, `'bitbucket'`, or `'facebook'`.
176
178
 
177
179
  **Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if called on the server.
178
180
 
@@ -302,10 +304,9 @@ Updates the current user's metadata or credentials. Requires an active session.
302
304
 
303
305
  ### Admin Operations
304
306
 
305
- The `admin` namespace provides user management functions for administrators. These work in two contexts:
307
+ The `admin` namespace provides server-only user management functions. Admin methods use the operator token from the Netlify runtime, which is automatically available in Netlify Functions and Edge Functions.
306
308
 
307
- - **Server:** Uses the operator token from the Netlify runtime for full admin access. No logged-in user required.
308
- - **Browser:** Uses the logged-in user's JWT. The user must have an admin role.
309
+ Calling any admin method from a browser environment throws an `AuthError`.
309
310
 
310
311
  ```ts
311
312
  import { admin } from '@netlify/identity'
@@ -341,9 +342,9 @@ export default async (req: Request, context: Context) => {
341
342
  admin.listUsers(options?: ListUsersOptions): Promise<User[]>
342
343
  ```
343
344
 
344
- Lists all users. Pagination options are supported on the server; they are ignored in the browser.
345
+ Lists all users. Pagination options (`page`, `perPage`) are forwarded as query parameters.
345
346
 
346
- **Throws:** `AuthError` if the operator token is missing (server) or no user is logged in (browser).
347
+ **Throws:** `AuthError` if called from a browser, or if the operator token is missing.
347
348
 
348
349
  #### `admin.getUser`
349
350
 
@@ -353,7 +354,7 @@ admin.getUser(userId: string): Promise<User>
353
354
 
354
355
  Gets a single user by ID.
355
356
 
356
- **Throws:** `AuthError` if the user is not found, the operator token is missing (server), or no user is logged in (browser).
357
+ **Throws:** `AuthError` if called from a browser, the user is not found, or the operator token is missing.
357
358
 
358
359
  #### `admin.createUser`
359
360
 
@@ -361,9 +362,9 @@ Gets a single user by ID.
361
362
  admin.createUser(params: CreateUserParams): Promise<User>
362
363
  ```
363
364
 
364
- Creates a new user. The user is auto-confirmed. Optional `data` is spread into the request body as additional attributes.
365
+ Creates a new user. The user is auto-confirmed. Optional `data` forwards allowed fields (`role`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored. `data` cannot override `email`, `password`, or `confirm`.
365
366
 
366
- **Throws:** `AuthError` on failure (e.g., email already exists).
367
+ **Throws:** `AuthError` if called from a browser, the email already exists, or the operator token is missing.
367
368
 
368
369
  #### `admin.updateUser`
369
370
 
@@ -371,9 +372,9 @@ Creates a new user. The user is auto-confirmed. Optional `data` is spread into t
371
372
  admin.updateUser(userId: string, attributes: AdminUserUpdates): Promise<User>
372
373
  ```
373
374
 
374
- Updates an existing user by ID. Pass any attributes to change (e.g., `{ email: 'new@example.com' }`). See `AdminUserUpdates` for typed fields.
375
+ Updates an existing user by ID. Only typed `AdminUserUpdates` fields are forwarded (e.g., `{ email: 'new@example.com' }`, `{ role: 'editor' }`).
375
376
 
376
- **Throws:** `AuthError` if the user is not found or the update fails.
377
+ **Throws:** `AuthError` if called from a browser, the user is not found, or the update fails.
377
378
 
378
379
  #### `admin.deleteUser`
379
380
 
@@ -383,7 +384,7 @@ admin.deleteUser(userId: string): Promise<void>
383
384
 
384
385
  Deletes a user by ID.
385
386
 
386
- **Throws:** `AuthError` if the user is not found or the deletion fails.
387
+ **Throws:** `AuthError` if called from a browser, the user is not found, or the deletion fails.
387
388
 
388
389
  ### Types
389
390
 
@@ -393,16 +394,22 @@ Deletes a user by ID.
393
394
  interface User {
394
395
  id: string
395
396
  email?: string
396
- emailVerified?: boolean
397
+ confirmedAt?: string
397
398
  createdAt?: string
398
399
  updatedAt?: string
400
+ role?: string
399
401
  provider?: AuthProvider
400
402
  name?: string
401
403
  pictureUrl?: string
402
404
  roles?: string[]
403
- metadata?: Record<string, unknown>
405
+ invitedAt?: string
406
+ confirmationSentAt?: string
407
+ recoverySentAt?: string
408
+ pendingEmail?: string
409
+ emailChangeSentAt?: string
410
+ lastSignInAt?: string
411
+ userMetadata?: Record<string, unknown>
404
412
  appMetadata?: Record<string, unknown>
405
- rawGoTrueData?: Record<string, unknown>
406
413
  }
407
414
  ```
408
415
 
@@ -428,7 +435,7 @@ interface IdentityConfig {
428
435
  #### `AuthProvider`
429
436
 
430
437
  ```ts
431
- type AuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | 'saml' | 'email'
438
+ type AuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | 'email'
432
439
  ```
433
440
 
434
441
  #### `UserUpdates`
@@ -454,11 +461,10 @@ interface AdminUserUpdates {
454
461
  confirm?: boolean
455
462
  app_metadata?: Record<string, unknown>
456
463
  user_metadata?: Record<string, unknown>
457
- [key: string]: unknown
458
464
  }
459
465
  ```
460
466
 
461
- Fields accepted by `admin.updateUser()`. Unlike `UserUpdates`, admin updates can set `role`, force-confirm a user, and write to `app_metadata`.
467
+ Fields accepted by `admin.updateUser()`. Unlike `UserUpdates`, admin updates can set `role`, force-confirm a user, and write to `app_metadata`. Only these typed fields are forwarded.
462
468
 
463
469
  #### `SignupData`
464
470
 
@@ -487,7 +493,7 @@ interface ListUsersOptions {
487
493
  }
488
494
  ```
489
495
 
490
- Pagination options for `admin.listUsers()`. Only used on the server; pagination is ignored in the browser.
496
+ Pagination options for `admin.listUsers()`.
491
497
 
492
498
  #### `CreateUserParams`
493
499
 
@@ -499,7 +505,7 @@ interface CreateUserParams {
499
505
  }
500
506
  ```
501
507
 
502
- Parameters for `admin.createUser()`. Optional `data` is spread into the request body as top-level attributes (use it to set `app_metadata`, `user_metadata`, `role`, etc.).
508
+ Parameters for `admin.createUser()`. Optional `data` forwards allowed fields (`role`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored.
503
509
 
504
510
  #### `Admin`
505
511
 
@@ -1048,6 +1054,20 @@ Sessions are managed by Netlify Identity on the server side. The library stores
1048
1054
 
1049
1055
  Session lifetime is configured in your Netlify Identity settings, not in this library.
1050
1056
 
1057
+ ### Caching and authenticated content
1058
+
1059
+ Pages that display user-specific data (names, emails, roles, account settings) should not be served from a shared cache. If a cache stores an authenticated response and serves it to a different user, that user sees someone else's data. This applies to any authentication system, not just Netlify Identity.
1060
+
1061
+ **Next.js App Router** has multiple caching layers that are active by default:
1062
+
1063
+ - **Static rendering:** Server Components are statically rendered at build time unless they call a [Dynamic API](https://nextjs.org/docs/app/guides/caching#dynamic-rendering) like `cookies()`. This library's `getUser()` already calls `headers()` internally to opt the route into dynamic rendering, but if you check auth state without calling `getUser()` (e.g., reading the `nf_jwt` cookie directly), the page may still be statically cached. Always use `getUser()` rather than reading cookies directly.
1064
+ - **ISR (Incremental Static Regeneration):** Do not use ISR for pages that display user-specific content. ISR regenerates the page for the first visitor after the revalidation window and caches the result for all subsequent visitors.
1065
+ - **`use cache` / `unstable_cache`:** These directives cannot access `cookies()` or `headers()` directly. If you need to cache part of an authenticated page, read cookies outside the cache scope and pass relevant values as arguments.
1066
+
1067
+ > **Note:** Next.js caching defaults have changed across versions. For example, [Next.js 15 changed `fetch` requests, `GET` Route Handlers, and the client Router Cache to be uncached by default](https://nextjs.org/blog/next-15#caching-semantics), reversing the previous opt-out model. Check the [caching guide](https://nextjs.org/docs/app/guides/caching) for your specific Next.js version.
1068
+
1069
+ **Other SSR frameworks (Remix, Astro, SvelteKit, TanStack Start):** These frameworks do not cache SSR responses by default. If you add caching headers to improve performance, exclude routes that call `getUser()` or read auth cookies.
1070
+
1051
1071
  ## License
1052
1072
 
1053
1073
  MIT
package/dist/index.cjs CHANGED
@@ -56,7 +56,7 @@ __export(index_exports, {
56
56
  module.exports = __toCommonJS(index_exports);
57
57
 
58
58
  // src/types.ts
59
- var AUTH_PROVIDERS = ["google", "github", "gitlab", "bitbucket", "facebook", "saml", "email"];
59
+ var AUTH_PROVIDERS = ["google", "github", "gitlab", "bitbucket", "facebook", "email"];
60
60
 
61
61
  // src/environment.ts
62
62
  var import_gotrue_js = __toESM(require("gotrue-js"), 1);
@@ -681,6 +681,7 @@ var hydrateSession = async () => {
681
681
 
682
682
  // src/user.ts
683
683
  var toAuthProvider = (value) => typeof value === "string" && AUTH_PROVIDERS.includes(value) ? value : void 0;
684
+ var toOptionalString = (value) => typeof value === "string" && value !== "" ? value : void 0;
684
685
  var toRoles = (appMeta) => {
685
686
  const roles = appMeta.roles;
686
687
  if (Array.isArray(roles) && roles.every((r) => typeof r === "string")) {
@@ -693,20 +694,25 @@ var toUser = (userData) => {
693
694
  const appMeta = userData.app_metadata ?? {};
694
695
  const name = userMeta.full_name || userMeta.name;
695
696
  const pictureUrl = userMeta.avatar_url;
696
- const { token: _token, ...safeUserData } = userData;
697
697
  return {
698
698
  id: userData.id,
699
699
  email: userData.email,
700
- emailVerified: !!userData.confirmed_at,
700
+ confirmedAt: toOptionalString(userData.confirmed_at),
701
701
  createdAt: userData.created_at,
702
702
  updatedAt: userData.updated_at,
703
+ role: toOptionalString(userData.role),
703
704
  provider: toAuthProvider(appMeta.provider),
704
705
  name: typeof name === "string" ? name : void 0,
705
706
  pictureUrl: typeof pictureUrl === "string" ? pictureUrl : void 0,
706
707
  roles: toRoles(appMeta),
707
- metadata: userMeta,
708
- appMetadata: appMeta,
709
- rawGoTrueData: { ...safeUserData }
708
+ invitedAt: toOptionalString(userData.invited_at),
709
+ confirmationSentAt: toOptionalString(userData.confirmation_sent_at),
710
+ recoverySentAt: toOptionalString(userData.recovery_sent_at),
711
+ pendingEmail: toOptionalString(userData.new_email),
712
+ emailChangeSentAt: toOptionalString(userData.email_change_sent_at),
713
+ lastSignInAt: toOptionalString(userData.last_sign_in_at),
714
+ userMetadata: userMeta,
715
+ appMetadata: appMeta
710
716
  };
711
717
  };
712
718
  var claimsToUser = (claims) => {
@@ -721,7 +727,7 @@ var claimsToUser = (claims) => {
721
727
  name: typeof name === "string" ? name : void 0,
722
728
  pictureUrl: typeof pictureUrl === "string" ? pictureUrl : void 0,
723
729
  roles: toRoles(appMeta),
724
- metadata: userMeta,
730
+ userMetadata: userMeta,
725
731
  appMetadata: appMeta
726
732
  };
727
733
  };
@@ -818,8 +824,7 @@ var getSettings = async () => {
818
824
  gitlab: external.gitlab ?? false,
819
825
  bitbucket: external.bitbucket ?? false,
820
826
  facebook: external.facebook ?? false,
821
- email: external.email ?? false,
822
- saml: external.saml ?? false
827
+ email: external.email ?? false
823
828
  }
824
829
  };
825
830
  } catch (err) {
@@ -926,6 +931,19 @@ var updateUser = async (updates) => {
926
931
  };
927
932
 
928
933
  // src/admin.ts
934
+ var SERVER_ONLY_MESSAGE = "Admin operations are server-only. Call admin methods from a Netlify Function or Edge Function, not from browser code.";
935
+ var sanitizeUserId = (userId) => {
936
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
937
+ if (!uuidRegex.test(userId)) {
938
+ throw new AuthError("User ID is not a valid UUID");
939
+ }
940
+ return encodeURIComponent(userId);
941
+ };
942
+ var assertServer = () => {
943
+ if (isBrowser()) {
944
+ throw new AuthError(SERVER_ONLY_MESSAGE);
945
+ }
946
+ };
929
947
  var getAdminAuth = () => {
930
948
  const ctx = getIdentityContext();
931
949
  if (!ctx?.url) {
@@ -957,105 +975,67 @@ var adminFetch = async (path, options = {}) => {
957
975
  }
958
976
  return res;
959
977
  };
960
- var getAdminUser = () => {
961
- const client = getClient();
962
- const user = client.currentUser();
963
- if (!user) {
964
- throw new AuthError("Admin operations require a logged-in user with admin role");
965
- }
966
- return user;
967
- };
968
978
  var listUsers = async (options) => {
969
- if (!isBrowser()) {
970
- const params = new URLSearchParams();
971
- if (options?.page != null) params.set("page", String(options.page));
972
- if (options?.perPage != null) params.set("per_page", String(options.perPage));
973
- const query = params.toString();
974
- const path = `/admin/users${query ? `?${query}` : ""}`;
975
- const res = await adminFetch(path);
976
- const body = await res.json();
977
- return body.users.map(toUser);
978
- }
979
- try {
980
- const user = getAdminUser();
981
- const users = await user.admin.listUsers("");
982
- return users.map(toUser);
983
- } catch (error) {
984
- if (error instanceof AuthError) throw error;
985
- throw new AuthError(error.message, void 0, { cause: error });
986
- }
979
+ assertServer();
980
+ const params = new URLSearchParams();
981
+ if (options?.page != null) params.set("page", String(options.page));
982
+ if (options?.perPage != null) params.set("per_page", String(options.perPage));
983
+ const query = params.toString();
984
+ const path = `/admin/users${query ? `?${query}` : ""}`;
985
+ const res = await adminFetch(path);
986
+ const body = await res.json();
987
+ return body.users.map(toUser);
987
988
  };
988
989
  var getUser2 = async (userId) => {
989
- if (!isBrowser()) {
990
- const res = await adminFetch(`/admin/users/${userId}`);
991
- const userData = await res.json();
992
- return toUser(userData);
993
- }
994
- try {
995
- const user = getAdminUser();
996
- const userData = await user.admin.getUser({ id: userId });
997
- return toUser(userData);
998
- } catch (error) {
999
- if (error instanceof AuthError) throw error;
1000
- throw new AuthError(error.message, void 0, { cause: error });
1001
- }
990
+ assertServer();
991
+ const sanitizedUserId = sanitizeUserId(userId);
992
+ const res = await adminFetch(`/admin/users/${sanitizedUserId}`);
993
+ const userData = await res.json();
994
+ return toUser(userData);
1002
995
  };
1003
996
  var createUser = async (params) => {
1004
- if (!isBrowser()) {
1005
- const res = await adminFetch("/admin/users", {
1006
- method: "POST",
1007
- body: JSON.stringify({
1008
- email: params.email,
1009
- password: params.password,
1010
- ...params.data,
1011
- confirm: true
1012
- })
1013
- });
1014
- const userData = await res.json();
1015
- return toUser(userData);
1016
- }
1017
- try {
1018
- const user = getAdminUser();
1019
- const userData = await user.admin.createUser(params.email, params.password, {
1020
- ...params.data,
1021
- confirm: true
1022
- });
1023
- return toUser(userData);
1024
- } catch (error) {
1025
- if (error instanceof AuthError) throw error;
1026
- throw new AuthError(error.message, void 0, { cause: error });
997
+ assertServer();
998
+ const body = {
999
+ email: params.email,
1000
+ password: params.password,
1001
+ confirm: true
1002
+ };
1003
+ if (params.data) {
1004
+ const allowedKeys = ["role", "app_metadata", "user_metadata"];
1005
+ for (const key of allowedKeys) {
1006
+ if (key in params.data) {
1007
+ body[key] = params.data[key];
1008
+ }
1009
+ }
1027
1010
  }
1011
+ const res = await adminFetch("/admin/users", {
1012
+ method: "POST",
1013
+ body: JSON.stringify(body)
1014
+ });
1015
+ const userData = await res.json();
1016
+ return toUser(userData);
1028
1017
  };
1029
1018
  var updateUser2 = async (userId, attributes) => {
1030
- if (!isBrowser()) {
1031
- const res = await adminFetch(`/admin/users/${userId}`, {
1032
- method: "PUT",
1033
- body: JSON.stringify(attributes)
1034
- });
1035
- const userData = await res.json();
1036
- return toUser(userData);
1037
- }
1038
- try {
1039
- const user = getAdminUser();
1040
- const userData = await user.admin.updateUser({ id: userId }, attributes);
1041
- return toUser(userData);
1042
- } catch (error) {
1043
- if (error instanceof AuthError) throw error;
1044
- throw new AuthError(error.message, void 0, { cause: error });
1019
+ assertServer();
1020
+ const sanitizedUserId = sanitizeUserId(userId);
1021
+ const body = {};
1022
+ const allowedKeys = ["email", "password", "role", "confirm", "app_metadata", "user_metadata"];
1023
+ for (const key of allowedKeys) {
1024
+ if (key in attributes) {
1025
+ body[key] = attributes[key];
1026
+ }
1045
1027
  }
1028
+ const res = await adminFetch(`/admin/users/${sanitizedUserId}`, {
1029
+ method: "PUT",
1030
+ body: JSON.stringify(body)
1031
+ });
1032
+ const userData = await res.json();
1033
+ return toUser(userData);
1046
1034
  };
1047
1035
  var deleteUser = async (userId) => {
1048
- if (!isBrowser()) {
1049
- await adminFetch(`/admin/users/${userId}`, { method: "DELETE" });
1050
- return;
1051
- }
1052
- try {
1053
- const user = getAdminUser();
1054
- await user.admin.deleteUser({ id: userId });
1055
- } catch (error) {
1056
- if (error instanceof AuthError) throw error;
1057
- throw new AuthError(error.message, void 0, { cause: error });
1058
- }
1036
+ assertServer();
1037
+ const sanitizedUserId = sanitizeUserId(userId);
1038
+ await adminFetch(`/admin/users/${sanitizedUserId}`, { method: "DELETE" });
1059
1039
  };
1060
1040
  var admin = { listUsers, getUser: getUser2, createUser, updateUser: updateUser2, deleteUser };
1061
1041
  // Annotate the CommonJS export names for ESM import in node: