@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
@@ -38,6 +38,7 @@ __export(stack_app_exports, {
38
38
  stackAppInternalsSymbol: () => stackAppInternalsSymbol
39
39
  });
40
40
  module.exports = __toCommonJS(stack_app_exports);
41
+ var import_browser = require("@simplewebauthn/browser");
41
42
  var import_stack_sc = require("@stackframe/stack-sc");
42
43
  var import_stack_shared = require("@stackframe/stack-shared");
43
44
  var import_production_mode = require("@stackframe/stack-shared/dist/helpers/production-mode");
@@ -63,7 +64,7 @@ var import_url = require("../utils/url");
63
64
  var import_auth = require("./auth");
64
65
  var import_cookie = require("./cookie");
65
66
  var NextNavigation = (0, import_compile_time.scrambleDuringCompileTime)(NextNavigationUnscrambled);
66
- var clientVersion = "js @stackframe/stack@2.6.11";
67
+ var clientVersion = "js @stackframe/stack@2.6.15";
67
68
  function getUrls(partial) {
68
69
  const handler = partial.handler ?? "/handler";
69
70
  const home = partial.home ?? "/";
@@ -101,10 +102,10 @@ async function _redirectTo(url, options) {
101
102
  }
102
103
  }
103
104
  function getDefaultProjectId() {
104
- return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || (0, import_errors.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."));
105
+ return process.env.NEXT_PUBLIC_STACK_PROJECT_ID || (0, import_errors.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."));
105
106
  }
106
107
  function getDefaultPublishableClientKey() {
107
- return process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || (0, import_errors.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."));
108
+ return process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY || (0, import_errors.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."));
108
109
  }
109
110
  function getDefaultSecretServerKey() {
110
111
  return process.env.STACK_SECRET_SERVER_KEY || (0, import_errors.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."));
@@ -226,6 +227,11 @@ var _StackClientAppImpl = class __StackClientAppImpl {
226
227
  return await this._interface.getTeamMemberProfile({ teamId, userId: "me" }, session);
227
228
  }
228
229
  );
230
+ this._clientContactChannelsCache = createCacheBySession(
231
+ async (session) => {
232
+ return await this._interface.listClientContactChannels(session);
233
+ }
234
+ );
229
235
  this._memoryTokenStore = createEmptyTokenStore();
230
236
  this._requestTokenStores = /* @__PURE__ */ new WeakMap();
231
237
  this._storedCookieTokenStore = null;
@@ -537,6 +543,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
537
543
  signUpEnabled: crud.config.sign_up_enabled,
538
544
  credentialEnabled: crud.config.credential_enabled,
539
545
  magicLinkEnabled: crud.config.magic_link_enabled,
546
+ passkeyEnabled: crud.config.passkey_enabled,
540
547
  clientTeamCreationEnabled: crud.config.client_team_creation_enabled,
541
548
  clientUserDeletionEnabled: crud.config.client_user_deletion_enabled,
542
549
  oauthProviders: crud.config.enabled_oauth_providers.map((p) => ({
@@ -568,7 +575,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
568
575
  clientMetadata: crud.client_metadata,
569
576
  clientReadOnlyMetadata: crud.client_read_only_metadata,
570
577
  async inviteUser(options) {
571
- return await app._interface.sendTeamInvitation({
578
+ await app._interface.sendTeamInvitation({
572
579
  teamId: crud.id,
573
580
  email: options.email,
574
581
  session: app._getSession(),
@@ -589,6 +596,28 @@ var _StackClientAppImpl = class __StackClientAppImpl {
589
596
  }
590
597
  };
591
598
  }
599
+ _clientContactChannelFromCrud(crud) {
600
+ const app = this;
601
+ return {
602
+ id: crud.id,
603
+ value: crud.value,
604
+ type: crud.type,
605
+ isVerified: crud.is_verified,
606
+ isPrimary: crud.is_primary,
607
+ usedForAuth: crud.used_for_auth,
608
+ async sendVerificationEmail() {
609
+ return await app._interface.sendCurrentUserContactChannelVerificationEmail(crud.id, (0, import_url.constructRedirectUrl)(app.urls.emailVerification), app._getSession());
610
+ },
611
+ async update(data) {
612
+ await app._interface.updateClientContactChannel(crud.id, contactChannelUpdateOptionsToCrud(data), app._getSession());
613
+ await app._clientContactChannelsCache.refresh([app._getSession()]);
614
+ },
615
+ async delete() {
616
+ await app._interface.deleteClientContactChannel(crud.id, app._getSession());
617
+ await app._clientContactChannelsCache.refresh([app._getSession()]);
618
+ }
619
+ };
620
+ }
592
621
  _createAuth(session) {
593
622
  const app = this;
594
623
  return {
@@ -611,6 +640,31 @@ var _StackClientAppImpl = class __StackClientAppImpl {
611
640
  const tokens = await this.currentSession.getTokens();
612
641
  return tokens;
613
642
  },
643
+ async registerPasskey() {
644
+ const initiationResult = await app._interface.initiatePasskeyRegistration({}, session);
645
+ if (initiationResult.status !== "ok") {
646
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to get initiation options for passkey registration"));
647
+ }
648
+ const { options_json, code } = initiationResult.data;
649
+ if (options_json.rp.id !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
650
+ throw new import_errors.StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rp.id}`);
651
+ }
652
+ options_json.rp.id = window.location.hostname;
653
+ let attResp;
654
+ try {
655
+ attResp = await (0, import_browser.startRegistration)({ optionsJSON: options_json });
656
+ debugger;
657
+ } catch (error) {
658
+ if (error instanceof import_browser.WebAuthnError) {
659
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyWebAuthnError(error.message, error.name));
660
+ } else {
661
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyRegistrationFailed("Failed to start passkey registration"));
662
+ }
663
+ }
664
+ const registrationResult = await app._interface.registerPasskey({ credential: attResp, code }, session);
665
+ await app._refreshUser(session);
666
+ return registrationResult;
667
+ },
614
668
  signOut() {
615
669
  return app._signOut(session);
616
670
  }
@@ -631,7 +685,9 @@ var _StackClientAppImpl = class __StackClientAppImpl {
631
685
  clientReadOnlyMetadata: crud.client_read_only_metadata,
632
686
  hasPassword: crud.has_password,
633
687
  emailAuthEnabled: crud.auth_with_email,
688
+ otpAuthEnabled: crud.otp_auth_enabled,
634
689
  oauthProviders: crud.oauth_providers,
690
+ passkeyAuthEnabled: crud.passkey_auth_enabled,
635
691
  selectedTeam: crud.selected_team && this._clientTeamFromCrud(crud.selected_team),
636
692
  isMultiFactorRequired: crud.requires_totp_mfa,
637
693
  toClientJson() {
@@ -739,7 +795,14 @@ var _StackClientAppImpl = class __StackClientAppImpl {
739
795
  return await app._sendVerificationEmail(crud.primary_email, session);
740
796
  },
741
797
  async updatePassword(options) {
742
- return await app._updatePassword(options, session);
798
+ const result = await app._interface.updatePassword(options, session);
799
+ await app._currentUserCache.refresh([session]);
800
+ return result;
801
+ },
802
+ async setPassword(options) {
803
+ const result = await app._interface.setPassword(options, session);
804
+ await app._currentUserCache.refresh([session]);
805
+ return result;
743
806
  },
744
807
  async getTeamProfile(team) {
745
808
  const result = await app._currentUserTeamProfileCache.getOrWait([session, team.id], "write-only");
@@ -752,6 +815,19 @@ var _StackClientAppImpl = class __StackClientAppImpl {
752
815
  async delete() {
753
816
  await app._interface.deleteCurrentUser(session);
754
817
  session.markInvalid();
818
+ },
819
+ async listContactChannels() {
820
+ const result = await app._clientContactChannelsCache.getOrWait([session], "write-only");
821
+ return result.map((crud2) => app._clientContactChannelFromCrud(crud2));
822
+ },
823
+ useContactChannels() {
824
+ const result = useAsyncCache(app._clientContactChannelsCache, [session], "user.useContactChannels()");
825
+ return result.map((crud2) => app._clientContactChannelFromCrud(crud2));
826
+ },
827
+ async createContactChannel(data) {
828
+ const crud2 = await app._interface.createClientContactChannel(contactChannelCreateOptionsToCrud("me", data), session);
829
+ await app._clientContactChannelsCache.refresh([session]);
830
+ return app._clientContactChannelFromCrud(crud2);
755
831
  }
756
832
  };
757
833
  }
@@ -934,7 +1010,10 @@ var _StackClientAppImpl = class __StackClientAppImpl {
934
1010
  }
935
1011
  }
936
1012
  async verifyEmail(code) {
937
- return await this._interface.verifyEmail(code);
1013
+ const result = await this._interface.verifyEmail(code);
1014
+ await this._currentUserCache.refresh([this._getSession()]);
1015
+ await this._clientContactChannelsCache.refresh([this._getSession()]);
1016
+ return result;
938
1017
  }
939
1018
  async getUser(options) {
940
1019
  this._ensurePersistentTokenStore(options?.tokenStore);
@@ -1095,6 +1174,38 @@ var _StackClientAppImpl = class __StackClientAppImpl {
1095
1174
  return import_results.Result.error(result.error);
1096
1175
  }
1097
1176
  }
1177
+ async signInWithPasskey() {
1178
+ this._ensurePersistentTokenStore();
1179
+ let result;
1180
+ try {
1181
+ result = await this._catchMfaRequiredError(async () => {
1182
+ const initiationResult = await this._interface.initiatePasskeyAuthentication({}, this._getSession());
1183
+ if (initiationResult.status !== "ok") {
1184
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyAuthenticationFailed("Failed to get initiation options for passkey authentication"));
1185
+ }
1186
+ const { options_json, code } = initiationResult.data;
1187
+ if (options_json.rpId !== "THIS_VALUE_WILL_BE_REPLACED.example.com") {
1188
+ throw new import_errors.StackAssertionError(`Expected returned RP ID from server to equal sentinel, but found ${options_json.rpId}`);
1189
+ }
1190
+ options_json.rpId = window.location.hostname;
1191
+ const authentication_response = await (0, import_browser.startAuthentication)({ optionsJSON: options_json });
1192
+ return await this._interface.signInWithPasskey({ authentication_response, code });
1193
+ });
1194
+ } catch (error) {
1195
+ if (error instanceof import_browser.WebAuthnError) {
1196
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyWebAuthnError(error.message, error.name));
1197
+ } else {
1198
+ return import_results.Result.error(new import_stack_shared.KnownErrors.PasskeyAuthenticationFailed("Failed to sign in with passkey"));
1199
+ }
1200
+ }
1201
+ if (result.status === "ok") {
1202
+ await this._signInToAccountWithTokens(result.data);
1203
+ await this.redirectToAfterSignIn({ replace: true });
1204
+ return import_results.Result.ok(void 0);
1205
+ } else {
1206
+ return import_results.Result.error(result.error);
1207
+ }
1208
+ }
1098
1209
  async callOAuthCallback() {
1099
1210
  this._ensurePersistentTokenStore();
1100
1211
  let result;
@@ -1131,9 +1242,6 @@ var _StackClientAppImpl = class __StackClientAppImpl {
1131
1242
  const emailVerificationRedirectUrl = (0, import_url.constructRedirectUrl)(this.urls.emailVerification);
1132
1243
  return await this._interface.sendVerificationEmail(email, emailVerificationRedirectUrl, session);
1133
1244
  }
1134
- async _updatePassword(options, session) {
1135
- return await this._interface.updatePassword(options, session);
1136
- }
1137
1245
  async signOut() {
1138
1246
  const user = await this.getUser();
1139
1247
  if (user) {
@@ -1303,6 +1411,11 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1303
1411
  return await this._interface.getServerTeamMemberProfile({ teamId, userId });
1304
1412
  }
1305
1413
  );
1414
+ this._serverContactChannelsCache = createCache(
1415
+ async ([userId]) => {
1416
+ return await this._interface.listServerContactChannels(userId);
1417
+ }
1418
+ );
1306
1419
  }
1307
1420
  async _updateServerUser(userId, update) {
1308
1421
  const result = await this._interface.updateServerUser(userId, serverUserUpdateOptionsToCrud(update));
@@ -1320,6 +1433,21 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1320
1433
  }
1321
1434
  };
1322
1435
  }
1436
+ _serverContactChannelFromCrud(userId, crud) {
1437
+ const app = this;
1438
+ return {
1439
+ ...this._clientContactChannelFromCrud(crud),
1440
+ async sendVerificationEmail() {
1441
+ return await app._interface.sendServerContactChannelVerificationEmail(userId, crud.id, (0, import_url.constructRedirectUrl)(app.urls.emailVerification));
1442
+ },
1443
+ async update(data) {
1444
+ await app._interface.updateServerContactChannel(userId, crud.id, serverContactChannelUpdateOptionsToCrud(data));
1445
+ },
1446
+ async delete() {
1447
+ await app._interface.deleteServerContactChannel(userId, crud.id);
1448
+ }
1449
+ };
1450
+ }
1323
1451
  _serverUserFromCrud(crud) {
1324
1452
  const app = this;
1325
1453
  async function getConnectedAccount(id, options) {
@@ -1436,7 +1564,14 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1436
1564
  return await app._checkFeatureSupport("sendVerificationEmail() on ServerUser", {});
1437
1565
  },
1438
1566
  async updatePassword(options) {
1439
- return await this.update({ password: options.newPassword });
1567
+ const result = await this.update({ password: options.newPassword });
1568
+ await app._serverUserCache.refresh([crud.id]);
1569
+ return result;
1570
+ },
1571
+ async setPassword(options) {
1572
+ const result = await this.update(options);
1573
+ await app._serverUserCache.refresh([crud.id]);
1574
+ return result;
1440
1575
  },
1441
1576
  async getTeamProfile(team) {
1442
1577
  const result = await app._serverUserTeamProfileCache.getOrWait([team.id, crud.id], "write-only");
@@ -1445,6 +1580,19 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1445
1580
  useTeamProfile(team) {
1446
1581
  const result = useAsyncCache(app._serverUserTeamProfileCache, [team.id, crud.id], "user.useTeamProfile()");
1447
1582
  return (0, import_react2.useMemo)(() => app._serverEditableTeamProfileFromCrud(result), [result]);
1583
+ },
1584
+ async listContactChannels() {
1585
+ const result = await app._serverContactChannelsCache.getOrWait([crud.id], "write-only");
1586
+ return result.map((data) => app._serverContactChannelFromCrud(crud.id, data));
1587
+ },
1588
+ useContactChannels() {
1589
+ const result = useAsyncCache(app._serverContactChannelsCache, [crud.id], "user.useContactChannels()");
1590
+ return (0, import_react2.useMemo)(() => result.map((data) => app._serverContactChannelFromCrud(crud.id, data)), [result]);
1591
+ },
1592
+ createContactChannel: async (data) => {
1593
+ const contactChannel = await app._interface.createServerContactChannel(serverContactChannelCreateOptionsToCrud(crud.id, data));
1594
+ await app._serverContactChannelsCache.refresh([crud.id]);
1595
+ return app._serverContactChannelFromCrud(crud.id, contactChannel);
1448
1596
  }
1449
1597
  };
1450
1598
  }
@@ -1508,7 +1656,7 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1508
1656
  await app._serverTeamMemberProfilesCache.refresh([crud.id]);
1509
1657
  },
1510
1658
  async inviteUser(options) {
1511
- return await app._interface.sendTeamInvitation({
1659
+ await app._interface.sendTeamInvitation({
1512
1660
  teamId: crud.id,
1513
1661
  email: options.email,
1514
1662
  session: null,
@@ -1712,6 +1860,7 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1712
1860
  signUpEnabled: data.config.sign_up_enabled,
1713
1861
  credentialEnabled: data.config.credential_enabled,
1714
1862
  magicLinkEnabled: data.config.magic_link_enabled,
1863
+ passkeyEnabled: data.config.passkey_enabled,
1715
1864
  legacyGlobalJwtSigning: data.config.legacy_global_jwt_signing,
1716
1865
  clientTeamCreationEnabled: data.config.client_team_creation_enabled,
1717
1866
  clientUserDeletionEnabled: data.config.client_user_deletion_enabled,
@@ -1893,13 +2042,46 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1893
2042
  await this._apiKeysCache.refresh([]);
1894
2043
  }
1895
2044
  };
2045
+ function contactChannelCreateOptionsToCrud(userId, options) {
2046
+ return {
2047
+ value: options.value,
2048
+ type: options.type,
2049
+ used_for_auth: options.usedForAuth,
2050
+ user_id: userId
2051
+ };
2052
+ }
2053
+ function contactChannelUpdateOptionsToCrud(options) {
2054
+ return {
2055
+ value: options.value,
2056
+ used_for_auth: options.usedForAuth,
2057
+ is_primary: options.isPrimary
2058
+ };
2059
+ }
2060
+ function serverContactChannelUpdateOptionsToCrud(options) {
2061
+ return {
2062
+ value: options.value,
2063
+ is_verified: options.isVerified,
2064
+ used_for_auth: options.usedForAuth
2065
+ };
2066
+ }
2067
+ function serverContactChannelCreateOptionsToCrud(userId, options) {
2068
+ return {
2069
+ type: options.type,
2070
+ value: options.value,
2071
+ is_verified: options.isVerified,
2072
+ user_id: userId,
2073
+ used_for_auth: options.usedForAuth
2074
+ };
2075
+ }
1896
2076
  function userUpdateOptionsToCrud(options) {
1897
2077
  return {
1898
2078
  display_name: options.displayName,
1899
2079
  client_metadata: options.clientMetadata,
1900
2080
  selected_team_id: options.selectedTeamId,
1901
2081
  totp_secret_base64: options.totpMultiFactorSecret != null ? (0, import_bytes.encodeBase64)(options.totpMultiFactorSecret) : options.totpMultiFactorSecret,
1902
- profile_image_url: options.profileImageUrl
2082
+ profile_image_url: options.profileImageUrl,
2083
+ otp_auth_enabled: options.otpAuthEnabled,
2084
+ passkey_auth_enabled: options.passkeyAuthEnabled
1903
2085
  };
1904
2086
  }
1905
2087
  function serverUserUpdateOptionsToCrud(options) {
@@ -1921,7 +2103,8 @@ function serverUserCreateOptionsToCrud(options) {
1921
2103
  return {
1922
2104
  primary_email: options.primaryEmail,
1923
2105
  password: options.password,
1924
- primary_email_auth_enabled: true,
2106
+ otp_auth_enabled: options.otpAuthEnabled,
2107
+ primary_email_auth_enabled: options.primaryEmailAuthEnabled,
1925
2108
  display_name: options.displayName,
1926
2109
  primary_email_verified: options.primaryEmailVerified
1927
2110
  };
@@ -1961,6 +2144,7 @@ function adminProjectUpdateOptionsToCrud(options) {
1961
2144
  sign_up_enabled: options.config?.signUpEnabled,
1962
2145
  credential_enabled: options.config?.credentialEnabled,
1963
2146
  magic_link_enabled: options.config?.magicLinkEnabled,
2147
+ passkey_enabled: options.config?.passkeyEnabled,
1964
2148
  allow_localhost: options.config?.allowLocalhost,
1965
2149
  create_team_on_sign_up: options.config?.createTeamOnSignUp,
1966
2150
  client_team_creation_enabled: options.config?.clientTeamCreationEnabled,