@phantom/browser-sdk 1.0.0-beta.1 → 1.0.0-beta.10

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
@@ -1,5 +1,8 @@
1
+ // src/types.ts
2
+ import { AddressType } from "@phantom/client";
3
+
1
4
  // src/providers/injected/index.ts
2
- import { AddressType as AddressType3 } from "@phantom/client";
5
+ import { AddressType as AddressType4 } from "@phantom/client";
3
6
  import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
4
7
  import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
5
8
  import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
@@ -83,7 +86,7 @@ var DebugCategory = {
83
86
 
84
87
  // src/providers/injected/chains/SolanaChain.ts
85
88
  import { EventEmitter } from "eventemitter3";
86
- import { AddressType } from "@phantom/client";
89
+ import { AddressType as AddressType2 } from "@phantom/client";
87
90
  import { Buffer } from "buffer";
88
91
  var InjectedSolanaChain = class {
89
92
  constructor(phantom, callbacks) {
@@ -108,7 +111,7 @@ var InjectedSolanaChain = class {
108
111
  return Promise.reject(new Error("Provider not connected. Call provider connect first."));
109
112
  }
110
113
  const addresses = this.callbacks.getAddresses();
111
- const solanaAddress = addresses.find((addr) => addr.addressType === AddressType.solana);
114
+ const solanaAddress = addresses.find((addr) => addr.addressType === AddressType2.solana);
112
115
  if (!solanaAddress) {
113
116
  return Promise.reject(new Error("Solana not enabled for this provider"));
114
117
  }
@@ -127,17 +130,42 @@ var InjectedSolanaChain = class {
127
130
  publicKey: this._publicKey || ""
128
131
  };
129
132
  }
130
- signTransaction(_transaction) {
131
- return Promise.reject(
132
- new Error("Sign-only transactions not supported by injected provider. Use signAndSendTransaction instead.")
133
- );
133
+ async signTransaction(transaction) {
134
+ if (!this.callbacks.isConnected()) {
135
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
136
+ }
137
+ try {
138
+ const result = await this.phantom.solana.signTransaction(transaction);
139
+ return result;
140
+ } catch (error) {
141
+ return Promise.reject(error);
142
+ }
134
143
  }
135
144
  async signAndSendTransaction(transaction) {
136
145
  const result = await this.phantom.solana.signAndSendTransaction(transaction);
137
146
  return { signature: result.signature };
138
147
  }
139
- signAllTransactions(_transactions) {
140
- return Promise.reject(new Error("Sign-only transactions not supported by injected provider"));
148
+ async signAllTransactions(transactions) {
149
+ if (!this.callbacks.isConnected()) {
150
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
151
+ }
152
+ try {
153
+ const result = await this.phantom.solana.signAllTransactions(transactions);
154
+ return result;
155
+ } catch (error) {
156
+ return Promise.reject(error);
157
+ }
158
+ }
159
+ async signAndSendAllTransactions(transactions) {
160
+ if (!this.callbacks.isConnected()) {
161
+ return Promise.reject(new Error("Provider not connected. Call provider connect first."));
162
+ }
163
+ try {
164
+ const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
165
+ return { signatures: result.signatures };
166
+ } catch (error) {
167
+ return Promise.reject(error);
168
+ }
141
169
  }
142
170
  switchNetwork(_network) {
143
171
  return Promise.resolve();
@@ -163,7 +191,7 @@ var InjectedSolanaChain = class {
163
191
  this.eventEmitter.emit("accountChanged", publicKey);
164
192
  });
165
193
  this.callbacks.on("connect", (data) => {
166
- const solanaAddress = data.addresses?.find((addr) => addr.addressType === AddressType.solana);
194
+ const solanaAddress = data.addresses?.find((addr) => addr.addressType === AddressType2.solana);
167
195
  if (solanaAddress) {
168
196
  this.updateConnectionState(true, solanaAddress.address);
169
197
  }
@@ -174,7 +202,7 @@ var InjectedSolanaChain = class {
174
202
  }
175
203
  syncInitialState() {
176
204
  if (this.callbacks.isConnected()) {
177
- const solanaAddress = this.callbacks.getAddresses().find((addr) => addr.addressType === AddressType.solana);
205
+ const solanaAddress = this.callbacks.getAddresses().find((addr) => addr.addressType === AddressType2.solana);
178
206
  if (solanaAddress) {
179
207
  this.updateConnectionState(true, solanaAddress.address);
180
208
  }
@@ -195,7 +223,7 @@ var InjectedSolanaChain = class {
195
223
 
196
224
  // src/providers/injected/chains/EthereumChain.ts
197
225
  import { EventEmitter as EventEmitter2 } from "eventemitter3";
198
- import { AddressType as AddressType2 } from "@phantom/client";
226
+ import { AddressType as AddressType3 } from "@phantom/client";
199
227
  var InjectedEthereumChain = class {
200
228
  constructor(phantom, callbacks) {
201
229
  this._connected = false;
@@ -217,8 +245,13 @@ var InjectedEthereumChain = class {
217
245
  get accounts() {
218
246
  return this._accounts;
219
247
  }
220
- // EIP-1193 core method - unchanged, already compliant!
248
+ // EIP-1193 core method with eth_signTransaction support
221
249
  async request(args) {
250
+ if (args.method === "eth_signTransaction") {
251
+ const [transaction] = args.params;
252
+ const result = await this.signTransaction(transaction);
253
+ return result;
254
+ }
222
255
  const provider = await this.phantom.ethereum.getProvider();
223
256
  return await provider.request(args);
224
257
  }
@@ -228,7 +261,7 @@ var InjectedEthereumChain = class {
228
261
  return Promise.reject(new Error("Provider not connected. Call provider connect first."));
229
262
  }
230
263
  const addresses = this.callbacks.getAddresses();
231
- const ethAddresses = addresses.filter((addr) => addr.addressType === AddressType2.ethereum).map((addr) => addr.address);
264
+ const ethAddresses = addresses.filter((addr) => addr.addressType === AddressType3.ethereum).map((addr) => addr.address);
232
265
  this.updateConnectionState(true, ethAddresses);
233
266
  return Promise.resolve(ethAddresses);
234
267
  }
@@ -242,6 +275,9 @@ var InjectedEthereumChain = class {
242
275
  async signTypedData(typedData, address) {
243
276
  return await this.phantom.ethereum.signTypedData(typedData, address);
244
277
  }
278
+ async signTransaction(transaction) {
279
+ return await this.phantom.ethereum.signTransaction(transaction);
280
+ }
245
281
  async sendTransaction(transaction) {
246
282
  return await this.phantom.ethereum.sendTransaction(transaction);
247
283
  }
@@ -280,7 +316,7 @@ var InjectedEthereumChain = class {
280
316
  this.eventEmitter.emit("chainChanged", chainId);
281
317
  });
282
318
  this.callbacks.on("connect", (data) => {
283
- const ethAddresses = data.addresses?.filter((addr) => addr.addressType === AddressType2.ethereum)?.map((addr) => addr.address) || [];
319
+ const ethAddresses = data.addresses?.filter((addr) => addr.addressType === AddressType3.ethereum)?.map((addr) => addr.address) || [];
284
320
  if (ethAddresses.length > 0) {
285
321
  this.updateConnectionState(true, ethAddresses);
286
322
  }
@@ -291,7 +327,7 @@ var InjectedEthereumChain = class {
291
327
  }
292
328
  syncInitialState() {
293
329
  if (this.callbacks.isConnected()) {
294
- const ethAddresses = this.callbacks.getAddresses().filter((addr) => addr.addressType === AddressType2.ethereum).map((addr) => addr.address);
330
+ const ethAddresses = this.callbacks.getAddresses().filter((addr) => addr.addressType === AddressType3.ethereum).map((addr) => addr.address);
295
331
  if (ethAddresses.length > 0) {
296
332
  this.updateConnectionState(true, ethAddresses);
297
333
  }
@@ -323,11 +359,11 @@ var InjectedProvider = class {
323
359
  this.addressTypes = config.addressTypes;
324
360
  debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
325
361
  const plugins = [createExtensionPlugin()];
326
- if (this.addressTypes.includes(AddressType3.solana)) {
362
+ if (this.addressTypes.includes(AddressType4.solana)) {
327
363
  plugins.push(createSolanaPlugin());
328
364
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana plugin added");
329
365
  }
330
- if (this.addressTypes.includes(AddressType3.ethereum)) {
366
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
331
367
  plugins.push(createEthereumPlugin());
332
368
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum plugin added");
333
369
  }
@@ -338,10 +374,10 @@ var InjectedProvider = class {
338
374
  });
339
375
  this.phantom = createPhantom({ plugins });
340
376
  const callbacks = this.createCallbacks();
341
- if (this.addressTypes.includes(AddressType3.solana)) {
377
+ if (this.addressTypes.includes(AddressType4.solana)) {
342
378
  this._solanaChain = new InjectedSolanaChain(this.phantom, callbacks);
343
379
  }
344
- if (this.addressTypes.includes(AddressType3.ethereum)) {
380
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
345
381
  this._ethereumChain = new InjectedEthereumChain(this.phantom, callbacks);
346
382
  }
347
383
  debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
@@ -350,7 +386,7 @@ var InjectedProvider = class {
350
386
  * Access to Solana chain operations
351
387
  */
352
388
  get solana() {
353
- if (!this.addressTypes.includes(AddressType3.solana)) {
389
+ if (!this.addressTypes.includes(AddressType4.solana)) {
354
390
  throw new Error("Solana not enabled for this provider");
355
391
  }
356
392
  if (!this._solanaChain) {
@@ -362,7 +398,7 @@ var InjectedProvider = class {
362
398
  * Access to Ethereum chain operations
363
399
  */
364
400
  get ethereum() {
365
- if (!this.addressTypes.includes(AddressType3.ethereum)) {
401
+ if (!this.addressTypes.includes(AddressType4.ethereum)) {
366
402
  throw new Error("Ethereum not enabled for this provider");
367
403
  }
368
404
  if (!this._ethereumChain) {
@@ -392,13 +428,13 @@ var InjectedProvider = class {
392
428
  }
393
429
  debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
394
430
  const connectedAddresses = [];
395
- if (this.addressTypes.includes(AddressType3.solana)) {
431
+ if (this.addressTypes.includes(AddressType4.solana)) {
396
432
  debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
397
433
  try {
398
434
  const publicKey = await this.phantom.solana.connect();
399
435
  if (publicKey) {
400
436
  connectedAddresses.push({
401
- addressType: AddressType3.solana,
437
+ addressType: AddressType4.solana,
402
438
  address: publicKey
403
439
  });
404
440
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
@@ -407,13 +443,13 @@ var InjectedProvider = class {
407
443
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
408
444
  }
409
445
  }
410
- if (this.addressTypes.includes(AddressType3.ethereum)) {
446
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
411
447
  try {
412
448
  const accounts = await this.phantom.ethereum.connect();
413
449
  if (accounts && accounts.length > 0) {
414
450
  connectedAddresses.push(
415
451
  ...accounts.map((address) => ({
416
- addressType: AddressType3.ethereum,
452
+ addressType: AddressType4.ethereum,
417
453
  address
418
454
  }))
419
455
  );
@@ -455,7 +491,7 @@ var InjectedProvider = class {
455
491
  }
456
492
  async disconnect() {
457
493
  debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
458
- if (this.addressTypes.includes(AddressType3.solana)) {
494
+ if (this.addressTypes.includes(AddressType4.solana)) {
459
495
  try {
460
496
  await this.phantom.solana.disconnect();
461
497
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
@@ -463,7 +499,7 @@ var InjectedProvider = class {
463
499
  debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
464
500
  }
465
501
  }
466
- if (this.addressTypes.includes(AddressType3.ethereum)) {
502
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
467
503
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected (no-op)");
468
504
  }
469
505
  this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
@@ -475,6 +511,87 @@ var InjectedProvider = class {
475
511
  });
476
512
  debug.info(DebugCategory.INJECTED_PROVIDER, "Injected provider disconnected successfully");
477
513
  }
514
+ /**
515
+ * Attempt auto-connection using onlyIfTrusted parameter
516
+ * This will only connect if the dApp is already trusted by the user
517
+ * Should be called after setting up event listeners
518
+ */
519
+ async autoConnect() {
520
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting auto-connect with onlyIfTrusted=true");
521
+ this.emit("connect_start", {
522
+ source: "auto-connect",
523
+ providerType: "injected"
524
+ });
525
+ try {
526
+ if (!this.phantom.extension?.isInstalled?.()) {
527
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found for auto-connect");
528
+ this.emit("connect_error", {
529
+ error: "Phantom wallet not found",
530
+ source: "auto-connect"
531
+ });
532
+ return;
533
+ }
534
+ const connectedAddresses = [];
535
+ if (this.addressTypes.includes(AddressType4.solana)) {
536
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana auto-connect");
537
+ try {
538
+ const publicKey = await this.phantom.solana.connect({ onlyIfTrusted: true });
539
+ if (publicKey) {
540
+ connectedAddresses.push({
541
+ addressType: AddressType4.solana,
542
+ address: publicKey
543
+ });
544
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Solana auto-connected successfully", { address: publicKey });
545
+ }
546
+ } catch (err) {
547
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana auto-connect failed (expected if not trusted)", { error: err });
548
+ }
549
+ }
550
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
551
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum auto-connect");
552
+ try {
553
+ const accounts = await this.phantom.ethereum.connect({ onlyIfTrusted: true });
554
+ if (accounts && accounts.length > 0) {
555
+ connectedAddresses.push(
556
+ ...accounts.map((address) => ({
557
+ addressType: AddressType4.ethereum,
558
+ address
559
+ }))
560
+ );
561
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connected successfully", { addresses: accounts });
562
+ }
563
+ } catch (err) {
564
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connect failed (expected if not trusted)", { error: err });
565
+ }
566
+ }
567
+ if (connectedAddresses.length === 0) {
568
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed: no trusted connections available");
569
+ this.emit("connect_error", {
570
+ error: "No trusted connections available",
571
+ source: "auto-connect"
572
+ });
573
+ return;
574
+ }
575
+ this.addresses = connectedAddresses;
576
+ this.connected = true;
577
+ this.emit("connect", {
578
+ addresses: this.addresses,
579
+ source: "auto-connect"
580
+ });
581
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
582
+ addressCount: connectedAddresses.length,
583
+ addresses: connectedAddresses.map((addr) => ({ type: addr.addressType, address: addr.address.substring(0, 8) + "..." }))
584
+ });
585
+ } catch (error) {
586
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed with error", {
587
+ error: error instanceof Error ? error.message : String(error)
588
+ });
589
+ this.emit("connect_error", {
590
+ error: error instanceof Error ? error.message : "Auto-connect failed",
591
+ source: "auto-connect"
592
+ });
593
+ }
594
+ }
478
595
  getAddresses() {
479
596
  return this.addresses;
480
597
  }
@@ -538,10 +655,10 @@ var InjectedProvider = class {
538
655
  }
539
656
  setupBrowserInjectedEvents() {
540
657
  debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
541
- if (this.addressTypes.includes(AddressType3.solana)) {
658
+ if (this.addressTypes.includes(AddressType4.solana)) {
542
659
  this.setupSolanaEvents();
543
660
  }
544
- if (this.addressTypes.includes(AddressType3.ethereum)) {
661
+ if (this.addressTypes.includes(AddressType4.ethereum)) {
545
662
  this.setupEthereumEvents();
546
663
  }
547
664
  }
@@ -549,8 +666,8 @@ var InjectedProvider = class {
549
666
  debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
550
667
  const handleSolanaConnect = (publicKey) => {
551
668
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
552
- const solanaAddress = { addressType: AddressType3.solana, address: publicKey };
553
- if (!this.addresses.find((addr) => addr.addressType === AddressType3.solana)) {
669
+ const solanaAddress = { addressType: AddressType4.solana, address: publicKey };
670
+ if (!this.addresses.find((addr) => addr.addressType === AddressType4.solana)) {
554
671
  this.addresses.push(solanaAddress);
555
672
  }
556
673
  this.connected = true;
@@ -561,19 +678,19 @@ var InjectedProvider = class {
561
678
  };
562
679
  const handleSolanaDisconnect = () => {
563
680
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
564
- this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType3.solana);
565
- this.connected = this.addresses.length > 0;
681
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType4.solana);
682
+ this.connected = false;
566
683
  this.emit("disconnect", {
567
684
  source: "injected-extension"
568
685
  });
569
686
  };
570
687
  const handleSolanaAccountChanged = (publicKey) => {
571
688
  debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
572
- const solanaIndex = this.addresses.findIndex((addr) => addr.addressType === AddressType3.solana);
689
+ const solanaIndex = this.addresses.findIndex((addr) => addr.addressType === AddressType4.solana);
573
690
  if (solanaIndex >= 0) {
574
- this.addresses[solanaIndex] = { addressType: AddressType3.solana, address: publicKey };
691
+ this.addresses[solanaIndex] = { addressType: AddressType4.solana, address: publicKey };
575
692
  } else {
576
- this.addresses.push({ addressType: AddressType3.solana, address: publicKey });
693
+ this.addresses.push({ addressType: AddressType4.solana, address: publicKey });
577
694
  }
578
695
  this.emit("connect", {
579
696
  addresses: this.addresses,
@@ -582,21 +699,18 @@ var InjectedProvider = class {
582
699
  };
583
700
  const cleanupConnect = this.phantom.solana.addEventListener("connect", handleSolanaConnect);
584
701
  const cleanupDisconnect = this.phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
585
- const cleanupAccountChanged = this.phantom.solana.addEventListener(
586
- "accountChanged",
587
- handleSolanaAccountChanged
588
- );
702
+ const cleanupAccountChanged = this.phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
589
703
  this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
590
704
  }
591
705
  setupEthereumEvents() {
592
706
  debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
593
707
  const handleEthereumConnect = (accounts) => {
594
708
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
595
- this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
709
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType4.ethereum);
596
710
  if (accounts && accounts.length > 0) {
597
711
  this.addresses.push(
598
712
  ...accounts.map((address) => ({
599
- addressType: AddressType3.ethereum,
713
+ addressType: AddressType4.ethereum,
600
714
  address
601
715
  }))
602
716
  );
@@ -609,27 +723,32 @@ var InjectedProvider = class {
609
723
  };
610
724
  const handleEthereumDisconnect = () => {
611
725
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
612
- this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
613
- this.connected = this.addresses.length > 0;
726
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType4.ethereum);
727
+ this.connected = false;
614
728
  this.emit("disconnect", {
615
729
  source: "injected-extension"
616
730
  });
617
731
  };
618
732
  const handleEthereumAccountsChanged = (accounts) => {
619
733
  debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
620
- this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType3.ethereum);
734
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType4.ethereum);
621
735
  if (accounts && accounts.length > 0) {
622
736
  this.addresses.push(
623
737
  ...accounts.map((address) => ({
624
- addressType: AddressType3.ethereum,
738
+ addressType: AddressType4.ethereum,
625
739
  address
626
740
  }))
627
741
  );
742
+ this.emit("connect", {
743
+ addresses: this.addresses,
744
+ source: "injected-extension-account-change"
745
+ });
746
+ } else {
747
+ this.connected = false;
748
+ this.emit("disconnect", {
749
+ source: "injected-extension-account-change"
750
+ });
628
751
  }
629
- this.emit("connect", {
630
- addresses: this.addresses,
631
- source: "injected-extension-account-change"
632
- });
633
752
  };
634
753
  const cleanupConnect = this.phantom.ethereum.addEventListener("connect", handleEthereumConnect);
635
754
  const cleanupDisconnect = this.phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
@@ -758,15 +877,19 @@ var BrowserURLParamsAccessor = class {
758
877
  };
759
878
  var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
760
879
 
761
- // src/constants.ts
762
- var DEFAULT_AUTH_URL = "https://connect.phantom.app";
763
- var DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
764
-
765
880
  // src/providers/embedded/adapters/auth.ts
881
+ import { DEFAULT_AUTH_URL } from "@phantom/constants";
766
882
  var BrowserAuthProvider = class {
767
883
  constructor(urlParamsAccessor) {
768
884
  this.urlParamsAccessor = urlParamsAccessor;
769
885
  }
886
+ getValidatedCurrentUrl() {
887
+ const currentUrl = window.location.href;
888
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
889
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
890
+ }
891
+ return currentUrl;
892
+ }
770
893
  authenticate(options) {
771
894
  return new Promise((resolve) => {
772
895
  if ("jwtToken" in options) {
@@ -775,7 +898,6 @@ var BrowserAuthProvider = class {
775
898
  const phantomOptions = options;
776
899
  debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Starting Phantom Connect authentication", {
777
900
  organizationId: phantomOptions.organizationId,
778
- parentOrganizationId: phantomOptions.parentOrganizationId,
779
901
  appId: phantomOptions.appId,
780
902
  provider: phantomOptions.provider,
781
903
  authUrl: phantomOptions.authUrl,
@@ -785,11 +907,11 @@ var BrowserAuthProvider = class {
785
907
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
786
908
  const params = new URLSearchParams({
787
909
  organization_id: phantomOptions.organizationId,
788
- parent_organization_id: phantomOptions.parentOrganizationId,
789
910
  app_id: phantomOptions.appId,
790
- redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? window.location.href : ""),
911
+ redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
791
912
  session_id: phantomOptions.sessionId,
792
- clear_previous_session: true.toString()
913
+ clear_previous_session: true.toString(),
914
+ sdk_version: "1.0.0-beta.10"
793
915
  });
794
916
  if (phantomOptions.provider) {
795
917
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -806,7 +928,6 @@ var BrowserAuthProvider = class {
806
928
  }
807
929
  const authContext = {
808
930
  organizationId: phantomOptions.organizationId,
809
- parentOrganizationId: phantomOptions.parentOrganizationId,
810
931
  appId: phantomOptions.appId,
811
932
  provider: phantomOptions.provider,
812
933
  sessionId: phantomOptions.sessionId
@@ -815,6 +936,9 @@ var BrowserAuthProvider = class {
815
936
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
816
937
  const authUrl = `${baseUrl}?${params.toString()}`;
817
938
  debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
939
+ if (!authUrl.startsWith("https:")) {
940
+ throw new Error("Invalid auth URL - only HTTPS URLs are allowed for authentication");
941
+ }
818
942
  window.location.href = authUrl;
819
943
  resolve();
820
944
  });
@@ -903,7 +1027,7 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
903
1027
  let name = "unknown";
904
1028
  let version = "unknown";
905
1029
  if (!userAgent || typeof userAgent !== "string") {
906
- return { name, version };
1030
+ return { name, version, userAgent: "unknown" };
907
1031
  }
908
1032
  try {
909
1033
  if (userAgent.includes("Edg/")) {
@@ -985,11 +1109,11 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
985
1109
  }
986
1110
  } catch (error) {
987
1111
  }
988
- return { name, version };
1112
+ return { name, version, userAgent };
989
1113
  }
990
1114
  function detectBrowser() {
991
1115
  if (typeof window === "undefined" || !window.navigator?.userAgent) {
992
- return { name: "unknown", version: "unknown" };
1116
+ return { name: "unknown", version: "unknown", userAgent: "unknown" };
993
1117
  }
994
1118
  const userAgent = window.navigator.userAgent;
995
1119
  const hasBraveAPI = !!navigator.brave;
@@ -1004,25 +1128,70 @@ function getBrowserDisplayName() {
1004
1128
  const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1005
1129
  return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
1006
1130
  }
1131
+ function isMobileDevice() {
1132
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1133
+ return false;
1134
+ }
1135
+ const userAgent = window.navigator.userAgent.toLowerCase();
1136
+ const mobilePatterns = [
1137
+ /android/,
1138
+ /iphone|ipad|ipod/,
1139
+ /blackberry/,
1140
+ /windows phone/,
1141
+ /mobile/,
1142
+ /tablet/,
1143
+ /silk/,
1144
+ /kindle/,
1145
+ /opera mini/,
1146
+ /opera mobi/
1147
+ ];
1148
+ const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
1149
+ let isSmallScreen = false;
1150
+ try {
1151
+ isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
1152
+ } catch (error) {
1153
+ isSmallScreen = false;
1154
+ }
1155
+ let isTouchDevice = false;
1156
+ try {
1157
+ isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1158
+ } catch (error) {
1159
+ isTouchDevice = false;
1160
+ }
1161
+ return isMobileUA || isSmallScreen && isTouchDevice;
1162
+ }
1007
1163
 
1008
1164
  // src/providers/embedded/index.ts
1165
+ import { ANALYTICS_HEADERS } from "@phantom/constants";
1009
1166
  var EmbeddedProvider = class extends CoreEmbeddedProvider {
1010
1167
  constructor(config) {
1011
1168
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
1012
1169
  const urlParamsAccessor = new BrowserURLParamsAccessor();
1013
1170
  const stamper = new IndexedDbStamper({
1014
- dbName: `phantom-embedded-sdk-${config.organizationId}`,
1171
+ dbName: `phantom-embedded-sdk-${config.appId}`,
1015
1172
  storeName: "crypto-keys",
1016
1173
  keyName: "signing-key"
1017
1174
  });
1018
1175
  const platformName = getPlatformName();
1176
+ const { name: browserName, version } = detectBrowser();
1019
1177
  const platform = {
1020
1178
  storage: new BrowserStorage(),
1021
1179
  authProvider: new BrowserAuthProvider(urlParamsAccessor),
1022
1180
  urlParamsAccessor,
1023
1181
  stamper,
1024
- name: platformName
1182
+ name: platformName,
1025
1183
  // Use detected browser name and version for identification
1184
+ analyticsHeaders: {
1185
+ [ANALYTICS_HEADERS.SDK_TYPE]: "browser",
1186
+ [ANALYTICS_HEADERS.PLATFORM]: browserName,
1187
+ // firefox, chrome, safari, etc.
1188
+ [ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
1189
+ // Full user agent for more detailed info
1190
+ [ANALYTICS_HEADERS.APP_ID]: config.appId,
1191
+ [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1192
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
1193
+ // Replaced at build time
1194
+ }
1026
1195
  };
1027
1196
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
1028
1197
  const logger = new BrowserLogger();
@@ -1032,6 +1201,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1032
1201
  };
1033
1202
 
1034
1203
  // src/ProviderManager.ts
1204
+ import { DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
1035
1205
  var ProviderManager = class {
1036
1206
  // Track which providers have forwarding set up
1037
1207
  constructor(config) {
@@ -1050,6 +1220,15 @@ var ProviderManager = class {
1050
1220
  currentProviderKey: this.currentProviderKey
1051
1221
  });
1052
1222
  }
1223
+ getValidatedCurrentUrl() {
1224
+ if (typeof window === "undefined")
1225
+ return "";
1226
+ const currentUrl = window.location.href;
1227
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
1228
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
1229
+ }
1230
+ return currentUrl;
1231
+ }
1053
1232
  /**
1054
1233
  * Switch to a different provider type
1055
1234
  */
@@ -1081,7 +1260,8 @@ var ProviderManager = class {
1081
1260
  getCurrentProviderInfo() {
1082
1261
  if (!this.currentProviderKey)
1083
1262
  return null;
1084
- const [type, embeddedWalletType] = this.currentProviderKey.split("-");
1263
+ const parts = this.currentProviderKey.split("-");
1264
+ const [type, embeddedWalletType] = parts;
1085
1265
  return {
1086
1266
  type,
1087
1267
  embeddedWalletType
@@ -1227,7 +1407,7 @@ var ProviderManager = class {
1227
1407
  */
1228
1408
  setDefaultProvider() {
1229
1409
  const defaultType = this.config.providerType || "embedded";
1230
- const defaultEmbeddedType = this.config.embeddedWalletType || "app-wallet";
1410
+ const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
1231
1411
  this.createProvider(defaultType, defaultEmbeddedType);
1232
1412
  this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1233
1413
  }
@@ -1241,22 +1421,27 @@ var ProviderManager = class {
1241
1421
  let provider;
1242
1422
  if (type === "injected") {
1243
1423
  provider = new InjectedProvider({
1244
- solanaProvider: this.config.solanaProvider || "web3js",
1245
- addressTypes: this.config.addressTypes
1424
+ addressTypes: this.config.addressTypes || [AddressType.solana]
1246
1425
  });
1247
- } else {
1248
- if (!this.config.apiBaseUrl || !this.config.appId) {
1249
- throw new Error("apiBaseUrl and appId are required for embedded provider");
1426
+ } else if (type === "embedded") {
1427
+ if (!this.config.appId) {
1428
+ throw new Error("appId is required for embedded provider");
1250
1429
  }
1430
+ const apiBaseUrl = this.config.apiBaseUrl || DEFAULT_WALLET_API_URL;
1431
+ const authUrl = this.config.authOptions?.authUrl || DEFAULT_AUTH_URL2;
1251
1432
  provider = new EmbeddedProvider({
1252
- apiBaseUrl: this.config.apiBaseUrl,
1253
- organizationId: this.config.appId,
1433
+ apiBaseUrl,
1254
1434
  appId: this.config.appId,
1255
- authOptions: this.config.authOptions,
1256
- embeddedWalletType: embeddedWalletType || "app-wallet",
1257
- addressTypes: this.config.addressTypes,
1258
- solanaProvider: this.config.solanaProvider || "web3js"
1435
+ authOptions: {
1436
+ ...this.config.authOptions || {},
1437
+ authUrl,
1438
+ redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
1439
+ },
1440
+ embeddedWalletType: embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
1441
+ addressTypes: this.config.addressTypes || [AddressType.solana]
1259
1442
  });
1443
+ } else {
1444
+ throw new Error(`Unsupported provider type: ${type}`);
1260
1445
  }
1261
1446
  this.providers.set(key, provider);
1262
1447
  }
@@ -1266,8 +1451,10 @@ var ProviderManager = class {
1266
1451
  getProviderKey(type, embeddedWalletType) {
1267
1452
  if (type === "injected") {
1268
1453
  return "injected";
1454
+ } else if (type === "embedded") {
1455
+ return `embedded-${embeddedWalletType || "app-wallet"}`;
1269
1456
  }
1270
- return `embedded-${embeddedWalletType || "app-wallet"}`;
1457
+ throw new Error(`Unsupported provider type: ${type}`);
1271
1458
  }
1272
1459
  /**
1273
1460
  * Save provider preference to localStorage
@@ -1328,6 +1515,7 @@ async function waitForPhantomExtension(timeoutMs = 3e3) {
1328
1515
  }
1329
1516
 
1330
1517
  // src/BrowserSDK.ts
1518
+ import { DEFAULT_EMBEDDED_WALLET_TYPE as DEFAULT_EMBEDDED_WALLET_TYPE2 } from "@phantom/constants";
1331
1519
  var BrowserSDK = class {
1332
1520
  constructor(config) {
1333
1521
  debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
@@ -1339,7 +1527,7 @@ var BrowserSDK = class {
1339
1527
  debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
1340
1528
  throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
1341
1529
  }
1342
- const embeddedWalletType = config.embeddedWalletType || "app-wallet";
1530
+ const embeddedWalletType = config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE2;
1343
1531
  if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
1344
1532
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
1345
1533
  embeddedWalletType: config.embeddedWalletType
@@ -1475,7 +1663,7 @@ var BrowserSDK = class {
1475
1663
  async autoConnect() {
1476
1664
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
1477
1665
  const currentProvider = this.providerManager.getCurrentProvider();
1478
- if (currentProvider && "autoConnect" in currentProvider) {
1666
+ if (currentProvider) {
1479
1667
  await currentProvider.autoConnect();
1480
1668
  } else {
1481
1669
  debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
@@ -1624,8 +1812,15 @@ var BrowserSDK = class {
1624
1812
  }
1625
1813
  };
1626
1814
 
1627
- // src/types.ts
1628
- import { AddressType as AddressType4 } from "@phantom/client";
1815
+ // src/utils/deeplink.ts
1816
+ function getDeeplinkToPhantom(ref) {
1817
+ if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
1818
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
1819
+ }
1820
+ const currentUrl = encodeURIComponent(window.location.href);
1821
+ const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
1822
+ return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1823
+ }
1629
1824
 
1630
1825
  // src/index.ts
1631
1826
  import { NetworkId } from "@phantom/constants";
@@ -1633,15 +1828,15 @@ import { AddressType as AddressType5 } from "@phantom/client";
1633
1828
  export {
1634
1829
  AddressType5 as AddressType,
1635
1830
  BrowserSDK,
1636
- DEFAULT_AUTH_URL,
1637
- DEFAULT_WALLET_API_URL,
1638
1831
  DebugCategory,
1639
1832
  DebugLevel,
1640
1833
  NetworkId,
1641
1834
  debug,
1642
1835
  detectBrowser,
1643
1836
  getBrowserDisplayName,
1837
+ getDeeplinkToPhantom,
1644
1838
  getPlatformName,
1839
+ isMobileDevice,
1645
1840
  parseBrowserFromUserAgent,
1646
1841
  waitForPhantomExtension
1647
1842
  };