@account-kit/signer 4.16.1-alpha.3 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/esm/base.d.ts +15 -32
  2. package/dist/esm/base.js +94 -122
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +2 -36
  5. package/dist/esm/client/base.js.map +1 -1
  6. package/dist/esm/client/index.d.ts +1 -40
  7. package/dist/esm/client/index.js +7 -164
  8. package/dist/esm/client/index.js.map +1 -1
  9. package/dist/esm/client/types.d.ts +12 -66
  10. package/dist/esm/client/types.js.map +1 -1
  11. package/dist/esm/errors.d.ts +0 -6
  12. package/dist/esm/errors.js +0 -18
  13. package/dist/esm/errors.js.map +1 -1
  14. package/dist/esm/index.d.ts +1 -1
  15. package/dist/esm/index.js +1 -1
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/session/manager.d.ts +0 -1
  18. package/dist/esm/session/manager.js.map +1 -1
  19. package/dist/esm/signer.d.ts +2 -3
  20. package/dist/esm/signer.js.map +1 -1
  21. package/dist/esm/types.d.ts +0 -8
  22. package/dist/esm/types.js +0 -5
  23. package/dist/esm/types.js.map +1 -1
  24. package/dist/esm/version.d.ts +1 -1
  25. package/dist/esm/version.js +1 -1
  26. package/dist/esm/version.js.map +1 -1
  27. package/dist/types/base.d.ts +15 -32
  28. package/dist/types/base.d.ts.map +1 -1
  29. package/dist/types/client/base.d.ts +2 -36
  30. package/dist/types/client/base.d.ts.map +1 -1
  31. package/dist/types/client/index.d.ts +1 -40
  32. package/dist/types/client/index.d.ts.map +1 -1
  33. package/dist/types/client/types.d.ts +12 -66
  34. package/dist/types/client/types.d.ts.map +1 -1
  35. package/dist/types/errors.d.ts +0 -6
  36. package/dist/types/errors.d.ts.map +1 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/session/manager.d.ts +0 -1
  40. package/dist/types/session/manager.d.ts.map +1 -1
  41. package/dist/types/signer.d.ts +2 -3
  42. package/dist/types/signer.d.ts.map +1 -1
  43. package/dist/types/types.d.ts +0 -8
  44. package/dist/types/types.d.ts.map +1 -1
  45. package/dist/types/version.d.ts +1 -1
  46. package/dist/types/version.d.ts.map +1 -1
  47. package/package.json +4 -4
  48. package/src/base.ts +87 -166
  49. package/src/client/base.ts +1 -43
  50. package/src/client/index.ts +7 -174
  51. package/src/client/types.ts +14 -76
  52. package/src/errors.ts +1 -11
  53. package/src/index.ts +1 -5
  54. package/src/session/manager.ts +1 -5
  55. package/src/signer.ts +2 -6
  56. package/src/types.ts +0 -9
  57. package/src/version.ts +1 -1
  58. package/dist/esm/utils/parseMfaError.d.ts +0 -2
  59. package/dist/esm/utils/parseMfaError.js +0 -15
  60. package/dist/esm/utils/parseMfaError.js.map +0 -1
  61. package/dist/types/utils/parseMfaError.d.ts +0 -3
  62. package/dist/types/utils/parseMfaError.d.ts.map +0 -1
  63. package/src/utils/parseMfaError.ts +0 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@account-kit/signer",
3
- "version": "4.16.1-alpha.3",
3
+ "version": "4.17.0",
4
4
  "description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
5
5
  "author": "Alchemy",
6
6
  "license": "MIT",
@@ -49,8 +49,8 @@
49
49
  "vitest": "^2.0.4"
50
50
  },
