@formo/analytics 1.11.10 → 1.11.12

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 (82) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/src/FormoAnalytics.ts +70 -133
  4. package/src/types/base.ts +1 -1
  5. package/dist/223.index.umd.min.js +0 -125
  6. package/dist/223.index.umd.min.js.map +0 -1
  7. package/dist/cjs/src/FormoAnalytics.d.ts +0 -96
  8. package/dist/cjs/src/FormoAnalytics.d.ts.map +0 -1
  9. package/dist/cjs/src/FormoAnalytics.js +0 -580
  10. package/dist/cjs/src/FormoAnalytics.js.map +0 -1
  11. package/dist/cjs/src/FormoAnalyticsProvider.d.ts +0 -7
  12. package/dist/cjs/src/FormoAnalyticsProvider.d.ts.map +0 -1
  13. package/dist/cjs/src/FormoAnalyticsProvider.js +0 -127
  14. package/dist/cjs/src/FormoAnalyticsProvider.js.map +0 -1
  15. package/dist/cjs/src/constants/config.d.ts +0 -559
  16. package/dist/cjs/src/constants/config.d.ts.map +0 -1
  17. package/dist/cjs/src/constants/config.js +0 -570
  18. package/dist/cjs/src/constants/config.js.map +0 -1
  19. package/dist/cjs/src/constants/events.d.ts +0 -8
  20. package/dist/cjs/src/constants/events.d.ts.map +0 -1
  21. package/dist/cjs/src/constants/events.js +0 -12
  22. package/dist/cjs/src/constants/events.js.map +0 -1
  23. package/dist/cjs/src/constants/index.d.ts +0 -3
  24. package/dist/cjs/src/constants/index.d.ts.map +0 -1
  25. package/dist/cjs/src/constants/index.js +0 -19
  26. package/dist/cjs/src/constants/index.js.map +0 -1
  27. package/dist/cjs/src/index.d.ts +0 -4
  28. package/dist/cjs/src/index.d.ts.map +0 -1
  29. package/dist/cjs/src/index.js.map +0 -1
  30. package/dist/cjs/src/types/base.d.ts +0 -12
  31. package/dist/cjs/src/types/base.d.ts.map +0 -1
  32. package/dist/cjs/src/types/base.js +0 -3
  33. package/dist/cjs/src/types/base.js.map +0 -1
  34. package/dist/cjs/src/types/index.d.ts +0 -3
  35. package/dist/cjs/src/types/index.d.ts.map +0 -1
  36. package/dist/cjs/src/types/index.js +0 -19
  37. package/dist/cjs/src/types/index.js.map +0 -1
  38. package/dist/cjs/src/types/wallet.d.ts +0 -11
  39. package/dist/cjs/src/types/wallet.d.ts.map +0 -1
  40. package/dist/cjs/src/types/wallet.js +0 -3
  41. package/dist/cjs/src/types/wallet.js.map +0 -1
  42. package/dist/cjs/tsconfig.tsbuildinfo +0 -1
  43. package/dist/esm/src/FormoAnalytics.d.ts +0 -96
  44. package/dist/esm/src/FormoAnalytics.d.ts.map +0 -1
  45. package/dist/esm/src/FormoAnalytics.js +0 -574
  46. package/dist/esm/src/FormoAnalytics.js.map +0 -1
  47. package/dist/esm/src/FormoAnalyticsProvider.d.ts +0 -7
  48. package/dist/esm/src/FormoAnalyticsProvider.d.ts.map +0 -1
  49. package/dist/esm/src/FormoAnalyticsProvider.js +0 -122
  50. package/dist/esm/src/FormoAnalyticsProvider.js.map +0 -1
  51. package/dist/esm/src/constants/config.d.ts +0 -559
  52. package/dist/esm/src/constants/config.d.ts.map +0 -1
  53. package/dist/esm/src/constants/config.js +0 -567
  54. package/dist/esm/src/constants/config.js.map +0 -1
  55. package/dist/esm/src/constants/events.d.ts +0 -8
  56. package/dist/esm/src/constants/events.d.ts.map +0 -1
  57. package/dist/esm/src/constants/events.js +0 -9
  58. package/dist/esm/src/constants/events.js.map +0 -1
  59. package/dist/esm/src/constants/index.d.ts +0 -3
  60. package/dist/esm/src/constants/index.d.ts.map +0 -1
  61. package/dist/esm/src/constants/index.js +0 -3
  62. package/dist/esm/src/constants/index.js.map +0 -1
  63. package/dist/esm/src/index.d.ts +0 -4
  64. package/dist/esm/src/index.d.ts.map +0 -1
  65. package/dist/esm/src/index.js +0 -4
  66. package/dist/esm/src/index.js.map +0 -1
  67. package/dist/esm/src/types/base.d.ts +0 -12
  68. package/dist/esm/src/types/base.d.ts.map +0 -1
  69. package/dist/esm/src/types/base.js +0 -2
  70. package/dist/esm/src/types/base.js.map +0 -1
  71. package/dist/esm/src/types/index.d.ts +0 -3
  72. package/dist/esm/src/types/index.d.ts.map +0 -1
  73. package/dist/esm/src/types/index.js +0 -3
  74. package/dist/esm/src/types/index.js.map +0 -1
  75. package/dist/esm/src/types/wallet.d.ts +0 -11
  76. package/dist/esm/src/types/wallet.d.ts.map +0 -1
  77. package/dist/esm/src/types/wallet.js +0 -2
  78. package/dist/esm/src/types/wallet.js.map +0 -1
  79. package/dist/esm/tsconfig.tsbuildinfo +0 -1
  80. package/dist/index.umd.min.js +0 -3
  81. package/dist/index.umd.min.js.LICENSE.txt +0 -31
  82. package/dist/index.umd.min.js.map +0 -1
