@formo/analytics 1.15.2 → 1.16.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 (44) hide show
  1. package/dist/cjs/src/FormoAnalytics.d.ts +10 -4
  2. package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
  3. package/dist/cjs/src/FormoAnalytics.js +106 -113
  4. package/dist/cjs/src/FormoAnalytics.js.map +1 -1
  5. package/dist/cjs/src/constants/base.d.ts +1 -1
  6. package/dist/cjs/src/constants/base.d.ts.map +1 -1
  7. package/dist/cjs/src/constants/base.js +2 -2
  8. package/dist/cjs/src/constants/base.js.map +1 -1
  9. package/dist/cjs/src/constants/events.d.ts +1 -0
  10. package/dist/cjs/src/constants/events.d.ts.map +1 -1
  11. package/dist/cjs/src/constants/events.js +1 -0
  12. package/dist/cjs/src/constants/events.js.map +1 -1
  13. package/dist/cjs/src/lib/queue.d.ts.map +1 -1
  14. package/dist/cjs/src/lib/queue.js +3 -2
  15. package/dist/cjs/src/lib/queue.js.map +1 -1
  16. package/dist/cjs/src/types/events.d.ts +1 -1
  17. package/dist/cjs/src/types/events.d.ts.map +1 -1
  18. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  19. package/dist/esm/src/FormoAnalytics.d.ts +10 -4
  20. package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
  21. package/dist/esm/src/FormoAnalytics.js +109 -116
  22. package/dist/esm/src/FormoAnalytics.js.map +1 -1
  23. package/dist/esm/src/constants/base.d.ts +1 -1
  24. package/dist/esm/src/constants/base.d.ts.map +1 -1
  25. package/dist/esm/src/constants/base.js +1 -1
  26. package/dist/esm/src/constants/base.js.map +1 -1
  27. package/dist/esm/src/constants/events.d.ts +1 -0
  28. package/dist/esm/src/constants/events.d.ts.map +1 -1
  29. package/dist/esm/src/constants/events.js +1 -0
  30. package/dist/esm/src/constants/events.js.map +1 -1
  31. package/dist/esm/src/lib/queue.d.ts.map +1 -1
  32. package/dist/esm/src/lib/queue.js +3 -2
  33. package/dist/esm/src/lib/queue.js.map +1 -1
  34. package/dist/esm/src/types/events.d.ts +1 -1
  35. package/dist/esm/src/types/events.d.ts.map +1 -1
  36. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  37. package/dist/index.umd.min.js +1 -1
  38. package/dist/index.umd.min.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/FormoAnalytics.ts +89 -75
  41. package/src/constants/base.ts +3 -2
  42. package/src/constants/events.ts +8 -7
  43. package/src/lib/queue.ts +2 -1
  44. package/src/types/events.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formo/analytics",
3
- "version": "1.15.2",
3
+ "version": "1.16.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/getformo/sdk.git"
@@ -6,8 +6,6 @@ import {
6
6
  EVENTS_API_URL,
7
7
  Event,
8
8
  SESSION_USER_ID_KEY,
9
- EVENTS_API_REQUEST_HEADER,
10
- USER_API_URL,
11
9
  } from "./constants";