51
51
  "dependencies": {
52
- "@aa-sdk/core": "^4.16.1-alpha.3",
53
- "@account-kit/logging": "^4.16.1-alpha.3",
52
+ "@aa-sdk/core": "^4.17.0",
53
+ "@account-kit/logging": "^4.17.0",
54
54
  "@solana/web3.js": "^1.98.0",
55
55
  "@turnkey/http": "^2.6.2",
56
56
  "@turnkey/iframe-stamper": "^1.0.0",
@@ -74,5 +74,5 @@
74
74
  "url": "https://github.com/alchemyplatform/aa-sdk/issues"
75
75
  },
76
76
  "homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
77
- "gitHead": "156dbc81d12e9f120f8123df6b4fec8a41f41e7a"
77
+ "gitHead": "680b0acb112f02deaa1fa4e8b253ac3800c06cb2"
78
78
  }
package/src/base.ts CHANGED
@@ -21,14 +21,7 @@ import type { Mutate, StoreApi } from "zustand";
21
21
  import { subscribeWithSelector } from "zustand/middleware";
22
22
  import { createStore } from "zustand/vanilla";
23
23
  import type { BaseSignerClient } from "./client/base";
24
- import type {
25
- EmailType,
26
- MfaFactor,
27
- OauthConfig,
28
- OauthParams,
29
- User,
30
- VerifyMfaParams,
31
- } from "./client/types";
24
+ import type { OauthConfig, OauthParams, User } from "./client/types";
32
25
  import { NotAuthenticatedError } from "./errors.js";
33
26
  import { SignerLogger } from "./metrics.js";
