@phantom/browser-sdk 1.0.2 → 1.0.4

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.js CHANGED
@@ -30,11 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
- AddressType: () => import_client4.AddressType,
33
+ AddressType: () => import_client5.AddressType,
34
34
  BrowserSDK: () => BrowserSDK,
35
35
  DebugCategory: () => DebugCategory,
36
36
  DebugLevel: () => DebugLevel,
37
- NetworkId: () => import_constants5.NetworkId,
37
+ NetworkId: () => import_constants7.NetworkId,
38
+ PHANTOM_ICON: () => import_constants8.PHANTOM_ICON,
38
39
  debug: () => debug,
39
40
  detectBrowser: () => detectBrowser,
40
41
  getBrowserDisplayName: () => getBrowserDisplayName,
@@ -51,7 +52,7 @@ module.exports = __toCommonJS(src_exports);
51
52
  var import_client = require("@phantom/client");
52
53
 
53
54
  // src/providers/injected/index.ts
54
- var import_client3 = require("@phantom/client");
55
+ var import_client4 = require("@phantom/client");
55
56
 
56
57
  // src/debug.ts
57
58
  var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
@@ -128,12 +129,27 @@ var DebugCategory = {
128
129
  };
129
130
 
130
131
  // src/wallets/discovery.ts
131
- var import_client2 = require("@phantom/client");
132
+ var import_constants = require("@phantom/constants");
133
+ var import_client3 = require("@phantom/client");
132
134
  var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
133
135
  var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
134
136
  var import_solana = require("@phantom/browser-injected-sdk/solana");
135
137
  var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
136
138
  var import_auto_confirm = require("@phantom/browser-injected-sdk/auto-confirm");