12
10
  import {
13
11
  ChainID,
@@ -21,14 +19,14 @@ import {
21
19
  TransactionStatus,
22
20
  RequestEvent,
23
21
  } from "./types";
24
- import { session, local, logger, EventQueue, fetch, Logger } from "./lib";
22
+ import { session, local, logger, EventQueue, Logger } from "./lib";
25
23
  import {
26
24
  isLocalhost,
27
25
  isAddress,
28
26
  toSnakeCase,
29
27
  generateNativeUUID,
30
28
  } from "./utils";
31
- import { SESSION_IDENTIFIED_KEY } from "./constants";
29
+ import { SESSION_WALLET_DETECTED_KEY } from "./constants";
32
30
  import { UUID } from "crypto";
33
31
 
34
32
  interface IFormoAnalytics {
@@ -77,7 +75,7 @@ export class FormoAnalytics implements IFormoAnalytics {
77
75
  private session: FormoAnalyticsSession;
78
76
  private eventQueue: EventQueue;
79
77
  private anonymousId: UUID | null = null;
80
- private userId: UUID | null = null;
78
+ private userId: string | null = null;
81
79
 
82
80
  config: Config;
83
81
  currentChainId?: ChainID;
@@ -109,7 +107,7 @@ export class FormoAnalytics implements IFormoAnalytics {
109
107
  });
110
108
 
111
109
  this.anonymousId = this.getAnonymousId();
112
- this.getUserId(null).then((userId) => (this.userId = userId));
110
+ this.userId = session.get(SESSION_USER_ID_KEY) as string | null;
113
111
 
114
112
  // TODO: replace with eip6963
115
113
  const provider = options.provider || window?.ethereum;
@@ -127,9 +125,9 @@ export class FormoAnalytics implements IFormoAnalytics {
127
125
  ): Promise<FormoAnalytics> {
128
126
  const analytics = new FormoAnalytics(writeKey, options);
129
127
 
130
- // Identify
128
+ // Detect
131
129
  const providers = await analytics.getProviders();
132
- await analytics.identifyAll(providers);
130
+ await analytics.detects(providers);
133
131
 
134
132
  return analytics;
135
133
  }
@@ -311,23 +309,22 @@ export class FormoAnalytics implements IFormoAnalytics {
311
309
  }
312
310
 
313
311
  /**
314
- * Emits an identify event with current wallet address.
312
+ * Emits an detect event with current wallet provider info.
315
313
  * @param {Address} params.address
316
314
  * @returns {Promise<void>}
317
315
  */
318
316
  public async identify({
319
317
  address,
320
318
  providerName,
319
+ userId,
321
320
  rdns,
322
321
  }: {
323
322
  address: Address | null;
324
323
  providerName?: string;
324
+ userId?: string;
325
325
  rdns?: string;
326
326
  }): Promise<void> {
327
- if (this.session.isIdentified())
328
- return logger.warn("Identify: Wallet already identified in this session");
329
-
330
- this.session.identify();
327
+ if (userId) this.userId = userId || null;
331
328
  await this.trackEvent(Event.IDENTIFY, {
332
329
  address,
333
330
  providerName,
@@ -335,6 +332,30 @@ export class FormoAnalytics implements IFormoAnalytics {
335
332
  });
336
333
  }
337
334
 
335
+ /**
336
+ * Emits an identify event with current wallet address.
337
+ * @param {Address} params.address
338
+ * @returns {Promise<void>}
339
+ */
340
+ private async detect({
341
+ providerName,
342
+ rdns,
343
+ }: {
344
+ providerName: string;
345
+ rdns: string;
346
+ }): Promise<void> {
347
+ if (this.session.isWalletDetected(rdns))
348
+ return logger.warn(
349
+ `detect: Wallet ${providerName} already detected in this session`
350
+ );
351
+
352
+ this.session.markWalletdetected(rdns);
353
+ await this.trackEvent(Event.DETECT_WALLET, {
354
+ providerName,
355
+ rdns,
356
+ });
357
+ }
358
+
338
359
  /**
339
360
  * Emits a custom event with custom data.
340
361
  * @param {string} action
@@ -573,7 +594,6 @@ export class FormoAnalytics implements IFormoAnalytics {
573
594
  return Promise.resolve();
574
595
  }
575
596
  this.currentConnectedAddress = address;
576
- this.userId = await this.getUserId(address);
577
597
  }
578
598
 
579
599
  // Proceed only if the address exists
@@ -646,7 +666,7 @@ export class FormoAnalytics implements IFormoAnalytics {
646
666
  private async trackEvent(action: string, payload: any): Promise<void> {
647
667
  try {
648
668
  const address = await this.getAddress();
649
- const user_id = await this.getUserId(address);
669
+ const user_id = this.userId;
650
670
 
651
671
  const requestData: RequestEvent = {
652
672
  anonymous_id: this.anonymousId as UUID,
@@ -685,38 +705,54 @@ export class FormoAnalytics implements IFormoAnalytics {
685
705
  return providers;
686
706
  }
687
707
 
688
- private async identifyAll(
708
+ private async detects(
689
709
  providers: readonly EIP6963ProviderDetail[]
690
710
  ): Promise<void> {
691
711
  try {
692
712
  for (const eip6963ProviderDetail of providers) {
693
- if (!eip6963ProviderDetail) continue;
694
- const accounts = await this.getAccounts(
695
- eip6963ProviderDetail?.provider
696
- );
697
- // Identify with accounts
698
- if (accounts && accounts.length > 0) {
699
- for (const address of accounts) {
700
- await this.identify({
701
- address,
702
- providerName: eip6963ProviderDetail?.info.name,
703
- rdns: eip6963ProviderDetail?.info.rdns,
704
- });
705
- }
706
- } else {
707
- // Identify without accounts
708
- await this.identify({
709
- address: null,
710
- providerName: eip6963ProviderDetail?.info.name,
711
- rdns: eip6963ProviderDetail?.info.rdns,
712
- });
713
- }
713
+ await this.detect({
714
+ providerName: eip6963ProviderDetail?.info.name,
715
+ rdns: eip6963ProviderDetail?.info.rdns,
716
+ });
714
717
  }
715
718
  } catch (err) {
716
- logger.error("Error identifying all:", err);
719
+ logger.error("Error detect all wallets:", err);
717
720
  }
718
721
  }
719
722
 
723
+ // TODO: Refactoring => public this function as API
724
+ // private async identifyAll(
725
+ // providers: readonly EIP6963ProviderDetail[]
726
+ // ): Promise<void> {
727
+ // try {
728
+ // for (const eip6963ProviderDetail of providers) {
729
+ // if (!eip6963ProviderDetail) continue;
730
+ // const accounts = await this.getAccounts(
731
+ // eip6963ProviderDetail?.provider
732
+ // );
733
+ // // Identify with accounts
734
+ // if (accounts && accounts.length > 0) {
735
+ // for (const address of accounts) {
736
+ // await this.identify({
737
+ // address,
738
+ // providerName: eip6963ProviderDetail?.info.name,
739
+ // rdns: eip6963ProviderDetail?.info.rdns,
740
+ // });
741
+ // }
742
+ // } else {
743
+ // // Identify without accounts
744
+ // await this.identify({
745
+ // address: null,
746
+ // providerName: eip6963ProviderDetail?.info.name,
747
+ // rdns: eip6963ProviderDetail?.info.rdns,
748
+ // });
749
+ // }
750
+ // }
751
+ // } catch (err) {
752
+ // logger.error("Error identifying all:", err);
753
+ // }
754
+ // }
755
+
720
756
  get provider(): EIP1193Provider | undefined {
721
757
  return this._provider;
722
758
  }
@@ -730,31 +766,6 @@ export class FormoAnalytics implements IFormoAnalytics {
730
766
  return newAnonymousId;
731
767
  }
732
768
 
733
- private async getUserId(address: string | null): Promise<UUID | null> {
734
- const storedUserId = session.get(SESSION_USER_ID_KEY);
735
- if (storedUserId && typeof storedUserId === "string")
736
- return storedUserId as UUID;
737
-
738
- if (address) {
739
- const res = await fetch(`${USER_API_URL}?address=${address}`, {
740
- headers: EVENTS_API_REQUEST_HEADER(this.writeKey),
741
- method: "GET",
742
- });
743
- const data = await res.json();
744
- const userId = data?.data?.[0]?.user_id;
745
- if (userId) {
746
- session.set(SESSION_USER_ID_KEY, userId);
747
- return userId;
748
- }
749
-
750
- const newUserId = generateNativeUUID();
751
- session.set(SESSION_USER_ID_KEY, newUserId);
752
- return newUserId;
753
- }
754
-
755
- return null;
756
- }
757
-
758
769
  private async getAddress(): Promise<Address | null> {
759
770
  if (this.currentConnectedAddress) return this.currentConnectedAddress;
760
771
  if (!this?.provider) {
@@ -860,12 +871,12 @@ export class FormoAnalytics implements IFormoAnalytics {
860
871
  locale: language,
861
872
  location,
862
873
  referrer: document.referrer,
863
- utm_source: params.get("utm_source"),
864
- utm_medium: params.get("utm_medium"),
865
- utm_campaign: params.get("utm_campaign"),
866
- utm_content: params.get("utm_content"),
867
- utm_term: params.get("utm_term"),
868
- ref: params.get("ref"),
874
+ utm_source: params.get("utm_source")?.trim() || "",
875
+ utm_medium: params.get("utm_medium")?.trim() || "",
876
+ utm_campaign: params.get("utm_campaign")?.trim() || "",
877
+ utm_content: params.get("utm_content")?.trim() || "",
878
+ utm_term: params.get("utm_term")?.trim() || "",
879
+ ref: params.get("ref")?.trim() || "",
869
880
  ...eventSpecificPayload,
870
881
  };
871
882
  }
@@ -920,18 +931,21 @@ export class FormoAnalytics implements IFormoAnalytics {
920
931
  }
921
932
 
922
933
  interface IFormoAnalyticsSession {
923
- isIdentified(): boolean;
924
- identify(): void;
934
+ isWalletDetected(rdns: string): boolean;
935
+ markWalletdetected(rdns: string): void;
925
936
  }
926
937
 
927
938
  class FormoAnalyticsSession implements IFormoAnalyticsSession {
928
939
  constructor() {}
929
940
 
930
- public isIdentified(): boolean {
931
- return session.get(SESSION_IDENTIFIED_KEY) === true;
941
+ public isWalletDetected(rdns: string): boolean {
942
+ const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
943
+ return rdnses.includes(rdns);
932
944
  }
933
945
 
934
- public identify(): void {
935
- session.set(SESSION_IDENTIFIED_KEY, true);
946
+ public markWalletdetected(rdns: string): void {
947
+ const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
948
+ rdnses.push(rdns);
949
+ session.set(SESSION_WALLET_DETECTED_KEY, rdnses);
936
950
  }
937
951
  }
@@ -2,8 +2,9 @@ const STORAGE_PREFIX = "formo-";
2
2
 
3
3
  const generateStoragePrefix = (prefix: string) => `${STORAGE_PREFIX}${prefix}`;
4
4
 
5
- export const SESSION_IDENTIFIED_KEY =
6
- generateStoragePrefix("session-identified");
5
+ export const SESSION_WALLET_DETECTED_KEY = generateStoragePrefix(
6
+ "session-wallet-detected"
7
+ );
7
8
  export const SESSION_CURRENT_URL_KEY = generateStoragePrefix(
8
9
  "analytics-current-url"
9
10
  );
@@ -1,9 +1,10 @@
1
1
  export enum Event {
2
- PAGE = 'page_hit',
3
- IDENTIFY = 'identify',
4
- CONNECT = 'connect',
5
- DISCONNECT = 'disconnect',
6
- CHAIN_CHANGED = 'chain_changed',
7
- SIGNATURE = 'signature',
8
- TRANSACTION = 'transaction',
2
+ PAGE = "page_hit",
3
+ IDENTIFY = "identify",
4
+ DETECT_WALLET = "detect_wallet",
5
+ CONNECT = "connect",
6
+ DISCONNECT = "disconnect",
7
+ CHAIN_CHANGED = "chain_changed",
8
+ SIGNATURE = "signature",
9
+ TRANSACTION = "transaction",
9
10
  }
package/src/lib/queue.ts CHANGED
@@ -100,6 +100,7 @@ export class EventQueue {
100
100
  callback = callback || noop;
101
101
 
102
102
  const formattedTimestamp = toDateHourMinute(new Date(event.timestamp));
103
+ const originTimestamp = event.timestamp;
103
104
  event.timestamp = formattedTimestamp;
104
105
 
105
106
  const eventString = JSON.stringify(event);
@@ -114,7 +115,7 @@ export class EventQueue {
114
115
  return;
115
116
  }
116
117
 
117
- this.queue.push({ message: { ...event, id: eventId }, callback });
118
+ this.queue.push({ message: { ...event, timestamp: originTimestamp, id: eventId }, callback });
118
119
 
119
120
  logger.log(
120
121
  `Event enqueued: ${getActionDescriptor(event.action, event.payload)}`
@@ -2,7 +2,7 @@ import { UUID } from "crypto";
2
2
 
3
3
  export interface RequestEvent {
4
4
  anonymous_id: UUID;
5
- user_id: UUID | null;
5
+ user_id: string | null;
6
6
  action: string;
7
7
  payload: Record<string, unknown>;
8
8
  address: string | null;