@phantom/browser-sdk 1.0.0-beta.15 → 1.0.0-beta.16

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/README.md CHANGED
@@ -305,7 +305,9 @@ interface BrowserSDKConfig {
305
305
 
306
306
  ### Extension Detection
307
307
 
308
- For injected provider usage, you can check if the Phantom extension is installed:
308
+ #### waitForPhantomExtension
309
+
310
+ Check if the Phantom extension is installed:
309
311
 
310
312
  ```typescript
311
313
  import { waitForPhantomExtension } from "@phantom/browser-sdk";
@@ -319,6 +321,23 @@ if (isAvailable) {
319
321
  }
320
322
  ```
321
323
 
324
+ #### isPhantomLoginAvailable
325
+
326
+ Check if Phantom Login is available (requires extension to be installed and support the `phantom_login` feature):
327
+
328
+ ```typescript
329
+ import { isPhantomLoginAvailable } from "@phantom/browser-sdk";
330
+
331
+ const isAvailable = await isPhantomLoginAvailable();
332
+
333
+ if (isAvailable) {
334
+ console.log("Phantom Login is available!");
335
+ // Can use provider: "phantom" in connect()
336
+ } else {
337
+ console.log("Phantom Login is not available");
338
+ }
339
+ ```
340
+
322
341
  ### Core Methods
323
342
 
324
343
  #### connect()
@@ -552,6 +571,106 @@ Attempt auto-connection using existing session. Should be called after setting u
552
571
  await sdk.autoConnect();
553
572
  ```
554
573
 
574
+ ### Event Handlers
575
+
576
+ The SDK provides typed event handlers that allow you to listen for connection state changes. This is especially useful for `autoConnect()` flows where you need to track the connection result.
577
+
578
+ #### Available Events
579
+
580
+ ```typescript
581
+ import { BrowserSDK } from '@phantom/browser-sdk';
582
+ import type {
583
+ ConnectEventData,
584
+ ConnectStartEventData,
585
+ ConnectErrorEventData,
586
+ DisconnectEventData
587
+ } from '@phantom/browser-sdk';
588
+
589
+ const sdk = new BrowserSDK({
590
+ providerType: 'embedded',
591
+ appId: 'your-app-id',
592
+ addressTypes: [AddressType.solana],
593
+ });
594
+
595
+ // 1. connect_start - Fired when connection starts
596
+ sdk.on('connect_start', (data: ConnectStartEventData) => {
597
+ console.log('Connection starting:', data.source); // "auto-connect" | "manual-connect"
598
+ console.log('Auth options:', data.authOptions?.provider); // "google" | "apple" | etc.
599
+ });
600
+
601
+ // 2. connect - Fired when connection succeeds (includes full ConnectResult)
602
+ sdk.on('connect', (data: ConnectEventData) => {
603
+ console.log('Connected successfully!');
604
+ console.log('Provider type:', data.providerType); // "embedded" | "injected"
605
+ console.log('Wallet ID:', data.walletId); // only for embedded providers
606
+ console.log('Addresses:', data.addresses); // WalletAddress[]
607
+ console.log('Status:', data.status); // "pending" | "completed"
608
+ console.log('Source:', data.source); // "auto-connect" | "manual-connect" | "manual-existing" | "existing-session" | "manual"
609
+ });
610
+
611
+ // 3. connect_error - Fired when connection fails
612
+ sdk.on('connect_error', (data: ConnectErrorEventData) => {
613
+ console.error('Connection failed:', data.error);
614
+ console.log('Source:', data.source); // "auto-connect" | "manual-connect"
615
+ });
616
+
617
+ // 4. disconnect - Fired when disconnected
618
+ sdk.on('disconnect', (data: DisconnectEventData) => {
619
+ console.log('Disconnected from wallet');
620
+ console.log('Source:', data.source); // "manual"
621
+ });
622
+
623
+ // 5. error - General error handler
624
+ sdk.on('error', (error: unknown) => {
625
+ console.error('SDK error:', error);
626
+ });
627
+
628
+ // Don't forget to remove listeners when done
629
+ sdk.off('connect', handleConnect);
630
+ ```
631
+
632
+ #### Event Types
633
+
634
+ | Event | Payload Type | When Fired | Key Data |
635
+ |-------|-------------|------------|----------|
636
+ | `connect_start` | `ConnectStartEventData` | Connection initiated | `source`, `authOptions` |
637
+ | `connect` | `ConnectEventData` | Connection successful | `providerType`, `addresses`, `status`, `source`, `user`|
638
+ | `connect_error` | `ConnectErrorEventData` | Connection failed | `error`, `source` |
639
+ | `disconnect` | `DisconnectEventData` | Disconnected | `source` |
640
+ | `error` | `unknown` | General SDK errors | Error details |
641
+
642
+ #### Using Events with autoConnect()
643
+
644
+ Event handlers are especially useful with `autoConnect()` since it doesn't return a value:
645
+
646
+ ```typescript
647
+ const sdk = new BrowserSDK({
648
+ providerType: 'embedded',
649
+ appId: 'your-app-id',
650
+ addressTypes: [AddressType.solana],
651
+ autoConnect: true,
652
+ });
653
+
654
+ // Set up event listeners BEFORE autoConnect
655
+ sdk.on('connect', (data: ConnectEventData) => {
656
+ console.log('Auto-connected successfully!');
657
+ console.log('Provider type:', data.providerType);
658
+ console.log('Addresses:', data.addresses);
659
+
660
+ // Update your UI state here
661
+ updateUIWithAddresses(data.addresses);
662
+ });
663
+
664
+ sdk.on('connect_error', (data: ConnectErrorEventData) => {
665
+ console.log('Auto-connect failed:', data.error);
666
+ // Show connect button to user
667
+ showConnectButton();
668
+ });
669
+
670
+ // Auto-connect will trigger events
671
+ await sdk.autoConnect();
672
+ ```
673
+
555
674
  ### Auto-Confirm Methods (Injected Provider Only)
556
675
 
557
676
  The SDK provides auto-confirm functionality that allows automatic transaction confirmation for specified chains. This feature is only available when using the injected provider (Phantom browser extension).
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EmbeddedProviderConfig, AuthOptions, ConnectResult, WalletAddress, EmbeddedProviderEvent, EventCallback } from '@phantom/embedded-provider-core';
2
- export { AuthOptions, ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
2
+ export { AuthOptions, ConnectErrorEventData, ConnectEventData, ConnectResult, ConnectStartEventData, DisconnectEventData, EmbeddedProviderEvent, EmbeddedProviderEventMap, EventCallback, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
3
3
  import { ISolanaChain, IEthereumChain } from '@phantom/chain-interfaces';
4
4
  export { EthTransactionRequest, IEthereumChain, ISolanaChain } from '@phantom/chain-interfaces';
5
5
  import { AddressType } from '@phantom/client';
@@ -68,6 +68,7 @@ interface PhantomAppLoginResult {
68
68
  }
69
69
  interface PhantomApp {
70
70
  login(options: PhantomAppLoginOptions): Promise<PhantomAppLoginResult>;
71
+ features(): Promise<string[]>;
71
72
  }
72
73
  declare global {
73
74
  interface Window {
@@ -297,4 +298,26 @@ declare function getDeeplinkToPhantom(ref?: string): string;
297
298
  */
298
299
  declare function waitForPhantomExtension(timeoutMs?: number): Promise<boolean>;
299
300
 
300
- export { BrowserInfo, BrowserSDK, BrowserSDKConfig, DebugCallback, DebugCategory, DebugConfig, DebugLevel, DebugMessage, Provider, debug, detectBrowser, getBrowserDisplayName, getDeeplinkToPhantom, getPlatformName, isMobileDevice, parseBrowserFromUserAgent, waitForPhantomExtension };
301
+ /**
302
+ * Check if Phantom Login is available
303
+ *
304
+ * This function checks if:
305
+ * 1. The Phantom extension is installed
306
+ * 2. The extension supports the phantom_login feature
307
+ *
308
+ * @param timeoutMs - Maximum time to wait for extension in milliseconds (default: 3000)
309
+ * @returns Promise<boolean> - true if Phantom Login is available, false otherwise
310
+ *
311
+ * Usage:
312
+ * ```typescript
313
+ * const isAvailable = await isPhantomLoginAvailable();
314
+ * if (isAvailable) {
315
+ * console.log("Phantom Login is available!");
316
+ * } else {
317
+ * console.log("Phantom Login is not available");
318
+ * }
319
+ * ```
320
+ */
321
+ declare function isPhantomLoginAvailable(timeoutMs?: number): Promise<boolean>;
322
+
323
+ export { BrowserInfo, BrowserSDK, BrowserSDKConfig, DebugCallback, DebugCategory, DebugConfig, DebugLevel, DebugMessage, Provider, debug, detectBrowser, getBrowserDisplayName, getDeeplinkToPhantom, getPlatformName, isMobileDevice, isPhantomLoginAvailable, parseBrowserFromUserAgent, waitForPhantomExtension };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ __export(src_exports, {
31
31
  getDeeplinkToPhantom: () => getDeeplinkToPhantom,
32
32
  getPlatformName: () => getPlatformName,
33
33
  isMobileDevice: () => isMobileDevice,
34
+ isPhantomLoginAvailable: () => isPhantomLoginAvailable,
34
35
  parseBrowserFromUserAgent: () => parseBrowserFromUserAgent,
35
36
  waitForPhantomExtension: () => waitForPhantomExtension
36
37
  });
@@ -476,7 +477,12 @@ var InjectedProvider = class {
476
477
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
477
478
  }
478
479
  } catch (err) {
479
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
480
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", { error: err });
481
+ this.emit("connect_error", {
482
+ error: err instanceof Error ? err.message : "Failed to connect",
483
+ source: "manual-connect"
484
+ });
485
+ throw err;
480
486
  }
481
487
  }
482
488
  if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
@@ -492,7 +498,12 @@ var InjectedProvider = class {
492
498
  debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", { addresses: accounts });
493
499
  }
494
500
  } catch (err) {
495
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
501
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", { error: err });
502
+ this.emit("connect_error", {
503
+ error: err instanceof Error ? err.message : "Failed to connect",
504
+ source: "manual-connect"
505
+ });
506
+ throw err;
496
507
  }
497
508
  }
498
509
  if (connectedAddresses.length === 0) {
@@ -1129,7 +1140,7 @@ var BrowserAuthProvider = class {
1129
1140
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
1130
1141
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
1131
1142
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
1132
- sdk_version: "1.0.0-beta.15",
1143
+ sdk_version: "1.0.0-beta.16",
1133
1144
  sdk_type: "browser",
1134
1145
  platform: detectBrowser().name
1135
1146
  });
@@ -1267,6 +1278,26 @@ var BrowserPhantomAppProvider = class {
1267
1278
  "Phantom extension authentication is not yet implemented. The extension needs to expose an app.login API (window.phantom.app.login)."
1268
1279
  );
1269
1280
  }
1281
+ try {
1282
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
1283
+ throw new Error(
1284
+ "Phantom Login is not available. The extension does not support the features API."
1285
+ );
1286
+ }
1287
+ const features = await window.phantom.app.features();
1288
+ if (!Array.isArray(features) || !features.includes("phantom_login")) {
1289
+ throw new Error(
1290
+ "Phantom Login is not available. Please update your Phantom extension to use this authentication method."
1291
+ );
1292
+ }
1293
+ } catch (error) {
1294
+ if (error instanceof Error) {
1295
+ throw error;
1296
+ }
1297
+ throw new Error(
1298
+ "Failed to check Phantom Login availability. Please ensure you have the latest version of the Phantom extension."
1299
+ );
1300
+ }
1270
1301
  try {
1271
1302
  const result = await window.phantom.app.login({
1272
1303
  publicKey: options.publicKey,
@@ -1337,7 +1368,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
1337
1368
  // Full user agent for more detailed info
1338
1369
  [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
1339
1370
  [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1340
- [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
1371
+ [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.16"
1341
1372
  // Replaced at build time
1342
1373
  }
1343
1374
  };
@@ -1457,9 +1488,11 @@ var ProviderManager = class {
1457
1488
  to: targetProviderType,
1458
1489
  requestedProvider
1459
1490
  });
1460
- this.switchProvider(targetProviderType, {
1461
- embeddedWalletType: currentInfo?.embeddedWalletType || this.config.embeddedWalletType
1462
- });
1491
+ const switchOptions = {};
1492
+ if (targetProviderType === "embedded") {
1493
+ switchOptions.embeddedWalletType = currentInfo?.embeddedWalletType || this.config.embeddedWalletType;
1494
+ }
1495
+ this.switchProvider(targetProviderType, switchOptions);
1463
1496
  }
1464
1497
  }
1465
1498
  }
@@ -1469,12 +1502,16 @@ var ProviderManager = class {
1469
1502
  }
1470
1503
  debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
1471
1504
  const result = await this.currentProvider.connect(authOptions);
1505
+ const providerInfo = this.getCurrentProviderInfo();
1506
+ result.providerType = providerInfo?.type;
1472
1507
  debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
1473
- addressCount: result.addresses?.length || 0
1508
+ addressCount: result.addresses?.length || 0,
1509
+ providerType: result.providerType
1474
1510
  });
1475
1511
  this.saveProviderPreference();
1476
1512
  debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
1477
- addresses: result.addresses
1513
+ addresses: result.addresses,
1514
+ providerType: result.providerType
1478
1515
  });
1479
1516
  return result;
1480
1517
  }
@@ -1658,7 +1695,11 @@ var ProviderManager = class {
1658
1695
  }
1659
1696
  debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider");
1660
1697
  this.createProvider("injected");
1661
- this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1698
+ const switchOptions = {};
1699
+ if (defaultType === "embedded") {
1700
+ switchOptions.embeddedWalletType = defaultEmbeddedType;
1701
+ }
1702
+ this.switchProvider(defaultType, switchOptions);
1662
1703
  }
1663
1704
  /**
1664
1705
  * Create a provider instance
@@ -2030,6 +2071,49 @@ function getDeeplinkToPhantom(ref) {
2030
2071
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
2031
2072
  }
2032
2073
 
2074
+ // src/isPhantomLoginAvailable.ts
2075
+ var import_browser_injected_sdk4 = require("@phantom/browser-injected-sdk");
2076
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2077
+ const extensionInstalled = await waitForExtension(timeoutMs);
2078
+ if (!extensionInstalled) {
2079
+ return false;
2080
+ }
2081
+ try {
2082
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2083
+ return false;
2084
+ }
2085
+ const features = await window.phantom.app.features();
2086
+ if (!Array.isArray(features)) {
2087
+ return false;
2088
+ }
2089
+ return features.includes("phantom_login");
2090
+ } catch (error) {
2091
+ return false;
2092
+ }
2093
+ }
2094
+ async function waitForExtension(timeoutMs) {
2095
+ return new Promise((resolve) => {
2096
+ const startTime = Date.now();
2097
+ const checkInterval = 100;
2098
+ const checkForExtension = () => {
2099
+ try {
2100
+ if ((0, import_browser_injected_sdk4.isPhantomExtensionInstalled)()) {
2101
+ resolve(true);
2102
+ return;
2103
+ }
2104
+ } catch (error) {
2105
+ }
2106
+ const elapsed = Date.now() - startTime;
2107
+ if (elapsed >= timeoutMs) {
2108
+ resolve(false);
2109
+ return;
2110
+ }
2111
+ setTimeout(checkForExtension, checkInterval);
2112
+ };
2113
+ checkForExtension();
2114
+ });
2115
+ }
2116
+
2033
2117
  // src/index.ts
2034
2118
  var import_constants5 = require("@phantom/constants");
2035
2119
  var import_client5 = require("@phantom/client");
package/dist/index.mjs CHANGED
@@ -440,7 +440,12 @@ var InjectedProvider = class {
440
440
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
441
441
  }
442
442
  } catch (err) {
443
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
443
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", { error: err });
444
+ this.emit("connect_error", {
445
+ error: err instanceof Error ? err.message : "Failed to connect",
446
+ source: "manual-connect"
447
+ });
448
+ throw err;
444
449
  }
445
450
  }
446
451
  if (this.addressTypes.includes(AddressType4.ethereum)) {
@@ -456,7 +461,12 @@ var InjectedProvider = class {
456
461
  debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", { addresses: accounts });
457
462
  }
458
463
  } catch (err) {
459
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
464
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", { error: err });
465
+ this.emit("connect_error", {
466
+ error: err instanceof Error ? err.message : "Failed to connect",
467
+ source: "manual-connect"
468
+ });
469
+ throw err;
460
470
  }
461
471
  }
462
472
  if (connectedAddresses.length === 0) {
@@ -1093,7 +1103,7 @@ var BrowserAuthProvider = class {
1093
1103
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
1094
1104
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
1095
1105
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
1096
- sdk_version: "1.0.0-beta.15",
1106
+ sdk_version: "1.0.0-beta.16",
1097
1107
  sdk_type: "browser",
1098
1108
  platform: detectBrowser().name
1099
1109
  });
@@ -1231,6 +1241,26 @@ var BrowserPhantomAppProvider = class {
1231
1241
  "Phantom extension authentication is not yet implemented. The extension needs to expose an app.login API (window.phantom.app.login)."
1232
1242
  );
1233
1243
  }
1244
+ try {
1245
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
1246
+ throw new Error(
1247
+ "Phantom Login is not available. The extension does not support the features API."
1248
+ );
1249
+ }
1250
+ const features = await window.phantom.app.features();
1251
+ if (!Array.isArray(features) || !features.includes("phantom_login")) {
1252
+ throw new Error(
1253
+ "Phantom Login is not available. Please update your Phantom extension to use this authentication method."
1254
+ );
1255
+ }
1256
+ } catch (error) {
1257
+ if (error instanceof Error) {
1258
+ throw error;
1259
+ }
1260
+ throw new Error(
1261
+ "Failed to check Phantom Login availability. Please ensure you have the latest version of the Phantom extension."
1262
+ );
1263
+ }
1234
1264
  try {
1235
1265
  const result = await window.phantom.app.login({
1236
1266
  publicKey: options.publicKey,
@@ -1301,7 +1331,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1301
1331
  // Full user agent for more detailed info
1302
1332
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
1303
1333
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1304
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
1334
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.16"
1305
1335
  // Replaced at build time
1306
1336
  }
1307
1337
  };
@@ -1421,9 +1451,11 @@ var ProviderManager = class {
1421
1451
  to: targetProviderType,
1422
1452
  requestedProvider
1423
1453
  });
1424
- this.switchProvider(targetProviderType, {
1425
- embeddedWalletType: currentInfo?.embeddedWalletType || this.config.embeddedWalletType
1426
- });
1454
+ const switchOptions = {};
1455
+ if (targetProviderType === "embedded") {
1456
+ switchOptions.embeddedWalletType = currentInfo?.embeddedWalletType || this.config.embeddedWalletType;
1457
+ }
1458
+ this.switchProvider(targetProviderType, switchOptions);
1427
1459
  }
1428
1460
  }
1429
1461
  }
@@ -1433,12 +1465,16 @@ var ProviderManager = class {
1433
1465
  }
1434
1466
  debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
1435
1467
  const result = await this.currentProvider.connect(authOptions);
1468
+ const providerInfo = this.getCurrentProviderInfo();
1469
+ result.providerType = providerInfo?.type;
1436
1470
  debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
1437
- addressCount: result.addresses?.length || 0
1471
+ addressCount: result.addresses?.length || 0,
1472
+ providerType: result.providerType
1438
1473
  });
1439
1474
  this.saveProviderPreference();
1440
1475
  debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
1441
- addresses: result.addresses
1476
+ addresses: result.addresses,
1477
+ providerType: result.providerType
1442
1478
  });
1443
1479
  return result;
1444
1480
  }
@@ -1622,7 +1658,11 @@ var ProviderManager = class {
1622
1658
  }
1623
1659
  debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider");
1624
1660
  this.createProvider("injected");
1625
- this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1661
+ const switchOptions = {};
1662
+ if (defaultType === "embedded") {
1663
+ switchOptions.embeddedWalletType = defaultEmbeddedType;
1664
+ }
1665
+ this.switchProvider(defaultType, switchOptions);
1626
1666
  }
1627
1667
  /**
1628
1668
  * Create a provider instance
@@ -1994,6 +2034,49 @@ function getDeeplinkToPhantom(ref) {
1994
2034
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1995
2035
  }
1996
2036
 
2037
+ // src/isPhantomLoginAvailable.ts
2038
+ import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
2039
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2040
+ const extensionInstalled = await waitForExtension(timeoutMs);
2041
+ if (!extensionInstalled) {
2042
+ return false;
2043
+ }
2044
+ try {
2045
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2046
+ return false;
2047
+ }
2048
+ const features = await window.phantom.app.features();
2049
+ if (!Array.isArray(features)) {
2050
+ return false;
2051
+ }
2052
+ return features.includes("phantom_login");
2053
+ } catch (error) {
2054
+ return false;
2055
+ }
2056
+ }
2057
+ async function waitForExtension(timeoutMs) {
2058
+ return new Promise((resolve) => {
2059
+ const startTime = Date.now();
2060
+ const checkInterval = 100;
2061
+ const checkForExtension = () => {
2062
+ try {
2063
+ if (isPhantomExtensionInstalled3()) {
2064
+ resolve(true);
2065
+ return;
2066
+ }
2067
+ } catch (error) {
2068
+ }
2069
+ const elapsed = Date.now() - startTime;
2070
+ if (elapsed >= timeoutMs) {
2071
+ resolve(false);
2072
+ return;
2073
+ }
2074
+ setTimeout(checkForExtension, checkInterval);
2075
+ };
2076
+ checkForExtension();
2077
+ });
2078
+ }
2079
+
1997
2080
  // src/index.ts
1998
2081
  import { NetworkId } from "@phantom/constants";
1999
2082
  import { AddressType as AddressType5 } from "@phantom/client";
@@ -2009,6 +2092,7 @@ export {
2009
2092
  getDeeplinkToPhantom,
2010
2093
  getPlatformName,
2011
2094
  isMobileDevice,
2095
+ isPhantomLoginAvailable,
2012
2096
  parseBrowserFromUserAgent,
2013
2097
  waitForPhantomExtension
2014
2098
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/browser-sdk",
3
- "version": "1.0.0-beta.15",
3
+ "version": "1.0.0-beta.16",
4
4
  "description": "Browser SDK for Phantom Wallet",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -31,9 +31,9 @@
31
31
  "@phantom/base64url": "^1.0.0-beta.7",
32
32
  "@phantom/browser-injected-sdk": "^1.0.0-beta.5",
33
33
  "@phantom/chain-interfaces": "^1.0.0-beta.7",
34
- "@phantom/client": "^1.0.0-beta.15",
34
+ "@phantom/client": "^1.0.0-beta.16",
35
35
  "@phantom/constants": "^1.0.0-beta.7",
36
- "@phantom/embedded-provider-core": "^1.0.0-beta.15",
36
+ "@phantom/embedded-provider-core": "^1.0.0-beta.16",
37
37
  "@phantom/indexed-db-stamper": "^1.0.0-beta.1",
38
38
  "@phantom/parsers": "^1.0.0-beta.7",
39
39
  "@phantom/sdk-types": "^1.0.0-beta.7",