@formo/analytics 1.19.7 → 1.19.8

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.
@@ -22,6 +22,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
22
22
  */
23
23
  private _trackedProviders;
24
24
  private _injectedProviderDetail?;
25
+ private _processingAccountsChanged;
25
26
  private _seenProviders;
26
27
  config: Config;
27
28
  currentChainId?: ChainID;
@@ -181,6 +182,17 @@ export declare class FormoAnalytics implements IFormoAnalytics {
181
182
  private addProviderListener;
182
183
  private registerAccountsChangedListener;
183
184
  private onAccountsChanged;
185
+ /**
186
+ * Handles changes to the accounts of a given EIP-1193 provider.
187
+ *
188
+ * @param provider - The EIP-1193 provider whose accounts have changed.
189
+ * @param accounts - The new array of account addresses. An empty array indicates a disconnect.
190
+ * @returns A promise that resolves when the account change has been processed.
191
+ *
192
+ * If the accounts array is empty and the provider is the active provider, this method triggers
193
+ * a disconnect flow. Otherwise, it updates the state to reflect the new accounts as needed.
194
+ */
195
+ private _handleAccountsChanged;
184
196
  private registerChainChangedListener;
185
197
  private onChainChanged;
186
198
  private registerConnectListener;
@@ -65,6 +65,14 @@ var utils_1 = require("./utils");
65
65
  var address_1 = require("./utils/address");
66
66
  var validators_1 = require("./validators");
67
67
  var chain_1 = require("./utils/chain");
68
+ /**
69
+ * Constants for provider switching reasons
70
+ */
71
+ var PROVIDER_SWITCH_REASONS = {
72
+ ADDRESS_MISMATCH: "Address mismatch indicates wallet switch",
73
+ NO_ACCOUNTS: "Current provider has no accounts",
74
+ CHECK_FAILED: "Could not check current provider accounts"
75
+ };
68
76
  var FormoAnalytics = /** @class */ (function () {
69
77
  function FormoAnalytics(writeKey, options) {
70
78
  if (options === void 0) { options = {}; }
@@ -86,6 +94,8 @@ var FormoAnalytics = /** @class */ (function () {
86
94
  * - A provider can be tracked but later removed from discovery
87
95
  */
88
96
  this._trackedProviders = new Set();
97
+ // Flag to prevent concurrent processing of accountsChanged events
98
+ this._processingAccountsChanged = false;
89
99
  // Set to efficiently track seen providers for deduplication and O(1) lookup
90
100
  this._seenProviders = new Set();
91
101
  this.currentUserId = "";
@@ -285,7 +295,8 @@ var FormoAnalytics = /** @class */ (function () {
285
295
  _a.sent();
286
296
  this.currentAddress = undefined;
287
297
  this.currentChainId = undefined;
288
- lib_1.logger.info("Wallet disconnected: Cleared currentAddress and currentChainId");
298
+ this._provider = undefined;
299
+ lib_1.logger.info("Wallet disconnected: Cleared currentAddress, currentChainId, and provider");
289
300
  return [2 /*return*/];
290
301
  }
291
302
  });
@@ -583,12 +594,49 @@ var FormoAnalytics = /** @class */ (function () {
583
594
  };
584
595
  FormoAnalytics.prototype.onAccountsChanged = function (provider, accounts) {
585
596
  return __awaiter(this, void 0, void 0, function () {
586
- var error_1, address, nextChainId, wasDisconnected, isProviderSwitch, hadPreviousConnection, error_2, providerInfo, effectiveChainId;
587
- var _a, _b, _c;
588
- return __generator(this, function (_d) {
589
- switch (_d.label) {
597
+ return __generator(this, function (_a) {
598
+ switch (_a.label) {
590
599
  case 0:
591
600
  lib_1.logger.info("onAccountsChanged", accounts);
601
+ // Prevent concurrent processing of accountsChanged events to avoid race conditions
602
+ if (this._processingAccountsChanged) {
603
+ lib_1.logger.debug("OnAccountsChanged: Already processing accountsChanged, skipping", {
604
+ provider: this.getProviderInfo(provider).name
605
+ });
606
+ return [2 /*return*/];
607
+ }
608
+ this._processingAccountsChanged = true;
609
+ _a.label = 1;
610
+ case 1:
611
+ _a.trys.push([1, , 3, 4]);
612
+ return [4 /*yield*/, this._handleAccountsChanged(provider, accounts)];
613
+ case 2:
614
+ _a.sent();
615
+ return [3 /*break*/, 4];
616
+ case 3:
617
+ this._processingAccountsChanged = false;
618
+ return [7 /*endfinally*/];
619
+ case 4: return [2 /*return*/];
620
+ }
621
+ });
622
+ });
623
+ };
624
+ /**
625
+ * Handles changes to the accounts of a given EIP-1193 provider.
626
+ *
627
+ * @param provider - The EIP-1193 provider whose accounts have changed.
628
+ * @param accounts - The new array of account addresses. An empty array indicates a disconnect.
629
+ * @returns A promise that resolves when the account change has been processed.
630
+ *
631
+ * If the accounts array is empty and the provider is the active provider, this method triggers
632
+ * a disconnect flow. Otherwise, it updates the state to reflect the new accounts as needed.
633
+ */
634
+ FormoAnalytics.prototype._handleAccountsChanged = function (provider, accounts) {
635
+ return __awaiter(this, void 0, void 0, function () {
636
+ var error_1, address, currentStoredAddress, newProviderAddress, activeProviderAccounts, error_2, nextChainId, wasDisconnected, providerInfo, effectiveChainId;
637
+ return __generator(this, function (_a) {
638
+ switch (_a.label) {
639
+ case 0:
592
640
  if (!(accounts.length === 0)) return [3 /*break*/, 7];
593
641
  if (!(this._provider === provider)) return [3 /*break*/, 5];
594
642
  lib_1.logger.info("OnAccountsChanged: Detecting disconnect, current state:", {
@@ -596,9 +644,9 @@ var FormoAnalytics = /** @class */ (function () {
596
644
  currentChainId: this.currentChainId,
597
645
  providerMatch: this._provider === provider
598
646
  });
599
- _d.label = 1;
647
+ _a.label = 1;
600
648
  case 1:
601
- _d.trys.push([1, 3, , 4]);
649
+ _a.trys.push([1, 3, , 4]);
602
650
  // Pass current state explicitly to ensure we have the data for the disconnect event
603
651
  return [4 /*yield*/, this.disconnect({
604
652
  chainId: this.currentChainId,
@@ -606,16 +654,16 @@ var FormoAnalytics = /** @class */ (function () {
606
654
  })];
607
655
  case 2:
608
656
  // Pass current state explicitly to ensure we have the data for the disconnect event
609
- _d.sent();
657
+ _a.sent();
610
658
  return [3 /*break*/, 4];
611
659
  case 3:
612
- error_1 = _d.sent();
660
+ error_1 = _a.sent();
613
661
  lib_1.logger.error("Failed to disconnect provider on accountsChanged", error_1);
614
662
  return [3 /*break*/, 4];
615
663
  case 4: return [3 /*break*/, 6];
616
664
  case 5:
617
665
  lib_1.logger.info("OnAccountsChanged: Ignoring disconnect for non-active provider");
618
- _d.label = 6;
666
+ _a.label = 6;
619
667
  case 6: return [2 /*return*/];
620
668
  case 7:
621
669
  address = this.validateAndChecksumAddress(accounts[0]);
@@ -623,54 +671,106 @@ var FormoAnalytics = /** @class */ (function () {
623
671
  lib_1.logger.warn("onAccountsChanged: Invalid address received", accounts[0]);
624
672
  return [2 /*return*/];
625
673
  }
626
- // If both the provider and address are the same, no-op. Allow provider switches even if address is the same.
627
- if (this._provider === provider && address === this.currentAddress) {
628
- return [2 /*return*/];
629
- }
630
- return [4 /*yield*/, this.getCurrentChainId(provider)];
631
- case 8:
632
- nextChainId = _d.sent();
633
- wasDisconnected = !this.currentAddress;
634
- isProviderSwitch = this._provider && this._provider !== provider;
635
- lib_1.logger.info("OnAccountsChanged: Provider switching analysis:", {
636
- currentProvider: ((_b = (_a = this._provider) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name) || 'none',
637
- newProvider: ((_c = provider === null || provider === void 0 ? void 0 : provider.constructor) === null || _c === void 0 ? void 0 : _c.name) || 'unknown',
638
- currentAddress: this.currentAddress,
639
- wasDisconnected: wasDisconnected,
640
- isProviderMismatch: isProviderSwitch
674
+ if (!(this._provider && this._provider !== provider)) return [3 /*break*/, 18];
675
+ currentStoredAddress = this.currentAddress;
676
+ newProviderAddress = this.validateAndChecksumAddress(address);
677
+ lib_1.logger.info("OnAccountsChanged: Different provider attempting to connect", {
678
+ activeProvider: this.getProviderInfo(this._provider).name,
679
+ eventProvider: this.getProviderInfo(provider).name,
680
+ currentStoredAddress: currentStoredAddress,
681
+ newProviderAddress: newProviderAddress
641
682
  });
642
- if (!isProviderSwitch) return [3 /*break*/, 13];
643
- hadPreviousConnection = !!this.currentAddress;
644
- if (!hadPreviousConnection) return [3 /*break*/, 12];
645
- lib_1.logger.info("OnAccountsChanged: Detected provider switch with existing connection - emitting disconnect for previous provider");
646
- _d.label = 9;
683
+ _a.label = 8;
684
+ case 8:
685
+ _a.trys.push([8, 16, , 18]);
686
+ return [4 /*yield*/, this.getAccounts(this._provider)];
647
687
  case 9:
648
- _d.trys.push([9, 11, , 12]);
688
+ activeProviderAccounts = _a.sent();
689
+ lib_1.logger.info("OnAccountsChanged: Checking current provider accounts", {
690
+ activeProvider: this.getProviderInfo(this._provider).name,
691
+ accountsLength: activeProviderAccounts ? activeProviderAccounts.length : 0,
692
+ accounts: activeProviderAccounts
693
+ });
694
+ if (!(activeProviderAccounts && activeProviderAccounts.length > 0)) return [3 /*break*/, 13];
695
+ if (!(newProviderAddress && currentStoredAddress && newProviderAddress !== currentStoredAddress)) return [3 /*break*/, 11];
696
+ lib_1.logger.info("OnAccountsChanged: Different address detected, switching providers despite current provider having accounts", {
697
+ activeProvider: this.getProviderInfo(this._provider).name,
698
+ eventProvider: this.getProviderInfo(provider).name,
699
+ currentAddress: currentStoredAddress,
700
+ newAddress: newProviderAddress,
701
+ reason: PROVIDER_SWITCH_REASONS.ADDRESS_MISMATCH
702
+ });
703
+ // Emit disconnect for the old provider
649
704
  return [4 /*yield*/, this.disconnect({
650
705
  chainId: this.currentChainId,
651
706
  address: this.currentAddress
652
707
  })];
653
708
  case 10:
654
- _d.sent();
709
+ // Emit disconnect for the old provider
710
+ _a.sent();
711
+ // Clear state and let the new provider become active
712
+ this._provider = undefined;
655
713
  return [3 /*break*/, 12];
656
714
  case 11:
657
- error_2 = _d.sent();
658
- lib_1.logger.error("Failed to emit disconnect during provider switch:", error_2);
659
- return [3 /*break*/, 12];
660
- case 12:
661
- // Validate that the new provider is in a valid state before switching
662
- if (this.isProviderInValidState(provider)) {
663
- lib_1.logger.info("OnAccountsChanged: Handling provider mismatch - switching providers");
664
- this.handleProviderMismatch(provider);
715
+ lib_1.logger.info("OnAccountsChanged: Current provider still has accounts and same address, ignoring new provider", {
716
+ activeProvider: this.getProviderInfo(this._provider).name,
717
+ eventProvider: this.getProviderInfo(provider).name,
718
+ activeProviderAccountsCount: activeProviderAccounts.length,
719
+ currentAddress: currentStoredAddress,
720
+ newAddress: newProviderAddress
721
+ });
722
+ return [2 /*return*/];
723
+ case 12: return [3 /*break*/, 15];
724
+ case 13:
725
+ lib_1.logger.info("OnAccountsChanged: Current provider has no accounts, switching to new provider", {
726
+ oldProvider: this.getProviderInfo(this._provider).name,
727
+ newProvider: this.getProviderInfo(provider).name,
728
+ reason: PROVIDER_SWITCH_REASONS.NO_ACCOUNTS
729
+ });
730
+ // Emit disconnect for the old provider that didn't signal properly
731
+ return [4 /*yield*/, this.disconnect({
732
+ chainId: this.currentChainId,
733
+ address: this.currentAddress
734
+ })];
735
+ case 14:
736
+ // Emit disconnect for the old provider that didn't signal properly
737
+ _a.sent();
738
+ // Clear state and let the new provider become active
739
+ this._provider = undefined;
740
+ _a.label = 15;
741
+ case 15: return [3 /*break*/, 18];
742
+ case 16:
743
+ error_2 = _a.sent();
744
+ lib_1.logger.warn("OnAccountsChanged: Could not check current provider accounts, switching to new provider", {
745
+ error: error_2 instanceof Error ? error_2.message : String(error_2),
746
+ errorType: error_2 instanceof Error ? error_2.constructor.name : typeof error_2,
747
+ oldProvider: this._provider ? this.getProviderInfo(this._provider).name : 'unknown',
748
+ newProvider: this.getProviderInfo(provider).name,
749
+ reason: PROVIDER_SWITCH_REASONS.CHECK_FAILED
750
+ });
751
+ // If we can't check the current provider, assume it's disconnected
752
+ return [4 /*yield*/, this.disconnect({
753
+ chainId: this.currentChainId,
754
+ address: this.currentAddress
755
+ })];
756
+ case 17:
757
+ // If we can't check the current provider, assume it's disconnected
758
+ _a.sent();
759
+ this._provider = undefined;
760
+ return [3 /*break*/, 18];
761
+ case 18:
762
+ // Set provider if none exists (first connection)
763
+ if (!this._provider) {
764
+ this._provider = provider;
665
765
  }
666
- else {
667
- lib_1.logger.warn("Provider switching blocked: new provider is not in a valid state");
766
+ // If both the provider and address are the same, no-op
767
+ if (this._provider === provider && address === this.currentAddress) {
668
768
  return [2 /*return*/];
669
769
  }
670
- _d.label = 13;
671
- case 13:
672
- // Commit new active provider and state
673
- this._provider = provider;
770
+ return [4 /*yield*/, this.getCurrentChainId(provider)];
771
+ case 19:
772
+ nextChainId = _a.sent();
773
+ wasDisconnected = !this.currentAddress;
674
774
  this.currentAddress = address;
675
775
  this.currentChainId = nextChainId;
676
776
  providerInfo = this.getProviderInfo(provider);
@@ -678,7 +778,6 @@ var FormoAnalytics = /** @class */ (function () {
678
778
  chainId: nextChainId,
679
779
  address: address,
680
780
  wasDisconnected: wasDisconnected,
681
- isProviderSwitch: isProviderSwitch,
682
781
  providerName: providerInfo.name,
683
782
  rdns: providerInfo.rdns,
684
783
  hasChainId: !!nextChainId
@@ -801,7 +900,7 @@ var FormoAnalytics = /** @class */ (function () {
801
900
  };
802
901
  FormoAnalytics.prototype.onConnected = function (provider, connection) {
803
902
  return __awaiter(this, void 0, void 0, function () {
804
- var chainId, address, wasDisconnected, providerInfo, effectiveChainId, e_3;
903
+ var chainId, address, wasDisconnected, isActiveProvider, providerInfo, effectiveChainId, providerInfo, e_3;
805
904
  return __generator(this, function (_a) {
806
905
  switch (_a.label) {
807
906
  case 0:
@@ -821,17 +920,21 @@ var FormoAnalytics = /** @class */ (function () {
821
920
  if (!this._provider) {
822
921
  this._provider = provider;
823
922
  }
824
- this.currentChainId = chainId;
825
- this.currentAddress = this.validateAndChecksumAddress(address) || undefined;
826
- // Always emit connect event for better analytics capture
827
- if (this.currentAddress) {
923
+ isActiveProvider = this._provider === provider;
924
+ // Only update global state (chainId/address) from the active provider
925
+ if (isActiveProvider) {
926
+ this.currentChainId = chainId;
927
+ this.currentAddress = this.validateAndChecksumAddress(address) || undefined;
928
+ }
929
+ if (isActiveProvider && this.currentAddress) {
828
930
  providerInfo = this.getProviderInfo(provider);
829
931
  lib_1.logger.info("OnConnected: Detected wallet connection, emitting connect event", {
830
932
  chainId: chainId,
831
933
  wasDisconnected: wasDisconnected,
832
934
  providerName: providerInfo.name,
833
935
  rdns: providerInfo.rdns,
834
- hasChainId: !!chainId
936
+ hasChainId: !!chainId,
937
+ isActiveProvider: isActiveProvider
835
938
  });
836
939
  effectiveChainId = chainId || 0;
837
940
  if (effectiveChainId === 0) {
@@ -847,6 +950,16 @@ var FormoAnalytics = /** @class */ (function () {
847
950
  lib_1.logger.error("Failed to track connect event during provider connection:", error);
848
951
  });
849
952
  }
953
+ else if (address && !isActiveProvider) {
954
+ providerInfo = this.getProviderInfo(provider);
955
+ lib_1.logger.debug("OnConnected: Skipping connect event for non-active provider", {
956
+ chainId: chainId,
957
+ providerName: providerInfo.name,
958
+ rdns: providerInfo.rdns,
959
+ isActiveProvider: isActiveProvider,
960
+ activeProviderInfo: this._provider ? this.getProviderInfo(this._provider) : null
961
+ });
962
+ }
850
963
  }
851
964
  return [3 /*break*/, 4];
852
965
  case 3:
@@ -1,2 +1,2 @@
1
- export declare const version = "1.19.5";
1
+ export declare const version = "1.19.7";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // Generated by genversion.
5
- exports.version = '1.19.5';
5
+ exports.version = '1.19.7';
6
6
  //# sourceMappingURL=version.js.map
@@ -2,7 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getActionDescriptor = void 0;
4
4
  var getActionDescriptor = function (type, properties) {
5
- return "".concat(type).concat((properties === null || properties === void 0 ? void 0 : properties.status) ? " ".concat(properties === null || properties === void 0 ? void 0 : properties.status) : "");
5
+ var descriptor = type;
6
+ // Add status for events that have it (e.g., signature, transaction)
7
+ if (properties === null || properties === void 0 ? void 0 : properties.status) {
8
+ descriptor += " ".concat(properties.status);
9
+ }
10
+ // Add RDNS for connect/disconnect events to identify the wallet provider
11
+ if ((type === 'connect' || type === 'disconnect') && (properties === null || properties === void 0 ? void 0 : properties.rdns)) {
12
+ descriptor += " (".concat(properties.rdns, ")");
13
+ }
14
+ return descriptor;
6
15
  };
7
16
  exports.getActionDescriptor = getActionDescriptor;
8
17
  //# sourceMappingURL=base.js.map
@@ -22,6 +22,7 @@ export declare class FormoAnalytics implements IFormoAnalytics {
22
22
  */
23
23
  private _trackedProviders;
24
24
  private _injectedProviderDetail?;
25
+ private _processingAccountsChanged;
25
26
  private _seenProviders;
26
27
  config: Config;
27
28
  currentChainId?: ChainID;
@@ -181,6 +182,17 @@ export declare class FormoAnalytics implements IFormoAnalytics {
181
182
  private addProviderListener;
182
183
  private registerAccountsChangedListener;
183
184
  private onAccountsChanged;
185
+ /**
186
+ * Handles changes to the accounts of a given EIP-1193 provider.
187
+ *
188
+ * @param provider - The EIP-1193 provider whose accounts have changed.
189
+ * @param accounts - The new array of account addresses. An empty array indicates a disconnect.
190
+ * @returns A promise that resolves when the account change has been processed.
191
+ *
192
+ * If the accounts array is empty and the provider is the active provider, this method triggers
193
+ * a disconnect flow. Otherwise, it updates the state to reflect the new accounts as needed.
194
+ */
195
+ private _handleAccountsChanged;
184
196
  private registerChainChangedListener;
185
197
  private onChainChanged;
186
198
  private registerConnectListener;