@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.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { AddressType } from "@phantom/client";
3
3
 
4
4
  // src/providers/injected/index.ts
5
- import { AddressType as AddressType2 } from "@phantom/client";
5
+ import { AddressType as AddressType3 } from "@phantom/client";
6
6
 
7
7
  // src/debug.ts
8
8
  var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
@@ -79,12 +79,27 @@ var DebugCategory = {
79
79
  };
80
80
 
81
81
  // src/wallets/discovery.ts
82
+ import { PHANTOM_ICON } from "@phantom/constants";
82
83
  import { AddressType as ClientAddressType } from "@phantom/client";
83
84
  import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
84
85
  import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
85
86
  import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
86
87
  import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
87
88
  import { createAutoConfirmPlugin } from "@phantom/browser-injected-sdk/auto-confirm";
89
+
90
+ // src/wallets/custom-wallets.ts
91
+ import { AddressType as AddressType2 } from "@phantom/client";
92
+ var CUSTOM_WALLET_CONFIGS = [
93
+ {
94
+ id: "coinbase-wallet",
95
+ name: "Coinbase Wallet",
96
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI4IDU2YzE1LjQ2NCAwIDI4LTEyLjUzNiAyOC0yOFM0My40NjQgMCAyOCAwIDAgMTIuNTM2IDAgMjhzMTIuNTM2IDI4IDI4IDI4WiIgZmlsbD0iIzFCNTNFNCIvPjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNyAyOGMwIDExLjU5OCA5LjQwMiAyMSAyMSAyMXMyMS05LjQwMiAyMS0yMVMzOS41OTggNyAyOCA3IDcgMTYuNDAyIDcgMjhabTE3LjIzNC02Ljc2NmEzIDMgMCAwIDAtMyAzdjcuNTMzYTMgMyAwIDAgMCAzIDNoNy41MzNhMyAzIDAgMCAwIDMtM3YtNy41MzNhMyAzIDAgMCAwLTMtM2gtNy41MzNaIiBmaWxsPSIjZmZmIi8+PC9zdmc+",
97
+ windowProperty: "coinbaseSolana",
98
+ addressTypes: [AddressType2.solana]
99
+ }
100
+ ];
101
+
102
+ // src/wallets/discovery.ts
88
103
  function generateWalletIdFromEIP6963(info) {
89
104
  if (info.rdns) {
90
105
  return info.rdns.split(".").reverse().join("-");
@@ -348,6 +363,51 @@ async function discoverSolanaWallets() {
348
363
  walletNames: wallets.map((w) => w.name)
349
364
  };
350
365
  debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
366
+ const customWallets = discoverCustomSolanaWallets();
367
+ wallets.push(...customWallets);
368
+ return wallets;
369
+ }
370
+ function discoverCustomSolanaWallets() {
371
+ const wallets = [];
372
+ if (typeof window === "undefined") {
373
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet discovery skipped (not in browser environment)");
374
+ return wallets;
375
+ }
376
+ debug.log(DebugCategory.BROWSER_SDK, "Starting custom Solana wallet discovery", {
377
+ configCount: CUSTOM_WALLET_CONFIGS.length
378
+ });
379
+ for (const config of CUSTOM_WALLET_CONFIGS) {
380
+ if (!config.addressTypes.includes(ClientAddressType.solana)) {
381
+ continue;
382
+ }
383
+ const provider = window[config.windowProperty];
384
+ if (!provider) {
385
+ debug.log(DebugCategory.BROWSER_SDK, "Custom wallet not found", {
386
+ walletId: config.id,
387
+ windowProperty: config.windowProperty
388
+ });
389
+ continue;
390
+ }
391
+ debug.log(DebugCategory.BROWSER_SDK, "Discovered custom Solana wallet", {
392
+ walletId: config.id,
393
+ walletName: config.name,
394
+ windowProperty: config.windowProperty
395
+ });
396
+ wallets.push({
397
+ id: config.id,
398
+ name: config.name,
399
+ icon: config.icon,
400
+ addressTypes: config.addressTypes,
401
+ providers: {
402
+ solana: provider
403
+ },
404
+ discovery: "custom"
405
+ });
406
+ }
407
+ debug.log(DebugCategory.BROWSER_SDK, "Custom Solana wallet discovery completed", {
408
+ discoveredCount: wallets.length,
409
+ walletIds: wallets.map((w) => w.id)
410
+ });
351
411
  return wallets;
352
412
  }
353
413
  function discoverPhantomWallet(addressTypes) {
@@ -369,8 +429,7 @@ function discoverPhantomWallet(addressTypes) {
369
429
  return {
370
430
  id: "phantom",
371
431
  name: "Phantom",
372
- icon: void 0,
373
- // Icon will be rendered from icons package in UI components
432
+ icon: PHANTOM_ICON,
374
433
  addressTypes,
375
434
  providers: {
376
435
  solana: addressTypes.includes(ClientAddressType.solana) ? phantomInstance.solana : void 0,
@@ -439,6 +498,9 @@ async function discoverWallets(addressTypes) {
439
498
  return Array.from(walletMap.values());
440
499
  }
441
500
 
501
+ // src/wallets/registry.ts
502
+ import { PHANTOM_ICON as PHANTOM_ICON2 } from "@phantom/constants";
503
+
442
504
  // src/providers/injected/chains/InjectedWalletSolanaChain.ts
443
505
  import { EventEmitter } from "eventemitter3";
444
506
  import { Buffer } from "buffer";
@@ -446,61 +508,55 @@ var InjectedWalletSolanaChain = class {
446
508
  constructor(provider, walletId, walletName) {
447
509
  // Expose eventEmitter for testing - allows tests to trigger events directly
448
510
  this.eventEmitter = new EventEmitter();
449
- this._connected = false;
450
511
  this._publicKey = null;
451
512
  this.provider = provider;
452
513
  this.walletId = walletId;
453
514
  this.walletName = walletName;
454
515
  this.setupEventListeners();
455
516
  }
456
- get connected() {
457
- return this._connected;
458
- }
459
517
  get publicKey() {
460
518
  return this._publicKey;
461
519
  }
520
+ get isConnected() {
521
+ return this.provider.isConnected || !!this._publicKey;
522
+ }
462
523
  async connect(options) {
463
- debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
464
- walletId: this.walletId,
465
- walletName: this.walletName,
466
- onlyIfTrusted: options?.onlyIfTrusted
467
- });
468
524
  try {
469
- const result = await this.provider.connect(options);
470
- if (typeof result === "string") {
471
- this._connected = true;
472
- this._publicKey = result;
473
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
525
+ await this.provider.connect(options);
526
+ const isConnected = this.provider.isConnected;
527
+ if (!isConnected || this.provider.publicKey === null) {
528
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Provider not connected after connect() call", {
474
529
  walletId: this.walletId,
475
530
  walletName: this.walletName,
476
- publicKey: result
531
+ providerConnected: isConnected,
532
+ providerPublicKey: this.provider.publicKey
477
533
  });
478
- return { publicKey: result };
479
- }
480
- if (typeof result === "object" && result !== null && "publicKey" in result) {
481
- this._connected = true;
482
- this._publicKey = result.publicKey;
483
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
534
+ throw new Error("Provider not connected after connect() call");
535
+ }
536
+ let publicKey;
537
+ const providerPublicKey = this.provider.publicKey;
538
+ if (typeof providerPublicKey === "string") {
539
+ publicKey = providerPublicKey;
540
+ } else if (providerPublicKey !== null && providerPublicKey !== void 0 && typeof providerPublicKey.toString === "function") {
541
+ publicKey = providerPublicKey.toString();
542
+ } else {
543
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Invalid publicKey format in provider state", {
484
544
  walletId: this.walletId,
485
545
  walletName: this.walletName,
486
- publicKey: result.publicKey
546
+ publicKeyType: typeof providerPublicKey
487
547
  });
488
- return result;
489
- }
490
- if (Array.isArray(result) && result.length > 0) {
491
- const firstAccount = result[0];
492
- if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
493
- this._connected = true;
494
- this._publicKey = firstAccount.address;
495
- debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
496
- walletId: this.walletId,
497
- walletName: this.walletName,
498
- publicKey: firstAccount.address
499
- });
500
- return { publicKey: firstAccount.address };
501
- }
548
+ throw new Error("Invalid publicKey format in provider state");
502
549
  }
