@phantom/browser-sdk 1.0.0-beta.2 → 1.0.0-beta.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/README.md CHANGED
@@ -44,8 +44,7 @@ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
44
44
  const sdk = new BrowserSDK({
45
45
  providerType: "embedded",
46
46
  addressTypes: [AddressType.solana, AddressType.ethereum],
47
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
48
- appId: "your-app-id",
47
+ appId: "your-app-id", // Get your app ID from phantom.com/portal
49
48
  });
50
49
 
51
50
  const { addresses } = await sdk.connect();
@@ -190,48 +189,29 @@ Creates a non-custodial wallet embedded in your application. Requires API config
190
189
  const sdk = new BrowserSDK({
191
190
  providerType: "embedded",
192
191
  addressTypes: [AddressType.solana, AddressType.ethereum],
193
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
194
- appId: "your-app-id",
195
- embeddedWalletType: "app-wallet", // or 'user-wallet'
192
+ appId: "your-app-id", // Get your app ID from phantom.com/portal
196
193
  authOptions: {
197
- authUrl: "https://auth.phantom.app", // optional, defaults to "https://connect.phantom.app"
194
+ authUrl: "https://connect.phantom.app/login", // optional, defaults to "https://connect.phantom.app/login"
198
195
  redirectUrl: "https://yourapp.com/callback", // optional, defaults to current page
199
196
  },
200
197
  autoConnect: true, // optional, auto-connect to existing session (default: true for embedded)
201
198
  });
202
199
  ```
203
200
 
204
- ### Embedded Wallet Types
205
-
206
- #### App Wallet (`'app-wallet'`)
207
-
208
- - **New wallets** created per application
209
- - **Unfunded** by default - you need to fund them
210
- - **Independent** from user's existing Phantom wallet
211
- - **Perfect for**: Gaming, DeFi protocols, or apps that need fresh wallets
212
-
213
- ```typescript
214
- const sdk = new BrowserSDK({
215
- providerType: "embedded",
216
- embeddedWalletType: "app-wallet",
217
- addressTypes: [AddressType.solana],
218
- // ... other config
219
- });
220
- ```
201
+ ### Embedded Wallet Type
221
202
 
222
203
  #### User Wallet (`'user-wallet'`)
223
204
 
224
205
  - **Uses Phantom authentication** - user logs in with existing Phantom account
225
206
  - **Potentially funded** - brings in user's existing wallet balance
226
207
  - **Connected** to user's Phantom ecosystem
227
- - **Perfect for**: Trading platforms, NFT marketplaces, or apps needing funded wallets
208
+ - **Perfect for**: All embedded wallet use cases
228
209
 
229
210
  ```typescript
230
211
  const sdk = new BrowserSDK({
231
212
  providerType: "embedded",
232
- embeddedWalletType: "user-wallet",
213
+ appId: "your-app-id",
233
214
  addressTypes: [AddressType.solana, AddressType.ethereum],
234
- // ... other config
235
215
  });
236
216
  ```
237
217
 
@@ -242,28 +222,6 @@ const sdk = new BrowserSDK({
242
222
  | `AddressType.solana` | Solana Mainnet, Devnet, Testnet |
243
223
  | `AddressType.ethereum` | Ethereum, Polygon, Arbitrum, and more |
244
224
 
245
- ### Solana Provider Configuration
246
-
247
- When using `AddressType.solana`, you can choose between two Solana libraries:
248
-
249
- ```typescript
250
- const sdk = new BrowserSDK({
251
- providerType: "embedded",
252
- addressTypes: [AddressType.solana],
253
- solanaProvider: "web3js", // or 'kit'
254
- // ... other config
255
- });
256
- ```
257
-
258
- **Provider Options:**
259
-
260
- - `'web3js'` (default) - Uses `@solana/web3.js` library
261
- - `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
262
-
263
- **When to use each:**
264
-
265
- - **@solana/web3.js**: Better ecosystem compatibility, wider community support
266
- - **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
267
225
 
268
226
  ### Auto-Connect Feature
269
227
 
@@ -272,8 +230,8 @@ The SDK can automatically reconnect to existing sessions when instantiated, prov
272
230
  ```typescript
273
231
  const sdk = new BrowserSDK({
274
232
  providerType: "embedded",
233
+ appId: "your-app-id",
275
234
  addressTypes: [AddressType.solana],
276
- // ... other config
277
235
  autoConnect: true, // Default: true for embedded, false for injected
278
236
  });
279
237
 
@@ -295,8 +253,8 @@ if (sdk.isConnected()) {
295
253
  ```typescript
296
254
  const sdk = new BrowserSDK({
297
255
  providerType: "embedded",
256
+ appId: "your-app-id",
298
257
  addressTypes: [AddressType.solana],
299
- // ... other config
300
258
  autoConnect: false, // Disable auto-connect
301
259
  });
302
260
 
