@stackframe/stack 2.6.11 → 2.6.15

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 (36) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/components/passkey-button.d.mts +7 -0
  3. package/dist/components/passkey-button.d.ts +7 -0
  4. package/dist/components/passkey-button.js +58 -0
  5. package/dist/components/passkey-button.js.map +1 -0
  6. package/dist/components-page/account-settings.js +343 -102
  7. package/dist/components-page/account-settings.js.map +1 -1
  8. package/dist/components-page/auth-page.d.mts +1 -0
  9. package/dist/components-page/auth-page.d.ts +1 -0
  10. package/dist/components-page/auth-page.js +5 -1
  11. package/dist/components-page/auth-page.js.map +1 -1
  12. package/dist/esm/components/passkey-button.js +34 -0
  13. package/dist/esm/components/passkey-button.js.map +1 -0
  14. package/dist/esm/components-page/account-settings.js +344 -103
  15. package/dist/esm/components-page/account-settings.js.map +1 -1
  16. package/dist/esm/components-page/auth-page.js +5 -1
  17. package/dist/esm/components-page/auth-page.js.map +1 -1
  18. package/dist/esm/generated/global-css.js +1 -1
  19. package/dist/esm/generated/global-css.js.map +1 -1
  20. package/dist/esm/generated/quetzal-translations.js +2268 -1824
  21. package/dist/esm/generated/quetzal-translations.js.map +1 -1
  22. package/dist/esm/lib/stack-app.js +197 -13
  23. package/dist/esm/lib/stack-app.js.map +1 -1
  24. package/dist/generated/global-css.d.mts +1 -1
  25. package/dist/generated/global-css.d.ts +1 -1
  26. package/dist/generated/global-css.js +1 -1
  27. package/dist/generated/global-css.js.map +1 -1
  28. package/dist/generated/quetzal-translations.d.mts +2 -2
  29. package/dist/generated/quetzal-translations.d.ts +2 -2
  30. package/dist/generated/quetzal-translations.js +2268 -1824
  31. package/dist/generated/quetzal-translations.js.map +1 -1
  32. package/dist/lib/stack-app.d.mts +60 -19
  33. package/dist/lib/stack-app.d.ts +60 -19
  34. package/dist/lib/stack-app.js +197 -13
  35. package/dist/lib/stack-app.js.map +1 -1
  36. package/package.json +5 -4
@@ -1,4 +1,5 @@
1
1
  // src/lib/stack-app.ts
2
+ import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
2
3
  import { isReactServer } from "@stackframe/stack-sc";
3
4
  import { KnownErrors, StackAdminInterface, StackClientInterface, StackServerInterface } from "@stackframe/stack-shared";
4
5
  import { getProductionModeErrors } from "@stackframe/stack-shared/dist/helpers/production-mode";
@@ -24,7 +25,7 @@ import { constructRedirectUrl } from "../utils/url";
24
25
  import { addNewOAuthProviderOrScope, callOAuthCallback, signInWithOAuth } from "./auth";
25
26
  import { deleteCookie, getCookie, setOrDeleteCookie } from "./cookie";
26
27
  var NextNavigation = scrambleDuringCompileTime(NextNavigationUnscrambled);
27
- var clientVersion = "js @stackframe/stack@2.6.11";
28
+ var clientVersion = "js @stackframe/stack@2.6.15";
28
29
  function getUrls(partial) {
29
30
  const handler = partial.handler ?? "/handler";
30
31
  const home = partial.home ?? "/";
@@ -62,10 +63,10 @@ async function _redirectTo(url, options) {
62
63
  }
63
64
  }
64
65
  function getDefaultProjectId() {
65
- return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || throwErr(new Error("Welcome to Stack! It seems that you haven't provided a project ID. Please create a project on the Stack dashboard at https://app.stack-auth.com and put it in the NEXT_PUBLIC_STACK_PROJECT_ID environment variable."));
66
+ return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || throwErr(new Error("Welcome to Stack Auth! It seems that you haven't provided a project ID. Please create a project on the Stack dashboard at https://app.stack-auth.com and put it in the NEXT_PUBLIC_STACK_PROJECT_ID environment variable."));
66
67
  }
67
68
  function getDefaultPublishableClientKey() {
68
- return process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || throwErr(new Error("Welcome to Stack! It seems that you haven't provided a publishable client key. Please create an API key for your project on the Stack dashboard at https://app.stack-auth.com and copy your publishable client key into the NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY environment variable."));
69
+ return process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || throwErr(new Error("Welcome to Stack Auth! It seems that you haven't provided a publishable client key. Please create an API key for your project on the Stack dashboard at https://app.stack-auth.com and copy your publishable client key into the NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY environment variable."));
69
70
  }
