@formo/analytics 1.11.5 → 1.11.6-alpha.1

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 (56) hide show
  1. package/README.md +10 -18
  2. package/dist/cjs/src/FormoAnalytics.d.ts +30 -37
  3. package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
  4. package/dist/cjs/src/FormoAnalytics.js +164 -247
  5. package/dist/cjs/src/FormoAnalytics.js.map +1 -1
  6. package/dist/cjs/src/FormoAnalyticsProvider.d.ts +1 -1
  7. package/dist/cjs/src/FormoAnalyticsProvider.d.ts.map +1 -1
  8. package/dist/cjs/src/FormoAnalyticsProvider.js +3 -3
  9. package/dist/cjs/src/FormoAnalyticsProvider.js.map +1 -1
  10. package/dist/cjs/src/constants/config.d.ts +1 -1
  11. package/dist/cjs/src/constants/config.d.ts.map +1 -1
  12. package/dist/cjs/src/constants/config.js +2 -2
  13. package/dist/cjs/src/constants/config.js.map +1 -1
  14. package/dist/cjs/src/types/base.d.ts +5 -1
  15. package/dist/cjs/src/types/base.d.ts.map +1 -1
  16. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  17. package/dist/esm/src/FormoAnalytics.d.ts +30 -37
  18. package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
  19. package/dist/esm/src/FormoAnalytics.js +165 -248
  20. package/dist/esm/src/FormoAnalytics.js.map +1 -1
  21. package/dist/esm/src/FormoAnalyticsProvider.d.ts +1 -1
  22. package/dist/esm/src/FormoAnalyticsProvider.d.ts.map +1 -1
  23. package/dist/esm/src/FormoAnalyticsProvider.js +3 -3
  24. package/dist/esm/src/FormoAnalyticsProvider.js.map +1 -1
  25. package/dist/esm/src/constants/config.d.ts +1 -1
  26. package/dist/esm/src/constants/config.d.ts.map +1 -1
  27. package/dist/esm/src/constants/config.js +1 -1
  28. package/dist/esm/src/constants/config.js.map +1 -1
  29. package/dist/esm/src/types/base.d.ts +5 -1
  30. package/dist/esm/src/types/base.d.ts.map +1 -1
  31. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  32. package/dist/index.umd.min.js +1 -1
  33. package/dist/index.umd.min.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/FormoAnalytics.ts +164 -254
  36. package/src/FormoAnalyticsProvider.tsx +3 -6
  37. package/src/constants/config.ts +1 -1
  38. package/src/types/base.ts +7 -1
  39. package/dist/cjs/src/utils/index.d.ts +0 -2
  40. package/dist/cjs/src/utils/index.d.ts.map +0 -1
  41. package/dist/cjs/src/utils/index.js +0 -18
  42. package/dist/cjs/src/utils/index.js.map +0 -1
  43. package/dist/cjs/src/utils/isNotEmptyObject.d.ts +0 -2
  44. package/dist/cjs/src/utils/isNotEmptyObject.d.ts.map +0 -1
  45. package/dist/cjs/src/utils/isNotEmptyObject.js +0 -9
  46. package/dist/cjs/src/utils/isNotEmptyObject.js.map +0 -1
  47. package/dist/esm/src/utils/index.d.ts +0 -2
  48. package/dist/esm/src/utils/index.d.ts.map +0 -1
  49. package/dist/esm/src/utils/index.js +0 -2
  50. package/dist/esm/src/utils/index.js.map +0 -1
  51. package/dist/esm/src/utils/isNotEmptyObject.d.ts +0 -2
  52. package/dist/esm/src/utils/isNotEmptyObject.d.ts.map +0 -1
  53. package/dist/esm/src/utils/isNotEmptyObject.js +0 -6
  54. package/dist/esm/src/utils/isNotEmptyObject.js.map +0 -1
  55. package/src/utils/index.ts +0 -1
  56. package/src/utils/isNotEmptyObject.ts +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formo/analytics",
3
- "version": "1.11.5",
3
+ "version": "1.11.6-alpha.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/getformo/sdk.git"
@@ -1,24 +1,18 @@
1
1
  import axios from 'axios';
2
2
  import {
3
3
  COUNTRY_LIST,
4
- EVENTS_API,
4
+ EVENTS_API_URL,
5
5
  SESSION_STORAGE_ID_KEY,
6
6
  Event,
7
7
  } from './constants';
