@formo/analytics 1.25.0 → 1.26.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.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/src/FormoAnalytics.d.ts +24 -14
  3. package/dist/cjs/src/FormoAnalytics.js +195 -255
  4. package/dist/cjs/src/FormoAnalyticsProvider.js +71 -13
  5. package/dist/{esm/src/lib/consent.d.ts → cjs/src/consent/index.d.ts} +1 -1
  6. package/dist/cjs/src/{lib/consent.js → consent/index.js} +1 -1
  7. package/dist/cjs/src/constants/base.d.ts +0 -2
  8. package/dist/cjs/src/constants/base.js +3 -3
  9. package/dist/cjs/src/constants/config.js +1 -1
  10. package/dist/cjs/src/{lib/event → event}/EventFactory.d.ts +1 -1
  11. package/dist/cjs/src/{lib/event → event}/EventFactory.js +6 -6
  12. package/dist/cjs/src/{lib/event → event}/EventManager.d.ts +1 -1
  13. package/dist/cjs/src/{lib/event → event}/EventManager.js +1 -1
  14. package/dist/cjs/src/{lib/event → event}/type.d.ts +1 -1
  15. package/dist/cjs/src/{lib/event → event}/utils.d.ts +1 -1
  16. package/dist/cjs/src/{lib/event → event}/utils.js +1 -1
  17. package/dist/cjs/src/{lib/fetch.d.ts → fetch/index.d.ts} +1 -1
  18. package/dist/cjs/src/{lib/fetch.js → fetch/index.js} +1 -1
  19. package/dist/cjs/src/provider/detection.d.ts +58 -0
  20. package/dist/cjs/src/provider/detection.js +103 -0
  21. package/dist/cjs/src/provider/index.d.ts +6 -0
  22. package/dist/cjs/src/provider/index.js +11 -0
  23. package/dist/{esm/src/lib → cjs/src}/queue/EventQueue.d.ts +1 -1
  24. package/dist/cjs/src/{lib/queue → queue}/EventQueue.js +3 -3
  25. package/dist/{esm/src/lib → cjs/src}/queue/type.d.ts +1 -1
  26. package/dist/cjs/src/session/index.d.ts +91 -0
  27. package/dist/cjs/src/session/index.js +126 -0
  28. package/dist/cjs/src/{lib/storage → storage}/built-in/blueprint.js +1 -1
  29. package/dist/cjs/src/types/base.d.ts +27 -1
  30. package/dist/cjs/src/validators/object.js +0 -2
  31. package/dist/cjs/src/version.d.ts +1 -1
  32. package/dist/cjs/src/version.js +1 -1
  33. package/dist/cjs/src/wagmi/WagmiEventHandler.d.ts +69 -0
  34. package/dist/cjs/src/wagmi/WagmiEventHandler.js +449 -0
  35. package/dist/cjs/src/wagmi/index.d.ts +9 -0
  36. package/dist/cjs/src/wagmi/index.js +12 -0
  37. package/dist/cjs/src/wagmi/types.d.ts +115 -0
  38. package/dist/cjs/src/wagmi/types.js +10 -0
  39. package/dist/esm/src/FormoAnalytics.d.ts +24 -14
  40. package/dist/esm/src/FormoAnalytics.js +85 -145
  41. package/dist/esm/src/FormoAnalyticsProvider.js +68 -10
  42. package/dist/{cjs/src/lib/consent.d.ts → esm/src/consent/index.d.ts} +1 -1
  43. package/dist/esm/src/{lib/consent.js → consent/index.js} +1 -1
  44. package/dist/esm/src/constants/base.d.ts +0 -2
  45. package/dist/esm/src/constants/base.js +2 -2
  46. package/dist/esm/src/constants/config.js +1 -1
  47. package/dist/esm/src/{lib/event → event}/EventFactory.d.ts +1 -1
  48. package/dist/esm/src/{lib/event → event}/EventFactory.js +6 -6
  49. package/dist/esm/src/{lib/event → event}/EventManager.d.ts +1 -1
  50. package/dist/esm/src/{lib/event → event}/EventManager.js +1 -1
  51. package/dist/esm/src/{lib/event → event}/type.d.ts +1 -1
  52. package/dist/esm/src/{lib/event → event}/utils.d.ts +1 -1
  53. package/dist/esm/src/{lib/event → event}/utils.js +1 -1
  54. package/dist/esm/src/{lib/fetch.d.ts → fetch/index.d.ts} +1 -1
  55. package/dist/esm/src/{lib/fetch.js → fetch/index.js} +1 -1
  56. package/dist/esm/src/provider/detection.d.ts +58 -0
  57. package/dist/esm/src/provider/detection.js +98 -0
  58. package/dist/esm/src/provider/index.d.ts +6 -0
  59. package/dist/esm/src/provider/index.js +5 -0
  60. package/dist/{cjs/src/lib → esm/src}/queue/EventQueue.d.ts +1 -1
  61. package/dist/esm/src/{lib/queue → queue}/EventQueue.js +3 -3
  62. package/dist/{cjs/src/lib → esm/src}/queue/type.d.ts +1 -1
  63. package/dist/esm/src/session/index.d.ts +91 -0
  64. package/dist/esm/src/session/index.js +123 -0
  65. package/dist/esm/src/{lib/storage → storage}/built-in/blueprint.js +1 -1
  66. package/dist/esm/src/types/base.d.ts +27 -1
  67. package/dist/esm/src/validators/object.js +0 -2
  68. package/dist/esm/src/version.d.ts +1 -1
  69. package/dist/esm/src/version.js +1 -1
  70. package/dist/esm/src/wagmi/WagmiEventHandler.d.ts +69 -0
  71. package/dist/esm/src/wagmi/WagmiEventHandler.js +446 -0
  72. package/dist/esm/src/wagmi/index.d.ts +9 -0
  73. package/dist/esm/src/wagmi/index.js +8 -0
  74. package/dist/esm/src/wagmi/types.d.ts +115 -0
  75. package/dist/esm/src/wagmi/types.js +9 -0
  76. package/dist/index.umd.min.js +1 -1
  77. package/package.json +18 -3
  78. package/dist/cjs/src/lib/index.d.ts +0 -7
  79. package/dist/cjs/src/lib/index.js +0 -28
  80. package/dist/esm/src/lib/index.d.ts +0 -7
  81. package/dist/esm/src/lib/index.js +0 -7
  82. /package/dist/cjs/src/{lib/browser → browser}/browsers.d.ts +0 -0
  83. /package/dist/cjs/src/{lib/browser → browser}/browsers.js +0 -0
  84. /package/dist/cjs/src/{lib/event → event}/constants.d.ts +0 -0
  85. /package/dist/cjs/src/{lib/event → event}/constants.js +0 -0
  86. /package/dist/cjs/src/{lib/event → event}/index.d.ts +0 -0
  87. /package/dist/cjs/src/{lib/event → event}/index.js +0 -0
  88. /package/dist/cjs/src/{lib/event → event}/type.js +0 -0
  89. /package/dist/cjs/src/{lib/logger → logger}/Logger.d.ts +0 -0
  90. /package/dist/cjs/src/{lib/logger → logger}/Logger.js +0 -0
  91. /package/dist/cjs/src/{lib/logger → logger}/index.d.ts +0 -0
  92. /package/dist/cjs/src/{lib/logger → logger}/index.js +0 -0
  93. /package/dist/cjs/src/{lib/logger → logger}/type.d.ts +0 -0
  94. /package/dist/cjs/src/{lib/logger → logger}/type.js +0 -0
  95. /package/dist/cjs/src/{lib/queue → queue}/index.d.ts +0 -0
  96. /package/dist/cjs/src/{lib/queue → queue}/index.js +0 -0
  97. /package/dist/cjs/src/{lib/queue → queue}/type.js +0 -0
  98. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry1.d.ts +0 -0
  99. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry1.js +0 -0
  100. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry2.d.ts +0 -0
  101. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry2.js +0 -0
  102. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry3.d.ts +0 -0
  103. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_curry3.js +0 -0
  104. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_has.d.ts +0 -0
  105. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_has.js +0 -0
  106. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_isObject.d.ts +0 -0
  107. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_isObject.js +0 -0
  108. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_isPlaceholder.d.ts +0 -0
  109. /package/dist/cjs/src/{lib/ramda → ramda}/internal/_isPlaceholder.js +0 -0
  110. /package/dist/cjs/src/{lib/ramda → ramda}/mergeDeepRight.d.ts +0 -0
  111. /package/dist/cjs/src/{lib/ramda → ramda}/mergeDeepRight.js +0 -0
  112. /package/dist/cjs/src/{lib/ramda → ramda}/mergeDeepWithKey.d.ts +0 -0
  113. /package/dist/cjs/src/{lib/ramda → ramda}/mergeDeepWithKey.js +0 -0
  114. /package/dist/cjs/src/{lib/ramda → ramda}/mergeWithKey.d.ts +0 -0
  115. /package/dist/cjs/src/{lib/ramda → ramda}/mergeWithKey.js +0 -0
  116. /package/dist/cjs/src/{lib/storage → storage}/StorageManager.d.ts +0 -0
  117. /package/dist/cjs/src/{lib/storage → storage}/StorageManager.js +0 -0
  118. /package/dist/cjs/src/{lib/storage → storage}/built-in/blueprint.d.ts +0 -0
  119. /package/dist/cjs/src/{lib/storage → storage}/built-in/cookie.d.ts +0 -0
  120. /package/dist/cjs/src/{lib/storage → storage}/built-in/cookie.js +0 -0
  121. /package/dist/cjs/src/{lib/storage → storage}/built-in/memory.d.ts +0 -0
  122. /package/dist/cjs/src/{lib/storage → storage}/built-in/memory.js +0 -0
  123. /package/dist/cjs/src/{lib/storage → storage}/built-in/web.d.ts +0 -0
  124. /package/dist/cjs/src/{lib/storage → storage}/built-in/web.js +0 -0
  125. /package/dist/cjs/src/{lib/storage → storage}/constant.d.ts +0 -0
  126. /package/dist/cjs/src/{lib/storage → storage}/constant.js +0 -0
  127. /package/dist/cjs/src/{lib/storage → storage}/index.d.ts +0 -0
  128. /package/dist/cjs/src/{lib/storage → storage}/index.js +0 -0
  129. /package/dist/cjs/src/{lib/storage → storage}/type.d.ts +0 -0
  130. /package/dist/cjs/src/{lib/storage → storage}/type.js +0 -0
  131. /package/dist/esm/src/{lib/browser → browser}/browsers.d.ts +0 -0
  132. /package/dist/esm/src/{lib/browser → browser}/browsers.js +0 -0
  133. /package/dist/esm/src/{lib/event → event}/constants.d.ts +0 -0
  134. /package/dist/esm/src/{lib/event → event}/constants.js +0 -0
  135. /package/dist/esm/src/{lib/event → event}/index.d.ts +0 -0
  136. /package/dist/esm/src/{lib/event → event}/index.js +0 -0
  137. /package/dist/esm/src/{lib/event → event}/type.js +0 -0
  138. /package/dist/esm/src/{lib/logger → logger}/Logger.d.ts +0 -0
  139. /package/dist/esm/src/{lib/logger → logger}/Logger.js +0 -0
  140. /package/dist/esm/src/{lib/logger → logger}/index.d.ts +0 -0
  141. /package/dist/esm/src/{lib/logger → logger}/index.js +0 -0
  142. /package/dist/esm/src/{lib/logger → logger}/type.d.ts +0 -0
  143. /package/dist/esm/src/{lib/logger → logger}/type.js +0 -0
  144. /package/dist/esm/src/{lib/queue → queue}/index.d.ts +0 -0
  145. /package/dist/esm/src/{lib/queue → queue}/index.js +0 -0
  146. /package/dist/esm/src/{lib/queue → queue}/type.js +0 -0
  147. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry1.d.ts +0 -0
  148. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry1.js +0 -0
  149. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry2.d.ts +0 -0
  150. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry2.js +0 -0
  151. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry3.d.ts +0 -0
  152. /package/dist/esm/src/{lib/ramda → ramda}/internal/_curry3.js +0 -0
  153. /package/dist/esm/src/{lib/ramda → ramda}/internal/_has.d.ts +0 -0
  154. /package/dist/esm/src/{lib/ramda → ramda}/internal/_has.js +0 -0
  155. /package/dist/esm/src/{lib/ramda → ramda}/internal/_isObject.d.ts +0 -0
  156. /package/dist/esm/src/{lib/ramda → ramda}/internal/_isObject.js +0 -0
  157. /package/dist/esm/src/{lib/ramda → ramda}/internal/_isPlaceholder.d.ts +0 -0
  158. /package/dist/esm/src/{lib/ramda → ramda}/internal/_isPlaceholder.js +0 -0
  159. /package/dist/esm/src/{lib/ramda → ramda}/mergeDeepRight.d.ts +0 -0
  160. /package/dist/esm/src/{lib/ramda → ramda}/mergeDeepRight.js +0 -0
  161. /package/dist/esm/src/{lib/ramda → ramda}/mergeDeepWithKey.d.ts +0 -0
  162. /package/dist/esm/src/{lib/ramda → ramda}/mergeDeepWithKey.js +0 -0
  163. /package/dist/esm/src/{lib/ramda → ramda}/mergeWithKey.d.ts +0 -0
  164. /package/dist/esm/src/{lib/ramda → ramda}/mergeWithKey.js +0 -0
  165. /package/dist/esm/src/{lib/storage → storage}/StorageManager.d.ts +0 -0
  166. /package/dist/esm/src/{lib/storage → storage}/StorageManager.js +0 -0
  167. /package/dist/esm/src/{lib/storage → storage}/built-in/blueprint.d.ts +0 -0
  168. /package/dist/esm/src/{lib/storage → storage}/built-in/cookie.d.ts +0 -0
  169. /package/dist/esm/src/{lib/storage → storage}/built-in/cookie.js +0 -0
  170. /package/dist/esm/src/{lib/storage → storage}/built-in/memory.d.ts +0 -0
  171. /package/dist/esm/src/{lib/storage → storage}/built-in/memory.js +0 -0
  172. /package/dist/esm/src/{lib/storage → storage}/built-in/web.d.ts +0 -0
  173. /package/dist/esm/src/{lib/storage → storage}/built-in/web.js +0 -0
  174. /package/dist/esm/src/{lib/storage → storage}/constant.d.ts +0 -0
  175. /package/dist/esm/src/{lib/storage → storage}/constant.js +0 -0
  176. /package/dist/esm/src/{lib/storage → storage}/index.d.ts +0 -0
  177. /package/dist/esm/src/{lib/storage → storage}/index.js +0 -0
  178. /package/dist/esm/src/{lib/storage → storage}/type.d.ts +0 -0
  179. /package/dist/esm/src/{lib/storage → storage}/type.js +0 -0