70
71
  function getDefaultSecretServerKey() {
71
72
  return process.env.STACK_SECRET_SERVER_KEY || throwErr(new Error("No secret server key provided. Please copy your key from the Stack dashboard and put your it in the STACK_SECRET_SERVER_KEY environment variable."));
@@ -187,6 +188,11 @@ var _StackClientAppImpl = class __StackClientAppImpl {
187
188
  return await this._interface.getTeamMemberProfile({ teamId, userId: "me" }, session);
188
189
  }
189
190
  );
191
+ this._clientContactChannelsCache = createCacheBySession(
192
+ async (session) => {
193
+ return await this._interface.listClientContactChannels(session);
194
+ }
195
+ );
190
196
  this._memoryTokenStore = createEmptyTokenStore();
191
197
  this._requestTokenStores = /* @__PURE__ */ new WeakMap();
192
198
  this._storedCookieTokenStore = null;
@@ -498,6 +504,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
498
504
  signUpEnabled: crud.config.sign_up_enabled,
499
505
  credentialEnabled: crud.config.credential_enabled,
500
506
  magicLinkEnabled: crud.config.magic_link_enabled,
507
+ passkeyEnabled: crud.config.passkey_enabled,
501
508
  clientTeamCreationEnabled: crud.config.client_team_creation_enabled,
502
509
  clientUserDeletionEnabled: crud.config.client_user_deletion_enabled,
