@formo/analytics 1.11.5-alpha.4 → 1.11.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.
Files changed (57) hide show
  1. package/README.md +133 -37
  2. package/dist/cjs/src/FormoAnalytics.d.ts +72 -2
  3. package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
  4. package/dist/cjs/src/FormoAnalytics.js +282 -5
  5. package/dist/cjs/src/FormoAnalytics.js.map +1 -1
  6. package/dist/cjs/src/constants/events.d.ts +8 -0
  7. package/dist/cjs/src/constants/events.d.ts.map +1 -0
  8. package/dist/cjs/src/constants/events.js +12 -0
  9. package/dist/cjs/src/constants/events.js.map +1 -0
  10. package/dist/cjs/src/constants/index.d.ts +1 -0
  11. package/dist/cjs/src/constants/index.d.ts.map +1 -1
  12. package/dist/cjs/src/constants/index.js +1 -0
  13. package/dist/cjs/src/constants/index.js.map +1 -1
  14. package/dist/cjs/src/types/base.d.ts +1 -0
  15. package/dist/cjs/src/types/base.d.ts.map +1 -1
  16. package/dist/cjs/src/types/index.d.ts +1 -0
  17. package/dist/cjs/src/types/index.d.ts.map +1 -1
  18. package/dist/cjs/src/types/index.js +1 -0
  19. package/dist/cjs/src/types/index.js.map +1 -1
  20. package/dist/cjs/src/types/wallet.d.ts +11 -0
  21. package/dist/cjs/src/types/wallet.d.ts.map +1 -0
  22. package/dist/cjs/src/types/wallet.js +3 -0
  23. package/dist/cjs/src/types/wallet.js.map +1 -0
  24. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  25. package/dist/esm/src/FormoAnalytics.d.ts +72 -2
  26. package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
  27. package/dist/esm/src/FormoAnalytics.js +283 -6
  28. package/dist/esm/src/FormoAnalytics.js.map +1 -1
  29. package/dist/esm/src/constants/events.d.ts +8 -0
  30. package/dist/esm/src/constants/events.d.ts.map +1 -0
  31. package/dist/esm/src/constants/events.js +9 -0
  32. package/dist/esm/src/constants/events.js.map +1 -0
  33. package/dist/esm/src/constants/index.d.ts +1 -0
  34. package/dist/esm/src/constants/index.d.ts.map +1 -1
  35. package/dist/esm/src/constants/index.js +1 -0
  36. package/dist/esm/src/constants/index.js.map +1 -1
  37. package/dist/esm/src/types/base.d.ts +1 -0
  38. package/dist/esm/src/types/base.d.ts.map +1 -1
  39. package/dist/esm/src/types/index.d.ts +1 -0
  40. package/dist/esm/src/types/index.d.ts.map +1 -1
  41. package/dist/esm/src/types/index.js +1 -0
  42. package/dist/esm/src/types/index.js.map +1 -1
  43. package/dist/esm/src/types/wallet.d.ts +11 -0
  44. package/dist/esm/src/types/wallet.d.ts.map +1 -0
  45. package/dist/esm/src/types/wallet.js +2 -0
  46. package/dist/esm/src/types/wallet.js.map +1 -0
  47. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  48. package/dist/index.umd.min.js +1 -1
  49. package/dist/index.umd.min.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/FormoAnalytics.ts +322 -6
  52. package/src/constants/events.ts +7 -0
  53. package/src/constants/index.ts +1 -0
  54. package/src/global.d.ts +4 -0
  55. package/src/types/base.ts +2 -0
  56. package/src/types/index.ts +1 -0
  57. package/src/types/wallet.ts +12 -0
package/README.md CHANGED
@@ -33,21 +33,99 @@ Add the following to your `index.html`:
33
33
 
34
34
  ---
35
35
 
36
- ### 1. Install the npm package:
36
+ ### React Application
37
37
 
38
- Install @formo/analytics via yarn or npm:
38
+ **1. Install the SDK**
39
+ Install the Formo Analytics SDK using Yarn or NPM:
39
40
 