139
+
140
+ // src/wallets/custom-wallets.ts
141
+ var import_client2 = require("@phantom/client");
142
+ var CUSTOM_WALLET_CONFIGS = [
143
+ {
144
+ id: "coinbase-wallet",
145
+ name: "Coinbase Wallet",
146
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI4IDU2YzE1LjQ2NCAwIDI4LTEyLjUzNiAyOC0yOFM0My40NjQgMCAyOCAwIDAgMTIuNTM2IDAgMjhzMTIuNTM2IDI4IDI4IDI4WiIgZmlsbD0iIzFCNTNFNCIvPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNyAyOGMwIDExLjU5OCA5LjQwMiAyMSAyMSAyMXMyMS05LjQwMiAyMS0yMVMzOS41OTggNyAyOCA3IDcgMTYuNDAyIDcgMjhabTE3LjIzNC02Ljc2NmEzIDMgMCAwIDAtMyAzdjcuNTMzYTMgMyAwIDAgMCAzIDNoNy41MzNhMyAzIDAgMCAwIDMtM3YtNy41MzNhMyAzIDAgMCAwLTMtM2gtNy41MzNaIiBmaWxsPSIjZmZmIi8+PC9zdmc+",
147
+ windowProperty: "coinbaseSolana",
148
+ addressTypes: [import_client2.AddressType.solana]
149
+ }
150
+ ];
151
+
152
+ // src/wallets/discovery.ts
137
153
  function generateWalletIdFromEIP6963(info) {
138
154
  if (info.rdns) {
139
155
  return info.rdns.split(".").reverse().join("-");
@@ -166,7 +182,7 @@ function processEIP6963Providers(providers) {
166
182
  id: walletId,
167
183
  name: info.name,
168
184
  icon: info.icon,
169
- addressTypes: [import_client2.AddressType.ethereum],
185
+ addressTypes: [import_client3.AddressType.ethereum],
170
186
  providers: {
171
187
  // EIP-6963 provider implements EIP-1193 interface (IEthereumChain)
172
188
  ethereum: provider
@@ -376,7 +392,7 @@ async function discoverSolanaWallets() {
376
392
  id: walletId,
377
393
  name: wallet.name,
378
394
  icon: wallet.icon,
379
- addressTypes: [import_client2.AddressType.solana],
395
+ addressTypes: [import_client3.AddressType.solana],
380
396
  providers: {
381
397
  // Cast to ISolanaChain - Wallet Standard wallets have compatible methods
382
398
  // The InjectedWalletSolanaChain wrapper will handle the actual method calls
@@ -397,6 +413,51 @@ async function discoverSolanaWallets() {
397
413
  walletNames: wallets.map((w) => w.name)
398
414
  };
399
415
  debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
416
+ const customWallets = discoverCustomSolanaWallets();
417
+ wallets.push(...customWallets);
418
+ return wallets;
419
+ }
420
+ function discoverCustomSolanaWallets() {
421
+ const wallets = [];
422
+ if (typeof window === "undefined") {
423
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet discovery skipped (not in browser environment)");
424
+ return wallets;
425
+ }
426
+ debug.log(DebugCategory.BROWSER_SDK, "Starting custom Solana wallet discovery", {
427
+ configCount: CUSTOM_WALLET_CONFIGS.length
428
+ });
429
+ for (const config of CUSTOM_WALLET_CONFIGS) {
430
+ if (!config.addressTypes.includes(import_client3.AddressType.solana)) {
431
+ continue;
432
+ }
433
+ const provider = window[config.windowProperty];
434
+ if (!provider) {
435
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet not found", {
436
+ walletId: config.id,
437
+ windowProperty: config.windowProperty
438
+ });
439
+ continue;
440
+ }
441
+ debug.log(DebugCategory.BROWSER_SDK, "Discovered custom Solana wallet", {
442
+ walletId: config.id,
443
+ walletName: config.name,
444
+ windowProperty: config.windowProperty
445
+ });
446
+ wallets.push({
447
+ id: config.id,
448
+ name: config.name,
449
+ icon: config.icon,
450
+ addressTypes: config.addressTypes,
451
+ providers: {
452
+ solana: provider
453
+ },
454
+ discovery: "custom"
455
+ });
456
+ }
457
+ debug.log(DebugCategory.BROWSER_SDK, "Custom Solana wallet discovery completed", {
458
+ discoveredCount: wallets.length,
459
+ walletIds: wallets.map((w) => w.id)
460
+ });
400
461
  return wallets;
401
462
  }
402
463
  function discoverPhantomWallet(addressTypes) {
@@ -407,10 +468,10 @@ function discoverPhantomWallet(addressTypes) {
407
468
  return null;
408
469
  }
409
470
  const plugins = [(0, import_browser_injected_sdk2.createExtensionPlugin)()];
410
- if (addressTypes.includes(import_client2.AddressType.solana)) {
471
+ if (addressTypes.includes(import_client3.AddressType.solana)) {
411
472
  plugins.push((0, import_solana.createSolanaPlugin)());
412
473
  }
413
- if (addressTypes.includes(import_client2.AddressType.ethereum)) {
474
+ if (addressTypes.includes(import_client3.AddressType.ethereum)) {
414
475
  plugins.push((0, import_ethereum.createEthereumPlugin)());
415
476
  }
416
477
  plugins.push((0, import_auto_confirm.createAutoConfirmPlugin)());
@@ -418,12 +479,11 @@ function discoverPhantomWallet(addressTypes) {
418
479
  return {
419
480
  id: "phantom",
420
481
  name: "Phantom",
421
- icon: void 0,
422
- // Icon will be rendered from icons package in UI components
482
+ icon: import_constants.PHANTOM_ICON,
423
483
  addressTypes,
424
484
  providers: {
425
- solana: addressTypes.includes(import_client2.AddressType.solana) ? phantomInstance.solana : void 0,
426
- ethereum: addressTypes.includes(import_client2.AddressType.ethereum) ? phantomInstance.ethereum : void 0
485
+ solana: addressTypes.includes(import_client3.AddressType.solana) ? phantomInstance.solana : void 0,
486
+ ethereum: addressTypes.includes(import_client3.AddressType.ethereum) ? phantomInstance.ethereum : void 0
427
487
  },
428
488
  isPhantom: true,
429
489
  phantomInstance,
@@ -488,6 +548,9 @@ async function discoverWallets(addressTypes) {
488
548
  return Array.from(walletMap.values());
489
549
  }
490
550
 
551
+ // src/wallets/registry.ts
552
+ var import_constants2 = require("@phantom/constants");
553
+
491
554
  // src/providers/injected/chains/InjectedWalletSolanaChain.ts
492
555
  var import_eventemitter3 = require("eventemitter3");
493
556
  var import_buffer = require("buffer");
@@ -495,61 +558,55 @@ var InjectedWalletSolanaChain = class {
495
558
  constructor(provider, walletId, walletName) {
496
559
  // Expose eventEmitter for testing - allows tests to trigger events directly
497
560
  this.eventEmitter = new import_eventemitter3.EventEmitter();
498
- this._connected = false;
499
561
  this._publicKey = null;
500
562
  this.provider = provider;
501
563
  this.walletId = walletId;
502
564
  this.walletName = walletName;
503
565
  this.setupEventListeners();
504
566
  }
505
- get connected() {
506
- return this._connected;
507
- }
508
567
  get publicKey() {
509
568
  return this._publicKey;
510
569
  }
570
+ get isConnected() {
571
+ return this.provider.isConnected || !!this._publicKey;
572
+ }
511
573
  async connect(options) {
512
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
513
- walletId: this.walletId,
514
- walletName: this.walletName,
515
- onlyIfTrusted: options?.onlyIfTrusted
516
- });
517
574
  try {
518
- const result = await this.provider.connect(options);
519
- if (typeof result === "string") {
520
- this._connected = true;
521
- this._publicKey = result;
522
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
575
+ await this.provider.connect(options);
576
+ const isConnected = this.provider.isConnected;
577
+ if (!isConnected || this.provider.publicKey === null) {
578
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Provider not connected after connect() call", {
523
579
  walletId: this.walletId,
524
580
  walletName: this.walletName,
525
- publicKey: result
581
+ providerConnected: isConnected,
582
+ providerPublicKey: this.provider.publicKey
526
583
  });
527
- return { publicKey: result };
528
- }
529
- if (typeof result === "object" && result !== null && "publicKey" in result) {
530
- this._connected = true;
531
- this._publicKey = result.publicKey;
532
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
584
+ throw new Error("Provider not connected after connect() call");
585
+ }
586
+ let publicKey;
587
+ const providerPublicKey = this.provider.publicKey;
588
+ if (typeof providerPublicKey === "string") {
589
+ publicKey = providerPublicKey;
590
+ } else if (providerPublicKey !== null && providerPublicKey !== void 0 && typeof providerPublicKey.toString === "function") {
591
+ publicKey = providerPublicKey.toString();
592
+ } else {
593
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Invalid publicKey format in provider state", {
533
594
  walletId: this.walletId,
534
595
  walletName: this.walletName,
535
- publicKey: result.publicKey
596
+ publicKeyType: typeof providerPublicKey
536
597
  });
537
- return result;
538
- }
539
- if (Array.isArray(result) && result.length > 0) {
540
- const firstAccount = result[0];
541
- if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
542
- this._connected = true;
543
- this._publicKey = firstAccount.address;
544
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
545
- walletId: this.walletId,
546
- walletName: this.walletName,
547
- publicKey: firstAccount.address
548
- });
549
- return { publicKey: firstAccount.address };
550
- }
598
+ throw new Error("Invalid publicKey format in provider state");
599
+ }
600
+ if (!publicKey || publicKey.length === 0) {
601
+ throw new Error("Empty publicKey from provider");
551
602
  }
552
- throw new Error("Unexpected connect result format");
603
+ this._publicKey = publicKey;
604
+ debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
605
+ walletId: this.walletId,
606
+ walletName: this.walletName,
607
+ publicKey
608
+ });
609
+ return { publicKey };
553
610
  } catch (error) {
554
611
  debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
555
612
  walletId: this.walletId,
@@ -566,7 +623,6 @@ var InjectedWalletSolanaChain = class {
566
623
  });