503
510
  oauthProviders: crud.config.enabled_oauth_providers.map((p) => ({
@@ -529,7 +536,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
529
536
  clientMetadata: crud.client_metadata,
530
537
  clientReadOnlyMetadata: crud.client_read_only_metadata,
531
538
  async inviteUser(options) {
532
- return await app._interface.sendTeamInvitation({
539
+ await app._interface.sendTeamInvitation({
533
540
  teamId: crud.id,
534
541
  email: options.email,
535
542
  session: app._getSession(),
@@ -550,6 +557,28 @@ var _StackClientAppImpl = class __StackClientAppImpl {
550
557
  }
551
558
  };
552
559
  }
560
+ _clientContactChannelFromCrud(crud) {
561
+ const app = this;
562
+ return {
563
+ id: crud.id,
564
+ value: crud.value,
565
+ type: crud.type,
566
+ isVerified: crud.is_verified,
567
+ isPrimary: crud.is_primary,
568
+ usedForAuth: crud.used_for_auth,
569
+ async sendVerificationEmail() {
570
+ return await app._interface.sendCurrentUserContactChannelVerificationEmail(crud.id, constructRedirectUrl(app.urls.emailVerification), app._getSession());
571
+ },
572
+ async update(data) {
573
+ await app._interface.updateClientContactChannel(crud.id, contactChannelUpdateOptionsToCrud(data), app._getSession());
574
+ await app._clientContactChannelsCache.refresh([app._getSession()]);
575
+ },
576
+ async delete() {
577
+ await app._interface.deleteClientContactChannel(crud.id, app._getSession());
578
+ await app._clientContactChannelsCache.refresh([app._getSession()]);
579
+ }
580
+ };
581
+ }
553
582
  _createAuth(session) {
554
583
  const app = this;
555
584
  return {
@@ -572,6 +601,31 @@ var _StackClientAppImpl = class __StackClientAppImpl {
572
601
  const tokens = await this.currentSession.getTokens();
573
602
  return tokens;
574
603
  },
604
+ async registerPasskey() {
605
+ const initiationResult = await app._interface.initiatePasskeyRegistration({}, session);
606
+ if (initiationResult.status !== "ok") {
607
+ return Result.error(new KnownErrors.PasskeyRegistrationFailed("Failed to get initiation options for passkey registration"));
608
+ }
609
+ const { options_json, code } = initiationResult.data;
610
+ if (options_json.rp.id !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
611
+ throw new StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rp.id}`);
612
+ }
613
+ options_json.rp.id = window.location.hostname;
614
+ let attResp;
615
+ try {
616
+ attResp = await startRegistration({ optionsJSON: options_json });
617
+ debugger;
618
+ } catch (error) {
619
+ if (error instanceof WebAuthnError) {
620
+ return Result.error(new KnownErrors.PasskeyWebAuthnError(error.message, error.name));
621
+ } else {
622
+ return Result.error(new KnownErrors.PasskeyRegistrationFailed("Failed to start passkey registration"));
623
+ }
624
+ }
625
+ const registrationResult = await app._interface.registerPasskey({ credential: attResp, code }, session);
626
+ await app._refreshUser(session);
627
+ return registrationResult;
628
+ },
575
629
  signOut() {
576
630
  return app._signOut(session);
577
631
  }
@@ -592,7 +646,9 @@ var _StackClientAppImpl = class __StackClientAppImpl {
592
646
  clientReadOnlyMetadata: crud.client_read_only_metadata,
593
647
  hasPassword: crud.has_password,
594
648
  emailAuthEnabled: crud.auth_with_email,
649
+ otpAuthEnabled: crud.otp_auth_enabled,
595
650
  oauthProviders: crud.oauth_providers,
651
+ passkeyAuthEnabled: crud.passkey_auth_enabled,
596
652
  selectedTeam: crud.selected_team && this._clientTeamFromCrud(crud.selected_team),
597
653
  isMultiFactorRequired: crud.requires_totp_mfa,
598
654
  toClientJson() {
@@ -700,7 +756,14 @@ var _StackClientAppImpl = class __StackClientAppImpl {
700
756
  return await app._sendVerificationEmail(crud.primary_email, session);
701
757
  },
702
758
  async updatePassword(options) {
703
- return await app._updatePassword(options, session);
759
+ const result = await app._interface.updatePassword(options, session);
760
+ await app._currentUserCache.refresh([session]);
761
+ return result;
762
+ },
763
+ async setPassword(options) {
764
+ const result = await app._interface.setPassword(options, session);
765
+ await app._currentUserCache.refresh([session]);
766
+ return result;
704
767
  },
705
768
  async getTeamProfile(team) {
706
769
  const result = await app._currentUserTeamProfileCache.getOrWait([session, team.id], "write-only");
@@ -713,6 +776,19 @@ var _StackClientAppImpl = class __StackClientAppImpl {
713
776
  async delete() {
714
777
  await app._interface.deleteCurrentUser(session);
715
778
  session.markInvalid();
779
+ },
780
+ async listContactChannels() {
781
+ const result = await app._clientContactChannelsCache.getOrWait([session], "write-only");
782
+ return result.map((crud2) => app._clientContactChannelFromCrud(crud2));
783
+ },
784
+ useContactChannels() {
785
+ const result = useAsyncCache(app._clientContactChannelsCache, [session], "user.useContactChannels()");
786
+ return result.map((crud2) => app._clientContactChannelFromCrud(crud2));
787
+ },
788
+ async createContactChannel(data) {
789
+ const crud2 = await app._interface.createClientContactChannel(contactChannelCreateOptionsToCrud("me", data), session);
790
+ await app._clientContactChannelsCache.refresh([session]);
791
+ return app._clientContactChannelFromCrud(crud2);
716
792
  }
717
793
  };
718
794
  }
@@ -895,7 +971,10 @@ var _StackClientAppImpl = class __StackClientAppImpl {
895
971
  }
896
972
  }
897
973
  async verifyEmail(code) {
898
- return await this._interface.verifyEmail(code);
974
+ const result = await this._interface.verifyEmail(code);
975
+ await this._currentUserCache.refresh([this._getSession()]);
976
+ await this._clientContactChannelsCache.refresh([this._getSession()]);
977
+ return result;
899
978
  }
900
979
  async getUser(options) {
901
980
  this._ensurePersistentTokenStore(options?.tokenStore);
@@ -1056,6 +1135,38 @@ var _StackClientAppImpl = class __StackClientAppImpl {
1056
1135
  return Result.error(result.error);
1057
1136
  }
1058
1137
  }
1138
+ async signInWithPasskey() {
1139
+ this._ensurePersistentTokenStore();
1140
+ let result;
1141
+ try {
1142
+ result = await this._catchMfaRequiredError(async () => {
1143
+ const initiationResult = await this._interface.initiatePasskeyAuthentication({}, this._getSession());
1144
+ if (initiationResult.status !== "ok") {
1145
+ return Result.error(new KnownErrors.PasskeyAuthenticationFailed("Failed to get initiation options for passkey authentication"));
1146
+ }
1147
+ const { options_json, code } = initiationResult.data;
1148
+ if (options_json.rpId !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
1149
+ throw new StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rpId}`);
1150
+ }
1151
+ options_json.rpId = window.location.hostname;
1152
+ const authentication_response = await startAuthentication({ optionsJSON: options_json });
1153
+ return await this._interface.signInWithPasskey({ authentication_response, code });
1154
+ });
1155
+ } catch (error) {
1156
+ if (error instanceof WebAuthnError) {
1157
+ return Result.error(new KnownErrors.PasskeyWebAuthnError(error.message, error.name));
1158
+ } else {
1159
+ return Result.error(new KnownErrors.PasskeyAuthenticationFailed("Failed to sign in with passkey"));
1160
+ }
1161
+ }
1162
+ if (result.status === "ok") {
1163
+ await this._signInToAccountWithTokens(result.data);
1164
+ await this.redirectToAfterSignIn({ replace: true });
1165
+ return Result.ok(void 0);
1166
+ } else {
1167
+ return Result.error(result.error);
1168
+ }
1169
+ }
1059
1170
  async callOAuthCallback() {
1060
1171
  this._ensurePersistentTokenStore();
1061
1172
  let result;
@@ -1092,9 +1203,6 @@ var _StackClientAppImpl = class __StackClientAppImpl {
1092
1203
  const emailVerificationRedirectUrl = constructRedirectUrl(this.urls.emailVerification);
1093
1204
  return await this._interface.sendVerificationEmail(email, emailVerificationRedirectUrl, session);
1094
1205
  }
1095
- async _updatePassword(options, session) {
1096
- return await this._interface.updatePassword(options, session);
1097
- }
1098
1206
  async signOut() {
1099
1207
  const user = await this.getUser();
1100
1208
  if (user) {
@@ -1264,6 +1372,11 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1264
1372
  return await this._interface.getServerTeamMemberProfile({ teamId, userId });
1265
1373
  }
1266
1374
  );
1375
+ this._serverContactChannelsCache = createCache(
1376
+ async ([userId]) => {
1377
+ return await this._interface.listServerContactChannels(userId);
1378
+ }
1379
+ );
1267
1380
  }
1268
1381
  async _updateServerUser(userId, update) {
1269
1382
  const result = await this._interface.updateServerUser(userId, serverUserUpdateOptionsToCrud(update));
@@ -1281,6 +1394,21 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1281
1394
  }
1282
1395
  };
1283
1396
  }
1397
+ _serverContactChannelFromCrud(userId, crud) {
1398
+ const app = this;
1399
+ return {
1400
+ ...this._clientContactChannelFromCrud(crud),
1401
+ async sendVerificationEmail() {
1402
+ return await app._interface.sendServerContactChannelVerificationEmail(userId, crud.id, constructRedirectUrl(app.urls.emailVerification));
1403
+ },
1404
+ async update(data) {
1405
+ await app._interface.updateServerContactChannel(userId, crud.id, serverContactChannelUpdateOptionsToCrud(data));
1406
+ },
1407
+ async delete() {
1408
+ await app._interface.deleteServerContactChannel(userId, crud.id);
1409
+ }
1410
+ };
1411
+ }
1284
1412
  _serverUserFromCrud(crud) {
1285
1413
  const app = this;
1286
1414
  async function getConnectedAccount(id, options) {
@@ -1397,7 +1525,14 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1397
1525
  return await app._checkFeatureSupport("sendVerificationEmail() on ServerUser", {});
1398
1526
  },
1399
1527
  async updatePassword(options) {
1400
- return await this.update({ password: options.newPassword });
1528
+ const result = await this.update({ password: options.newPassword });
1529
+ await app._serverUserCache.refresh([crud.id]);
1530
+ return result;
1531
+ },
1532
+ async setPassword(options) {
1533
+ const result = await this.update(options);
1534
+ await app._serverUserCache.refresh([crud.id]);
1535
+ return result;
1401
1536
  },
1402
1537
  async getTeamProfile(team) {
1403
1538
  const result = await app._serverUserTeamProfileCache.getOrWait([team.id, crud.id], "write-only");
@@ -1406,6 +1541,19 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1406
1541
  useTeamProfile(team) {
1407
1542
  const result = useAsyncCache(app._serverUserTeamProfileCache, [team.id, crud.id], "user.useTeamProfile()");
1408
1543
  return useMemo(() => app._serverEditableTeamProfileFromCrud(result), [result]);
1544
+ },
1545
+ async listContactChannels() {
1546
+ const result = await app._serverContactChannelsCache.getOrWait([crud.id], "write-only");
1547
+ return result.map((data) => app._serverContactChannelFromCrud(crud.id, data));
1548
+ },
1549
+ useContactChannels() {
1550
+ const result = useAsyncCache(app._serverContactChannelsCache, [crud.id], "user.useContactChannels()");
1551
+ return useMemo(() => result.map((data) => app._serverContactChannelFromCrud(crud.id, data)), [result]);
1552
+ },
1553
+ createContactChannel: async (data) => {
1554
+ const contactChannel = await app._interface.createServerContactChannel(serverContactChannelCreateOptionsToCrud(crud.id, data));
1555
+ await app._serverContactChannelsCache.refresh([crud.id]);
1556
+ return app._serverContactChannelFromCrud(crud.id, contactChannel);
1409
1557
  }
1410
1558
  };
1411
1559
  }
@@ -1469,7 +1617,7 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1469
1617
  await app._serverTeamMemberProfilesCache.refresh([crud.id]);
1470
1618
  },