8
- import { isNotEmpty } from './utils';
9
8
  import { H } from 'highlight.run';
10
- import { ChainID, EIP1193Provider, RequestArguments } from './types';
9
+ import { ChainID, EIP1193Provider, Options } from './types';
11
10
 
12
11
  interface IFormoAnalytics {
13
12
  /**
14
13
  * Initializes the FormoAnalytics instance with the provided API key and project ID.
15
14
  */
16
- init(apiKey: string, projectId: string): Promise<FormoAnalytics>;
17
-
18
- /**
19
- * Identifies the user with the provided user data.
20
- */
21
- identify(userData: Record<string, any>): void;
15
+ init(apiKey: string, options: Options): Promise<FormoAnalytics>;
22
16
 
23
17
  /**
24
18
  * Tracks page visit events.
@@ -28,22 +22,25 @@ interface IFormoAnalytics {
28
22
  /**
29
23
  * Connects to a wallet with the specified chain ID and address.
30
24
  */
31
- connect(params: { account: string; chainId: ChainID }): Promise<void>;
25
+ connect(params: { chainId: ChainID; address: string }): Promise<void>;
32
26
 
33
27
  /**
34
28
  * Disconnects the current wallet and clears the session information.
35
29
  */
36
- disconnect(attributes?: { account?: string; chainId?: ChainID }): void;
30
+ disconnect(params?: { chainId?: ChainID; address?: string }): void;
37
31
 
38
32
  /**
39
- * Tracks a specific event with a name and associated data.
33
+ * Switches the blockchain chain context and optionally logs additional params.
40
34
  */
41
- track(eventName: string, eventData: Record<string, any>): void;
35
+ chain(params: { chainId: ChainID; address?: string }): void;
42
36
 
43
37
  /**
44
- * Switches the blockchain chain context and optionally logs additional attributes.
38
+ * Tracks a specific event with a name and associated data.
45
39
  */
46
- chain(attributes: { chainId: ChainID; account?: string }): void;
40
+ track(eventName: string, eventData: Record<string, any>): void;
41
+ }
42
+ interface Config {
43
+ token: string;
47
44
  }
