@stackframe/stack 2.6.12 → 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 (30) hide show
  1. package/CHANGELOG.md +28 -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 +58 -1
  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 +58 -1
  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/quetzal-translations.js +2244 -2124
  19. package/dist/esm/generated/quetzal-translations.js.map +1 -1
  20. package/dist/esm/lib/stack-app.js +67 -4
  21. package/dist/esm/lib/stack-app.js.map +1 -1
  22. package/dist/generated/quetzal-translations.d.mts +2 -2
  23. package/dist/generated/quetzal-translations.d.ts +2 -2
  24. package/dist/generated/quetzal-translations.js +2244 -2124
  25. package/dist/generated/quetzal-translations.js.map +1 -1
  26. package/dist/lib/stack-app.d.mts +9 -2
  27. package/dist/lib/stack-app.d.ts +9 -2
  28. package/dist/lib/stack-app.js +67 -4
  29. package/dist/lib/stack-app.js.map +1 -1
  30. package/package.json +5 -4
@@ -176,6 +176,7 @@ type Auth = {
176
176
  accessToken: string | null;
177
177
  refreshToken: string | null;
178
178
  }>;
179
+ registerPasskey(): Promise<Result<undefined, KnownErrors["PasskeyRegistrationFailed"] | KnownErrors["PasskeyWebAuthnError"]>>;
179
180
  };
180
181
  /**
181
182
  * ```
@@ -218,6 +219,7 @@ type BaseUser = {
218
219
  */
219
220
  readonly hasPassword: boolean;
220
221
  readonly otpAuthEnabled: boolean;
222
+ readonly passkeyAuthEnabled: boolean;
221
223
  readonly isMultiFactorRequired: boolean;
222
224
  /**
223
225
  * A shorthand method to update multiple fields of the user at once.
@@ -297,6 +299,7 @@ type UserUpdateOptions = {
297
299
  totpMultiFactorSecret?: Uint8Array | null;
298
300
  profileImageUrl?: string | null;
299
301
  otpAuthEnabled?: boolean;
302
+ passkeyAuthEnabled?: boolean;
300
303
  };
301
304
  type ServerBaseUser = {
302
305
  setPrimaryEmail(email: string, options?: {
@@ -380,6 +383,7 @@ type ProjectConfig = {
380
383
  readonly signUpEnabled: boolean;
381
384
  readonly credentialEnabled: boolean;
382
385
  readonly magicLinkEnabled: boolean;
386
+ readonly passkeyEnabled: boolean;
383
387
  readonly clientTeamCreationEnabled: boolean;
384
388
  readonly clientUserDeletionEnabled: boolean;
385
389
  readonly oauthProviders: OAuthProviderConfig[];
@@ -392,6 +396,7 @@ type AdminProjectConfig = {
392
396
  readonly signUpEnabled: boolean;
393
397
  readonly credentialEnabled: boolean;
394
398
  readonly magicLinkEnabled: boolean;
399
+ readonly passkeyEnabled: boolean;
395
400
  readonly clientTeamCreationEnabled: boolean;
396
401
  readonly clientUserDeletionEnabled: boolean;
397
402
  readonly legacyGlobalJwtSigning: boolean;
@@ -439,6 +444,7 @@ type AdminProjectConfigUpdateOptions = {
439
444
  signUpEnabled?: boolean;
440
445
  credentialEnabled?: boolean;
441
446
  magicLinkEnabled?: boolean;
447
+ passkeyEnabled?: boolean;
442
448
  clientTeamCreationEnabled?: boolean;
443
449
  clientUserDeletionEnabled?: boolean;
444
450
  allowLocalhost?: boolean;
@@ -509,7 +515,7 @@ type Team = {
509
515
  clientReadOnlyMetadata: any;
510
516
  inviteUser(options: {
511
517
  email: string;
512
- }): Promise<Result<undefined, KnownErrors["TeamPermissionRequired"]>>;
518
+ }): Promise<void>;
513
519
  listUsers(): Promise<TeamUser[]>;
514
520
  useUsers(): TeamUser[];
515
521
  update(update: TeamUpdateOptions): Promise<void>;
@@ -537,7 +543,7 @@ type ServerTeam = {
537
543
  addUser(userId: string): Promise<void>;
538
544
  inviteUser(options: {
539
545
  email: string;
540
- }): Promise<Result<undefined, KnownErrors["TeamPermissionRequired"]>>;
546
+ }): Promise<void>;
541
547
  removeUser(userId: string): Promise<void>;
542
548
  } & Team;
543
549
  type ServerTeamCreateOptions = TeamCreateOptions;
@@ -600,6 +606,7 @@ type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends s
600
606
  password: string;
601
607
  noRedirect?: boolean;
602
608
  }): Promise<Result<undefined, KnownErrors["UserEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]>>;
609
+ signInWithPasskey(): Promise<Result<undefined, KnownErrors["PasskeyAuthenticationFailed"] | KnownErrors["InvalidTotpCode"] | KnownErrors["PasskeyWebAuthnError"]>>;
603
610
  callOAuthCallback(): Promise<boolean>;
604
611
  sendForgotPasswordEmail(email: string): Promise<Result<undefined, KnownErrors["UserNotFound"]>>;
605
612
  sendMagicLinkEmail(email: string): Promise<Result<{
@@ -176,6 +176,7 @@ type Auth = {
176
176
  accessToken: string | null;
177
177
  refreshToken: string | null;
178
178
  }>;
179
+ registerPasskey(): Promise<Result<undefined, KnownErrors["PasskeyRegistrationFailed"] | KnownErrors["PasskeyWebAuthnError"]>>;
179
180
  };
180
181
  /**
181
182
  * ```
@@ -218,6 +219,7 @@ type BaseUser = {
218
219
  */
