@stackframe/stack 2.4.22 → 2.4.24

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/magic-link-sign-in.js +1 -1
  3. package/dist/components/magic-link-sign-in.js.map +1 -1
  4. package/dist/components/team-switcher.d.mts +8 -0
  5. package/dist/components/team-switcher.d.ts +8 -0
  6. package/dist/components/team-switcher.js +75 -0
  7. package/dist/components/team-switcher.js.map +1 -0
  8. package/dist/components-core/index.d.mts +4 -4
  9. package/dist/components-core/index.d.ts +4 -4
  10. package/dist/components-core-joy/text.d.mts +2 -2
  11. package/dist/components-core-joy/text.d.ts +2 -2
  12. package/dist/components-page/stack-handler.js +1 -1
  13. package/dist/components-page/stack-handler.js.map +1 -1
  14. package/dist/esm/components/magic-link-sign-in.js +1 -1
  15. package/dist/esm/components/magic-link-sign-in.js.map +1 -1
  16. package/dist/esm/components/team-switcher.js +63 -0
  17. package/dist/esm/components/team-switcher.js.map +1 -0
  18. package/dist/esm/components-page/stack-handler.js +1 -1
  19. package/dist/esm/components-page/stack-handler.js.map +1 -1
  20. package/dist/esm/index.js +18 -16
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/lib/hooks.js.map +1 -1
  23. package/dist/esm/lib/stack-app.js +286 -283
  24. package/dist/esm/lib/stack-app.js.map +1 -1
  25. package/dist/esm/providers/stack-provider.js +1 -1
  26. package/dist/esm/providers/stack-provider.js.map +1 -1
  27. package/dist/index.d.mts +1 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +3 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/lib/hooks.d.mts +3 -3
  32. package/dist/lib/hooks.d.ts +3 -3
  33. package/dist/lib/hooks.js.map +1 -1
  34. package/dist/lib/stack-app.d.mts +100 -81
  35. package/dist/lib/stack-app.d.ts +100 -81
  36. package/dist/lib/stack-app.js +284 -281
  37. package/dist/lib/stack-app.js.map +1 -1
  38. package/dist/providers/component-provider.d.mts +6 -6
  39. package/dist/providers/component-provider.d.ts +6 -6
  40. package/dist/providers/joy-provider.d.mts +2 -2
  41. package/dist/providers/joy-provider.d.ts +2 -2
  42. package/dist/providers/stack-provider.js +1 -1
  43. package/dist/providers/stack-provider.js.map +1 -1
  44. package/package.json +3 -3
@@ -1,7 +1,7 @@
1
1
  // src/lib/stack-app.ts
2
2
  import React, { use, useCallback, useMemo } from "react";
3
3
  import { KnownError, KnownErrors, StackAdminInterface, StackClientInterface, StackServerInterface } from "@stackframe/stack-shared";
4
- import { getCookie, setOrDeleteCookie } from "./cookie";
4
+ import { deleteCookie, getCookie, setOrDeleteCookie } from "./cookie";
5
5
  import { StackAssertionError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
6
6
  import { generateUuid } from "@stackframe/stack-shared/dist/utils/uuids";
7
7
  import { AsyncResult, Result } from "@stackframe/stack-shared/dist/utils/results";
@@ -12,7 +12,7 @@ import { isBrowserLike } from "@stackframe/stack-shared/dist/utils/env";
12
12
  import { addNewOAuthProviderOrScope, callOAuthCallback, signInWithOAuth } from "./auth";
13
13
  import * as NextNavigationUnscrambled from "next/navigation";
14
14
  import { constructRedirectUrl } from "../utils/url";
15
- import { deepPlainEquals, filterUndefined, omit } from "@stackframe/stack-shared/dist/utils/objects";
15
+ import { deepPlainEquals, filterUndefined, omit, pick } from "@stackframe/stack-shared/dist/utils/objects";
16
16
  import { neverResolve, resolved, runAsynchronously, wait } from "@stackframe/stack-shared/dist/utils/promises";
17
17
  import { AsyncCache } from "@stackframe/stack-shared/dist/utils/caches";
18
18
  import { suspend } from "@stackframe/stack-shared/dist/utils/react";
@@ -21,9 +21,9 @@ import { isReactServer } from "@stackframe/stack-sc";
21
21
  import * as cookie from "cookie";
22
22
  import { InternalSession } from "@stackframe/stack-shared/dist/sessions";
23
23
  import { useTrigger } from "@stackframe/stack-shared/dist/hooks/use-trigger";
24
- import { mergeScopeStrings } from "@stackframe/stack-shared/src/utils/strings";
24
+ import { mergeScopeStrings } from "@stackframe/stack-shared/dist/utils/strings";
25
25
  var NextNavigation = scrambleDuringCompileTime(NextNavigationUnscrambled);
26
- var clientVersion = "js @stackframe/stack@2.4.22";
26
+ var clientVersion = "js @stackframe/stack@2.4.24";
27
27
  function permissionDefinitionScopeToType(scope) {
28
28
  return { "any-team": "team", "specific-team": "team", "global": "global" }[scope.type];
29
29
  }
@@ -201,7 +201,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
201
201
  errorRedirectUrl: this.urls.error,
202
202
  providerScope: mergeScopeStrings(scope || "", (this._oauthScopesOnSignIn[connectionId] ?? []).join(" "))
203
203
  },