1471
1619
  async inviteUser(options) {
1472
- return await app._interface.sendTeamInvitation({
1620
+ await app._interface.sendTeamInvitation({
1473
1621
  teamId: crud.id,
1474
1622
  email: options.email,
1475
1623
  session: null,
@@ -1673,6 +1821,7 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1673
1821
  signUpEnabled: data.config.sign_up_enabled,
1674
1822
  credentialEnabled: data.config.credential_enabled,
1675
1823
  magicLinkEnabled: data.config.magic_link_enabled,
1824
+ passkeyEnabled: data.config.passkey_enabled,
1676
1825
  legacyGlobalJwtSigning: data.config.legacy_global_jwt_signing,
1677
1826
  clientTeamCreationEnabled: data.config.client_team_creation_enabled,
1678
1827
  clientUserDeletionEnabled: data.config.client_user_deletion_enabled,
@@ -1854,13 +2003,46 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1854
2003
  await this._apiKeysCache.refresh([]);
1855
2004
  }
1856
2005
  };
2006
+ function contactChannelCreateOptionsToCrud(userId, options) {
2007
+ return {
2008
+ value: options.value,
2009
+ type: options.type,
2010
+ used_for_auth: options.usedForAuth,
2011
+ user_id: userId
2012
+ };
2013
+ }
2014
+ function contactChannelUpdateOptionsToCrud(options) {
2015
+ return {
2016
+ value: options.value,
2017
+ used_for_auth: options.usedForAuth,
2018
+ is_primary: options.isPrimary
2019
+ };
2020
+ }
2021
+ function serverContactChannelUpdateOptionsToCrud(options) {
2022
+ return {
2023
+ value: options.value,
2024
+ is_verified: options.isVerified,
2025
+ used_for_auth: options.usedForAuth
2026
+ };
2027
+ }
2028
+ function serverContactChannelCreateOptionsToCrud(userId, options) {
2029
+ return {
2030
+ type: options.type,
2031
+ value: options.value,
2032
+ is_verified: options.isVerified,
2033
+ user_id: userId,
2034
+ used_for_auth: options.usedForAuth
2035
+ };
2036
+ }
1857
2037
  function userUpdateOptionsToCrud(options) {
1858
2038
  return {
1859
2039
  display_name: options.displayName,
1860
2040
  client_metadata: options.clientMetadata,
1861
2041
  selected_team_id: options.selectedTeamId,
1862
2042
  totp_secret_base64: options.totpMultiFactorSecret != null ? encodeBase64(options.totpMultiFactorSecret) : options.totpMultiFactorSecret,
1863
- profile_image_url: options.profileImageUrl
2043
+ profile_image_url: options.profileImageUrl,
2044
+ otp_auth_enabled: options.otpAuthEnabled,
2045
+ passkey_auth_enabled: options.passkeyAuthEnabled
1864
2046
  };
1865
2047
  }
1866
2048
  function serverUserUpdateOptionsToCrud(options) {
@@ -1882,7 +2064,8 @@ function serverUserCreateOptionsToCrud(options) {
1882
2064
  return {
1883
2065
  primary_email: options.primaryEmail,
1884
2066
  password: options.password,
1885
- primary_email_auth_enabled: true,
2067
+ otp_auth_enabled: options.otpAuthEnabled,
2068
+ primary_email_auth_enabled: options.primaryEmailAuthEnabled,
1886
2069
  display_name: options.displayName,
1887
2070
  primary_email_verified: options.primaryEmailVerified
1888
2071
  };
@@ -1922,6 +2105,7 @@ function adminProjectUpdateOptionsToCrud(options) {
1922
2105
  sign_up_enabled: options.config?.signUpEnabled,
1923
2106
  credential_enabled: options.config?.credentialEnabled,
1924
2107
  magic_link_enabled: options.config?.magicLinkEnabled,
2108
+ passkey_enabled: options.config?.passkeyEnabled,
1925
2109
  allow_localhost: options.config?.allowLocalhost,
1926
2110
  create_team_on_sign_up: options.config?.createTeamOnSignUp,
1927
2111
  client_team_creation_enabled: options.config?.clientTeamCreationEnabled,