@phantom/browser-sdk 0.2.2 → 0.3.1

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
@@ -3,26 +3,121 @@ import { AddressType } from "@phantom/client";
3
3
  import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
4
4
  import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
5
5
  import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
6
+
7
+ // src/debug.ts
8
+ var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
9
+ DebugLevel2[DebugLevel2["ERROR"] = 0] = "ERROR";
10
+ DebugLevel2[DebugLevel2["WARN"] = 1] = "WARN";
11
+ DebugLevel2[DebugLevel2["INFO"] = 2] = "INFO";
12
+ DebugLevel2[DebugLevel2["DEBUG"] = 3] = "DEBUG";
13
+ return DebugLevel2;
14
+ })(DebugLevel || {});
15
+ var Debug = class {
16
+ constructor() {
17
+ this.level = 0 /* ERROR */;
18
+ this.enabled = false;
19
+ }
20
+ static getInstance() {
21
+ if (!Debug.instance) {
22
+ Debug.instance = new Debug();
23
+ }
24
+ return Debug.instance;
25
+ }
26
+ setCallback(callback) {
27
+ this.callback = callback;
28
+ }
29
+ setLevel(level) {
30
+ this.level = level;
31
+ }
32
+ enable() {
33
+ this.enabled = true;
34
+ }
35
+ disable() {
36
+ this.enabled = false;
37
+ }
38
+ writeLog(level, category, message, data) {
39
+ if (!this.enabled || level > this.level) {
40
+ return;
41
+ }
42
+ const debugMessage = {
43
+ timestamp: Date.now(),
44
+ level,
45
+ category,
46
+ message,
47
+ data
48
+ };
49
+ if (this.callback) {
50
+ this.callback(debugMessage);
51
+ }
52
+ }
53
+ error(category, message, data) {
54
+ this.writeLog(0 /* ERROR */, category, message, data);
55
+ }
56
+ warn(category, message, data) {
57
+ this.writeLog(1 /* WARN */, category, message, data);
58
+ }
59
+ info(category, message, data) {
60
+ this.writeLog(2 /* INFO */, category, message, data);
61
+ }
62
+ debug(category, message, data) {
63
+ this.writeLog(3 /* DEBUG */, category, message, data);
64
+ }
65
+ log(category, message, data) {
66
+ this.writeLog(3 /* DEBUG */, category, message, data);
67
+ }
68
+ };
69
+ var debug = Debug.getInstance();
70
+ var DebugCategory = {
71
+ BROWSER_SDK: "BrowserSDK",
72
+ PROVIDER_MANAGER: "ProviderManager",
73
+ EMBEDDED_PROVIDER: "EmbeddedProvider",
74
+ INJECTED_PROVIDER: "InjectedProvider",
75
+ PHANTOM_CONNECT_AUTH: "PhantomConnectAuth",
76
+ JWT_AUTH: "JWTAuth",
77
+ STORAGE: "Storage",
78
+ SESSION: "Session"
79
+ };
80
+
81
+ // src/providers/injected/index.ts
82
+ import { base64urlEncode } from "@phantom/base64url";
83
+ import { getExplorerUrl } from "@phantom/constants";
84
+ import bs58 from "bs58";
6
85
  var InjectedProvider = class {
7
86
  constructor(config) {
8
87
  this.connected = false;
9
88
  this.addresses = [];
89
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
10
90
  this.addressTypes = config.addressTypes || [AddressType.solana, AddressType.ethereum];
91
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
11
92
  const plugins = [createExtensionPlugin()];
12
93
  if (this.addressTypes.includes(AddressType.solana)) {
13
94
  plugins.push(createSolanaPlugin());
95
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana plugin added");
14
96
  }
15
97
  if (this.addressTypes.includes(AddressType.ethereum)) {
16
98
  plugins.push(createEthereumPlugin());
99
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum plugin added");
17
100
  }
101
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Creating Phantom instance with plugins", {
102
+ pluginCount: plugins.length
103
+ });
18
104
  this.phantom = createPhantom({ plugins });
105
+ debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
19
106
  }