@@ -55,13 +55,20 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
55
55
  return to.concat(ar || Array.prototype.slice.call(from));
56
56
  };
57
57
  import { createStore } from "mipd";
58
- import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_CURRENT_URL_KEY, SESSION_USER_ID_KEY, SESSION_WALLET_DETECTED_KEY, SESSION_WALLET_IDENTIFIED_KEY, DEFAULT_PROVIDER_ICON, CONSENT_OPT_OUT_KEY, } from "./constants";
59
- import { cookie, EventManager, EventQueue, initStorageManager, logger, Logger, setConsentFlag, getConsentFlag, removeConsentFlag, } from "./lib";
58
+ import { EVENTS_API_HOST, EventType, LOCAL_ANONYMOUS_ID_KEY, SESSION_CURRENT_URL_KEY, SESSION_USER_ID_KEY, CONSENT_OPT_OUT_KEY, } from "./constants";
59
+ import { cookie, initStorageManager } from "./storage";
60
+ import { EventManager } from "./event";
61
+ import { EventQueue } from "./queue";
62
+ import { logger, Logger } from "./logger";
63
+ import { setConsentFlag, getConsentFlag, removeConsentFlag, } from "./consent";
64
+ import { detectInjectedProviderInfo, isValidProvider } from "./provider";
65
+ import { FormoAnalyticsSession, SESSION_WALLET_DETECTED_KEY, SESSION_WALLET_IDENTIFIED_KEY, } from "./session";
60
66
  import { SignatureStatus, TransactionStatus, WRAPPED_REQUEST_SYMBOL, WRAPPED_REQUEST_REF_SYMBOL, } from "./types";
