@formo/analytics 1.21.0 → 1.22.0

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.
@@ -111,6 +111,7 @@ var FormoAnalytics = /** @class */ (function () {
111
111
  this.transaction = this.transaction.bind(this);
112
112
  this.detect = this.detect.bind(this);
113
113
  this.track = this.track.bind(this);
114
+ this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
114
115
  // Initialize logger with configuration from options
115
116
  Logger.init({
116
117
  enabled: ((_a = options.logger) === null || _a === void 0 ? void 0 : _a.enabled) || false,
@@ -620,12 +621,26 @@ var FormoAnalytics = /** @class */ (function () {
620
621
  logger.warn("TrackProvider: Provider already tracked.");
621
622
  return;
622
623
  }
623
- // Register listeners for this provider first
624
+ // CRITICAL: Always register accountsChanged for state management
625
+ // This ensures currentAddress, currentChainId, and _provider are always up-to-date
626
+ // Event emission is controlled conditionally inside the handlers
624
627
  this.registerAccountsChangedListener(provider);
625
- this.registerChainChangedListener(provider);
626
- this.registerConnectListener(provider);
627
- this.registerRequestListeners(provider);
628
- this.registerDisconnectListener(provider);
628
+ // Register other listeners based on autocapture configuration
629
+ if (this.isAutocaptureEnabled("chain")) {
630
+ this.registerChainChangedListener(provider);
631
+ }
632
+ if (this.isAutocaptureEnabled("connect")) {
633
+ this.registerConnectListener(provider);
634
+ }
635
+ if (this.isAutocaptureEnabled("signature") || this.isAutocaptureEnabled("transaction")) {
636
+ this.registerRequestListeners(provider);
637
+ }
638
+ else {
639
+ logger.debug("TrackProvider: Skipping request wrapping (both signature and transaction autocapture disabled)");
640
+ }
641
+ if (this.isAutocaptureEnabled("disconnect")) {
642
+ this.registerDisconnectListener(provider);
643
+ }
629
644
  // Only add to tracked providers after all listeners are successfully registered
630
645
  this._trackedProviders.add(provider);
631
646
  }
@@ -710,13 +725,14 @@ var FormoAnalytics = /** @class */ (function () {
710
725
  return __generator(this, function (_a) {
711
726
  switch (_a.label) {
712
727
  case 0:
713
- if (!(accounts.length === 0)) return [3 /*break*/, 7];
714
- if (!(this._provider === provider)) return [3 /*break*/, 5];
728
+ if (!(accounts.length === 0)) return [3 /*break*/, 9];
729
+ if (!(this._provider === provider)) return [3 /*break*/, 7];
715
730
  logger.info("OnAccountsChanged: Detecting disconnect, current state:", {
716
731
  currentAddress: this.currentAddress,
717
732
  currentChainId: this.currentChainId,
718
733
  providerMatch: this._provider === provider,
719
734
  });
735
+ if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 5];
720
736
  _a.label = 1;
721
737
  case 1:
722
738
  _a.trys.push([1, 3, , 4]);
@@ -735,16 +751,24 @@ var FormoAnalytics = /** @class */ (function () {
735
751
  return [3 /*break*/, 4];
736
752
  case 4: return [3 /*break*/, 6];
737
753
  case 5:
738
- logger.info("OnAccountsChanged: Ignoring disconnect for non-active provider");
754
+ logger.debug("OnAccountsChanged: Disconnect event skipped (autocapture.disconnect: false)");
755
+ // Still clear state even if not tracking the event
756
+ this.currentAddress = undefined;
757
+ this.currentChainId = undefined;
758
+ this.clearActiveProvider();
739
759
  _a.label = 6;
740
- case 6: return [2 /*return*/];
760
+ case 6: return [3 /*break*/, 8];
741
761
  case 7:
762
+ logger.info("OnAccountsChanged: Ignoring disconnect for non-active provider");
763
+ _a.label = 8;
764
+ case 8: return [2 /*return*/];
765
+ case 9:
742
766
  address = this.validateAndChecksumAddress(accounts[0]);
743
767
  if (!address) {
744
768
  logger.warn("onAccountsChanged: Invalid address received", accounts[0]);
745
769
  return [2 /*return*/];
746
770
  }
747
- if (!(this._provider && this._provider !== provider)) return [3 /*break*/, 18];
771
+ if (!(this._provider && this._provider !== provider)) return [3 /*break*/, 26];
748
772
  currentStoredAddress = this.currentAddress;
749
773
  newProviderAddress = this.validateAndChecksumAddress(address);
750
774
  logger.info("OnAccountsChanged: Different provider attempting to connect", {
@@ -753,11 +777,11 @@ var FormoAnalytics = /** @class */ (function () {
753
777
  currentStoredAddress: currentStoredAddress,
754
778
  newProviderAddress: newProviderAddress,
755
779
  });
756
- _a.label = 8;
757
- case 8:
758
- _a.trys.push([8, 16, , 18]);
780
+ _a.label = 10;
781
+ case 10:
782
+ _a.trys.push([10, 22, , 26]);
759
783
  return [4 /*yield*/, this.getAccounts(this._provider)];
760
- case 9:
784
+ case 11:
761
785
  activeProviderAccounts = _a.sent();
762
786
  logger.info("OnAccountsChanged: Checking current provider accounts", {
763
787
  activeProvider: this.getProviderInfo(this._provider).name,
@@ -766,10 +790,10 @@ var FormoAnalytics = /** @class */ (function () {
766
790
  : 0,
767
791
  accounts: activeProviderAccounts,
768
792
  });
769
- if (!(activeProviderAccounts && activeProviderAccounts.length > 0)) return [3 /*break*/, 13];
793
+ if (!(activeProviderAccounts && activeProviderAccounts.length > 0)) return [3 /*break*/, 17];
770
794
  if (!(newProviderAddress &&
771
795
  currentStoredAddress &&
772
- newProviderAddress !== currentStoredAddress)) return [3 /*break*/, 11];
796
+ newProviderAddress !== currentStoredAddress)) return [3 /*break*/, 15];
773
797
  logger.info("OnAccountsChanged: Different address detected, switching providers despite current provider having accounts", {
774
798
  activeProvider: this.getProviderInfo(this._provider).name,
775
799
  eventProvider: this.getProviderInfo(provider).name,
@@ -777,18 +801,25 @@ var FormoAnalytics = /** @class */ (function () {
777
801
  newAddress: newProviderAddress,
778
802
  reason: PROVIDER_SWITCH_REASONS.ADDRESS_MISMATCH,
779
803
  });
780
- // Emit disconnect for the old provider
804
+ if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 13];
781
805
  return [4 /*yield*/, this.disconnect({
782
806
  chainId: this.currentChainId,
783
807
  address: this.currentAddress,
784
808
  })];
785
- case 10:
786
- // Emit disconnect for the old provider
809
+ case 12:
787
810
  _a.sent();
811
+ return [3 /*break*/, 14];
812
+ case 13:
813
+ logger.debug("OnAccountsChanged: Disconnect event skipped during provider switch (autocapture.disconnect: false)");
814
+ // Still clear state even if not tracking the event
815
+ this.currentAddress = undefined;
816
+ this.currentChainId = undefined;
817
+ _a.label = 14;
818
+ case 14:
788
819
  // Clear state and let the new provider become active
789
820
  this.clearActiveProvider();
790
- return [3 /*break*/, 12];
791
- case 11:
821
+ return [3 /*break*/, 16];
822
+ case 15:
792
823
  logger.info("OnAccountsChanged: Current provider still has accounts and same address, ignoring new provider", {
793
824
  activeProvider: this.getProviderInfo(this._provider).name,
794
825
  eventProvider: this.getProviderInfo(provider).name,
@@ -797,26 +828,33 @@ var FormoAnalytics = /** @class */ (function () {
797
828
  newAddress: newProviderAddress,
798
829
  });
799
830
  return [2 /*return*/];
800
- case 12: return [3 /*break*/, 15];
801
- case 13:
831
+ case 16: return [3 /*break*/, 21];
832
+ case 17:
802
833
  logger.info("OnAccountsChanged: Current provider has no accounts, switching to new provider", {
803
834
  oldProvider: this.getProviderInfo(this._provider).name,
804
835
  newProvider: this.getProviderInfo(provider).name,
805
836
  reason: PROVIDER_SWITCH_REASONS.NO_ACCOUNTS,
806
837
  });
807
- // Emit disconnect for the old provider that didn't signal properly
838
+ if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 19];
808
839
  return [4 /*yield*/, this.disconnect({
809
840
  chainId: this.currentChainId,
810
841
  address: this.currentAddress,
811
842
  })];
812
- case 14:
813
- // Emit disconnect for the old provider that didn't signal properly
843
+ case 18:
814
844
  _a.sent();
845
+ return [3 /*break*/, 20];
846
+ case 19:
847
+ logger.debug("OnAccountsChanged: Disconnect event skipped for old provider (autocapture.disconnect: false)");
848
+ // Still clear state even if not tracking the event
849
+ this.currentAddress = undefined;
850
+ this.currentChainId = undefined;
851
+ _a.label = 20;
852
+ case 20:
815
853
  // Clear state and let the new provider become active
816
854
  this.clearActiveProvider();
817
- _a.label = 15;
818
- case 15: return [3 /*break*/, 18];
819
- case 16:
855
+ _a.label = 21;
856
+ case 21: return [3 /*break*/, 26];
857
+ case 22:
820
858
  error_2 = _a.sent();
821
859
  logger.warn("OnAccountsChanged: Could not check current provider accounts, switching to new provider", {
822
860
  error: error_2 instanceof Error ? error_2.message : String(error_2),
@@ -827,17 +865,24 @@ var FormoAnalytics = /** @class */ (function () {
827
865
  newProvider: this.getProviderInfo(provider).name,
828
866
  reason: PROVIDER_SWITCH_REASONS.CHECK_FAILED,
829
867
  });
830
- // If we can't check the current provider, assume it's disconnected
868
+ if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 24];
831
869
  return [4 /*yield*/, this.disconnect({
832
870
  chainId: this.currentChainId,
833
871
  address: this.currentAddress,
834
872
  })];
835
- case 17:
836
- // If we can't check the current provider, assume it's disconnected
873
+ case 23:
837
874
  _a.sent();
875
+ return [3 /*break*/, 25];
876
+ case 24:
877
+ logger.debug("OnAccountsChanged: Disconnect event skipped for failed provider check (autocapture.disconnect: false)");
878
+ // Still clear state even if not tracking the event
879
+ this.currentAddress = undefined;
880
+ this.currentChainId = undefined;
881
+ _a.label = 25;
882
+ case 25:
838
883
  this.clearActiveProvider();
839
- return [3 /*break*/, 18];
840
- case 18:
884
+ return [3 /*break*/, 26];
885
+ case 26:
841
886
  // Set provider if none exists (first connection)
842
887
  if (!this._provider) {
843
888
  this._provider = provider;
@@ -847,33 +892,44 @@ var FormoAnalytics = /** @class */ (function () {
847
892
  return [2 /*return*/];
848
893
  }
849
894
  return [4 /*yield*/, this.getCurrentChainId(provider)];
850
- case 19:
895
+ case 27:
851
896
  nextChainId = _a.sent();
852
897
  wasDisconnected = !this.currentAddress;
898
+ // CRITICAL: Always update state regardless of whether connect tracking is enabled
899
+ // This ensures disconnect events will have valid address/chainId values
853
900
  this.currentAddress = address;
854
901
  this.currentChainId = nextChainId;
855
902
  providerInfo = this.getProviderInfo(provider);
856
- logger.info("OnAccountsChanged: Detected wallet connection, emitting connect event", {
857
- chainId: nextChainId,
858
- address: address,
859
- wasDisconnected: wasDisconnected,
860
- providerName: providerInfo.name,
861
- rdns: providerInfo.rdns,
862
- hasChainId: !!nextChainId,
863
- });
864
903
  effectiveChainId = nextChainId || 0;
865
- if (effectiveChainId === 0) {
866
- logger.info("OnAccountsChanged: Using fallback chainId 0 for connect event");
904
+ if (this.isAutocaptureEnabled("connect")) {
905
+ logger.info("OnAccountsChanged: Detected wallet connection, emitting connect event", {
906
+ chainId: nextChainId,
907
+ address: address,
908
+ wasDisconnected: wasDisconnected,
909
+ providerName: providerInfo.name,
910
+ rdns: providerInfo.rdns,
911
+ hasChainId: !!nextChainId,
912
+ });
913
+ if (effectiveChainId === 0) {
914
+ logger.info("OnAccountsChanged: Using fallback chainId 0 for connect event");
915
+ }
916
+ this.connect({
917
+ chainId: effectiveChainId,
918
+ address: address,
919
+ }, {
920
+ providerName: providerInfo.name,
921
+ rdns: providerInfo.rdns,
922
+ }).catch(function (error) {
923
+ logger.error("Failed to track connect event during account change:", error);
924
+ });
925
+ }
926
+ else {
927
+ logger.debug("OnAccountsChanged: Connect event skipped (autocapture.connect: false)", {
928
+ chainId: nextChainId,
929
+ address: address,
930
+ providerName: providerInfo.name,
931
+ });
867
932
  }
868
- this.connect({
869
- chainId: effectiveChainId,
870
- address: address,
871
- }, {
872
- providerName: providerInfo.name,
873
- rdns: providerInfo.rdns,
874
- }).catch(function (error) {
875
- logger.error("Failed to track connect event during account change:", error);
876
- });
877
933
  return [2 /*return*/];
878
934
  }
879
935
  });
@@ -914,10 +970,18 @@ var FormoAnalytics = /** @class */ (function () {
914
970
  this.currentChainId = nextChainId;
915
971
  try {
916
972
  // This is just a chain change since we already confirmed currentAddress exists
917
- return [2 /*return*/, this.chain({
973
+ if (this.isAutocaptureEnabled("chain")) {
974
+ return [2 /*return*/, this.chain({
975
+ chainId: this.currentChainId,
976
+ address: this.currentAddress,
977
+ })];
978
+ }
979
+ else {
980
+ logger.debug("OnChainChanged: Chain event skipped (autocapture.chain: false)", {
918
981
  chainId: this.currentChainId,
919
982
  address: this.currentAddress,
920
- })];
983
+ });
984
+ }
921
985
  }
922
986
  catch (error) {
923
987
  logger.error("OnChainChanged: Failed to emit chain event:", error);
@@ -954,6 +1018,7 @@ var FormoAnalytics = /** @class */ (function () {
954
1018
  currentAddress: this.currentAddress,
955
1019
  currentChainId: this.currentChainId,
956
1020
  });
1021
+ if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 5];
957
1022
  _a.label = 1;
958
1023
  case 1:
959
1024
  _a.trys.push([1, 3, , 4]);
@@ -970,7 +1035,15 @@ var FormoAnalytics = /** @class */ (function () {
970
1035
  e_2 = _a.sent();
971
1036
  logger.error("Error during disconnect in disconnect listener", e_2);
972
1037
  return [3 /*break*/, 4];
973
- case 4: return [2 /*return*/];
1038
+ case 4: return [3 /*break*/, 6];
1039
+ case 5:
1040
+ logger.debug("OnDisconnect: Disconnect event skipped (autocapture.disconnect: false)");
1041
+ // Still clear state even if not tracking the event
1042
+ this.currentAddress = undefined;
1043
+ this.currentChainId = undefined;
1044
+ this.clearActiveProvider();
1045
+ _a.label = 6;
1046
+ case 6: return [2 /*return*/];
974
1047
  }
975
1048
  });
976
1049
  }); };
@@ -1000,35 +1073,46 @@ var FormoAnalytics = /** @class */ (function () {
1000
1073
  this._provider = provider;
1001
1074
  }
1002
1075
  isActiveProvider = this._provider === provider;
1003
- // Only update global state (chainId/address) from the active provider
1076
+ // CRITICAL: Always update state from active provider regardless of tracking config
1077
+ // This ensures disconnect events will have valid address/chainId values
1004
1078
  if (isActiveProvider) {
1005
1079
  this.currentChainId = chainId;
1006
1080
  this.currentAddress =
1007
1081
  this.validateAndChecksumAddress(address) || undefined;
1008
1082
  }
1083
+ // Conditionally emit connect event based on tracking configuration
1009
1084
  if (isActiveProvider && this.currentAddress) {
1010
1085
  providerInfo = this.getProviderInfo(provider);
1011
- logger.info("OnConnected: Detected wallet connection, emitting connect event", {
1012
- chainId: chainId,
1013
- wasDisconnected: wasDisconnected,
1014
- providerName: providerInfo.name,
1015
- rdns: providerInfo.rdns,
1016
- hasChainId: !!chainId,
1017
- isActiveProvider: isActiveProvider,
1018
- });
1019
1086
  effectiveChainId = chainId || 0;
1020
- if (effectiveChainId === 0) {
1021
- logger.info("OnConnected: Using fallback chainId 0 for connect event");
1087
+ if (this.isAutocaptureEnabled("connect")) {
1088
+ logger.info("OnConnected: Detected wallet connection, emitting connect event", {
1089
+ chainId: chainId,
1090
+ wasDisconnected: wasDisconnected,
1091
+ providerName: providerInfo.name,
1092
+ rdns: providerInfo.rdns,
1093
+ hasChainId: !!chainId,
1094
+ isActiveProvider: isActiveProvider,
1095
+ });
1096
+ if (effectiveChainId === 0) {
1097
+ logger.info("OnConnected: Using fallback chainId 0 for connect event");
1098
+ }
1099
+ this.connect({
1100
+ chainId: effectiveChainId,
1101
+ address: address,
1102
+ }, {
1103
+ providerName: providerInfo.name,
1104
+ rdns: providerInfo.rdns,
1105
+ }).catch(function (error) {
1106
+ logger.error("Failed to track connect event during provider connection:", error);
1107
+ });
1108
+ }
1109
+ else {
1110
+ logger.debug("OnConnected: Connect event skipped (autocapture.connect: false)", {
1111
+ chainId: chainId,
1112
+ address: address,
1113
+ providerName: providerInfo.name,
1114
+ });
1022
1115
  }
1023
- this.connect({
1024
- chainId: effectiveChainId,
1025
- address: address,
1026
- }, {
1027
- providerName: providerInfo.name,
1028
- rdns: providerInfo.rdns,
1029
- }).catch(function (error) {
1030
- logger.error("Failed to track connect event during provider connection:", error);
1031
- });
1032
1116
  }
1033
1117
  else if (address && !isActiveProvider) {
1034
1118
  providerInfo = this.getProviderInfo(provider);
@@ -1076,6 +1160,10 @@ var FormoAnalytics = /** @class */ (function () {
1076
1160
  case 0:
1077
1161
  if (!(Array.isArray(params) &&
1078
1162
  ["eth_signTypedData_v4", "personal_sign"].includes(method))) return [3 /*break*/, 6];
1163
+ if (!this.isAutocaptureEnabled("signature")) {
1164
+ logger.debug("Signature event skipped (autocapture.signature: false)", { method: method });
1165
+ return [2 /*return*/, request({ method: method, params: params })];
1166
+ }
1079
1167
  _c = this.currentChainId;
1080
1168
  if (_c) return [3 /*break*/, 2];
1081
1169
  return [4 /*yield*/, this.getCurrentChainId(provider)];
@@ -1139,6 +1227,10 @@ var FormoAnalytics = /** @class */ (function () {
1139
1227
  if (!(Array.isArray(params) &&
1140
1228
  method === "eth_sendTransaction" &&
1141
1229
  params[0])) return [3 /*break*/, 10];
1230
+ if (!this.isAutocaptureEnabled("transaction")) {
1231
+ logger.debug("Transaction event skipped (autocapture.transaction: false)", { method: method });
1232
+ return [2 /*return*/, request({ method: method, params: params })];
1233
+ }
1142
1234
  (function () { return __awaiter(_this, void 0, void 0, function () {
1143
1235
  var payload, e_4;
1144
1236
  return __generator(this, function (_a) {
@@ -1378,6 +1470,30 @@ var FormoAnalytics = /** @class */ (function () {
1378
1470
  // Default behavior: track everywhere except localhost
1379
1471
  return !isLocalhost();
1380
1472
  };
1473
+ /**
1474
+ * Check if a specific wallet event type is enabled for autocapture
1475
+ * @param eventType The wallet event type to check
1476
+ * @returns {boolean} True if the event type should be autocaptured
1477
+ */
1478
+ FormoAnalytics.prototype.isAutocaptureEnabled = function (eventType) {
1479
+ // If no configuration provided, default to enabled
1480
+ if (this.options.autocapture === undefined) {
1481
+ return true;
1482
+ }
1483
+ // If boolean, return that value for all events
1484
+ if (typeof this.options.autocapture === "boolean") {
1485
+ return this.options.autocapture;
1486
+ }
1487
+ // If it's an object, check the specific event configuration
1488
+ if (this.options.autocapture !== null &&
1489
+ typeof this.options.autocapture === "object") {
1490
+ var eventConfig = this.options.autocapture[eventType];
1491
+ // Default to true if not explicitly set to false
1492
+ return eventConfig !== false;
1493
+ }
1494
+ // Default to enabled if no specific configuration
1495
+ return true;
1496
+ };
1381
1497
  /*
1382
1498
  Utility functions
1383
1499
  */
@@ -1,2 +1,2 @@
1
- export declare const version = "1.20.0";
1
+ export declare const version = "1.22.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export var version = '1.20.0';
2
+ export var version = '1.22.0';
3
3
  //# sourceMappingURL=version.js.map
@@ -63,9 +63,48 @@ export interface TrackingOptions {
63
63
  excludePaths?: string[];
64
64
  excludeChains?: ChainID[];
65
65
  }
66
+ /**
67
+ * Configuration options for controlling wallet event autocapture
68
+ * All events are enabled by default unless explicitly set to false
69
+ */
70
+ export interface AutocaptureOptions {
71
+ /**
72
+ * Track wallet connect events
73
+ * @default true
74
+ */
75
+ connect?: boolean;
76
+ /**
77
+ * Track wallet disconnect events
78
+ * @default true
79
+ */
80
+ disconnect?: boolean;
81
+ /**
82
+ * Track wallet signature events (personal_sign, eth_signTypedData_v4)
83
+ * @default true
84
+ */
85
+ signature?: boolean;
86
+ /**
87
+ * Track wallet transaction events (eth_sendTransaction)
88
+ * @default true
89
+ */
90
+ transaction?: boolean;
91
+ /**
92
+ * Track wallet chain change events
93
+ * @default true
94
+ */
95
+ chain?: boolean;
96
+ }
66
97
  export interface Options {
67
98
  provider?: EIP1193Provider;
68
99
  tracking?: boolean | TrackingOptions;
100
+ /**
101
+ * Control wallet event autocapture
102
+ * - `false`: Disable all wallet autocapture
103
+ * - `true`: Enable all wallet events (default)
104
+ * - `AutocaptureOptions`: Granular control over specific events
105
+ * @default true
106
+ */
107
+ autocapture?: boolean | AutocaptureOptions;
69
108
  flushAt?: number;
70
109
  flushInterval?: number;
71
110
  retryCount?: number;