20
- async connect() {
107
+ async connect(authOptions) {
108
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider connect", {
109
+ addressTypes: this.addressTypes,
110
+ authOptionsIgnored: !!authOptions
111
+ // Note: authOptions are ignored for injected provider
112
+ });
21
113
  if (!this.phantom.extension.isInstalled()) {
114
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found");
22
115
  throw new Error("Phantom wallet not found");
23
116
  }
117
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
24
118
  const connectedAddresses = [];
25
119
  if (this.addressTypes.includes(AddressType.solana)) {
120
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
26
121
  try {
27
122
  const publicKey = await this.phantom.solana.connect();
28
123
  if (publicKey) {
@@ -30,9 +125,10 @@ var InjectedProvider = class {
30
125
  addressType: AddressType.solana,
31
126
  address: publicKey
32
127
  });
128
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
33
129
  }
34
130
  } catch (err) {
35
- console.error("Failed to connect Solana:", err);
131
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
36
132
  }
37
133
  }
38
134
  if (this.addressTypes.includes(AddressType.ethereum)) {
@@ -47,7 +143,7 @@ var InjectedProvider = class {
47
143
  );
48
144
  }
49
145
  } catch (err) {
50
- console.error("Failed to connect Ethereum:", err);
146
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
51
147
  }
52
148
  }
53
149
  if (connectedAddresses.length === 0) {
@@ -56,7 +152,8 @@ var InjectedProvider = class {
56
152
  this.addresses = connectedAddresses;
57
153
  this.connected = true;
58
154
  return {
59
- addresses: this.addresses
155
+ addresses: this.addresses,
156
+ status: "completed"
60
157
  // walletId is not applicable for injected providers
61
158
  };
62
159
  }
@@ -83,18 +180,24 @@ var InjectedProvider = class {
83
180
  throw new Error("Wallet not connected");
84
181
  }
85
182
  const networkPrefix = params.networkId.split(":")[0].toLowerCase();
183
+ let signatureResult;
86
184
  if (networkPrefix === "solana") {
87
185
  const { signature } = await this.phantom.solana.signMessage(new TextEncoder().encode(params.message));
88
- return Array.from(signature).map((b) => b.toString(16).padStart(2, "0")).join("");
186
+ signatureResult = bs58.encode(signature);
89
187
  } else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
90
188
  const address = this.addresses.find((addr) => addr.addressType === AddressType.ethereum)?.address;
91
189
  if (!address) {
92
190
  throw new Error("No address available");
93
191
  }
94
192
  const signature = await this.phantom.ethereum.signPersonalMessage(params.message, address);
95
- return signature;
193
+ signatureResult = signature;
194
+ } else {
195
+ throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
96
196
  }
97
- throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
197
+ return {
198
+ signature: signatureResult,
199
+ rawSignature: base64urlEncode(signatureResult)
200
+ };
98
201
  }