61
67
  import { toChecksumAddress } from "./utils";
62
68
  import { getValidAddress } from "./utils/address";
63
69
  import { isLocalhost } from "./validators";
64
70
  import { parseChainId } from "./utils/chain";
71
+ import { WagmiEventHandler } from "./wagmi";
65
72
  /**
66
73
  * Constants for provider switching reasons
67
74
  */
@@ -95,11 +102,18 @@ var FormoAnalytics = /** @class */ (function () {
95
102
  this._processingAccountsChanged = false;
96
103
  // Set to efficiently track seen providers for deduplication and O(1) lookup
97
104
  this._seenProviders = new Set();
105
+ /**
106
+ * Flag indicating if Wagmi mode is enabled
107
+ * When true, EIP-1193 provider wrapping is skipped
108
+ */
109
+ this.isWagmiMode = false;
98
110
  this.currentUserId = "";
99
111
  this.config = {
100
112
  writeKey: writeKey,
101
113
  };
102
114
  this.options = options;
115
+ // Check if Wagmi mode is enabled
116
+ this.isWagmiMode = !!options.wagmi;
103
117
  this.session = new FormoAnalyticsSession();
104
118
  this.currentUserId =
105
119
  cookie().get(SESSION_USER_ID_KEY) || undefined;
@@ -128,17 +142,24 @@ var FormoAnalytics = /** @class */ (function () {
128
142
  if (this.hasOptedOutTracking()) {
129
143
  logger.info("User has previously opted out of tracking");
130
144
  }
131
- // Handle initial provider (injected) as fallback; listeners for EIP-6963 are added later
132
- var provider = undefined;
133
- var optProvider = options.provider;
134
- if (optProvider) {
135
- provider = optProvider;
145
+ // Initialize Wagmi handler if Wagmi mode is enabled
146
+ if (this.isWagmiMode && options.wagmi) {
147
+ logger.info("FormoAnalytics: Initializing in Wagmi mode");
148
+ this.wagmiHandler = new WagmiEventHandler(this, options.wagmi.config, options.wagmi.queryClient);
136
149
  }
137
- else if (typeof window !== "undefined" && window.ethereum) {
138
- provider = window.ethereum;
139
- }
140
- if (provider) {
141
- this.trackProvider(provider);
150
+ else {
151
+ // Handle initial provider (injected) as fallback; listeners for EIP-6963 are added later
152
+ var provider = undefined;
153
+ var optProvider = options.provider;
154
+ if (optProvider) {
155
+ provider = optProvider;
156
+ }
157
+ else if (typeof window !== "undefined" && window.ethereum) {
158
+ provider = window.ethereum;
159
+ }
160
+ if (provider) {
161
+ this.trackEIP1193Provider(provider);
162
+ }
142
163
  }
143
164
  this.trackPageHit();
144
165
  this.trackPageHits();
@@ -153,18 +174,6 @@ var FormoAnalytics = /** @class */ (function () {
153
174
  // This allows legitimate provider switching while preventing race conditions
154
175
  return this._provider != null && this._provider !== provider;
155
176
  };
156
- /**
157
- * Check if a provider is in a valid state for switching
158
- * @param provider The provider to validate
159
- * @returns true if the provider is in a valid state
160
- */
161
- FormoAnalytics.prototype.isProviderInValidState = function (provider) {
162
- // Basic validation: ensure provider exists and has required methods
163
- return (provider &&
164
- typeof provider.request === "function" &&
165
- typeof provider.on === "function" &&
166
- typeof provider.removeListener === "function");
167
- };
168
177
  FormoAnalytics.init = function (writeKey, options) {
169
178
  return __awaiter(this, void 0, void 0, function () {
170
179
  var analytics, _a;
@@ -173,6 +182,7 @@ var FormoAnalytics = /** @class */ (function () {
173
182
  case 0:
174
183
  initStorageManager(writeKey);
175
184
  analytics = new FormoAnalytics(writeKey, options);
185
+ if (!!analytics.isWagmiMode) return [3 /*break*/, 3];
176
186
  // Auto-detect wallet provider
177
187
  _a = analytics;
178
188
  return [4 /*yield*/, analytics.getProviders()];
@@ -183,7 +193,11 @@ var FormoAnalytics = /** @class */ (function () {
183
193
  case 2:
184
194
  _b.sent();
185
195
  analytics.trackProviders(analytics._providers);
186
- return [2 /*return*/, analytics];
196
+ return [3 /*break*/, 4];
197
+ case 3:
198
+ logger.info("FormoAnalytics: Skipping provider detection (Wagmi mode)");
199
+ _b.label = 4;
200
+ case 4: return [2 /*return*/, analytics];
187
201
  }
188
202
  });
189
203
  });
@@ -223,6 +237,27 @@ var FormoAnalytics = /** @class */ (function () {
223
237
  cookie().remove(SESSION_WALLET_DETECTED_KEY);
224
238
  cookie().remove(SESSION_WALLET_IDENTIFIED_KEY);
225
239
  };
240
+ /**
241
+ * Clean up resources and event listeners
242
+ * Call this when destroying the analytics instance
243
+ * @returns {void}
244
+ */
245
+ FormoAnalytics.prototype.cleanup = function () {
246
+ logger.info("FormoAnalytics: Cleaning up resources");
247
+ // Clean up Wagmi handler if present
248
+ if (this.wagmiHandler) {
249
+ this.wagmiHandler.cleanup();
250
+ this.wagmiHandler = undefined;
251
+ }
252
+ // Clean up EIP-1193 providers if not in Wagmi mode
253
+ if (!this.isWagmiMode) {
254
+ for (var _i = 0, _a = Array.from(this._trackedProviders); _i < _a.length; _i++) {
255
+ var provider = _a[_i];
256
+ this.untrackProvider(provider);
257
+ }
258
+ }
259
+ logger.info("FormoAnalytics: Cleanup complete");
260
+ };
226
261
  /**
227
262
  * Emits a connect wallet event.
228
263
  * @param {ChainID} params.chainId
@@ -612,13 +647,29 @@ var FormoAnalytics = /** @class */ (function () {
612
647
  /*
613
648
  SDK tracking and event listener functions
614
649
  */
615
- FormoAnalytics.prototype.trackProvider = function (provider) {
616
- logger.info("trackProvider", provider);
650
+ /**
651
+ * Track an EIP-1193 provider by wrapping its request method and adding event listeners
652
+ * Note: This is only used in non-Wagmi mode. When Wagmi is enabled, all tracking
653
+ * happens through Wagmi's connector system instead of EIP-1193/EIP-6963.
654
+ * @param provider The EIP-1193 provider to track
655
+ */
656
+ FormoAnalytics.prototype.trackEIP1193Provider = function (provider) {
657
+ logger.info("trackEIP1193Provider", provider);
658
+ // Defensive check: Skip provider tracking in Wagmi mode
659
+ // This should never be called in Wagmi mode due to guards in init(),
660
+ // but we check here for safety in case of future code changes
661
+ if (this.isWagmiMode) {
662
+ logger.debug("trackEIP1193Provider: Skipping EIP-1193 provider tracking (Wagmi mode - using connector system instead)");
663
+ return;
664
+ }
617
665
  try {
618
- if (!provider)
666
+ // Validate provider exists and has required methods
667
+ if (!isValidProvider(provider)) {
668
+ logger.warn("trackEIP1193Provider: Invalid provider - missing required methods");
619
669
  return;
670
+ }
620
671
  if (this._trackedProviders.has(provider)) {
621
- logger.warn("TrackProvider: Provider already tracked.");
672
+ logger.warn("trackEIP1193Provider: Provider already tracked");
622
673
  return;
623
674
  }
624
675
  // CRITICAL: Always register accountsChanged for state management
@@ -654,7 +705,7 @@ var FormoAnalytics = /** @class */ (function () {
654
705
  var eip6963ProviderDetail = providers_1[_i];
655
706
  var provider = eip6963ProviderDetail === null || eip6963ProviderDetail === void 0 ? void 0 : eip6963ProviderDetail.provider;
656
707
  if (provider && !this._trackedProviders.has(provider)) {
657
- this.trackProvider(provider);
708
+ this.trackEIP1193Provider(provider);
658
709
  }
659
710
  }
660
711
  }
@@ -1512,60 +1563,12 @@ var FormoAnalytics = /** @class */ (function () {
1512
1563
  };
1513
1564
  }
1514
1565
  // Fallback to injected provider detection
1515
- var injectedInfo = this.detectInjectedProviderInfo(provider);
1566
+ var injectedInfo = detectInjectedProviderInfo(provider);
1516
1567
  return {
1517
1568
  name: injectedInfo.name,
1518
1569
  rdns: injectedInfo.rdns,
1519
1570
  };
1520
1571
  };
1521
- /**
1522
- * Attempts to detect information about an injected provider
1523
- * @param provider The injected provider to analyze
1524
- * @returns Provider information with fallback values
1525
- */
1526
- FormoAnalytics.prototype.detectInjectedProviderInfo = function (provider) {
1527
- // Try to detect provider type from common properties
1528
- var name = "Injected Provider";
1529
- var rdns = "io.injected.provider";
1530
- // Use WalletProviderFlags interface for type safety
1531
- var flags = provider;
1532
- // Check if it's MetaMask
1533
- if (flags.isMetaMask) {
1534
- name = "MetaMask";
1535
- rdns = "io.metamask";
1536
- }
1537
- // Check if it's Coinbase Wallet
1538
- else if (flags.isCoinbaseWallet) {
1539
- name = "Coinbase Wallet";
1540
- rdns = "com.coinbase.wallet";
1541
- }
1542
- // Check if it's WalletConnect
1543
- else if (flags.isWalletConnect) {
1544
- name = "WalletConnect";
1545
- rdns = "com.walletconnect";
1546
- }
1547
- // Check if it's Trust Wallet
1548
- else if (flags.isTrust) {
1549
- name = "Trust Wallet";
1550
- rdns = "com.trustwallet";
1551
- }
1552
- // Check if it's Brave Wallet
1553
- else if (flags.isBraveWallet) {
1554
- name = "Brave Wallet";
1555
- rdns = "com.brave.wallet";
1556
- }
1557
- // Check if it's Phantom
1558
- else if (flags.isPhantom) {
1559
- name = "Phantom";
1560
- rdns = "app.phantom";
1561
- }
1562
- return {
1563
- name: name,
1564
- rdns: rdns,
1565
- uuid: "injected-".concat(rdns.replace(/[^a-zA-Z0-9]/g, "-")),
1566
- icon: DEFAULT_PROVIDER_ICON,
1567
- };
1568
- };
1569
1572
  FormoAnalytics.prototype.getProviders = function () {
1570
1573
  return __awaiter(this, void 0, void 0, function () {
1571
1574
  var store, providers, injected_1, injectedProviderInfo, injectedDetail, uniqueProviders, _i, uniqueProviders_1, detail;
@@ -1624,7 +1627,7 @@ var FormoAnalytics = /** @class */ (function () {
1624
1627
  this._injectedProviderDetail.provider === injected_1) {
1625
1628
  // Ensure it's tracked
1626
1629
  if (!this._trackedProviders.has(injected_1)) {
1627
- this.trackProvider(injected_1);
1630
+ this.trackEIP1193Provider(injected_1);
1628
1631
  }
1629
1632
  // Merge with existing providers instead of overwriting
1630
1633
  if (!this._providers.some(function (existing) { return existing.provider === injected_1; })) {
@@ -1636,9 +1639,9 @@ var FormoAnalytics = /** @class */ (function () {
1636
1639
  }
1637
1640
  // Re-check if the injected provider is already tracked just before tracking
1638
1641
  if (!this._trackedProviders.has(injected_1)) {
1639
- this.trackProvider(injected_1);
1642
+ this.trackEIP1193Provider(injected_1);
1640
1643
  }
1641
- injectedProviderInfo = this.detectInjectedProviderInfo(injected_1);
1644
+ injectedProviderInfo = detectInjectedProviderInfo(injected_1);
1642
1645
  injectedDetail = {
1643
1646
  provider: injected_1,
1644
1647
  info: injectedProviderInfo,
@@ -2040,67 +2043,4 @@ var FormoAnalytics = /** @class */ (function () {
2040
2043
  return FormoAnalytics;
2041
2044
  }());
2042
2045
  export { FormoAnalytics };
2043
- var FormoAnalyticsSession = /** @class */ (function () {
2044
- function FormoAnalyticsSession() {
2045
- }
2046
- FormoAnalyticsSession.prototype.generateIdentificationKey = function (address, rdns) {
2047
- // If rdns is missing, use address-only key as fallback for empty identifies
2048
- return rdns ? "".concat(address, ":").concat(rdns) : address;
2049
- };
2050
- FormoAnalyticsSession.prototype.isWalletDetected = function (rdns) {
2051
- var _a;
2052
- var rdnses = ((_a = cookie().get(SESSION_WALLET_DETECTED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
2053
- return rdnses.includes(rdns);
2054
- };
2055
- FormoAnalyticsSession.prototype.markWalletDetected = function (rdns) {
2056
- var _a;
2057
- var rdnses = ((_a = cookie().get(SESSION_WALLET_DETECTED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
2058
- if (!rdnses.includes(rdns)) {
2059
- rdnses.push(rdns);
2060
- cookie().set(SESSION_WALLET_DETECTED_KEY, rdnses.join(","), {
2061
- // by the end of the day
2062
- expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
2063
- path: "/",
2064
- });
2065
- }
2066
- };
2067
- FormoAnalyticsSession.prototype.isWalletIdentified = function (address, rdns) {
2068
- var identifiedKey = this.generateIdentificationKey(address, rdns);
2069
- var cookieValue = cookie().get(SESSION_WALLET_IDENTIFIED_KEY);
2070
- var identifiedWallets = (cookieValue === null || cookieValue === void 0 ? void 0 : cookieValue.split(",")) || [];
2071
- var isIdentified = identifiedWallets.includes(identifiedKey);
2072
- logger.debug("Session: Checking wallet identification", {
2073
- identifiedKey: identifiedKey,
2074
- isIdentified: isIdentified,
2075
- hasRdns: !!rdns,
2076
- });
2077
- return isIdentified;
2078
- };
2079
- FormoAnalyticsSession.prototype.markWalletIdentified = function (address, rdns) {
2080
- var _a;
2081
- var identifiedKey = this.generateIdentificationKey(address, rdns);
2082
- var identifiedWallets = ((_a = cookie().get(SESSION_WALLET_IDENTIFIED_KEY)) === null || _a === void 0 ? void 0 : _a.split(",")) || [];
2083
- if (!identifiedWallets.includes(identifiedKey)) {
2084
- identifiedWallets.push(identifiedKey);
2085
- var newValue = identifiedWallets.join(",");
2086
- cookie().set(SESSION_WALLET_IDENTIFIED_KEY, newValue, {
2087
- // by the end of the day
2088
- expires: new Date(Date.now() + 86400 * 1000).toUTCString(),
2089
- path: "/",
2090
- });
2091
- logger.debug("Session: Marked wallet as identified", {
2092
- identifiedKey: identifiedKey,
2093
- hasRdns: !!rdns,
2094
- });
2095
- }
2096
- else {
2097
- logger.info("Session: Wallet already marked as identified", {
2098
- identifiedKey: identifiedKey,
2099
- existingWallets: identifiedWallets,
2100
- hasRdns: !!rdns,
2101
- });
2102
- }
2103
- };
2104
- return FormoAnalyticsSession;
2105
- }());
2106
2046
  //# sourceMappingURL=FormoAnalytics.js.map
@@ -46,13 +46,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
46
  }
47
47
  };
48
48
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
49
- import { createContext, useContext, useEffect, useRef, useState } from "react";
49
+ import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
50
50
  import { FormoAnalytics } from "./FormoAnalytics";
51
- import { initStorageManager, logger } from "./lib";
51
+ import { initStorageManager } from "./storage";
52
+ import { logger } from "./logger";
52
53
  var defaultContext = {
53
54
  chain: function () { return Promise.resolve(); },
54
55
  page: function () { return Promise.resolve(); },
55
56
  reset: function () { },
57
+ cleanup: function () { },
56
58
  detect: function () { return Promise.resolve(); },
57
59
  connect: function () { return Promise.resolve(); },
58
60
  disconnect: function () { return Promise.resolve(); },
@@ -82,36 +84,92 @@ export var FormoAnalyticsProvider = function (props) {
82
84
  var InitializedAnalytics = function (_a) {
83
85
  var writeKey = _a.writeKey, options = _a.options, children = _a.children;
84
86
  var _b = useState(defaultContext), sdk = _b[0], setSdk = _b[1];
85
- var initializedStartedRef = useRef(false);
87
+ var sdkRef = useRef(defaultContext);
86
88
  initStorageManager(writeKey);
89
+ // Create a stable key from options that ignores complex objects and functions
90
+ // We only care about serializable config values that would affect SDK behavior
91
+ var optionsKey = useMemo(function () {
92
+ if (!options)
93
+ return 'undefined';
94
+ // Extract only the serializable parts of options
95
+ var serializableOptions = {
96
+ tracking: options.tracking,
97
+ autocapture: options.autocapture,
98
+ apiHost: options.apiHost,
99
+ flushAt: options.flushAt,
100
+ flushInterval: options.flushInterval,
101
+ retryCount: options.retryCount,
102
+ maxQueueSize: options.maxQueueSize,
103
+ logger: options.logger,
104
+ referral: options.referral,
105
+ // For complex objects, just track their presence, not their content
106
+ hasProvider: !!options.provider,
107
+ hasWagmi: !!options.wagmi,
108
+ hasReady: !!options.ready,
109
+ };
110
+ try {
111
+ return JSON.stringify(serializableOptions);
112
+ }
113
+ catch (error) {
114
+ // Fallback to timestamp if serialization fails
115
+ logger.warn('Failed to serialize options, using timestamp', error);
116
+ return Date.now().toString();
117
+ }
118
+ }, [options]);
87
119
  useEffect(function () {
120
+ var isCleanedUp = false;
88
121
  var initialize = function () { return __awaiter(void 0, void 0, void 0, function () {
89
122
  var sdkInstance, error_1;
90
123
  return __generator(this, function (_a) {
91
124
  switch (_a.label) {
92
125
  case 0:
93
- if (initializedStartedRef.current)
94
- return [2 /*return*/];
95
- initializedStartedRef.current = true;
126
+ // Clean up existing SDK instance before creating a new one
127
+ if (sdkRef.current && sdkRef.current !== defaultContext) {
128
+ logger.log("Cleaning up existing FormoAnalytics SDK instance before re-initialization");
129
+ sdkRef.current.cleanup();
130
+ sdkRef.current = defaultContext;
131
+ setSdk(defaultContext);
132
+ }
96
133
  _a.label = 1;
97
134
  case 1:
98
135
  _a.trys.push([1, 3, , 4]);
99
136
  return [4 /*yield*/, FormoAnalytics.init(writeKey, options)];
100
137
  case 2:
101
138
  sdkInstance = _a.sent();
102
- setSdk(sdkInstance);
103
- logger.log("Successfully initialized");
139
+ // Only set SDK if the component hasn't been cleaned up during async initialization
140
+ if (!isCleanedUp) {
141
+ setSdk(sdkInstance);
142
+ sdkRef.current = sdkInstance;
143
+ logger.log("Successfully initialized FormoAnalytics SDK");
144
+ }
145
+ else {
146
+ // Component was unmounted during initialization, clean up immediately
147
+ logger.log("Component unmounted during initialization, cleaning up SDK");
148
+ sdkInstance.cleanup();
149
+ }
104
150
  return [3 /*break*/, 4];
105
151
  case 3:
106
152
  error_1 = _a.sent();
107
- logger.error("Failed to initialize", error_1);
153
+ if (!isCleanedUp) {
154
+ logger.error("Failed to initialize FormoAnalytics SDK", error_1);
155
+ }
108
156
  return [3 /*break*/, 4];
109
157
  case 4: return [2 /*return*/];
110
158
  }
111
159
  });
112
160
  }); };
113
161
  initialize();
114
- }, [writeKey, options]);
162
+ // Cleanup function to prevent memory leaks
163
+ // Using ref ensures we clean up the actual SDK instance, not the stale closure value
164
+ return function () {
165
+ isCleanedUp = true;
166
+ if (sdkRef.current && sdkRef.current !== defaultContext) {
167
+ logger.log("Cleaning up FormoAnalytics SDK instance");
168
+ sdkRef.current.cleanup();
169
+ sdkRef.current = defaultContext;
170
+ }
171
+ };
172
+ }, [writeKey, optionsKey]);
115
173
  return (_jsx(FormoAnalyticsContext.Provider, { value: sdk, children: children }));
116
174
  };
117
175
  export var useFormo = function () {
@@ -32,4 +32,4 @@ export declare function getConsentFlag(projectId: string, key: string): string |
32
32
  * @param key - The cookie key
33
33
  */
34
34
  export declare function removeConsentFlag(projectId: string, key: string): void;
35
- //# sourceMappingURL=consent.d.ts.map
35
+ //# sourceMappingURL=index.d.ts.map
@@ -94,4 +94,4 @@ function deleteCookieDirectly(cookieName) {
94
94
  }
95
95
  }
96
96
  }
97
- //# sourceMappingURL=consent.js.map
97
+ //# sourceMappingURL=index.js.map
@@ -1,6 +1,4 @@
1
1
  export declare const SESSION_TRAFFIC_SOURCE_KEY = "traffic-source";
2
- export declare const SESSION_WALLET_DETECTED_KEY = "wallet-detected";
3
- export declare const SESSION_WALLET_IDENTIFIED_KEY = "wallet-identified";
4
2
  export declare const SESSION_CURRENT_URL_KEY = "analytics-current-url";
5
3
  export declare const SESSION_USER_ID_KEY = "user-id";
6
4
  export declare const LOCAL_ANONYMOUS_ID_KEY = "anonymous-id";
@@ -1,6 +1,6 @@
1
1
  export var SESSION_TRAFFIC_SOURCE_KEY = "traffic-source";
2
- export var SESSION_WALLET_DETECTED_KEY = "wallet-detected";
3
- export var SESSION_WALLET_IDENTIFIED_KEY = "wallet-identified";
2
+ // SESSION_WALLET_DETECTED_KEY and SESSION_WALLET_IDENTIFIED_KEY
3
+ // are now defined in src/session/index.ts
4
4
  export var SESSION_CURRENT_URL_KEY = "analytics-current-url";
5
5
  export var SESSION_USER_ID_KEY = "user-id";
6
6
  export var LOCAL_ANONYMOUS_ID_KEY = "anonymous-id";
@@ -2,7 +2,7 @@ export var EVENTS_API_ORIGIN = "https://events.formo.so";
2
2
  export var EVENTS_API_HOST = "".concat(EVENTS_API_ORIGIN, "/v0/raw_events");
3
3
  export var EVENTS_API_REQUEST_HEADER = function (writeKey) { return ({
4
4
  "Content-Type": "application/json",
5
- Authorization: "Basic ".concat(writeKey),
5
+ Authorization: "Bearer ".concat(writeKey),
6
6
  }); };
7
7
  export var COUNTRY_LIST = {
8
8
  // Africa
@@ -1,4 +1,4 @@
1
- import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../../types";
1
+ import { Address, APIEvent, ChainID, IFormoEvent, IFormoEventContext, IFormoEventProperties, Nullable, Options, SignatureStatus, TransactionStatus } from "../types";
2
2
  import { IEventFactory } from "./type";
3
3
  declare class EventFactory implements IEventFactory {
4
4
  private options?;
@@ -45,15 +45,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
45
45
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
46
  }
47
47
  };
48
- import { COUNTRY_LIST, LOCAL_ANONYMOUS_ID_KEY, SESSION_TRAFFIC_SOURCE_KEY, } from "../../constants";
49
- import { toChecksumAddress, toSnakeCase } from "../../utils";
50
- import { getValidAddress } from "../../utils/address";
51
- import { getCurrentTimeFormatted } from "../../utils/timestamp";
52
- import { isUndefined } from "../../validators";
48
+ import { COUNTRY_LIST, LOCAL_ANONYMOUS_ID_KEY, SESSION_TRAFFIC_SOURCE_KEY, } from "../constants";
49
+ import { toChecksumAddress, toSnakeCase } from "../utils";
50
+ import { getValidAddress } from "../utils/address";
51
+ import { getCurrentTimeFormatted } from "../utils/timestamp";
52
+ import { isUndefined } from "../validators";
53
53
  import { logger } from "../logger";
54
54
  import mergeDeepRight from "../ramda/mergeDeepRight";
55
55
  import { session } from "../storage";
56
- import { version } from "../../version";
56
+ import { version } from "../version";
57
57
  import { CHANNEL, VERSION, PAGE_PROPERTIES_EXCLUDED_FIELDS } from "./constants";
58
58
  import { generateAnonymousId } from "./utils";
59
59
  import { detectBrowser } from "../browser/browsers";
@@ -1,4 +1,4 @@
1
- import { Address, APIEvent, Options } from "../../types";
1
+ import { Address, APIEvent, Options } from "../types";
2
2
  import { IEventQueue } from "../queue";
3
3
  import { IEventFactory, IEventManager } from "./type";
4
4
  /**
@@ -47,7 +47,7 @@ var __rest = (this && this.__rest) || function (s, e) {
47
47
  };
48
48
  import { logger } from "../logger";
49
49
  import { EventFactory } from "./EventFactory";
50
- import { isBlockedAddress } from "../../utils/address";
50
+ import { isBlockedAddress } from "../utils/address";
51
51
  /**
52
52
  * A service to generate valid event payloads and queue them for processing
53
53
  */
@@ -1,4 +1,4 @@
1
- import { Address, APIEvent, IFormoEvent } from "../../types";
1
+ import { Address, APIEvent, IFormoEvent } from "../types";
2
2
  export interface IEventManager {
3
3
  addEvent(event: APIEvent, address?: Address, userId?: string): Promise<void>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { AnonymousID } from "../../types";
1
+ import { AnonymousID } from "../types";
2
2
  declare const generateAnonymousId: (key: string) => AnonymousID;
3
3
  declare function getCookieDomain(hostname?: string): string;
4
4
  export { generateAnonymousId, getCookieDomain };
@@ -1,4 +1,4 @@
1
- import { generateNativeUUID } from "../../utils";
1
+ import { generateNativeUUID } from "../utils";
2
2
  import { cookie } from "../storage";
3
3
  var generateAnonymousId = function (key) {
4
4
  var storedAnonymousId = cookie().get(key);
@@ -1,3 +1,3 @@
1
1
  declare const _default: (input: string | URL | Request, init?: (RequestInit & import("fetch-retry").RequestInitRetryParams<typeof globalThis.fetch>) | undefined) => Promise<Response>;
2
2
  export default _default;
3
- //# sourceMappingURL=fetch.d.ts.map
3
+ //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,3 @@
1
1
  import fetch from "fetch-retry";
2
2
  export default fetch(global.fetch);
3
- //# sourceMappingURL=fetch.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Provider detection utilities for identifying wallet providers
3
+ */
4
+ import { EIP1193Provider } from "../types";
5
+ /**
6
+ * Default icon for providers without custom icons
7
+ */
8
+ export declare const DEFAULT_PROVIDER_ICON: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiBmaWxsPSIjRkZGIi8+CjxwYXRoIGQ9Ik0xNiA4TDggMjRoMTZMMTYgOHoiIGZpbGw9IiMzMzMiLz4KPC9zdmc+Cg==";
9
+ /**
10
+ * Common wallet provider flags used for detection
11
+ */
12
+ export interface WalletProviderFlags {
13
+ isMetaMask?: boolean;
14
+ isCoinbaseWallet?: boolean;
15
+ isWalletConnect?: boolean;
16
+ isTrust?: boolean;
17
+ isBraveWallet?: boolean;
18
+ isPhantom?: boolean;
19
+ }
20
+ /**
21
+ * Provider information returned by detection
22
+ */
23
+ export interface ProviderInfo {
24
+ name: string;
25
+ rdns: string;
26
+ uuid: string;
27
+ icon: `data:image/${string}`;
28
+ }
29
+ /**
30
+ * Attempts to detect information about an injected provider by examining
31
+ * common wallet-specific flags and properties.
32
+ *
33
+ * @param provider The injected provider to analyze
34
+ * @returns Provider information with fallback values if detection fails
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const provider = window.ethereum;
39
+ * const info = detectInjectedProviderInfo(provider);
40
+ * console.log(info.name); // "MetaMask" or "Injected Provider"
41
+ * ```
42
+ */
43
+ export declare function detectInjectedProviderInfo(provider: EIP1193Provider): ProviderInfo;
44
+ /**
45
+ * Validates that a provider implements the required EIP-1193 interface
46
+ *
47
+ * @param provider The provider to validate
48
+ * @returns true if the provider has all required methods
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * if (isValidProvider(window.ethereum)) {
53
+ * // Safe to use provider
54
+ * }
55
+ * ```
56
+ */
57
+ export declare function isValidProvider(provider: EIP1193Provider | undefined | null): provider is EIP1193Provider;
58
+ //# sourceMappingURL=detection.d.ts.map