@@ -320,15 +278,16 @@ interface BrowserSDKConfig {
320
278
  addressTypes?: [AddressType, ...AddressType[]]; // Networks to enable (e.g., [AddressType.solana])
321
279
 
322
280
  // Required for embedded provider only
323
- apiBaseUrl?: string; // Phantom API base URL
324
- appId?: string; // Your app ID (required for embedded provider)
281
+ appId?: string; // Your app ID from phantom.com/portal (required for embedded provider)
282
+
283
+ // Optional configuration
284
+ apiBaseUrl?: string; // Phantom API base URL (optional, has default)
325
285
  authOptions?: {
326
- authUrl?: string; // Custom auth URL (default: "https://connect.phantom.app")
327
- redirectUrl?: string; // Custom redirect URL after authentication
286
+ authUrl?: string; // Custom auth URL (optional, defaults to "https://connect.phantom.app/login")
287
+ redirectUrl?: string; // Custom redirect URL after authentication (optional)
328
288
  };
329
- embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
330
- solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
331
- autoConnect?: boolean; // Enable auto-connect to existing sessions (default: true)
289
+ embeddedWalletType?: "user-wallet"; // Wallet type (optional, defaults to "user-wallet", currently the only supported type)
290
+ autoConnect?: boolean; // Enable auto-connect to existing sessions (optional, defaults to true for embedded)
332
291
  }