99
202
  async signAndSendTransaction(params) {
100
203
  if (!this.connected) {
@@ -105,7 +208,9 @@ var InjectedProvider = class {
105
208
  const transaction = params.transaction;
106
209
  const result = await this.phantom.solana.signAndSendTransaction(transaction);
107
210
  return {
108
- rawTransaction: result.signature
211
+ hash: result.signature,
212
+ rawTransaction: base64urlEncode(result.signature),
213
+ blockExplorer: getExplorerUrl(params.networkId, "transaction", result.signature)
109
214
  };
110
215
  } else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
111
216
  const toHex = (value) => {
@@ -128,7 +233,9 @@ var InjectedProvider = class {
128
233
  };
129
234
  const txHash = await this.phantom.ethereum.sendTransaction(txRequest);
130
235
  return {
131
- rawTransaction: txHash
236
+ hash: txHash,
237
+ rawTransaction: base64urlEncode(txHash),
238
+ blockExplorer: getExplorerUrl(params.networkId, "transaction", txHash)
132
239
  };
133
240
  }
134
241
  throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
@@ -142,11 +249,11 @@ var InjectedProvider = class {
142
249
  };
143
250
 
144
251
  // src/providers/embedded/index.ts
145
- import { PhantomClient, generateKeyPair } from "@phantom/client";
146
- import { ApiKeyStamper } from "@phantom/api-key-stamper";
252
+ import { EmbeddedProvider as CoreEmbeddedProvider } from "@phantom/embedded-provider-core";
253
+ import { IndexedDbStamper } from "@phantom/indexed-db-stamper";
147
254
 
148
- // src/providers/embedded/storage.ts
149
- var IndexedDBStorage = class {
255
+ // src/providers/embedded/adapters/storage.ts
256
+ var BrowserStorage = class {
150
257
  constructor() {
151
258
  this.dbName = "phantom-browser-sdk";
152
259
  this.storeName = "sessions";
@@ -166,149 +273,339 @@ var IndexedDBStorage = class {
166
273
  });
167
274
  }
168
275
  async getSession() {
276
+ debug.log(DebugCategory.STORAGE, "Getting session from IndexedDB");
169
277
  const db = await this.getDB();
170
278
  return new Promise((resolve, reject) => {
171
279
  const transaction = db.transaction([this.storeName], "readonly");
172
280
  const store = transaction.objectStore(this.storeName);
173
281
  const request = store.get("currentSession");
174
- request.onsuccess = () => resolve(request.result || null);
175
- request.onerror = () => reject(request.error);
282
+ request.onsuccess = () => {
283
+ const session = request.result || null;
284
+ debug.log(DebugCategory.STORAGE, "Retrieved session from IndexedDB", {
285
+ hasSession: !!session,
286
+ sessionId: session?.sessionId
287
+ });
288
+ resolve(session);
289
+ };
290
+ request.onerror = () => {
291
+ debug.error(DebugCategory.STORAGE, "Failed to get session from IndexedDB", { error: request.error });
292
+ reject(request.error);
293
+ };
176
294
  });
177
295
  }
178
296
  async saveSession(session) {
297
+ debug.log(DebugCategory.STORAGE, "Saving session to IndexedDB", {
298
+ sessionId: session.sessionId,
299
+ walletId: session.walletId,
300
+ status: session.status
301
+ });
179
302
  const db = await this.getDB();
180
303
  return new Promise((resolve, reject) => {
181
304
  const transaction = db.transaction([this.storeName], "readwrite");
182
305
  const store = transaction.objectStore(this.storeName);
183
306
  const request = store.put(session, "currentSession");
184
- request.onsuccess = () => resolve();
185
- request.onerror = () => reject(request.error);
307
+ request.onsuccess = () => {
308
+ debug.log(DebugCategory.STORAGE, "Successfully saved session to IndexedDB");
309
+ resolve();
310
+ };
311
+ request.onerror = () => {
312
+ debug.error(DebugCategory.STORAGE, "Failed to save session to IndexedDB", { error: request.error });
313
+ reject(request.error);
314
+ };
186
315
  });
187
316
  }
188
317
  async clearSession() {
318
+ debug.log(DebugCategory.STORAGE, "Clearing session from IndexedDB");
189
319
  const db = await this.getDB();
190
320
  return new Promise((resolve, reject) => {
191
321
  const transaction = db.transaction([this.storeName], "readwrite");
192
322
  const store = transaction.objectStore(this.storeName);
193
323
  const request = store.delete("currentSession");
194
- request.onsuccess = () => resolve();
195
- request.onerror = () => reject(request.error);
324
+ request.onsuccess = () => {
325
+ debug.log(DebugCategory.STORAGE, "Successfully cleared session from IndexedDB");
326
+ resolve();
327
+ };
328
+ request.onerror = () => {
329
+ debug.error(DebugCategory.STORAGE, "Failed to clear session from IndexedDB", { error: request.error });
330
+ reject(request.error);
331
+ };
196
332
  });
197
333
  }
198
334
  };
199
335
 
200
- // src/providers/embedded/auth.ts
201
- var IframeAuth = class {
202
- async authenticate(_options) {
203
- await new Promise((resolve) => setTimeout(resolve, 100));
204
- return {
205
- walletId: `wallet-${Date.now()}`
206
- };
336
+ // src/providers/embedded/adapters/url-params.ts
337
+ var BrowserURLParamsAccessor = class {
338
+ getParam(key) {
339
+ const urlParams = new URLSearchParams(window.location.search);
340
+ return urlParams.get(key);
207
341
  }
208
342
  };
343
+ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
209
344
 
210
- // src/providers/embedded/index.ts
211
- import { parseMessage, parseTransaction } from "@phantom/parsers";
212
- var EmbeddedProvider = class {
213
- constructor(config) {
214
- this.client = null;
215
- this.walletId = null;
216
- this.addresses = [];
217
- this.config = config;
218
- this.storage = new IndexedDBStorage();
219
- config.solanaProvider;
220
- }
221
- async connect() {
222
- let session = await this.storage.getSession();
223
- if (!session) {
224
- const keypair = generateKeyPair();
225
- const stamper2 = new ApiKeyStamper({
226
- apiSecretKey: keypair.secretKey
345
+ // src/constants.ts
346
+ var DEFAULT_AUTH_URL = "https://connect.phantom.app";
347
+ var DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
348
+
349
+ // src/providers/embedded/adapters/auth.ts
350
+ var BrowserAuthProvider = class {
351
+ constructor(urlParamsAccessor) {
352
+ this.urlParamsAccessor = urlParamsAccessor;
353
+ }
354
+ authenticate(options) {
355
+ return new Promise((resolve) => {
356
+ if ("jwtToken" in options) {
357
+ throw new Error("JWT authentication should be handled by the core JWTAuth class");
358
+ }
359
+ const phantomOptions = options;
360
+ debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Starting Phantom Connect authentication", {
361
+ organizationId: phantomOptions.organizationId,
362
+ parentOrganizationId: phantomOptions.parentOrganizationId,
363
+ provider: phantomOptions.provider,
364
+ authUrl: phantomOptions.authUrl,
365
+ hasCustomData: !!phantomOptions.customAuthData
227
366
  });
228
- const tempClient = new PhantomClient(
229
- {
230
- apiBaseUrl: this.config.apiBaseUrl
231
- },
232
- stamper2
233
- );
234
- const uid = Date.now();
235
- const organizationName = `${this.config.organizationId}-${uid}`;
236
- const { organizationId } = await tempClient.createOrganization(organizationName, keypair);
237
- let walletId;
238
- if (this.config.embeddedWalletType === "user-wallet") {
239
- const auth = new IframeAuth();
240
- const authResult = await auth.authenticate({
241
- iframeUrl: this.config.authUrl || "https://auth-flow.phantom.app",
242
- organizationId,
243
- parentOrganizationId: this.config.organizationId,
244
- embeddedWalletType: this.config.embeddedWalletType
367
+ const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
368
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
369
+ const params = new URLSearchParams({
370
+ organization_id: phantomOptions.organizationId,
371
+ parent_organization_id: phantomOptions.parentOrganizationId,
372
+ redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? window.location.href : ""),
373
+ session_id: phantomOptions.sessionId,
374
+ clear_previous_session: true.toString()
375
+ });
376
+ if (phantomOptions.provider) {
377
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
378
+ provider: phantomOptions.provider
245
379
  });
246
- walletId = authResult.walletId;
380
+ params.append("provider", phantomOptions.provider);
247
381
  } else {
248
- const wallet = await tempClient.createWallet(`Wallet ${Date.now()}`);
249
- walletId = wallet.walletId;
382
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
383
+ params.append("provider", "google");
384
+ }
385
+ if (phantomOptions.customAuthData) {
386
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
387
+ params.append("authData", JSON.stringify(phantomOptions.customAuthData));
388
+ }
389
+ const authContext = {
390
+ organizationId: phantomOptions.organizationId,
391
+ parentOrganizationId: phantomOptions.parentOrganizationId,
392
+ provider: phantomOptions.provider,
393
+ sessionId: phantomOptions.sessionId
394
+ };
395
+ sessionStorage.setItem("phantom-auth-context", JSON.stringify(authContext));
396
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
397
+ const authUrl = `${baseUrl}?${params.toString()}`;
398
+ debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
399
+ window.location.href = authUrl;
400
+ resolve();
401
+ });
402
+ }
403
+ resumeAuthFromRedirect() {
404
+ try {
405
+ const walletId = this.urlParamsAccessor.getParam("wallet_id");
406
+ const sessionId = this.urlParamsAccessor.getParam("session_id");
407
+ const error = this.urlParamsAccessor.getParam("error");
408
+ const errorDescription = this.urlParamsAccessor.getParam("error_description");
409
+ if (error) {
410
+ const errorMsg = errorDescription || error;
411
+ switch (error) {
412
+ case "access_denied":
413
+ throw new Error(`Authentication cancelled: ${errorMsg}`);
414
+ case "invalid_request":
415
+ throw new Error(`Invalid authentication request: ${errorMsg}`);
416
+ case "server_error":
417
+ throw new Error(`Authentication server error: ${errorMsg}`);
418
+ case "temporarily_unavailable":
419
+ throw new Error(`Authentication service temporarily unavailable: ${errorMsg}`);
420
+ default:
421
+ throw new Error(`Authentication failed: ${errorMsg}`);
422
+ }
250
423
  }
251
- session = {
424
+ if (!walletId || !sessionId) {
425
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing auth parameters in URL", {
426
+ hasWalletId: !!walletId,
427
+ hasSessionId: !!sessionId
428
+ });
429
+ return null;
430
+ }
431
+ const contextStr = sessionStorage.getItem("phantom-auth-context");
432
+ let context = {};
433
+ if (contextStr) {
434
+ try {
435
+ context = JSON.parse(contextStr);
436
+ } catch (parseError) {
437
+ debug.warn(DebugCategory.PHANTOM_CONNECT_AUTH, "Failed to parse stored auth context", { error: parseError });
438
+ }
439
+ }
440
+ if (context.sessionId && sessionId !== context.sessionId) {
441
+ debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Session ID mismatch", {
442
+ urlSessionId: sessionId,
443
+ storedSessionId: context.sessionId
444
+ });
445
+ throw new Error("Session ID mismatch - possible session corruption or replay attack");
446
+ }
447
+ sessionStorage.removeItem("phantom-auth-context");
448
+ debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Successfully resumed auth from redirect", {
252
449
  walletId,
253
- organizationId: this.config.organizationId,
254
- keypair
450
+ sessionId
451
+ });
452
+ return {
453
+ walletId,
454
+ userInfo: context
255
455
  };
256
- await this.storage.saveSession(session);
456
+ } catch (error) {
457
+ sessionStorage.removeItem("phantom-auth-context");
458
+ throw error;
257
459
  }
258
- const stamper = new ApiKeyStamper({
259
- apiSecretKey: session.keypair.secretKey
260
- });
261
- this.client = new PhantomClient(
262
- {
263
- apiBaseUrl: this.config.apiBaseUrl,
264
- organizationId: session.organizationId
265
- },
266
- stamper
267
- );
268
- this.walletId = session.walletId;
269
- const addresses = await this.client.getWalletAddresses(session.walletId);
270
- this.addresses = addresses.filter((addr) => this.config.addressTypes.some((type) => type === addr.addressType)).map((addr) => ({
271
- addressType: addr.addressType,
272
- address: addr.address
273
- }));
274
- return {
275
- walletId: this.walletId,
276
- addresses: this.addresses
277
- };
278
460
  }
279
- async disconnect() {
280
- await this.storage.clearSession();
281
- this.client = null;
282
- this.walletId = null;
283
- this.addresses = [];
461
+ };
462
+
463
+ // src/providers/embedded/adapters/logger.ts
464
+ var BrowserLogger = class {
465
+ info(category, message, data) {
466
+ debug.info(category, message, data);
284
467
  }
285
- async signMessage(params) {
286
- if (!this.client || !this.walletId) {
287
- throw new Error("Not connected");
288
- }
289
- const parsedMessage = parseMessage(params.message);
290
- return await this.client.signMessage({
291
- walletId: this.walletId,
292
- message: parsedMessage.base64url,
293
- networkId: params.networkId
294
- });
468
+ warn(category, message, data) {
469
+ debug.warn(category, message, data);
295
470
  }
296
- async signAndSendTransaction(params) {
297
- if (!this.client || !this.walletId) {
298
- throw new Error("Not connected");
471
+ error(category, message, data) {
472
+ debug.error(category, message, data);
473
+ }
474
+ log(category, message, data) {
475
+ debug.log(category, message, data);
476
+ }
477
+ };
478
+
479
+ // src/utils/browser-detection.ts
480
+ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
481
+ let name = "unknown";
482
+ let version = "unknown";
483
+ if (!userAgent || typeof userAgent !== "string") {
484
+ return { name, version };
485
+ }
486
+ try {
487
+ if (userAgent.includes("Edg/")) {
488
+ name = "edge";
489
+ const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
490
+ if (match)
491
+ version = match[1].split(".")[0];
492
+ } else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
493
+ name = "opera";
494
+ const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
495
+ if (match)
496
+ version = match[1].split(".")[0];
497
+ } else if (userAgent.includes("SamsungBrowser/")) {
498
+ name = "samsung";
499
+ const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
500
+ if (match)
501
+ version = match[1].split(".")[0];
502
+ } else if (userAgent.includes("DuckDuckGo/")) {
503
+ name = "duckduckgo";
504
+ const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
505
+ if (match)
506
+ version = match[1].split(".")[0];
507
+ } else if (userAgent.includes("Chrome/") && hasBraveAPI) {
508
+ name = "brave";
509
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
510
+ if (match)
511
+ version = match[1].split(".")[0];
512
+ } else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
513
+ if (userAgent.includes("Chrome/")) {
514
+ name = "chrome-mobile";
515
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
516
+ if (match)
517
+ version = match[1].split(".")[0];
518
+ } else if (userAgent.includes("Firefox/")) {
519
+ name = "firefox-mobile";
520
+ const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
521
+ if (match)
522
+ version = match[1].split(".")[0];
523
+ } else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
524
+ name = "safari-mobile";
525
+ const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
526
+ if (match)
527
+ version = match[1].split(".")[0];
528
+ } else {
529
+ name = "mobile";
530
+ }
531
+ } else if (userAgent.includes("Chrome/")) {
532
+ name = "chrome";
533
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
534
+ if (match)
535
+ version = match[1].split(".")[0];
536
+ } else if (userAgent.includes("Firefox/")) {
537
+ name = "firefox";
538
+ const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
539
+ if (match)
540
+ version = match[1].split(".")[0];
541
+ } else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
542
+ name = "safari";
543
+ const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
544
+ if (match)
545
+ version = match[1].split(".")[0];
299
546
  }
300
- const parsedTransaction = await parseTransaction(params.transaction, params.networkId);
301
- return await this.client.signAndSendTransaction({
302
- walletId: this.walletId,
303
- transaction: parsedTransaction.base64url,
304
- networkId: params.networkId
305
- });
547
+ if (name === "unknown") {
548
+ const patterns = [
549
+ { regex: /Chrome\/([0-9]+)/, name: "chrome" },
550
+ { regex: /Firefox\/([0-9]+)/, name: "firefox" },
551
+ { regex: /Safari\/([0-9]+)/, name: "safari" },
552
+ { regex: /Edge\/([0-9]+)/, name: "edge" },
553
+ { regex: /Opera\/([0-9]+)/, name: "opera" }
554
+ ];
555
+ for (const pattern of patterns) {
556
+ const match = userAgent.match(pattern.regex);
557
+ if (match) {
558
+ name = pattern.name;
559
+ version = match[1];
560
+ break;
561
+ }
562
+ }
563
+ }
564
+ } catch (error) {
306
565
  }
307
- getAddresses() {
308
- return this.addresses;
566
+ return { name, version };
567
+ }
568
+ function detectBrowser() {
569
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
570
+ return { name: "unknown", version: "unknown" };
309
571
  }
310
- isConnected() {
311
- return this.client !== null && this.walletId !== null;
572
+ const userAgent = window.navigator.userAgent;
573
+ const hasBraveAPI = !!navigator.brave;
574
+ return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
575
+ }
576
+ function getPlatformName() {
577
+ const { name, version } = detectBrowser();
578
+ return version !== "unknown" ? `${name}-v${version}` : name;
579
+ }
580
+ function getBrowserDisplayName() {
581
+ const { name, version } = detectBrowser();
582
+ const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
583
+ return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
584
+ }
585
+
586
+ // src/providers/embedded/index.ts
587
+ var EmbeddedProvider = class extends CoreEmbeddedProvider {
588
+ constructor(config) {
589
+ debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
590
+ const urlParamsAccessor = new BrowserURLParamsAccessor();
591
+ const stamper = new IndexedDbStamper({
592
+ dbName: `phantom-embedded-sdk-${config.organizationId}`,
593
+ storeName: "crypto-keys",
594
+ keyName: "signing-key"
595
+ });
596
+ const platformName = getPlatformName();
597
+ const platform = {
598
+ storage: new BrowserStorage(),
599
+ authProvider: new BrowserAuthProvider(urlParamsAccessor),
600
+ urlParamsAccessor,
601
+ stamper,
602
+ name: platformName
603
+ // Use detected browser name and version for identification
604
+ };
605
+ debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
606
+ const logger = new BrowserLogger();
607
+ super(config, platform, logger);
608
+ debug.info(DebugCategory.EMBEDDED_PROVIDER, "Browser EmbeddedProvider initialized");
312
609
  }
313
610
  };
314
611
 
@@ -319,8 +616,13 @@ var ProviderManager = class {
319
616
  this.currentProvider = null;
320
617
  this.currentProviderKey = null;
321
618
  this.walletId = null;
619
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Initializing ProviderManager", { config });
322
620
  this.config = config;
621
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Setting default provider");
323
622
  this.setDefaultProvider();
623
+ debug.info(DebugCategory.PROVIDER_MANAGER, "ProviderManager initialized", {
624
+ currentProviderKey: this.currentProviderKey
625
+ });
324
626
  }
325
627
  /**
326
628
  * Switch to a different provider type
@@ -361,13 +663,27 @@ var ProviderManager = class {
361
663
  /**
362
664
  * Connect using the current provider
363
665
  */
364
- async connect() {
666
+ async connect(authOptions) {
667
+ debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
668
+ currentProviderKey: this.currentProviderKey,
669
+ authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
670
+ });
365
671
  if (!this.currentProvider) {
672
+ debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
366
673
  throw new Error("No provider selected");
367
674
  }
368
- const result = await this.currentProvider.connect();
675
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
676
+ const result = await this.currentProvider.connect(authOptions);
369
677
  this.walletId = result.walletId || null;
678
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
679
+ walletId: this.walletId,
680
+ addressCount: result.addresses?.length || 0
681
+ });
370
682
  this.saveProviderPreference();