567
624
  try {
568
625
  await this.provider.disconnect();
569
- this._connected = false;
570
626
  this._publicKey = null;
571
627
  debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
572
628
  walletId: this.walletId,
@@ -702,28 +758,19 @@ var InjectedWalletSolanaChain = class {
702
758
  switchNetwork(_network) {
703
759
  return Promise.resolve();
704
760
  }
705
- getPublicKey() {
706
- return Promise.resolve(this._publicKey);
707
- }
708
- isConnected() {
709
- return this._connected;
710
- }
711
761
  setupEventListeners() {
712
762
  if (typeof this.provider.on === "function") {
713
763
  this.provider.on("connect", (publicKey) => {
714
- this._connected = true;
715
764
  this._publicKey = publicKey;
716
765
  this.eventEmitter.emit("connect", publicKey);
717
766
  });
718
767
  this.provider.on("disconnect", () => {
719
- this._connected = false;
720
768
  this._publicKey = null;
721
769
  this.eventEmitter.emit("disconnect");
722
770
  });
723
771
  this.provider.on("accountChanged", (publicKey) => {
724
- this._publicKey = publicKey;
725
- this._connected = publicKey != null && publicKey.length > 0;
726
- this.eventEmitter.emit("accountChanged", publicKey);
772
+ this._publicKey = publicKey ? publicKey : null;
773
+ this.eventEmitter.emit("accountChanged", this._publicKey);
727
774
  });
728
775
  }
729
776
  }
@@ -749,12 +796,12 @@ var WalletStandardSolanaAdapter = class {
749
796
  this.walletName = walletName;
750
797
  this.setupEventListeners();
751
798
  }
752
- get connected() {
753
- return this._publicKey !== null;
754
- }
755
799
  get publicKey() {
756
800
  return this._publicKey;
757
801
  }
802
+ get isConnected() {
803
+ return this._publicKey !== null;
804
+ }
758
805
  async connect(_options) {
759
806
  try {
760
807
  const connectFeature = this.wallet.features["standard:connect"];
@@ -966,12 +1013,6 @@ var WalletStandardSolanaAdapter = class {
966
1013
  async switchNetwork(_network) {
967
1014
  return Promise.resolve();
968
1015
  }
969
- getPublicKey() {
970
- return Promise.resolve(this._publicKey);
971
- }
972
- isConnected() {
973
- return this._publicKey !== null;
974
- }
975
1016
  /**
976
1017
  * Set up event listeners for Wallet Standard events
977
1018
  * Maps Wallet Standard "change" events to "accountChanged" events
@@ -1106,9 +1147,6 @@ var InjectedWalletEthereumChain = class {
1106
1147
  this.walletName = walletName;
1107
1148
  this.setupEventListeners();
1108
1149
  }
1109
- get connected() {
1110
- return this._connected;
1111
- }
1112
1150
  get chainId() {
1113
1151
  return this._chainId;
1114
1152
  }
@@ -1238,7 +1276,8 @@ var InjectedWalletEthereumChain = class {
1238
1276
  address
1239
1277
  });
1240
1278
  try {
1241
- const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
1279
+ const providerAny = this.provider;
1280
+ const providerConnected = (typeof providerAny.isConnected === "function" ? providerAny.isConnected() : false) || (typeof providerAny.connected === "boolean" ? providerAny.connected : false);
1242
1281
  if (!this._connected || this._accounts.length === 0 || !providerConnected) {
1243
1282
  debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
1244
1283
  walletId: this.walletId,
@@ -1552,8 +1591,7 @@ var InjectedWalletRegistry = class {
1552
1591
  const phantomWallet = {
1553
1592
  id: "phantom",
1554
1593
  name: "Phantom",
1555
- icon: "",
1556
- // Icon will be rendered from icons package in UI components
1594
+ icon: import_constants2.PHANTOM_ICON,
1557
1595
  addressTypes,
1558
1596
  providers: wrappedProviders,
1559
1597
  isPhantom: true,
@@ -1699,13 +1737,13 @@ var InjectedProvider = class {
1699
1737
  return provider;
1700
1738
  }
1701
1739
  get solana() {
1702
- return this.getChainProvider(import_client3.AddressType.solana, "solana", "Solana");
1740
+ return this.getChainProvider(import_client4.AddressType.solana, "solana", "Solana");
1703
1741
  }
1704
1742
  /**
1705
1743
  * Access to Ethereum chain operations
1706
1744
  */
1707
1745
  get ethereum() {
1708
- return this.getChainProvider(import_client3.AddressType.ethereum, "ethereum", "Ethereum");
1746
+ return this.getChainProvider(import_client4.AddressType.ethereum, "ethereum", "Ethereum");
1709
1747
  }
1710
1748
  validateAndSelectWallet(requestedWalletId) {
1711
1749
  if (!this.walletRegistry.has(requestedWalletId)) {
@@ -1746,7 +1784,7 @@ var InjectedProvider = class {
1746
1784
  this.setupEventListeners(walletInfo);
1747
1785
  }
1748
1786
  const connectedAddresses = [];
1749
- if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
1787
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers?.solana) {
1750
1788
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
1751
1789
  walletId: this.selectedWalletId,
1752
1790
  walletName: walletInfo.name,
@@ -1758,7 +1796,7 @@ var InjectedProvider = class {
1758
1796
  );
1759
1797
  const address = result.publicKey;
1760
1798
  connectedAddresses.push({
1761
- addressType: import_client3.AddressType.solana,
1799
+ addressType: import_client4.AddressType.solana,
1762
1800
  address
1763
1801
  });
1764
1802
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
@@ -1767,19 +1805,14 @@ var InjectedProvider = class {
1767
1805
  walletName: walletInfo.name
1768
1806
  });
1769
1807
  } catch (err) {
1770
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", {
1808
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, continuing with other chains", {
1771
1809
  error: err,
1772
1810
  walletId: this.selectedWalletId,
1773
1811
  walletName: walletInfo.name
1774
1812
  });
1775
- this.emit("connect_error", {
1776
- error: err instanceof Error ? err.message : "Failed to connect",
1777
- source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
1778
- });
1779
- throw err;
1780
1813
  }
1781
1814
  }
1782
- if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers?.ethereum) {
1815
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers?.ethereum) {
1783
1816
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
1784
1817
  walletId: this.selectedWalletId,
1785
1818
  walletName: walletInfo.name,
@@ -1795,7 +1828,7 @@ var InjectedProvider = class {
1795
1828
  if (accounts.length > 0) {
1796
1829
  connectedAddresses.push(
1797
1830
  ...accounts.map((address) => ({
1798
- addressType: import_client3.AddressType.ethereum,
1831
+ addressType: import_client4.AddressType.ethereum,
1799
1832
  address
1800
1833
  }))
1801
1834
  );
@@ -1806,16 +1839,11 @@ var InjectedProvider = class {
1806
1839
  });
1807
1840
  }
1808
1841
  } catch (err) {
1809
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", {
1842
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, continuing with other chains", {
1810
1843
  error: err,
1811
1844
  walletId: this.selectedWalletId,
1812
1845
  walletName: walletInfo.name
1813
1846
  });
1814
- this.emit("connect_error", {
1815
- error: err instanceof Error ? err.message : "Failed to connect",
1816
- source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
1817
- });
1818
- throw err;
1819
1847
  }
1820
1848
  }
1821
1849
  return connectedAddresses;
@@ -1875,7 +1903,8 @@ var InjectedProvider = class {
1875
1903
  this.emit("connect", {
1876
1904
  addresses: connectedAddresses,
1877
1905
  source: "manual-connect",
1878
- authUserId
1906
+ authUserId,
1907
+ walletId
1879
1908
  });
1880
1909
  return result;
1881
1910
  }