40
- ```
41
+ ```jsx
41
42
  yarn add @formo/analytics
42
43
  ```
43
44
 
44
45
  or
45
46
 
47
+ ```jsx
48
+ npm install @formo/analytics --save
49
+ ```
50
+
51
+ **2. Set up FormoAnalyticsProvider in Your Application**
52
+
53
+ Wrap your entire React application in the `FormoAnalyticsProvider` provided by the SDK.
54
+
55
+ ```jsx
56
+ //App.tsx (or App.js)
57
+ import React from 'react';
58
+ import ReactDOM from 'react-dom/client';
59
+ import { FormoAnalyticsProvider } from '@formo/analytics';
60
+ import App from './App';
61
+
62
+ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
63
+
64
+ root.render(
65
+ <React.StrictMode>
66
+ <FormoAnalyticsProvider apiKey="YOUR_API_KEY" projectId="YOUR_PROJECT_ID">
67
+ <App />
68
+ </FormoAnalyticsProvider>
69
+ </React.StrictMode>
70
+ );
71
+ ```
72
+
73
+ **3. Tracking Events and Page Views**
74
+
75
+ You can use the `useFormoAnalytics` hook from the SDK to track user interactions and page views.
76
+
77
+ Example: Tracking a Page View and Custom Event
78
+
79
+ ```jsx
80
+ import React, { useEffect } from 'react';
81
+ import { useFormoAnalytics } from '@formo/analytics';
82
+
83
+ const HomePage = () => {
84
+ const analytics = useFormoAnalytics();
85
+
86
+ useEffect(() => {
87
+ // Track a page view when the component is mounted
88
+ analytics?.page();
89
+
90
+ // Track a custom event
91
+ analytics?.track('custom_event', { key: 'value' });
92
+ }, [analytics]);
93
+
94
+ return <div>Welcome to the Home Page!</div>;
95
+ };
96
+
97
+ export default HomePage;
98
+ ```
99
+
100
+ **4. Folder Structure Example**
101
+
102
+ ```
103
+ /src
104
+ ├── /components
105
+ │ └── HomePage.tsx
106
+ ├── /App.tsx
107
+ └── /index.tsx (or index.js)
108
+ ```
109
+
110
+ ---
111
+
112
+ ### Next.js Application
113
+
114
+ **1. Install the npm package:**
115
+
116
+ Install `@formo/analytics` via yarn or npm:
117
+
118
+ ```jsx
119
+ yarn add @formo/analytics
46
120
  ```
121
+
122
+ or
123
+
124
+ ```jsx
47
125
  npm install @formo/analytics --save
48
126
  ```
49
127
 
50
- ### 2. Set up the `FormoAnalyticsProvider` in your application:
128
+ **2. Set up the `FormoAnalyticsProvider` in your application:**
51
129
 
52
130
  ```jsx
53
131
  // AnalyticsProvider.tsx