204
- this._getSession()
204
+ session
205
205
  );
206
206
  return await neverResolve();
207
207
  } else if (!hasConnection) {
@@ -247,12 +247,28 @@ var _StackClientAppImpl = class __StackClientAppImpl {
247
247
  }
248
248
  return this._uniqueIdentifier;
249
249
  }
250
+ async _checkFeatureSupport(featureName, options) {
251
+ return await this._interface.checkFeatureSupport({ ...options, featureName });
252
+ }
253
+ _useCheckFeatureSupport(featureName, options) {
254
+ runAsynchronously(this._checkFeatureSupport(featureName, options));
255
+ throw new StackAssertionError(`${featureName} is not currently supported. Please reach out to Stack support for more information.`);
256
+ }
250
257
  _memoryTokenStore = createEmptyTokenStore();
251
258
  _requestTokenStores = /* @__PURE__ */ new WeakMap();
252
259
  _storedCookieTokenStore = null;
253
260
  get _refreshTokenCookieName() {
254
261
  return `stack-refresh-${this.projectId}`;
255
262
  }
263
+ _getTokensFromCookies(cookies) {
264
+ const refreshToken = cookies.refreshTokenCookie;
265
+ const accessTokenObject = cookies.accessTokenCookie?.startsWith('["') ? JSON.parse(cookies.accessTokenCookie) : null;
266
+ const accessToken = accessTokenObject && refreshToken === accessTokenObject[0] ? accessTokenObject[1] : null;
267
+ return {
268
+ refreshToken,
269
+ accessToken
270
+ };
271
+ }
256
272
  get _accessTokenCookieName() {
257
273
  return `stack-access`;
258
274
  }
@@ -261,14 +277,17 @@ var _StackClientAppImpl = class __StackClientAppImpl {
261
277
  throw new Error("Cannot use cookie token store on the server!");
262
278
  }
