@account-kit/signer 4.52.4 → 4.53.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 (45) hide show
  1. package/dist/esm/base.d.ts +41 -1
  2. package/dist/esm/base.js +116 -39
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +14 -1
  5. package/dist/esm/client/base.js +24 -0
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +29 -1
  8. package/dist/esm/client/index.js +37 -0
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +13 -5
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/metrics.d.ts +1 -1
  13. package/dist/esm/metrics.js.map +1 -1
  14. package/dist/esm/signer.d.ts +3 -0
  15. package/dist/esm/signer.js.map +1 -1
  16. package/dist/esm/types.d.ts +1 -0
  17. package/dist/esm/types.js +1 -0
  18. package/dist/esm/types.js.map +1 -1
  19. package/dist/esm/version.d.ts +1 -1
  20. package/dist/esm/version.js +1 -1
  21. package/dist/esm/version.js.map +1 -1
  22. package/dist/types/base.d.ts +41 -1
  23. package/dist/types/base.d.ts.map +1 -1
  24. package/dist/types/client/base.d.ts +14 -1
  25. package/dist/types/client/base.d.ts.map +1 -1
  26. package/dist/types/client/index.d.ts +29 -1
  27. package/dist/types/client/index.d.ts.map +1 -1
  28. package/dist/types/client/types.d.ts +13 -5
  29. package/dist/types/client/types.d.ts.map +1 -1
  30. package/dist/types/metrics.d.ts +1 -1
  31. package/dist/types/metrics.d.ts.map +1 -1
  32. package/dist/types/signer.d.ts +3 -0
  33. package/dist/types/signer.d.ts.map +1 -1
  34. package/dist/types/types.d.ts +1 -0
  35. package/dist/types/types.d.ts.map +1 -1
  36. package/dist/types/version.d.ts +1 -1
  37. package/package.json +4 -4
  38. package/src/base.ts +175 -12
  39. package/src/client/base.ts +27 -0
  40. package/src/client/index.ts +37 -0
  41. package/src/client/types.ts +19 -6
  42. package/src/metrics.ts +1 -0
  43. package/src/signer.ts +4 -0
  44. package/src/types.ts +1 -0
  45. package/src/version.ts +1 -1