@@ -69,32 +147,6 @@ export const AnalyticsProvider: FC<FormoAnalyticsProviderProps> = ({
69
147
  projectId,
70
148
  children,
71
149
  }) => {
72
- // Initialize the FormoAnalytics SDK inside useEffect
73
- const [isInitialized, setIsInitialized] = useState(false);
74
-
75
- useEffect(() => {
76
- const initialize = async () => {
77
- try {
78
- await FormoAnalytics.init(apiKey, projectId);
79
- console.log('FormoAnalytics SDK initialized');
80
- setIsInitialized(true);
81
- } catch (error) {
82
- console.error('Failed to initialize FormoAnalytics SDK', error);
83
- }
84
- };
85
-
86
- initialize();
87
- }, [apiKey, projectId]);
88
-
89
- // To prevent app crashes, render a loading state during initialization
90
- if (!isInitialized) {
91
- return (
92
- <FormoAnalyticsProvider apiKey={apiKey} projectId={projectId}>
93
- Loading Content
94
- </FormoAnalyticsProvider>
95
- );
96
- }
97
-
98
150
  return (
99
151
  <FormoAnalyticsProvider apiKey={apiKey} projectId={projectId}>
100
152
  {children}
@@ -105,7 +157,7 @@ export const AnalyticsProvider: FC<FormoAnalyticsProviderProps> = ({
105
157
  export default AnalyticsProvider;
106
158
  ```
107
159
 
108
- ### 3. Integrating the Provider in Your Root Layout
160
+ **3. Integrating the Provider in Your Root Layout**
109
161
 
110
162
  Wrap your application with the newly created `AnalyticsProvider` in your main layout file:
111
163
 
@@ -129,7 +181,7 @@ export default function RootLayout({
129
181
  }
130
182
  ```
131
183
 
132
- ### 4. Using the SDK
184
+ **4. Using the SDK**
133
185
 
134
186
  Once the SDK is initialized, you can use its methods to track events and user interactions. Here’s how to do that:
135
187
 
@@ -158,10 +210,54 @@ const YourComponent = () => {
158
210
  };
159
211
  ```
160
212
 
161
- # Development notes
213
+ # Development Notes
214
+
215
+ If you want to contribute or run a local version of the Formo Analytics SDK, follow these steps:
216
+
217
+ 1. Build the SDK Locally
218
+
219
+ Run the following command to build both CommonJS and ESM versions of the SDK:
220
+
221
+ ```jsx
222
+ yarn build-cjs && yarn build-esm && yarn webpack --mode=production
223
+ ```
224
+
225
+ or if you're using NPM:
226
+
227
+ ```jsx
228
+ npm run build
229
+ ```
230
+
231
+ 2. Authenticate with NPM
232
+
233
+ To publish a new version of the package, log in to your NPM account:
234
+
235
+ ```jsx
236
+ npm login
237
+ ```
238
+
239
+ or:
240
+
241
+ ```jsx
242
+ npm adduser
243
+ ```
244
+
245
+ 3. Publish the Package
246
+
247
+ Run the following command to publish the package to NPM:
248
+
249
+ ```jsx
250
+ yarn publish
251
+ ```
252
+
253
+ or:
254
+
255
+ ```jsx
256
+ npm run publish
257
+ ```
162
258
 
163
- To run a local version of the script:
259
+ # Troubleshooting
164
260
 
165
- 1. Run `yarn build-cjs && yarn build-esm && yarn webpack --mode=production` or `npm run build` at the root level to build the script.
166
- 2. To authorize device, login into npmjs using `npm login` or `npm adduser`
167
- 3. Run `yarn publish` or `npm run publish` to publish new versions of the package.
261
+ **API Key Not Provided:** Ensure you pass a valid apiKey when initializing the SDK.
262
+ **SDK Not Initialized:** If you encounter issues with initialization, check the console logs for errors and ensure the project ID and API key are correct.
263
+ **Network Errors:** Verify that the analytics service URL is accessible from your network.
@@ -1,17 +1,57 @@
1
+ import { ChainID, EIP1193Provider } from './types';
1
2
  interface IFormoAnalytics {
3
+ /**
4
+ * Initializes the FormoAnalytics instance with the provided API key and project ID.
5
+ */
2
6
  init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
3
- identify(userData: any): void;
7
+ /**
8
+ * Identifies the user with the provided user data.
9
+ */
10
+ identify(userData: Record<string, any>): void;
11
+ /**
12
+ * Tracks page visit events.
13
+ */
4
14
  page(): void;
5
- track(eventName: string, eventData: any): void;
15
+ /**
16
+ * Connects to a wallet with the specified chain ID and address.
17
+ */
18
+ connect(params: {
19
+ account: string;
20
+ chainId: ChainID;
21
+ }): Promise<void>;
22
+ /**
23
+ * Disconnects the current wallet and clears the session information.
24
+ */
25
+ disconnect(attributes?: {
26
+ account?: string;
27
+ chainId?: ChainID;
28
+ }): void;
29
+ /**
30
+ * Tracks a specific event with a name and associated data.
31
+ */
32
+ track(eventName: string, eventData: Record<string, any>): void;
33
+ /**
34
+ * Switches the blockchain chain context and optionally logs additional attributes.
35
+ */
36
+ chain(attributes: {
37
+ chainId: ChainID;
38
+ account?: string;
39
+ }): void;
6
40
  }
7
41
  export declare class FormoAnalytics implements IFormoAnalytics {
8
42
  readonly apiKey: string;
9
43
  projectId: string;
44
+ private _provider?;
45
+ private _registeredProviderListeners;
46
+ private sessionKey;
10
47
  private config;
11
48
  private sessionIdKey;
12
49
  private timezoneToCountry;
50
+ currentChainId?: string | null;
51
+ currentConnectedAccount?: string;
13
52
  private constructor();
14
53
  static init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
54
+ get provider(): EIP1193Provider | undefined;
15
55
  private identifyUser;
16
56
  private getSessionId;
17
57
  private setSessionCookie;
@@ -20,7 +60,37 @@ export declare class FormoAnalytics implements IFormoAnalytics {
20
60
  private trackEvent;
21
61
  private maskSensitiveData;
22
62
  private trackPageHit;
63
+ private trackProvider;
64
+ private registerChainChangedListener;
65
+ private handleAccountDisconnected;
66
+ private onChainChanged;
67
+ private onAccountsChanged;
68
+ private registerAccountsChangedListener;
69
+ private getCurrentChainId;
70
+ private handleAccountConnected;
71
+ private getCurrentWallet;
72
+ /**
73
+ * Stores the wallet address in session storage when connected.
74
+ * @param address - The wallet address to store.
75
+ */
76
+ private storeWalletAddress;
77
+ /**
78
+ * Clears the wallet address from session storage when disconnected.
79
+ */
80
+ private clearWalletAddress;
23
81
  private buildApiUrl;
82
+ connect({ account, chainId }: {
83
+ account: string;
84
+ chainId: ChainID;
85
+ }): Promise<void>;
86
+ disconnect(attributes?: {
87
+ account?: string;
88
+ chainId?: ChainID;
89
+ }): Promise<void> | undefined;
90
+ chain({ chainId, account }: {
91
+ chainId: ChainID;
92
+ account?: string;
93
+ }): Promise<void>;
24
94
  init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
25
95
  identify(userData: any): void;
26
96
  page(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"FormoAnalytics.d.ts","sourceRoot":"","sources":["../../../src/FormoAnalytics.ts"],"names":[],"mappings":"AAKA,UAAU,eAAe;IACvB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACjE,QAAQ,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC;IAC9B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC;CAChD;AACD,qBAAa,cAAe,YAAW,eAAe;aAMlC,MAAM,EAAE,MAAM;IACvB,SAAS,EAAE,MAAM;IAN1B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,iBAAiB,CAAwC;IAEjE,OAAO;WASM,IAAI,CACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAU1B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,cAAc;YAUR,UAAU;IAyDxB,OAAO,CAAC,iBAAiB;IAkEzB,OAAO,CAAC,YAAY;IAoCpB,OAAO,CAAC,WAAW;IAiBnB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAMhE,QAAQ,CAAC,QAAQ,EAAE,GAAG;IAItB,IAAI;IAIJ,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;CAGxC"}
1
+ {"version":3,"file":"FormoAnalytics.d.ts","sourceRoot":"","sources":["../../../src/FormoAnalytics.ts"],"names":[],"mappings":"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"}
@@ -57,13 +57,20 @@ var utils_1 = require("./utils");
57
57
  var highlight_run_1 = require("highlight.run");
58
58
  var FormoAnalytics = /** @class */ (function () {
59
59
  function FormoAnalytics(apiKey, projectId) {
60
+ var _a;
60
61
  this.apiKey = apiKey;
61
62
  this.projectId = projectId;
63
+ this._registeredProviderListeners = {};
64
+ this.sessionKey = 'walletAddress';
62
65
  this.sessionIdKey = constants_1.SESSION_STORAGE_ID_KEY;
63
66
  this.timezoneToCountry = constants_1.COUNTRY_LIST;
64
67
  this.config = {
65
68
  token: this.apiKey,
66
69
  };
70
+ var provider = (window === null || window === void 0 ? void 0 : window.ethereum) || ((_a = window.web3) === null || _a === void 0 ? void 0 : _a.currentProvider);
71
+ if (provider) {
72
+ this.trackProvider(provider);
73
+ }
67
74
  }
68
75
  FormoAnalytics.init = function (apiKey, projectId) {
69
76
  return __awaiter(this, void 0, void 0, function () {
@@ -78,8 +85,15 @@ var FormoAnalytics = /** @class */ (function () {
78
85
  });
79
86
  });
80
87
  };
88
+ Object.defineProperty(FormoAnalytics.prototype, "provider", {
89
+ get: function () {
90
+ return this._provider;
91
+ },
92
+ enumerable: false,
93
+ configurable: true
94
+ });
81
95
  FormoAnalytics.prototype.identifyUser = function (userData) {
82
- this.trackEvent('identify', userData);
96
+ this.trackEvent(constants_1.Event.IDENTIFY, userData);
83
97
  };
84
98
  FormoAnalytics.prototype.getSessionId = function () {
85
99
  var existingSessionId = this.getCookieValue(this.sessionIdKey);
@@ -114,7 +128,7 @@ var FormoAnalytics = /** @class */ (function () {
114
128
  // Function to send tracking data
115
129
  FormoAnalytics.prototype.trackEvent = function (action, payload) {
116
130
  return __awaiter(this, void 0, void 0, function () {
117
- var maxRetries, attempt, apiUrl, requestData, sendRequest;
131
+ var maxRetries, attempt, apiUrl, address, requestData, sendRequest;
118
132
  var _this = this;
119
133
  return __generator(this, function (_a) {
120
134
  switch (_a.label) {
@@ -123,9 +137,12 @@ var FormoAnalytics = /** @class */ (function () {
123
137
  attempt = 0;
124
138
  this.setSessionCookie(this.config.domain);
125
139
  apiUrl = this.buildApiUrl();
140
+ return [4 /*yield*/, this.getCurrentWallet()];
141
+ case 1:
142
+ address = _a.sent();
126
143
  requestData = {
127
144
  project_id: this.projectId,
128
- address: '', // TODO: get cached / session wallet address
145
+ address: address,
129
146
  session_id: this.getSessionId(),
130
147
  timestamp: new Date().toISOString(),
131
148
  action: action,
@@ -170,7 +187,7 @@ var FormoAnalytics = /** @class */ (function () {
170
187
  });
171
188
  }); };
172
189
  return [4 /*yield*/, sendRequest()];
173
- case 1:
190
+ case 2:
174
191
  _a.sent();
175
192
  return [2 /*return*/];
176
193
  }
@@ -254,7 +271,7 @@ var FormoAnalytics = /** @class */ (function () {
254
271
  setTimeout(function () {
255
272
  var url = new URL(window.location.href);
256
273
  var params = new URLSearchParams(url.search);
257
- _this.trackEvent('page_hit', {
274
+ _this.trackEvent(constants_1.Event.PAGE, {
258
275
  'user-agent': window.navigator.userAgent,
259
276
  locale: language,
260
277
  location: location,
@@ -268,6 +285,221 @@ var FormoAnalytics = /** @class */ (function () {
268
285
  });
269
286
  }, 300);
270
287
  };
288
+ FormoAnalytics.prototype.trackProvider = function (provider) {
289
+ if (provider === this._provider) {
290
+ return;
291
+ }
292
+ this.currentChainId = undefined;
293
+ this.currentConnectedAccount = undefined;
294
+ if (this._provider) {
295
+ var eventNames = Object.keys(this._registeredProviderListeners);
296
+ for (var _i = 0, eventNames_1 = eventNames; _i < eventNames_1.length; _i++) {
297
+ var eventName = eventNames_1[_i];
298
+ this._provider.removeListener(eventName, this._registeredProviderListeners[eventName]);
299
+ delete this._registeredProviderListeners[eventName];
300
+ }
301
+ }
302
+ this._provider = provider;
303
+ this.getCurrentWallet();
304
+ this.registerAccountsChangedListener();
305
+ this.registerChainChangedListener();
306
+ };
307
+ FormoAnalytics.prototype.registerChainChangedListener = function () {
308
+ var _this = this;
309
+ var _a;
310
+ var listener = function () {
311
+ var args = [];
312
+ for (var _i = 0; _i < arguments.length; _i++) {
313
+ args[_i] = arguments[_i];
314
+ }
315
+ return _this.onChainChanged(args[0]);
316
+ };
317
+ (_a = this.provider) === null || _a === void 0 ? void 0 : _a.on('chainChanged', listener);
318
+ this._registeredProviderListeners['chainChanged'] = listener;
319
+ };
320
+ FormoAnalytics.prototype.handleAccountDisconnected = function () {
321
+ if (!this.currentConnectedAccount) {
322
+ return;
323
+ }
324
+ var disconnectAttributes = {
325
+ address: this.currentConnectedAccount,
326
+ chainId: this.currentChainId,
327
+ };
328
+ this.currentChainId = undefined;
329
+ this.currentConnectedAccount = undefined;
330
+ this.clearWalletAddress();
331
+ return this.trackEvent(constants_1.Event.DISCONNECT, disconnectAttributes);
332
+ };
333
+ FormoAnalytics.prototype.onChainChanged = function (chainIdHex) {
334
+ return __awaiter(this, void 0, void 0, function () {
335
+ var res, err_1;
336
+ return __generator(this, function (_a) {
337
+ switch (_a.label) {
338
+ case 0:
339
+ this.currentChainId = parseInt(chainIdHex).toString();
340
+ if (!!this.currentConnectedAccount) return [3 /*break*/, 4];
341
+ if (!this.provider) {
342
+ console.error('error', 'FormoAnalytics::onChainChanged: provider not found. CHAIN_CHANGED not reported');
343
+ return [2 /*return*/];
344
+ }
345
+ _a.label = 1;
346
+ case 1:
347
+ _a.trys.push([1, 3, , 4]);
348
+ return [4 /*yield*/, this.provider.request({
349
+ method: 'eth_accounts',
350
+ })];
351
+ case 2:
352
+ res = _a.sent();
353
+ if (!res || res.length === 0) {
354
+ console.error('error', 'FormoAnalytics::onChainChanged: unable to get account. eth_accounts returned empty');
355
+ return [2 /*return*/];
356
+ }
357
+ this.currentConnectedAccount = res[0];
358
+ return [3 /*break*/, 4];
359
+ case 3:
360
+ err_1 = _a.sent();
361
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
362
+ if (err_1.code !== 4001) {
363
+ // 4001: The request is rejected by the user , see https://docs.metamask.io/wallet/reference/provider-api/#errors
364
+ console.error('error', "FormoAnalytics::onChainChanged: unable to get account. eth_accounts threw an error", err_1);
365
+ return [2 /*return*/];
366
+ }
367
+ return [3 /*break*/, 4];
368
+ case 4: return [2 /*return*/, this.chain({
369
+ chainId: this.currentChainId,
370
+ account: this.currentConnectedAccount,
371
+ })];
372
+ }
373
+ });
374
+ });
375
+ };
376
+ FormoAnalytics.prototype.onAccountsChanged = function (accounts) {
377
+ return __awaiter(this, void 0, void 0, function () {
378
+ var newAccount;
379
+ return __generator(this, function (_a) {
380
+ if (accounts.length > 0) {
381
+ newAccount = accounts[0];
382
+ if (newAccount !== this.currentConnectedAccount) {
383
+ this.handleAccountConnected(newAccount);
384
+ }
385
+ }
386
+ else {
387
+ this.handleAccountDisconnected();
388
+ }
389
+ return [2 /*return*/];
390
+ });
391
+ });
392
+ };
393
+ FormoAnalytics.prototype.registerAccountsChangedListener = function () {
394
+ var _this = this;
395
+ var _a, _b;
396
+ var listener = function () {
397
+ var args = [];
398
+ for (var _i = 0; _i < arguments.length; _i++) {
399
+ args[_i] = arguments[_i];
400
+ }
401
+ return _this.onAccountsChanged(args[0]);
402
+ };
403
+ (_a = this._provider) === null || _a === void 0 ? void 0 : _a.on('accountsChanged', listener);
404
+ this._registeredProviderListeners['accountsChanged'] = listener;
405
+ var handleAccountDisconnected = this.handleAccountDisconnected.bind(this);
406
+ (_b = this._provider) === null || _b === void 0 ? void 0 : _b.on('disconnect', handleAccountDisconnected);
407
+ this._registeredProviderListeners['disconnect'] = handleAccountDisconnected;
408
+ };
409
+ FormoAnalytics.prototype.getCurrentChainId = function () {
410
+ return __awaiter(this, void 0, void 0, function () {
411
+ var chainIdHex;
412
+ var _a;
413
+ return __generator(this, function (_b) {
414
+ switch (_b.label) {
415
+ case 0:
416
+ if (!this.provider) {
417
+ console.error('FormoAnalytics::getCurrentChainId: provider not set');
418
+ }
419
+ return [4 /*yield*/, ((_a = this.provider) === null || _a === void 0 ? void 0 : _a.request({
420
+ method: 'eth_chainId',
421
+ }))];
422
+ case 1:
423
+ chainIdHex = _b.sent();
424
+ // Because we're connected, the chainId cannot be null
425
+ if (!chainIdHex) {
426
+ console.error("FormoAnalytics::getCurrentChainId: chainIdHex is: ".concat(chainIdHex));
427
+ }
428
+ return [2 /*return*/, parseInt(chainIdHex, 16).toString()];
429
+ }
430
+ });
431
+ });
432
+ };
433
+ FormoAnalytics.prototype.handleAccountConnected = function (account) {
434
+ return __awaiter(this, void 0, void 0, function () {
435
+ var _a;
436
+ return __generator(this, function (_b) {
437
+ switch (_b.label) {
438
+ case 0:
439
+ if (account === this.currentConnectedAccount) {
440
+ // We have already reported this account
441
+ return [2 /*return*/];
442
+ }
443
+ else {
444
+ this.currentConnectedAccount = account;
445
+ }
446
+ _a = this;
447
+ return [4 /*yield*/, this.getCurrentChainId()];
448
+ case 1:
449
+ _a.currentChainId = _b.sent();
450
+ this.connect({ account: account, chainId: this.currentChainId });
451
+ this.storeWalletAddress(account);
452
+ return [2 /*return*/];
453
+ }
454
+ });
455
+ });
456
+ };
457
+ FormoAnalytics.prototype.getCurrentWallet = function () {
458
+ return __awaiter(this, void 0, void 0, function () {
459
+ var sessionData, parsedData, sessionExpiry, currentTime;
460
+ return __generator(this, function (_a) {
461
+ if (!this.provider) {
462
+ console.warn('FormoAnalytics::getCurrentWallet: the provider is not set');
463
+ return [2 /*return*/];
464
+ }
465
+ sessionData = sessionStorage.getItem(this.sessionKey);
466
+ if (!sessionData) {
467
+ return [2 /*return*/, null];
468
+ }
469
+ parsedData = JSON.parse(sessionData);
470
+ sessionExpiry = 30 * 60 * 1000;
471
+ currentTime = Date.now();
472
+ if (currentTime - parsedData.timestamp > sessionExpiry) {
473
+ console.warn('Session expired. Ignoring wallet address.');
474
+ sessionStorage.removeItem(this.sessionKey); // Clear expired session data
475
+ return [2 /*return*/, ''];
476
+ }
477
+ this.handleAccountConnected(parsedData.address);
478
+ return [2 /*return*/, parsedData.address || ''];
479
+ });
480
+ });
481
+ };
482
+ /**
483
+ * Stores the wallet address in session storage when connected.
484
+ * @param address - The wallet address to store.
485
+ */
486
+ FormoAnalytics.prototype.storeWalletAddress = function (address) {
487
+ if (!address) {
488
+ console.error('No wallet address provided to store.');
489
+ return;
490
+ }
491
+ var sessionData = {
492
+ address: address,
493
+ timestamp: Date.now(),
494
+ };
495
+ sessionStorage.setItem(this.sessionKey, JSON.stringify(sessionData));
496
+ };
497
+ /**
498
+ * Clears the wallet address from session storage when disconnected.
499
+ */
500
+ FormoAnalytics.prototype.clearWalletAddress = function () {
501
+ sessionStorage.removeItem(this.sessionKey);
502
+ };
271
503
  // Function to build the API URL
272
504
  FormoAnalytics.prototype.buildApiUrl = function () {
273
505
  var _a = this.config, host = _a.host, proxy = _a.proxy, token = _a.token, _b = _a.dataSource, dataSource = _b === void 0 ? 'analytics_events' : _b;
@@ -282,6 +514,51 @@ var FormoAnalytics = /** @class */ (function () {
282
514
  }
283
515
  return 'Error: No token provided';
284
516
  };
517
+ FormoAnalytics.prototype.connect = function (_a) {
518
+ var account = _a.account, chainId = _a.chainId;
519
+ if (!chainId) {
520
+ throw new Error('FormoAnalytics::connect: chainId cannot be empty');
521
+ }
522
+ if (!account) {
523
+ throw new Error('FormoAnalytics::connect: account cannot be empty');
524
+ }
525
+ this.currentChainId = chainId.toString();
526
+ this.currentConnectedAccount = account;
527
+ return this.trackEvent(constants_1.Event.CONNECT, {
528
+ chainId: chainId,
529
+ address: account,
530
+ });
531
+ };
532
+ FormoAnalytics.prototype.disconnect = function (attributes) {
533
+ var account = (attributes === null || attributes === void 0 ? void 0 : attributes.account) || this.currentConnectedAccount;
534
+ if (!account) {
535
+ // We have most likely already reported this disconnection with the automatic
536
+ // `disconnect` detection
537
+ return;
538
+ }
539
+ var chainId = (attributes === null || attributes === void 0 ? void 0 : attributes.chainId) || this.currentChainId;
540
+ var eventAttributes = __assign({ account: account }, (chainId && { chainId: chainId }));
541
+ this.currentChainId = undefined;
542
+ this.currentConnectedAccount = undefined;
543
+ return this.trackEvent(constants_1.Event.DISCONNECT, eventAttributes);
544
+ };
545
+ FormoAnalytics.prototype.chain = function (_a) {
546
+ var chainId = _a.chainId, account = _a.account;
547
+ if (!chainId || Number(chainId) === 0) {
548
+ throw new Error('FormoAnalytics::chain: chainId cannot be empty or 0');
549
+ }
550
+ if (!account && !this.currentConnectedAccount) {
551
+ throw new Error('FormoAnalytics::chain: account was empty and no previous account has been recorded. You can either pass an account or call connect() first');
552
+ }
553
+ if (isNaN(Number(chainId))) {
554
+ throw new Error('FormoAnalytics::chain: chainId must be a valid hex or decimal number');
555
+ }
556
+ this.currentChainId = chainId.toString();
557
+ return this.trackEvent(constants_1.Event.CHAIN_CHANGED, {
558
+ chainId: chainId,
559
+ account: account || this.currentConnectedAccount,
560
+ });
561
+ };
285
562
  FormoAnalytics.prototype.init = function (apiKey, projectId) {
286
563
  var instance = new FormoAnalytics(apiKey, projectId);
287
564
  return Promise.resolve(instance);