503
- throw new Error("Unexpected connect result format");
550
+ if (!publicKey || publicKey.length === 0) {
551
+ throw new Error("Empty publicKey from provider");
552
+ }
553
+ this._publicKey = publicKey;
554
+ debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
555
+ walletId: this.walletId,
556
+ walletName: this.walletName,
557
+ publicKey
558
+ });
559
+ return { publicKey };
504
560
  } catch (error) {
505
561
  debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
506
562
  walletId: this.walletId,
@@ -517,7 +573,6 @@ var InjectedWalletSolanaChain = class {
517
573
  });
518
574
  try {
519
575
  await this.provider.disconnect();
520
- this._connected = false;
521
576
  this._publicKey = null;
522
577
  debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
523
578
  walletId: this.walletId,
@@ -653,28 +708,19 @@ var InjectedWalletSolanaChain = class {
653
708
  switchNetwork(_network) {
654
709
  return Promise.resolve();
655
710
  }
656
- getPublicKey() {
657
- return Promise.resolve(this._publicKey);
658
- }
659
- isConnected() {
660
- return this._connected;
661
- }
662
711
  setupEventListeners() {
663
712
  if (typeof this.provider.on === "function") {
664
713
  this.provider.on("connect", (publicKey) => {
665
- this._connected = true;
666
714
  this._publicKey = publicKey;
667
715
  this.eventEmitter.emit("connect", publicKey);
668
716
  });
669
717
  this.provider.on("disconnect", () => {
670
- this._connected = false;
671
718
  this._publicKey = null;
672
719
  this.eventEmitter.emit("disconnect");
673
720
  });
674
721
  this.provider.on("accountChanged", (publicKey) => {
675
- this._publicKey = publicKey;
676
- this._connected = publicKey != null && publicKey.length > 0;
677
- this.eventEmitter.emit("accountChanged", publicKey);
722
+ this._publicKey = publicKey ? publicKey : null;
723
+ this.eventEmitter.emit("accountChanged", this._publicKey);
678
724
  });
679
725
  }
680
726
  }
@@ -700,12 +746,12 @@ var WalletStandardSolanaAdapter = class {
700
746
  this.walletName = walletName;
701
747
  this.setupEventListeners();
702
748
  }
703
- get connected() {
704
- return this._publicKey !== null;
705
- }
706
749
  get publicKey() {
707
750
  return this._publicKey;
708
751
  }
752
+ get isConnected() {
753
+ return this._publicKey !== null;
754
+ }
709
755
  async connect(_options) {
710
756
  try {
711
757
  const connectFeature = this.wallet.features["standard:connect"];
@@ -917,12 +963,6 @@ var WalletStandardSolanaAdapter = class {
917
963
  async switchNetwork(_network) {
918
964
  return Promise.resolve();
919
965
  }
920
- getPublicKey() {
921
- return Promise.resolve(this._publicKey);
922
- }
923
- isConnected() {
924
- return this._publicKey !== null;
925
- }
926
966
  /**
927
967
  * Set up event listeners for Wallet Standard events
928
968
  * Maps Wallet Standard "change" events to "accountChanged" events
@@ -1057,9 +1097,6 @@ var InjectedWalletEthereumChain = class {
1057
1097
  this.walletName = walletName;
1058
1098
  this.setupEventListeners();
1059
1099
  }
1060
- get connected() {
1061
- return this._connected;
1062
- }
1063
1100
  get chainId() {
1064
1101
  return this._chainId;
1065
1102
  }
@@ -1189,7 +1226,8 @@ var InjectedWalletEthereumChain = class {
1189
1226
  address
1190
1227
  });
1191
1228
  try {
1192
- const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
1229
+ const providerAny = this.provider;
1230
+ const providerConnected = (typeof providerAny.isConnected === "function" ? providerAny.isConnected() : false) || (typeof providerAny.connected === "boolean" ? providerAny.connected : false);
1193
1231
  if (!this._connected || this._accounts.length === 0 || !providerConnected) {
1194
1232
  debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
1195
1233
  walletId: this.walletId,
@@ -1503,8 +1541,7 @@ var InjectedWalletRegistry = class {
1503
1541
  const phantomWallet = {
1504
1542
  id: "phantom",
1505
1543
  name: "Phantom",
1506
- icon: "",
1507
- // Icon will be rendered from icons package in UI components
1544
+ icon: PHANTOM_ICON2,
1508
1545
  addressTypes,
1509
1546
  providers: wrappedProviders,
1510
1547
  isPhantom: true,
@@ -1650,13 +1687,13 @@ var InjectedProvider = class {
1650
1687
  return provider;
1651
1688
  }
1652
1689
  get solana() {
1653
- return this.getChainProvider(AddressType2.solana, "solana", "Solana");
1690
+ return this.getChainProvider(AddressType3.solana, "solana", "Solana");
1654
1691
  }
1655
1692
  /**
1656
1693
  * Access to Ethereum chain operations
1657
1694
  */
1658
1695
  get ethereum() {
1659
- return this.getChainProvider(AddressType2.ethereum, "ethereum", "Ethereum");
1696
+ return this.getChainProvider(AddressType3.ethereum, "ethereum", "Ethereum");
1660
1697
  }
1661
1698
  validateAndSelectWallet(requestedWalletId) {
1662
1699
  if (!this.walletRegistry.has(requestedWalletId)) {
@@ -1697,7 +1734,7 @@ var InjectedProvider = class {
1697
1734
  this.setupEventListeners(walletInfo);
1698
1735
  }
1699
1736
  const connectedAddresses = [];
1700
- if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
1737
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers?.solana) {
1701
1738
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
1702
1739
  walletId: this.selectedWalletId,
1703
1740
  walletName: walletInfo.name,
@@ -1709,7 +1746,7 @@ var InjectedProvider = class {
1709
1746
  );
1710
1747
  const address = result.publicKey;
1711
1748
  connectedAddresses.push({
1712
- addressType: AddressType2.solana,
1749
+ addressType: AddressType3.solana,
1713
1750
  address
1714
1751
  });
1715
1752
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
@@ -1718,19 +1755,14 @@ var InjectedProvider = class {
1718
1755
  walletName: walletInfo.name
1719
1756
  });
1720
1757
  } catch (err) {
1721
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", {
1758
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, continuing with other chains", {
1722
1759
  error: err,
1723
1760
  walletId: this.selectedWalletId,
1724
1761
  walletName: walletInfo.name
1725
1762
  });
1726
- this.emit("connect_error", {
1727
- error: err instanceof Error ? err.message : "Failed to connect",
1728
- source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
1729
- });
1730
- throw err;
1731
1763
  }
1732
1764
  }
1733
- if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers?.ethereum) {
1765
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers?.ethereum) {
1734
1766
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
1735
1767
  walletId: this.selectedWalletId,
1736
1768
  walletName: walletInfo.name,
@@ -1746,7 +1778,7 @@ var InjectedProvider = class {
1746
1778
  if (accounts.length > 0) {
1747
1779
  connectedAddresses.push(
1748
1780
  ...accounts.map((address) => ({
1749
- addressType: AddressType2.ethereum,
1781
+ addressType: AddressType3.ethereum,
1750
1782
  address
1751
1783
  }))
1752
1784
  );
@@ -1757,16 +1789,11 @@ var InjectedProvider = class {
1757
1789
  });
1758
1790
  }
1759
1791
  } catch (err) {
1760
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", {
1792
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, continuing with other chains", {
1761
1793
  error: err,
1762
1794
  walletId: this.selectedWalletId,
1763
1795
  walletName: walletInfo.name
1764
1796
  });