package/README.md CHANGED
@@ -217,7 +217,7 @@ yarn build-cjs && yarn build-esm && yarn webpack --mode=production
217
217
  or if you're using NPM:
218
218
 
219
219
  ```jsx
220
- npm run build
220
+ yarn build
221
221
  ```
222
222
 
223
223
  2. Authenticate with NPM
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formo/analytics",
3
- "version": "1.11.10",
3
+ "version": "1.11.12",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/getformo/sdk.git"
@@ -63,7 +63,7 @@
63
63
  "sinon-chai": "^3.7.0",
64
64
  "ts-loader": "^9.3.1",
65
65
  "ts-node": "^10.8.2",
66
- "typescript": "^5.7.2",
66
+ "typescript": "^5.6.3",
67
67
  "webpack": "^5.74.0",
68
68
  "webpack-cli": "^4.10.0"
69
69
  },
@@ -1,18 +1,18 @@
1
- import axios from 'axios';
1
+ import axios from "axios";
2
2
  import {
3
3
  COUNTRY_LIST,
4
4
  EVENTS_API_URL,
5
5
  SESSION_STORAGE_ID_KEY,
6
6
  Event,
7
- } from './constants';
8
- import { H } from 'highlight.run';
9
- import { ChainID, EIP1193Provider, Options } from './types';
7
+ } from "./constants";
8
+ import { H } from "highlight.run";
9
+ import { ChainID, EIP1193Provider, Options } from "./types";
10
10
 
