@phantom/browser-sdk 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,8 +41,7 @@ const sdk = new BrowserSDK({
41
41
  organizationId: "your-org-id",
42
42
  });
43
43
 
44
- const { walletId, addresses } = await sdk.connect();
45
- console.log("Wallet ID:", walletId);
44
+ const { addresses } = await sdk.connect();
46
45
  console.log("Addresses:", addresses);
47
46
 
48
47
  const result = await sdk.signAndSendTransaction({
@@ -89,6 +88,7 @@ const sdk = new BrowserSDK({
89
88
  },
90
89
  appName: "My DApp", // optional, for branding
91
90
  appLogo: "https://myapp.com/logo.png", // optional, for branding
91
+ autoConnect: true, // optional, auto-connect to existing session (default: true for embedded)
92
92
  debug: {
93
93
  enabled: true, // optional, enable debug logging
94
94
  level: "info", // optional, debug level
@@ -162,6 +162,43 @@ const sdk = new BrowserSDK({
162
162
  - **@solana/web3.js**: Better ecosystem compatibility, wider community support
163
163
  - **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
164
164
 
165
+ ### Auto-Connect Feature
166
+
167
+ The SDK can automatically reconnect to existing sessions when instantiated, providing a seamless user experience.
168
+
169
+ ```typescript
170
+ const sdk = new BrowserSDK({
171
+ providerType: "embedded",
172
+ // ... other config
173
+ autoConnect: true, // Default: true for embedded, false for injected
174
+ });
175
+
176
+ // SDK will automatically check for existing valid session and connect in background
177
+ // No need to call connect() if user already has a session
178
+
179
+ // Check if already connected
180
+ if (sdk.isConnected()) {
181
+ console.log("Already connected!");
182
+ const addresses = await sdk.getAddresses();
183
+ } else {
184
+ // First time or session expired, need to connect manually
185
+ await sdk.connect();
186
+ }
187
+ ```
188
+
189
+ **Disabling Auto-Connect:**
190
+
191
+ ```typescript
192
+ const sdk = new BrowserSDK({
193
+ providerType: "embedded",
194
+ // ... other config
195
+ autoConnect: false, // Disable auto-connect
196
+ });
197
+
198
+ // Now you must manually call connect() every time
199
+ await sdk.connect();
200
+ ```
201
+
165
202
  ## API Reference
166
203
 
167
204
  ### Constructor
@@ -188,6 +225,7 @@ interface BrowserSDKConfig {
188
225
  };
189
226
  embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
190
227
  solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
228
+ autoConnect?: boolean; // Enable auto-connect to existing sessions (default: true)
191
229
 
192
230
  // Debug options
193
231
  debug?: {
@@ -316,6 +354,14 @@ Disconnect from wallet and clear session.
316
354
  await sdk.disconnect();
317
355
  ```
318
356
 
357
+ #### autoConnect()
358
+
359
+ Attempt auto-connection using existing session. Should be called after setting up event listeners to avoid race conditions. Only works with embedded providers.
360
+
361
+ ```typescript
362
+ await sdk.autoConnect();
363
+ ```
364
+
319
365
  ## Transaction Examples
320
366
 
321
367
  ### Solana Transactions
package/dist/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { AddressType } from '@phantom/client';
2
- export { AddressType } from '@phantom/client';
3
- import { AuthOptions, ConnectResult, SignMessageParams, SignMessageResult, SignAndSendTransactionParams, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
1
+ import { EmbeddedProviderConfig, AuthOptions, ConnectResult, SignMessageParams, SignMessageResult, SignAndSendTransactionParams, SignedTransaction, WalletAddress, EmbeddedProviderEvent, EventCallback } from '@phantom/embedded-provider-core';
4
2
  export { AuthOptions, ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
5
3
  export { NetworkId } from '@phantom/constants';
4
+ export { AddressType } from '@phantom/client';
6
5
 
7
6
  declare enum DebugLevel {
8
7
  ERROR = 0,
@@ -48,19 +47,12 @@ declare const DebugCategory: {
48
47
  readonly SESSION: "Session";
49
48
  };
50
49
 
51
- interface BrowserSDKConfig {
50
+ interface BrowserSDKConfig extends Partial<EmbeddedProviderConfig> {
52
51
  providerType: "injected" | "embedded" | (string & Record<never, never>);
53
- appName?: string;
54
- appLogo?: string;
55
- addressTypes?: AddressType[];
56
52
  apiBaseUrl?: string;
57
53
  organizationId?: string;
58
- authOptions?: {
59
- authUrl?: string;
60
- redirectUrl?: string;
61
- };
62
54
  embeddedWalletType?: "app-wallet" | "user-wallet" | (string & Record<never, never>);
63
- solanaProvider?: "web3js" | "kit";
55
+ autoConnect?: boolean;
64
56
  debug?: {
65
57
  enabled?: boolean;
66
58
  level?: DebugLevel;
@@ -137,6 +129,22 @@ declare class BrowserSDK {
137
129
  * Get the current wallet ID (for embedded wallets)
138
130
  */
139
131
  getWalletId(): string | null;
132
+ /**
133
+ * Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
134
+ * Works with both embedded and injected providers
135
+ */
136
+ on(event: EmbeddedProviderEvent, callback: EventCallback): void;
137
+ /**
138
+ * Remove event listener for provider events
139
+ * Works with both embedded and injected providers
140
+ */
141
+ off(event: EmbeddedProviderEvent, callback: EventCallback): void;
142
+ /**
143
+ * Attempt auto-connection using existing session
144
+ * Should be called after setting up event listeners
145
+ * Only works with embedded providers
146
+ */
147
+ autoConnect(): Promise<void>;
140
148
  }
141
149
 
142
150
  /**
package/dist/index.js CHANGED
@@ -133,6 +133,10 @@ var InjectedProvider = class {
133
133
  constructor(config) {
134
134
  this.connected = false;
135
135
  this.addresses = [];
136
+ // Event management
137
+ this.eventListeners = /* @__PURE__ */ new Map();
138
+ this.browserInjectedCleanupFunctions = [];
139
+ this.eventsInitialized = false;
136
140
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
137
141
  this.addressTypes = config.addressTypes || [import_client.AddressType.solana, import_client.AddressType.ethereum];
138
142
  debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
@@ -157,70 +161,108 @@ var InjectedProvider = class {
157
161
  authOptionsIgnored: !!authOptions
158
162
  // Note: authOptions are ignored for injected provider
159
163
  });
160
- if (!this.phantom.extension.isInstalled()) {
161
- debug.error(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found");
162
- throw new Error("Phantom wallet not found");
163
- }
164
- debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
165
- const connectedAddresses = [];
166
- if (this.addressTypes.includes(import_client.AddressType.solana)) {
167
- debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
168
- try {
169
- const publicKey = await this.phantom.solana.connect();
170
- if (publicKey) {
171
- connectedAddresses.push({
172
- addressType: import_client.AddressType.solana,
173
- address: publicKey
174
- });
175
- debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
164
+ this.emit("connect_start", {
165
+ source: "manual-connect",
166
+ providerType: "injected"
167
+ });
168
+ try {
169
+ if (!this.phantom.extension.isInstalled()) {
170
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found");
171
+ const error = new Error("Phantom wallet not found");
172
+ this.emit("connect_error", {
173
+ error: error.message,
174
+ source: "manual-connect"
175
+ });
176
+ throw error;
177
+ }
178
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
179
+ const connectedAddresses = [];
180
+ if (this.addressTypes.includes(import_client.AddressType.solana)) {
181
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
182
+ try {
183
+ const publicKey = await this.phantom.solana.connect();
184
+ if (publicKey) {
185
+ connectedAddresses.push({
186
+ addressType: import_client.AddressType.solana,
187
+ address: publicKey
188
+ });
189
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
190
+ }
191
+ } catch (err) {
192
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
176
193
  }
177
- } catch (err) {
178
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
179
194
  }
180
- }
181
- if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
182
- try {
183
- const accounts = await this.phantom.ethereum.connect();
184
- if (accounts && accounts.length > 0) {
185
- connectedAddresses.push(
186
- ...accounts.map((address) => ({
187
- addressType: import_client.AddressType.ethereum,
188
- address
189
- }))
190
- );
195
+ if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
196
+ try {
197
+ const accounts = await this.phantom.ethereum.connect();
198
+ if (accounts && accounts.length > 0) {
199
+ connectedAddresses.push(
200
+ ...accounts.map((address) => ({
201
+ addressType: import_client.AddressType.ethereum,
202
+ address
203
+ }))
204
+ );
205
+ }
206
+ } catch (err) {
207
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
191
208
  }
192
- } catch (err) {
193
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
194
209
  }
210
+ if (connectedAddresses.length === 0) {
211
+ const error = new Error("Failed to connect to any supported wallet provider");
212
+ this.emit("connect_error", {
213
+ error: error.message,
214
+ source: "manual-connect"
215
+ });
216
+ throw error;
217
+ }
218
+ this.addresses = connectedAddresses;
219
+ this.connected = true;
220
+ const result = {
221
+ addresses: this.addresses,
222
+ status: "completed"
223
+ // walletId is not applicable for injected providers
224
+ };
225
+ this.emit("connect", {
226
+ addresses: this.addresses,
227
+ source: "manual-connect"
228
+ });
229
+ return result;
230
+ } catch (error) {
231
+ if (error instanceof Error && !error.message.includes("Phantom wallet not found") && !error.message.includes("Failed to connect to any supported wallet provider")) {
232
+ this.emit("connect_error", {
233
+ error: error.message,
234
+ source: "manual-connect"
235
+ });
236
+ }
237
+ throw error;
195
238
  }
196
- if (connectedAddresses.length === 0) {
197
- throw new Error("Failed to connect to any supported wallet provider");
198
- }
199
- this.addresses = connectedAddresses;
200
- this.connected = true;
201
- return {
202
- addresses: this.addresses,
203
- status: "completed"
204
- // walletId is not applicable for injected providers
205
- };
206
239
  }
207
240
  async disconnect() {
241
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
208
242
  if (this.addressTypes.includes(import_client.AddressType.solana)) {
209
243
  try {
210
244
  await this.phantom.solana.disconnect();
245
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
211
246
  } catch (err) {
212
- console.error("Failed to disconnect Solana:", err);
247
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
213
248
  }
214
249
  }
215
250
  if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
216
251
  try {
217
252
  await this.phantom.ethereum.disconnect();
253
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
218
254
  } catch (err) {
219
- console.error("Failed to disconnect Ethereum:", err);
255
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Ethereum", { error: err });
220
256
  }
221
257
  }
258
+ this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
259
+ this.browserInjectedCleanupFunctions = [];
222
260
  this.connected = false;
223
261
  this.addresses = [];
262
+ this.emit("disconnect", {
263
+ source: "manual-disconnect"
264
+ });
265
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Injected provider disconnected successfully");
224
266
  }
225
267
  async signMessage(params) {
226
268
  if (!this.connected) {
@@ -293,6 +335,139 @@ var InjectedProvider = class {
293
335
  isConnected() {
294
336
  return this.connected;
295
337
  }
338
+ // Event management methods - implementing unified event interface
339
+ on(event, callback) {
340
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
341
+ if (!this.eventsInitialized) {
342
+ this.setupBrowserInjectedEvents();
343
+ this.eventsInitialized = true;
344
+ }
345
+ if (!this.eventListeners.has(event)) {
346
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
347
+ }
348
+ this.eventListeners.get(event).add(callback);
349
+ }
350
+ off(event, callback) {
351
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
352
+ if (this.eventListeners.has(event)) {
353
+ this.eventListeners.get(event).delete(callback);
354
+ if (this.eventListeners.get(event).size === 0) {
355
+ this.eventListeners.delete(event);
356
+ }
357
+ }
358
+ }
359
+ emit(event, data) {
360
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitting event", {
361
+ event,
362
+ listenerCount: this.eventListeners.get(event)?.size || 0,
363
+ data
364
+ });
365
+ const listeners = this.eventListeners.get(event);
366
+ if (listeners && listeners.size > 0) {
367
+ listeners.forEach((callback) => {
368
+ try {
369
+ callback(data);
370
+ } catch (error) {
371
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Event callback error", { event, error });
372
+ }
373
+ });
374
+ }
375
+ }
376
+ setupBrowserInjectedEvents() {
377
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
378
+ if (this.addressTypes.includes(import_client.AddressType.solana) && this.phantom.solana) {
379
+ this.setupSolanaEvents();
380
+ }
381
+ if (this.addressTypes.includes(import_client.AddressType.ethereum) && this.phantom.ethereum) {
382
+ this.setupEthereumEvents();
383
+ }
384
+ }
385
+ setupSolanaEvents() {
386
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
387
+ const solanaConnectCleanup = this.phantom.solana.addEventListener("connect", (publicKey) => {
388
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
389
+ const solanaAddress = { addressType: import_client.AddressType.solana, address: publicKey };
390
+ if (!this.addresses.find((addr) => addr.addressType === import_client.AddressType.solana)) {
391
+ this.addresses.push(solanaAddress);
392
+ }
393
+ this.connected = true;
394
+ this.emit("connect", {
395
+ addresses: this.addresses,
396
+ source: "injected-extension"
397
+ });
398
+ });
399
+ const solanaDisconnectCleanup = this.phantom.solana.addEventListener("disconnect", () => {
400
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
401
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client.AddressType.solana);
402
+ this.connected = this.addresses.length > 0;
403
+ this.emit("disconnect", {
404
+ source: "injected-extension"
405
+ });
406
+ });
407
+ const solanaAccountChangedCleanup = this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
408
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
409
+ const solanaIndex = this.addresses.findIndex((addr) => addr.addressType === import_client.AddressType.solana);
410
+ if (solanaIndex >= 0) {
411
+ this.addresses[solanaIndex] = { addressType: import_client.AddressType.solana, address: publicKey };
412
+ } else {
413
+ this.addresses.push({ addressType: import_client.AddressType.solana, address: publicKey });
414
+ }
415
+ this.emit("connect", {
416
+ addresses: this.addresses,
417
+ source: "injected-extension-account-change"
418
+ });
419
+ });
420
+ this.browserInjectedCleanupFunctions.push(
421
+ solanaConnectCleanup,
422
+ solanaDisconnectCleanup,
423
+ solanaAccountChangedCleanup
424
+ );
425
+ }
426
+ setupEthereumEvents() {
427
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
428
+ const ethConnectCleanup = this.phantom.ethereum.addEventListener("connect", (accounts) => {
429
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
430
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client.AddressType.ethereum);
431
+ if (accounts && accounts.length > 0) {
432
+ this.addresses.push(...accounts.map((address) => ({
433
+ addressType: import_client.AddressType.ethereum,
434
+ address
435
+ })));
436
+ }
437
+ this.connected = this.addresses.length > 0;
438
+ this.emit("connect", {
439
+ addresses: this.addresses,
440
+ source: "injected-extension"
441
+ });
442
+ });
443
+ const ethDisconnectCleanup = this.phantom.ethereum.addEventListener("disconnect", () => {
444
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
445
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client.AddressType.ethereum);
446
+ this.connected = this.addresses.length > 0;
447
+ this.emit("disconnect", {
448
+ source: "injected-extension"
449
+ });
450
+ });
451
+ const ethAccountChangedCleanup = this.phantom.ethereum.addEventListener("accountChanged", (accounts) => {
452
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum account changed event received", { accounts });
453
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client.AddressType.ethereum);
454
+ if (accounts && accounts.length > 0) {
455
+ this.addresses.push(...accounts.map((address) => ({
456
+ addressType: import_client.AddressType.ethereum,
457
+ address
458
+ })));
459
+ }
460
+ this.emit("connect", {
461
+ addresses: this.addresses,
462
+ source: "injected-extension-account-change"
463
+ });
464
+ });
465
+ this.browserInjectedCleanupFunctions.push(
466
+ ethConnectCleanup,
467
+ ethDisconnectCleanup,
468
+ ethAccountChangedCleanup
469
+ );
470
+ }
296
471
  };
297
472
 
298
473
  // src/providers/embedded/index.ts
@@ -662,11 +837,15 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
662
837
 
663
838
  // src/ProviderManager.ts
664
839
  var ProviderManager = class {
840
+ // Track which providers have forwarding set up
665
841
  constructor(config) {
666
842
  this.providers = /* @__PURE__ */ new Map();
667
843
  this.currentProvider = null;
668
844
  this.currentProviderKey = null;
669
845
  this.walletId = null;
846
+ // Event management for forwarding provider events
847
+ this.eventListeners = /* @__PURE__ */ new Map();
848
+ this.providerForwardingSetup = /* @__PURE__ */ new WeakSet();
670
849
  debug.log(DebugCategory.PROVIDER_MANAGER, "Initializing ProviderManager", { config });
671
850
  this.config = config;
672
851
  debug.log(DebugCategory.PROVIDER_MANAGER, "Setting default provider");
@@ -691,6 +870,7 @@ var ProviderManager = class {
691
870
  this.currentProvider = this.providers.get(key);
692
871
  this.currentProviderKey = key;
693
872
  this.walletId = null;
873
+ this.ensureProviderEventForwarding();
694
874
  return this.currentProvider;
695
875
  }
696
876
  /**
@@ -785,6 +965,79 @@ var ProviderManager = class {
785
965
  getWalletId() {
786
966
  return this.walletId;
787
967
  }
968
+ /**
969
+ * Add event listener - stores callback and ensures current provider forwards events to ProviderManager
970
+ */
971
+ on(event, callback) {
972
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Adding event listener", { event });
973
+ if (!this.eventListeners.has(event)) {
974
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
975
+ }
976
+ this.eventListeners.get(event).add(callback);
977
+ this.ensureProviderEventForwarding();
978
+ }
979
+ /**
980
+ * Remove event listener
981
+ */
982
+ off(event, callback) {
983
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
984
+ if (this.eventListeners.has(event)) {
985
+ this.eventListeners.get(event).delete(callback);
986
+ if (this.eventListeners.get(event).size === 0) {
987
+ this.eventListeners.delete(event);
988
+ }
989
+ }
990
+ }
991
+ /**
992
+ * Emit event to all registered callbacks
993
+ */
994
+ emit(event, data) {
995
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Emitting event to stored callbacks", {
996
+ event,
997
+ listenerCount: this.eventListeners.get(event)?.size || 0,
998
+ data
999
+ });
1000
+ const listeners = this.eventListeners.get(event);
1001
+ if (listeners && listeners.size > 0) {
1002
+ listeners.forEach((callback) => {
1003
+ try {
1004
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Calling stored callback for event", { event });
1005
+ callback(data);
1006
+ } catch (error) {
1007
+ debug.error(DebugCategory.PROVIDER_MANAGER, "Event callback error", { event, error });
1008
+ }
1009
+ });
1010
+ } else {
1011
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "No stored callbacks for event", { event });
1012
+ }
1013
+ }
1014
+ /**
1015
+ * Ensure current provider forwards its events to this ProviderManager
1016
+ * Only sets up forwarding once per provider instance to avoid accumulation
1017
+ */
1018
+ ensureProviderEventForwarding() {
1019
+ if (!this.currentProvider || !("on" in this.currentProvider)) {
1020
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Current provider does not support events", {
1021
+ providerType: this.getCurrentProviderInfo()?.type
1022
+ });
1023
+ return;
1024
+ }
1025
+ if (this.providerForwardingSetup.has(this.currentProvider)) {
1026
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Event forwarding already set up for current provider");
1027
+ return;
1028
+ }
1029
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Setting up event forwarding from current provider");
1030
+ const eventsToForward = ["connect_start", "connect", "connect_error", "disconnect", "error"];
1031
+ for (const event of eventsToForward) {
1032
+ const forwardingCallback = (data) => {
1033
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Forwarding event from provider", { event, data });
1034
+ this.emit(event, data);
1035
+ };
1036
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Attaching forwarding callback for event", { event });
1037
+ this.currentProvider.on(event, forwardingCallback);
1038
+ }
1039
+ this.providerForwardingSetup.add(this.currentProvider);
1040
+ }
788
1041
  /**
789
1042
  * Set default provider based on initial config
790
1043
  */
@@ -817,7 +1070,10 @@ var ProviderManager = class {
817
1070
  authOptions: this.config.authOptions,
818
1071
  embeddedWalletType: embeddedWalletType || "app-wallet",
819
1072
  addressTypes: this.config.addressTypes || [],
820
- solanaProvider: this.config.solanaProvider || "web3js"
1073
+ solanaProvider: this.config.solanaProvider || "web3js",
1074
+ appLogo: this.config.appLogo,
1075
+ // Optional app logo URL
1076
+ appName: this.config.appName
821
1077
  });
822
1078
  }
823
1079
  this.providers.set(key, provider);
@@ -1035,6 +1291,38 @@ var BrowserSDK = class {
1035
1291
  getWalletId() {
1036
1292
  return this.providerManager.getWalletId();
1037
1293
  }
1294
+ /**
1295
+ * Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
1296
+ * Works with both embedded and injected providers
1297
+ */
1298
+ on(event, callback) {
1299
+ debug.log(DebugCategory.BROWSER_SDK, "Adding event listener", { event });
1300
+ this.providerManager.on(event, callback);
1301
+ }
1302
+ /**
1303
+ * Remove event listener for provider events
1304
+ * Works with both embedded and injected providers
1305
+ */
1306
+ off(event, callback) {
1307
+ debug.log(DebugCategory.BROWSER_SDK, "Removing event listener", { event });
1308
+ this.providerManager.off(event, callback);
1309
+ }
1310
+ /**
1311
+ * Attempt auto-connection using existing session
1312
+ * Should be called after setting up event listeners
1313
+ * Only works with embedded providers
1314
+ */
1315
+ async autoConnect() {
1316
+ debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
1317
+ const currentProvider = this.providerManager.getCurrentProvider();
1318
+ if (currentProvider && "autoConnect" in currentProvider) {
1319
+ await currentProvider.autoConnect();
1320
+ } else {
1321
+ debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
1322
+ providerType: this.getCurrentProviderInfo()?.type
1323
+ });
1324
+ }
1325
+ }
1038
1326
  };
1039
1327
 
1040
1328
  // src/index.ts
package/dist/index.mjs CHANGED
@@ -86,6 +86,10 @@ var InjectedProvider = class {
86
86
  constructor(config) {
87
87
  this.connected = false;
88
88
  this.addresses = [];
89
+ // Event management
90
+ this.eventListeners = /* @__PURE__ */ new Map();
91
+ this.browserInjectedCleanupFunctions = [];
92
+ this.eventsInitialized = false;
89
93
  debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
90
94
  this.addressTypes = config.addressTypes || [AddressType.solana, AddressType.ethereum];
91
95
  debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
@@ -110,70 +114,108 @@ var InjectedProvider = class {
110
114
  authOptionsIgnored: !!authOptions
111
115
  // Note: authOptions are ignored for injected provider
112
116
  });
113
- if (!this.phantom.extension.isInstalled()) {
114
- debug.error(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found");
115
- throw new Error("Phantom wallet not found");
116
- }
117
- debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
118
- const connectedAddresses = [];
119
- if (this.addressTypes.includes(AddressType.solana)) {
120
- debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
121
- try {
122
- const publicKey = await this.phantom.solana.connect();
123
- if (publicKey) {
124
- connectedAddresses.push({
125
- addressType: AddressType.solana,
126
- address: publicKey
127
- });
128
- debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
117
+ this.emit("connect_start", {
118
+ source: "manual-connect",
119
+ providerType: "injected"
120
+ });
121
+ try {
122
+ if (!this.phantom.extension.isInstalled()) {
123
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found");
124
+ const error = new Error("Phantom wallet not found");
125
+ this.emit("connect_error", {
126
+ error: error.message,
127
+ source: "manual-connect"
128
+ });
129
+ throw error;
130
+ }
131
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
132
+ const connectedAddresses = [];
133
+ if (this.addressTypes.includes(AddressType.solana)) {
134
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
135
+ try {
136
+ const publicKey = await this.phantom.solana.connect();
137
+ if (publicKey) {
138
+ connectedAddresses.push({
139
+ addressType: AddressType.solana,
140
+ address: publicKey
141
+ });
142
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
143
+ }
144
+ } catch (err) {
145
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
129
146
  }
130
- } catch (err) {
131
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
132
147
  }
133
- }
134
- if (this.addressTypes.includes(AddressType.ethereum)) {
135
- try {
136
- const accounts = await this.phantom.ethereum.connect();
137
- if (accounts && accounts.length > 0) {
138
- connectedAddresses.push(
139
- ...accounts.map((address) => ({
140
- addressType: AddressType.ethereum,
141
- address
142
- }))
143
- );
148
+ if (this.addressTypes.includes(AddressType.ethereum)) {
149
+ try {
150
+ const accounts = await this.phantom.ethereum.connect();
151
+ if (accounts && accounts.length > 0) {
152
+ connectedAddresses.push(
153
+ ...accounts.map((address) => ({
154
+ addressType: AddressType.ethereum,
155
+ address
156
+ }))
157
+ );
158
+ }
159
+ } catch (err) {
160
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
144
161
  }
145
- } catch (err) {
146
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
147
162
  }
163
+ if (connectedAddresses.length === 0) {
164
+ const error = new Error("Failed to connect to any supported wallet provider");
165
+ this.emit("connect_error", {
166
+ error: error.message,
167
+ source: "manual-connect"
168
+ });
169
+ throw error;
170
+ }
171
+ this.addresses = connectedAddresses;
172
+ this.connected = true;
173
+ const result = {
174
+ addresses: this.addresses,
175
+ status: "completed"
176
+ // walletId is not applicable for injected providers
177
+ };
178
+ this.emit("connect", {
179
+ addresses: this.addresses,
180
+ source: "manual-connect"
181
+ });
182
+ return result;
183
+ } catch (error) {
184
+ if (error instanceof Error && !error.message.includes("Phantom wallet not found") && !error.message.includes("Failed to connect to any supported wallet provider")) {
185
+ this.emit("connect_error", {
186
+ error: error.message,
187
+ source: "manual-connect"
188
+ });
189
+ }
190
+ throw error;
148
191
  }
149
- if (connectedAddresses.length === 0) {
150
- throw new Error("Failed to connect to any supported wallet provider");
151
- }
152
- this.addresses = connectedAddresses;
153
- this.connected = true;
154
- return {
155
- addresses: this.addresses,
156
- status: "completed"
157
- // walletId is not applicable for injected providers
158
- };
159
192
  }
160
193
  async disconnect() {
194
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
161
195
  if (this.addressTypes.includes(AddressType.solana)) {
162
196
  try {
163
197
  await this.phantom.solana.disconnect();
198
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
164
199
  } catch (err) {
165
- console.error("Failed to disconnect Solana:", err);
200
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
166
201
  }
167
202
  }
168
203
  if (this.addressTypes.includes(AddressType.ethereum)) {
169
204
  try {
170
205
  await this.phantom.ethereum.disconnect();
206
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
171
207
  } catch (err) {
172
- console.error("Failed to disconnect Ethereum:", err);
208
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Ethereum", { error: err });
173
209
  }
174
210
  }
211
+ this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
212
+ this.browserInjectedCleanupFunctions = [];
175
213
  this.connected = false;
176
214
  this.addresses = [];
215
+ this.emit("disconnect", {
216
+ source: "manual-disconnect"
217
+ });
218
+ debug.info(DebugCategory.INJECTED_PROVIDER, "Injected provider disconnected successfully");
177
219
  }
178
220
  async signMessage(params) {
179
221
  if (!this.connected) {
@@ -246,6 +288,139 @@ var InjectedProvider = class {
246
288
  isConnected() {
247
289
  return this.connected;
248
290
  }
291
+ // Event management methods - implementing unified event interface
292
+ on(event, callback) {
293
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Adding event listener", { event });
294
+ if (!this.eventsInitialized) {
295
+ this.setupBrowserInjectedEvents();
296
+ this.eventsInitialized = true;
297
+ }
298
+ if (!this.eventListeners.has(event)) {
299
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
300
+ }
301
+ this.eventListeners.get(event).add(callback);
302
+ }
303
+ off(event, callback) {
304
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Removing event listener", { event });
305
+ if (this.eventListeners.has(event)) {
306
+ this.eventListeners.get(event).delete(callback);
307
+ if (this.eventListeners.get(event).size === 0) {
308
+ this.eventListeners.delete(event);
309
+ }
310
+ }
311
+ }
312
+ emit(event, data) {
313
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Emitting event", {
314
+ event,
315
+ listenerCount: this.eventListeners.get(event)?.size || 0,
316
+ data
317
+ });
318
+ const listeners = this.eventListeners.get(event);
319
+ if (listeners && listeners.size > 0) {
320
+ listeners.forEach((callback) => {
321
+ try {
322
+ callback(data);
323
+ } catch (error) {
324
+ debug.error(DebugCategory.INJECTED_PROVIDER, "Event callback error", { event, error });
325
+ }
326
+ });
327
+ }
328
+ }
329
+ setupBrowserInjectedEvents() {
330
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
331
+ if (this.addressTypes.includes(AddressType.solana) && this.phantom.solana) {
332
+ this.setupSolanaEvents();
333
+ }
334
+ if (this.addressTypes.includes(AddressType.ethereum) && this.phantom.ethereum) {
335
+ this.setupEthereumEvents();
336
+ }
337
+ }
338
+ setupSolanaEvents() {
339
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
340
+ const solanaConnectCleanup = this.phantom.solana.addEventListener("connect", (publicKey) => {
341
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
342
+ const solanaAddress = { addressType: AddressType.solana, address: publicKey };
343
+ if (!this.addresses.find((addr) => addr.addressType === AddressType.solana)) {
344
+ this.addresses.push(solanaAddress);
345
+ }
346
+ this.connected = true;
347
+ this.emit("connect", {
348
+ addresses: this.addresses,
349
+ source: "injected-extension"
350
+ });
351
+ });
352
+ const solanaDisconnectCleanup = this.phantom.solana.addEventListener("disconnect", () => {
353
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
354
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType.solana);
355
+ this.connected = this.addresses.length > 0;
356
+ this.emit("disconnect", {
357
+ source: "injected-extension"
358
+ });
359
+ });
360
+ const solanaAccountChangedCleanup = this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
361
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
362
+ const solanaIndex = this.addresses.findIndex((addr) => addr.addressType === AddressType.solana);
363
+ if (solanaIndex >= 0) {
364
+ this.addresses[solanaIndex] = { addressType: AddressType.solana, address: publicKey };
365
+ } else {
366
+ this.addresses.push({ addressType: AddressType.solana, address: publicKey });
367
+ }
368
+ this.emit("connect", {
369
+ addresses: this.addresses,
370
+ source: "injected-extension-account-change"
371
+ });
372
+ });
373
+ this.browserInjectedCleanupFunctions.push(
374
+ solanaConnectCleanup,
375
+ solanaDisconnectCleanup,
376
+ solanaAccountChangedCleanup
377
+ );
378
+ }
379
+ setupEthereumEvents() {
380
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
381
+ const ethConnectCleanup = this.phantom.ethereum.addEventListener("connect", (accounts) => {
382
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
383
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType.ethereum);
384
+ if (accounts && accounts.length > 0) {
385
+ this.addresses.push(...accounts.map((address) => ({
386
+ addressType: AddressType.ethereum,
387
+ address
388
+ })));
389
+ }
390
+ this.connected = this.addresses.length > 0;
391
+ this.emit("connect", {
392
+ addresses: this.addresses,
393
+ source: "injected-extension"
394
+ });
395
+ });
396
+ const ethDisconnectCleanup = this.phantom.ethereum.addEventListener("disconnect", () => {
397
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
398
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType.ethereum);
399
+ this.connected = this.addresses.length > 0;
400
+ this.emit("disconnect", {
401
+ source: "injected-extension"
402
+ });
403
+ });
404
+ const ethAccountChangedCleanup = this.phantom.ethereum.addEventListener("accountChanged", (accounts) => {
405
+ debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum account changed event received", { accounts });
406
+ this.addresses = this.addresses.filter((addr) => addr.addressType !== AddressType.ethereum);
407
+ if (accounts && accounts.length > 0) {
408
+ this.addresses.push(...accounts.map((address) => ({
409
+ addressType: AddressType.ethereum,
410
+ address
411
+ })));
412
+ }
413
+ this.emit("connect", {
414
+ addresses: this.addresses,
415
+ source: "injected-extension-account-change"
416
+ });
417
+ });
418
+ this.browserInjectedCleanupFunctions.push(
419
+ ethConnectCleanup,
420
+ ethDisconnectCleanup,
421
+ ethAccountChangedCleanup
422
+ );
423
+ }
249
424
  };
250
425
 
251
426
  // src/providers/embedded/index.ts
@@ -615,11 +790,15 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
615
790
 
616
791
  // src/ProviderManager.ts
617
792
  var ProviderManager = class {
793
+ // Track which providers have forwarding set up
618
794
  constructor(config) {
619
795
  this.providers = /* @__PURE__ */ new Map();
620
796
  this.currentProvider = null;
621
797
  this.currentProviderKey = null;
622
798
  this.walletId = null;
799
+ // Event management for forwarding provider events
800
+ this.eventListeners = /* @__PURE__ */ new Map();
801
+ this.providerForwardingSetup = /* @__PURE__ */ new WeakSet();
623
802
  debug.log(DebugCategory.PROVIDER_MANAGER, "Initializing ProviderManager", { config });
624
803
  this.config = config;
625
804
  debug.log(DebugCategory.PROVIDER_MANAGER, "Setting default provider");
@@ -644,6 +823,7 @@ var ProviderManager = class {
644
823
  this.currentProvider = this.providers.get(key);
645
824
  this.currentProviderKey = key;
646
825
  this.walletId = null;
826
+ this.ensureProviderEventForwarding();
647
827
  return this.currentProvider;
648
828
  }
649
829
  /**
@@ -738,6 +918,79 @@ var ProviderManager = class {
738
918
  getWalletId() {
739
919
  return this.walletId;
740
920
  }
921
+ /**
922
+ * Add event listener - stores callback and ensures current provider forwards events to ProviderManager
923
+ */
924
+ on(event, callback) {
925
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Adding event listener", { event });
926
+ if (!this.eventListeners.has(event)) {
927
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
928
+ }
929
+ this.eventListeners.get(event).add(callback);
930
+ this.ensureProviderEventForwarding();
931
+ }
932
+ /**
933
+ * Remove event listener
934
+ */
935
+ off(event, callback) {
936
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Removing event listener", { event });
937
+ if (this.eventListeners.has(event)) {
938
+ this.eventListeners.get(event).delete(callback);
939
+ if (this.eventListeners.get(event).size === 0) {
940
+ this.eventListeners.delete(event);
941
+ }
942
+ }
943
+ }
944
+ /**
945
+ * Emit event to all registered callbacks
946
+ */
947
+ emit(event, data) {
948
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Emitting event to stored callbacks", {
949
+ event,
950
+ listenerCount: this.eventListeners.get(event)?.size || 0,
951
+ data
952
+ });
953
+ const listeners = this.eventListeners.get(event);
954
+ if (listeners && listeners.size > 0) {
955
+ listeners.forEach((callback) => {
956
+ try {
957
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Calling stored callback for event", { event });
958
+ callback(data);
959
+ } catch (error) {
960
+ debug.error(DebugCategory.PROVIDER_MANAGER, "Event callback error", { event, error });
961
+ }
962
+ });
963
+ } else {
964
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "No stored callbacks for event", { event });
965
+ }
966
+ }
967
+ /**
968
+ * Ensure current provider forwards its events to this ProviderManager
969
+ * Only sets up forwarding once per provider instance to avoid accumulation
970
+ */
971
+ ensureProviderEventForwarding() {
972
+ if (!this.currentProvider || !("on" in this.currentProvider)) {
973
+ debug.warn(DebugCategory.PROVIDER_MANAGER, "Current provider does not support events", {
974
+ providerType: this.getCurrentProviderInfo()?.type
975
+ });
976
+ return;
977
+ }
978
+ if (this.providerForwardingSetup.has(this.currentProvider)) {
979
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Event forwarding already set up for current provider");
980
+ return;
981
+ }
982
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Setting up event forwarding from current provider");
983
+ const eventsToForward = ["connect_start", "connect", "connect_error", "disconnect", "error"];
984
+ for (const event of eventsToForward) {
985
+ const forwardingCallback = (data) => {
986
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Forwarding event from provider", { event, data });
987
+ this.emit(event, data);
988
+ };
989
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Attaching forwarding callback for event", { event });
990
+ this.currentProvider.on(event, forwardingCallback);
991
+ }
992
+ this.providerForwardingSetup.add(this.currentProvider);
993
+ }
741
994
  /**
742
995
  * Set default provider based on initial config
743
996
  */
@@ -770,7 +1023,10 @@ var ProviderManager = class {
770
1023
  authOptions: this.config.authOptions,
771
1024
  embeddedWalletType: embeddedWalletType || "app-wallet",
772
1025
  addressTypes: this.config.addressTypes || [],
773
- solanaProvider: this.config.solanaProvider || "web3js"
1026
+ solanaProvider: this.config.solanaProvider || "web3js",
1027
+ appLogo: this.config.appLogo,
1028
+ // Optional app logo URL
1029
+ appName: this.config.appName
774
1030
  });
775
1031
  }
776
1032
  this.providers.set(key, provider);
@@ -988,6 +1244,38 @@ var BrowserSDK = class {
988
1244
  getWalletId() {
989
1245
  return this.providerManager.getWalletId();
990
1246
  }
1247
+ /**
1248
+ * Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
1249
+ * Works with both embedded and injected providers
1250
+ */
1251
+ on(event, callback) {
1252
+ debug.log(DebugCategory.BROWSER_SDK, "Adding event listener", { event });
1253
+ this.providerManager.on(event, callback);
1254
+ }
1255
+ /**
1256
+ * Remove event listener for provider events
1257
+ * Works with both embedded and injected providers
1258
+ */
1259
+ off(event, callback) {
1260
+ debug.log(DebugCategory.BROWSER_SDK, "Removing event listener", { event });
1261
+ this.providerManager.off(event, callback);
1262
+ }
1263
+ /**
1264
+ * Attempt auto-connection using existing session
1265
+ * Should be called after setting up event listeners
1266
+ * Only works with embedded providers
1267
+ */
1268
+ async autoConnect() {
1269
+ debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
1270
+ const currentProvider = this.providerManager.getCurrentProvider();
1271
+ if (currentProvider && "autoConnect" in currentProvider) {
1272
+ await currentProvider.autoConnect();
1273
+ } else {
1274
+ debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
1275
+ providerType: this.getCurrentProviderInfo()?.type
1276
+ });
1277
+ }
1278
+ }
991
1279
  };
992
1280
 
993
1281
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/browser-sdk",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Browser SDK for Phantom Wallet with unified interface",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -30,11 +30,11 @@
30
30
  "dependencies": {
31
31
  "@phantom/base64url": "^0.1.0",
32
32
  "@phantom/browser-injected-sdk": "^0.0.9",
33
- "@phantom/client": "^0.1.7",
34
- "@phantom/constants": "^0.0.2",
35
- "@phantom/embedded-provider-core": "^0.1.4",
36
- "@phantom/indexed-db-stamper": "^0.1.3",
37
- "@phantom/parsers": "^0.0.6",
33
+ "@phantom/client": "^0.1.8",
34
+ "@phantom/constants": "^0.0.3",
35
+ "@phantom/embedded-provider-core": "^0.1.6",
36
+ "@phantom/indexed-db-stamper": "^0.1.4",
37
+ "@phantom/parsers": "^0.0.7",
38
38
  "axios": "^1.10.0",
39
39
  "bs58": "^6.0.0",
40
40
  "buffer": "^6.0.3",