683
+ debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
684
+ walletId: this.walletId,
685
+ addresses: result.addresses
686
+ });
371
687
  return result;
372
688
  }
373
689
  /**
@@ -447,7 +763,7 @@ var ProviderManager = class {
447
763
  provider = new EmbeddedProvider({
448
764
  apiBaseUrl: this.config.apiBaseUrl,
449
765
  organizationId: this.config.organizationId,
450
- authUrl: this.config.authUrl,
766
+ authOptions: this.config.authOptions,
451
767
  embeddedWalletType: embeddedWalletType || "app-wallet",
452
768
  addressTypes: this.config.addressTypes || [],
453
769
  solanaProvider: this.config.solanaProvider || "web3js"
@@ -501,37 +817,78 @@ var ProviderManager = class {
501
817
  import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
502
818
  var BrowserSDK = class {
503
819
  constructor(config) {
820
+ if (config.debug?.enabled) {
821
+ debug.enable();
822
+ if (config.debug.level !== void 0) {
823
+ debug.setLevel(config.debug.level);
824
+ }
825
+ if (config.debug.callback) {
826
+ debug.setCallback(config.debug.callback);
827
+ }
828
+ }
829
+ debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
830
+ providerType: config.providerType,
831
+ embeddedWalletType: config.embeddedWalletType,
832
+ addressTypes: config.addressTypes,
833
+ debugEnabled: config.debug?.enabled
834
+ });
504
835
  if (!["injected", "embedded"].includes(config.providerType)) {
836
+ debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
505
837
  throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
506
838
  }
507
839
  const embeddedWalletType = config.embeddedWalletType || "app-wallet";
508
840
  if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
841
+ debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
842
+ embeddedWalletType: config.embeddedWalletType
843
+ });
509
844
  throw new Error(
510
845
  `Invalid embeddedWalletType: ${config.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
511
846
  );
512
847
  }
513
848
  config.embeddedWalletType = embeddedWalletType;
514
849
  this.config = config;
850
+ debug.log(DebugCategory.BROWSER_SDK, "Creating ProviderManager", { config });
515
851
  this.providerManager = new ProviderManager(config);
852
+ debug.info(DebugCategory.BROWSER_SDK, "BrowserSDK initialized successfully");
516
853
  }
517
854
  /**
518
855
  * Connect to the wallet with optional provider switching
519
856
  */
