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

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) {
@@ -774,8 +897,7 @@ var BrowserAuthProvider = class {
774
897
  }
775
898
  const phantomOptions = options;
776
899
  debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Starting Phantom Connect authentication", {
777
- organizationId: phantomOptions.organizationId,
778
- parentOrganizationId: phantomOptions.parentOrganizationId,
900
+ publicKey: phantomOptions.publicKey,
779
901
  appId: phantomOptions.appId,
780
902
  provider: phantomOptions.provider,
781
903
  authUrl: phantomOptions.authUrl,
@@ -784,12 +906,12 @@ var BrowserAuthProvider = class {
784
906
  const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
785
907
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
786
908
  const params = new URLSearchParams({
787
- organization_id: phantomOptions.organizationId,
788
- parent_organization_id: phantomOptions.parentOrganizationId,
909
+ public_key: phantomOptions.publicKey,
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.11"
793
915
  });
794
916
  if (phantomOptions.provider) {
795
917
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -805,8 +927,7 @@ var BrowserAuthProvider = class {
805
927
  params.append("authData", JSON.stringify(phantomOptions.customAuthData));
806
928
  }
807
929
  const authContext = {
808
- organizationId: phantomOptions.organizationId,
809
- parentOrganizationId: phantomOptions.parentOrganizationId,
930
+ publicKey: phantomOptions.publicKey,
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:") && !authUrl.startsWith("http://localhost")) {
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
  });
@@ -870,10 +994,30 @@ var BrowserAuthProvider = class {
870
994
  sessionId,
871
995
  accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : void 0
872
996
  });
997
+ const organizationId = this.urlParamsAccessor.getParam("organization_id");
998
+ const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
999
+ debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
1000
+ walletId,
1001
+ organizationId,
1002
+ sessionId,
1003
+ accountDerivationIndex,
1004
+ expiresInMs
1005
+ });
1006
+ if (!organizationId) {
1007
+ debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
1008
+ throw new Error("Missing organization_id in auth response");
1009
+ }
1010
+ if (organizationId.startsWith("temp-")) {
1011
+ debug.warn(DebugCategory.PHANTOM_CONNECT_AUTH, "Received temporary organization_id, server may not be configured properly", {
1012
+ organizationId
1013
+ });
1014
+ }
873
1015
  return {
874
1016
  walletId,
1017
+ organizationId,
875
1018
  userInfo: context,
876
- accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : void 0
1019
+ accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
1020
+ expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
877
1021
  };
878
1022
  } catch (error) {
879
1023
  sessionStorage.removeItem("phantom-auth-context");
@@ -903,7 +1047,7 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
903
1047
  let name = "unknown";
904
1048
  let version = "unknown";
905
1049
  if (!userAgent || typeof userAgent !== "string") {
906
- return { name, version };
1050
+ return { name, version, userAgent: "unknown" };
907
1051
  }
908
1052
  try {
909
1053
  if (userAgent.includes("Edg/")) {
@@ -985,11 +1129,11 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
985
1129
  }
986
1130
  } catch (error) {
987
1131
  }
988
- return { name, version };
1132
+ return { name, version, userAgent };
989
1133
  }
990
1134
  function detectBrowser() {
991
1135
  if (typeof window === "undefined" || !window.navigator?.userAgent) {
992
- return { name: "unknown", version: "unknown" };
1136
+ return { name: "unknown", version: "unknown", userAgent: "unknown" };
993
1137
  }
994
1138
  const userAgent = window.navigator.userAgent;
995
1139
  const hasBraveAPI = !!navigator.brave;
@@ -1004,25 +1148,70 @@ function getBrowserDisplayName() {
1004
1148
  const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1005
1149
  return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
1006
1150
  }
1151
+ function isMobileDevice() {
1152
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1153
+ return false;
1154
+ }
1155
+ const userAgent = window.navigator.userAgent.toLowerCase();
1156
+ const mobilePatterns = [
1157
+ /android/,
1158
+ /iphone|ipad|ipod/,
1159
+ /blackberry/,
1160
+ /windows phone/,
1161
+ /mobile/,
1162
+ /tablet/,
1163
+ /silk/,
1164
+ /kindle/,
1165
+ /opera mini/,
1166
+ /opera mobi/
1167
+ ];
1168
+ const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
1169
+ let isSmallScreen = false;
1170
+ try {
1171
+ isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
1172
+ } catch (error) {
1173
+ isSmallScreen = false;
1174
+ }
1175
+ let isTouchDevice = false;
1176
+ try {
1177
+ isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1178
+ } catch (error) {
1179
+ isTouchDevice = false;
1180
+ }
1181
+ return isMobileUA || isSmallScreen && isTouchDevice;
1182
+ }
1007
1183
 