48
45
  export class FormoAnalytics implements IFormoAnalytics {
49
46
  private _provider?: EIP1193Provider;
@@ -52,36 +49,34 @@ export class FormoAnalytics implements IFormoAnalytics {
52
49
  (...args: unknown[]) => void
53
50
  > = {};
54
51
 
55
- private sessionKey = 'walletAddress';
56
- private config: any;
52
+ private walletAddressSessionKey = 'walletAddress';
53
+ private config: Config;
57
54
  private sessionIdKey: string = SESSION_STORAGE_ID_KEY;
58
55
  private timezoneToCountry: Record<string, string> = COUNTRY_LIST;
59
56
 
60
57
  currentChainId?: string | null;
61
- currentConnectedAccount?: string;
58
+ currentConnectedAddress?: string;
62
59
 
63
60
  private constructor(
64
61
  public readonly apiKey: string,
65
- public projectId: string
62
+ public options: Options = {}
66
63
  ) {
67
64
  this.config = {
68
65
  token: this.apiKey,
69
66
  };
70
67
 
71
- const provider = window?.ethereum || window.web3?.currentProvider;
68
+ const provider =
69
+ window?.ethereum || window.web3?.currentProvider || options?.provider;
72
70
  if (provider) {
73
71
  this.trackProvider(provider);
74
72
  }
75
73
  }
76
74
 
77
- static async init(
78
- apiKey: string,
79
- projectId: string
80
- ): Promise<FormoAnalytics> {
75
+ static async init(apiKey: string, options: Options): Promise<FormoAnalytics> {
81
76
  const config = {
82
77
  token: apiKey,
83
78
  };
84
- const instance = new FormoAnalytics(apiKey, projectId);
79
+ const instance = new FormoAnalytics(apiKey, options);
85
80
  instance.config = config;
86
81
 
87
82
  return instance;
@@ -91,10 +86,6 @@ export class FormoAnalytics implements IFormoAnalytics {
91
86
  return this._provider;
92
87
  }
93
88
 
94
- private identifyUser(userData: any) {
95
- this.trackEvent(Event.IDENTIFY, userData);
96
- }
97
-
98
89
  private getSessionId() {
99
90
  const existingSessionId = this.getCookieValue(this.sessionIdKey);
100
91
 
@@ -106,13 +97,16 @@ export class FormoAnalytics implements IFormoAnalytics {
106
97
  return newSessionId;
107
98
  }
108
99
 
100
+ private getOrigin(): string {
101
+ return window.location.origin || 'ORIGIN_NOT_FOUND';
102
+ }
103
+
109
104
  // Function to set the session cookie
110
- private setSessionCookie(domain?: string) {
105
+ private setSessionCookie(): void {
111
106
  const sessionId = this.getSessionId();
112
- let cookieValue = `${this.sessionIdKey}=${sessionId}; Max-Age=1800; path=/; secure`;
113
- if (domain) {
114
- cookieValue += `; domain=${domain}`;
115
- }
107
+ let cookieValue = `${
108
+ this.sessionIdKey
109
+ }=${sessionId}; Max-Age=1800; path=/; secure; domain=${this.getOrigin()}`;
116
110
  document.cookie = cookieValue;
117
111
  }
118
112
 
@@ -136,27 +130,32 @@ export class FormoAnalytics implements IFormoAnalytics {
136
130
  const maxRetries = 3;
137
131
  let attempt = 0;
138
132
 
139
- this.setSessionCookie(this.config.domain);
140
- const apiUrl = this.buildApiUrl();
133
+ this.setSessionCookie();
141
134
  const address = await this.getCurrentWallet();
142
135
 
136
+ console.log('address:', address);
137
+
143
138
  const requestData = {
144
- project_id: this.projectId,
145
139
  address: address,
146
140
  session_id: this.getSessionId(),
147
141
  timestamp: new Date().toISOString(),
148
- action: action,
142
+ action,
149
143
  version: '1',
150
- payload: isNotEmpty(payload) ? this.maskSensitiveData(payload) : payload,
144
+ payload,
151
145
  };
152
146
 
153
147
  const sendRequest = async (): Promise<void> => {
154
148
  try {
155
- const response = await axios.post(apiUrl, JSON.stringify(requestData), {
156
- headers: {
157
- 'Content-Type': 'application/json',
158
- },
159
- });
149
+ const response = await axios.post(
150
+ EVENTS_API_URL,
151
+ JSON.stringify(requestData),
152
+ {
153
+ headers: {
154
+ 'Content-Type': 'application/json',
155
+ Authorization: `Bearer ${this.apiKey}`,
156
+ },
157
+ }
158
+ );
160
159
 
161
160
  if (response.status >= 200 && response.status < 300) {
162
161
  console.log('Event sent successfully:', action);
@@ -189,72 +188,6 @@ export class FormoAnalytics implements IFormoAnalytics {
189
188
  await sendRequest();
190
189
  }
191
190
 
192
- // Function to mask sensitive data in the payload
193
- private maskSensitiveData(
194
- data: string | undefined | null
195
- ): Record<string, any> | null {
196
- // Check if data is null or undefined
197
- if (data === null || data === undefined) {
198
- console.warn('Data is null or undefined, returning null');
199
- return null;
200
- }
201
-
202
- // Check if data is a string; if so, parse it to an object
203
- if (typeof data === 'string') {
204
- let parsedData: Record<string, any>;
205
- try {
206
- parsedData = JSON.parse(data);
207
- } catch (error) {
208
- console.error('Failed to parse JSON:', error);
209
- return null; // Return null if parsing fails
210
- }
211
-
212
- const sensitiveFields = [
213
- 'username',
214
- 'user',
215
- 'user_id',
216
- 'password',
217
- 'email',
218
- 'phone',
219
- ];
220
-
221
- // Create a new object to store masked data
222
- const maskedData = { ...parsedData };
223
-
224
- // Mask sensitive fields
225
- sensitiveFields.forEach((field) => {
226
- if (field in maskedData) {
227
- maskedData[field] = '********'; // Replace value with masked string
228
- }
229
- });
230
-
231
- return maskedData; // Return the new object with masked fields
232
- } else if (typeof data === 'object') {
233
- // If data is already an object, handle masking directly
234
- const sensitiveFields = [
235
- 'username',
236
- 'user',
237
- 'user_id',
238
- 'password',
239
- 'email',
240
- 'phone',
241
- ];
242
-
243
- const maskedData = { ...(data as Record<string, any>) };
244
-
245
- // Mask sensitive fields
246
- sensitiveFields.forEach((field) => {
247
- if (field in maskedData) {
248
- maskedData[field] = '********'; // Replace value with masked string
249
- }
250
- });
251
-
252
- return maskedData; // Return the new object with masked fields
253
- }
254
-
255
- return data;
256
- }
257
-
258
191
  // Function to track page hits
259
192
  private trackPageHit() {
260
193
  if (window.__nightmare || window.navigator.webdriver || window.Cypress)
@@ -278,6 +211,7 @@ export class FormoAnalytics implements IFormoAnalytics {
278
211
  const params = new URLSearchParams(url.search);
279
212
  this.trackEvent(Event.PAGE, {
280
213
  'user-agent': window.navigator.userAgent,
214
+ address: this.currentConnectedAddress,
281
215
  locale: language,
282
216
  location: location,
283
217
  referrer: document.referrer,
@@ -297,7 +231,7 @@ export class FormoAnalytics implements IFormoAnalytics {
297
231
  }
298
232
 
299
233
  this.currentChainId = undefined;
300
- this.currentConnectedAccount = undefined;
234
+ this.currentConnectedAddress = undefined;
301
235
 
302
236
  if (this._provider) {
303
237
  const eventNames = Object.keys(this._registeredProviderListeners);
@@ -313,10 +247,65 @@ export class FormoAnalytics implements IFormoAnalytics {
313
247
  this._provider = provider;
314
248
 
315
249
  this.getCurrentWallet();
316
- this.registerAccountsChangedListener();
250
+ this.registerAddressChangedListener();
317
251
  this.registerChainChangedListener();
318
252
  }
319
253
 
254
+ private async getCurrentWallet() {
255
+ if (!this.provider) {
256
+ console.warn('FormoAnalytics::getCurrentWallet: the provider is not set');
257
+ return;
258
+ }
259
+ const sessionData = sessionStorage.getItem(this.walletAddressSessionKey);
260
+ if (!sessionData) {
261
+ return null;
262
+ }
263
+
264
+ console.log(sessionData);
265
+
266
+ const parsedData = JSON.parse(sessionData);
267
+ const sessionExpiry = 30 * 60 * 1000; // 30 minutes
268
+ const currentTime = Date.now();
269
+
270
+ if (currentTime - parsedData.timestamp > sessionExpiry) {
271
+ console.warn('Session expired. Ignoring wallet address.');
272
+ sessionStorage.removeItem(this.walletAddressSessionKey); // Clear expired session data
273
+ return '';
274
+ }
275
+
276
+ this.onAddressConnected(parsedData.address);
277
+ return parsedData.address || '';
278
+ }
279
+
280
+ private async getCurrentChainId(): Promise<string> {
281
+ if (!this.provider) {
282
+ console.error('FormoAnalytics::getCurrentChainId: provider not set');
283
+ }
284
+ const chainIdHex = await this.provider?.request<string>({
285
+ method: 'eth_chainId',
286
+ });
287
+ // Because we're connected, the chainId cannot be null
288
+ if (!chainIdHex) {
289
+ console.error(
290
+ `FormoAnalytics::getCurrentChainId: chainIdHex is: ${chainIdHex}`
291
+ );
292
+ }
293
+
294
+ return parseInt(chainIdHex as string, 16).toString();
295
+ }
296
+
297
+ private registerAddressChangedListener() {
298
+ const listener = (...args: unknown[]) =>
299
+ this.onAddressChanged(args[0] as string[]);
300
+
301
+ this._provider?.on('accountsChanged', listener);
302
+ this._registeredProviderListeners['accountsChanged'] = listener;
303
+
304
+ const onAddressDisconnected = this.onAddressDisconnected.bind(this);
305
+ this._provider?.on('disconnect', onAddressDisconnected);
306
+ this._registeredProviderListeners['disconnect'] = onAddressDisconnected;
307
+ }
308
+
320
309
  private registerChainChangedListener() {
321
310
  const listener = (...args: unknown[]) =>
322
311
  this.onChainChanged(args[0] as string);
@@ -324,25 +313,50 @@ export class FormoAnalytics implements IFormoAnalytics {
324
313
  this._registeredProviderListeners['chainChanged'] = listener;
325
314
  }
326
315
 
327
- private handleAccountDisconnected() {
328
- if (!this.currentConnectedAccount) {
316
+ private async onAddressChanged(addresses: string[]) {
317
+ if (addresses.length > 0) {
318
+ const newAccount = addresses[0];
319
+ if (newAccount !== this.currentConnectedAddress) {
320
+ this.onAddressConnected(newAccount);
321
+ }
322
+ } else {
323
+ this.onAddressDisconnected();
324
+ }
325
+ }
326
+
327
+ private async onAddressConnected(address: string) {
328
+ if (address === this.currentConnectedAddress) {
329
+ // We have already reported this address
330
+ return;
331
+ } else {
332
+ this.currentConnectedAddress = address;
333
+ }
334
+
335
+ this.currentChainId = await this.getCurrentChainId();
336
+
337
+ this.connect({ chainId: this.currentChainId, address });
338
+ this.storeWalletAddress(address);
339
+ }
340
+
341
+ private onAddressDisconnected() {
342
+ if (!this.currentConnectedAddress) {
329
343
  return;
330
344
  }
331
345
 
332
- const disconnectAttributes = {
333
- address: this.currentConnectedAccount,
334
- chainId: this.currentChainId,
346
+ const payload = {
347
+ chain_id: this.currentChainId,
348
+ address: this.currentConnectedAddress,
335
349
  };
336
350
  this.currentChainId = undefined;
337
- this.currentConnectedAccount = undefined;
351
+ this.currentConnectedAddress = undefined;
338
352
  this.clearWalletAddress();
339
353
 
340
- return this.trackEvent(Event.DISCONNECT, disconnectAttributes);
354
+ return this.trackEvent(Event.DISCONNECT, payload);
341
355
  }
342
356
 
343
357
  private async onChainChanged(chainIdHex: string) {
344
358
  this.currentChainId = parseInt(chainIdHex).toString();
345
- if (!this.currentConnectedAccount) {
359
+ if (!this.currentConnectedAddress) {
346
360
  if (!this.provider) {
347
361
  console.error(
348
362
  'error',
@@ -363,7 +377,7 @@ export class FormoAnalytics implements IFormoAnalytics {
363
377
  return;
364
378
  }
365
379
 
366
- this.currentConnectedAccount = res[0];
380
+ this.currentConnectedAddress = res[0];
367
381
  } catch (err) {
368
382
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
369
383
  if ((err as any).code !== 4001) {
@@ -380,90 +394,10 @@ export class FormoAnalytics implements IFormoAnalytics {
380
394
 
381
395
  return this.chain({
382
396
  chainId: this.currentChainId,
383
- account: this.currentConnectedAccount,
397
+ address: this.currentConnectedAddress,
384
398
  });
385
399
  }
386
400
 
387
- private async onAccountsChanged(accounts: string[]) {
388
- if (accounts.length > 0) {
389
- const newAccount = accounts[0];
390
- if (newAccount !== this.currentConnectedAccount) {
391
- this.handleAccountConnected(newAccount);
392
- }
393
- } else {
394
- this.handleAccountDisconnected();
395
- }
396
- }
397
-
398
- private registerAccountsChangedListener() {
399
- const listener = (...args: unknown[]) =>
400
- this.onAccountsChanged(args[0] as string[]);
401
-
402
- this._provider?.on('accountsChanged', listener);
403
- this._registeredProviderListeners['accountsChanged'] = listener;
404
-
405
- const handleAccountDisconnected = this.handleAccountDisconnected.bind(this);
406
- this._provider?.on('disconnect', handleAccountDisconnected);
407
- this._registeredProviderListeners['disconnect'] = handleAccountDisconnected;
408
- }
409
-
410
- private async getCurrentChainId(): Promise<string> {
411
- if (!this.provider) {
412
- console.error('FormoAnalytics::getCurrentChainId: provider not set');
413
- }
414
-
415
- const chainIdHex = await this.provider?.request<string>({
416
- method: 'eth_chainId',
417
- });
418
- // Because we're connected, the chainId cannot be null
419
- if (!chainIdHex) {
420
- console.error(
421
- `FormoAnalytics::getCurrentChainId: chainIdHex is: ${chainIdHex}`
422
- );
423
- }
424
-
425
- return parseInt(chainIdHex as string, 16).toString();
426
- }
427
-
428
- private async handleAccountConnected(account: string) {
429
- if (account === this.currentConnectedAccount) {
430
- // We have already reported this account
431
- return;
432
- } else {
433
- this.currentConnectedAccount = account;
434
- }
435
-
436
- this.currentChainId = await this.getCurrentChainId();
437
-
438
- this.connect({ account, chainId: this.currentChainId });
439
- this.storeWalletAddress(account);
440
- }
441
-
442
- private async getCurrentWallet() {
443
- if (!this.provider) {
444
- console.warn('FormoAnalytics::getCurrentWallet: the provider is not set');
445
- return;
446
- }
447
- const sessionData = sessionStorage.getItem(this.sessionKey);
448
-
449
- if (!sessionData) {
450
- return null;
451
- }
452
-
453
- const parsedData = JSON.parse(sessionData);
454
- const sessionExpiry = 30 * 60 * 1000; // 30 minutes
455
- const currentTime = Date.now();
456
-
457
- if (currentTime - parsedData.timestamp > sessionExpiry) {
458
- console.warn('Session expired. Ignoring wallet address.');
459
- sessionStorage.removeItem(this.sessionKey); // Clear expired session data
460
- return '';
461
- }
462
-
463
- this.handleAccountConnected(parsedData.address);
464
- return parsedData.address || '';
465
- }
466
-
467
401
  /**
468
402
  * Stores the wallet address in session storage when connected.
469
403
  * @param address - The wallet address to store.
@@ -479,82 +413,68 @@ export class FormoAnalytics implements IFormoAnalytics {
479
413
  timestamp: Date.now(),
480
414
  };
481
415
 
482
- sessionStorage.setItem(this.sessionKey, JSON.stringify(sessionData));
416
+ sessionStorage.setItem(
417
+ this.walletAddressSessionKey,
418
+ JSON.stringify(sessionData)
419
+ );
483
420
  }
484
421
 
485
422
  /**
486
423
  * Clears the wallet address from session storage when disconnected.
487
424
  */
488
425
  private clearWalletAddress(): void {
489
- sessionStorage.removeItem(this.sessionKey);
426
+ sessionStorage.removeItem(this.walletAddressSessionKey);
490
427
  }
491
428
 
492
- // Function to build the API URL
493
- private buildApiUrl(): string {
494
- const { host, proxy, token, dataSource = 'analytics_events' } = this.config;
495
- if (token) {
496
- if (proxy) {
497
- return `${proxy}/api/tracking`;
498
- }
499
- if (host) {
500
- return `${host.replace(
501
- /\/+$/,
502
- ''
503
- )}/v0/events?name=${dataSource}&token=${token}`;
504
- }
505
- return `${EVENTS_API}?name=${dataSource}&token=${token}`;
506
- }
507
- return 'Error: No token provided';
429
+ init(apiKey: string, options: Options): Promise<FormoAnalytics> {
430
+ const instance = new FormoAnalytics(apiKey, options);
431
+ return Promise.resolve(instance);
508
432
  }
509
433
 
510
- connect({ account, chainId }: { account: string; chainId: ChainID }) {
434
+ connect({ chainId, address }: { chainId: ChainID; address: string }) {
511
435
  if (!chainId) {
512
- throw new Error('FormoAnalytics::connect: chainId cannot be empty');
436
+ throw new Error('FormoAnalytics::connect: chain ID cannot be empty');
513
437
  }
514
- if (!account) {
515
- throw new Error('FormoAnalytics::connect: account cannot be empty');
438
+ if (!address) {
439
+ throw new Error('FormoAnalytics::connect: address cannot be empty');
516
440
  }
517
441
 
518
442
  this.currentChainId = chainId.toString();
519
- this.currentConnectedAccount = account;
443
+ this.currentConnectedAddress = address;
520
444
 
521
445
  return this.trackEvent(Event.CONNECT, {
522
- chainId,
523
- address: account,
446
+ chain_id: chainId,
447
+ address: address,
524
448
  });
525
449
  }
526
450
 
527
- disconnect(attributes?: { account?: string; chainId?: ChainID }) {
528
- const account = attributes?.account || this.currentConnectedAccount;
529
- if (!account) {
451
+ disconnect(params?: { chainId?: ChainID; address?: string }) {
452
+ const address = params?.address || this.currentConnectedAddress;
453
+ if (!address) {
530
454
  // We have most likely already reported this disconnection with the automatic
531
455
  // `disconnect` detection
532
456
  return;
533
457
  }
534
458
 
535
- const chainId = attributes?.chainId || this.currentChainId;
536
- const eventAttributes = {
537
- account,
538
- ...(chainId && { chainId }),
459
+ const payload = {
460
+ chain_id: params?.chainId || this.currentChainId,
461
+ address,
539
462
  };
540
-
541
463
  this.currentChainId = undefined;
542
- this.currentConnectedAccount = undefined;
464
+ this.currentConnectedAddress = undefined;
543
465
 
544
- return this.trackEvent(Event.DISCONNECT, eventAttributes);
466
+ return this.trackEvent(Event.DISCONNECT, payload);
545
467
  }
546
468
 
547
- chain({ chainId, account }: { chainId: ChainID; account?: string }) {
469
+ chain({ chainId, address }: { chainId: ChainID; address?: string }) {
548
470
  if (!chainId || Number(chainId) === 0) {
549
471
  throw new Error('FormoAnalytics::chain: chainId cannot be empty or 0');
550
472
  }
551
-
552
- if (!account && !this.currentConnectedAccount) {
473
+ if (!address && !this.currentConnectedAddress) {
553
474
  throw new Error(
554
- 'FormoAnalytics::chain: account was empty and no previous account has been recorded. You can either pass an account or call connect() first'
475
+ 'FormoAnalytics::chain: address was empty and no previous address has been recorded. You can either pass an address or call connect() first'
555
476
  );
556
477
  }
557
-
558
478
  if (isNaN(Number(chainId))) {
559
479
  throw new Error(
560
480
  'FormoAnalytics::chain: chainId must be a valid hex or decimal number'
@@ -564,21 +484,11 @@ export class FormoAnalytics implements IFormoAnalytics {
564
484
  this.currentChainId = chainId.toString();
565
485
 
566
486
  return this.trackEvent(Event.CHAIN_CHANGED, {
567
- chainId,
568
- account: account || this.currentConnectedAccount,
487
+ chain_id: chainId,
488
+ address: address || this.currentConnectedAddress,
569
489
  });
570
490
  }
571
491
 
572
- init(apiKey: string, projectId: string): Promise<FormoAnalytics> {
573
- const instance = new FormoAnalytics(apiKey, projectId);
574
-
575
- return Promise.resolve(instance);
576
- }
577
-
578
- identify(userData: any) {
579
- this.identifyUser(userData);
580
- }
581
-
582
492
  page() {
583
493
  this.trackPageHit();
584
494
  }
@@ -18,7 +18,7 @@ export const FormoAnalyticsContext = createContext<FormoAnalytics | undefined>(
18
18
 
19
19
  export const FormoAnalyticsProvider = ({
20
20
  apiKey,
21
- projectId,
21
+ options,
22
22
  disabled,
23
23
  children,
24
24
  }: FormoAnalyticsProviderProps) => {
@@ -32,15 +32,12 @@ export const FormoAnalyticsProvider = ({
32
32
  console.error('FormoAnalyticsProvider: No API key provided');
33
33
  return;
34
34
  }
35
-
36
35
  if (disabled) {
37
36
  console.warn('FormoAnalytics is disabled');
38
37
  return;
39
38
  }
40
-
41
39
  if (initializedStartedRef.current) return;
42
40
  initializedStartedRef.current = true;
43
-
44
41
  // Initialize Highlight.run if project ID is available
45
42
  if (HIGHLIGHT_PROJECT_ID) {
46
43
  try {
@@ -64,7 +61,7 @@ export const FormoAnalyticsProvider = ({
64
61
 
65
62
  // Initialize FormoAnalytics
66
63
  try {
67
- const sdkInstance = await FormoAnalytics.init(apiKey, projectId);
64
+ const sdkInstance = await FormoAnalytics.init(apiKey, options);
68
65
  setSdk(sdkInstance);
69
66
  console.log('FormoAnalytics SDK initialized successfully');
70
67
  } catch (error) {
@@ -75,7 +72,7 @@ export const FormoAnalyticsProvider = ({
75
72
  };
76
73
 
77
74
  initialize();
78
- }, [apiKey, disabled, projectId]);
75
+ }, [apiKey, disabled, options]);
79
76
 
80
77
  if (!isInitialized) {
81
78
  // Optionally show a loading state until initialization attempt finishes
@@ -1,4 +1,4 @@
1
- export const EVENTS_API = 'https://api.eu-central-1.aws.tinybird.co/v0/events';
1
+ export const EVENTS_API_URL = 'https://events.formo.so/events';
2
2
  export const SESSION_STORAGE_ID_KEY = 'formo-analytics-session-id';
3
3
  export const COUNTRY_LIST = {
4
4
  // Africa