@phantom/embedded-provider-core 1.0.0-beta.9 → 1.0.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.
package/dist/index.mjs CHANGED
@@ -1,139 +1,25 @@
1
1
  // src/embedded-provider.ts
2
- import { AddressType, PhantomClient } from "@phantom/client";
3
- import { randomUUID } from "@phantom/utils";
4
- import { base64urlEncode } from "@phantom/base64url";
5
- import bs582 from "bs58";
2
+ import { base64urlEncode, stringToBase64url } from "@phantom/base64url";
3
+ import { AddressType, PhantomClient, SpendingLimitError } from "@phantom/client";
6
4
  import {
7
- parseMessage,
8
- parseTransactionToBase64Url,
9
5
  parseSignMessageResponse,
10
- parseTransactionResponse
6
+ parseTransactionResponse,
7
+ parseToKmsTransaction
11
8
  } from "@phantom/parsers";
9
+ import { randomUUID } from "@phantom/utils";
10
+ import { Buffer } from "buffer";
11
+ import bs582 from "bs58";
12
12
 
13
13
  // src/constants.ts
14
14
  var AUTHENTICATOR_EXPIRATION_TIME_MS = 7 * 24 * 60 * 60 * 1e3;
15
15
  var AUTHENTICATOR_RENEWAL_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
16
-
17
- // src/auth/jwt-auth.ts
18
- var JWTAuth = class {
19
- async authenticate(options) {
20
- if (!options.jwtToken || typeof options.jwtToken !== "string") {
21
- throw new Error("Invalid JWT token: token must be a non-empty string");
22
- }
23
- const jwtParts = options.jwtToken.split(".");
24
- if (jwtParts.length !== 3) {
25
- throw new Error("Invalid JWT token format: token must have 3 parts separated by dots");
26
- }
27
- try {
28
- const response = await fetch("/api/auth/jwt", {
29
- method: "POST",
30
- headers: {
31
- "Content-Type": "application/json",
32
- Authorization: `Bearer ${options.jwtToken}`,
33
- "X-PHANTOM-APPID": options.appId
34
- },
35
- body: JSON.stringify({
36
- appId: options.appId,
37
- customAuthData: options.customAuthData
38
- })
39
- });
40
- if (!response.ok) {
41
- let errorMessage = `HTTP ${response.status}`;
42
- try {
43
- const errorData = await response.json();
44
- errorMessage = errorData.message || errorData.error || errorMessage;
45
- } catch {
46
- errorMessage = response.statusText || errorMessage;
47
- }
48
- switch (response.status) {
49
- case 400:
50
- throw new Error(`Invalid JWT authentication request: ${errorMessage}`);
51
- case 401:
52
- throw new Error(`JWT token is invalid or expired: ${errorMessage}`);
53
- case 403:
54
- throw new Error(`JWT authentication forbidden: ${errorMessage}`);
55
- case 404:
56
- throw new Error(`JWT authentication endpoint not found: ${errorMessage}`);
57
- case 429:
58
- throw new Error(`Too many JWT authentication requests: ${errorMessage}`);
59
- case 500:
60
- case 502:
61
- case 503:
62
- case 504:
63
- throw new Error(`JWT authentication server error: ${errorMessage}`);
64
- default:
65
- throw new Error(`JWT authentication failed: ${errorMessage}`);
66
- }
67
- }
68
- let result;
69
- try {
70
- result = await response.json();
71
- } catch (parseError) {
72
- throw new Error("Invalid response from JWT authentication server: response is not valid JSON");
73
- }
74
- if (!result.walletId) {
75
- throw new Error("Invalid JWT authentication response: missing walletId");
76
- }
77
- return {
78
- walletId: result.walletId,
79
- provider: "jwt",
80
- userInfo: result.userInfo || {}
81
- };
82
- } catch (error) {
83
- if (error instanceof TypeError && error.message.includes("fetch")) {
84
- throw new Error("JWT authentication failed: network error or invalid endpoint");
85
- }
86
- if (error instanceof Error) {
87
- throw error;
88
- }
89
- throw new Error(`JWT authentication error: ${String(error)}`);
90
- }
91
- }
92
- };
93
-
94
- // src/utils/session.ts
95
- function generateSessionId() {
96
- return "session_" + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + "_" + Date.now();
97
- }
98
-
99
- // src/utils/retry.ts
100
- async function retryWithBackoff(operation, operationName, logger, maxRetries = 3, baseDelay = 1e3) {
101
- let lastError;
102
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
103
- try {
104
- logger.log("EMBEDDED_PROVIDER", `Attempting ${operationName}`, {
105
- attempt,
106
- maxRetries
107
- });
108
- return await operation();
109
- } catch (error) {
110
- lastError = error;
111
- logger.warn("EMBEDDED_PROVIDER", `${operationName} failed`, {
112
- attempt,
113
- maxRetries,
114
- error: error instanceof Error ? error.message : String(error)
115
- });
116
- if (attempt === maxRetries) {
117
- logger.error("EMBEDDED_PROVIDER", `${operationName} failed after ${maxRetries} attempts`, {
118
- finalError: error instanceof Error ? error.message : String(error)
119
- });
120
- break;
121
- }
122
- const delay = baseDelay * Math.pow(2, attempt - 1);
123
- logger.log("EMBEDDED_PROVIDER", `Retrying ${operationName} in ${delay}ms`, {
124
- attempt: attempt + 1,
125
- delay
126
- });
127
- await new Promise((resolve) => setTimeout(resolve, delay));
128
- }
129
- }
130
- throw lastError;
131
- }
16
+ var EMBEDDED_PROVIDER_AUTH_TYPES = ["google", "apple", "phantom"];
132
17
 
133
18
  // src/chains/SolanaChain.ts
134
19
  import { EventEmitter } from "eventemitter3";
135
20
  import { NetworkId } from "@phantom/constants";
136
21
  import bs58 from "bs58";