@@ -1887,12 +1916,13 @@ var InjectedProvider = class {
1887
1916
  if (authOptions.provider !== "injected") {
1888
1917
  throw new Error(`Invalid provider for injected connection: ${authOptions.provider}. Must be "injected"`);
1889
1918
  }
1919
+ const requestedWalletId = authOptions.walletId || "phantom";
1890
1920
  this.emit("connect_start", {
1891
1921
  source: "manual-connect",
1892
- providerType: "injected"
1922
+ providerType: "injected",
1923
+ walletId: requestedWalletId
1893
1924
  });
1894
1925
  try {
1895
- const requestedWalletId = authOptions.walletId || "phantom";
1896
1926
  const walletInfo = this.validateAndSelectWallet(requestedWalletId);
1897
1927
  const connectedAddresses = await this.connectToWallet(walletInfo);
1898
1928
  return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
@@ -1908,7 +1938,7 @@ var InjectedProvider = class {
1908
1938
  debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
1909
1939
  const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
1910
1940
  if (walletInfo?.providers) {
1911
- if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers.solana) {
1941
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers.solana) {
1912
1942
  try {
1913
1943
  await walletInfo.providers.solana.disconnect();
1914
1944
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
@@ -1916,7 +1946,7 @@ var InjectedProvider = class {
1916
1946
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
1917
1947
  }
1918
1948
  }
1919
- if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers.ethereum) {
1949
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers.ethereum) {
1920
1950
  try {
1921
1951
  await walletInfo.providers.ethereum.disconnect();
1922
1952
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
@@ -2012,7 +2042,8 @@ var InjectedProvider = class {
2012
2042
  this.emit("connect", {
2013
2043
  addresses: connectedAddresses,
2014
2044
  source: "auto-connect",
2015
- authUserId
2045
+ authUserId,
2046
+ walletId: this.selectedWalletId
2016
2047
  });
2017
2048
  debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
2018
2049
  addressCount: connectedAddresses.length,
@@ -2073,12 +2104,13 @@ var InjectedProvider = class {
2073
2104
  createSolanaConnectHandler(walletId, source) {
2074
2105
  return async (publicKey) => {
2075
2106
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2076
- const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client3.AddressType.solana);
2107
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client4.AddressType.solana);
2077
2108
  const authUserId = await this.getAuthUserId("Solana connect event");
2078
2109
  this.emit("connect", {
2079
2110
  addresses: newAddresses,
2080
2111
  source,
2081
- authUserId
2112
+ authUserId,
2113
+ walletId: this.selectedWalletId
2082
2114
  });
2083
2115
  };
2084
2116
  }
@@ -2089,7 +2121,7 @@ var InjectedProvider = class {
2089
2121
  return () => {
2090
2122
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2091
2123
  const state = this.getWalletState(walletId);
2092
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2124
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.solana);
2093
2125
  this.setWalletState(walletId, {
2094
2126
  connected: filteredAddresses.length > 0,
2095
2127
  addresses: filteredAddresses
@@ -2107,16 +2139,17 @@ var InjectedProvider = class {
2107
2139
  return async (publicKey) => {
2108
2140
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2109
2141
  if (publicKey) {
2110
- const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client3.AddressType.solana);
2142
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], import_client4.AddressType.solana);
2111
2143
  const authUserId = await this.getAuthUserId("Solana account changed event");
2112
2144
  this.emit("connect", {
2113
2145
  addresses: newAddresses,
2114
2146
  source: this.getAccountChangeSource(source),
2115
- authUserId
2147
+ authUserId,
2148
+ walletId: this.selectedWalletId
2116
2149
  });
2117
2150
  } else {
2118
2151
  const state = this.getWalletState(walletId);
2119
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
2152
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.solana);
2120
2153
  this.setWalletState(walletId, {
2121
2154
  connected: otherAddresses.length > 0,
2122
2155
  addresses: otherAddresses
@@ -2148,12 +2181,13 @@ var InjectedProvider = class {
2148
2181
  }
2149
2182
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2150
2183
  if (accounts.length > 0) {
2151
- const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client3.AddressType.ethereum);
2184
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client4.AddressType.ethereum);
2152
2185
  const authUserId = await this.getAuthUserId("Ethereum connect event");
2153
2186
  this.emit("connect", {
2154
2187
  addresses: newAddresses,
2155
2188
  source,
2156
- authUserId
2189
+ authUserId,
2190
+ walletId: this.selectedWalletId
2157
2191
  });
2158
2192
  }
2159
2193
  };
@@ -2165,7 +2199,7 @@ var InjectedProvider = class {
2165
2199
  return () => {
2166
2200
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2167
2201
  const state = this.getWalletState(walletId);
2168
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2202
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
2169
2203
  this.setWalletState(walletId, {
2170
2204
  connected: filteredAddresses.length > 0,
2171
2205
  addresses: filteredAddresses
@@ -2182,16 +2216,17 @@ var InjectedProvider = class {
2182
2216
  return async (accounts) => {
2183
2217
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2184
2218
  if (accounts && accounts.length > 0) {
2185
- const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client3.AddressType.ethereum);
2219
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, import_client4.AddressType.ethereum);
2186
2220
  const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2187
2221
  this.emit("connect", {
2188
2222
  addresses: newAddresses,
2189
2223
  source: this.getAccountChangeSource(source),
2190
- authUserId
2224
+ authUserId,
2225
+ walletId: this.selectedWalletId
2191
2226
  });
2192
2227
  } else {
2193
2228
  const state = this.getWalletState(walletId);
2194
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
2229
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
2195
2230
  this.setWalletState(walletId, {
2196
2231
  connected: otherAddresses.length > 0,
2197
2232
  addresses: otherAddresses
@@ -2385,7 +2420,9 @@ var InjectedProvider = class {
2385
2420
  this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2386
2421
  }
2387
2422
  /**
2388
- * Unified event listener setup for all wallet types (Phantom and external)
2423
+ * Unified event listener setup for all wallet types (Phantom and external).
2424
+ * Cleans up listeners for previously selected wallets to prevent stale events
2425
+ * from causing walletId flicker during connections.
2389
2426
  */
2390
2427
  setupEventListeners(walletInfo) {
2391
2428
  const walletId = this.selectedWalletId || "phantom";
@@ -2393,11 +2430,22 @@ var InjectedProvider = class {
2393
2430
  debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2394
2431
  return;
2395
2432
  }
2433
+ for (const existingWalletId of this.eventListenersSetup) {
2434
+ if (existingWalletId === walletId) {
2435
+ continue;
2436
+ }
2437
+ const cleanups = this.eventListenerCleanups.get(existingWalletId);
2438
+ if (cleanups) {
2439
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Cleaning up event listeners for wallet", { existingWalletId });
2440
+ cleanups.forEach((cleanup) => cleanup());
2441
+ }
2442
+ this.eventListenersSetup.delete(existingWalletId);
2443
+ }
2396
2444
  debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2397
- if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
2445
+ if (this.addressTypes.includes(import_client4.AddressType.solana) && walletInfo.providers?.solana) {
2398
2446
  this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2399
2447
  }
2400
- if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers?.ethereum) {
2448
+ if (this.addressTypes.includes(import_client4.AddressType.ethereum) && walletInfo.providers?.ethereum) {
2401
2449
  this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2402
2450
  }
2403
2451
  this.eventListenersSetup.add(walletId);
@@ -2541,7 +2589,7 @@ var BrowserURLParamsAccessor = class {
2541
2589
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
2542
2590
 
2543
2591
  // src/providers/embedded/adapters/auth.ts
2544
- var import_constants = require("@phantom/constants");
2592
+ var import_constants3 = require("@phantom/constants");
2545
2593
 
2546
2594
  // src/utils/browser-detection.ts
2547
2595
  function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
@@ -2706,7 +2754,7 @@ var BrowserAuthProvider = class {
2706
2754
  provider: phantomOptions.provider,
2707
2755
  authUrl: phantomOptions.authUrl
2708
2756
  });
2709
- const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
2757
+ const baseUrl = phantomOptions.authUrl || import_constants3.DEFAULT_AUTH_URL;
2710
2758
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
2711
2759
  const params = new URLSearchParams({
2712
2760
  public_key: phantomOptions.publicKey,
@@ -2716,9 +2764,10 @@ var BrowserAuthProvider = class {
2716
2764
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2717
2765
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2718
2766
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2719
- sdk_version: "1.0.2",
2767
+ sdk_version: "1.0.4",
2720
2768
  sdk_type: "browser",
2721
- platform: detectBrowser().name
2769
+ platform: detectBrowser().name,
2770
+ algorithm: phantomOptions.algorithm || import_constants3.DEFAULT_AUTHENTICATOR_ALGORITHM
2722
2771
  });
2723
2772
  if (phantomOptions.provider) {
2724
2773
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -2746,7 +2795,7 @@ var BrowserAuthProvider = class {
2746
2795
  resolve();
2747
2796
  });
2748
2797
  }
2749
- resumeAuthFromRedirect(provider) {
2798
+ async resumeAuthFromRedirect(provider) {
2750
2799
  try {
2751
2800
  const walletId = this.urlParamsAccessor.getParam("wallet_id");
2752
2801
  const sessionId = this.urlParamsAccessor.getParam("session_id");
@@ -2821,14 +2870,14 @@ var BrowserAuthProvider = class {
2821
2870
  }
2822
2871
  );
2823
2872
  }
2824
- return {
2873
+ return Promise.resolve({
2825
2874
  walletId,
2826
2875
  organizationId,
2827
2876
  accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
2828
2877
  expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
2829
2878
  authUserId: authUserId || void 0,
2830
2879
  provider
2831
- };
2880
+ });
2832
2881
  } catch (error) {
2833
2882
  sessionStorage.removeItem("phantom-auth-context");
2834
2883
  throw error;
@@ -2836,31 +2885,286 @@ var BrowserAuthProvider = class {
2836
2885
  }
2837
2886
  };
2838
2887
 
2839
- // src/providers/embedded/adapters/phantom-app.ts
2840
- var import_browser_injected_sdk4 = require("@phantom/browser-injected-sdk");
2841
-
2842
- // src/isPhantomLoginAvailable.ts
2843
- var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
2844
- async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2845
- const extensionInstalled = await waitForExtension(timeoutMs);
2846
- if (!extensionInstalled) {
2847
- return false;
2888
+ // src/providers/embedded/adapters/Auth2AuthProvider.ts
2889
+ var import_auth2 = require("@phantom/auth2");
2890
+ var Auth2AuthProvider = class {
2891
+ constructor(stamper, storage, urlParamsAccessor, auth2ProviderOptions, kmsClientOptions) {
2892
+ this.stamper = stamper;
2893
+ this.storage = storage;
2894
+ this.urlParamsAccessor = urlParamsAccessor;
2895
+ this.auth2ProviderOptions = auth2ProviderOptions;
2896
+ this.kms = new import_auth2.Auth2KmsRpcClient(stamper, kmsClientOptions);
2848
2897
  }
2849
- try {
2850
- if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2851
- return false;
2898
+ /** Redirect the browser. Extracted as a static method so tests can spy on it. */
2899
+ static navigate(url) {
2900
+ window.location.href = url;
2901
+ }
2902
+ /**
2903
+ * Builds the Auth2 /login/start URL and redirects the browser.
2904
+ *
2905
+ * Called by EmbeddedProvider.handleRedirectAuth() after the stamper has
2906
+ * already been initialized and a pending Session has been saved to storage.
2907
+ * We store the PKCE code_verifier and salt into that session so they survive
2908
+ * the page redirect without ever touching sessionStorage.
2909
+ */
2910
+ async authenticate(options) {
2911
+ if (!this.stamper.getKeyInfo()) {
2912
+ await this.stamper.init();
2913
+ }
2914
+ const keyPair = this.stamper.getCryptoKeyPair();
2915
+ if (!keyPair) {
2916
+ throw new Error("Stamper key pair not found.");
2917
+ }
2918
+ const codeVerifier = (0, import_auth2.createCodeVerifier)();
2919
+ const salt = (0, import_auth2.createSalt)();
2920
+ const session = await this.storage.getSession();
2921
+ if (!session) {
2922
+ throw new Error("Session not found.");
2923
+ }
2924
+ await this.storage.saveSession({ ...session, pkceCodeVerifier: codeVerifier, salt });
2925
+ const url = await (0, import_auth2.createConnectStartUrl)({
2926
+ keyPair,
2927
+ connectLoginUrl: this.auth2ProviderOptions.connectLoginUrl,
2928
+ clientId: this.auth2ProviderOptions.clientId,
2929
+ redirectUri: this.auth2ProviderOptions.redirectUri,
2930
+ sessionId: options.sessionId,
2931
+ provider: options.provider,
2932
+ codeVerifier,
2933
+ salt
2934
+ });
2935
+ Auth2AuthProvider.navigate(url);
2936
+ }
2937
+ /**
2938
+ * Processes the Auth2 callback after the browser returns from /login/start.
2939
+ *
2940
+ * Exchanges the authorization code for tokens, discovers the organization
2941
+ * and wallet via KMS RPC, then returns a completed AuthResult.
2942
+ */
2943
+ async resumeAuthFromRedirect(provider) {
2944
+ const code = this.urlParamsAccessor.getParam("code");
2945
+ if (!code) {
2946
+ return null;
2852
2947
  }
2853
- const response = await window.phantom.app.features();
2854
- if (!Array.isArray(response.features)) {
2855
- return false;
2948
+ if (!this.stamper.getKeyInfo()) {
2949
+ await this.stamper.init();
2856
2950
  }
2857
- return response.features.includes("phantom_login");
2858
- } catch (error) {
2859
- console.error("Error checking Phantom extension features", error);
2860
- return false;
2951
+ const session = await this.storage.getSession();
2952
+ if (!session) {
2953
+ throw new Error("Session not found.");
2954
+ }
2955
+ const codeVerifier = session?.pkceCodeVerifier;
2956
+ if (!codeVerifier) {
2957
+ return null;
2958
+ }
2959
+ const state = this.urlParamsAccessor.getParam("state");
2960
+ if (!state || state !== session.sessionId) {
2961
+ throw new Error("Missing or invalid Auth2 state parameter \u2014 possible CSRF attack.");
2962
+ }
2963
+ const error = this.urlParamsAccessor.getParam("error");
2964
+ if (error) {
2965
+ const description = this.urlParamsAccessor.getParam("error_description");
2966
+ throw new Error(`Auth2 callback error: ${description ?? error}`);
2967
+ }
2968
+ const { idToken, bearerToken, authUserId, expiresInMs } = await (0, import_auth2.exchangeAuthCode)({
2969
+ authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
2970
+ clientId: this.auth2ProviderOptions.clientId,
2971
+ redirectUri: this.auth2ProviderOptions.redirectUri,
2972
+ code,
2973
+ codeVerifier
2974
+ });
2975
+ this.stamper.idToken = idToken;
2976
+ this.stamper.salt = session?.salt;
2977
+ await this.storage.saveSession({
2978
+ ...session,
2979
+ status: "completed",
2980
+ bearerToken,
2981
+ authUserId,
2982
+ pkceCodeVerifier: void 0,
2983
+ // no longer needed after code exchange
2984
+ salt: void 0
2985
+ // no longer needed after nonce binding is complete
2986
+ });
2987
+ const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
2988
+ return {
2989
+ walletId,
2990
+ organizationId,
2991
+ provider,
2992
+ accountDerivationIndex: 0,
2993
+ // discoverWalletId uses derivation index of 0.
2994
+ expiresInMs,
2995
+ authUserId,
2996
+ bearerToken
2997
+ };
2861
2998
  }
2862
- }
2863
- async function waitForExtension(timeoutMs) {
2999
+ };
3000
+
3001
+ // src/providers/embedded/adapters/Auth2Stamper.ts
3002
+ var import_bs582 = __toESM(require("bs58"));
3003
+ var import_base64url = require("@phantom/base64url");
3004
+ var import_sdk_types = require("@phantom/sdk-types");
3005
+ var STORE_NAME = "crypto-keys";
3006
+ var ACTIVE_KEY = "auth2-p256-signing-key";
3007
+ var Auth2Stamper = class {
3008
+ /**
3009
+ * @param dbName - IndexedDB database name (use a unique name per app to
3010
+ * avoid key collisions with other stampers, e.g. `phantom-auth2-<appId>`).
3011
+ */
3012
+ constructor(dbName) {
3013
+ this.dbName = dbName;
3014
+ this.db = null;
3015
+ this.keyPair = null;
3016
+ this._keyInfo = null;
3017
+ this.algorithm = import_sdk_types.Algorithm.secp256r1;
3018
+ this.type = "PKI";
3019
+ }
3020
+ async init() {
3021
+ await this.openDB();
3022
+ const stored = await this.loadKeyPair();
3023
+ if (stored) {
3024
+ this.keyPair = stored.keyPair;
3025
+ this._keyInfo = stored.keyInfo;
3026
+ return this._keyInfo;
3027
+ }
3028
+ return this.generateAndStore();
3029
+ }
3030
+ getKeyInfo() {
3031
+ return this._keyInfo;
3032
+ }
3033
+ getCryptoKeyPair() {
3034
+ return this.keyPair;
3035
+ }
3036
+ async stamp(params) {
3037
+ if (!this.keyPair || !this._keyInfo) {
3038
+ throw new Error("Auth2Stamper not initialized. Call init() first.");
3039
+ }
3040
+ const signatureRaw = await crypto.subtle.sign(
3041
+ { name: "ECDSA", hash: "SHA-256" },
3042
+ this.keyPair.privateKey,
3043
+ new Uint8Array(params.data)
3044
+ );
3045
+ const rawPublicKey = import_bs582.default.decode(this._keyInfo.publicKey);
3046
+ if (this.idToken === void 0 || this.salt === void 0) {
3047
+ throw new Error("Auth2Stamper not initialized with idToken or salt.");
3048
+ }
3049
+ const stampData = {
3050
+ kind: "OIDC",
3051
+ idToken: this.idToken,
3052
+ publicKey: (0, import_base64url.base64urlEncode)(rawPublicKey),
3053
+ algorithm: "Secp256r1",
3054
+ salt: this.salt,
3055
+ signature: (0, import_base64url.base64urlEncode)(new Uint8Array(signatureRaw))
3056
+ };
3057
+ return (0, import_base64url.base64urlEncode)(new TextEncoder().encode(JSON.stringify(stampData)));
3058
+ }
3059
+ async resetKeyPair() {
3060
+ await this.clearStoredKey();
3061
+ this.keyPair = null;
3062
+ this._keyInfo = null;
3063
+ return this.generateAndStore();
3064
+ }
3065
+ async clear() {
3066
+ await this.clearStoredKey();
3067
+ this.keyPair = null;
3068
+ this._keyInfo = null;
3069
+ }
3070
+ // Auth2 doesn't use key rotation; provide minimal no-op implementations.
3071
+ async rotateKeyPair() {
3072
+ return this.init();
3073
+ }
3074
+ // eslint-disable-next-line @typescript-eslint/require-await
3075
+ async commitRotation(authenticatorId) {
3076
+ if (this._keyInfo) {
3077
+ this._keyInfo.authenticatorId = authenticatorId;
3078
+ }
3079
+ }
3080
+ async rollbackRotation() {
3081
+ }
3082
+ async generateAndStore() {
3083
+ const keyPair = await crypto.subtle.generateKey(
3084
+ { name: "ECDSA", namedCurve: "P-256" },
3085
+ false,
3086
+ // non-extractable — private key never leaves Web Crypto
3087
+ ["sign", "verify"]
3088
+ );
3089
+ const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
3090
+ const publicKeyBase58 = import_bs582.default.encode(rawPublicKey);
3091
+ const keyIdBuffer = await crypto.subtle.digest("SHA-256", rawPublicKey.buffer);
3092
+ const keyId = (0, import_base64url.base64urlEncode)(new Uint8Array(keyIdBuffer)).substring(0, 16);
3093
+ this.keyPair = keyPair;
3094
+ this._keyInfo = {
3095
+ keyId,
3096
+ publicKey: publicKeyBase58,
3097
+ createdAt: Date.now()
3098
+ };
3099
+ await this.storeKeyPair(keyPair, this._keyInfo);
3100
+ return this._keyInfo;
3101
+ }
3102
+ async openDB() {
3103
+ return new Promise((resolve, reject) => {
3104
+ const request = indexedDB.open(this.dbName, 1);
3105
+ request.onsuccess = () => {
3106
+ this.db = request.result;
3107
+ resolve();
3108
+ };
3109
+ request.onerror = () => reject(request.error);
3110
+ request.onupgradeneeded = (event) => {
3111
+ const db = event.target.result;
3112
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
3113
+ db.createObjectStore(STORE_NAME);
3114
+ }
3115
+ };
3116
+ });
3117
+ }
3118
+ async loadKeyPair() {
3119
+ return new Promise((resolve, reject) => {
3120
+ if (!this.db) {
3121
+ throw new Error("Database not initialized");
3122
+ }
3123
+ const request = this.db.transaction([STORE_NAME], "readonly").objectStore(STORE_NAME).get(ACTIVE_KEY);
3124
+ request.onsuccess = () => {
3125
+ resolve(request.result ?? null);
3126
+ };
3127
+ request.onerror = () => {
3128
+ reject(request.error);
3129
+ };
3130
+ });
3131
+ }
3132
+ async storeKeyPair(keyPair, keyInfo) {
3133
+ return new Promise((resolve, reject) => {
3134
+ if (!this.db) {
3135
+ throw new Error("Database not initialized");
3136
+ }
3137
+ const request = this.db.transaction([STORE_NAME], "readwrite").objectStore(STORE_NAME).put({ keyPair, keyInfo }, ACTIVE_KEY);
3138
+ request.onsuccess = () => {
3139
+ resolve();
3140
+ };
3141
+ request.onerror = () => {
3142
+ reject(request.error);
3143
+ };
3144
+ });
3145
+ }
3146
+ async clearStoredKey() {
3147
+ return new Promise((resolve, reject) => {
3148
+ if (!this.db) {
3149
+ throw new Error("Database not initialized");
3150
+ }
3151
+ const request = this.db.transaction([STORE_NAME], "readwrite").objectStore(STORE_NAME).delete(ACTIVE_KEY);
3152
+ request.onsuccess = () => {
3153
+ resolve();
3154
+ };
3155
+ request.onerror = () => {
3156
+ reject(request.error);
3157
+ };
3158
+ });
3159
+ }
3160
+ };
3161
+
3162
+ // src/providers/embedded/adapters/phantom-app.ts
3163
+ var import_browser_injected_sdk4 = require("@phantom/browser-injected-sdk");
3164
+
3165
+ // src/waitForPhantomExtension.ts
3166
+ var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
3167
+ async function waitForPhantomExtension(timeoutMs = 3e3) {
2864
3168
  return new Promise((resolve) => {
2865
3169
  const startTime = Date.now();
2866
3170
  const checkInterval = 100;
@@ -2883,6 +3187,27 @@ async function waitForExtension(timeoutMs) {
2883
3187
  });
2884
3188
  }
2885
3189
 
3190
+ // src/isPhantomLoginAvailable.ts
3191
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
3192
+ const extensionInstalled = await waitForPhantomExtension(timeoutMs);
3193
+ if (!extensionInstalled) {
3194
+ return false;
3195
+ }
3196
+ try {
3197
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
3198
+ return false;
3199
+ }
3200
+ const response = await window.phantom.app.features();
3201
+ if (!Array.isArray(response.features)) {
3202
+ return false;
3203
+ }
3204
+ return response.features.includes("phantom_login");
3205
+ } catch (error) {
3206
+ console.error("Error checking Phantom extension features", error);
3207
+ return false;
3208
+ }
3209
+ }
3210
+
2886
3211
  // src/providers/embedded/adapters/phantom-app.ts
2887
3212
  var BrowserPhantomAppProvider = class {
2888
3213
  /**
@@ -2952,35 +3277,50 @@ var BrowserLogger = class {
2952
3277
  };
2953
3278
 
2954
3279
  // src/providers/embedded/index.ts
2955
- var import_constants2 = require("@phantom/constants");
3280
+ var import_constants4 = require("@phantom/constants");
2956
3281
  var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
2957
3282
  constructor(config) {
2958
3283
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
2959
3284
  const urlParamsAccessor = new BrowserURLParamsAccessor();
2960
- const stamper = new import_indexed_db_stamper.IndexedDbStamper({
3285
+ const storage = new BrowserStorage();
3286
+ const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`) : new import_indexed_db_stamper.IndexedDbStamper({
2961
3287
  dbName: `phantom-embedded-sdk-${config.appId}`,
2962
3288
  storeName: "crypto-keys",
2963
3289
  keyName: "signing-key"
2964
3290
  });
2965
3291
  const platformName = getPlatformName();
2966
3292
  const { name: browserName, version } = detectBrowser();
3293
+ const authProvider = config.unstable__auth2Options && config.authOptions?.authUrl && config.authOptions?.redirectUrl && stamper instanceof Auth2Stamper ? new Auth2AuthProvider(
3294
+ stamper,
3295
+ storage,
3296
+ urlParamsAccessor,
3297
+ {
3298
+ redirectUri: config.authOptions.redirectUrl,
3299
+ connectLoginUrl: config.authOptions.authUrl,
3300
+ clientId: config.unstable__auth2Options.clientId,
3301
+ authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl
3302
+ },
3303
+ {
3304
+ apiBaseUrl: config.apiBaseUrl,
3305
+ appId: config.appId
3306
+ }
3307
+ ) : new BrowserAuthProvider(urlParamsAccessor);
2967
3308
  const platform = {
2968
- storage: new BrowserStorage(),
2969
- authProvider: new BrowserAuthProvider(urlParamsAccessor),
3309
+ storage,
3310
+ authProvider,
2970
3311
  phantomAppProvider: new BrowserPhantomAppProvider(),
2971
3312
  urlParamsAccessor,
2972
3313
  stamper,
2973
3314
  name: platformName,
2974
3315
  // Use detected browser name and version for identification
2975
3316
  analyticsHeaders: {
2976
- [import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
2977
- [import_constants2.ANALYTICS_HEADERS.PLATFORM]: browserName,
2978
- // firefox, chrome, safari, etc.
2979
- [import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
2980
- // Full user agent for more detailed info
2981
- [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
2982
- [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
2983
- [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.2"
3317
+ [import_constants4.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
3318
+ [import_constants4.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
3319
+ [import_constants4.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
3320
+ [import_constants4.ANALYTICS_HEADERS.CLIENT]: browserName,
3321
+ [import_constants4.ANALYTICS_HEADERS.APP_ID]: config.appId,
3322
+ [import_constants4.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3323
+ [import_constants4.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.4"
2984
3324
  // Replaced at build time
2985
3325
  }
2986
3326
  };
@@ -2997,7 +3337,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
2997
3337
 
2998
3338
  // src/ProviderManager.ts
2999
3339
  var import_embedded_provider_core2 = require("@phantom/embedded-provider-core");
3000
- var import_constants3 = require("@phantom/constants");
3340
+ var import_constants5 = require("@phantom/constants");
3001
3341
 
3002
3342
  // src/utils/auth-callback.ts
3003
3343
  function isAuthFailureCallback(searchParams) {
@@ -3017,11 +3357,12 @@ function isAuthCallbackUrl(searchParams) {
3017
3357
  }
3018
3358
 
3019
3359
  // src/utils/deeplink.ts
3020
- function getDeeplinkToPhantom(ref) {
3021
- if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
3360
+ function getDeeplinkToPhantom(ref, currentHref) {
3361
+ const resolvedHref = currentHref ?? window.location.href;
3362
+ if (!resolvedHref.startsWith("http:") && !resolvedHref.startsWith("https:")) {
3022
3363
  throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
3023
3364
  }
3024
- const currentUrl = encodeURIComponent(window.location.href);
3365
+ const currentUrl = encodeURIComponent(resolvedHref);
3025
3366
  const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
3026
3367
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
3027
3368
  }
@@ -3117,8 +3458,14 @@ var ProviderManager = class {
3117
3458
  } else if (requestedProvider === "deeplink") {
3118
3459
  try {
3119
3460
  const deeplinkUrl = getDeeplinkToPhantom();
3120
- if (typeof window !== "undefined") {
3121
- window.location.href = deeplinkUrl;
3461
+ if (typeof window !== "undefined" && window.location) {
3462
+ try {
3463
+ window.location.href = deeplinkUrl;
3464
+ } catch (error) {
3465
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Failed to set deeplink location", {
3466
+ error: error instanceof Error ? error.message : String(error)
3467
+ });
3468
+ }
3122
3469
  }
3123
3470
  return {
3124
3471
  addresses: [],
@@ -3381,8 +3728,8 @@ var ProviderManager = class {
3381
3728
  if (!this.config.appId) {
3382
3729
  throw new Error("appId is required for embedded provider");
3383
3730
  }
3384
- const apiBaseUrl = this.config.apiBaseUrl || import_constants3.DEFAULT_WALLET_API_URL;
3385
- const authUrl = this.config.authOptions?.authUrl || import_constants3.DEFAULT_AUTH_URL;
3731
+ const apiBaseUrl = this.config.apiBaseUrl || import_constants5.DEFAULT_WALLET_API_URL;
3732
+ const authUrl = this.config.authOptions?.authUrl || import_constants5.DEFAULT_AUTH_URL;
3386
3733
  provider = new EmbeddedProvider({
3387
3734
  apiBaseUrl,
3388
3735
  appId: this.config.appId,
@@ -3391,7 +3738,8 @@ var ProviderManager = class {
3391
3738
  authUrl,
3392
3739
  redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
3393
3740
  },
3394
- embeddedWalletType: embeddedWalletType || import_constants3.DEFAULT_EMBEDDED_WALLET_TYPE,
3741
+ unstable__auth2Options: this.config.unstable__auth2Options,
3742
+ embeddedWalletType: embeddedWalletType || import_constants5.DEFAULT_EMBEDDED_WALLET_TYPE,
3395
3743
  addressTypes: this.config.addressTypes || [import_client.AddressType.solana]
3396
3744
  });
3397
3745
  } else {
@@ -3427,7 +3775,7 @@ var ProviderManager = class {
3427
3775
 
3428
3776
  // src/BrowserSDK.ts
3429
3777
  var import_embedded_provider_core3 = require("@phantom/embedded-provider-core");
3430
- var import_constants4 = require("@phantom/constants");
3778
+ var import_constants6 = require("@phantom/constants");
3431
3779
  var BROWSER_SDK_PROVIDER_TYPES = [
3432
3780
  ...import_embedded_provider_core3.EMBEDDED_PROVIDER_AUTH_TYPES,
3433
3781
  "injected",
@@ -3463,7 +3811,7 @@ var BrowserSDK = class {
3463
3811
  });
3464
3812
  throw new Error("appId is required when using embedded providers (google, apple, phantom, etc.)");
3465
3813
  }
3466
- const embeddedWalletType = config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE;
3814
+ const embeddedWalletType = config.embeddedWalletType || import_constants6.DEFAULT_EMBEDDED_WALLET_TYPE;
3467
3815
  if (!["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
3468
3816
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
3469
3817
  embeddedWalletType: config.embeddedWalletType
@@ -3589,6 +3937,7 @@ var BrowserSDK = class {
3589
3937
  */
3590
3938
  async autoConnect() {
3591
3939
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
3940
+ await this.discoverWallets();
3592
3941
  const result = await this.providerManager.autoConnect();
3593
3942
  if (result) {
3594
3943
  debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
@@ -3736,31 +4085,7 @@ var BrowserSDK = class {
3736
4085
  }
3737
4086
  };
3738
4087
 
3739
- // src/waitForPhantomExtension.ts
3740
- var import_browser_injected_sdk5 = require("@phantom/browser-injected-sdk");
3741
- async function waitForPhantomExtension(timeoutMs = 3e3) {
3742
- return new Promise((resolve) => {
3743
- const startTime = Date.now();
3744
- const checkInterval = 100;
3745
- const checkForExtension = () => {
3746
- try {
3747
- if ((0, import_browser_injected_sdk5.isPhantomExtensionInstalled)()) {
3748
- resolve(true);
3749
- return;
3750
- }
3751
- } catch (error) {
3752
- }
3753
- const elapsed = Date.now() - startTime;
3754
- if (elapsed >= timeoutMs) {
3755
- resolve(false);
3756
- return;
3757
- }
3758
- setTimeout(checkForExtension, checkInterval);
3759
- };
3760
- checkForExtension();
3761
- });
3762
- }
3763
-
3764
4088
  // src/index.ts
3765
- var import_constants5 = require("@phantom/constants");
3766
- var import_client4 = require("@phantom/client");
4089
+ var import_constants7 = require("@phantom/constants");
4090
+ var import_client5 = require("@phantom/client");
4091
+ var import_constants8 = require("@phantom/constants");