263
279
  if (this._storedCookieTokenStore === null) {
264
- const getCurrentValue = (old) => ({
265
- refreshToken: getCookie(this._refreshTokenCookieName) ?? getCookie("stack-refresh"),
266
- // keep old cookie name for backwards-compatibility
267
- // if there is an access token in memory already, don't update the access token based on cookies (access token
268
- // cookies may be set by another project on the same domain)
269
- // see the comment in _accessTokenCookieName for more information
270
- accessToken: old === null ? getCookie(this._accessTokenCookieName) : old.accessToken
271
- });
280
+ const getCurrentValue = (old) => {
281
+ const tokens = this._getTokensFromCookies({
282
+ refreshTokenCookie: getCookie(this._refreshTokenCookieName) ?? getCookie("stack-refresh"),
283
+ // keep old cookie name for backwards-compatibility
284
+ accessTokenCookie: getCookie(this._accessTokenCookieName)
285
+ });
286
+ return {
287
+ refreshToken: tokens.refreshToken,
288
+ accessToken: tokens.accessToken ?? (old?.refreshToken === tokens.refreshToken ? old.accessToken : null)
289
+ };
290
+ };
272
291
  this._storedCookieTokenStore = new Store(getCurrentValue(null));
273
292
  let hasSucceededInWriting = true;
274
293
  setInterval(() => {
@@ -283,7 +302,8 @@ var _StackClientAppImpl = class __StackClientAppImpl {
283
302
  this._storedCookieTokenStore.onChange((value) => {
284
303
  try {
285
304
  setOrDeleteCookie(this._refreshTokenCookieName, value.refreshToken, { maxAge: 60 * 60 * 24 * 365 });
286
- setOrDeleteCookie(this._accessTokenCookieName, value.accessToken, { maxAge: 60 * 60 * 24 });
305
+ setOrDeleteCookie(this._accessTokenCookieName, value.accessToken ? JSON.stringify([value.refreshToken, value.accessToken]) : null, { maxAge: 60 * 60 * 24 });
306
+ deleteCookie("stack-refresh");
287
307
  hasSucceededInWriting = true;
288
308
  } catch (e) {
289
309
  if (!isBrowserLike()) {
@@ -306,15 +326,16 @@ var _StackClientAppImpl = class __StackClientAppImpl {
306
326
  if (isBrowserLike()) {
307
327
  return this._getCookieTokenStore();
308
328
  } else {
309
- const store = new Store({
310
- refreshToken: getCookie(this._refreshTokenCookieName) ?? getCookie("stack-refresh"),
329
+ const tokens = this._getTokensFromCookies({
330
+ refreshTokenCookie: getCookie(this._refreshTokenCookieName) ?? getCookie("stack-refresh"),
311
331
  // keep old cookie name for backwards-compatibility
312
- accessToken: getCookie(this._accessTokenCookieName)
332
+ accessTokenCookie: getCookie(this._accessTokenCookieName)
313
333
  });
334
+ const store = new Store(tokens);
314
335
  store.onChange((value) => {
315
336
  try {
316
337
  setOrDeleteCookie(this._refreshTokenCookieName, value.refreshToken, { maxAge: 60 * 60 * 24 * 365 });
317
- setOrDeleteCookie(this._accessTokenCookieName, value.accessToken, { maxAge: 60 * 60 * 24 });
338
+ setOrDeleteCookie(this._accessTokenCookieName, value.accessToken ? JSON.stringify([value.refreshToken, value.accessToken]) : null, { maxAge: 60 * 60 * 24 });
318
339
  } catch (e) {
319
340
  }
320
341
  });
@@ -410,7 +431,9 @@ var _StackClientAppImpl = class __StackClientAppImpl {
410
431
  _useSession(overrideTokenStoreInit) {
411
432
  const tokenStore = this._getOrCreateTokenStore(overrideTokenStoreInit);
412
433
  const subscribe = useCallback((cb) => {
413
- const { unsubscribe } = tokenStore.onChange(() => cb());
434
+ const { unsubscribe } = tokenStore.onChange(() => {
435
+ cb();
436
+ });
414
437
  return unsubscribe;
415
438
  }, [tokenStore]);
416
439
  const getSnapshot = useCallback(() => this._getSessionFromTokenStore(tokenStore), [tokenStore]);
@@ -461,16 +484,43 @@ var _StackClientAppImpl = class __StackClientAppImpl {
461
484
  }
462
485
  };
463
486
  }
464
- _userFromJson(json) {
487
+ _teamMemberFromJson(json) {
488
+ if (json === null)
489
+ return null;
490
+ return {
491
+ teamId: json.teamId,
492
+ userId: json.userId,
493
+ displayName: json.displayName
494
+ };
495
+ }
496
+ _createAuth(session) {
465
497
  const app = this;
466
- async function getConnection(id, options) {
467
- const scopeString = options?.scopes?.join(" ");
468
- return await app._currentUserOAuthConnectionCache.getOrWait([app._getSession(), id, scopeString || "", options?.or === "redirect"], "write-only");
469
- }
470
- function useConnection(id, options) {
471
- const scopeString = options?.scopes?.join(" ");
472
- return useAsyncCache(app._currentUserOAuthConnectionCache, [app._useSession(), id, scopeString || "", options?.or === "redirect"], "user.useConnection()");
473
- }
498
+ return {
499
+ _internalSession: session,
500
+ currentSession: {
501
+ async getTokens() {
502
+ const tokens = await session.getPotentiallyExpiredTokens();
503
+ return {
504
+ accessToken: tokens?.accessToken.token ?? null,
505
+ refreshToken: tokens?.refreshToken?.token ?? null
506
+ };
507
+ }
508
+ },
509
+ async getAuthHeaders() {
510
+ return {
511
+ "x-stack-auth": JSON.stringify(await this.getAuthJson())
512
+ };
513
+ },
514
+ async getAuthJson() {
515
+ const tokens = await this.currentSession.getTokens();
516
+ return tokens;
517
+ },
518
+ signOut() {
519
+ return app._signOut(session);
520
+ }
521
+ };
522
+ }
523
+ _createBaseUser(json) {
474
524
  return {
475
525
  projectId: json.projectId,
476
526
  id: json.id,
@@ -480,18 +530,52 @@ var _StackClientAppImpl = class __StackClientAppImpl {
480
530
  profileImageUrl: json.profileImageUrl,
481
531
  signedUpAt: new Date(json.signedUpAtMillis),
482
532
  clientMetadata: json.clientMetadata,
483
- authMethod: json.authMethod,
484
533
  hasPassword: json.hasPassword,
485
534
  authWithEmail: json.authWithEmail,
486
535
  oauthProviders: json.oauthProviders,
487
- getConnection,
488
- useConnection,
489
- async getSelectedTeam() {
490
- return await this.getTeam(json.selectedTeamId || "");
536
+ selectedTeam: json.selectedTeam && this._teamFromJson(json.selectedTeam),
537
+ toClientJson() {
538
+ return pick(json, [
539
+ "projectId",
540
+ "id",
541
+ "displayName",
542
+ "primaryEmail",
543
+ "primaryEmailVerified",
544
+ "profileImageUrl",
545
+ "signedUpAtMillis",
546
+ "clientMetadata",
547
+ "hasPassword",
548
+ "authMethod",
549
+ "authWithEmail",
550
+ "selectedTeamId",
551
+ "selectedTeam",
552
+ "oauthProviders"
553
+ ]);
554
+ }
555
+ };
556
+ }
557
+ _createUserExtra(json, session) {
558
+ const app = this;
559
+ async function getConnectedAccount(id, options) {
560
+ const scopeString = options?.scopes?.join(" ");
561
+ return await app._currentUserOAuthConnectionCache.getOrWait([session, id, scopeString || "", options?.or === "redirect"], "write-only");
562
+ }
563
+ function useConnectedAccount(id, options) {
564
+ const scopeString = options?.scopes?.join(" ");
565
+ return useAsyncCache(app._currentUserOAuthConnectionCache, [session, id, scopeString || "", options?.or === "redirect"], "user.useConnectedAccount()");
566
+ }
567
+ return {
568
+ setDisplayName(displayName) {
569
+ return this.update({ displayName });
570
+ },
571
+ setClientMetadata(metadata) {
572
+ return this.update({ clientMetadata: metadata });
491
573
  },
492
- useSelectedTeam() {
493
- return this.useTeam(json.selectedTeamId || "");
574
+ async setSelectedTeam(team) {
575
+ await this.update({ selectedTeamId: team?.id ?? null });
494
576
  },
577
+ getConnectedAccount,
578
+ useConnectedAccount,
495
579
  async getTeam(teamId) {
496
580
  const teams = await this.listTeams();
497
581
  return teams.find((t) => t.id === teamId) ?? null;
@@ -502,32 +586,20 @@ var _StackClientAppImpl = class __StackClientAppImpl {
502
586
  return teams.find((t) => t.id === teamId) ?? null;
503
587
  }, [teams, teamId]);
504
588
  },
505
- onTeamChange(teamId, callback) {
506
- return this.onTeamsChange((teams) => {
507
- const team = teams.find((t) => t.id === teamId) ?? null;
508
- callback(team);
509
- });
510
- },
511
589
  async listTeams() {
512
- const teams = await app._currentUserTeamsCache.getOrWait([app._getSession()], "write-only");
590
+ const teams = await app._currentUserTeamsCache.getOrWait([session], "write-only");
513
591
  return teams.map((json2) => app._teamFromJson(json2));
514
592
  },
515
593
  useTeams() {
516
- const session = app._useSession();
517
594
  const teams = useAsyncCache(app._currentUserTeamsCache, [session], "user.useTeams()");
518
595
  return useMemo(() => teams.map((json2) => app._teamFromJson(json2)), [teams]);
519
596
  },
520
- onTeamsChange(callback) {
521
- return app._currentUserTeamsCache.onChange([app._getSession()], (value, oldValue) => {
522
- callback(value.map((json2) => app._teamFromJson(json2)), oldValue?.map((json2) => app._teamFromJson(json2)));
523
- });
524
- },
525
597
  async listPermissions(scope, options) {
526
- const permissions = await app._currentUserPermissionsCache.getOrWait([app._getSession(), scope.id, "team", !!options?.direct], "write-only");
598
+ const permissions = await app._currentUserPermissionsCache.getOrWait([session, scope.id, "team", !!options?.direct], "write-only");
527
599
  return permissions.map((json2) => app._permissionFromJson(json2));
528
600
  },
529
601
  usePermissions(scope, options) {
530
- const permissions = useAsyncCache(app._currentUserPermissionsCache, [app._getSession(), scope.id, "team", !!options?.direct], "user.usePermissions()");
602
+ const permissions = useAsyncCache(app._currentUserPermissionsCache, [session, scope.id, "team", !!options?.direct], "user.usePermissions()");
531
603
  return useMemo(() => permissions.map((json2) => app._permissionFromJson(json2)), [permissions]);
532
604
  },
533
605
  usePermission(scope, permissionId) {
@@ -541,49 +613,6 @@ var _StackClientAppImpl = class __StackClientAppImpl {
541
613
  async hasPermission(scope, permissionId) {
542
614
  return await this.getPermission(scope, permissionId) !== null;
543
615
  },
544
- toJson() {
545
- return json;
546
- }
547
- };
548
- }
549
- _teamMemberFromJson(json) {
550
- if (json === null)
551
- return null;
552
- return {
553
- teamId: json.teamId,
554
- userId: json.userId,
555
- displayName: json.displayName
556
- };
557
- }
558
- _authFromJson(session) {
559
- const app = this;
560
- return {
561
- _internalSession: session,
562
- currentSession: {
563
- async getTokens() {
564
- const tokens = await session.getPotentiallyExpiredTokens();
565
- return {
566
- accessToken: tokens?.accessToken.token ?? null,
567
- refreshToken: tokens?.refreshToken?.token ?? null
568
- };
569
- }
570
- },
571
- async getAuthHeaders() {
572
- return {
573
- "x-stack-auth": JSON.stringify(await this.getAuthJson())
574
- };
575
- },
576
- async getAuthJson() {
577
- const tokens = await this.currentSession.getTokens();
578
- return tokens;
579
- },
580
- signOut() {
581
- return app._signOut(session);
582
- },
583
- // TODO these should not actually be on Auth, instead on User
584
- async updateSelectedTeam(team) {
585
- await app._updateUser({ selectedTeamId: team?.id ?? null }, session);
586
- },
587
616
  update(update) {
588
617
  return app._updateUser(update, session);
589
618
  },
@@ -595,36 +624,30 @@ var _StackClientAppImpl = class __StackClientAppImpl {
595
624
  }
596
625
  };
597
626
  }
598
- _currentUserFromJson(json, session) {
599
- if (json === null)
600
- return null;
627
+ _createInternalUserExtra(session) {
601
628
  const app = this;
629
+ this._ensureInternalProject();
630
+ return {
631
+ createProject(newProject) {
632
+ return app._createProject(session, newProject);
633
+ },
634
+ listOwnedProjects() {
635
+ return app._listOwnedProjects(session);
636
+ },
637
+ useOwnedProjects() {
638
+ return app._useOwnedProjects(session);
639
+ }
640
+ };
641
+ }
642
+ _createCurrentUser(json, session) {
602
643
  const currentUser = {
603
- ...this._userFromJson(json),
604
- ...this._authFromJson(session)
644
+ ...this._createBaseUser(json),
645
+ ...this._createAuth(session),
646
+ ...this._createUserExtra(json, session),
647
+ ...this._isInternalProject() ? this._createInternalUserExtra(session) : {}
605
648
  };
606
- if (this._isInternalProject()) {
607
- const internalUser = {
608
- ...currentUser,
609
- createProject(newProject) {
610
- return app._createProject(newProject);
611
- },
612
- listOwnedProjects() {
613
- return app._listOwnedProjects();
614
- },
615
- useOwnedProjects() {
616
- return app._useOwnedProjects();
617
- },
618
- onOwnedProjectsChange(callback) {
619
- return app._onOwnedProjectsChange(callback);
620
- }
621
- };
622
- Object.freeze(internalUser);
623
- return internalUser;
624
- } else {
625
- Object.freeze(currentUser);
626
- return currentUser;
627
- }
649
+ Object.freeze(currentUser);
650
+ return currentUser;
628
651
  }
629
652
  _projectAdminFromJson(data, adminInterface, onRefresh) {
630
653
  if (data.id !== adminInterface.projectId) {
@@ -760,12 +783,12 @@ var _StackClientAppImpl = class __StackClientAppImpl {
760
783
  }
761
784
  }
762
785
  }
763
- return this._currentUserFromJson(userJson, session);
786
+ return userJson && this._createCurrentUser(userJson, session);
764
787
  }
765
788
  useUser(options) {
766
789
  this._ensurePersistentTokenStore(options?.tokenStore);
767
790
  const router = NextNavigation.useRouter();
768
- const session = this._getSession(options?.tokenStore);
791
+ const session = this._useSession(options?.tokenStore);
769
792
  const userJson = useAsyncCache(this._currentUserCache, [session], "useUser()");
770
793
  const triggerRedirectToSignIn = useTrigger(() => router.replace(this.urls.signIn));
771
794
  if (userJson === null) {
@@ -784,16 +807,9 @@ var _StackClientAppImpl = class __StackClientAppImpl {
784
807
  }
785
808
  }
786
809
  return useMemo(() => {
787
- return this._currentUserFromJson(userJson, session);
810
+ return userJson && this._createCurrentUser(userJson, session);
788
811
  }, [userJson, session, options?.or]);
789
812
  }
790
- onUserChange(callback) {
791
- this._ensurePersistentTokenStore();
792
- const session = this._getSession();
793
- return this._currentUserCache.onChange([session], (userJson) => {
794
- callback(this._currentUserFromJson(userJson, session));
795
- });
796
- }
797
813
  async _updateUser(update, session) {
798
814
  const res = await this._interface.setClientUserCustomizableData(update, session);
799
815
  await this._refreshUser(session);
@@ -892,12 +908,8 @@ var _StackClientAppImpl = class __StackClientAppImpl {
892
908
  useProject() {
893
909
  return useAsyncCache(this._currentProjectCache, [], "useProject()");
894
910
  }
895
- onProjectChange(callback) {
896
- return this._currentProjectCache.onChange([], callback);
897
- }
898
- async _listOwnedProjects() {
911
+ async _listOwnedProjects(session) {
899
912
  this._ensureInternalProject();
900
- const session = this._getSession();
901
913
  const json = await this._ownedProjectsCache.getOrWait([session], "write-only");
902
914
  return json.map((j) => this._projectAdminFromJson(
903
915
  j,
@@ -905,9 +917,8 @@ var _StackClientAppImpl = class __StackClientAppImpl {
905
917
  () => this._refreshOwnedProjects(session)
906
918
  ));
907
919
  }
908
- _useOwnedProjects() {
920
+ _useOwnedProjects(session) {
909
921
  this._ensureInternalProject();
910
- const session = this._getSession();
911
922
  const json = useAsyncCache(this._ownedProjectsCache, [session], "useOwnedProjects()");
912
923
  return useMemo(() => json.map((j) => this._projectAdminFromJson(
913
924
  j,
@@ -915,20 +926,8 @@ var _StackClientAppImpl = class __StackClientAppImpl {
915
926
  () => this._refreshOwnedProjects(session)
916
927
  )), [json]);
917
928
  }
918
- _onOwnedProjectsChange(callback) {
929
+ async _createProject(session, newProject) {
919
930
  this._ensureInternalProject();
920
- const session = this._getSession();
921
- return this._ownedProjectsCache.onChange([session], (projects) => {
922
- callback(projects.map((j) => this._projectAdminFromJson(
923
- j,
924
- this._createAdminInterface(j.id, session),
925
- () => this._refreshOwnedProjects(session)
926
- )));
927
- });
928
- }
929
- async _createProject(newProject) {
930
- this._ensureInternalProject();
931
- const session = this._getSession();
932
931
  const json = await this._interface.createProject(newProject, session);
933
932
  const res = this._projectAdminFromJson(
934
933
  json,
@@ -1042,37 +1041,45 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1042
1041
  oauthScopesOnSignIn: options.oauthScopesOnSignIn ?? {}
1043
1042
  });
1044
1043
  }
1045
- _serverUserFromJson(json) {
1046
- if (json === null)
1047
- return null;
1044
+ _createBaseUser(json) {
1045
+ return {
1046
+ ...super._createBaseUser(json),
1047
+ ..."serverMetadata" in json ? {
1048
+ serverMetadata: json.serverMetadata,
1049
+ toServerJson() {
1050
+ return {
1051
+ ...this.toClientJson(),
1052
+ ...pick(json, [
1053
+ "serverMetadata"
1054
+ ])
1055
+ };
1056
+ }
1057
+ } : {}
1058
+ };
1059
+ }
1060
+ _createUserExtra(json) {
1048
1061
  const app = this;
1049
1062
  return {
1050
- ...this._userFromJson(json),
1051
- serverMetadata: json.serverMetadata,
1052
- async delete() {
1053
- const res = await app._interface.deleteServerUser(this.id);
1054
- await app._refreshUsers();
1055
- return res;
1063
+ async setDisplayName(displayName) {
1064
+ return await this.update({ displayName });
1056
1065
  },
1057
- async update(update) {
1058
- const res = await app._interface.setServerUserCustomizableData(this.id, update);
1059
- await app._refreshUsers();
1060
- return res;
1066
+ async setClientMetadata(metadata) {
1067
+ return await this.update({ clientMetadata: metadata });
1061
1068
  },
1062
- getClientUser() {
1063
- return app._userFromJson(json);
1069
+ async setServerMetadata(metadata) {
1070
+ return await this.update({ serverMetadata: metadata });
1064
1071
  },
1065
- async grantPermission(scope, permissionId) {
1066
- await app._interface.grantTeamUserPermission(scope.id, json.id, permissionId, "team");
1067
- for (const direct of [true, false]) {
1068
- await app._serverTeamUserPermissionsCache.refresh([scope.id, json.id, "team", direct]);
1069
- }
1072
+ async setSelectedTeam(team) {
1073
+ return await this.update({ selectedTeamId: team?.id ?? null });
1070
1074
  },
1071
- async revokePermission(scope, permissionId) {
1072
- await app._interface.revokeTeamUserPermission(scope.id, json.id, permissionId, "team");
1073
- for (const direct of [true, false]) {
1074
- await app._serverTeamUserPermissionsCache.refresh([scope.id, json.id, "team", direct]);
1075
- }
1075
+ async setPrimaryEmail(email, options) {
1076
+ return await this.update({ primaryEmail: email });
1077
+ },
1078
+ getConnectedAccount: async () => {
1079
+ return await app._checkFeatureSupport("getConnectedAccount() on ServerUser", {});
1080
+ },
1081
+ useConnectedAccount: () => {
1082
+ return app._useCheckFeatureSupport("useConnectedAccount() on ServerUser", {});
1076
1083
  },
1077
1084
  async getTeam(teamId) {
1078
1085
  const teams = await this.listTeams();
@@ -1084,24 +1091,13 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1084
1091
  return teams.find((t) => t.id === teamId) ?? null;
1085
1092
  }, [teams, teamId]);
1086
1093
  },
1087
- onTeamChange(teamId, callback) {
1088
- return this.onTeamsChange((teams) => {
1089
- const team = teams.find((t) => t.id === teamId) ?? null;
1090
- callback(team);
1091
- });
1092
- },
1093
1094
  async listTeams() {
1094
- const teams = await app._serverTeamsCache.getOrWait([app._getSession()], "write-only");
1095
- return teams.map((json2) => app._serverTeamFromJson(json2));
1095
+ const teams = await app.listTeams();
1096
+ const withMembers = await Promise.all(teams.map(async (t) => [t, await t.listMembers()]));
1097
+ return withMembers.filter(([_, members]) => members.find((m) => m.userId === json.id)).map(([t]) => t);
1096
1098
  },
1097
1099
  useTeams() {
1098
- const teams = useAsyncCache(app._serverTeamsCache, [app._getSession()], "user.useTeams()");
1099
- return useMemo(() => teams.map((json2) => app._serverTeamFromJson(json2)), [teams]);
1100
- },
1101
- onTeamsChange(callback) {
1102
- return app._serverTeamsCache.onChange([app._getSession()], (value, oldValue) => {
1103
- callback(value.map((json2) => app._serverTeamFromJson(json2)), oldValue?.map((json2) => app._serverTeamFromJson(json2)));
1104
- });
1100
+ return app._useCheckFeatureSupport("useTeams() on ServerUser", {});
1105
1101
  },
1106
1102
  async listPermissions(scope, options) {
1107
1103
  const permissions = await app._serverTeamUserPermissionsCache.getOrWait([scope.id, json.id, "team", !!options?.direct], "write-only");
@@ -1111,62 +1107,62 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1111
1107
  const permissions = useAsyncCache(app._serverTeamUserPermissionsCache, [scope.id, json.id, "team", !!options?.direct], "user.usePermissions()");
1112
1108
  return useMemo(() => permissions.map((json2) => app._serverPermissionFromJson(json2)), [permissions]);
1113
1109
  },
1114
- usePermission(scope, permissionId) {
1115
- const permissions = this.usePermissions(scope);
1116
- return useMemo(() => permissions.find((p) => p.id === permissionId) ?? null, [permissions, permissionId]);
1117
- },
1118
1110
  async getPermission(scope, permissionId) {
1119
1111
  const permissions = await this.listPermissions(scope);
1120
1112
  return permissions.find((p) => p.id === permissionId) ?? null;
1121
1113
  },
1114
+ usePermission(scope, permissionId) {
1115
+ const permissions = this.usePermissions(scope);
1116
+ return useMemo(() => permissions.find((p) => p.id === permissionId) ?? null, [permissions, permissionId]);
1117
+ },
1122
1118
  async hasPermission(scope, permissionId) {
1123
- const permissions = await this.listPermissions(scope);
1124
- return permissions.some((p) => p.id === permissionId);
1119
+ return await this.getPermission(scope, permissionId) !== null;
1125
1120
  },
1126
- toJson() {
1127
- return json;
1121
+ async grantPermission(scope, permissionId) {
1122
+ await app._interface.grantTeamUserPermission(scope.id, json.id, permissionId, "team");
1123
+ for (const direct of [true, false]) {
1124
+ await app._serverTeamUserPermissionsCache.refresh([scope.id, json.id, "team", direct]);
1125
+ }
1126
+ },
1127
+ async revokePermission(scope, permissionId) {
1128
+ await app._interface.revokeTeamUserPermission(scope.id, json.id, permissionId, "team");
1129
+ for (const direct of [true, false]) {
1130
+ await app._serverTeamUserPermissionsCache.refresh([scope.id, json.id, "team", direct]);
1131
+ }
1132
+ },
1133
+ async delete() {
1134
+ const res = await app._interface.deleteServerUser(json.id);
1135
+ await app._refreshUsers();
1136
+ return res;
1137
+ },
1138
+ async update(update) {
1139
+ const res = await app._interface.setServerUserCustomizableData(json.id, update);
1140
+ await app._refreshUsers();
1141
+ return res;
1142
+ },
1143
+ async sendVerificationEmail() {
1144
+ return await app._checkFeatureSupport("sendVerificationEmail() on ServerUser", {});
1145
+ },
1146
+ async updatePassword(options) {
1147
+ return await app._checkFeatureSupport("updatePassword() on ServerUser", {});
1128
1148
  }
1129
1149
  };
1130
1150
  }
1131
- _currentServerUserFromJson(json, session) {
1132
- if (json === null)
1133
- return null;
1151
+ _createUser(json) {
1152
+ return {
1153
+ ...this._createBaseUser(json),
1154
+ ...this._createUserExtra(json)
1155
+ };
1156
+ }
1157
+ _createCurrentUser(json, session) {
1134
1158
  const app = this;
1135
- const nonCurrentServerUser = this._serverUserFromJson(json);
1136
1159
  const currentUser = {
1137
- ...nonCurrentServerUser,
1138
- ...this._authFromJson(session),
1139
- async delete() {
1140
- const res = await nonCurrentServerUser.delete();
1141
- await app._refreshUser(session);
1142
- return res;
1143
- },
1144
- getClientUser() {
1145
- return app._currentUserFromJson(json, session);
1146
- }
1160
+ ...this._createUser(json),
1161
+ ...this._createAuth(session),
1162
+ ...this._isInternalProject() ? this._createInternalUserExtra(session) : {}
1147
1163
  };
1148
- if (this._isInternalProject()) {
1149
- const internalUser = {
1150
- ...currentUser,
1151
- createProject(newProject) {
1152
- return app._createProject(newProject);
1153
- },
1154
- listOwnedProjects() {
1155
- return app._listOwnedProjects();
1156
- },
1157
- useOwnedProjects() {
1158
- return app._useOwnedProjects();
1159
- },
1160
- onOwnedProjectsChange(callback) {
1161
- return app._onOwnedProjectsChange(callback);
1162
- }
1163
- };
1164
- Object.freeze(internalUser);
1165
- return internalUser;
1166
- } else {
1167
- Object.freeze(currentUser);
1168
- return currentUser;
1169
- }
1164
+ Object.freeze(currentUser);
1165
+ return currentUser;
1170
1166
  }
1171
1167
  _serverTeamMemberFromJson(json) {
1172
1168
  if (json === null)
@@ -1174,12 +1170,7 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1174
1170
  const app = this;
1175
1171
  return {
1176
1172
  ...app._teamMemberFromJson(json),
1177
- async getUser() {
1178
- const user = app._serverUserFromJson(await app._serverUserCache.getOrWait([json.userId], "write-only"));
1179
- if (!user)
1180
- throw new Error(`User ${json.userId} not found`);
1181
- return user;
1182
- }
1173
+ user: app._createUser(json.user)
1183
1174
  };
1184
1175
  }
1185
1176
  _serverTeamFromJson(json) {
@@ -1222,49 +1213,75 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1222
1213
  }
1223
1214
  };
1224
1215
  }
1225
- async getServerUser() {
1226
- this._ensurePersistentTokenStore();
1227
- const session = this._getSession();
1216
+ async getUser(options) {
1217
+ this._ensurePersistentTokenStore(options?.tokenStore);
1218
+ const session = this._getSession(options?.tokenStore);
1228
1219
  const userJson = await this._currentServerUserCache.getOrWait([session], "write-only");
1229
- return this._currentServerUserFromJson(userJson, session);
1220
+ if (userJson === null) {
1221
+ switch (options?.or) {
1222
+ case "redirect": {
1223
+ await this.redirectToSignIn();
1224
+ break;
1225
+ }
1226
+ case "throw": {
1227
+ throw new Error("User is not signed in but getUser was called with { or: 'throw' }");
1228
+ }
1229
+ default: {
1230
+ return null;
1231
+ }
1232
+ }
1233
+ }
1234
+ return userJson && this._createCurrentUser(userJson, session);
1235
+ }
1236
+ async getServerUser() {
1237
+ console.warn("stackServerApp.getServerUser is deprecated; use stackServerApp.getUser instead");
1238
+ return await this.getUser();
1230
1239
  }
1231
1240
  async getServerUserById(userId) {
1232
1241
  const json = await this._serverUserCache.getOrWait([userId], "write-only");
1233
- return this._serverUserFromJson(json);
1242
+ return json && this._createUser(json);
1234
1243
  }
1235
- useServerUser(options) {
1236
- this._ensurePersistentTokenStore();
1237
- const session = this._getSession();
1238
- const userJson = useAsyncCache(this._currentServerUserCache, [session], "useServerUser()");
1239
- return useMemo(() => {
1240
- if (options?.required && userJson === null) {
1241
- use(this.redirectToSignIn());
1244
+ useUser(options) {
1245
+ this._ensurePersistentTokenStore(options?.tokenStore);
1246
+ const router = NextNavigation.useRouter();
1247
+ const session = this._getSession(options?.tokenStore);
1248
+ const userJson = useAsyncCache(this._currentServerUserCache, [session], "useUser()");
1249
+ const triggerRedirectToSignIn = useTrigger(() => router.replace(this.urls.signIn));
1250
+ if (userJson === null) {
1251
+ switch (options?.or) {
1252
+ case "redirect": {
1253
+ triggerRedirectToSignIn();
1254
+ suspend();
1255
+ throw new StackAssertionError("suspend should never return");
1256
+ }
1257
+ case "throw": {
1258
+ throw new Error("User is not signed in but useUser was called with { or: 'throw' }");
1259
+ }
1260
+ case void 0:
1261
+ case "return-null": {
1262
+ }
1242
1263
  }
1243
- return this._currentServerUserFromJson(userJson, session);
1244
- }, [userJson, session, options?.required]);
1264
+ }
1265
+ return useMemo(() => {
1266
+ return userJson && this._createCurrentUser(userJson, session);
1267
+ }, [userJson, session, options?.or]);
1245
1268
  }
1246
- onServerUserChange(callback) {
1247
- this._ensurePersistentTokenStore();
1248
- const session = this._getSession();
1249
- return this._currentServerUserCache.onChange([session], (userJson) => {
1250
- callback(this._currentServerUserFromJson(userJson, session));
1251
- });
1269
+ useUserById(userId) {
1270
+ const json = useAsyncCache(this._serverUserCache, [userId], "useUserById()");
1271
+ return useMemo(() => {
1272
+ return json && this._createUser(json);
1273
+ }, [json]);
1252
1274
  }
1253
- async listServerUsers() {
1275
+ async listUsers() {
1254
1276
  const json = await this._serverUsersCache.getOrWait([], "write-only");
1255
- return json.map((j) => this._serverUserFromJson(j));
1277
+ return json.map((j) => this._createUser(j));
1256
1278
  }
1257
- useServerUsers() {
1279
+ useUsers() {
1258
1280
  const json = useAsyncCache(this._serverUsersCache, [], "useServerUsers()");
1259
1281
  return useMemo(() => {
1260
- return json.map((j) => this._serverUserFromJson(j));
1282
+ return json.map((j) => this._createUser(j));
1261
1283
  }, [json]);
1262
1284
  }
1263
- onServerUsersChange(callback) {
1264
- return this._serverUsersCache.onChange([], (users) => {
1265
- callback(users.map((j) => this._serverUserFromJson(j)));
1266
- });
1267
- }
1268
1285
  async listPermissionDefinitions() {
1269
1286
  return await this._serverTeamPermissionDefinitionsCache.getOrWait([], "write-only");
1270
1287
  }
@@ -1426,15 +1443,6 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1426
1443
  () => this._refreshProject()
1427
1444
  ), [json]);
1428
1445
  }
1429
- onProjectAdminChange(callback) {
1430
- return this._adminProjectCache.onChange([], (project) => {
1431
- callback(this._projectAdminFromJson(
1432
- project,
1433
- this._interface,
1434
- () => this._refreshProject()
1435
- ));
1436
- });
1437
- }
1438
1446
  async listApiKeySets() {
1439
1447
  const json = await this._apiKeySetsCache.getOrWait([], "write-only");
1440
1448
  return json.map((j) => this._createApiKeySetFromJson(j));
@@ -1445,11 +1453,6 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1445
1453
  return json.map((j) => this._createApiKeySetFromJson(j));
1446
1454
  }, [json]);
1447
1455
  }
1448
- onApiKeySetsChange(callback) {
1449
- return this._apiKeySetsCache.onChange([], (apiKeySets) => {
1450
- callback(apiKeySets.map((j) => this._createApiKeySetFromJson(j)));
1451
- });
1452
- }
1453
1456
  async createApiKeySet(options) {
1454
1457
  const json = await this._interface.createApiKeySet(options);
1455
1458
  await this._refreshApiKeySets();