22
+ import { parseSolanaSignedTransaction } from "@phantom/parsers";
137
23
  var EmbeddedSolanaChain = class {
138
24
  constructor(provider) {
139
25
  this.provider = provider;
@@ -170,8 +56,17 @@ var EmbeddedSolanaChain = class {
170
56
  publicKey: this._publicKey || ""
171
57
  };
172
58
  }
173
- signTransaction(_transaction) {
174
- return Promise.reject(new Error("signTransaction is not supported in embedded provider. Use signAndSendTransaction instead."));
59
+ async signTransaction(transaction) {
60
+ this.ensureConnected();
61
+ const result = await this.provider.signTransaction({
62
+ transaction,
63
+ networkId: this.currentNetworkId
64
+ });
65
+ const signedTransaction = parseSolanaSignedTransaction(result.rawTransaction);
66
+ if (!signedTransaction) {
67
+ throw new Error("Failed to parse signed transaction");
68
+ }
69
+ return signedTransaction;
175
70
  }
176
71
  async signAndSendTransaction(transaction) {
177
72
  this.ensureConnected();
@@ -184,8 +79,10 @@ var EmbeddedSolanaChain = class {
184
79
  }
185
80
  return { signature: result.hash };
186
81
  }
187
- signAllTransactions(_transactions) {
188
- return Promise.reject(new Error("signAllTransactions is not supported in embedded provider. Use signAndSendAllTransactions instead."));
82
+ async signAllTransactions(transactions) {
83
+ this.ensureConnected();
84
+ const results = await Promise.all(transactions.map((tx) => this.signTransaction(tx)));
85
+ return results;
189
86
  }
190
87
  async signAndSendAllTransactions(transactions) {
191
88
  const results = await Promise.all(transactions.map((tx) => this.signAndSendTransaction(tx)));
@@ -255,10 +152,8 @@ var EmbeddedSolanaChain = class {
255
152
  };
256
153
 
257
154
  // src/chains/EthereumChain.ts
258
- import { EventEmitter as EventEmitter2 } from "eventemitter3";
259
155
  import { NetworkId as NetworkId2, chainIdToNetworkId, networkIdToChainId } from "@phantom/constants";
260
- import { base64urlDecode } from "@phantom/base64url";
261
- import { Buffer } from "buffer";
156
+ import { EventEmitter as EventEmitter2 } from "eventemitter3";
262
157
  var EmbeddedEthereumChain = class {
263
158
  constructor(provider) {
264
159
  this.provider = provider;
@@ -316,18 +211,25 @@ var EmbeddedEthereumChain = class {
316
211
  });
317
212
  }
318
213
  async signTransaction(transaction) {
214
+ let networkId = this.currentNetworkId;
215
+ if (transaction.chainId) {
216
+ const numericChainId = typeof transaction.chainId === "number" ? transaction.chainId : parseInt(transaction.chainId, 16);
217
+ const txNetworkId = chainIdToNetworkId(numericChainId);
218
+ if (txNetworkId) {
219
+ networkId = txNetworkId;
220
+ }
221
+ }
319
222
  const result = await this.provider.signTransaction({
320
223
  transaction,
321
- networkId: this.currentNetworkId
224
+ networkId
322
225
  });
323
- try {
324
- const signatureBytes = base64urlDecode(result.rawTransaction);
325
- return "0x" + Buffer.from(signatureBytes).toString("hex");
326
- } catch (error) {
327
- return result.rawTransaction.startsWith("0x") ? result.rawTransaction : "0x" + result.rawTransaction;
328
- }
226
+ return result.rawTransaction;
329
227
  }
330
228
  async sendTransaction(transaction) {
229
+ if (transaction.chainId) {
230
+ const numericChainId = typeof transaction.chainId === "number" ? transaction.chainId : parseInt(transaction.chainId, 16);
231
+ await this.switchChain(numericChainId);
232
+ }
331
233
  const result = await this.provider.signAndSendTransaction({
332
234
  transaction,
333
235
  networkId: this.currentNetworkId
@@ -338,12 +240,13 @@ var EmbeddedEthereumChain = class {
338
240
  return result.hash;
339
241
  }
340
242
  switchChain(chainId) {
341
- const networkId = chainIdToNetworkId(chainId);
243
+ const numericChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? parseInt(chainId, 16) : parseInt(chainId, 10) : chainId;
244
+ const networkId = chainIdToNetworkId(numericChainId);
342
245
  if (!networkId) {
343
246
  throw new Error(`Unsupported chainId: ${chainId}`);
344
247
  }
345
248
  this.currentNetworkId = networkId;
346
- this.eventEmitter.emit("chainChanged", `0x${chainId.toString(16)}`);
249
+ this.eventEmitter.emit("chainChanged", `0x${numericChainId.toString(16)}`);
347
250
  return Promise.resolve();
348
251
  }
349
252
  getChainId() {
@@ -388,7 +291,7 @@ var EmbeddedEthereumChain = class {
388
291
  switch (args.method) {
389
292
  case "personal_sign": {
390
293
  const [message, _address] = args.params;
391
- const result = await this.provider.signMessage({
294
+ const result = await this.provider.signEthereumMessage({
392
295
  message,
393
296
  networkId: this.currentNetworkId
394
297
  });
@@ -396,10 +299,9 @@ var EmbeddedEthereumChain = class {
396
299
  }
397
300
  case "eth_signTypedData_v4": {
398
301
  const [_typedDataAddress, typedDataStr] = args.params;
399
- const _typedData = JSON.parse(typedDataStr);
400
- const typedDataResult = await this.provider.signMessage({
401
- message: typedDataStr,
402
- // Pass the stringified typed data as message
302
+ const typedData = JSON.parse(typedDataStr);
303
+ const typedDataResult = await this.provider.signTypedDataV4({
304
+ typedData,
403
305
  networkId: this.currentNetworkId
404
306
  });
405
307
  return typedDataResult.signature;
@@ -453,6 +355,45 @@ var EmbeddedEthereumChain = class {
453
355
  }
454
356
  };
455
357
 
358
+ // src/utils/retry.ts
359
+ async function retryWithBackoff(operation, operationName, logger, maxRetries = 3, baseDelay = 1e3) {
360
+ let lastError;
361
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
362
+ try {
363
+ logger.log("EMBEDDED_PROVIDER", `Attempting ${operationName}`, {
364
+ attempt,
365
+ maxRetries
366
+ });
367
+ return await operation();
368
+ } catch (error) {
369
+ lastError = error;
370
+ logger.warn("EMBEDDED_PROVIDER", `${operationName} failed`, {
371
+ attempt,
372
+ maxRetries,
373
+ error: error instanceof Error ? error.message : String(error)
374
+ });
375
+ if (attempt === maxRetries) {
376
+ logger.error("EMBEDDED_PROVIDER", `${operationName} failed after ${maxRetries} attempts`, {
377
+ finalError: error instanceof Error ? error.message : String(error)
378
+ });
379
+ break;
380
+ }
381
+ const delay = baseDelay * Math.pow(2, attempt - 1);
382
+ logger.log("EMBEDDED_PROVIDER", `Retrying ${operationName} in ${delay}ms`, {
383
+ attempt: attempt + 1,
384
+ delay
385
+ });
386
+ await new Promise((resolve) => setTimeout(resolve, delay));
387
+ }
388
+ }
389
+ throw lastError;
390
+ }
391
+
392
+ // src/utils/session.ts
393
+ function generateSessionId() {
394
+ return "session_" + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + "_" + Date.now();
395
+ }
396
+
456
397
  // src/embedded-provider.ts
457
398
  var EmbeddedProvider = class {
458
399
  constructor(config, platform, logger) {
@@ -469,9 +410,9 @@ var EmbeddedProvider = class {
469
410
  this.platform = platform;
470
411
  this.storage = platform.storage;
471
412
  this.authProvider = platform.authProvider;
413
+ this.phantomAppProvider = platform.phantomAppProvider;
472
414
  this.urlParamsAccessor = platform.urlParamsAccessor;
473
415
  this.stamper = platform.stamper;
474
- this.jwtAuth = new JWTAuth();
475
416
  this.solana = new EmbeddedSolanaChain(this);
476
417
  this.ethereum = new EmbeddedEthereumChain(this);
477
418
  this.logger.info("EMBEDDED_PROVIDER", "EmbeddedProvider initialized");
@@ -588,10 +529,16 @@ var EmbeddedProvider = class {
588
529
  }
589
530
  }
590
531
  if (session.status === "completed" && !this.isSessionValid(session)) {
591
- this.logger.warn("EMBEDDED_PROVIDER", "Session invalid due to authenticator expiration", {
592
- sessionId: session.sessionId,
593
- authenticatorExpiresAt: session.authenticatorExpiresAt
594
- });
532
+ this.logger.warn(
533
+ "EMBEDDED_PROVIDER",
534
+ "Session invalid due to authenticator expiration, will regenerate keypair",
535
+ {
536
+ sessionId: session.sessionId,
537
+ authenticatorExpiresAt: session.authenticatorExpiresAt,
538
+ currentTime: Date.now(),
539
+ expired: session.authenticatorExpiresAt < Date.now()
540
+ }
541
+ );
595
542
  await this.storage.clearSession();
596
543
  return null;
597
544
  }
@@ -606,7 +553,11 @@ var EmbeddedProvider = class {
606
553
  this.logger.log("EMBEDDED_PROVIDER", "Getting existing session");
607
554
  let session = await this.storage.getSession();
608
555
  session = await this.validateAndCleanSession(session);
609
- if (session && session.status === "completed") {
556
+ if (!session) {
557
+ this.logger.log("EMBEDDED_PROVIDER", "No existing session found");
558
+ return null;
559
+ }
560
+ if (session.status === "completed") {
610
561
  this.logger.info("EMBEDDED_PROVIDER", "Using existing completed session", {
611
562
  sessionId: session.sessionId,
612
563
  walletId: session.walletId
@@ -622,18 +573,19 @@ var EmbeddedProvider = class {
622
573
  const result = {
623
574
  walletId: this.walletId,
624
575
  addresses: this.addresses,
625
- status: "completed"
576
+ status: "completed",
577
+ authUserId: session.authUserId,
578
+ authProvider: session.authProvider
626
579
  };
627
580
  this.emit("connect", {
628
- walletId: this.walletId,
629
- addresses: this.addresses,
581
+ ...result,
630
582
  source: "existing-session"
631
583
  });
632
584
  return result;
633
585
  }
634
586
  this.logger.log("EMBEDDED_PROVIDER", "No completed session found, checking for redirect resume");
635
587
  if (this.authProvider.resumeAuthFromRedirect) {
636
- const authResult = this.authProvider.resumeAuthFromRedirect();
588
+ const authResult = this.authProvider.resumeAuthFromRedirect(session.authProvider);
637
589
  if (authResult) {
638
590
  this.logger.info("EMBEDDED_PROVIDER", "Resuming from redirect", {
639
591
  walletId: authResult.walletId,
@@ -665,13 +617,10 @@ var EmbeddedProvider = class {
665
617
  * This ensures only supported auth providers are used and required tokens are present.
666
618
  */
667
619
  validateAuthOptions(authOptions) {
668
- if (!authOptions)
669
- return;
670
- if (authOptions.provider && !["google", "apple", "jwt"].includes(authOptions.provider)) {
671
- throw new Error(`Invalid auth provider: ${authOptions.provider}. Must be "google", "apple", or "jwt"`);
672
- }
673
- if (authOptions.provider === "jwt" && !authOptions.jwtToken) {
674
- throw new Error("JWT token is required when using JWT authentication");
620
+ if (!EMBEDDED_PROVIDER_AUTH_TYPES.includes(authOptions.provider)) {
621
+ throw new Error(
622
+ `Invalid auth provider: ${authOptions.provider}. Must be ${EMBEDDED_PROVIDER_AUTH_TYPES.join(", ")}`
623
+ );
675
624
  }
676
625
  }
677
626
  /*
@@ -731,8 +680,7 @@ var EmbeddedProvider = class {
731
680
  addressCount: result.addresses.length
732
681
  });
733
682
  this.emit("connect", {
734
- walletId: result.walletId,
735
- addresses: result.addresses,
683
+ ...result,
736
684
  source: "auto-connect"
737
685
  });
738
686
  return;
@@ -750,40 +698,46 @@ var EmbeddedProvider = class {
750
698
  error: error instanceof Error ? error.message : "Auto-connect failed",
751
699
  source: "auto-connect"
752
700
  });
701
+ await this.storage.setShouldClearPreviousSession(true);
753
702
  }
754
703
  }
755
704
  /*
756
705
  * We use this method to initialize the stamper and create an organization for new sessions.
757
706
  * This is the first step when no existing session is found and we need to set up a new wallet.
758
707
  */
759
- async createOrganizationAndStamper() {
708
+ async initializeStamper() {
760
709
  this.logger.log("EMBEDDED_PROVIDER", "Initializing stamper");
761
- const stamperInfo = await this.stamper.init();
762
- this.logger.log("EMBEDDED_PROVIDER", "Stamper initialized", {
710
+ await this.stamper.init();
711
+ this.logger.log("EMBEDDED_PROVIDER", "Resetting keypair to avoid conflicts with existing keypairs");
712
+ const stamperInfo = await this.stamper.resetKeyPair();
713
+ this.logger.log("EMBEDDED_PROVIDER", "Stamper initialized with fresh keypair", {
763
714
  publicKey: stamperInfo.publicKey,
764
715
  keyId: stamperInfo.keyId,
765
716
  algorithm: this.stamper.algorithm
766
717
  });
767
- this.logger.log("EMBEDDED_PROVIDER", "Creating temporary PhantomClient");
768
- const tempClient = new PhantomClient(
769
- {
770
- apiBaseUrl: this.config.apiBaseUrl,
771
- headers: {
772
- ...this.platform.analyticsHeaders || {}
773
- }
774
- },
775
- this.stamper
776
- );
718
+ const expiresInMs = AUTHENTICATOR_EXPIRATION_TIME_MS;
719
+ this.logger.info("EMBEDDED_PROVIDER", "Stamper ready for auth flow with fresh keypair", {
720
+ publicKey: stamperInfo.publicKey,
721
+ keyId: stamperInfo.keyId
722
+ });
723
+ return { stamperInfo, expiresInMs };
724
+ }
725
+ async createOrganizationForAppWallet(stamperInfo, expiresInMs) {
726
+ const tempClient = new PhantomClient({
727
+ apiBaseUrl: this.config.apiBaseUrl,
728
+ headers: {
729
+ ...this.platform.analyticsHeaders || {}
730
+ }
731
+ });
777
732
  const platformName = this.platform.name || "unknown";
778
733
  const shortPubKey = stamperInfo.publicKey.slice(0, 8);
779
734
  const organizationName = `${this.config.appId.substring(0, 8)}-${platformName}-${shortPubKey}`;
780
- this.logger.log("EMBEDDED_PROVIDER", "Creating organization", {
735
+ this.logger.log("EMBEDDED_PROVIDER", "Creating organization for app-wallet", {
781
736
  organizationName,
782
737
  publicKey: stamperInfo.publicKey,
783
738
  platform: platformName
784
739
  });
785
740
  const base64urlPublicKey = base64urlEncode(bs582.decode(stamperInfo.publicKey));
786
- const expiresInMs = AUTHENTICATOR_EXPIRATION_TIME_MS;
787
741
  const username = `user-${randomUUID()}`;
788
742
  const { organizationId } = await tempClient.createOrganization(organizationName, [
789
743
  {
@@ -794,27 +748,25 @@ var EmbeddedProvider = class {
794
748
  authenticatorName: `auth-${shortPubKey}`,
795
749
  authenticatorKind: "keypair",
796
750
  publicKey: base64urlPublicKey,
797
- algorithm: "Ed25519"
798
- // Commented for now until KMS supports fully expirable organizations
799
- // expiresInMs: expiresInMs,
751
+ algorithm: "Ed25519",
752
+ expiresInMs
800
753
  }
801
754
  ]
802
755
  }
803
756
  ]);
804
- this.logger.info("EMBEDDED_PROVIDER", "Organization created", { organizationId });
805
- return { organizationId, stamperInfo, expiresInMs, username };
757
+ this.logger.info("EMBEDDED_PROVIDER", "Organization created for app-wallet", { organizationId });
758
+ return organizationId;
806
759
  }
807
760
  async connect(authOptions) {
808
761
  try {
809
762
  this.logger.info("EMBEDDED_PROVIDER", "Starting embedded provider connect", {
810
- authOptions: authOptions ? {
811
- provider: authOptions.provider,
812
- hasJwtToken: !!authOptions.jwtToken
813
- } : void 0
763
+ authOptions: {
764
+ provider: authOptions.provider
765
+ }
814
766
  });
815
767
  this.emit("connect_start", {
816
768
  source: "manual-connect",
817
- authOptions: authOptions ? { provider: authOptions.provider } : void 0
769
+ authOptions: { provider: authOptions.provider }
818
770
  });
819
771
  const existingResult = await this.tryExistingConnection(false);
820
772
  if (existingResult) {
@@ -823,23 +775,26 @@ var EmbeddedProvider = class {
823
775
  addressCount: existingResult.addresses.length
824
776
  });
825
777
  this.emit("connect", {
826
- walletId: existingResult.walletId,
827
- addresses: existingResult.addresses,
778
+ ...existingResult,
828
779
  source: "manual-existing"
829
780
  });
830
781
  return existingResult;
831
782
  }
832
783
  this.validateAuthOptions(authOptions);
833
- this.logger.info("EMBEDDED_PROVIDER", "No existing connection, creating new auth flow");
834
- const { organizationId, stamperInfo, expiresInMs, username } = await this.createOrganizationAndStamper();
835
- const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions, expiresInMs, username);
784
+ this.logger.info(
785
+ "EMBEDDED_PROVIDER",
786
+ "No existing connection available, creating new auth flow with fresh keypair"
787
+ );
788
+ const { stamperInfo, expiresInMs } = await this.initializeStamper();
789
+ const session = await this.handleAuthFlow(stamperInfo.publicKey, stamperInfo, authOptions, expiresInMs);
836
790
  if (!session) {
837
791
  return {
838
792
  addresses: [],
839
- status: "pending"
793
+ status: "pending",
794
+ authProvider: authOptions.provider
840
795
  };
841
796
  }
842
- if (!authOptions || authOptions.provider === "jwt" || this.config.embeddedWalletType === "app-wallet") {
797
+ if (this.config.embeddedWalletType === "app-wallet") {
843
798
  session.lastUsed = Date.now();
844
799
  await this.storage.saveSession(session);
845
800
  }
@@ -848,11 +803,12 @@ var EmbeddedProvider = class {
848
803
  const result = {
849
804
  walletId: this.walletId,
850
805
  addresses: this.addresses,
851
- status: "completed"
806
+ status: "completed",
807
+ authUserId: session?.authUserId,
808
+ authProvider: session?.authProvider
852
809
  };
853
810
  this.emit("connect", {
854
- walletId: this.walletId,
855
- addresses: this.addresses,
811
+ ...result,
856
812
  source: "manual"
857
813
  });
858
814
  return result;
@@ -893,8 +849,10 @@ var EmbeddedProvider = class {
893
849
  throw new Error(`Embedded wallet connection failed: ${String(error)}`);
894
850
  }
895
851
  }
896
- async disconnect() {
852
+ async disconnect(shouldClearPreviousSession = true) {
897
853
  const wasConnected = this.client !== null;
854
+ await this.storage.setShouldClearPreviousSession(shouldClearPreviousSession);
855
+ this.logger.log("EMBEDDED_PROVIDER", "Set flag to clear previous session on next login");
898
856
  await this.storage.clearSession();
899
857
  this.client = null;
900
858
  this.walletId = null;
@@ -915,12 +873,44 @@ var EmbeddedProvider = class {
915
873
  walletId: this.walletId,
916
874
  message: params.message
917
875
  });
918
- const parsedMessage = parseMessage(params.message);
919
876
  const session = await this.storage.getSession();
920
877
  const derivationIndex = session?.accountDerivationIndex ?? 0;
921
- const rawResponse = await this.client.signMessage({
878
+ const rawResponse = await this.client.signUtf8Message({
879
+ walletId: this.walletId,
880
+ message: params.message,
881
+ networkId: params.networkId,
882
+ derivationIndex
883
+ });
884
+ this.logger.info("EMBEDDED_PROVIDER", "Message signed successfully", {
885
+ walletId: this.walletId,
886
+ message: params.message
887
+ });
888
+ return parseSignMessageResponse(rawResponse, params.networkId);
889
+ }
890
+ async signEthereumMessage(params) {
891
+ if (!this.client || !this.walletId) {
892
+ throw new Error("Not connected");
893
+ }
894
+ await this.ensureValidAuthenticator();
895
+ this.logger.info("EMBEDDED_PROVIDER", "Signing message", {
896
+ walletId: this.walletId,
897
+ message: params.message
898
+ });
899
+ const looksLikeHex = (str) => /^0x[0-9a-fA-F]+$/.test(str);
900
+ const normalizedMessage = (() => {
901
+ if (looksLikeHex(params.message)) {
902
+ const hexPayload = params.message.slice(2);
903
+ const normalizedHex = hexPayload.length % 2 === 0 ? hexPayload : `0${hexPayload}`;
904
+ return Buffer.from(normalizedHex, "hex").toString("utf8");
905
+ }
906
+ return params.message;
907
+ })();
908
+ const base64UrlMessage = stringToBase64url(normalizedMessage);
909
+ const session = await this.storage.getSession();
910
+ const derivationIndex = session?.accountDerivationIndex ?? 0;
911
+ const rawResponse = await this.client.ethereumSignMessage({
922
912
  walletId: this.walletId,
923
- message: parsedMessage.base64url,
913
+ message: base64UrlMessage,
924
914
  networkId: params.networkId,
925
915
  derivationIndex
926
916
  });
@@ -930,6 +920,28 @@ var EmbeddedProvider = class {
930
920
  });
931
921
  return parseSignMessageResponse(rawResponse, params.networkId);
932
922
  }
923
+ async signTypedDataV4(params) {
924
+ if (!this.client || !this.walletId) {
925
+ throw new Error("Not connected");
926
+ }
927
+ await this.ensureValidAuthenticator();
928
+ this.logger.info("EMBEDDED_PROVIDER", "Signing typed data", {
929
+ walletId: this.walletId,
930
+ typedData: params.typedData
931
+ });
932
+ const session = await this.storage.getSession();
933
+ const derivationIndex = session?.accountDerivationIndex ?? 0;
934
+ const rawResponse = await this.client.ethereumSignTypedData({
935
+ walletId: this.walletId,
936
+ typedData: params.typedData,
937
+ networkId: params.networkId,
938
+ derivationIndex
939
+ });
940
+ this.logger.info("EMBEDDED_PROVIDER", "Typed data signed successfully", {
941
+ walletId: this.walletId
942
+ });
943
+ return parseSignMessageResponse(rawResponse, params.networkId);
944
+ }
933
945
  async signTransaction(params) {
934
946
  if (!this.client || !this.walletId) {
935
947
  throw new Error("Not connected");
@@ -939,7 +951,7 @@ var EmbeddedProvider = class {
939
951
  walletId: this.walletId,
940
952
  networkId: params.networkId
941
953
  });
942
- const parsedTransaction = await parseTransactionToBase64Url(params.transaction, params.networkId);
954
+ const parsedTransaction = await parseToKmsTransaction(params.transaction, params.networkId);
943
955
  const session = await this.storage.getSession();
944
956
  const derivationIndex = session?.accountDerivationIndex ?? 0;
945
957
  this.logger.log("EMBEDDED_PROVIDER", "Parsed transaction for signing", {
@@ -947,12 +959,20 @@ var EmbeddedProvider = class {
947
959
  transaction: parsedTransaction,
948
960
  derivationIndex
949
961
  });
962
+ const transactionPayload = parsedTransaction.parsed;
963
+ if (!transactionPayload) {
964
+ throw new Error("Failed to parse transaction: no valid encoding found");
965
+ }
966
+ const account = this.getAddressForNetwork(params.networkId);
967
+ if (!account) {
968
+ throw new Error(`No address found for network ${params.networkId}`);
969
+ }
950
970
  const rawResponse = await this.client.signTransaction({
951
971
  walletId: this.walletId,
952
- transaction: parsedTransaction.base64url,
972
+ transaction: transactionPayload,
953
973
  networkId: params.networkId,
954
974
  derivationIndex,
955
- account: this.getAddressForNetwork(params.networkId)
975
+ account
956
976
  });
957
977
  this.logger.info("EMBEDDED_PROVIDER", "Transaction signed successfully", {
958
978
  walletId: this.walletId,
@@ -970,7 +990,7 @@ var EmbeddedProvider = class {
970
990
  walletId: this.walletId,
971
991
  networkId: params.networkId
972
992
  });
973
- const parsedTransaction = await parseTransactionToBase64Url(params.transaction, params.networkId);
993
+ const parsedTransaction = await parseToKmsTransaction(params.transaction, params.networkId);
974
994
  const session = await this.storage.getSession();
975
995
  const derivationIndex = session?.accountDerivationIndex ?? 0;
976
996
  this.logger.log("EMBEDDED_PROVIDER", "Parsed transaction for signing", {
@@ -978,13 +998,29 @@ var EmbeddedProvider = class {
978
998
  transaction: parsedTransaction,
979
999
  derivationIndex
980
1000
  });
981
- const rawResponse = await this.client.signAndSendTransaction({
982
- walletId: this.walletId,
983
- transaction: parsedTransaction.base64url,
984
- networkId: params.networkId,
985
- derivationIndex,
986
- account: this.getAddressForNetwork(params.networkId)
987
- });
1001
+ const transactionPayload = parsedTransaction.parsed;
1002
+ if (!transactionPayload) {
1003
+ throw new Error("Failed to parse transaction: no valid encoding found");
1004
+ }
1005
+ const account = this.getAddressForNetwork(params.networkId);
1006
+ if (!account) {
1007
+ throw new Error(`No address found for network ${params.networkId}`);
1008
+ }
1009
+ let rawResponse;
1010
+ try {
1011
+ rawResponse = await this.client.signAndSendTransaction({
1012
+ walletId: this.walletId,
1013
+ transaction: transactionPayload,
1014
+ networkId: params.networkId,
1015
+ derivationIndex,
1016
+ account
1017
+ });
1018
+ } catch (error) {
1019
+ if (error instanceof SpendingLimitError) {
1020
+ this.emit("spending_limit_reached", { error });
1021
+ }
1022
+ throw error;
1023
+ }
988
1024
  this.logger.info("EMBEDDED_PROVIDER", "Transaction signed and sent successfully", {
989
1025
  walletId: this.walletId,
990
1026
  networkId: params.networkId,
@@ -1004,24 +1040,25 @@ var EmbeddedProvider = class {
1004
1040
  * It handles app-wallet creation directly or routes to JWT/redirect authentication for user-wallets.
1005
1041
  * Returns null for redirect flows since they don't complete synchronously.
1006
1042
  */
1007
- async handleAuthFlow(organizationId, stamperInfo, authOptions, expiresInMs, username) {
1043
+ async handleAuthFlow(publicKey, stamperInfo, authOptions, expiresInMs) {
1008
1044
  if (this.config.embeddedWalletType === "user-wallet") {
1009
1045
  this.logger.info("EMBEDDED_PROVIDER", "Creating user-wallet, routing authentication", {
1010
- authProvider: authOptions?.provider || "phantom-connect"
1046
+ authProvider: authOptions.provider
1011
1047
  });
1012
- if (authOptions?.provider === "jwt") {
1013
- return await this.handleJWTAuth(organizationId, stamperInfo, authOptions, expiresInMs, username);
1048
+ if (authOptions.provider === "phantom") {
1049
+ return await this.handlePhantomAuth(publicKey, stamperInfo, expiresInMs);
1014
1050
  } else {
1015
1051
  this.logger.info("EMBEDDED_PROVIDER", "Starting redirect-based authentication flow", {
1016
- organizationId,
1052
+ publicKey,
1017
1053
  provider: authOptions?.provider
1018
1054
  });
1019
- return await this.handleRedirectAuth(organizationId, stamperInfo, authOptions, username);
1055
+ return await this.handleRedirectAuth(publicKey, stamperInfo, authOptions);
1020
1056
  }
1021
1057
  } else {
1022
1058
  this.logger.info("EMBEDDED_PROVIDER", "Creating app-wallet", {
1023
- organizationId
1059
+ publicKey
1024
1060
  });
1061
+ const organizationId = await this.createOrganizationForAppWallet(stamperInfo, expiresInMs);
1025
1062
  const tempClient = new PhantomClient(
1026
1063
  {
1027
1064
  apiBaseUrl: this.config.apiBaseUrl,
@@ -1041,8 +1078,8 @@ var EmbeddedProvider = class {
1041
1078
  organizationId,
1042
1079
  appId: this.config.appId,
1043
1080
  stamperInfo,
1044
- authProvider: "app-wallet",
1045
- userInfo: { embeddedWalletType: this.config.embeddedWalletType },
1081
+ authProvider: "device",
1082
+ // For now app wallets have no auth provider.
1046
1083
  accountDerivationIndex: 0,
1047
1084
  // App wallets default to index 0
1048
1085
  status: "completed",
@@ -1050,8 +1087,7 @@ var EmbeddedProvider = class {
1050
1087
  lastUsed: now,
1051
1088
  authenticatorCreatedAt: now,
1052
1089
  authenticatorExpiresAt: Date.now() + expiresInMs,
1053
- lastRenewalAttempt: void 0,
1054
- username
1090
+ lastRenewalAttempt: void 0
1055
1091
  };
1056
1092
  await this.storage.saveSession(session);
1057
1093
  this.logger.info("EMBEDDED_PROVIDER", "App-wallet created successfully", { walletId, organizationId });
@@ -1059,43 +1095,56 @@ var EmbeddedProvider = class {
1059
1095
  }
1060
1096
  }
1061
1097
  /*
1062
- * We use this method to handle JWT-based authentication for user-wallets.
1063
- * It authenticates using the provided JWT token and creates a completed session.
1098
+ * We use this method to handle Phantom app-based authentication for user-wallets.
1099
+ * This method uses the PhantomAppProvider to authenticate via the browser extension or mobile app.
1100
+ *
1101
+ * NOTE: Mobile deeplink support is not yet implemented. If we wanted to support mobile deeplinks,
1102
+ * we would:
1103
+ * 1. Check if the app provider is available using phantomAppProvider.isAvailable()
1104
+ * 2. If not available, generate a deeplink (phantom://auth?...)
1105
+ * 3. Save a pending session before opening the deeplink
1106
+ * 4. Start a polling mechanism to check for auth completion
1107
+ * 5. Update the session when the mobile app completes the auth
1064
1108
  */
1065
- async handleJWTAuth(organizationId, stamperInfo, authOptions, expiresInMs, username) {
1066
- this.logger.info("EMBEDDED_PROVIDER", "Using JWT authentication flow");
1067
- if (!authOptions.jwtToken) {
1068
- this.logger.error("EMBEDDED_PROVIDER", "JWT token missing for JWT authentication");
1069
- throw new Error("JWT token is required for JWT authentication");
1109
+ async handlePhantomAuth(publicKey, stamperInfo, expiresInMs) {
1110
+ this.logger.info("EMBEDDED_PROVIDER", "Starting Phantom authentication flow");
1111
+ const isAvailable = this.phantomAppProvider.isAvailable();
1112
+ if (!isAvailable) {
1113
+ this.logger.error("EMBEDDED_PROVIDER", "Phantom app not available");
1114
+ throw new Error(
1115
+ "Phantom app is not available. Please install the Phantom browser extension or mobile app to use this authentication method."
1116
+ );
1070
1117
  }
1071
- this.logger.log("EMBEDDED_PROVIDER", "Starting JWT authentication");
1072
- const authResult = await this.jwtAuth.authenticate({
1073
- organizationId,
1118
+ this.logger.info("EMBEDDED_PROVIDER", "Phantom app detected, proceeding with authentication");
1119
+ const sessionId = generateSessionId();
1120
+ const authResult = await this.phantomAppProvider.authenticate({
1121
+ publicKey,
1074
1122
  appId: this.config.appId,
1075
- jwtToken: authOptions.jwtToken,
1076
- customAuthData: authOptions.customAuthData
1123
+ sessionId
1077
1124
  });
1078
- const walletId = authResult.walletId;
1079
- this.logger.info("EMBEDDED_PROVIDER", "JWT authentication completed", { walletId });
1125
+ this.logger.info("EMBEDDED_PROVIDER", "Phantom authentication completed", {
1126
+ walletId: authResult.walletId,
1127
+ organizationId: authResult.organizationId
1128
+ });
1129
+ const effectiveExpiresInMs = authResult.expiresInMs > 0 ? authResult.expiresInMs : expiresInMs;
1080
1130
  const now = Date.now();
1081
1131
  const session = {
1082
- sessionId: generateSessionId(),
1083
- walletId,
1084
- organizationId,
1132
+ sessionId,
1133
+ walletId: authResult.walletId,
1134
+ organizationId: authResult.organizationId,
1085
1135
  appId: this.config.appId,
1086
1136
  stamperInfo,
1087
- authProvider: authResult.provider,
1088
- userInfo: authResult.userInfo,
1137
+ authProvider: "phantom",
1089
1138
  accountDerivationIndex: authResult.accountDerivationIndex,
1090
1139
  status: "completed",
1091
1140
  createdAt: now,
1092
1141
  lastUsed: now,
1093
1142
  authenticatorCreatedAt: now,
1094
- authenticatorExpiresAt: Date.now() + expiresInMs,
1143
+ authenticatorExpiresAt: now + effectiveExpiresInMs,
1095
1144
  lastRenewalAttempt: void 0,
1096
- username
1145
+ authUserId: authResult.authUserId
1097
1146
  };
1098
- this.logger.log("EMBEDDED_PROVIDER", "Saving JWT session");
1147
+ this.logger.log("EMBEDDED_PROVIDER", "Saving Phantom session");
1099
1148
  await this.storage.saveSession(session);
1100
1149
  return session;
1101
1150
  }
@@ -1104,9 +1153,9 @@ var EmbeddedProvider = class {
1104
1153
  * It saves a temporary session before redirecting to prevent losing state during the redirect flow.
1105
1154
  * Session timestamp is updated before redirect to prevent race conditions.
1106
1155
  */
1107
- async handleRedirectAuth(organizationId, stamperInfo, authOptions, username) {
1156
+ async handleRedirectAuth(publicKey, stamperInfo, authOptions) {
1108
1157
  this.logger.info("EMBEDDED_PROVIDER", "Using Phantom Connect authentication flow (redirect-based)", {
1109
- provider: authOptions?.provider,
1158
+ provider: authOptions.provider,
1110
1159
  hasRedirectUrl: !!this.config.authOptions.redirectUrl,
1111
1160
  authUrl: this.config.authOptions.authUrl
1112
1161
  });
@@ -1114,13 +1163,13 @@ var EmbeddedProvider = class {
1114
1163
  const sessionId = generateSessionId();
1115
1164
  const tempSession = {
1116
1165
  sessionId,
1117
- walletId: `temp-${now}`,
1166
+ walletId: `temp-wallet-${now}`,
1167
+ // Temporary ID, will be updated after redirect
1168
+ organizationId: `temp-org-${now}`,
1118
1169
  // Temporary ID, will be updated after redirect
1119
- organizationId,
1120
1170
  appId: this.config.appId,
1121
1171
  stamperInfo,
1122
- authProvider: "phantom-connect",
1123
- userInfo: { provider: authOptions?.provider },
1172
+ authProvider: authOptions.provider,
1124
1173
  accountDerivationIndex: void 0,
1125
1174
  // Will be set when redirect completes
1126
1175
  status: "pending",
@@ -1128,8 +1177,7 @@ var EmbeddedProvider = class {
1128
1177
  lastUsed: now,
1129
1178
  authenticatorCreatedAt: now,
1130
1179
  authenticatorExpiresAt: now + AUTHENTICATOR_EXPIRATION_TIME_MS,
1131
- lastRenewalAttempt: void 0,
1132
- username: username || `user-${randomUUID()}`
1180
+ lastRenewalAttempt: void 0
1133
1181
  };
1134
1182
  this.logger.log("EMBEDDED_PROVIDER", "Saving temporary session before redirect", {
1135
1183
  sessionId: tempSession.sessionId,
@@ -1137,32 +1185,53 @@ var EmbeddedProvider = class {
1137
1185
  });
1138
1186
  tempSession.lastUsed = Date.now();
1139
1187
  await this.storage.saveSession(tempSession);
1188
+ const shouldClearPreviousSession = await this.storage.getShouldClearPreviousSession();
1140
1189
  this.logger.info("EMBEDDED_PROVIDER", "Starting Phantom Connect redirect", {
1141
- organizationId,
1190
+ publicKey,
1142
1191
  appId: this.config.appId,
1143
1192
  provider: authOptions?.provider,
1144
- authUrl: this.config.authOptions.authUrl
1193
+ authUrl: this.config.authOptions.authUrl,
1194
+ clearPreviousSession: shouldClearPreviousSession,
1195
+ allowRefresh: !shouldClearPreviousSession
1145
1196
  });
1146
1197
  const authResult = await this.authProvider.authenticate({
1147
- organizationId,
1198
+ publicKey,
1148
1199
  appId: this.config.appId,
1149
1200
  provider: authOptions?.provider,
1150
1201
  redirectUrl: this.config.authOptions.redirectUrl,
1151
- customAuthData: authOptions?.customAuthData,
1152
1202
  authUrl: this.config.authOptions.authUrl,
1153
- sessionId
1203
+ sessionId,
1204
+ // OAuth session management - defaults to allowing refresh unless user explicitly logged out
1205
+ clearPreviousSession: shouldClearPreviousSession,
1206
+ // true only after logout
1207
+ allowRefresh: !shouldClearPreviousSession
1208
+ // false only after logout
1154
1209
  });
1155
1210
  if (authResult && "walletId" in authResult) {
1156
1211
  this.logger.info("EMBEDDED_PROVIDER", "Authentication completed after redirect", {
1157
1212
  walletId: authResult.walletId,
1213
+ organizationId: authResult.organizationId,
1158
1214
  provider: authResult.provider
1159
1215
  });
1160
1216
  tempSession.walletId = authResult.walletId;
1217
+ tempSession.organizationId = authResult.organizationId;
1161
1218
  tempSession.authProvider = authResult.provider || tempSession.authProvider;
1162
1219
  tempSession.accountDerivationIndex = authResult.accountDerivationIndex;
1220
+ tempSession.authUserId = authResult.authUserId;
1163
1221
  tempSession.status = "completed";
1164
1222
  tempSession.lastUsed = Date.now();
1223
+ if (authResult.expiresInMs > 0) {
1224
+ const now2 = Date.now();
1225
+ tempSession.authenticatorCreatedAt = now2;
1226
+ tempSession.authenticatorExpiresAt = now2 + authResult.expiresInMs;
1227
+ this.logger.log("EMBEDDED_PROVIDER", "Updated authenticator expiration from immediate auth response", {
1228
+ expiresInMs: authResult.expiresInMs,
1229
+ expiresAt: new Date(tempSession.authenticatorExpiresAt).toISOString()
1230
+ });
1231
+ }
1165
1232
  await this.storage.saveSession(tempSession);
1233
+ await this.storage.setShouldClearPreviousSession(false);
1234
+ this.logger.log("EMBEDDED_PROVIDER", "Cleared logout flag after successful authentication");
1166
1235
  return tempSession;
1167
1236
  }
1168
1237
  this.logger.info("EMBEDDED_PROVIDER", "Redirect authentication initiated, waiting for redirect completion");
@@ -1175,16 +1244,31 @@ var EmbeddedProvider = class {
1175
1244
  }
1176
1245
  session.walletId = authResult.walletId;
1177
1246
  session.authProvider = authResult.provider || session.authProvider;
1247
+ session.organizationId = authResult.organizationId;
1178
1248
  session.accountDerivationIndex = authResult.accountDerivationIndex;
1249
+ session.authUserId = authResult.authUserId;
1179
1250
  session.status = "completed";
1180
1251
  session.lastUsed = Date.now();
1252
+ if (authResult.expiresInMs > 0) {
1253
+ const now = Date.now();
1254
+ session.authenticatorCreatedAt = now;
1255
+ session.authenticatorExpiresAt = now + authResult.expiresInMs;
1256
+ this.logger.log("EMBEDDED_PROVIDER", "Updated authenticator expiration from auth response", {
1257
+ expiresInMs: authResult.expiresInMs,
1258
+ expiresAt: new Date(session.authenticatorExpiresAt).toISOString()
1259
+ });
1260
+ }
1181
1261
  await this.storage.saveSession(session);
1262
+ await this.storage.setShouldClearPreviousSession(false);
1263
+ this.logger.log("EMBEDDED_PROVIDER", "Cleared logout flag after successful authentication");
1182
1264
  await this.initializeClientFromSession(session);
1183
1265
  await this.ensureValidAuthenticator();
1184
1266
  return {
1185
1267
  walletId: this.walletId,
1186
1268
  addresses: this.addresses,
1187
- status: "completed"
1269
+ status: "completed",
1270
+ authUserId: session.authUserId,
1271
+ authProvider: session.authProvider
1188
1272
  };
1189
1273
  }
1190
1274
  /*
@@ -1199,7 +1283,7 @@ var EmbeddedProvider = class {
1199
1283
  const now = Date.now();
1200
1284
  if (!session.authenticatorExpiresAt) {
1201
1285
  this.logger.warn("EMBEDDED_PROVIDER", "Session missing authenticator timing - treating as invalid session");
1202
- await this.disconnect();
1286
+ await this.disconnect(false);
1203
1287
  throw new Error("Invalid session - missing authenticator timing");
1204
1288
  }
1205
1289
  const timeUntilExpiry = session.authenticatorExpiresAt - now;
@@ -1209,86 +1293,9 @@ var EmbeddedProvider = class {
1209
1293
  });
1210
1294
  if (timeUntilExpiry <= 0) {
1211
1295
  this.logger.error("EMBEDDED_PROVIDER", "Authenticator has expired, disconnecting");
1212
- await this.disconnect();
1296
+ await this.disconnect(false);
1213
1297
  throw new Error("Authenticator expired");
1214
1298
  }
1215
- const renewalWindow = AUTHENTICATOR_RENEWAL_WINDOW_MS;
1216
- if (timeUntilExpiry <= renewalWindow) {
1217
- this.logger.info("EMBEDDED_PROVIDER", "Authenticator needs renewal", {
1218
- expiresAt: new Date(session.authenticatorExpiresAt).toISOString(),
1219
- timeUntilExpiry,
1220
- renewalWindow
1221
- });
1222
- try {
1223
- await this.renewAuthenticator(session);
1224
- this.logger.info("EMBEDDED_PROVIDER", "Authenticator renewed successfully");
1225
- } catch (error) {
1226
- this.logger.error("EMBEDDED_PROVIDER", "Failed to renew authenticator", {
1227
- error: error instanceof Error ? error.message : String(error)
1228
- });
1229
- }
1230
- }
1231
- }
1232
- /*
1233
- * We use this method to perform silent authenticator renewal.
1234
- * It generates a new keypair, creates a new authenticator, and switches to it.
1235
- */
1236
- async renewAuthenticator(session) {
1237
- if (!this.client) {
1238
- throw new Error("Client not initialized");
1239
- }
1240
- this.logger.info("EMBEDDED_PROVIDER", "Starting authenticator renewal");
1241
- try {
1242
- const newKeyInfo = await this.stamper.rotateKeyPair();
1243
- this.logger.log("EMBEDDED_PROVIDER", "Generated new keypair for renewal", {
1244
- newKeyId: newKeyInfo.keyId,
1245
- newPublicKey: newKeyInfo.publicKey
1246
- });
1247
- const base64urlPublicKey = base64urlEncode(bs582.decode(newKeyInfo.publicKey));
1248
- const expiresInMs = AUTHENTICATOR_EXPIRATION_TIME_MS;
1249
- let authenticatorResult;
1250
- try {
1251
- authenticatorResult = await this.client.createAuthenticator({
1252
- organizationId: session.organizationId,
1253
- username: session.username,
1254
- authenticatorName: `auth-${newKeyInfo.keyId.substring(0, 8)}`,
1255
- authenticator: {
1256
- authenticatorName: `auth-${newKeyInfo.keyId.substring(0, 8)}`,
1257
- authenticatorKind: "keypair",
1258
- publicKey: base64urlPublicKey,
1259
- algorithm: "Ed25519"
1260
- // Commented for now until KMS supports fully expiring organizations
1261
- // expiresInMs: expiresInMs,
1262
- },
1263
- replaceExpirable: true
1264
- });
1265
- } catch (error) {
1266
- this.logger.error("EMBEDDED_PROVIDER", "Failed to create new authenticator", {
1267
- error: error instanceof Error ? error.message : String(error)
1268
- });
1269
- await this.stamper.rollbackRotation();
1270
- throw new Error(
1271
- `Failed to create new authenticator: ${error instanceof Error ? error.message : String(error)}`
1272
- );
1273
- }
1274
- this.logger.info("EMBEDDED_PROVIDER", "Created new authenticator", {
1275
- authenticatorId: authenticatorResult.id
1276
- });
1277
- await this.stamper.commitRotation(authenticatorResult.id || "unknown");
1278
- const now = Date.now();
1279
- session.stamperInfo = newKeyInfo;
1280
- session.authenticatorCreatedAt = now;
1281
- session.authenticatorExpiresAt = Date.now() + expiresInMs;
1282
- session.lastRenewalAttempt = now;
1283
- await this.storage.saveSession(session);
1284
- this.logger.info("EMBEDDED_PROVIDER", "Authenticator renewal completed successfully", {
1285
- newKeyId: newKeyInfo.keyId,
1286
- expiresAt: new Date(Date.now() + expiresInMs).toISOString()
1287
- });
1288
- } catch (error) {
1289
- await this.stamper.rollbackRotation();
1290
- throw error;
1291
- }
1292
1299
  }
1293
1300
  /*
1294
1301
  * We use this method to initialize the PhantomClient and fetch wallet addresses from a completed session.
@@ -1320,10 +1327,10 @@ var EmbeddedProvider = class {
1320
1327
  export {
1321
1328
  AUTHENTICATOR_EXPIRATION_TIME_MS,
1322
1329
  AUTHENTICATOR_RENEWAL_WINDOW_MS,
1330
+ EMBEDDED_PROVIDER_AUTH_TYPES,
1323
1331
  EmbeddedEthereumChain,
1324
1332
  EmbeddedProvider,
1325
1333
  EmbeddedSolanaChain,
1326
- JWTAuth,
1327
1334
  generateSessionId,
1328
1335
  retryWithBackoff
1329
1336
  };