11
11
  interface IFormoAnalytics {
12
12
  /**
13
13
  * Initializes the FormoAnalytics instance with the provided API key and project ID.
14
14
  */
15
- init(apiKey: string, options?: Options): Promise<FormoAnalytics>;
15
+ init(apiKey: string, options: Options): Promise<FormoAnalytics>;
16
16
 
17
17
  /**
18
18
  * Tracks page visit events.
@@ -49,7 +49,7 @@ export class FormoAnalytics implements IFormoAnalytics {
49
49
  (...args: unknown[]) => void
50
50
  > = {};
51
51
 
52
- private walletAddressSessionKey = 'walletAddress';
52
+ private walletAddressSessionKey = "walletAddress";
53
53
  private config: Config;
54
54
  private sessionIdKey: string = SESSION_STORAGE_ID_KEY;
55
55
  private timezoneToCountry: Record<string, string> = COUNTRY_LIST;
@@ -72,10 +72,7 @@ export class FormoAnalytics implements IFormoAnalytics {
72
72
  }
73
73
  }
74
74
 
75
- static async init(
76
- apiKey: string,
77
- options?: Options
78
- ): Promise<FormoAnalytics> {
75
+ static async init(apiKey: string, options: Options): Promise<FormoAnalytics> {
79
76
  const config = {
80
77
  token: apiKey,
81
78
  };
@@ -101,7 +98,7 @@ export class FormoAnalytics implements IFormoAnalytics {
101
98
  }
102
99
 
103
100
  private getOrigin(): string {
104
- return window.location.origin || 'ORIGIN_NOT_FOUND';
101
+ return window.location.origin || "ORIGIN_NOT_FOUND";
105
102
  }
106
103
 
107
104
  // Function to set the session cookie
@@ -120,8 +117,8 @@ export class FormoAnalytics implements IFormoAnalytics {
120
117
 
121
118
  // Function to get a cookie value by name
122
119
  private getCookieValue(name: string): string | undefined {
123
- const cookies = document.cookie.split(';').reduce((acc, cookie) => {
124
- const [key, value] = cookie.split('=');
120
+ const cookies = document.cookie.split(";").reduce((acc, cookie) => {
121
+ const [key, value] = cookie.split("=");
125
122
  acc[key.trim()] = value;
126
123
  return acc;
127
124
  }, {} as Record<string, string>);
@@ -141,8 +138,12 @@ export class FormoAnalytics implements IFormoAnalytics {
141
138
  session_id: this.getSessionId(),
142
139
  timestamp: new Date().toISOString(),
143
140
  action,
144
- version: '1',
145
- payload,
141
+ version: "1",
142
+ payload: {
143
+ // common fields
144
+ ...this.getCommonTrackingFields(),
145
+ ...payload,
146
+ },
146
147
  };
147
148
 
148
149
  const sendRequest = async (): Promise<void> => {
@@ -152,14 +153,14 @@ export class FormoAnalytics implements IFormoAnalytics {
152
153
  JSON.stringify(requestData),
153
154
  {
154
155
  headers: {
155
- 'Content-Type': 'application/json',
156
+ "Content-Type": "application/json",
156
157
  Authorization: `Bearer ${this.apiKey}`,
157
158
  },
158
159
  }
159
160
  );
160
161
 
161
162
  if (response.status >= 200 && response.status < 300) {
162
- console.log('Event sent successfully:', action);
163
+ console.log("Event sent successfully:", action);
163
164
  } else {
164
165
  throw new Error(`Failed with status: ${response.status}`);
165
166
  }
@@ -189,46 +190,49 @@ export class FormoAnalytics implements IFormoAnalytics {
189
190
  await sendRequest();
190
191
  }
191
192
 
192
- // Function to track page hits
193
- private trackPageHit() {
194
- if (window.__nightmare || window.navigator.webdriver || window.Cypress)
195
- return;
196
-
193
+ private getCommonTrackingFields() {
197
194
  let location: string | undefined;
198
- let language: string;
195
+ let language: string = "en";
199
196
  try {
200
197
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
201
198
  location = this.timezoneToCountry[timezone];
202
199
  language =
203
200
  navigator.languages && navigator.languages.length
204
201
  ? navigator.languages[0]
205
- : navigator.language || 'en';
202
+ : navigator.language || "en";
206
203
  } catch (error) {
207
- console.error('Error resolving timezone or language:', error);
204
+ console.error("Error resolving timezone or language:", error);
208
205
  }
209
206
 
207
+ const url = new URL(window.location.href);
208
+ const params = new URLSearchParams(url.search);
209
+ return {
210
+ "user-agent": window.navigator.userAgent,
211
+ locale: language,
212
+ location,
213
+ referrer: document.referrer,
214
+ utm_source: params.get("utm_source"),
215
+ utm_medium: params.get("utm_medium"),
216
+ utm_campaign: params.get("utm_campaign"),
217
+ ref: params.get("ref"),
218
+ };
219
+ }
220
+
221
+ // Function to track page hits
222
+ private trackPageHit() {
223
+ if (window.__nightmare || window.navigator.webdriver || window.Cypress)
224
+ return;
225
+
210
226
  setTimeout(() => {
211
- const url = new URL(window.location.href);
212
- const params = new URLSearchParams(url.search);
213
227
  this.trackEvent(Event.PAGE, {
214
- 'user-agent': window.navigator.userAgent,
215
- address: this.currentConnectedAddress,
216
- locale: language,
217
- location: location,
218
- referrer: document.referrer,
219
228
  pathname: window.location.pathname,
220
229
  href: window.location.href,
221
- utm_source: params.get('utm_source'),
222
- utm_medium: params.get('utm_medium'),
223
- utm_campaign: params.get('utm_campaign'),
224
- ref: params.get('ref'),
225
230
  });
226
231
  }, 300);
227
232
  }
228
233
 
229
234
  private trackProvider(provider: EIP1193Provider) {
230
235
  if (provider === this._provider) {
231
- console.log('Provider already tracked.');
232
236
  return;
233
237
  }
234
238
 
@@ -246,7 +250,6 @@ export class FormoAnalytics implements IFormoAnalytics {
246
250
  }
247
251
  }
248
252
 
249
- console.log('Tracking new provider:', provider);
250
253
  this._provider = provider;
251
254
 
252
255
  this.getCurrentWallet();
@@ -254,33 +257,14 @@ export class FormoAnalytics implements IFormoAnalytics {
254
257
  this.registerChainChangedListener();
255
258
  }
256
259
 
257
- private async getAndStoreConnectedAddress(): Promise<string | null> {
258
- console.warn(
259
- 'Session data missing. Attempting to fetch address from provider.'
260
- );
261
- try {
262
- const accounts = await this.fetchAccounts();
263
- if (accounts && accounts.length > 0) {
264
- const address = accounts[0];
265
- this.storeWalletAddress(address);
266
- return address;
267
- }
268
- } catch (err) {
269
- console.error('Failed to fetch accounts from provider:', err);
270
- }
271
- return null;
272
- }
273
-
274
260
  private async getCurrentWallet() {
275
261
  if (!this.provider) {
276
- console.warn('FormoAnalytics::getCurrentWallet: the provider is not set');
262
+ console.warn("FormoAnalytics::getCurrentWallet: the provider is not set");
277
263
  return;
278
264
  }
279
-
280
265
  const sessionData = sessionStorage.getItem(this.walletAddressSessionKey);
281
-
282
266
  if (!sessionData) {
283
- return await this.getAndStoreConnectedAddress();
267
+ return null;
284
268
  }
285
269
 
286
270
  const parsedData = JSON.parse(sessionData);
@@ -288,70 +272,22 @@ export class FormoAnalytics implements IFormoAnalytics {
288
272
  const currentTime = Date.now();
289
273
 
290
274
  if (currentTime - parsedData.timestamp > sessionExpiry) {
291
- console.warn('Session expired. Ignoring wallet address.');
275
+ console.warn("Session expired. Ignoring wallet address.");
292
276
  sessionStorage.removeItem(this.walletAddressSessionKey); // Clear expired session data
293
- return '';
277
+ return "";
294
278
  }
295
279
 
296
280
  this.onAddressConnected(parsedData.address);
297
- return parsedData.address || '';
298
- }
299
-
300
- // Utility to fetch accounts
301
- private async fetchAccounts(): Promise<string[] | null> {
302
- try {
303
- const res: string[] | null | undefined = await this.provider?.request({
304
- method: 'eth_accounts',
305
- });
306
- if (!res || res.length === 0) {
307
- console.error(
308
- 'error',
309
- 'FormoAnalytics::fetchAccounts: unable to get account. eth_accounts returned empty'
310
- );
311
- return null;
312
- }
313
- return res;
314
- } catch (err) {
315
- if ((err as any).code !== 4001) {
316
- console.error(
317
- 'error',
318
- 'FormoAnalytics::fetchAccounts: eth_accounts threw an error',
319
- err
320
- );
321
- }
322
- return null;
323
- }
324
- }
325
-
326
- // Utility to fetch chain ID
327
- private async fetchChainId(): Promise<string | null> {
328
- try {
329
- const chainIdHex = await this.provider?.request<string>({
330
- method: 'eth_chainId',
331
- });
332
- if (!chainIdHex) {
333
- console.error(
334
- 'FormoAnalytics::fetchChainId: chainIdHex is null or undefined'
335
- );
336
- return null;
337
- }
338
- return chainIdHex;
339
- } catch (err) {
340
- console.error(
341
- 'error',
342
- 'FormoAnalytics::fetchChainId: eth_chainId threw an error',
343
- err
344
- );
345
- return null;
346
- }
281
+ return parsedData.address || "";
347
282
  }
348
283
 
349
284
  private async getCurrentChainId(): Promise<string> {
350
285
  if (!this.provider) {
351
- console.error('FormoAnalytics::getCurrentChainId: provider not set');
286
+ console.error("FormoAnalytics::getCurrentChainId: provider not set");
352
287
  }
353
-
354
- const chainIdHex = await this.fetchChainId();
288
+ const chainIdHex = await this.provider?.request<string>({
289
+ method: "eth_chainId",
290
+ });
355
291
  // Because we're connected, the chainId cannot be null
356
292
  if (!chainIdHex) {
357
293
  console.error(
@@ -366,19 +302,19 @@ export class FormoAnalytics implements IFormoAnalytics {
366
302
  const listener = (...args: unknown[]) =>
367
303
  this.onAddressChanged(args[0] as string[]);
368
304
 
369
- this._provider?.on('accountsChanged', listener);
370
- this._registeredProviderListeners['accountsChanged'] = listener;
305
+ this._provider?.on("accountsChanged", listener);
306
+ this._registeredProviderListeners["accountsChanged"] = listener;
371
307
 
372
308
  const onAddressDisconnected = this.onAddressDisconnected.bind(this);
373
- this._provider?.on('disconnect', onAddressDisconnected);
374
- this._registeredProviderListeners['disconnect'] = onAddressDisconnected;
309
+ this._provider?.on("disconnect", onAddressDisconnected);
310
+ this._registeredProviderListeners["disconnect"] = onAddressDisconnected;
375
311
  }
376
312
 
377
313
  private registerChainChangedListener() {
378
314
  const listener = (...args: unknown[]) =>
379
315
  this.onChainChanged(args[0] as string);
380
- this.provider?.on('chainChanged', listener);
381
- this._registeredProviderListeners['chainChanged'] = listener;
316
+ this.provider?.on("chainChanged", listener);
317
+ this._registeredProviderListeners["chainChanged"] = listener;
382
318
  }
383
319
 
384
320
  private async onAddressChanged(addresses: string[]) {
@@ -427,19 +363,20 @@ export class FormoAnalytics implements IFormoAnalytics {
427
363
  if (!this.currentConnectedAddress) {
428
364
  if (!this.provider) {
429
365
  console.error(
430
- 'error',
431
- 'FormoAnalytics::onChainChanged: provider not found. CHAIN_CHANGED not reported'
366
+ "error",
367
+ "FormoAnalytics::onChainChanged: provider not found. CHAIN_CHANGED not reported"
432
368
  );
433
369
  return;
434
370
  }
435
371
 
436
372
  try {
437
- const res: string[] | null | undefined = await this.fetchAccounts();
438
-
373
+ const res: string[] | null | undefined = await this.provider.request({
374
+ method: "eth_accounts",
375
+ });
439
376
  if (!res || res.length === 0) {
440
377
  console.error(
441
- 'error',
442
- 'FormoAnalytics::onChainChanged: unable to get account. eth_accounts returned empty'
378
+ "error",
379
+ "FormoAnalytics::onChainChanged: unable to get account. eth_accounts returned empty"
443
380
  );
444
381
  return;
445
382
  }
@@ -450,7 +387,7 @@ export class FormoAnalytics implements IFormoAnalytics {
450
387
  if ((err as any).code !== 4001) {
451
388
  // 4001: The request is rejected by the user , see https://docs.metamask.io/wallet/reference/provider-api/#errors
452
389
  console.error(
453
- 'error',
390
+ "error",
454
391
  `FormoAnalytics::onChainChanged: unable to get account. eth_accounts threw an error`,
455
392
  err
456
393
  );
@@ -471,7 +408,7 @@ export class FormoAnalytics implements IFormoAnalytics {
471
408
  */
472
409
  private storeWalletAddress(address: string): void {
473
410
  if (!address) {
474
- console.error('No wallet address provided to store.');
411
+ console.error("No wallet address provided to store.");
475
412
  return;
476
413
  }
477
414
 
@@ -500,10 +437,10 @@ export class FormoAnalytics implements IFormoAnalytics {
500
437
 
501
438
  connect({ chainId, address }: { chainId: ChainID; address: string }) {
502
439
  if (!chainId) {
503
- throw new Error('FormoAnalytics::connect: chain ID cannot be empty');
440
+ throw new Error("FormoAnalytics::connect: chain ID cannot be empty");
504
441
  }
505
442
  if (!address) {
506
- throw new Error('FormoAnalytics::connect: address cannot be empty');
443
+ throw new Error("FormoAnalytics::connect: address cannot be empty");
507
444
  }
508
445
 
509
446
  this.currentChainId = chainId.toString();
@@ -535,16 +472,16 @@ export class FormoAnalytics implements IFormoAnalytics {
535
472
 
536
473
  chain({ chainId, address }: { chainId: ChainID; address?: string }) {
537
474
  if (!chainId || Number(chainId) === 0) {
538
- throw new Error('FormoAnalytics::chain: chainId cannot be empty or 0');
475
+ throw new Error("FormoAnalytics::chain: chainId cannot be empty or 0");
539
476
  }
540
477
  if (!address && !this.currentConnectedAddress) {
541
478
  throw new Error(
542
- 'FormoAnalytics::chain: address was empty and no previous address has been recorded. You can either pass an address or call connect() first'
479
+ "FormoAnalytics::chain: address was empty and no previous address has been recorded. You can either pass an address or call connect() first"
543
480
  );
544
481
  }
545
482
  if (isNaN(Number(chainId))) {
546
483
  throw new Error(
547
- 'FormoAnalytics::chain: chainId must be a valid hex or decimal number'
484
+ "FormoAnalytics::chain: chainId must be a valid hex or decimal number"
548
485
  );
549
486
  }
550
487
 
package/src/types/base.ts CHANGED
@@ -8,7 +8,7 @@ export interface Options {
8
8
 
9
9
  export interface FormoAnalyticsProviderProps {
10
10
  apiKey: string;
11
- options?: Options;
11
+ options: Options;
12
12
  disabled?: boolean;
13
13
  children: React.ReactNode;
14
14
  }