219
220
  readonly hasPassword: boolean;
220
221
  readonly otpAuthEnabled: boolean;
222
+ readonly passkeyAuthEnabled: boolean;
221
223
  readonly isMultiFactorRequired: boolean;
222
224
  /**
223
225
  * A shorthand method to update multiple fields of the user at once.
@@ -297,6 +299,7 @@ type UserUpdateOptions = {
297
299
  totpMultiFactorSecret?: Uint8Array | null;
298
300
  profileImageUrl?: string | null;
299
301
  otpAuthEnabled?: boolean;
302
+ passkeyAuthEnabled?: boolean;
300
303
  };
301
304
  type ServerBaseUser = {
302
305
  setPrimaryEmail(email: string, options?: {
@@ -380,6 +383,7 @@ type ProjectConfig = {
380
383
  readonly signUpEnabled: boolean;
381
384
  readonly credentialEnabled: boolean;
382
385
  readonly magicLinkEnabled: boolean;
386
+ readonly passkeyEnabled: boolean;
383
387
  readonly clientTeamCreationEnabled: boolean;
384
388
  readonly clientUserDeletionEnabled: boolean;
385
389
  readonly oauthProviders: OAuthProviderConfig[];
@@ -392,6 +396,7 @@ type AdminProjectConfig = {
392
396
  readonly signUpEnabled: boolean;
393
397
  readonly credentialEnabled: boolean;
394
398
  readonly magicLinkEnabled: boolean;
399
+ readonly passkeyEnabled: boolean;
395
400
  readonly clientTeamCreationEnabled: boolean;
396
401
  readonly clientUserDeletionEnabled: boolean;
397
402
  readonly legacyGlobalJwtSigning: boolean;
@@ -439,6 +444,7 @@ type AdminProjectConfigUpdateOptions = {
439
444
  signUpEnabled?: boolean;
440
445
  credentialEnabled?: boolean;
441
446
  magicLinkEnabled?: boolean;
447
+ passkeyEnabled?: boolean;
442
448
  clientTeamCreationEnabled?: boolean;
443
449
  clientUserDeletionEnabled?: boolean;
444
450
  allowLocalhost?: boolean;
@@ -509,7 +515,7 @@ type Team = {
509
515
  clientReadOnlyMetadata: any;
510
516
  inviteUser(options: {
511
517
  email: string;
512
- }): Promise<Result<undefined, KnownErrors["TeamPermissionRequired"]>>;
518
+ }): Promise<void>;
513
519
  listUsers(): Promise<TeamUser[]>;
514
520
  useUsers(): TeamUser[];
515
521
  update(update: TeamUpdateOptions): Promise<void>;
@@ -537,7 +543,7 @@ type ServerTeam = {
537
543
  addUser(userId: string): Promise<void>;
538
544
  inviteUser(options: {
539
545
  email: string;
540
- }): Promise<Result<undefined, KnownErrors["TeamPermissionRequired"]>>;
546
+ }): Promise<void>;
541
547
  removeUser(userId: string): Promise<void>;
542
548
  } & Team;
543
549
  type ServerTeamCreateOptions = TeamCreateOptions;
@@ -600,6 +606,7 @@ type StackClientApp<HasTokenStore extends boolean = boolean, ProjectId extends s
600
606
  password: string;
601
607
  noRedirect?: boolean;
602
608
  }): Promise<Result<undefined, KnownErrors["UserEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]>>;
609
+ signInWithPasskey(): Promise<Result<undefined, KnownErrors["PasskeyAuthenticationFailed"] | KnownErrors["InvalidTotpCode"] | KnownErrors["PasskeyWebAuthnError"]>>;
603
610
  callOAuthCallback(): Promise<boolean>;
604
611
  sendForgotPasswordEmail(email: string): Promise<Result<undefined, KnownErrors["UserNotFound"]>>;
605
612
  sendMagicLinkEmail(email: string): Promise<Result<{
@@ -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.12";
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 ?? "/";
@@ -542,6 +543,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
542
543
  signUpEnabled: crud.config.sign_up_enabled,
543
544
  credentialEnabled: crud.config.credential_enabled,
544
545
  magicLinkEnabled: crud.config.magic_link_enabled,
546
+ passkeyEnabled: crud.config.passkey_enabled,
545
547
  clientTeamCreationEnabled: crud.config.client_team_creation_enabled,
546
548
  clientUserDeletionEnabled: crud.config.client_user_deletion_enabled,
547
549
  oauthProviders: crud.config.enabled_oauth_providers.map((p) => ({
@@ -573,7 +575,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
573
575
  clientMetadata: crud.client_metadata,
574
576
  clientReadOnlyMetadata: crud.client_read_only_metadata,
575
577
  async inviteUser(options) {
576
- return await app._interface.sendTeamInvitation({
578
+ await app._interface.sendTeamInvitation({
577
579
  teamId: crud.id,
578
580
  email: options.email,
579
581
  session: app._getSession(),
@@ -638,6 +640,31 @@ var _StackClientAppImpl = class __StackClientAppImpl {
638
640
  const tokens = await this.currentSession.getTokens();
639
641
  return tokens;
640
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
+ },
641
668
  signOut() {
642
669
  return app._signOut(session);
643
670
  }
@@ -660,6 +687,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
660
687
  emailAuthEnabled: crud.auth_with_email,
661
688
  otpAuthEnabled: crud.otp_auth_enabled,
662
689
  oauthProviders: crud.oauth_providers,
690
+ passkeyAuthEnabled: crud.passkey_auth_enabled,
663
691
  selectedTeam: crud.selected_team && this._clientTeamFromCrud(crud.selected_team),
664
692
  isMultiFactorRequired: crud.requires_totp_mfa,
665
693
  toClientJson() {
@@ -1146,6 +1174,38 @@ var _StackClientAppImpl = class __StackClientAppImpl {
1146
1174
  return import_results.Result.error(result.error);
1147
1175
  }
1148
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
+ }
1149
1209
  async callOAuthCallback() {
1150
1210
  this._ensurePersistentTokenStore();
1151
1211
  let result;
@@ -1596,7 +1656,7 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
1596
1656
  await app._serverTeamMemberProfilesCache.refresh([crud.id]);
1597
1657
  },
1598
1658
  async inviteUser(options) {
1599
- return await app._interface.sendTeamInvitation({
1659
+ await app._interface.sendTeamInvitation({
1600
1660
  teamId: crud.id,
1601
1661
  email: options.email,
1602
1662
  session: null,
@@ -1800,6 +1860,7 @@ var _StackAdminAppImpl = class extends _StackServerAppImpl {
1800
1860
  signUpEnabled: data.config.sign_up_enabled,
1801
1861
  credentialEnabled: data.config.credential_enabled,
1802
1862
  magicLinkEnabled: data.config.magic_link_enabled,
1863
+ passkeyEnabled: data.config.passkey_enabled,
1803
1864
  legacyGlobalJwtSigning: data.config.legacy_global_jwt_signing,
1804
1865
  clientTeamCreationEnabled: data.config.client_team_creation_enabled,
1805
1866
  clientUserDeletionEnabled: data.config.client_user_deletion_enabled,
@@ -2019,7 +2080,8 @@ function userUpdateOptionsToCrud(options) {
2019
2080
  selected_team_id: options.selectedTeamId,
2020
2081
  totp_secret_base64: options.totpMultiFactorSecret != null ? (0, import_bytes.encodeBase64)(options.totpMultiFactorSecret) : options.totpMultiFactorSecret,
2021
2082
  profile_image_url: options.profileImageUrl,
2022
- otp_auth_enabled: options.otpAuthEnabled
2083
+ otp_auth_enabled: options.otpAuthEnabled,
2084
+ passkey_auth_enabled: options.passkeyAuthEnabled
2023
2085
  };
2024
2086
  }
2025
2087
  function serverUserUpdateOptionsToCrud(options) {
@@ -2082,6 +2144,7 @@ function adminProjectUpdateOptionsToCrud(options) {
2082
2144
  sign_up_enabled: options.config?.signUpEnabled,
2083
2145
  credential_enabled: options.config?.credentialEnabled,
2084
2146
  magic_link_enabled: options.config?.magicLinkEnabled,
2147
+ passkey_enabled: options.config?.passkeyEnabled,
2085
2148
  allow_localhost: options.config?.allowLocalhost,
2086
2149
  create_team_on_sign_up: options.config?.createTeamOnSignUp,
2087
2150
  client_team_creation_enabled: options.config?.clientTeamCreationEnabled,