520
857
  async connect(options) {
858
+ debug.info(DebugCategory.BROWSER_SDK, "Starting connect process", { options });
521
859
  if (options?.providerType) {
860
+ debug.log(DebugCategory.BROWSER_SDK, "Provider switch requested", {
861
+ providerType: options.providerType,
862
+ embeddedWalletType: options.embeddedWalletType
863
+ });
522
864
  if (!["injected", "embedded"].includes(options.providerType)) {
865
+ debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType in connect options", {
866
+ providerType: options.providerType
867
+ });
523
868
  throw new Error(`Invalid providerType: ${options.providerType}. Must be "injected" or "embedded".`);
524
869
  }
525
870
  if (options.embeddedWalletType && !["app-wallet", "user-wallet"].includes(options.embeddedWalletType)) {
871
+ debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType in connect options", {
872
+ embeddedWalletType: options.embeddedWalletType
873
+ });
526
874
  throw new Error(
527
875
  `Invalid embeddedWalletType: ${options.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
528
876
  );
529
877
  }
878
+ debug.log(DebugCategory.BROWSER_SDK, "Switching provider", {
879
+ providerType: options.providerType,
880
+ embeddedWalletType: options.embeddedWalletType
881
+ });
530
882
  await this.providerManager.switchProvider(options.providerType, {
531
883
  embeddedWalletType: options.embeddedWalletType
532
884
  });
533
885
  }
534
- return this.providerManager.connect();
886
+ debug.log(DebugCategory.BROWSER_SDK, "Delegating to ProviderManager.connect", {
887
+ authOptions: options?.authOptions
888
+ });
889
+ const result = await this.providerManager.connect(options?.authOptions);
890
+ debug.info(DebugCategory.BROWSER_SDK, "Connect completed successfully", result);
891
+ return result;
535
892
  }
536
893
  /**
537
894
  * Switch to a different provider type
@@ -582,7 +939,17 @@ var BrowserSDK = class {
582
939
  * @returns Signature string
583
940
  */
584
941
  async signMessage(params) {
585
- return this.providerManager.signMessage(params);
942
+ debug.info(DebugCategory.BROWSER_SDK, "Signing message", {
943
+ message: params.message,
944
+ networkId: params.networkId
945
+ });
946
+ const result = await this.providerManager.signMessage(params);
947
+ debug.info(DebugCategory.BROWSER_SDK, "Message signed successfully", {
948
+ message: params.message,
949
+ networkId: params.networkId,
950
+ result
951
+ });
952
+ return result;
586
953
  }
587
954
  /**
588
955
  * Sign and send a transaction
@@ -590,7 +957,15 @@ var BrowserSDK = class {
590
957
  * @returns Transaction result
591
958
  */
592
959
  async signAndSendTransaction(params) {
593
- return this.providerManager.signAndSendTransaction(params);
960
+ debug.info(DebugCategory.BROWSER_SDK, "Signing and sending transaction", {
961
+ networkId: params.networkId
962
+ });
963
+ const result = await this.providerManager.signAndSendTransaction(params);
964
+ debug.info(DebugCategory.BROWSER_SDK, "Transaction signed and sent successfully", {
965
+ networkId: params.networkId,
966
+ result
967
+ });
968
+ return result;
594
969
  }
595
970
  /**
596
971
  * Get wallet addresses
@@ -639,9 +1014,19 @@ var BrowserSDK = class {
639
1014
  };
640
1015
 
641
1016
  // src/index.ts
642
- import { NetworkId, AddressType as AddressType2 } from "@phantom/client";
1017
+ import { NetworkId } from "@phantom/constants";
1018
+ import { AddressType as AddressType2 } from "@phantom/client";
643
1019
  export {
644
1020
  AddressType2 as AddressType,
645
1021
  BrowserSDK,
646
- NetworkId
1022
+ DEFAULT_AUTH_URL,
1023
+ DEFAULT_WALLET_API_URL,
1024
+ DebugCategory,
1025
+ DebugLevel,
1026
+ NetworkId,
1027
+ debug,
1028
+ detectBrowser,
1029
+ getBrowserDisplayName,
1030
+ getPlatformName,
1031
+ parseBrowserFromUserAgent
647
1032
  };