333
292
  ```
334
293
 
@@ -748,7 +707,7 @@ import { BrowserSDK, DebugLevel } from "@phantom/browser-sdk";
748
707
 
749
708
  const sdk = new BrowserSDK({
750
709
  providerType: "embedded",
751
- // ... other config
710
+ appId: "your-app-id",
752
711
  });
753
712
 
754
713
  // Store debug messages
@@ -815,7 +774,6 @@ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
815
774
  const sdk = new BrowserSDK({
816
775
  providerType: "injected",
817
776
  addressTypes: [AddressType.solana],
818
- solanaProvider: "web3js",
819
777
  });
820
778
 
821
779
  await sdk.connect();
@@ -869,7 +827,6 @@ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
869
827
  const sdk = new BrowserSDK({
870
828
  providerType: "injected",
871
829
  addressTypes: [AddressType.solana],
872
- solanaProvider: "kit",
873
830
  });
874
831
 
875
832
  await sdk.connect();
package/dist/index.d.ts CHANGED
@@ -57,13 +57,17 @@ interface DebugConfig {
57
57
  level?: DebugLevel;
58
58
  callback?: DebugCallback;
59
59
  }
60
- interface BrowserSDKConfig extends Partial<EmbeddedProviderConfig> {
60
+ interface BrowserSDKConfig extends Partial<Omit<EmbeddedProviderConfig, "authOptions">> {
61
61
  providerType: "injected" | "embedded" | (string & Record<never, never>);
62
62
  addressTypes: [AddressType, ...AddressType[]];
63
63
  apiBaseUrl?: string;
64
64
  appId?: string;
65
65
  embeddedWalletType?: "app-wallet" | "user-wallet" | (string & Record<never, never>);
66
66
  autoConnect?: boolean;
67
+ authOptions?: {
68
+ authUrl?: string;
69
+ redirectUrl?: string;
70
+ };
67
71
  }
68
72
 
69
73
  interface Provider {
@@ -205,18 +209,13 @@ declare class BrowserSDK {
205
209
  getSupportedAutoConfirmChains(): Promise<AutoConfirmSupportedChainsResult>;
206
210
  }
207
211
 
208
- /**
209
- * Constants used throughout the browser SDK
210
- */
211
- declare const DEFAULT_AUTH_URL = "https://connect.phantom.app";
212
- declare const DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
213
-
214
212
  /**
215
213
  * Browser detection utility to identify browser name and version
216
214
  */
217
215
  interface BrowserInfo {
218
216
  name: string;
219
217
  version: string;
218
+ userAgent: string;
220
219
  }
221
220
  /**
222
221
  * Parse browser information from a user agent string
@@ -237,6 +236,18 @@ declare function getPlatformName(): string;
237
236
  * Format: "Chrome 120.0" or "Firefox 119.0"
238
237
  */
239
238
  declare function getBrowserDisplayName(): string;
239
+ /**
240
+ * Detect if the current device is a mobile device
241
+ * Checks user agent for mobile indicators and screen size
242
+ */
243
+ declare function isMobileDevice(): boolean;
244
+
245
+ /**
246
+ * Generates a deeplink URL to open the current page in Phantom mobile app
247
+ * @param ref Optional referrer parameter
248
+ * @returns Phantom mobile app deeplink URL
249
+ */
250
+ declare function getDeeplinkToPhantom(ref?: string): string;
240
251
 
241
252
  /**
242
253
  * Wait for Phantom extension to be available with retry logic
@@ -256,4 +267,4 @@ declare function getBrowserDisplayName(): string;
256
267
  */
257
268
  declare function waitForPhantomExtension(timeoutMs?: number): Promise<boolean>;
258
269
 
259
- export { BrowserInfo, BrowserSDK, BrowserSDKConfig, DEFAULT_AUTH_URL, DEFAULT_WALLET_API_URL, DebugCallback, DebugCategory, DebugConfig, DebugLevel, DebugMessage, Provider, debug, detectBrowser, getBrowserDisplayName, getPlatformName, parseBrowserFromUserAgent, waitForPhantomExtension };
270
+ export { BrowserInfo, BrowserSDK, BrowserSDKConfig, DebugCallback, DebugCategory, DebugConfig, DebugLevel, DebugMessage, Provider, debug, detectBrowser, getBrowserDisplayName, getDeeplinkToPhantom, getPlatformName, isMobileDevice, parseBrowserFromUserAgent, waitForPhantomExtension };
package/dist/index.js CHANGED
@@ -22,15 +22,15 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  AddressType: () => import_client5.AddressType,
24
24
  BrowserSDK: () => BrowserSDK,
25
- DEFAULT_AUTH_URL: () => DEFAULT_AUTH_URL,
26
- DEFAULT_WALLET_API_URL: () => DEFAULT_WALLET_API_URL,
27
25
  DebugCategory: () => DebugCategory,
28
26
  DebugLevel: () => DebugLevel,
29
- NetworkId: () => import_constants2.NetworkId,
27
+ NetworkId: () => import_constants5.NetworkId,
30
28
  debug: () => debug,
31
29
  detectBrowser: () => detectBrowser,
32
30
  getBrowserDisplayName: () => getBrowserDisplayName,
31
+ getDeeplinkToPhantom: () => getDeeplinkToPhantom,
33
32
  getPlatformName: () => getPlatformName,
33
+ isMobileDevice: () => isMobileDevice,
34
34
  parseBrowserFromUserAgent: () => parseBrowserFromUserAgent,
35
35
  waitForPhantomExtension: () => waitForPhantomExtension
36
36
  });
@@ -178,8 +178,27 @@ var InjectedSolanaChain = class {
178
178
  const result = await this.phantom.solana.signAndSendTransaction(transaction);
179
179
  return { signature: result.signature };
180
180
  }
181
- signAllTransactions(_transactions) {
182
- return Promise.reject(new Error("Sign-only transactions not supported by injected provider"));
181
+ async signAllTransactions(transactions) {
182
+ if (!this.callbacks.isConnected()) {
183
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
184
+ }
185
+ try {
186
+ const result = await this.phantom.solana.signAllTransactions(transactions);
187
+ return result;
188
+ } catch (error) {
189
+ return Promise.reject(error);
190
+ }
191
+ }
192
+ async signAndSendAllTransactions(transactions) {
193
+ if (!this.callbacks.isConnected()) {
194
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
195
+ }
196
+ try {
197
+ const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
198
+ return { signatures: result.signatures };
199
+ } catch (error) {
200
+ return Promise.reject(error);
201
+ }
183
202
  }
184
203
  switchNetwork(_network) {
185
204
  return Promise.resolve();
@@ -808,15 +827,19 @@ var BrowserURLParamsAccessor = class {
808
827
  };
809
828
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
810
829
 
811
- // src/constants.ts
812
- var DEFAULT_AUTH_URL = "https://connect.phantom.app";
813
- var DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
814
-
815
830
  // src/providers/embedded/adapters/auth.ts
831
+ var import_constants = require("@phantom/constants");
816
832
  var BrowserAuthProvider = class {
817
833
  constructor(urlParamsAccessor) {
818
834
  this.urlParamsAccessor = urlParamsAccessor;
819
835
  }
836
+ getValidatedCurrentUrl() {
837
+ const currentUrl = window.location.href;
838
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
839
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
840
+ }
841
+ return currentUrl;
842
+ }
820
843
  authenticate(options) {
821
844
  return new Promise((resolve) => {
822
845
  if ("jwtToken" in options) {
@@ -831,13 +854,13 @@ var BrowserAuthProvider = class {
831
854
  authUrl: phantomOptions.authUrl,
832
855
  hasCustomData: !!phantomOptions.customAuthData
833
856
  });
834
- const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
857
+ const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
835
858
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
836
859
  const params = new URLSearchParams({
837
860
  organization_id: phantomOptions.organizationId,
838
861
  parent_organization_id: phantomOptions.parentOrganizationId,
839
862
  app_id: phantomOptions.appId,
840
- redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? window.location.href : ""),
863
+ redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
841
864
  session_id: phantomOptions.sessionId,
842
865
  clear_previous_session: true.toString()
843
866
  });
@@ -865,6 +888,9 @@ var BrowserAuthProvider = class {
865
888
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
866
889
  const authUrl = `${baseUrl}?${params.toString()}`;
867
890
  debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
891
+ if (!authUrl.startsWith("https:")) {
892
+ throw new Error("Invalid auth URL - only HTTPS URLs are allowed for authentication");
893
+ }
868
894
  window.location.href = authUrl;
869
895
  resolve();
870
896
  });
@@ -953,7 +979,7 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
953
979
  let name = "unknown";
954
980
  let version = "unknown";
955
981
  if (!userAgent || typeof userAgent !== "string") {
956
- return { name, version };
982
+ return { name, version, userAgent: "unknown" };
957
983
  }
958
984
  try {
959
985
  if (userAgent.includes("Edg/")) {
@@ -1035,11 +1061,11 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
1035
1061
  }
1036
1062
  } catch (error) {
1037
1063
  }
1038
- return { name, version };
1064
+ return { name, version, userAgent };
1039
1065
  }
1040
1066
  function detectBrowser() {
1041
1067
  if (typeof window === "undefined" || !window.navigator?.userAgent) {
1042
- return { name: "unknown", version: "unknown" };
1068
+ return { name: "unknown", version: "unknown", userAgent: "unknown" };
1043
1069
  }
1044
1070
  const userAgent = window.navigator.userAgent;
1045
1071
  const hasBraveAPI = !!navigator.brave;
@@ -1054,8 +1080,41 @@ function getBrowserDisplayName() {
1054
1080
  const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1055
1081
  return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
1056
1082
  }
1083
+ function isMobileDevice() {
1084
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1085
+ return false;
1086
+ }
1087
+ const userAgent = window.navigator.userAgent.toLowerCase();
1088
+ const mobilePatterns = [
1089
+ /android/,
1090
+ /iphone|ipad|ipod/,
1091
+ /blackberry/,
1092
+ /windows phone/,
1093
+ /mobile/,
1094
+ /tablet/,
1095
+ /silk/,
1096
+ /kindle/,
1097
+ /opera mini/,
1098
+ /opera mobi/
1099
+ ];
1100
+ const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
1101
+ let isSmallScreen = false;
1102
+ try {
1103
+ isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
1104
+ } catch (error) {
1105
+ isSmallScreen = false;
1106
+ }
1107
+ let isTouchDevice = false;
1108
+ try {
1109
+ isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1110
+ } catch (error) {
1111
+ isTouchDevice = false;
1112
+ }
1113
+ return isMobileUA || isSmallScreen && isTouchDevice;
1114
+ }
1057
1115
 
1058
1116
  // src/providers/embedded/index.ts
1117
+ var import_constants2 = require("@phantom/constants");
1059
1118
  var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
1060
1119
  constructor(config) {
1061
1120
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
@@ -1066,13 +1125,25 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
1066
1125
  keyName: "signing-key"
1067
1126
  });
1068
1127
  const platformName = getPlatformName();
1128
+ const { name: browserName, version } = detectBrowser();
1069
1129
  const platform = {
1070
1130
  storage: new BrowserStorage(),
1071
1131
  authProvider: new BrowserAuthProvider(urlParamsAccessor),
1072
1132
  urlParamsAccessor,
1073
1133
  stamper,
1074
- name: platformName
1134
+ name: platformName,
1075
1135
  // Use detected browser name and version for identification
1136
+ analyticsHeaders: {
1137
+ [import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
1138
+ [import_constants2.ANALYTICS_HEADERS.PLATFORM]: browserName,
1139
+ // firefox, chrome, safari, etc.
1140
+ [import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
1141
+ // Full user agent for more detailed info
1142
+ [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
1143
+ [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1144
+ [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.4"
1145
+ // Replaced at build time
1146
+ }
1076
1147
  };
1077
1148
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
1078
1149
  const logger = new BrowserLogger();
@@ -1082,6 +1153,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
1082
1153
  };
1083
1154
 
1084
1155
  // src/ProviderManager.ts
1156
+ var import_constants3 = require("@phantom/constants");
1085
1157
  var ProviderManager = class {
1086
1158
  // Track which providers have forwarding set up
1087
1159
  constructor(config) {
@@ -1100,6 +1172,15 @@ var ProviderManager = class {
1100
1172
  currentProviderKey: this.currentProviderKey
1101
1173
  });
1102
1174
  }
1175
+ getValidatedCurrentUrl() {
1176
+ if (typeof window === "undefined")
1177
+ return "";
1178
+ const currentUrl = window.location.href;
1179
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
1180
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
1181
+ }
1182
+ return currentUrl;
1183
+ }
1103
1184
  /**
1104
1185
  * Switch to a different provider type
1105
1186
  */
@@ -1131,7 +1212,8 @@ var ProviderManager = class {
1131
1212
  getCurrentProviderInfo() {
1132
1213
  if (!this.currentProviderKey)
1133
1214
  return null;
1134
- const [type, embeddedWalletType] = this.currentProviderKey.split("-");
1215
+ const parts = this.currentProviderKey.split("-");
1216
+ const [type, embeddedWalletType] = parts;
1135
1217
  return {
1136
1218
  type,
1137
1219
  embeddedWalletType
@@ -1277,7 +1359,7 @@ var ProviderManager = class {
1277
1359
  */
1278
1360
  setDefaultProvider() {
1279
1361
  const defaultType = this.config.providerType || "embedded";
1280
- const defaultEmbeddedType = this.config.embeddedWalletType || "app-wallet";
1362
+ const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
1281
1363
  this.createProvider(defaultType, defaultEmbeddedType);
1282
1364
  this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1283
1365
  }
@@ -1291,22 +1373,28 @@ var ProviderManager = class {
1291
1373
  let provider;
1292
1374
  if (type === "injected") {
1293
1375
  provider = new InjectedProvider({
1294
- solanaProvider: this.config.solanaProvider || "web3js",
1295
1376
  addressTypes: this.config.addressTypes
1296
1377
  });
1297
- } else {
1298
- if (!this.config.apiBaseUrl || !this.config.appId) {
1299
- throw new Error("apiBaseUrl and appId are required for embedded provider");
1378
+ } else if (type === "embedded") {
1379
+ if (!this.config.appId) {
1380
+ throw new Error("appId is required for embedded provider");
1300
1381
  }
1382
+ const apiBaseUrl = this.config.apiBaseUrl || import_constants3.DEFAULT_WALLET_API_URL;
1383
+ const authUrl = this.config.authOptions?.authUrl || import_constants3.DEFAULT_AUTH_URL;
1301
1384
  provider = new EmbeddedProvider({
1302
- apiBaseUrl: this.config.apiBaseUrl,
1385
+ apiBaseUrl,
1303
1386
  organizationId: this.config.appId,
1304
1387
  appId: this.config.appId,
1305
- authOptions: this.config.authOptions,
1306
- embeddedWalletType: embeddedWalletType || "app-wallet",
1307
- addressTypes: this.config.addressTypes,
1308
- solanaProvider: this.config.solanaProvider || "web3js"
1388
+ authOptions: {
1389
+ ...this.config.authOptions || {},
1390
+ authUrl,
1391
+ redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
1392
+ },
1393
+ embeddedWalletType: embeddedWalletType || import_constants3.DEFAULT_EMBEDDED_WALLET_TYPE,
1394
+ addressTypes: this.config.addressTypes
1309
1395
  });
1396
+ } else {
1397
+ throw new Error(`Unsupported provider type: ${type}`);
1310
1398
  }
1311
1399
  this.providers.set(key, provider);
1312
1400
  }
@@ -1316,8 +1404,10 @@ var ProviderManager = class {
1316
1404
  getProviderKey(type, embeddedWalletType) {
1317
1405
  if (type === "injected") {
1318
1406
  return "injected";
1407
+ } else if (type === "embedded") {
1408
+ return `embedded-${embeddedWalletType || "app-wallet"}`;
1319
1409
  }
1320
- return `embedded-${embeddedWalletType || "app-wallet"}`;
1410
+ throw new Error(`Unsupported provider type: ${type}`);
1321
1411
  }
1322
1412
  /**
1323
1413
  * Save provider preference to localStorage
@@ -1378,6 +1468,7 @@ async function waitForPhantomExtension(timeoutMs = 3e3) {
1378
1468
  }
1379
1469
 
1380
1470
  // src/BrowserSDK.ts
1471
+ var import_constants4 = require("@phantom/constants");
1381
1472
  var BrowserSDK = class {
1382
1473
  constructor(config) {
1383
1474
  debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
@@ -1389,7 +1480,7 @@ var BrowserSDK = class {
1389
1480
  debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
1390
1481
  throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
1391
1482
  }
1392
- const embeddedWalletType = config.embeddedWalletType || "app-wallet";
1483
+ const embeddedWalletType = config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE;
1393
1484
  if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
1394
1485
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
1395
1486
  embeddedWalletType: config.embeddedWalletType
@@ -1677,6 +1768,16 @@ var BrowserSDK = class {
1677
1768
  // src/types.ts
1678
1769
  var import_client4 = require("@phantom/client");
1679
1770
 
1771
+ // src/utils/deeplink.ts
1772
+ function getDeeplinkToPhantom(ref) {
1773
+ if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
1774
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
1775
+ }
1776
+ const currentUrl = encodeURIComponent(window.location.href);
1777
+ const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
1778
+ return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1779
+ }
1780
+
1680
1781
  // src/index.ts
1681
- var import_constants2 = require("@phantom/constants");
1782
+ var import_constants5 = require("@phantom/constants");
1682
1783
  var import_client5 = require("@phantom/client");
package/dist/index.mjs CHANGED
@@ -142,8 +142,27 @@ var InjectedSolanaChain = class {
142
142
  const result = await this.phantom.solana.signAndSendTransaction(transaction);
143
143
  return { signature: result.signature };
144
144
  }
145
- signAllTransactions(_transactions) {
146
- return Promise.reject(new Error("Sign-only transactions not supported by injected provider"));
145
+ async signAllTransactions(transactions) {
146
+ if (!this.callbacks.isConnected()) {
147
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
148
+ }
149
+ try {
150
+ const result = await this.phantom.solana.signAllTransactions(transactions);
151
+ return result;
152
+ } catch (error) {
153
+ return Promise.reject(error);
154
+ }
155
+ }
156
+ async signAndSendAllTransactions(transactions) {
157
+ if (!this.callbacks.isConnected()) {
158
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
159
+ }
160
+ try {
161
+ const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
162
+ return { signatures: result.signatures };
163
+ } catch (error) {
164
+ return Promise.reject(error);
165
+ }
147
166
  }
148
167
  switchNetwork(_network) {
149
168
  return Promise.resolve();
@@ -772,15 +791,19 @@ var BrowserURLParamsAccessor = class {
772
791
  };
773
792
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
774
793
 
775
- // src/constants.ts
776
- var DEFAULT_AUTH_URL = "https://connect.phantom.app";
777
- var DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
778
-
779
794
  // src/providers/embedded/adapters/auth.ts
795
+ import { DEFAULT_AUTH_URL } from "@phantom/constants";
780
796
  var BrowserAuthProvider = class {
781
797
  constructor(urlParamsAccessor) {
782
798
  this.urlParamsAccessor = urlParamsAccessor;
783
799
  }
800
+ getValidatedCurrentUrl() {
801
+ const currentUrl = window.location.href;
802
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
803
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
804
+ }
805
+ return currentUrl;
806
+ }
784
807
  authenticate(options) {
785
808
  return new Promise((resolve) => {
786
809
  if ("jwtToken" in options) {
@@ -801,7 +824,7 @@ var BrowserAuthProvider = class {
801
824
  organization_id: phantomOptions.organizationId,
802
825
  parent_organization_id: phantomOptions.parentOrganizationId,
803
826
  app_id: phantomOptions.appId,
804
- redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? window.location.href : ""),
827
+ redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
805
828
  session_id: phantomOptions.sessionId,
806
829
  clear_previous_session: true.toString()
807
830
  });
@@ -829,6 +852,9 @@ var BrowserAuthProvider = class {
829
852
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
830
853
  const authUrl = `${baseUrl}?${params.toString()}`;
831
854
  debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
855
+ if (!authUrl.startsWith("https:")) {
856
+ throw new Error("Invalid auth URL - only HTTPS URLs are allowed for authentication");
857
+ }
832
858
  window.location.href = authUrl;
833
859
  resolve();
834
860
  });
@@ -917,7 +943,7 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
917
943
  let name = "unknown";
918
944
  let version = "unknown";
919
945
  if (!userAgent || typeof userAgent !== "string") {
920
- return { name, version };
946
+ return { name, version, userAgent: "unknown" };
921
947
  }
922
948
  try {
923
949
  if (userAgent.includes("Edg/")) {
@@ -999,11 +1025,11 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
999
1025
  }
1000
1026
  } catch (error) {
1001
1027
  }
1002
- return { name, version };
1028
+ return { name, version, userAgent };
1003
1029
  }
1004
1030
  function detectBrowser() {
1005
1031
  if (typeof window === "undefined" || !window.navigator?.userAgent) {
1006
- return { name: "unknown", version: "unknown" };
1032
+ return { name: "unknown", version: "unknown", userAgent: "unknown" };
1007
1033
  }
1008
1034
  const userAgent = window.navigator.userAgent;
1009
1035
  const hasBraveAPI = !!navigator.brave;
@@ -1018,8 +1044,41 @@ function getBrowserDisplayName() {
1018
1044
  const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1019
1045
  return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
1020
1046
  }
1047
+ function isMobileDevice() {
1048
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1049
+ return false;
1050
+ }
1051
+ const userAgent = window.navigator.userAgent.toLowerCase();
1052
+ const mobilePatterns = [
1053
+ /android/,
1054
+ /iphone|ipad|ipod/,
1055
+ /blackberry/,
1056
+ /windows phone/,
1057
+ /mobile/,
1058
+ /tablet/,
1059
+ /silk/,
1060
+ /kindle/,
1061
+ /opera mini/,
1062
+ /opera mobi/
1063
+ ];
1064
+ const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
1065
+ let isSmallScreen = false;
1066
+ try {
1067
+ isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
1068
+ } catch (error) {
1069
+ isSmallScreen = false;
1070
+ }
1071
+ let isTouchDevice = false;
1072
+ try {
1073
+ isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1074
+ } catch (error) {
1075
+ isTouchDevice = false;
1076
+ }
1077
+ return isMobileUA || isSmallScreen && isTouchDevice;
1078
+ }
1021
1079
 
1022
1080
  // src/providers/embedded/index.ts
1081
+ import { ANALYTICS_HEADERS } from "@phantom/constants";
1023
1082
  var EmbeddedProvider = class extends CoreEmbeddedProvider {
1024
1083
  constructor(config) {
1025
1084
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
@@ -1030,13 +1089,25 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1030
1089
  keyName: "signing-key"
1031
1090
  });
1032
1091
  const platformName = getPlatformName();
1092
+ const { name: browserName, version } = detectBrowser();
1033
1093
  const platform = {
1034
1094
  storage: new BrowserStorage(),
1035
1095
  authProvider: new BrowserAuthProvider(urlParamsAccessor),
1036
1096
  urlParamsAccessor,
1037
1097
  stamper,
1038
- name: platformName
1098
+ name: platformName,
1039
1099
  // Use detected browser name and version for identification
1100
+ analyticsHeaders: {
1101
+ [ANALYTICS_HEADERS.SDK_TYPE]: "browser",
1102
+ [ANALYTICS_HEADERS.PLATFORM]: browserName,
1103
+ // firefox, chrome, safari, etc.
1104
+ [ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
1105
+ // Full user agent for more detailed info
1106
+ [ANALYTICS_HEADERS.APP_ID]: config.appId,
1107
+ [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1108
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.4"
1109
+ // Replaced at build time
1110
+ }
1040
1111
  };
1041
1112
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
1042
1113
  const logger = new BrowserLogger();
@@ -1046,6 +1117,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1046
1117
  };
1047
1118
 
1048
1119
  // src/ProviderManager.ts
1120
+ import { DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
1049
1121
  var ProviderManager = class {
1050
1122
  // Track which providers have forwarding set up
1051
1123
  constructor(config) {
@@ -1064,6 +1136,15 @@ var ProviderManager = class {
1064
1136
  currentProviderKey: this.currentProviderKey
1065
1137
  });
1066
1138
  }
1139
+ getValidatedCurrentUrl() {
1140
+ if (typeof window === "undefined")
1141
+ return "";
1142
+ const currentUrl = window.location.href;
1143
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
1144
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
1145
+ }
1146
+ return currentUrl;
1147
+ }
1067
1148
  /**
1068
1149
  * Switch to a different provider type
1069
1150
  */
@@ -1095,7 +1176,8 @@ var ProviderManager = class {
1095
1176
  getCurrentProviderInfo() {
1096
1177
  if (!this.currentProviderKey)
1097
1178
  return null;
1098
- const [type, embeddedWalletType] = this.currentProviderKey.split("-");
1179
+ const parts = this.currentProviderKey.split("-");
1180
+ const [type, embeddedWalletType] = parts;
1099
1181
  return {
1100
1182
  type,
1101
1183
  embeddedWalletType
@@ -1241,7 +1323,7 @@ var ProviderManager = class {
1241
1323
  */
1242
1324
  setDefaultProvider() {
1243
1325
  const defaultType = this.config.providerType || "embedded";
1244
- const defaultEmbeddedType = this.config.embeddedWalletType || "app-wallet";
1326
+ const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
1245
1327
  this.createProvider(defaultType, defaultEmbeddedType);
1246
1328
  this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1247
1329
  }
@@ -1255,22 +1337,28 @@ var ProviderManager = class {
1255
1337
  let provider;
1256
1338
  if (type === "injected") {
1257
1339
  provider = new InjectedProvider({
1258
- solanaProvider: this.config.solanaProvider || "web3js",
1259
1340
  addressTypes: this.config.addressTypes
1260
1341
  });
1261
- } else {
1262
- if (!this.config.apiBaseUrl || !this.config.appId) {
1263
- throw new Error("apiBaseUrl and appId are required for embedded provider");
1342
+ } else if (type === "embedded") {
1343
+ if (!this.config.appId) {
1344
+ throw new Error("appId is required for embedded provider");
1264
1345
  }
1346
+ const apiBaseUrl = this.config.apiBaseUrl || DEFAULT_WALLET_API_URL;
1347
+ const authUrl = this.config.authOptions?.authUrl || DEFAULT_AUTH_URL2;
1265
1348
  provider = new EmbeddedProvider({
1266
- apiBaseUrl: this.config.apiBaseUrl,
1349
+ apiBaseUrl,
1267
1350
  organizationId: this.config.appId,
1268
1351
  appId: this.config.appId,
1269
- authOptions: this.config.authOptions,
1270
- embeddedWalletType: embeddedWalletType || "app-wallet",
1271
- addressTypes: this.config.addressTypes,
1272
- solanaProvider: this.config.solanaProvider || "web3js"
1352
+ authOptions: {
1353
+ ...this.config.authOptions || {},
1354
+ authUrl,
1355
+ redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
1356
+ },
1357
+ embeddedWalletType: embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
1358
+ addressTypes: this.config.addressTypes
1273
1359
  });
1360
+ } else {
1361
+ throw new Error(`Unsupported provider type: ${type}`);
1274
1362
  }
1275
1363
  this.providers.set(key, provider);
1276
1364
  }
@@ -1280,8 +1368,10 @@ var ProviderManager = class {
1280
1368
  getProviderKey(type, embeddedWalletType) {
1281
1369
  if (type === "injected") {
1282
1370
  return "injected";
1371
+ } else if (type === "embedded") {
1372
+ return `embedded-${embeddedWalletType || "app-wallet"}`;
1283
1373
  }
1284
- return `embedded-${embeddedWalletType || "app-wallet"}`;
1374
+ throw new Error(`Unsupported provider type: ${type}`);
1285
1375
  }
1286
1376
  /**
1287
1377
  * Save provider preference to localStorage
@@ -1342,6 +1432,7 @@ async function waitForPhantomExtension(timeoutMs = 3e3) {
1342
1432
  }
1343
1433
 
1344
1434
  // src/BrowserSDK.ts
1435
+ import { DEFAULT_EMBEDDED_WALLET_TYPE as DEFAULT_EMBEDDED_WALLET_TYPE2 } from "@phantom/constants";
1345
1436
  var BrowserSDK = class {
1346
1437
  constructor(config) {
1347
1438
  debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
@@ -1353,7 +1444,7 @@ var BrowserSDK = class {
1353
1444
  debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
1354
1445
  throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
1355
1446
  }
1356
- const embeddedWalletType = config.embeddedWalletType || "app-wallet";
1447
+ const embeddedWalletType = config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE2;
1357
1448
  if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
1358
1449
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
1359
1450
  embeddedWalletType: config.embeddedWalletType
@@ -1641,21 +1732,31 @@ var BrowserSDK = class {
1641
1732
  // src/types.ts
1642
1733
  import { AddressType as AddressType4 } from "@phantom/client";
1643
1734
 
1735
+ // src/utils/deeplink.ts
1736
+ function getDeeplinkToPhantom(ref) {
1737
+ if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
1738
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
1739
+ }
1740
+ const currentUrl = encodeURIComponent(window.location.href);
1741
+ const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
1742
+ return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1743
+ }
1744
+
1644
1745
  // src/index.ts
1645
1746
  import { NetworkId } from "@phantom/constants";
1646
1747
  import { AddressType as AddressType5 } from "@phantom/client";
1647
1748
  export {
1648
1749
  AddressType5 as AddressType,
1649
1750
  BrowserSDK,
1650
- DEFAULT_AUTH_URL,
1651
- DEFAULT_WALLET_API_URL,
1652
1751
  DebugCategory,
1653
1752
  DebugLevel,
1654
1753
  NetworkId,
1655
1754
  debug,
1656
1755
  detectBrowser,
1657
1756
  getBrowserDisplayName,
1757
+ getDeeplinkToPhantom,
1658
1758
  getPlatformName,
1759
+ isMobileDevice,
1659
1760
  parseBrowserFromUserAgent,
1660
1761
  waitForPhantomExtension
1661
1762
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/browser-sdk",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "Browser SDK for Phantom Wallet",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -28,14 +28,15 @@
28
28
  "prettier": "prettier --write \"src/**/*.{ts,tsx}\""
29
29
  },
30
30
  "dependencies": {
31
- "@phantom/base64url": "^1.0.0-beta.2",
32
- "@phantom/browser-injected-sdk": "^1.0.0-beta.2",
33
- "@phantom/chains": "^1.0.0-beta.2",
34
- "@phantom/client": "^1.0.0-beta.2",
35
- "@phantom/constants": "^1.0.0-beta.2",
36
- "@phantom/embedded-provider-core": "^1.0.0-beta.2",
31
+ "@phantom/base64url": "^1.0.0-beta.4",
32
+ "@phantom/browser-injected-sdk": "^1.0.0-beta.3",
33
+ "@phantom/chains": "^1.0.0-beta.4",
34
+ "@phantom/client": "^1.0.0-beta.4",
35
+ "@phantom/constants": "^1.0.0-beta.4",
36
+ "@phantom/embedded-provider-core": "^1.0.0-beta.4",
37
37
  "@phantom/indexed-db-stamper": "^1.0.0-beta.1",
38
- "@phantom/parsers": "^1.0.0-beta.2",
38
+ "@phantom/parsers": "^1.0.0-beta.4",
39
+ "@phantom/sdk-types": "^1.0.0-beta.4",
39
40
  "axios": "^1.10.0",
40
41
  "bs58": "^6.0.0",
41
42
  "buffer": "^6.0.3",