@formo/analytics 1.11.5 → 1.11.6-alpha.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 (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 +163 -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 +164 -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 +162 -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.0",
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,63 @@ 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
+ const parsedData = JSON.parse(sessionData);
265
+ const sessionExpiry = 30 * 60 * 1000; // 30 minutes
266
+ const currentTime = Date.now();
267
+
268
+ if (currentTime - parsedData.timestamp > sessionExpiry) {
269
+ console.warn('Session expired. Ignoring wallet address.');
270
+ sessionStorage.removeItem(this.walletAddressSessionKey); // Clear expired session data
271
+ return '';
272
+ }
273
+
274
+ this.onAddressConnected(parsedData.address);
275
+ return parsedData.address || '';
276
+ }
277
+
278
+ private async getCurrentChainId(): Promise<string> {
279
+ if (!this.provider) {
280
+ console.error('FormoAnalytics::getCurrentChainId: provider not set');
281
+ }
282
+ const chainIdHex = await this.provider?.request<string>({
283
+ method: 'eth_chainId',
284
+ });
285
+ // Because we're connected, the chainId cannot be null
286
+ if (!chainIdHex) {
287
+ console.error(
288
+ `FormoAnalytics::getCurrentChainId: chainIdHex is: ${chainIdHex}`
289
+ );
290
+ }
291
+
292
+ return parseInt(chainIdHex as string, 16).toString();
293
+ }
294
+
295
+ private registerAddressChangedListener() {
296
+ const listener = (...args: unknown[]) =>
297
+ this.onAddressChanged(args[0] as string[]);
298
+
299
+ this._provider?.on('accountsChanged', listener);
300
+ this._registeredProviderListeners['accountsChanged'] = listener;
301
+
302
+ const onAddressDisconnected = this.onAddressDisconnected.bind(this);
303
+ this._provider?.on('disconnect', onAddressDisconnected);
304
+ this._registeredProviderListeners['disconnect'] = onAddressDisconnected;
305
+ }
306
+
320
307
  private registerChainChangedListener() {
321
308
  const listener = (...args: unknown[]) =>
322
309
  this.onChainChanged(args[0] as string);
@@ -324,25 +311,50 @@ export class FormoAnalytics implements IFormoAnalytics {
324
311
  this._registeredProviderListeners['chainChanged'] = listener;
325
312
  }
326
313
 
327
- private handleAccountDisconnected() {
328
- if (!this.currentConnectedAccount) {
314
+ private async onAddressChanged(addresses: string[]) {
315
+ if (addresses.length > 0) {
316
+ const newAccount = addresses[0];
317
+ if (newAccount !== this.currentConnectedAddress) {
318
+ this.onAddressConnected(newAccount);
319
+ }
320
+ } else {
321
+ this.onAddressDisconnected();
322
+ }
323
+ }
324
+
325
+ private async onAddressConnected(address: string) {
326
+ if (address === this.currentConnectedAddress) {
327
+ // We have already reported this address
329
328
  return;
329
+ } else {
330
+ this.currentConnectedAddress = address;
330
331
  }
331
332
 
332
- const disconnectAttributes = {
333
- address: this.currentConnectedAccount,
334
- chainId: this.currentChainId,
333
+ this.currentChainId = await this.getCurrentChainId();
334
+
335
+ this.connect({ chainId: this.currentChainId, address });
336
+ this.storeWalletAddress(address);
337
+ }
338
+
339
+ private onAddressDisconnected() {
340
+ if (!this.currentConnectedAddress) {
341
+ return;
342
+ }
343
+
344
+ const payload = {
345
+ chain_id: this.currentChainId,
346
+ address: this.currentConnectedAddress,
335
347
  };
336
348
  this.currentChainId = undefined;
337
- this.currentConnectedAccount = undefined;
349
+ this.currentConnectedAddress = undefined;
338
350
  this.clearWalletAddress();
339
351
 
340
- return this.trackEvent(Event.DISCONNECT, disconnectAttributes);
352
+ return this.trackEvent(Event.DISCONNECT, payload);
341
353
  }
342
354
 
343
355
  private async onChainChanged(chainIdHex: string) {
344
356
  this.currentChainId = parseInt(chainIdHex).toString();
345
- if (!this.currentConnectedAccount) {
357
+ if (!this.currentConnectedAddress) {
346
358
  if (!this.provider) {
347
359
  console.error(
348
360
  'error',
@@ -363,7 +375,7 @@ export class FormoAnalytics implements IFormoAnalytics {
363
375
  return;
364
376
  }
365
377
 
366
- this.currentConnectedAccount = res[0];
378
+ this.currentConnectedAddress = res[0];
367
379
  } catch (err) {
368
380
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
369
381
  if ((err as any).code !== 4001) {
@@ -380,88 +392,8 @@ export class FormoAnalytics implements IFormoAnalytics {
380
392
 
381
393
  return this.chain({
382
394
  chainId: this.currentChainId,
383
- account: this.currentConnectedAccount,
384
- });
385
- }
386
-
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',
395
+ address: this.currentConnectedAddress,
417
396
  });
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
397
  }
466
398
 
467
399
  /**
@@ -479,82 +411,68 @@ export class FormoAnalytics implements IFormoAnalytics {
479
411
  timestamp: Date.now(),
480
412
  };
481
413
 
482
- sessionStorage.setItem(this.sessionKey, JSON.stringify(sessionData));
414
+ sessionStorage.setItem(
415
+ this.walletAddressSessionKey,
416
+ JSON.stringify(sessionData)
417
+ );
483
418
  }
484
419
 
485
420
  /**
486
421
  * Clears the wallet address from session storage when disconnected.
487
422
  */
488
423
  private clearWalletAddress(): void {
489
- sessionStorage.removeItem(this.sessionKey);
424
+ sessionStorage.removeItem(this.walletAddressSessionKey);
490
425
  }
491
426
 
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';
427
+ init(apiKey: string, options: Options): Promise<FormoAnalytics> {
428
+ const instance = new FormoAnalytics(apiKey, options);
429
+ return Promise.resolve(instance);
508
430
  }
509
431
 
510
- connect({ account, chainId }: { account: string; chainId: ChainID }) {
432
+ connect({ chainId, address }: { chainId: ChainID; address: string }) {
511
433
  if (!chainId) {
512
- throw new Error('FormoAnalytics::connect: chainId cannot be empty');
434
+ throw new Error('FormoAnalytics::connect: chain ID cannot be empty');
513
435
  }
514
- if (!account) {
515
- throw new Error('FormoAnalytics::connect: account cannot be empty');
436
+ if (!address) {
437
+ throw new Error('FormoAnalytics::connect: address cannot be empty');
516
438
  }
517
439
 
518
440
  this.currentChainId = chainId.toString();
519
- this.currentConnectedAccount = account;
441
+ this.currentConnectedAddress = address;
520
442
 
521
443
  return this.trackEvent(Event.CONNECT, {
522
- chainId,
523
- address: account,
444
+ chain_id: chainId,
445
+ address: address,
524
446
  });
525
447
  }
526
448
 
527
- disconnect(attributes?: { account?: string; chainId?: ChainID }) {
528
- const account = attributes?.account || this.currentConnectedAccount;
529
- if (!account) {
449
+ disconnect(params?: { chainId?: ChainID; address?: string }) {
450
+ const address = params?.address || this.currentConnectedAddress;
451
+ if (!address) {
530
452
  // We have most likely already reported this disconnection with the automatic
531
453
  // `disconnect` detection
532
454
  return;
533
455
  }
534
456
 
535
- const chainId = attributes?.chainId || this.currentChainId;
536
- const eventAttributes = {
537
- account,
538
- ...(chainId && { chainId }),
457
+ const payload = {
458
+ chain_id: params?.chainId || this.currentChainId,
459
+ address,
539
460
  };
540
-
541
461
  this.currentChainId = undefined;
542
- this.currentConnectedAccount = undefined;
462
+ this.currentConnectedAddress = undefined;
543
463
 
544
- return this.trackEvent(Event.DISCONNECT, eventAttributes);
464
+ return this.trackEvent(Event.DISCONNECT, payload);
545
465
  }
546
466
 
547
- chain({ chainId, account }: { chainId: ChainID; account?: string }) {
467
+ chain({ chainId, address }: { chainId: ChainID; address?: string }) {
548
468
  if (!chainId || Number(chainId) === 0) {
549
469
  throw new Error('FormoAnalytics::chain: chainId cannot be empty or 0');
550
470
  }
551
-
552
- if (!account && !this.currentConnectedAccount) {
471
+ if (!address && !this.currentConnectedAddress) {
553
472
  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'
473
+ 'FormoAnalytics::chain: address was empty and no previous address has been recorded. You can either pass an address or call connect() first'
555
474
  );
556
475
  }
557
-
558
476
  if (isNaN(Number(chainId))) {
559
477
  throw new Error(
560
478
  'FormoAnalytics::chain: chainId must be a valid hex or decimal number'
@@ -564,21 +482,11 @@ export class FormoAnalytics implements IFormoAnalytics {
564
482
  this.currentChainId = chainId.toString();
565
483
 
566
484
  return this.trackEvent(Event.CHAIN_CHANGED, {
567
- chainId,
568
- account: account || this.currentConnectedAccount,
485
+ chain_id: chainId,
486
+ address: address || this.currentConnectedAddress,
569
487
  });
570
488
  }
571
489
 
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
490
  page() {
583
491
  this.trackPageHit();
584
492
  }
@@ -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
package/src/types/base.ts CHANGED
@@ -1,8 +1,14 @@
1
+ import { EIP1193Provider } from "./wallet";
2
+
1
3
  export type ChainID = string | number
2
4
 
5
+ export interface Options {
6
+ provider?: EIP1193Provider;
7
+ }
8
+
3
9
  export interface FormoAnalyticsProviderProps {
4
10
  apiKey: string;
5
- projectId: string;
11
+ options: Options;
6
12
  disabled?: boolean;
7
13
  children: React.ReactNode;
8
14
  }