1008
1184
  // src/providers/embedded/index.ts
1185
+ import { ANALYTICS_HEADERS } from "@phantom/constants";
1009
1186
  var EmbeddedProvider = class extends CoreEmbeddedProvider {
1010
1187
  constructor(config) {
1011
1188
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
1012
1189
  const urlParamsAccessor = new BrowserURLParamsAccessor();
1013
1190
  const stamper = new IndexedDbStamper({
1014
- dbName: `phantom-embedded-sdk-${config.organizationId}`,
1191
+ dbName: `phantom-embedded-sdk-${config.appId}`,
1015
1192
  storeName: "crypto-keys",
1016
1193
  keyName: "signing-key"
1017
1194
  });
1018
1195
  const platformName = getPlatformName();
1196
+ const { name: browserName, version } = detectBrowser();
1019
1197
  const platform = {
1020
1198
  storage: new BrowserStorage(),
1021
1199
  authProvider: new BrowserAuthProvider(urlParamsAccessor),
1022
1200
  urlParamsAccessor,
1023
1201
  stamper,
1024
- name: platformName
1202
+ name: platformName,
1025
1203
  // Use detected browser name and version for identification
1204
+ analyticsHeaders: {
1205
+ [ANALYTICS_HEADERS.SDK_TYPE]: "browser",
1206
+ [ANALYTICS_HEADERS.PLATFORM]: browserName,
1207
+ // firefox, chrome, safari, etc.
1208
+ [ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
1209
+ // Full user agent for more detailed info
1210
+ [ANALYTICS_HEADERS.APP_ID]: config.appId,
1211
+ [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1212
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.11"
1213
+ // Replaced at build time
1214
+ }
1026
1215
  };
1027
1216
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
1028
1217
  const logger = new BrowserLogger();
@@ -1032,6 +1221,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1032
1221
  };
1033
1222
 
1034
1223
  // src/ProviderManager.ts
1224
+ import { DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
1035
1225
  var ProviderManager = class {
1036
1226
  // Track which providers have forwarding set up
1037
1227
  constructor(config) {
@@ -1050,6 +1240,15 @@ var ProviderManager = class {
1050
1240
  currentProviderKey: this.currentProviderKey
1051
1241
  });
1052
1242
  }
1243
+ getValidatedCurrentUrl() {
1244
+ if (typeof window === "undefined")
1245
+ return "";
1246
+ const currentUrl = window.location.href;
1247
+ if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
1248
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
1249
+ }
1250
+ return currentUrl;
1251
+ }
1053
1252
  /**
1054
1253
  * Switch to a different provider type
1055
1254
  */
@@ -1081,7 +1280,8 @@ var ProviderManager = class {
1081
1280
  getCurrentProviderInfo() {
1082
1281
  if (!this.currentProviderKey)
1083
1282
  return null;
1084
- const [type, embeddedWalletType] = this.currentProviderKey.split("-");
1283
+ const parts = this.currentProviderKey.split("-");
1284
+ const [type, embeddedWalletType] = parts;
1085
1285
  return {
1086
1286
  type,
1087
1287
  embeddedWalletType
@@ -1227,7 +1427,7 @@ var ProviderManager = class {
1227
1427
  */
1228
1428
  setDefaultProvider() {
1229
1429
  const defaultType = this.config.providerType || "embedded";
1230
- const defaultEmbeddedType = this.config.embeddedWalletType || "app-wallet";
1430
+ const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
1231
1431
  this.createProvider(defaultType, defaultEmbeddedType);
1232
1432
  this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1233
1433
  }
@@ -1241,22 +1441,27 @@ var ProviderManager = class {
1241
1441
  let provider;
1242
1442
  if (type === "injected") {
1243
1443
  provider = new InjectedProvider({
1244
- solanaProvider: this.config.solanaProvider || "web3js",
1245
- addressTypes: this.config.addressTypes
1444
+ addressTypes: this.config.addressTypes || [AddressType.solana]
1246
1445
  });
1247
- } else {
1248
- if (!this.config.apiBaseUrl || !this.config.appId) {
1249
- throw new Error("apiBaseUrl and appId are required for embedded provider");
1446
+ } else if (type === "embedded") {
1447
+ if (!this.config.appId) {
1448
+ throw new Error("appId is required for embedded provider");
1250
1449
  }
1450
+ const apiBaseUrl = this.config.apiBaseUrl || DEFAULT_WALLET_API_URL;
1451
+ const authUrl = this.config.authOptions?.authUrl || DEFAULT_AUTH_URL2;
1251
1452
  provider = new EmbeddedProvider({
1252
- apiBaseUrl: this.config.apiBaseUrl,
1253
- organizationId: this.config.appId,
1453
+ apiBaseUrl,
1254
1454
  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"
1455
+ authOptions: {
1456
+ ...this.config.authOptions || {},
1457
+ authUrl,
1458
+ redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
1459
+ },
1460
+ embeddedWalletType: embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
1461
+ addressTypes: this.config.addressTypes || [AddressType.solana]
1259
1462
  });
1463
+ } else {
1464
+ throw new Error(`Unsupported provider type: ${type}`);
1260
1465
  }
1261
1466
  this.providers.set(key, provider);
1262
1467
  }
@@ -1266,8 +1471,10 @@ var ProviderManager = class {
1266
1471
  getProviderKey(type, embeddedWalletType) {
1267
1472
  if (type === "injected") {
1268
1473
  return "injected";
1474
+ } else if (type === "embedded") {
1475
+ return `embedded-${embeddedWalletType || "app-wallet"}`;
1269
1476
  }
1270
- return `embedded-${embeddedWalletType || "app-wallet"}`;
1477
+ throw new Error(`Unsupported provider type: ${type}`);
1271
1478
  }
1272
1479
  /**
1273
1480
  * Save provider preference to localStorage
@@ -1328,6 +1535,7 @@ async function waitForPhantomExtension(timeoutMs = 3e3) {
1328
1535
  }
1329
1536
 
1330
1537
  // src/BrowserSDK.ts
1538
+ import { DEFAULT_EMBEDDED_WALLET_TYPE as DEFAULT_EMBEDDED_WALLET_TYPE2 } from "@phantom/constants";
1331
1539
  var BrowserSDK = class {
1332
1540
  constructor(config) {
1333
1541
  debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
@@ -1339,7 +1547,7 @@ var BrowserSDK = class {
1339
1547
  debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
1340
1548
  throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
1341
1549
  }
1342
- const embeddedWalletType = config.embeddedWalletType || "app-wallet";
1550
+ const embeddedWalletType = config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE2;
1343
1551
  if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
1344
1552
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
1345
1553
  embeddedWalletType: config.embeddedWalletType
@@ -1475,7 +1683,7 @@ var BrowserSDK = class {
1475
1683
  async autoConnect() {
1476
1684
  debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
1477
1685
  const currentProvider = this.providerManager.getCurrentProvider();
1478
- if (currentProvider && "autoConnect" in currentProvider) {
1686
+ if (currentProvider) {
1479
1687
  await currentProvider.autoConnect();
1480
1688
  } else {
1481
1689
  debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
@@ -1624,8 +1832,15 @@ var BrowserSDK = class {
1624
1832
  }
1625
1833
  };
1626
1834
 
1627
- // src/types.ts
1628
- import { AddressType as AddressType4 } from "@phantom/client";
1835
+ // src/utils/deeplink.ts
1836
+ function getDeeplinkToPhantom(ref) {
1837
+ if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
1838
+ throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
1839
+ }
1840
+ const currentUrl = encodeURIComponent(window.location.href);
1841
+ const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
1842
+ return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1843
+ }
1629
1844
 
1630
1845
  // src/index.ts
1631
1846
  import { NetworkId } from "@phantom/constants";
@@ -1633,15 +1848,15 @@ import { AddressType as AddressType5 } from "@phantom/client";
1633
1848
  export {
1634
1849
  AddressType5 as AddressType,
1635
1850
  BrowserSDK,
1636
- DEFAULT_AUTH_URL,
1637
- DEFAULT_WALLET_API_URL,
1638
1851
  DebugCategory,
1639
1852
  DebugLevel,
1640
1853
  NetworkId,
1641
1854
  debug,
1642
1855
  detectBrowser,
1643
1856
  getBrowserDisplayName,
1857
+ getDeeplinkToPhantom,
1644
1858
  getPlatformName,
1859
+ isMobileDevice,
1645
1860
  parseBrowserFromUserAgent,
1646
1861
  waitForPhantomExtension
1647
1862
  };