@account-kit/signer 4.0.0-alpha.9 → 4.0.0-beta.1

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 (78) hide show
  1. package/dist/esm/base.d.ts +286 -3
  2. package/dist/esm/base.js +307 -1
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +80 -1
  5. package/dist/esm/client/base.js +97 -0
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +162 -0
  8. package/dist/esm/client/index.js +167 -1
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +4 -0
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/session/manager.js +18 -1
  13. package/dist/esm/session/manager.js.map +1 -1
  14. package/dist/esm/signer.d.ts +28 -0
  15. package/dist/esm/signer.js +24 -0
  16. package/dist/esm/signer.js.map +1 -1
  17. package/dist/esm/version.d.ts +1 -1
  18. package/dist/esm/version.js +3 -1
  19. package/dist/esm/version.js.map +1 -1
  20. package/dist/types/base.d.ts +1 -3
  21. package/dist/types/base.d.ts.map +1 -1
  22. package/dist/types/client/base.d.ts +11 -1
  23. package/dist/types/client/base.d.ts.map +1 -1
  24. package/dist/types/client/index.d.ts.map +1 -1
  25. package/dist/types/client/types.d.ts +4 -0
  26. package/dist/types/client/types.d.ts.map +1 -1
  27. package/dist/types/signer.d.ts +4 -3
  28. package/dist/types/signer.d.ts.map +1 -1
  29. package/dist/types/version.d.ts +1 -1
  30. package/dist/types/version.d.ts.map +1 -1
  31. package/package.json +10 -15
  32. package/src/base.ts +17 -3
  33. package/src/client/base.ts +21 -2
  34. package/src/client/index.ts +2 -1
  35. package/src/client/types.ts +5 -0
  36. package/src/signer.ts +5 -0
  37. package/src/version.ts +1 -1
  38. package/dist/cjs/base.d.ts +0 -37
  39. package/dist/cjs/base.js +0 -292
  40. package/dist/cjs/base.js.map +0 -1
  41. package/dist/cjs/client/base.d.ts +0 -230
  42. package/dist/cjs/client/base.js +0 -298
  43. package/dist/cjs/client/base.js.map +0 -1
  44. package/dist/cjs/client/index.d.ts +0 -146
  45. package/dist/cjs/client/index.js +0 -260
  46. package/dist/cjs/client/index.js.map +0 -1
  47. package/dist/cjs/client/types.d.ts +0 -106
  48. package/dist/cjs/client/types.js +0 -3
  49. package/dist/cjs/client/types.js.map +0 -1
  50. package/dist/cjs/errors.d.ts +0 -4
  51. package/dist/cjs/errors.js +0 -16
  52. package/dist/cjs/errors.js.map +0 -1
  53. package/dist/cjs/index.d.ts +0 -9
  54. package/dist/cjs/index.js +0 -16
  55. package/dist/cjs/index.js.map +0 -1
  56. package/dist/cjs/package.json +0 -1
  57. package/dist/cjs/session/manager.d.ts +0 -45
  58. package/dist/cjs/session/manager.js +0 -230
  59. package/dist/cjs/session/manager.js.map +0 -1
  60. package/dist/cjs/session/types.d.ts +0 -16
  61. package/dist/cjs/session/types.js +0 -3
  62. package/dist/cjs/session/types.js.map +0 -1
  63. package/dist/cjs/signer.d.ts +0 -262
  64. package/dist/cjs/signer.js +0 -34
  65. package/dist/cjs/signer.js.map +0 -1
  66. package/dist/cjs/types.d.ts +0 -14
  67. package/dist/cjs/types.js +0 -12
  68. package/dist/cjs/types.js.map +0 -1
  69. package/dist/cjs/utils/base64UrlEncode.d.ts +0 -1
  70. package/dist/cjs/utils/base64UrlEncode.js +0 -12
  71. package/dist/cjs/utils/base64UrlEncode.js.map +0 -1
  72. package/dist/cjs/utils/generateRandomBuffer.d.ts +0 -1
  73. package/dist/cjs/utils/generateRandomBuffer.js +0 -10
  74. package/dist/cjs/utils/generateRandomBuffer.js.map +0 -1
  75. package/dist/cjs/version.d.ts +0 -1
  76. package/dist/cjs/version.js +0 -5
  77. package/dist/cjs/version.js.map +0 -1
  78. package/dist/esm/package.json +0 -1
package/dist/esm/base.js CHANGED
@@ -6,7 +6,20 @@ import { createStore } from "zustand/vanilla";
6
6
  import { NotAuthenticatedError } from "./errors.js";
7
7
  import { SessionManager, } from "./session/manager.js";
8
8
  import { AlchemySignerStatus, } from "./types.js";