1765
- this.emit("connect_error", {
1766
- error: err instanceof Error ? err.message : "Failed to connect",
1767
- source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
1768
- });
1769
- throw err;
1770
1797
  }
1771
1798
  }
1772
1799
  return connectedAddresses;
@@ -1826,7 +1853,8 @@ var InjectedProvider = class {
1826
1853
  this.emit("connect", {
1827
1854
  addresses: connectedAddresses,
1828
1855
  source: "manual-connect",
1829
- authUserId
1856
+ authUserId,
1857
+ walletId
1830
1858
  });
1831
1859
  return result;
1832
1860
  }
@@ -1838,12 +1866,13 @@ var InjectedProvider = class {
1838
1866
  if (authOptions.provider !== "injected") {
1839
1867
  throw new Error(`Invalid provider for injected connection: ${authOptions.provider}. Must be "injected"`);
1840
1868
  }
1869
+ const requestedWalletId = authOptions.walletId || "phantom";
1841
1870
  this.emit("connect_start", {
1842
1871
  source: "manual-connect",
1843
- providerType: "injected"
1872
+ providerType: "injected",
1873
+ walletId: requestedWalletId
1844
1874
  });
1845
1875
  try {
1846
- const requestedWalletId = authOptions.walletId || "phantom";
1847
1876
  const walletInfo = this.validateAndSelectWallet(requestedWalletId);
1848
1877
  const connectedAddresses = await this.connectToWallet(walletInfo);
1849
1878
  return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
@@ -1859,7 +1888,7 @@ var InjectedProvider = class {
1859
1888
  debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
1860
1889
  const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
1861
1890
  if (walletInfo?.providers) {
1862
- if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers.solana) {
1891
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers.solana) {
1863
1892
  try {
1864
1893
  await walletInfo.providers.solana.disconnect();
1865
1894
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
@@ -1867,7 +1896,7 @@ var InjectedProvider = class {
1867
1896
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
1868
1897
  }
1869
1898
  }
1870
- if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers.ethereum) {
1899
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers.ethereum) {
1871
1900
  try {
1872
1901
  await walletInfo.providers.ethereum.disconnect();
1873
1902
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
@@ -1963,7 +1992,8 @@ var InjectedProvider = class {
1963
1992
  this.emit("connect", {
1964
1993
  addresses: connectedAddresses,
1965
1994
  source: "auto-connect",
1966
- authUserId
1995
+ authUserId,
1996
+ walletId: this.selectedWalletId
1967
1997
  });
1968
1998
  debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
1969
1999
  addressCount: connectedAddresses.length,
@@ -2024,12 +2054,13 @@ var InjectedProvider = class {
2024
2054
  createSolanaConnectHandler(walletId, source) {
2025
2055
  return async (publicKey) => {
2026
2056
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey, walletId });
2027
- const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType2.solana);
2057
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType3.solana);
2028
2058
  const authUserId = await this.getAuthUserId("Solana connect event");
2029
2059
  this.emit("connect", {
2030
2060
  addresses: newAddresses,
2031
2061
  source,
2032
- authUserId
2062
+ authUserId,
2063
+ walletId: this.selectedWalletId
2033
2064
  });
2034
2065
  };
2035
2066
  }
@@ -2040,7 +2071,7 @@ var InjectedProvider = class {
2040
2071
  return () => {
2041
2072
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received", { walletId });
2042
2073
  const state = this.getWalletState(walletId);
2043
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2074
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.solana);
2044
2075
  this.setWalletState(walletId, {
2045
2076
  connected: filteredAddresses.length > 0,
2046
2077
  addresses: filteredAddresses
@@ -2058,16 +2089,17 @@ var InjectedProvider = class {
2058
2089
  return async (publicKey) => {
2059
2090
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey, walletId });
2060
2091
  if (publicKey) {
2061
- const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType2.solana);
2092
+ const newAddresses = this.updateWalletAddresses(walletId, [publicKey], AddressType3.solana);
2062
2093
  const authUserId = await this.getAuthUserId("Solana account changed event");
2063
2094
  this.emit("connect", {
2064
2095
  addresses: newAddresses,
2065
2096
  source: this.getAccountChangeSource(source),
2066
- authUserId
2097
+ authUserId,
2098
+ walletId: this.selectedWalletId
2067
2099
  });
2068
2100
  } else {
2069
2101
  const state = this.getWalletState(walletId);
2070
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
2102
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.solana);
2071
2103
  this.setWalletState(walletId, {
2072
2104
  connected: otherAddresses.length > 0,
2073
2105
  addresses: otherAddresses
@@ -2099,12 +2131,13 @@ var InjectedProvider = class {
2099
2131
  }
2100
2132
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts, walletId });
2101
2133
  if (accounts.length > 0) {
2102
- const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType2.ethereum);
2134
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType3.ethereum);
2103
2135
  const authUserId = await this.getAuthUserId("Ethereum connect event");
2104
2136
  this.emit("connect", {
2105
2137
  addresses: newAddresses,
2106
2138
  source,
2107
- authUserId
2139
+ authUserId,
2140
+ walletId: this.selectedWalletId
2108
2141
  });
2109
2142
  }
2110
2143
  };
@@ -2116,7 +2149,7 @@ var InjectedProvider = class {
2116
2149
  return () => {
2117
2150
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received", { walletId });
2118
2151
  const state = this.getWalletState(walletId);
2119
- const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2152
+ const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
2120
2153
  this.setWalletState(walletId, {
2121
2154
  connected: filteredAddresses.length > 0,
2122
2155
  addresses: filteredAddresses
@@ -2133,16 +2166,17 @@ var InjectedProvider = class {
2133
2166
  return async (accounts) => {
2134
2167
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts, walletId });
2135
2168
  if (accounts && accounts.length > 0) {
2136
- const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType2.ethereum);
2169
+ const newAddresses = this.updateWalletAddresses(walletId, accounts, AddressType3.ethereum);
2137
2170
  const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
2138
2171
  this.emit("connect", {
2139
2172
  addresses: newAddresses,
2140
2173
  source: this.getAccountChangeSource(source),
2141
- authUserId
2174
+ authUserId,
2175
+ walletId: this.selectedWalletId
2142
2176
  });
2143
2177
  } else {
2144
2178
  const state = this.getWalletState(walletId);
2145
- const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
2179
+ const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
2146
2180
  this.setWalletState(walletId, {
2147
2181
  connected: otherAddresses.length > 0,
2148
2182
  addresses: otherAddresses
@@ -2336,7 +2370,9 @@ var InjectedProvider = class {
2336
2370
  this.eventListenerCleanups.set(walletId, [...existingCleanups, ...cleanups]);
2337
2371
  }
2338
2372
  /**
2339
- * Unified event listener setup for all wallet types (Phantom and external)
2373
+ * Unified event listener setup for all wallet types (Phantom and external).
2374
+ * Cleans up listeners for previously selected wallets to prevent stale events
2375
+ * from causing walletId flicker during connections.
2340
2376
  */
2341
2377
  setupEventListeners(walletInfo) {
2342
2378
  const walletId = this.selectedWalletId || "phantom";
@@ -2344,11 +2380,22 @@ var InjectedProvider = class {
2344
2380
  debug.log(DebugCategory.INJECTED_PROVIDER, "Event listeners already set up for wallet", { walletId });
2345
2381
  return;
2346
2382
  }
2383
+ for (const existingWalletId of this.eventListenersSetup) {
2384
+ if (existingWalletId === walletId) {
2385
+ continue;
2386
+ }
2387
+ const cleanups = this.eventListenerCleanups.get(existingWalletId);
2388
+ if (cleanups) {
2389
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Cleaning up event listeners for wallet", { existingWalletId });
2390
+ cleanups.forEach((cleanup) => cleanup());
2391
+ }
2392
+ this.eventListenersSetup.delete(existingWalletId);
2393
+ }
2347
2394
  debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up event listeners", { walletId });
2348
- if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
2395
+ if (this.addressTypes.includes(AddressType3.solana) && walletInfo.providers?.solana) {
2349
2396
  this.setupSolanaEventListeners(walletInfo.providers.solana, walletId, "wallet");
2350
2397
  }
2351
- if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers?.ethereum) {
2398
+ if (this.addressTypes.includes(AddressType3.ethereum) && walletInfo.providers?.ethereum) {
2352
2399
  this.setupEthereumEventListeners(walletInfo.providers.ethereum, walletId, "wallet");
2353
2400
  }
2354
2401
  this.eventListenersSetup.add(walletId);
@@ -2492,7 +2539,7 @@ var BrowserURLParamsAccessor = class {
2492
2539
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
2493
2540
 
2494
2541
  // src/providers/embedded/adapters/auth.ts
2495
- import { DEFAULT_AUTH_URL } from "@phantom/constants";
2542
+ import { DEFAULT_AUTH_URL, DEFAULT_AUTHENTICATOR_ALGORITHM } from "@phantom/constants";
2496
2543
 
2497
2544
  // src/utils/browser-detection.ts
2498
2545
  function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
@@ -2667,9 +2714,10 @@ var BrowserAuthProvider = class {
2667
2714
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2668
2715
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2669
2716
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2670
- sdk_version: "1.0.2",
2717
+ sdk_version: "1.0.4",
2671
2718
  sdk_type: "browser",
2672
- platform: detectBrowser().name
2719
+ platform: detectBrowser().name,
2720
+ algorithm: phantomOptions.algorithm || DEFAULT_AUTHENTICATOR_ALGORITHM
2673
2721
  });
2674
2722
  if (phantomOptions.provider) {
2675
2723
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -2697,7 +2745,7 @@ var BrowserAuthProvider = class {
2697
2745
  resolve();
2698
2746
  });
2699
2747
  }
2700
- resumeAuthFromRedirect(provider) {
2748
+ async resumeAuthFromRedirect(provider) {
2701
2749
  try {
2702
2750
  const walletId = this.urlParamsAccessor.getParam("wallet_id");
2703
2751
  const sessionId = this.urlParamsAccessor.getParam("session_id");
@@ -2772,14 +2820,14 @@ var BrowserAuthProvider = class {
2772
2820
  }
2773
2821
  );
2774
2822
  }
2775
- return {
2823
+ return Promise.resolve({
2776
2824
  walletId,
2777
2825
  organizationId,
2778
2826
  accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
2779
2827
  expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
2780
2828
  authUserId: authUserId || void 0,
2781
2829
  provider
2782
- };
2830
+ });
2783
2831
  } catch (error) {
2784
2832
  sessionStorage.removeItem("phantom-auth-context");
2785
2833
  throw error;
@@ -2787,31 +2835,292 @@ var BrowserAuthProvider = class {
2787
2835
  }
2788
2836
  };
2789
2837
 
2790
- // src/providers/embedded/adapters/phantom-app.ts
2791
- import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
2792
-
2793
- // src/isPhantomLoginAvailable.ts
2794
- import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
2795
- async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2796
- const extensionInstalled = await waitForExtension(timeoutMs);
2797
- if (!extensionInstalled) {
2798
- return false;
2838
+ // src/providers/embedded/adapters/Auth2AuthProvider.ts
2839
+ import {
2840
+ createCodeVerifier,
2841
+ createSalt,
2842
+ createConnectStartUrl,
2843
+ exchangeAuthCode,
2844
+ Auth2KmsRpcClient
2845
+ } from "@phantom/auth2";
2846
+ var Auth2AuthProvider = class {
2847
+ constructor(stamper, storage, urlParamsAccessor, auth2ProviderOptions, kmsClientOptions) {
2848
+ this.stamper = stamper;
2849
+ this.storage = storage;
2850
+ this.urlParamsAccessor = urlParamsAccessor;
2851
+ this.auth2ProviderOptions = auth2ProviderOptions;
2852
+ this.kms = new Auth2KmsRpcClient(stamper, kmsClientOptions);
2799
2853
  }
2800
- try {
2801
- if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2802
- return false;
2854
+ /** Redirect the browser. Extracted as a static method so tests can spy on it. */
2855
+ static navigate(url) {
2856
+ window.location.href = url;
2857
+ }
2858
+ /**
2859
+ * Builds the Auth2 /login/start URL and redirects the browser.
2860
+ *
2861
+ * Called by EmbeddedProvider.handleRedirectAuth() after the stamper has
2862
+ * already been initialized and a pending Session has been saved to storage.
2863
+ * We store the PKCE code_verifier and salt into that session so they survive
2864
+ * the page redirect without ever touching sessionStorage.
2865
+ */
2866
+ async authenticate(options) {
2867
+ if (!this.stamper.getKeyInfo()) {
2868
+ await this.stamper.init();
2869
+ }
2870
+ const keyPair = this.stamper.getCryptoKeyPair();
2871
+ if (!keyPair) {
2872
+ throw new Error("Stamper key pair not found.");
2873
+ }
2874
+ const codeVerifier = createCodeVerifier();
2875
+ const salt = createSalt();
2876
+ const session = await this.storage.getSession();
2877
+ if (!session) {
2878
+ throw new Error("Session not found.");
2879
+ }
2880
+ await this.storage.saveSession({ ...session, pkceCodeVerifier: codeVerifier, salt });
2881
+ const url = await createConnectStartUrl({
2882
+ keyPair,
2883
+ connectLoginUrl: this.auth2ProviderOptions.connectLoginUrl,
2884
+ clientId: this.auth2ProviderOptions.clientId,
2885
+ redirectUri: this.auth2ProviderOptions.redirectUri,
2886
+ sessionId: options.sessionId,
2887
+ provider: options.provider,
2888
+ codeVerifier,
2889
+ salt
2890
+ });
2891
+ Auth2AuthProvider.navigate(url);
2892
+ }
2893
+ /**
2894
+ * Processes the Auth2 callback after the browser returns from /login/start.
2895
+ *
2896
+ * Exchanges the authorization code for tokens, discovers the organization
2897
+ * and wallet via KMS RPC, then returns a completed AuthResult.
2898
+ */
2899
+ async resumeAuthFromRedirect(provider) {
2900
+ const code = this.urlParamsAccessor.getParam("code");
2901
+ if (!code) {
2902
+ return null;
2803
2903
  }
2804
- const response = await window.phantom.app.features();
2805
- if (!Array.isArray(response.features)) {
2806
- return false;
2904
+ if (!this.stamper.getKeyInfo()) {
2905
+ await this.stamper.init();
2807
2906
  }
2808
- return response.features.includes("phantom_login");
2809
- } catch (error) {
2810
- console.error("Error checking Phantom extension features", error);
2811
- return false;
2907
+ const session = await this.storage.getSession();
2908
+ if (!session) {
2909
+ throw new Error("Session not found.");
2910
+ }
2911
+ const codeVerifier = session?.pkceCodeVerifier;
2912
+ if (!codeVerifier) {
2913
+ return null;
2914
+ }
2915
+ const state = this.urlParamsAccessor.getParam("state");
2916
+ if (!state || state !== session.sessionId) {
2917
+ throw new Error("Missing or invalid Auth2 state parameter \u2014 possible CSRF attack.");
2918
+ }
2919
+ const error = this.urlParamsAccessor.getParam("error");
2920
+ if (error) {
2921
+ const description = this.urlParamsAccessor.getParam("error_description");
2922
+ throw new Error(`Auth2 callback error: ${description ?? error}`);
2923
+ }
2924
+ const { idToken, bearerToken, authUserId, expiresInMs } = await exchangeAuthCode({
2925
+ authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
2926
+ clientId: this.auth2ProviderOptions.clientId,
2927
+ redirectUri: this.auth2ProviderOptions.redirectUri,
2928
+ code,
2929
+ codeVerifier
2930
+ });
2931
+ this.stamper.idToken = idToken;
2932
+ this.stamper.salt = session?.salt;
2933
+ await this.storage.saveSession({
2934
+ ...session,
2935
+ status: "completed",
2936
+ bearerToken,
2937
+ authUserId,
2938
+ pkceCodeVerifier: void 0,
2939
+ // no longer needed after code exchange
2940
+ salt: void 0
2941
+ // no longer needed after nonce binding is complete
2942
+ });
2943
+ const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
2944
+ return {
2945
+ walletId,
2946
+ organizationId,
2947
+ provider,
2948
+ accountDerivationIndex: 0,
2949
+ // discoverWalletId uses derivation index of 0.
2950
+ expiresInMs,
2951
+ authUserId,
2952
+ bearerToken
2953
+ };
2812
2954
  }
2813
- }
2814
- async function waitForExtension(timeoutMs) {
2955
+ };
2956
+
2957
+ // src/providers/embedded/adapters/Auth2Stamper.ts
2958
+ import bs582 from "bs58";
2959
+ import { base64urlEncode } from "@phantom/base64url";
2960
+ import { Algorithm } from "@phantom/sdk-types";
2961
+ var STORE_NAME = "crypto-keys";
2962
+ var ACTIVE_KEY = "auth2-p256-signing-key";
2963
+ var Auth2Stamper = class {
2964
+ /**
2965
+ * @param dbName - IndexedDB database name (use a unique name per app to
2966
+ * avoid key collisions with other stampers, e.g. `phantom-auth2-<appId>`).
2967
+ */
2968
+ constructor(dbName) {
2969
+ this.dbName = dbName;
2970
+ this.db = null;
2971
+ this.keyPair = null;
2972
+ this._keyInfo = null;
2973
+ this.algorithm = Algorithm.secp256r1;
2974
+ this.type = "PKI";
2975
+ }
2976
+ async init() {
2977
+ await this.openDB();
2978
+ const stored = await this.loadKeyPair();
2979
+ if (stored) {
2980
+ this.keyPair = stored.keyPair;
2981
+ this._keyInfo = stored.keyInfo;
2982
+ return this._keyInfo;
2983
+ }
2984
+ return this.generateAndStore();
2985
+ }
2986
+ getKeyInfo() {
2987
+ return this._keyInfo;
2988
+ }
2989
+ getCryptoKeyPair() {
2990
+ return this.keyPair;
2991
+ }
2992
+ async stamp(params) {
2993
+ if (!this.keyPair || !this._keyInfo) {
2994
+ throw new Error("Auth2Stamper not initialized. Call init() first.");
2995
+ }
2996
+ const signatureRaw = await crypto.subtle.sign(
2997
+ { name: "ECDSA", hash: "SHA-256" },
2998
+ this.keyPair.privateKey,
2999
+ new Uint8Array(params.data)
3000
+ );
3001
+ const rawPublicKey = bs582.decode(this._keyInfo.publicKey);
3002
+ if (this.idToken === void 0 || this.salt === void 0) {
3003
+ throw new Error("Auth2Stamper not initialized with idToken or salt.");
3004
+ }
3005
+ const stampData = {
3006
+ kind: "OIDC",
3007
+ idToken: this.idToken,
3008
+ publicKey: base64urlEncode(rawPublicKey),
3009
+ algorithm: "Secp256r1",
3010
+ salt: this.salt,
3011
+ signature: base64urlEncode(new Uint8Array(signatureRaw))
3012
+ };
3013
+ return base64urlEncode(new TextEncoder().encode(JSON.stringify(stampData)));
3014
+ }
3015
+ async resetKeyPair() {
3016
+ await this.clearStoredKey();
3017
+ this.keyPair = null;
3018
+ this._keyInfo = null;
3019
+ return this.generateAndStore();
3020
+ }
3021
+ async clear() {
3022
+ await this.clearStoredKey();
3023
+ this.keyPair = null;
3024
+ this._keyInfo = null;
3025
+ }
3026
+ // Auth2 doesn't use key rotation; provide minimal no-op implementations.
3027
+ async rotateKeyPair() {
3028
+ return this.init();
3029
+ }
3030
+ // eslint-disable-next-line @typescript-eslint/require-await
3031
+ async commitRotation(authenticatorId) {
3032
+ if (this._keyInfo) {
3033
+ this._keyInfo.authenticatorId = authenticatorId;
3034
+ }
3035
+ }
3036
+ async rollbackRotation() {
3037
+ }
3038
+ async generateAndStore() {
3039
+ const keyPair = await crypto.subtle.generateKey(
3040
+ { name: "ECDSA", namedCurve: "P-256" },
3041
+ false,
3042
+ // non-extractable — private key never leaves Web Crypto
3043
+ ["sign", "verify"]
3044
+ );
3045
+ const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
3046
+ const publicKeyBase58 = bs582.encode(rawPublicKey);
3047
+ const keyIdBuffer = await crypto.subtle.digest("SHA-256", rawPublicKey.buffer);
3048
+ const keyId = base64urlEncode(new Uint8Array(keyIdBuffer)).substring(0, 16);
3049
+ this.keyPair = keyPair;
3050
+ this._keyInfo = {
3051
+ keyId,
3052
+ publicKey: publicKeyBase58,
3053
+ createdAt: Date.now()
3054
+ };
3055
+ await this.storeKeyPair(keyPair, this._keyInfo);
3056
+ return this._keyInfo;
3057
+ }
3058
+ async openDB() {
3059
+ return new Promise((resolve, reject) => {
3060
+ const request = indexedDB.open(this.dbName, 1);
3061
+ request.onsuccess = () => {
3062
+ this.db = request.result;
3063
+ resolve();
3064
+ };
3065
+ request.onerror = () => reject(request.error);
3066
+ request.onupgradeneeded = (event) => {
3067
+ const db = event.target.result;
3068
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
3069
+ db.createObjectStore(STORE_NAME);
3070
+ }
3071
+ };
3072
+ });
3073
+ }
3074
+ async loadKeyPair() {
3075
+ return new Promise((resolve, reject) => {
3076
+ if (!this.db) {
3077
+ throw new Error("Database not initialized");
3078
+ }
3079
+ const request = this.db.transaction([STORE_NAME], "readonly").objectStore(STORE_NAME).get(ACTIVE_KEY);
3080
+ request.onsuccess = () => {
3081
+ resolve(request.result ?? null);
3082
+ };
3083
+ request.onerror = () => {
3084
+ reject(request.error);
3085
+ };
3086
+ });
3087
+ }
3088
+ async storeKeyPair(keyPair, keyInfo) {
3089
+ return new Promise((resolve, reject) => {
3090
+ if (!this.db) {
3091
+ throw new Error("Database not initialized");
3092
+ }
3093
+ const request = this.db.transaction([STORE_NAME], "readwrite").objectStore(STORE_NAME).put({ keyPair, keyInfo }, ACTIVE_KEY);
3094
+ request.onsuccess = () => {
3095
+ resolve();
3096
+ };
3097
+ request.onerror = () => {
3098
+ reject(request.error);
3099
+ };
3100
+ });
3101
+ }
3102
+ async clearStoredKey() {
3103
+ return new Promise((resolve, reject) => {
3104
+ if (!this.db) {
3105
+ throw new Error("Database not initialized");
3106
+ }
3107
+ const request = this.db.transaction([STORE_NAME], "readwrite").objectStore(STORE_NAME).delete(ACTIVE_KEY);
3108
+ request.onsuccess = () => {
3109
+ resolve();
3110
+ };
3111
+ request.onerror = () => {
3112
+ reject(request.error);
3113
+ };
3114
+ });
3115
+ }
3116
+ };
3117
+
3118
+ // src/providers/embedded/adapters/phantom-app.ts
3119
+ import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
3120
+
3121
+ // src/waitForPhantomExtension.ts
3122
+ import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
3123
+ async function waitForPhantomExtension(timeoutMs = 3e3) {
2815
3124
  return new Promise((resolve) => {
2816
3125
  const startTime = Date.now();
2817
3126
  const checkInterval = 100;
@@ -2834,6 +3143,27 @@ async function waitForExtension(timeoutMs) {
2834
3143
  });
2835
3144
  }
2836
3145
 
3146
+ // src/isPhantomLoginAvailable.ts
3147
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
3148
+ const extensionInstalled = await waitForPhantomExtension(timeoutMs);
3149
+ if (!extensionInstalled) {
3150
+ return false;
3151
+ }
3152
+ try {
3153
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
3154
+ return false;
3155
+ }
3156
+ const response = await window.phantom.app.features();
3157
+ if (!Array.isArray(response.features)) {
3158
+ return false;
3159
+ }
3160
+ return response.features.includes("phantom_login");
3161
+ } catch (error) {
3162
+ console.error("Error checking Phantom extension features", error);
3163
+ return false;
3164
+ }
3165
+ }
3166
+
2837
3167
  // src/providers/embedded/adapters/phantom-app.ts
2838
3168
  var BrowserPhantomAppProvider = class {
2839
3169
  /**
@@ -2908,16 +3238,32 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
2908
3238
  constructor(config) {
2909
3239
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
2910
3240
  const urlParamsAccessor = new BrowserURLParamsAccessor();
2911
- const stamper = new IndexedDbStamper({
3241
+ const storage = new BrowserStorage();
3242
+ const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`) : new IndexedDbStamper({
2912
3243
  dbName: `phantom-embedded-sdk-${config.appId}`,
2913
3244
  storeName: "crypto-keys",
2914
3245
  keyName: "signing-key"
2915
3246
  });
2916
3247
  const platformName = getPlatformName();
2917
3248
  const { name: browserName, version } = detectBrowser();
3249
+ const authProvider = config.unstable__auth2Options && config.authOptions?.authUrl && config.authOptions?.redirectUrl && stamper instanceof Auth2Stamper ? new Auth2AuthProvider(
3250
+ stamper,
3251
+ storage,
3252
+ urlParamsAccessor,
3253
+ {
3254
+ redirectUri: config.authOptions.redirectUrl,
3255
+ connectLoginUrl: config.authOptions.authUrl,
3256
+ clientId: config.unstable__auth2Options.clientId,
3257
+ authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl
3258
+ },
3259
+ {
3260
+ apiBaseUrl: config.apiBaseUrl,
3261
+ appId: config.appId
3262
+ }
3263
+ ) : new BrowserAuthProvider(urlParamsAccessor);
2918
3264
  const platform = {
2919
- storage: new BrowserStorage(),
2920
- authProvider: new BrowserAuthProvider(urlParamsAccessor),
3265
+ storage,
3266
+ authProvider,
2921
3267
  phantomAppProvider: new BrowserPhantomAppProvider(),
2922
3268
  urlParamsAccessor,
2923
3269
  stamper,
@@ -2925,13 +3271,12 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
2925
3271
  // Use detected browser name and version for identification
2926
3272
  analyticsHeaders: {
2927
3273
  [ANALYTICS_HEADERS.SDK_TYPE]: "browser",
2928
- [ANALYTICS_HEADERS.PLATFORM]: browserName,
2929
- // firefox, chrome, safari, etc.
3274
+ [ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
2930
3275
  [ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
2931
- // Full user agent for more detailed info
3276
+ [ANALYTICS_HEADERS.CLIENT]: browserName,
2932
3277
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
2933
3278
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
2934
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.2"
3279
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.4"
2935
3280
  // Replaced at build time
2936
3281
  }
2937
3282
  };
@@ -2970,11 +3315,12 @@ function isAuthCallbackUrl(searchParams) {
2970
3315
  }
2971
3316
 
2972
3317
  // src/utils/deeplink.ts
2973
- function getDeeplinkToPhantom(ref) {
2974
- if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
3318
+ function getDeeplinkToPhantom(ref, currentHref) {
3319
+ const resolvedHref = currentHref ?? window.location.href;
3320
+ if (!resolvedHref.startsWith("http:") && !resolvedHref.startsWith("https:")) {
2975
3321
  throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
2976
3322
  }
2977
- const currentUrl = encodeURIComponent(window.location.href);
3323
+ const currentUrl = encodeURIComponent(resolvedHref);
2978
3324
  const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
2979
3325
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
2980
3326
  }
@@ -3070,8 +3416,14 @@ var ProviderManager = class {
3070
3416
  } else if (requestedProvider === "deeplink") {
3071
3417
  try {
3072
3418
  const deeplinkUrl = getDeeplinkToPhantom();
3073
- if (typeof window !== "undefined") {
3074
- window.location.href = deeplinkUrl;
3419
+ if (typeof window !== "undefined" && window.location) {
3420
+ try {
3421
+ window.location.href = deeplinkUrl;
3422
+ } catch (error) {
3423
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Failed to set deeplink location", {
3424
+ error: error instanceof Error ? error.message : String(error)
3425
+ });
3426
+ }
3075
3427
  }
3076
3428
  return {
3077
3429
  addresses: [],
@@ -3344,6 +3696,7 @@ var ProviderManager = class {
3344
3696
  authUrl,
3345
3697
  redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
3346
3698
  },
3699
+ unstable__auth2Options: this.config.unstable__auth2Options,
3347
3700
  embeddedWalletType: embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
3348
3701
  addressTypes: this.config.addressTypes || [AddressType.solana]
3349
3702
  });
@@ -3542,6 +3895,7 @@ var BrowserSDK = class {
3542
3895
  */
3543
3896
  async autoConnect() {
3544
3897
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
3898
+ await this.discoverWallets();
3545
3899
  const result = await this.providerManager.autoConnect();
3546
3900
  if (result) {
3547
3901
  debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
@@ -3689,40 +4043,17 @@ var BrowserSDK = class {
3689
4043
  }
3690
4044
  };
3691
4045
 
3692
- // src/waitForPhantomExtension.ts
3693
- import { isPhantomExtensionInstalled as isPhantomExtensionInstalled4 } from "@phantom/browser-injected-sdk";
3694
- async function waitForPhantomExtension(timeoutMs = 3e3) {
3695
- return new Promise((resolve) => {
3696
- const startTime = Date.now();
3697
- const checkInterval = 100;
3698
- const checkForExtension = () => {
3699
- try {
3700
- if (isPhantomExtensionInstalled4()) {
3701
- resolve(true);
3702
- return;
3703
- }
3704
- } catch (error) {
3705
- }
3706
- const elapsed = Date.now() - startTime;
3707
- if (elapsed >= timeoutMs) {
3708
- resolve(false);
3709
- return;
3710
- }
3711
- setTimeout(checkForExtension, checkInterval);
3712
- };
3713
- checkForExtension();
3714
- });
3715
- }
3716
-
3717
4046
  // src/index.ts
3718
4047
  import { NetworkId } from "@phantom/constants";
3719
- import { AddressType as AddressType3 } from "@phantom/client";
4048
+ import { AddressType as AddressType4 } from "@phantom/client";
4049
+ import { PHANTOM_ICON as PHANTOM_ICON3 } from "@phantom/constants";
3720
4050
  export {
3721
- AddressType3 as AddressType,
4051
+ AddressType4 as AddressType,
3722
4052
  BrowserSDK,
3723
4053
  DebugCategory,
3724
4054
  DebugLevel,
3725
4055
  NetworkId,
4056
+ PHANTOM_ICON3 as PHANTOM_ICON,
3726
4057
  debug,
3727
4058
  detectBrowser,
3728
4059
  getBrowserDisplayName,