@@ -18,6 +18,13 @@ export type EmailConfig = {
18
18
  export type SignerConfig = {
19
19
  email: EmailConfig;
20
20
  };
21
+ type GetUserParams = {
22
+ type: "email";
23
+ value: string;
24
+ } | {
25
+ type: "phone";
26
+ value: string;
27
+ };
21
28
  /**
22
29
  * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.
23
30
  * Implements the `SmartAccountAuthenticator` interface and handles various signer events.
@@ -315,6 +322,8 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
315
322
  /**
316
323
  * Unauthenticated call to look up a user's organizationId by email
317
324
  *
325
+ * @deprecated Use getUser({ type: "email", value: email }) instead
326
+ *
318
327
  * @example
319
328
  * ```ts
320
329
  * import { AlchemyWebSigner } from "@account-kit/signer";
@@ -336,7 +345,34 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
336
345
  * @param {string} email the email to lookup
337
346
  * @returns {Promise<{orgId: string}>} the organization id for the user if they exist
338
347
  */
339
- getUser: (email: string) => Promise<{
348
+ getUser(email: string): Promise<{
349
+ orgId: string;
350
+ } | null>;
351
+ /**
352
+ * Unauthenticated call to look up a user's organizationId by email or phone
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * import { AlchemyWebSigner } from "@account-kit/signer";
357
+ *
358
+ * const signer = new AlchemyWebSigner({
359
+ * client: {
360
+ * connection: {
361
+ * rpcUrl: "/api/rpc",
362
+ * },
363
+ * iframeConfig: {
364
+ * iframeContainerId: "alchemy-signer-iframe-container",
365
+ * },
366
+ * },
367
+ * });
368
+ *
369
+ * const result = await signer.getUser({ type: "email", value: "foo@mail.com" });
370
+ * ```
371
+ *
372
+ * @param {string} email the email to lookup
373
+ * @returns {Promise<{orgId: string}>} the organization id for the user if they exist
374
+ */
375
+ getUser(params: GetUserParams): Promise<{
340
376
  orgId: string;
341
377
  } | null>;
342
378
  setEmail: (email: string) => Promise<void>;
@@ -483,6 +519,7 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
483
519
  */
484
520
  toSolanaSigner: () => SolanaSigner;
485
521
  private authenticateWithEmail;
522
+ private authenticateWithSms;
486
523
  private authenticateWithPasskey;
487
524
  private authenticateWithOauth;
488
525
  /**
@@ -511,12 +548,14 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
511
548
  listAuthMethods: () => Promise<AuthMethods>;
512
549
  private authenticateWithOtp;
513
550
  private setAwaitingEmailAuth;
551
+ private setAwaitingSmsAuth;
514
552
  private handleOauthReturn;
515
553
  private handleMfaRequired;
516
554
  private getExpirationSeconds;
517
555
  private registerListeners;
518
556
  private emitNewUserEvent;
519
557
  private initOrCreateEmailUser;
558
+ private initOrCreateSmsUser;
520
559
  private completeEmailAuth;
521
560
  /**
522
561
  * Retrieves the list of MFA factors configured for the current user.
@@ -677,3 +716,4 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
677
716
  private setAuthLinkingPrompt;
678
717
  private waitForConnected;
679
718
  }
719
+ export {};
package/dist/esm/base.js CHANGED
@@ -173,6 +173,8 @@ export class BaseAlchemySigner {
173
173
  switch (type) {
174
174
  case "email":
175
175
  return this.authenticateWithEmail(params);
176
+ case "sms":
177
+ return this.authenticateWithSms(params);
176
178
  case "passkey":
177
179
  return this.authenticateWithPasskey(params);
178
180
  case "oauth":
@@ -220,6 +222,14 @@ export class BaseAlchemySigner {
220
222
  });
221
223
  return;
222
224
  }
225
+ case "sms": {
226
+ // we just want to track the start of phone auth
227
+ SignerLogger.trackEvent({
228
+ name: "signer_authnticate",
229
+ data: { authType: "sms" },
230
+ });
231
+ return;
232
+ }
223
233
  case "passkey": {
224
234
  const isAnon = !("email" in params) && params.createNew == null;
225
235
  SignerLogger.trackEvent({
@@ -543,44 +553,6 @@ export class BaseAlchemySigner {
543
553
  };
544
554
  }
545
555
  });
546
- /**
547
- * Unauthenticated call to look up a user's organizationId by email
548
- *
549
- * @example
550
- * ```ts
551
- * import { AlchemyWebSigner } from "@account-kit/signer";
552
- *
553
- * const signer = new AlchemyWebSigner({
554
- * client: {
555
- * connection: {
556
- * rpcUrl: "/api/rpc",
557
- * },
558
- * iframeConfig: {
559
- * iframeContainerId: "alchemy-signer-iframe-container",
560
- * },
561
- * },
562
- * });
563
- *
564
- * const result = await signer.getUser("foo@mail.com");
565
- * ```
566
- *
567
- * @param {string} email the email to lookup
568
- * @returns {Promise<{orgId: string}>} the organization id for the user if they exist
569
- */
570
- Object.defineProperty(this, "getUser", {
571
- enumerable: true,
572
- configurable: true,
573
- writable: true,
574
- value: SignerLogger.profiled("BaseAlchemySigner.getUser", async (email) => {
575
- const result = await this.inner.lookupUserByEmail(email);
576
- if (result.orgId == null) {
577
- return null;
578
- }
579
- return {
580
- orgId: result.orgId,
581
- };
582
- })
583
- });
584
556
  /*
585
557
  * Sets the email for the authenticated user, allowing them to login with that
586
558
  * email.
@@ -825,6 +797,26 @@ export class BaseAlchemySigner {
825
797
  return this.waitForConnected();
826
798
  }
827
799
  });
800
+ Object.defineProperty(this, "authenticateWithSms", {
801
+ enumerable: true,
802
+ configurable: true,
803
+ writable: true,
804
+ value: async (params) => {
805
+ const { orgId, otpId, isNewUser } = await this.initOrCreateSmsUser(params.phone);
806
+ this.setAwaitingSmsAuth({ orgId, otpId, isNewUser });
807
+ // TODO: add phone auth linking
808
+ // // Clear the auth linking status if the email has changed. This would mean
809
+ // // that the previously initiated social login is not associated with the
810
+ // // email which is now being used to login.
811
+ // const { authLinkingStatus } = this.store.getState();
812
+ // if (authLinkingStatus && authLinkingStatus.email !== params.email) {
813
+ // this.store.setState({ authLinkingStatus: undefined });
814
+ // }
815
+ // We wait for the session manager to emit a connected event if
816
+ // cross tab sessions are permitted
817
+ return this.waitForConnected();
818
+ }
819
+ });
828
820
  Object.defineProperty(this, "authenticateWithPasskey", {
829
821
  enumerable: true,
830
822
  configurable: true,
@@ -833,7 +825,10 @@ export class BaseAlchemySigner {
833
825
  let user;
834
826
  const shouldCreateNew = async () => {
835
827
  if ("email" in args) {
836
- const existingUser = await this.getUser(args.email);
828
+ const existingUser = await this.getUser({
829
+ type: "email",
830
+ value: args.email,
831
+ });
837
832
  return existingUser == null;
838
833
  }
839
834
  return args.createNew;
@@ -1019,6 +1014,22 @@ export class BaseAlchemySigner {
1019
1014
  });
1020
1015
  }
1021
1016
  });
1017
+ Object.defineProperty(this, "setAwaitingSmsAuth", {
1018
+ enumerable: true,
1019
+ configurable: true,
1020
+ writable: true,
1021
+ value: ({ orgId, otpId, isNewUser, }) => {
1022
+ this.sessionManager.setTemporarySession({
1023
+ orgId,
1024
+ isNewUser,
1025
+ });
1026
+ this.store.setState({
1027
+ status: AlchemySignerStatus.AWAITING_SMS_AUTH,
1028
+ otpId,
1029
+ error: null,
1030
+ });
1031
+ }
1032
+ });
1022
1033
  Object.defineProperty(this, "handleOauthReturn", {
1023
1034
  enumerable: true,
1024
1035
  configurable: true,
@@ -1086,6 +1097,8 @@ export class BaseAlchemySigner {
1086
1097
  case "otp":
1087
1098
  case "otpVerify":
1088
1099
  return AlchemySignerStatus.AWAITING_OTP_AUTH;
1100
+ case "sms":
1101
+ return AlchemySignerStatus.AWAITING_SMS_AUTH;
1089
1102
  default:
1090
1103
  assertNever(type, "unhandled authenticating type");
1091
1104
  }
@@ -1340,6 +1353,48 @@ export class BaseAlchemySigner {
1340
1353
  this.setAuthLinkingPrompt(initialAuthLinkingPrompt);
1341
1354
  }
1342
1355
  }
1356
+ /**
1357
+ * Unauthenticated call to look up a user's organizationId by email or phone
1358
+ *
1359
+ * @example
1360
+ * ```ts
1361
+ * import { AlchemyWebSigner } from "@account-kit/signer";
1362
+ *
1363
+ * const signer = new AlchemyWebSigner({
1364
+ * client: {
1365
+ * connection: {
1366
+ * rpcUrl: "/api/rpc",
1367
+ * },
1368
+ * iframeConfig: {
1369
+ * iframeContainerId: "alchemy-signer-iframe-container",
1370
+ * },
1371
+ * },
1372
+ * });
1373
+ *
1374
+ * const result = await signer.getUser({ type: "email", value: "foo@mail.com" });
1375
+ * ```
1376
+ *
1377
+ * @param {string | GetUserParams} params the params to look up
1378
+ * @returns {Promise<{orgId: string}>} the organization id for the user if they exist
1379
+ */
1380
+ getUser(params) {
1381
+ return SignerLogger.profiled("BaseAlchemySigner.getUser", async (params) => {
1382
+ const _params = typeof params === "string"
1383
+ ? { type: "email", value: params }
1384
+ : params;
1385
+ const result = _params.type === "email"
1386
+ ? await this.inner.lookupUserByEmail(_params.value)
1387
+ : _params.type === "phone"
1388
+ ? await this.inner.lookupUserByPhone(_params.value)
1389
+ : assertNever(_params, "unhandled get user params");
1390
+ if (result?.orgId == null) {
1391
+ return null;
1392
+ }
1393
+ return {
1394
+ orgId: result.orgId,
1395
+ };
1396
+ })(params);
1397
+ }
1343
1398
  handleMfaRequired(encryptedPayload, multiFactors) {
1344
1399
  // Store complete MFA context in the temporary session
1345
1400
  const tempSession = this.sessionManager.getTemporarySession();
@@ -1390,6 +1445,28 @@ export class BaseAlchemySigner {
1390
1445
  isNewUser: true,
1391
1446
  };
1392
1447
  }
1448
+ async initOrCreateSmsUser(phone) {
1449
+ const existingUser = await this.getUser({ type: "phone", value: phone });
1450
+ if (existingUser) {
1451
+ const { orgId, otpId } = await this.inner.initSmsAuth({
1452
+ phone,
1453
+ });
1454
+ return {
1455
+ orgId,
1456
+ otpId,
1457
+ isNewUser: false,
1458
+ };
1459
+ }
1460
+ const { orgId, otpId } = await this.inner.createAccount({
1461
+ type: "sms",
1462
+ phone,
1463
+ });
1464
+ return {
1465
+ orgId,
1466
+ otpId,
1467
+ isNewUser: true,
1468
+ };
1469
+ }
1393
1470
  async completeEmailAuth(params) {
1394
1471
  const temporarySession = params.orgId
1395
1472
  ? { orgId: params.orgId }