9
+ /**
10
+ * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.
11
+ * Implements the `SmartAccountAuthenticator` interface and handles various signer events.
12
+ */
9
13
  export class BaseAlchemySigner {
14
+ /**
15
+ * Initializes an instance with the provided client and session configuration.
16
+ * This function sets up the internal store, initializes the session manager,
17
+ * registers listeners and initializes the session manager to manage session state.
18
+ *
19
+ * @param {BaseAlchemySignerParams<TClient>} param0 Object containing the client and session configuration
20
+ * @param {TClient} param0.client The client instance to be used internally
21
+ * @param {SessionConfig} param0.sessionConfig Configuration for managing sessions
22
+ */
10
23
  constructor({ client, sessionConfig }) {
11
24
  Object.defineProperty(this, "signerType", {
12
25
  enumerable: true,
@@ -32,11 +45,21 @@ export class BaseAlchemySigner {
32
45
  writable: true,
33
46
  value: void 0
34
47
  });
48
+ /**
49
+ * Allows you to subscribe to events emitted by the signer
50
+ *
51
+ * @param {AlchemySignerEvent} event the event to subscribe to
52
+ * @param {AlchemySignerEvents[AlchemySignerEvent]} listener the function to run when the event is emitted
53
+ * @returns {() => void} a function to remove the listener
54
+ */
35
55
  Object.defineProperty(this, "on", {
36
56
  enumerable: true,
37
57
  configurable: true,
38
58
  writable: true,
39
59
  value: (event, listener) => {
60
+ // NOTE: we're using zustand here to handle this because we are able to use the fireImmediately
61
+ // option which deals with a possible race condition where the listener is added after the event
62
+ // is fired. In the Client and SessionManager we use EventEmitter because it's easier to handle internally
40
63
  switch (event) {
41
64
  case "connected":
42
65
  return this.store.subscribe(({ status }) => status, (status) => status === AlchemySignerStatus.CONNECTED &&
@@ -51,6 +74,33 @@ export class BaseAlchemySigner {
51
74
  }
52
75
  }
53
76
  });
77
+ /**
78
+ * Authenticate a user with either an email or a passkey and create a session for that user
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { AlchemyWebSigner } from "@account-kit/signer";
83
+ *
84
+ * const signer = new AlchemyWebSigner({
85
+ * client: {
86
+ * connection: {
87
+ * rpcUrl: "/api/rpc",
88
+ * },
89
+ * iframeConfig: {
90
+ * iframeContainerId: "alchemy-signer-iframe-container",
91
+ * },
92
+ * },
93
+ * });
94
+ *
95
+ * const result = await signer.authenticate({
96
+ * type: "email",
97
+ * email: "foo@mail.com",
98
+ * });
99
+ * ```
100
+ *
101
+ * @param {AuthParams} params - undefined if passkey login, otherwise an object with email and bundle to resolve
102
+ * @returns {Promise<User>} the user that was authenticated
103
+ */
54
104
  Object.defineProperty(this, "authenticate", {
55
105
  enumerable: true,
56
106
  configurable: true,
@@ -62,6 +112,29 @@ export class BaseAlchemySigner {
62
112
  return this.authenticateWithPasskey(params);
63
113
  }
64
114
  });
115
+ /**
116
+ * Clear a user session and log them out
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { AlchemyWebSigner } from "@account-kit/signer";
121
+ *
122
+ * const signer = new AlchemyWebSigner({
123
+ * client: {
124
+ * connection: {
125
+ * rpcUrl: "/api/rpc",
126
+ * },
127
+ * iframeConfig: {
128
+ * iframeContainerId: "alchemy-signer-iframe-container",
129
+ * },
130
+ * },
131
+ * });
132
+ *
133
+ * await signer.disconnect();
134
+ * ```
135
+ *
136
+ * @returns {Promise<void>} a promise that resolves when the user is logged out
137
+ */
65
138
  Object.defineProperty(this, "disconnect", {
66
139
  enumerable: true,
67
140
  configurable: true,
@@ -70,6 +143,33 @@ export class BaseAlchemySigner {
70
143
  await this.inner.disconnect();
71
144
  }
72
145
  });
146
+ /**
147
+ * Gets the current logged in user
148
+ * If a user has an ongoing session, it will use that session and
149
+ * try to authenticate
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * import { AlchemyWebSigner } from "@account-kit/signer";
154
+ *
155
+ * const signer = new AlchemyWebSigner({
156
+ * client: {
157
+ * connection: {
158
+ * rpcUrl: "/api/rpc",
159
+ * },
160
+ * iframeConfig: {
161
+ * iframeContainerId: "alchemy-signer-iframe-container",
162
+ * },
163
+ * },
164
+ * });
165
+ *
166
+ * // throws if not logged in
167
+ * const user = await signer.getAuthDetails();
168
+ * ```
169
+ *
170
+ * @throws if there is no user logged in
171
+ * @returns {Promise<User>} the current user
172
+ */
73
173
  Object.defineProperty(this, "getAuthDetails", {
74
174
  enumerable: true,
75
175
  configurable: true,
@@ -82,6 +182,11 @@ export class BaseAlchemySigner {
82
182
  return this.inner.whoami();
83
183
  }
84
184
  });
185
+ /**
186
+ * Retrieves the address of the current user by calling the `whoami` method on `this.inner`.
187
+ *
188
+ * @returns {Promise<string>} A promise that resolves to the address of the current user.
189
+ */
85
190
  Object.defineProperty(this, "getAddress", {
86
191
  enumerable: true,
87
192
  configurable: true,
@@ -91,6 +196,30 @@ export class BaseAlchemySigner {
91
196
  return address;
92
197
  }
93
198
  });
199
+ /**
200
+ * Signs a raw message after hashing it.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * import { AlchemyWebSigner } from "@account-kit/signer";
205
+ *
206
+ * const signer = new AlchemyWebSigner({
207
+ * client: {
208
+ * connection: {
209
+ * rpcUrl: "/api/rpc",
210
+ * },
211
+ * iframeConfig: {
212
+ * iframeContainerId: "alchemy-signer-iframe-container",
213
+ * },
214
+ * },
215
+ * });
216
+ *
217
+ * const signature = await signer.signMessage("Hello, world!");
218
+ * ```
219
+ *
220
+ * @param {string} msg the message to be hashed and then signed
221
+ * @returns {Promise<string>} a promise that resolves to the signed message
222
+ */
94
223
  Object.defineProperty(this, "signMessage", {
95
224
  enumerable: true,
96
225
  configurable: true,
@@ -100,6 +229,35 @@ export class BaseAlchemySigner {
100
229
  return this.inner.signRawMessage(messageHash);
101
230
  }
102
231
  });
232
+ /**
233
+ * Signs a typed message by first hashing it and then signing the hashed message using the `signRawMessage` method.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * import { AlchemyWebSigner } from "@account-kit/signer";
238
+ *
239
+ * const signer = new AlchemyWebSigner({
240
+ * client: {
241
+ * connection: {
242
+ * rpcUrl: "/api/rpc",
243
+ * },
244
+ * iframeConfig: {
245
+ * iframeContainerId: "alchemy-signer-iframe-container",
246
+ * },
247
+ * },
248
+ * });
249
+ *
250
+ * const signature = await signer.signTypedData({
251
+ * domain: {},
252
+ * types: {},
253
+ * primaryType: "",
254
+ * message: {},
255
+ * });
256
+ * ```
257
+ *
258
+ * @param {TypedDataDefinition<TTypedData, TPrimaryType>} params The parameters for the typed message to be hashed and signed
259
+ * @returns {Promise<any>} A promise that resolves to the signed message
260
+ */
103
261
  Object.defineProperty(this, "signTypedData", {
104
262
  enumerable: true,
105
263
  configurable: true,
@@ -109,6 +267,36 @@ export class BaseAlchemySigner {
109
267
  return this.inner.signRawMessage(messageHash);
110
268
  }
111
269
  });
270
+ /**
271
+ * Serializes a transaction, signs it with a raw message, and then returns the serialized transaction with the signature.
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * import { AlchemyWebSigner } from "@account-kit/signer";
276
+ *
277
+ * const signer = new AlchemyWebSigner({
278
+ * client: {
279
+ * connection: {
280
+ * rpcUrl: "/api/rpc",
281
+ * },
282
+ * iframeConfig: {
283
+ * iframeContainerId: "alchemy-signer-iframe-container",
284
+ * },
285
+ * },
286
+ * });
287
+ *
288
+ * const tx = await signer.signTransaction({
289
+ * to: "0x1234",
290
+ * value: "0x1234",
291
+ * data: "0x1234",
292
+ * });
293
+ * ```
294
+ *
295
+ * @param {Transaction} tx the transaction to be serialized and signed
296
+ * @param {{serializer?: SerializeTransactionFn}} args options for serialization
297
+ * @param {() => Hex} [args.serializer] an optional serializer function. If not provided, the default `serializeTransaction` function will be used
298
+ * @returns {Promise<string>} a promise that resolves to the serialized transaction with the signature
299
+ */
112
300
  Object.defineProperty(this, "signTransaction", {
113
301
  enumerable: true,
114
302
  configurable: true,
@@ -125,6 +313,30 @@ export class BaseAlchemySigner {
125
313
  return serializeFn(tx, signature);
126
314
  }
127
315
  });
316
+ /**
317
+ * Unauthenticated call to look up a user's organizationId by email
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * import { AlchemyWebSigner } from "@account-kit/signer";
322
+ *
323
+ * const signer = new AlchemyWebSigner({
324
+ * client: {
325
+ * connection: {
326
+ * rpcUrl: "/api/rpc",
327
+ * },
328
+ * iframeConfig: {
329
+ * iframeContainerId: "alchemy-signer-iframe-container",
330
+ * },
331
+ * },
332
+ * });
333
+ *
334
+ * const result = await signer.getUser("foo@mail.com");
335
+ * ```
336
+ *
337
+ * @param {string} email the email to lookup
338
+ * @returns {Promise<{orgId: string}>} the organization id for the user if they exist
339
+ */
128
340
  Object.defineProperty(this, "getUser", {
129
341
  enumerable: true,
130
342
  configurable: true,
@@ -139,6 +351,30 @@ export class BaseAlchemySigner {
139
351
  };
140
352
  }
141
353
  });
354
+ /**
355
+ * Adds a passkey to the user's account
356
+ *
357
+ * @example
358
+ * ```ts
359
+ * import { AlchemyWebSigner } from "@account-kit/signer";
360
+ *
361
+ * const signer = new AlchemyWebSigner({
362
+ * client: {
363
+ * connection: {
364
+ * rpcUrl: "/api/rpc",
365
+ * },
366
+ * iframeConfig: {
367
+ * iframeContainerId: "alchemy-signer-iframe-container",
368
+ * },
369
+ * },
370
+ * });
371
+ *
372
+ * const result = await signer.addPasskey()
373
+ * ```
374
+ *
375
+ * @param {CredentialCreationOptions | undefined} params optional parameters for the passkey creation
376
+ * @returns {Promise<string[]>} an array of the authenticator ids added to the user
377
+ */
142
378
  Object.defineProperty(this, "addPasskey", {
143
379
  enumerable: true,
144
380
  configurable: true,
@@ -147,6 +383,33 @@ export class BaseAlchemySigner {
147
383
  return this.inner.addPasskey(params ?? {});
148
384
  }
149
385
  });
386
+ /**
387
+ * Used to export the wallet for a given user
388
+ * If the user is authenticated with an Email, this will return a seed phrase
389
+ * If the user is authenticated with a Passkey, this will return a private key
390
+ *
391
+ * @example
392
+ * ```ts
393
+ * import { AlchemyWebSigner } from "@account-kit/signer";
394
+ *
395
+ * const signer = new AlchemyWebSigner({
396
+ * client: {
397
+ * connection: {
398
+ * rpcUrl: "/api/rpc",
399
+ * },
400
+ * iframeConfig: {
401
+ * iframeContainerId: "alchemy-signer-iframe-container",
402
+ * },
403
+ * },
404
+ * });
405
+ *
406
+ * // the params passed to this are different based on the specific signer
407
+ * const result = signer.exportWallet()
408
+ * ```
409
+ *
410
+ * @param {unknown} params export wallet parameters
411
+ * @returns {boolean} true if the wallet was exported successfully
412
+ */
150
413
  Object.defineProperty(this, "exportWallet", {
151
414
  enumerable: true,
152
415
  configurable: true,
@@ -155,11 +418,38 @@ export class BaseAlchemySigner {
155
418
  return this.inner.exportWallet(params);
156
419
  }
157
420
  });
421
+ /**
422
+ * This method lets you adapt your AlchemySigner to a viem LocalAccount, which
423
+ * will let you use the signer as an EOA directly.
424
+ *
425
+ * @example
426
+ * ```ts
427
+ * import { AlchemyWebSigner } from "@account-kit/signer";
428
+ *
429
+ * const signer = new AlchemyWebSigner({
430
+ * client: {
431
+ * connection: {
432
+ * rpcUrl: "/api/rpc",
433
+ * },
434
+ * iframeConfig: {
435
+ * iframeContainerId: "alchemy-signer-iframe-container",
436
+ * },
437
+ * },
438
+ * });
439
+ *
440
+ * const account = signer.toViemAccount();
441
+ * ```
442
+ *
443
+ * @throws if your signer is not authenticated
444
+ * @returns {LocalAccount} a LocalAccount object that can be used with viem's wallet client
445
+ */
158
446
  Object.defineProperty(this, "toViemAccount", {
159
447
  enumerable: true,
160
448
  configurable: true,
161
449
  writable: true,
162
450
  value: () => {
451
+ // if we want this method to be synchronous, then we need to do this check here
452
+ // otherwise we can use the sessionManager to get the user
163
453
  if (!this.inner.getUser()) {
164
454
  throw new NotAuthenticatedError();
165
455
  }
@@ -192,6 +482,8 @@ export class BaseAlchemySigner {
192
482
  });
193
483
  this.sessionManager.setTemporarySession({ orgId });
194
484
  this.store.setState({ status: AlchemySignerStatus.AWAITING_EMAIL_AUTH });
485
+ // We wait for the session manager to emit a connected event if
486
+ // cross tab sessions are permitted
195
487
  return new Promise((resolve) => {
196
488
  const removeListener = this.sessionManager.on("connected", (session) => {
197
489
  resolve(session.user);
@@ -221,8 +513,17 @@ export class BaseAlchemySigner {
221
513
  writable: true,
222
514
  value: async (args) => {
223
515
  let user;
224
- if (args.createNew) {
516
+ const shouldCreateNew = async () => {
517
+ if ("email" in args) {
518
+ const existingUser = await this.getUser(args.email);
519
+ return existingUser == null;
520
+ }
521
+ return args.createNew;
522
+ };
523
+ if (await shouldCreateNew()) {
225
524
  const result = await this.inner.createAccount(args);
525
+ // account creation for passkeys returns the whoami response so we don't have to
526
+ // call it again after signup
226
527
  user = {
227
528
  address: result.address,
228
529
  userId: result.userId,
@@ -273,6 +574,9 @@ export class BaseAlchemySigner {
273
574
  user: null,
274
575
  status: AlchemySignerStatus.INITIALIZING,
275
576
  })));
577
+ // NOTE: it's important that the session manager share a client
578
+ // with the signer. The SessionManager leverages the Signer's client
579
+ // to manage session state.
276
580
  this.sessionManager = new SessionManager({
277
581
  ...sessionConfig,
278
582
  client: this.inner,
@@ -281,7 +585,9 @@ export class BaseAlchemySigner {
281
585
  user: null,
282
586
  status: AlchemySignerStatus.INITIALIZING,
283
587
  })));
588
+ // register listeners first
284
589
  this.registerListeners();
590
+ // then initialize so that we can catch those events
285
591
  this.sessionManager.initialize();
286
592
  }
287
593
  }
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/base.ts"],"names":[],"mappings":"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","sourcesContent":["import { takeBytes, type SmartAccountAuthenticator } from \"@aa-sdk/core\";\nimport {\n hashMessage,\n hashTypedData,\n keccak256,\n serializeTransaction,\n type CustomSource,\n type Hex,\n type LocalAccount,\n type SignableMessage,\n type TypedData,\n type TypedDataDefinition,\n} from \"viem\";\nimport { toAccount } from \"viem/accounts\";\nimport type { Mutate, StoreApi } from \"zustand\";\nimport { subscribeWithSelector } from \"zustand/middleware\";\nimport { createStore } from \"zustand/vanilla\";\nimport type { BaseSignerClient } from \"./client/base\";\nimport type { User } from \"./client/types\";\nimport { NotAuthenticatedError } from \"./errors.js\";\nimport {\n SessionManager,\n type SessionManagerParams,\n} from \"./session/manager.js\";\nimport type { AuthParams } from \"./signer\";\nimport {\n AlchemySignerStatus,\n type AlchemySignerEvent,\n type AlchemySignerEvents,\n} from \"./types.js\";\n\nexport interface BaseAlchemySignerParams<TClient extends BaseSignerClient> {\n client: TClient;\n sessionConfig?: Omit<SessionManagerParams, \"client\">;\n}\n\ntype AlchemySignerStore = {\n user: User | null;\n status: AlchemySignerStatus;\n};\n\ntype InternalStore = Mutate<\n StoreApi<AlchemySignerStore>,\n [[\"zustand/subscribeWithSelector\", never]]\n>;\n\n/**\n * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.\n * Implements the `SmartAccountAuthenticator` interface and handles various signer events.\n */\nexport abstract class BaseAlchemySigner<TClient extends BaseSignerClient>\n implements SmartAccountAuthenticator<AuthParams, User, TClient>\n{\n signerType: string = \"alchemy-signer\";\n inner: TClient;\n private sessionManager: SessionManager;\n private store: InternalStore;\n\n /**\n * Initializes an instance with the provided client and session configuration.\n * This function sets up the internal store, initializes the session manager,\n * registers listeners and initializes the session manager to manage session state.\n *\n * @param {BaseAlchemySignerParams<TClient>} param0 Object containing the client and session configuration\n * @param {TClient} param0.client The client instance to be used internally\n * @param {SessionConfig} param0.sessionConfig Configuration for managing sessions\n */\n constructor({ client, sessionConfig }: BaseAlchemySignerParams<TClient>) {\n this.inner = client;\n this.store = createStore(\n subscribeWithSelector(\n () =>\n ({\n user: null,\n status: AlchemySignerStatus.INITIALIZING,\n } satisfies AlchemySignerStore)\n )\n );\n // NOTE: it's important that the session manager share a client\n // with the signer. The SessionManager leverages the Signer's client\n // to manage session state.\n this.sessionManager = new SessionManager({\n ...sessionConfig,\n client: this.inner,\n });\n this.store = createStore(\n subscribeWithSelector(\n () =>\n ({\n user: null,\n status: AlchemySignerStatus.INITIALIZING,\n } satisfies AlchemySignerStore)\n )\n );\n // register listeners first\n this.registerListeners();\n // then initialize so that we can catch those events\n this.sessionManager.initialize();\n }\n\n /**\n * Allows you to subscribe to events emitted by the signer\n *\n * @param {AlchemySignerEvent} event the event to subscribe to\n * @param {AlchemySignerEvents[AlchemySignerEvent]} listener the function to run when the event is emitted\n * @returns {() => void} a function to remove the listener\n */\n on = <E extends AlchemySignerEvent>(\n event: E,\n listener: AlchemySignerEvents[E]\n ) => {\n // NOTE: we're using zustand here to handle this because we are able to use the fireImmediately\n // option which deals with a possible race condition where the listener is added after the event\n // is fired. In the Client and SessionManager we use EventEmitter because it's easier to handle internally\n switch (event) {\n case \"connected\":\n return this.store.subscribe(\n ({ status }) => status,\n (status) =>\n status === AlchemySignerStatus.CONNECTED &&\n (listener as AlchemySignerEvents[\"connected\"])(\n this.store.getState().user!\n ),\n { fireImmediately: true }\n );\n case \"disconnected\":\n return this.store.subscribe(\n ({ status }) => status,\n (status) =>\n status === AlchemySignerStatus.DISCONNECTED &&\n (listener as AlchemySignerEvents[\"disconnected\"])(),\n { fireImmediately: true }\n );\n case \"statusChanged\":\n return this.store.subscribe(\n ({ status }) => status,\n listener as AlchemySignerEvents[\"statusChanged\"],\n { fireImmediately: true }\n );\n default:\n throw new Error(`Uknown event type ${event}`);\n }\n };\n\n /**\n * Authenticate a user with either an email or a passkey and create a session for that user\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.authenticate({\n * type: \"email\",\n * email: \"foo@mail.com\",\n * });\n * ```\n *\n * @param {AuthParams} params - undefined if passkey login, otherwise an object with email and bundle to resolve\n * @returns {Promise<User>} the user that was authenticated\n */\n authenticate: (params: AuthParams) => Promise<User> = async (params) => {\n if (params.type === \"email\") {\n return this.authenticateWithEmail(params);\n }\n\n return this.authenticateWithPasskey(params);\n };\n\n /**\n * Clear a user session and log them out\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * await signer.disconnect();\n * ```\n *\n * @returns {Promise<void>} a promise that resolves when the user is logged out\n */\n disconnect: () => Promise<void> = async () => {\n await this.inner.disconnect();\n };\n\n /**\n * Gets the current logged in user\n * If a user has an ongoing session, it will use that session and\n * try to authenticate\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * // throws if not logged in\n * const user = await signer.getAuthDetails();\n * ```\n *\n * @throws if there is no user logged in\n * @returns {Promise<User>} the current user\n */\n getAuthDetails = async (): Promise<User> => {\n const sessionUser = await this.sessionManager.getSessionUser();\n if (sessionUser != null) {\n return sessionUser;\n }\n\n return this.inner.whoami();\n };\n\n /**\n * Retrieves the address of the current user by calling the `whoami` method on `this.inner`.\n *\n * @returns {Promise<string>} A promise that resolves to the address of the current user.\n */\n getAddress: () => Promise<`0x${string}`> = async () => {\n const { address } = await this.inner.whoami();\n\n return address;\n };\n\n /**\n * Signs a raw message after hashing it.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const signature = await signer.signMessage(\"Hello, world!\");\n * ```\n *\n * @param {string} msg the message to be hashed and then signed\n * @returns {Promise<string>} a promise that resolves to the signed message\n */\n signMessage: (msg: SignableMessage) => Promise<`0x${string}`> = async (\n msg\n ) => {\n const messageHash = hashMessage(msg);\n\n return this.inner.signRawMessage(messageHash);\n };\n\n /**\n * Signs a typed message by first hashing it and then signing the hashed message using the `signRawMessage` method.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const signature = await signer.signTypedData({\n * domain: {},\n * types: {},\n * primaryType: \"\",\n * message: {},\n * });\n * ```\n *\n * @param {TypedDataDefinition<TTypedData, TPrimaryType>} params The parameters for the typed message to be hashed and signed\n * @returns {Promise<any>} A promise that resolves to the signed message\n */\n signTypedData: <\n const TTypedData extends TypedData | { [key: string]: unknown },\n TPrimaryType extends keyof TTypedData | \"EIP712Domain\" = keyof TTypedData\n >(\n params: TypedDataDefinition<TTypedData, TPrimaryType>\n ) => Promise<Hex> = async (params) => {\n const messageHash = hashTypedData(params);\n\n return this.inner.signRawMessage(messageHash);\n };\n\n /**\n * Serializes a transaction, signs it with a raw message, and then returns the serialized transaction with the signature.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const tx = await signer.signTransaction({\n * to: \"0x1234\",\n * value: \"0x1234\",\n * data: \"0x1234\",\n * });\n * ```\n *\n * @param {Transaction} tx the transaction to be serialized and signed\n * @param {{serializer?: SerializeTransactionFn}} args options for serialization\n * @param {() => Hex} [args.serializer] an optional serializer function. If not provided, the default `serializeTransaction` function will be used\n * @returns {Promise<string>} a promise that resolves to the serialized transaction with the signature\n */\n signTransaction: CustomSource[\"signTransaction\"] = async (tx, args) => {\n const serializeFn = args?.serializer ?? serializeTransaction;\n const serializedTx = serializeFn(tx);\n const signatureHex = await this.inner.signRawMessage(\n keccak256(serializedTx)\n );\n\n const signature = {\n r: takeBytes(signatureHex, { count: 32 }),\n s: takeBytes(signatureHex, { count: 32, offset: 32 }),\n v: BigInt(takeBytes(signatureHex, { count: 1, offset: 64 })),\n };\n\n return serializeFn(tx, signature);\n };\n\n /**\n * Unauthenticated call to look up a user's organizationId by email\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.getUser(\"foo@mail.com\");\n * ```\n *\n * @param {string} email the email to lookup\n * @returns {Promise<{orgId: string}>} the organization id for the user if they exist\n */\n getUser: (email: string) => Promise<{ orgId: string } | null> = async (\n email\n ) => {\n const result = await this.inner.lookupUserByEmail(email);\n\n if (result.orgId == null) {\n return null;\n }\n\n return {\n orgId: result.orgId,\n };\n };\n\n /**\n * Adds a passkey to the user's account\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.addPasskey()\n * ```\n *\n * @param {CredentialCreationOptions | undefined} params optional parameters for the passkey creation\n * @returns {Promise<string[]>} an array of the authenticator ids added to the user\n */\n addPasskey: (params?: CredentialCreationOptions) => Promise<string[]> =\n async (params) => {\n return this.inner.addPasskey(params ?? {});\n };\n\n /**\n * Used to export the wallet for a given user\n * If the user is authenticated with an Email, this will return a seed phrase\n * If the user is authenticated with a Passkey, this will return a private key\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * // the params passed to this are different based on the specific signer\n * const result = signer.exportWallet()\n * ```\n *\n * @param {unknown} params export wallet parameters\n * @returns {boolean} true if the wallet was exported successfully\n */\n exportWallet: (\n params: Parameters<(typeof this.inner)[\"exportWallet\"]>[0]\n ) => Promise<boolean> = async (params) => {\n return this.inner.exportWallet(params);\n };\n\n /**\n * This method lets you adapt your AlchemySigner to a viem LocalAccount, which\n * will let you use the signer as an EOA directly.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const account = signer.toViemAccount();\n * ```\n *\n * @throws if your signer is not authenticated\n * @returns {LocalAccount} a LocalAccount object that can be used with viem's wallet client\n */\n toViemAccount = (): LocalAccount => {\n // if we want this method to be synchronous, then we need to do this check here\n // otherwise we can use the sessionManager to get the user\n if (!this.inner.getUser()) {\n throw new NotAuthenticatedError();\n }\n\n return toAccount({\n address: this.inner.getUser()!.address,\n signMessage: (msg) => this.signMessage(msg.message),\n signTypedData: <\n const typedData extends TypedData | Record<string, unknown>,\n primaryType extends keyof typedData | \"EIP712Domain\" = keyof typedData\n >(\n typedDataDefinition: TypedDataDefinition<typedData, primaryType>\n ) => this.signTypedData<typedData, primaryType>(typedDataDefinition),\n signTransaction: this.signTransaction,\n });\n };\n\n private authenticateWithEmail = async (\n params: Extract<AuthParams, { type: \"email\" }>\n ): Promise<User> => {\n if (\"email\" in params) {\n const existingUser = await this.getUser(params.email);\n\n const { orgId } = existingUser\n ? await this.inner.initEmailAuth({\n email: params.email,\n expirationSeconds: this.sessionManager.expirationTimeMs,\n redirectParams: params.redirectParams,\n })\n : await this.inner.createAccount({\n type: \"email\",\n email: params.email,\n expirationSeconds: this.sessionManager.expirationTimeMs,\n redirectParams: params.redirectParams,\n });\n\n this.sessionManager.setTemporarySession({ orgId });\n this.store.setState({ status: AlchemySignerStatus.AWAITING_EMAIL_AUTH });\n\n // We wait for the session manager to emit a connected event if\n // cross tab sessions are permitted\n return new Promise<User>((resolve) => {\n const removeListener = this.sessionManager.on(\n \"connected\",\n (session) => {\n resolve(session.user);\n removeListener();\n }\n );\n });\n } else {\n const temporarySession = params.orgId\n ? { orgId: params.orgId }\n : this.sessionManager.getTemporarySession();\n\n if (!temporarySession) {\n this.store.setState({ status: AlchemySignerStatus.DISCONNECTED });\n throw new Error(\"Could not find email auth init session!\");\n }\n\n const user = await this.inner.completeEmailAuth({\n bundle: params.bundle,\n orgId: temporarySession.orgId,\n });\n\n return user;\n }\n };\n\n private authenticateWithPasskey = async (\n args: Extract<AuthParams, { type: \"passkey\" }>\n ) => {\n let user: User;\n if (args.createNew) {\n const result = await this.inner.createAccount(args);\n // account creation for passkeys returns the whoami response so we don't have to\n // call it again after signup\n user = {\n address: result.address!,\n userId: result.userId!,\n orgId: result.orgId,\n };\n } else {\n user = await this.inner.lookupUserWithPasskey();\n if (!user) {\n this.store.setState({ status: AlchemySignerStatus.DISCONNECTED });\n throw new Error(\"No user found\");\n }\n }\n\n return user;\n };\n\n private registerListeners = () => {\n this.sessionManager.on(\"connected\", (session) => {\n this.store.setState({\n user: session.user,\n status: AlchemySignerStatus.CONNECTED,\n });\n });\n\n this.sessionManager.on(\"disconnected\", () => {\n this.store.setState({\n user: null,\n status: AlchemySignerStatus.DISCONNECTED,\n });\n });\n\n this.sessionManager.on(\"initialized\", () => {\n this.store.setState((state) => ({\n status: state.user\n ? AlchemySignerStatus.CONNECTED\n : AlchemySignerStatus.DISCONNECTED,\n }));\n });\n\n this.inner.on(\"authenticating\", () => {\n this.store.setState({ status: AlchemySignerStatus.AUTHENTICATING });\n });\n };\n}\n"]}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/base.ts"],"names":[],"mappings":"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","sourcesContent":["import { takeBytes, type SmartAccountAuthenticator } from \"@aa-sdk/core\";\nimport {\n hashMessage,\n hashTypedData,\n keccak256,\n serializeTransaction,\n type CustomSource,\n type Hex,\n type LocalAccount,\n type SignableMessage,\n type TypedData,\n type TypedDataDefinition,\n} from \"viem\";\nimport { toAccount } from \"viem/accounts\";\nimport type { Mutate, StoreApi } from \"zustand\";\nimport { subscribeWithSelector } from \"zustand/middleware\";\nimport { createStore } from \"zustand/vanilla\";\nimport type { BaseSignerClient } from \"./client/base\";\nimport type { User } from \"./client/types\";\nimport { NotAuthenticatedError } from \"./errors.js\";\nimport {\n SessionManager,\n type SessionManagerParams,\n} from \"./session/manager.js\";\nimport type { AuthParams } from \"./signer\";\nimport {\n AlchemySignerStatus,\n type AlchemySignerEvent,\n type AlchemySignerEvents,\n} from \"./types.js\";\n\nexport interface BaseAlchemySignerParams<TClient extends BaseSignerClient> {\n client: TClient;\n sessionConfig?: Omit<SessionManagerParams, \"client\">;\n}\n\ntype AlchemySignerStore = {\n user: User | null;\n status: AlchemySignerStatus;\n};\n\ntype InternalStore = Mutate<\n StoreApi<AlchemySignerStore>,\n [[\"zustand/subscribeWithSelector\", never]]\n>;\n\n/**\n * Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.\n * Implements the `SmartAccountAuthenticator` interface and handles various signer events.\n */\nexport abstract class BaseAlchemySigner<TClient extends BaseSignerClient>\n implements SmartAccountAuthenticator<AuthParams, User, TClient>\n{\n signerType: string = \"alchemy-signer\";\n inner: TClient;\n private sessionManager: SessionManager;\n private store: InternalStore;\n\n /**\n * Initializes an instance with the provided client and session configuration.\n * This function sets up the internal store, initializes the session manager,\n * registers listeners and initializes the session manager to manage session state.\n *\n * @param {BaseAlchemySignerParams<TClient>} param0 Object containing the client and session configuration\n * @param {TClient} param0.client The client instance to be used internally\n * @param {SessionConfig} param0.sessionConfig Configuration for managing sessions\n */\n constructor({ client, sessionConfig }: BaseAlchemySignerParams<TClient>) {\n this.inner = client;\n this.store = createStore(\n subscribeWithSelector(\n () =>\n ({\n user: null,\n status: AlchemySignerStatus.INITIALIZING,\n } satisfies AlchemySignerStore)\n )\n );\n // NOTE: it's important that the session manager share a client\n // with the signer. The SessionManager leverages the Signer's client\n // to manage session state.\n this.sessionManager = new SessionManager({\n ...sessionConfig,\n client: this.inner,\n });\n this.store = createStore(\n subscribeWithSelector(\n () =>\n ({\n user: null,\n status: AlchemySignerStatus.INITIALIZING,\n } satisfies AlchemySignerStore)\n )\n );\n // register listeners first\n this.registerListeners();\n // then initialize so that we can catch those events\n this.sessionManager.initialize();\n }\n\n /**\n * Allows you to subscribe to events emitted by the signer\n *\n * @param {AlchemySignerEvent} event the event to subscribe to\n * @param {AlchemySignerEvents[AlchemySignerEvent]} listener the function to run when the event is emitted\n * @returns {() => void} a function to remove the listener\n */\n on = <E extends AlchemySignerEvent>(\n event: E,\n listener: AlchemySignerEvents[E]\n ) => {\n // NOTE: we're using zustand here to handle this because we are able to use the fireImmediately\n // option which deals with a possible race condition where the listener is added after the event\n // is fired. In the Client and SessionManager we use EventEmitter because it's easier to handle internally\n switch (event) {\n case \"connected\":\n return this.store.subscribe(\n ({ status }) => status,\n (status) =>\n status === AlchemySignerStatus.CONNECTED &&\n (listener as AlchemySignerEvents[\"connected\"])(\n this.store.getState().user!\n ),\n { fireImmediately: true }\n );\n case \"disconnected\":\n return this.store.subscribe(\n ({ status }) => status,\n (status) =>\n status === AlchemySignerStatus.DISCONNECTED &&\n (listener as AlchemySignerEvents[\"disconnected\"])(),\n { fireImmediately: true }\n );\n case \"statusChanged\":\n return this.store.subscribe(\n ({ status }) => status,\n listener as AlchemySignerEvents[\"statusChanged\"],\n { fireImmediately: true }\n );\n default:\n throw new Error(`Uknown event type ${event}`);\n }\n };\n\n /**\n * Authenticate a user with either an email or a passkey and create a session for that user\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.authenticate({\n * type: \"email\",\n * email: \"foo@mail.com\",\n * });\n * ```\n *\n * @param {AuthParams} params - undefined if passkey login, otherwise an object with email and bundle to resolve\n * @returns {Promise<User>} the user that was authenticated\n */\n authenticate: (params: AuthParams) => Promise<User> = async (params) => {\n if (params.type === \"email\") {\n return this.authenticateWithEmail(params);\n }\n\n return this.authenticateWithPasskey(params);\n };\n\n /**\n * Clear a user session and log them out\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * await signer.disconnect();\n * ```\n *\n * @returns {Promise<void>} a promise that resolves when the user is logged out\n */\n disconnect: () => Promise<void> = async () => {\n await this.inner.disconnect();\n };\n\n /**\n * Gets the current logged in user\n * If a user has an ongoing session, it will use that session and\n * try to authenticate\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * // throws if not logged in\n * const user = await signer.getAuthDetails();\n * ```\n *\n * @throws if there is no user logged in\n * @returns {Promise<User>} the current user\n */\n getAuthDetails = async (): Promise<User> => {\n const sessionUser = await this.sessionManager.getSessionUser();\n if (sessionUser != null) {\n return sessionUser;\n }\n\n return this.inner.whoami();\n };\n\n /**\n * Retrieves the address of the current user by calling the `whoami` method on `this.inner`.\n *\n * @returns {Promise<string>} A promise that resolves to the address of the current user.\n */\n getAddress: () => Promise<`0x${string}`> = async () => {\n const { address } = await this.inner.whoami();\n\n return address;\n };\n\n /**\n * Signs a raw message after hashing it.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const signature = await signer.signMessage(\"Hello, world!\");\n * ```\n *\n * @param {string} msg the message to be hashed and then signed\n * @returns {Promise<string>} a promise that resolves to the signed message\n */\n signMessage: (msg: SignableMessage) => Promise<`0x${string}`> = async (\n msg\n ) => {\n const messageHash = hashMessage(msg);\n\n return this.inner.signRawMessage(messageHash);\n };\n\n /**\n * Signs a typed message by first hashing it and then signing the hashed message using the `signRawMessage` method.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const signature = await signer.signTypedData({\n * domain: {},\n * types: {},\n * primaryType: \"\",\n * message: {},\n * });\n * ```\n *\n * @param {TypedDataDefinition<TTypedData, TPrimaryType>} params The parameters for the typed message to be hashed and signed\n * @returns {Promise<any>} A promise that resolves to the signed message\n */\n signTypedData: <\n const TTypedData extends TypedData | Record<string, unknown>,\n TPrimaryType extends keyof TTypedData | \"EIP712Domain\" = keyof TTypedData\n >(\n params: TypedDataDefinition<TTypedData, TPrimaryType>\n ) => Promise<Hex> = async (params) => {\n const messageHash = hashTypedData(params);\n\n return this.inner.signRawMessage(messageHash);\n };\n\n /**\n * Serializes a transaction, signs it with a raw message, and then returns the serialized transaction with the signature.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const tx = await signer.signTransaction({\n * to: \"0x1234\",\n * value: \"0x1234\",\n * data: \"0x1234\",\n * });\n * ```\n *\n * @param {Transaction} tx the transaction to be serialized and signed\n * @param {{serializer?: SerializeTransactionFn}} args options for serialization\n * @param {() => Hex} [args.serializer] an optional serializer function. If not provided, the default `serializeTransaction` function will be used\n * @returns {Promise<string>} a promise that resolves to the serialized transaction with the signature\n */\n signTransaction: CustomSource[\"signTransaction\"] = async (tx, args) => {\n const serializeFn = args?.serializer ?? serializeTransaction;\n const serializedTx = serializeFn(tx);\n const signatureHex = await this.inner.signRawMessage(\n keccak256(serializedTx)\n );\n\n const signature = {\n r: takeBytes(signatureHex, { count: 32 }),\n s: takeBytes(signatureHex, { count: 32, offset: 32 }),\n v: BigInt(takeBytes(signatureHex, { count: 1, offset: 64 })),\n };\n\n return serializeFn(tx, signature);\n };\n\n /**\n * Unauthenticated call to look up a user's organizationId by email\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.getUser(\"foo@mail.com\");\n * ```\n *\n * @param {string} email the email to lookup\n * @returns {Promise<{orgId: string}>} the organization id for the user if they exist\n */\n getUser: (email: string) => Promise<{ orgId: string } | null> = async (\n email\n ) => {\n const result = await this.inner.lookupUserByEmail(email);\n\n if (result.orgId == null) {\n return null;\n }\n\n return {\n orgId: result.orgId,\n };\n };\n\n /**\n * Adds a passkey to the user's account\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const result = await signer.addPasskey()\n * ```\n *\n * @param {CredentialCreationOptions | undefined} params optional parameters for the passkey creation\n * @returns {Promise<string[]>} an array of the authenticator ids added to the user\n */\n addPasskey: (params?: CredentialCreationOptions) => Promise<string[]> =\n async (params) => {\n return this.inner.addPasskey(params ?? {});\n };\n\n /**\n * Used to export the wallet for a given user\n * If the user is authenticated with an Email, this will return a seed phrase\n * If the user is authenticated with a Passkey, this will return a private key\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * // the params passed to this are different based on the specific signer\n * const result = signer.exportWallet()\n * ```\n *\n * @param {unknown} params export wallet parameters\n * @returns {boolean} true if the wallet was exported successfully\n */\n exportWallet: (\n params: Parameters<(typeof this.inner)[\"exportWallet\"]>[0]\n ) => Promise<boolean> = async (params) => {\n return this.inner.exportWallet(params);\n };\n\n /**\n * This method lets you adapt your AlchemySigner to a viem LocalAccount, which\n * will let you use the signer as an EOA directly.\n *\n * @example\n * ```ts\n * import { AlchemyWebSigner } from \"@account-kit/signer\";\n *\n * const signer = new AlchemyWebSigner({\n * client: {\n * connection: {\n * rpcUrl: \"/api/rpc\",\n * },\n * iframeConfig: {\n * iframeContainerId: \"alchemy-signer-iframe-container\",\n * },\n * },\n * });\n *\n * const account = signer.toViemAccount();\n * ```\n *\n * @throws if your signer is not authenticated\n * @returns {LocalAccount} a LocalAccount object that can be used with viem's wallet client\n */\n toViemAccount = (): LocalAccount => {\n // if we want this method to be synchronous, then we need to do this check here\n // otherwise we can use the sessionManager to get the user\n if (!this.inner.getUser()) {\n throw new NotAuthenticatedError();\n }\n\n return toAccount({\n address: this.inner.getUser()!.address,\n signMessage: (msg) => this.signMessage(msg.message),\n signTypedData: <\n const typedData extends TypedData | Record<string, unknown>,\n primaryType extends keyof typedData | \"EIP712Domain\" = keyof typedData\n >(\n typedDataDefinition: TypedDataDefinition<typedData, primaryType>\n ) => this.signTypedData<typedData, primaryType>(typedDataDefinition),\n signTransaction: this.signTransaction,\n });\n };\n\n private authenticateWithEmail = async (\n params: Extract<AuthParams, { type: \"email\" }>\n ): Promise<User> => {\n if (\"email\" in params) {\n const existingUser = await this.getUser(params.email);\n\n const { orgId } = existingUser\n ? await this.inner.initEmailAuth({\n email: params.email,\n expirationSeconds: this.sessionManager.expirationTimeMs,\n redirectParams: params.redirectParams,\n })\n : await this.inner.createAccount({\n type: \"email\",\n email: params.email,\n expirationSeconds: this.sessionManager.expirationTimeMs,\n redirectParams: params.redirectParams,\n });\n\n this.sessionManager.setTemporarySession({ orgId });\n this.store.setState({ status: AlchemySignerStatus.AWAITING_EMAIL_AUTH });\n\n // We wait for the session manager to emit a connected event if\n // cross tab sessions are permitted\n return new Promise<User>((resolve) => {\n const removeListener = this.sessionManager.on(\n \"connected\",\n (session) => {\n resolve(session.user);\n removeListener();\n }\n );\n });\n } else {\n const temporarySession = params.orgId\n ? { orgId: params.orgId }\n : this.sessionManager.getTemporarySession();\n\n if (!temporarySession) {\n this.store.setState({ status: AlchemySignerStatus.DISCONNECTED });\n throw new Error(\"Could not find email auth init session!\");\n }\n\n const user = await this.inner.completeEmailAuth({\n bundle: params.bundle,\n orgId: temporarySession.orgId,\n });\n\n return user;\n }\n };\n\n private authenticateWithPasskey = async (\n args: Extract<AuthParams, { type: \"passkey\" }>\n ) => {\n let user: User;\n const shouldCreateNew = async () => {\n if (\"email\" in args) {\n const existingUser = await this.getUser(args.email);\n return existingUser == null;\n }\n\n return args.createNew;\n };\n\n if (await shouldCreateNew()) {\n const result = await this.inner.createAccount(\n args as Extract<\n AuthParams,\n { type: \"passkey\" } & ({ email: string } | { createNew: true })\n >\n );\n // account creation for passkeys returns the whoami response so we don't have to\n // call it again after signup\n user = {\n address: result.address!,\n userId: result.userId!,\n orgId: result.orgId,\n };\n } else {\n user = await this.inner.lookupUserWithPasskey();\n if (!user) {\n this.store.setState({ status: AlchemySignerStatus.DISCONNECTED });\n throw new Error(\"No user found\");\n }\n }\n\n return user;\n };\n\n private registerListeners = () => {\n this.sessionManager.on(\"connected\", (session) => {\n this.store.setState({\n user: session.user,\n status: AlchemySignerStatus.CONNECTED,\n });\n });\n\n this.sessionManager.on(\"disconnected\", () => {\n this.store.setState({\n user: null,\n status: AlchemySignerStatus.DISCONNECTED,\n });\n });\n\n this.sessionManager.on(\"initialized\", () => {\n this.store.setState((state) => ({\n status: state.user\n ? AlchemySignerStatus.CONNECTED\n : AlchemySignerStatus.DISCONNECTED,\n }));\n });\n\n this.inner.on(\"authenticating\", () => {\n this.store.setState({ status: AlchemySignerStatus.AUTHENTICATING });\n });\n };\n}\n"]}