34
27
  import {
@@ -58,10 +51,6 @@ type AlchemySignerStore = {
58
51
  error: ErrorInfo | null;
59
52
  otpId?: string;
60
53
  isNewUser?: boolean;
61
- mfaStatus: {
62
- mfaRequired: boolean;
63
- mfaFactorId?: string;
64
- };
65
54
  };
66
55
 
67
56
  type UnpackedSignature = {
@@ -75,6 +64,14 @@ type InternalStore = Mutate<
75
64
  [["zustand/subscribeWithSelector", never]]
76
65
  >;
77
66
 
67
+ export type EmailConfig = {
68
+ mode?: "MAGIC_LINK" | "OTP";
69
+ };
70
+
71
+ export type SignerConfig = {
72
+ email: EmailConfig;
73
+ };
74
+
78
75
  /**
79
76
  * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.
80
77
  * Implements the `SmartAccountAuthenticator` interface and handles various signer events.
@@ -86,6 +83,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
86
83
  inner: TClient;
87
84
  private sessionManager: SessionManager;
88
85
  private store: InternalStore;
86
+ private config: Promise<SignerConfig>;
89
87
 
90
88
  /**
91
89
  * Initializes an instance with the provided client and session configuration.
@@ -110,10 +108,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
110
108
  user: null,
111
109
  status: AlchemySignerStatus.INITIALIZING,
112
110
  error: initialError ?? null,
113
- mfaStatus: {
114
- mfaRequired: false,
115
- mfaFactorId: undefined,
116
- },
117
111
  } satisfies AlchemySignerStore)
118
112
  )
119
113
  );
@@ -128,6 +122,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
128
122
  this.registerListeners();
129
123
  // then initialize so that we can catch those events
130
124
  this.sessionManager.initialize();
125
+ this.config = this.fetchConfig();
131
126
  }
132
127
 
133
128
  /**
@@ -186,13 +181,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
186
181
  },
187
182
  { fireImmediately: true }
188
183
  );
189
- case "mfaStatusChanged":
190
- return this.store.subscribe(
191
- ({ mfaStatus }) => mfaStatus,
192
- (mfaStatus) =>
193
- (listener as AlchemySignerEvents["mfaStatusChanged"])(mfaStatus),
194
- { fireImmediately: true }
195
- );
196
184
  default:
197
185
  assertNever(event, `Unknown event type ${event}`);
198
186
  }
@@ -602,39 +590,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
602
590
  }
603
591
  );
604
592
 
605
- /**
606
- * Gets the current MFA status
607
- *
608
- * @example
609
- * ```ts
610
- * import { AlchemyWebSigner } from "@account-kit/signer";
611
- *
612
- * const signer = new AlchemyWebSigner({
613
- * client: {
614
- * connection: {
615
- * rpcUrl: "/api/rpc",
616
- * },
617
- * iframeConfig: {
618
- * iframeContainerId: "alchemy-signer-iframe-container",
619
- * },
620
- * },
621
- * });
622
- *
623
- * const mfaStatus = signer.getMfaStatus();
624
- * if (mfaStatus === AlchemyMfaStatus.REQUIRED) {
625
- * // Handle MFA requirement
626
- * }
627
- * ```
628
- *
629
- * @returns {{ mfaRequired: boolean; mfaFactorId?: string }} The current MFA status
630
- */
631
- getMfaStatus = (): {
632
- mfaRequired: boolean;
633
- mfaFactorId?: string;
634
- } => {
635
- return this.store.getState().mfaStatus;
636
- };
637
-
638
593
  private unpackSignRawMessageBytes = (
639
594
  hex: `0x${string}`
640
595
  ): UnpackedSignature => {
@@ -824,48 +779,70 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
824
779
  private authenticateWithEmail = async (
825
780
  params: Extract<AuthParams, { type: "email" }>
826
781
  ): Promise<User> => {
827
- if ("bundle" in params) {
828
- return this.completeEmailAuth(params);
829
- }
782
+ if ("email" in params) {
783
+ const existingUser = await this.getUser(params.email);
784
+ const expirationSeconds = this.getExpirationSeconds();
785
+
786
+ const { orgId, otpId } = existingUser
787
+ ? await this.inner.initEmailAuth({
788
+ email: params.email,
789
+ emailMode: params.emailMode,
790
+ expirationSeconds,
791
+ redirectParams: params.redirectParams,
792
+ })
793
+ : await this.inner.createAccount({
794
+ type: "email",
795
+ email: params.email,
796
+ emailMode: params.emailMode,
797
+ expirationSeconds,
798
+ redirectParams: params.redirectParams,
799
+ });
830
800
 
831
- if (!("email" in params)) {
832
- throw new Error("Email is required");
833
- }
801
+ this.sessionManager.setTemporarySession({
802
+ orgId,
803
+ isNewUser: !existingUser,
804
+ });
805
+ this.store.setState({
806
+ status: AlchemySignerStatus.AWAITING_EMAIL_AUTH,
807
+ otpId,
808
+ error: null,
809
+ });
834
810
 
835
- const { orgId, otpId, multiFactors, isNewUser } =
836
- await this.initOrCreateEmailUser(
837
- params.email,
838
- params.emailMode ?? "otp",
839
- params.multiFactors,
840
- params.redirectParams
841
- );
811
+ // We wait for the session manager to emit a connected event if
812
+ // cross tab sessions are permitted
813
+ return new Promise<User>((resolve) => {
814
+ const removeListener = this.sessionManager.on(
815
+ "connected",
816
+ (session) => {
817
+ resolve(session.user);
818
+ removeListener();
819
+ }
820
+ );
821
+ });
822
+ } else {
823
+ const temporarySession = params.orgId
824
+ ? { orgId: params.orgId }
825
+ : this.sessionManager.getTemporarySession();
842
826
 
843
- const isMfaRequired = multiFactors ? multiFactors?.length > 0 : false;
827
+ if (!temporarySession) {
828
+ this.store.setState({
829
+ status: AlchemySignerStatus.DISCONNECTED,
830
+ });
831
+ throw new Error("Could not find email auth init session!");
832
+ }
844
833
 
845
- this.sessionManager.setTemporarySession({
846
- orgId,
847
- isNewUser,
848
- isMfaRequired,
849
- });
834
+ const user = await this.inner.completeAuthWithBundle({
835
+ bundle: params.bundle,
836
+ orgId: temporarySession.orgId,
837
+ connectedEventName: "connectedEmail",
838
+ authenticatingType: "email",
839
+ });
850
840
 
851
- this.store.setState({
852
- status: AlchemySignerStatus.AWAITING_EMAIL_AUTH,
853
- otpId,
854
- error: null,
855
- mfaStatus: {
856
- mfaRequired: isMfaRequired,
857
- mfaFactorId: multiFactors?.[0]?.multiFactorId,
858
- },
859
- });
841
+ // fire new user event
842
+ this.emitNewUserEvent(params.isNewUser);
860
843
 
861
- // We wait for the session manager to emit a connected event if
862
- // cross tab sessions are permitted
863
- return new Promise<User>((resolve) => {
864
- const removeListener = this.sessionManager.on("connected", (session) => {
865
- resolve(session.user);
866
- removeListener();
867
- });
868
- });
844
+ return user;
845
+ }
869
846
  };
870
847
 
871
848
  private authenticateWithPasskey = async (
@@ -926,7 +903,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
926
903
  args: Extract<AuthParams, { type: "otp" }>
927
904
  ): Promise<User> => {
928
905
  const tempSession = this.sessionManager.getTemporarySession();
929
- const { orgId, isNewUser, isMfaRequired } = tempSession ?? {};
906
+ const { orgId, isNewUser } = tempSession ?? {};
930
907
  const { otpId } = this.store.getState();
931
908
  if (!orgId) {
932
909
  throw new Error("orgId not found in session");
@@ -934,16 +911,11 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
934
911
  if (!otpId) {
935
912
  throw new Error("otpId not found in session");
936
913
  }
937
- if (isMfaRequired && !args.multiFactors) {
938
- throw new Error(`MFA is required.`);
939
- }
940
-
941
914
  const { bundle } = await this.inner.submitOtpCode({
942
915
  orgId,
943
916
  otpId,
944
917
  otpCode: args.otpCode,
945
918
  expirationSeconds: this.getExpirationSeconds(),
946
- multiFactors: args.multiFactors,
947
919
  });
948
920
  const user = await this.inner.completeAuthWithBundle({
949
921
  bundle,
@@ -1050,78 +1022,27 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
1050
1022
  if (isNewUser) this.store.setState({ isNewUser });
1051
1023
  };
1052
1024
 
1053
- private async initOrCreateEmailUser(
1054
- email: string,
1055
- emailMode: EmailType,
1056
- multiFactors?: VerifyMfaParams[],
1057
- redirectParams?: URLSearchParams
1058
- ): Promise<{
1059
- orgId: string;
1060
- otpId?: string;
1061
- multiFactors?: MfaFactor[];
1062
- isNewUser: boolean;
1063
- }> {
1064
- const existingUser = await this.getUser(email);
1065
- const expirationSeconds = this.getExpirationSeconds();
1066
-
1067
- if (existingUser) {
1068
- const {
1069
- orgId,
1070
- otpId,
1071
- multiFactors: mfaFactors,
1072
- } = await this.inner.initEmailAuth({
1073
- email: email,
1074
- emailMode: emailMode,
1075
- expirationSeconds,
1076
- redirectParams: redirectParams,
1077
- multiFactors,
1078
- });
1079
- return {
1080
- orgId,
1081
- otpId,
1082
- multiFactors: mfaFactors,
1083
- isNewUser: false,
1084
- };
1085
- }
1086
-
1087
- const { orgId, otpId } = await this.inner.createAccount({
1088
- type: "email",
1089
- email,
1090
- emailMode,
1091
- expirationSeconds,
1092
- redirectParams,
1093
- });
1094
- return {
1095
- orgId,
1096
- otpId,
1097
- isNewUser: true,
1098
- };
1099
- }
1100
-
1101
- private async completeEmailAuth(
1102
- params: Extract<AuthParams, { type: "email"; bundle: string }>
1103
- ): Promise<User> {
1104
- const temporarySession = params.orgId
1105
- ? { orgId: params.orgId }
1106
- : this.sessionManager.getTemporarySession();
1025
+ protected initConfig = async (): Promise<SignerConfig> => {
1026
+ this.config = this.fetchConfig();
1027
+ return this.config;
1028
+ };
1107
1029
 
1108
- if (!temporarySession) {
1109
- this.store.setState({ status: AlchemySignerStatus.DISCONNECTED });
1110
- throw new Error("Could not find email auth init session!");
1030
+ /**
1031
+ * Returns the signer configuration while fetching it if it's not already initialized.
1032
+ *
1033
+ * @returns {Promise<SignerConfig>} A promise that resolves to the signer configuration
1034
+ */
1035
+ public getConfig = async (): Promise<SignerConfig> => {
1036
+ if (!this.config) {
1037
+ return this.initConfig();
1111
1038
  }
1112
1039
 
1113
- const user = await this.inner.completeAuthWithBundle({
1114
- bundle: params.bundle,
1115
- orgId: temporarySession.orgId,
1116
- connectedEventName: "connectedEmail",
1117
- authenticatingType: "email",
1118
- });
1119
-
1120
- // fire new user event
1121
- this.emitNewUserEvent(params.isNewUser);
1040
+ return this.config;
1041
+ };
1122
1042
 
1123
- return user;
1124
- }
1043
+ protected fetchConfig = async (): Promise<SignerConfig> => {
1044
+ return this.inner.request("/v1/signer-config", {});
1045
+ };
1125
1046
  }
1126
1047
 
1127
1048
  function toErrorInfo(error: unknown): ErrorInfo {
@@ -14,13 +14,9 @@ import type {
14
14
  AlchemySignerClientEvents,
15
15
  AuthenticatingEventMetadata,
16
16
  CreateAccountParams,
17
- RemoveMfaParams,
18
17
  EmailAuthParams,
19
- EnableMfaParams,
20
- EnableMfaResult,
21
18
  GetOauthProviderUrlArgs,
22
19
  GetWebAuthnAttestationResult,
23
- MfaFactor,
24
20
  OauthConfig,
25
21
  OauthParams,
26
22
  OauthState,
@@ -30,7 +26,6 @@ import type {
30
26
  SignerRoutes,
31
27
  SignupResponse,
32
28
  User,
33
- VerifyMfaParams,
34
29
  } from "./types.js";
35
30
 
36
31
  export interface BaseSignerClientParams {
@@ -136,44 +131,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
136
131
 
137
132
  public abstract initEmailAuth(
138
133
  params: Omit<EmailAuthParams, "targetPublicKey">
139
- ): Promise<{ orgId: string; otpId?: string; multiFactors?: MfaFactor[] }>;
140
-
141
- /**
142
- * Retrieves the list of MFA factors configured for the current user.
143
- *
144
- * @returns {Promise<{ multiFactors: Array<MfaFactor> }>} A promise that resolves to an array of configured MFA factors
145
- */
146
- public abstract getMfaFactors(): Promise<{
147
- multiFactors: MfaFactor[];
148
- }>;
149
-
150
- /**
151
- * Initiates the setup of a new MFA factor for the current user. Mfa will need to be verified before it is active.
152
- *
153
- * @param {EnableMfaParams} params The parameters required to enable a new MFA factor
154
- * @returns {Promise<EnableMfaResult>} A promise that resolves to the factor setup information
155
- */
156
- public abstract addMfa(params: EnableMfaParams): Promise<EnableMfaResult>;
157
-
158
- /**
159
- * Verifies a newly created MFA factor to complete the setup process.
160
- *
161
- * @param {VerifyMfaParams} params The parameters required to verify the MFA factor
162
- * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
163
- */
164
- public abstract verifyMfa(params: VerifyMfaParams): Promise<{
165
- multiFactors: MfaFactor[];
166
- }>;
167
-
168
- /**
169
- * Removes existing MFA factors by ID or factor type.
170
- *
171
- * @param {RemoveMfaParams} params The parameters specifying which factors to disable
172
- * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
173
- */
174
- public abstract removeMfa(params: RemoveMfaParams): Promise<{
175
- multiFactors: MfaFactor[];
176
- }>;
134
+ ): Promise<{ orgId: string; otpId?: string }>;
177
135
 
178
136
  public abstract completeAuthWithBundle(params: {
179
137
  bundle: string;
@@ -17,23 +17,9 @@ import type {
17
17
  OauthConfig,
18
18
  OtpParams,
19
19
  User,
20
- MfaFactor,
21
- EnableMfaParams,
22
- EnableMfaResult,
23
- VerifyMfaParams,
24
- RemoveMfaParams,
25
20
  } from "./types.js";
26
- import { MfaRequiredError, NotAuthenticatedError } from "../errors.js";
27
- import { parseMfaError } from "../utils/parseMfaError.js";
28
21
 
29
22
  const CHECK_CLOSE_INTERVAL = 500;
30
- const MFA_PAYLOAD = {
31
- GET: "get_mfa",
32
- ADD: "add_mfa",
33
- DELETE: "delete_mfas",
34
- VERIFY: "verify_mfa",
35
- LIST: "list_mfas",
36
- };
37
23
 
38
24
  export const AlchemySignerClientParamsSchema = z.object({
39
25
  connection: ConnectionConfigSchema,
@@ -212,25 +198,13 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
212
198
  const { email, emailMode, expirationSeconds } = params;
213
199
  const publicKey = await this.initIframeStamper();
214
200
 
215
- try {
216
- return await this.request("/v1/auth", {
217
- email,
218
- emailMode,
219
- targetPublicKey: publicKey,
220
- expirationSeconds,
221
- redirectParams: params.redirectParams?.toString(),
222
- multiFactors: params.multiFactors,
223
- });
224
- } catch (error) {
225
- const multiFactors = parseMfaError(error);
226
-
227
- // If MFA is required, and emailMode is Magic Link, the user must submit mfa with the request or
228
- // the the server will return an error with the required mfa factors.
229
- if (multiFactors) {
230
- throw new MfaRequiredError(multiFactors);
231
- }
232
- throw error;
233
- }
201
+ return this.request("/v1/auth", {
202
+ email,
203
+ emailMode,
204
+ targetPublicKey: publicKey,
205
+ expirationSeconds,
206
+ redirectParams: params.redirectParams?.toString(),
207
+ });
234
208
  };
235
209
 
236
210
  /**
@@ -268,12 +242,6 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
268
242
  ...args,
269
243
  targetPublicKey,
270
244
  });
271
-
272
- if (!credentialBundle) {
273
- throw new Error(
274
- "Failed to submit OTP code. Check if multiFactor is required."
275
- );
276
- }
277
245
  return { bundle: credentialBundle };
278
246
  }
279
247
 
@@ -702,141 +670,6 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
702
670
  const nonce = this.getOauthNonce(publicKey);
703
671
  return this.request("/v1/prepare-oauth", { nonce });
704
672
  };
705
-
706
- /**
707
- * Retrieves the list of MFA factors configured for the current user.
708
- *
709
- * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to an array of configured MFA factors
710
- * @throws {NotAuthenticatedError} If no user is authenticated
711
- */
712
- public override getMfaFactors = async (): Promise<{
713
- multiFactors: MfaFactor[];
714
- }> => {
715
- if (!this.user) {
716
- throw new NotAuthenticatedError();
717
- }
718
-
719
- const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
720
- organizationId: this.user.orgId,
721
- type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
722
- timestampMs: Date.now().toString(),
723
- parameters: {
724
- encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
725
- hashFunction: "HASH_FUNCTION_NO_OP",
726
- payload: MFA_PAYLOAD.LIST,
727
- signWith: this.user.address,
728
- },
729
- });
730
-
731
- return this.request("/v1/auth-list-multi-factors", {
732
- stampedRequest,
733
- });
734
- };
735
-
736
- /**
737
- * Initiates the setup of a new MFA factor for the current user. Mfa will need to be verified before it is active.
738
- *
739
- * @param {EnableMfaParams} params The parameters required to enable a new MFA factor
740
- * @returns {Promise<EnableMfaResult>} A promise that resolves to the factor setup information
741
- * @throws {NotAuthenticatedError} If no user is authenticated
742
- * @throws {Error} If an unsupported factor type is provided
743
- */
744
- public override addMfa = async (
745
- params: EnableMfaParams
746
- ): Promise<EnableMfaResult> => {
747
- if (!this.user) {
748
- throw new NotAuthenticatedError();
749
- }
750
-
751
- const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
752
- organizationId: this.user.orgId,
753
- type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
754
- timestampMs: Date.now().toString(),
755
- parameters: {
756
- encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
757
- hashFunction: "HASH_FUNCTION_NO_OP",
758
- payload: MFA_PAYLOAD.ADD,
759
- signWith: this.user.address,
760
- },
761
- });
762
-
763
- switch (params.multiFactorType) {
764
- case "totp":
765
- return this.request("/v1/auth-request-multi-factor", {
766
- stampedRequest,
767
- multiFactorType: params.multiFactorType,
768
- });
769
- default:
770
- throw new Error(
771
- `Unsupported MFA factor type: ${params.multiFactorType}`
772
- );
773
- }
774
- };
775
-
776
- /**
777
- * Verifies a newly created MFA factor to complete the setup process.
778
- *
779
- * @param {VerifyMfaParams} params The parameters required to verify the MFA factor
780
- * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
781
- * @throws {NotAuthenticatedError} If no user is authenticated
782
- */
783
- public override verifyMfa = async (
784
- params: VerifyMfaParams
785
- ): Promise<{ multiFactors: MfaFactor[] }> => {
786
- if (!this.user) {
787
- throw new NotAuthenticatedError();
788
- }
789
-
790
- const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
791
- organizationId: this.user.orgId,
792
- type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
793
- timestampMs: Date.now().toString(),
794
- parameters: {
795
- encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
796
- hashFunction: "HASH_FUNCTION_NO_OP",
797
- payload: MFA_PAYLOAD.VERIFY,
798
- signWith: this.user.address,
799
- },
800
- });
801
-
802
- return this.request("/v1/auth-verify-multi-factor", {
803
- stampedRequest,
804
- multiFactorId: params.multiFactorId,
805
- multiFactorCode: params.multiFactorCode,
806
- });
807
- };
808
-
809
- /**
810
- * Removes existing MFA factors by ID.
811
- *
812
- * @param {RemoveMfaParams} params The parameters specifying which factors to disable
813
- * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
814
- * @throws {NotAuthenticatedError} If no user is authenticated
815
- */
816
- public override removeMfa = async (
817
- params: RemoveMfaParams
818
- ): Promise<{ multiFactors: MfaFactor[] }> => {
819
- if (!this.user) {
820
- throw new NotAuthenticatedError();
821
- }
822
-
823
- const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
824
- organizationId: this.user.orgId,
825
- type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
826
- timestampMs: Date.now().toString(),
827
- parameters: {
828
- encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
829
- hashFunction: "HASH_FUNCTION_NO_OP",
830
- payload: MFA_PAYLOAD.DELETE,
831
- signWith: this.user.address,
832
- },
833
- });
834
-
835
- return this.request("/v1/auth-delete-multi-factors", {
836
- stampedRequest,
837
- multiFactorIds: params.multiFactorIds,
838
- });
839
- };
840
673
  }
841
674
 
842
675
  /**