@formo/analytics 1.16.7 → 1.16.9

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 (108) hide show
  1. package/dist/cjs/src/FormoAnalytics.d.ts +9 -49
  2. package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
  3. package/dist/cjs/src/FormoAnalytics.js +123 -50
  4. package/dist/cjs/src/FormoAnalytics.js.map +1 -1
  5. package/dist/cjs/src/FormoAnalyticsProvider.d.ts +3 -4
  6. package/dist/cjs/src/FormoAnalyticsProvider.d.ts.map +1 -1
  7. package/dist/cjs/src/FormoAnalyticsProvider.js +14 -2
  8. package/dist/cjs/src/FormoAnalyticsProvider.js.map +1 -1
  9. package/dist/cjs/src/constants/base.d.ts +5 -4
  10. package/dist/cjs/src/constants/base.d.ts.map +1 -1
  11. package/dist/cjs/src/constants/base.js +6 -7
  12. package/dist/cjs/src/constants/base.js.map +1 -1
  13. package/dist/cjs/src/lib/event/EventFactory.d.ts +4 -1
  14. package/dist/cjs/src/lib/event/EventFactory.d.ts.map +1 -1
  15. package/dist/cjs/src/lib/event/EventFactory.js +52 -10
  16. package/dist/cjs/src/lib/event/EventFactory.js.map +1 -1
  17. package/dist/cjs/src/lib/event/EventManager.d.ts +2 -1
  18. package/dist/cjs/src/lib/event/EventManager.d.ts.map +1 -1
  19. package/dist/cjs/src/lib/event/EventManager.js +2 -2
  20. package/dist/cjs/src/lib/event/EventManager.js.map +1 -1
  21. package/dist/cjs/src/lib/event/utils.d.ts +1 -1
  22. package/dist/cjs/src/lib/event/utils.d.ts.map +1 -1
  23. package/dist/cjs/src/lib/event/utils.js +3 -4
  24. package/dist/cjs/src/lib/event/utils.js.map +1 -1
  25. package/dist/cjs/src/lib/storage/index.d.ts +2 -0
  26. package/dist/cjs/src/lib/storage/index.d.ts.map +1 -1
  27. package/dist/cjs/src/lib/storage/index.js +18 -1
  28. package/dist/cjs/src/lib/storage/index.js.map +1 -1
  29. package/dist/cjs/src/lib/storage/key.d.ts +9 -0
  30. package/dist/cjs/src/lib/storage/key.d.ts.map +1 -0
  31. package/dist/cjs/src/lib/storage/key.js +15 -0
  32. package/dist/cjs/src/lib/storage/key.js.map +1 -0
  33. package/dist/cjs/src/lib/storage/native.js +1 -1
  34. package/dist/cjs/src/lib/storage/native.js.map +1 -1
  35. package/dist/cjs/src/lib/storage/type.d.ts +4 -0
  36. package/dist/cjs/src/lib/storage/type.d.ts.map +1 -0
  37. package/dist/cjs/src/lib/storage/type.js +3 -0
  38. package/dist/cjs/src/lib/storage/type.js.map +1 -0
  39. package/dist/cjs/src/lib/version.d.ts +1 -1
  40. package/dist/cjs/src/lib/version.js +1 -1
  41. package/dist/cjs/src/types/base.d.ts +44 -0
  42. package/dist/cjs/src/types/base.d.ts.map +1 -1
  43. package/dist/cjs/src/types/events.d.ts +11 -1
  44. package/dist/cjs/src/types/events.d.ts.map +1 -1
  45. package/dist/cjs/src/types/events.js.map +1 -1
  46. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  47. package/dist/esm/src/FormoAnalytics.d.ts +9 -49
  48. package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
  49. package/dist/esm/src/FormoAnalytics.js +124 -51
  50. package/dist/esm/src/FormoAnalytics.js.map +1 -1
  51. package/dist/esm/src/FormoAnalyticsProvider.d.ts +3 -4
  52. package/dist/esm/src/FormoAnalyticsProvider.d.ts.map +1 -1
  53. package/dist/esm/src/FormoAnalyticsProvider.js +15 -3
  54. package/dist/esm/src/FormoAnalyticsProvider.js.map +1 -1
  55. package/dist/esm/src/constants/base.d.ts +5 -4
  56. package/dist/esm/src/constants/base.d.ts.map +1 -1
  57. package/dist/esm/src/constants/base.js +5 -6
  58. package/dist/esm/src/constants/base.js.map +1 -1
  59. package/dist/esm/src/lib/event/EventFactory.d.ts +4 -1
  60. package/dist/esm/src/lib/event/EventFactory.d.ts.map +1 -1
  61. package/dist/esm/src/lib/event/EventFactory.js +54 -12
  62. package/dist/esm/src/lib/event/EventFactory.js.map +1 -1
  63. package/dist/esm/src/lib/event/EventManager.d.ts +2 -1
  64. package/dist/esm/src/lib/event/EventManager.d.ts.map +1 -1
  65. package/dist/esm/src/lib/event/EventManager.js +2 -2
  66. package/dist/esm/src/lib/event/EventManager.js.map +1 -1
  67. package/dist/esm/src/lib/event/utils.d.ts +1 -1
  68. package/dist/esm/src/lib/event/utils.d.ts.map +1 -1
  69. package/dist/esm/src/lib/event/utils.js +3 -4
  70. package/dist/esm/src/lib/event/utils.js.map +1 -1
  71. package/dist/esm/src/lib/storage/index.d.ts +2 -0
  72. package/dist/esm/src/lib/storage/index.d.ts.map +1 -1
  73. package/dist/esm/src/lib/storage/index.js +2 -0
  74. package/dist/esm/src/lib/storage/index.js.map +1 -1
  75. package/dist/esm/src/lib/storage/key.d.ts +9 -0
  76. package/dist/esm/src/lib/storage/key.d.ts.map +1 -0
  77. package/dist/esm/src/lib/storage/key.js +12 -0
  78. package/dist/esm/src/lib/storage/key.js.map +1 -0
  79. package/dist/esm/src/lib/storage/native.js +1 -1
  80. package/dist/esm/src/lib/storage/native.js.map +1 -1
  81. package/dist/esm/src/lib/storage/type.d.ts +4 -0
  82. package/dist/esm/src/lib/storage/type.d.ts.map +1 -0
  83. package/dist/esm/src/lib/storage/type.js +2 -0
  84. package/dist/esm/src/lib/storage/type.js.map +1 -0
  85. package/dist/esm/src/lib/version.d.ts +1 -1
  86. package/dist/esm/src/lib/version.js +1 -1
  87. package/dist/esm/src/types/base.d.ts +44 -0
  88. package/dist/esm/src/types/base.d.ts.map +1 -1
  89. package/dist/esm/src/types/events.d.ts +11 -1
  90. package/dist/esm/src/types/events.d.ts.map +1 -1
  91. package/dist/esm/src/types/events.js.map +1 -1
  92. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  93. package/dist/index.umd.min.js +1 -1
  94. package/dist/index.umd.min.js.map +1 -1
  95. package/package.json +2 -2
  96. package/src/FormoAnalytics.ts +124 -125
  97. package/src/FormoAnalyticsProvider.tsx +18 -6
  98. package/src/constants/base.ts +5 -12
  99. package/src/lib/event/EventFactory.ts +89 -15
  100. package/src/lib/event/EventManager.ts +3 -2
  101. package/src/lib/event/utils.ts +3 -4
  102. package/src/lib/storage/index.ts +2 -0
  103. package/src/lib/storage/key.ts +16 -0
  104. package/src/lib/storage/native.ts +1 -1
  105. package/src/lib/storage/type.ts +3 -0
  106. package/src/lib/version.ts +1 -1
  107. package/src/types/base.ts +83 -0
  108. package/src/types/events.ts +11 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formo/analytics",
3
- "version": "1.16.7",
3
+ "version": "1.16.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/getformo/sdk.git"
@@ -87,7 +87,7 @@
87
87
  "size-limit": [
88
88
  {
89
89
  "path": "dist/index.umd.min.js",
90
- "limit": "25 KB"
90
+ "limit": "26 KB"
91
91
  }
92
92
  ],
93
93
  "peerDependencies": {
@@ -12,16 +12,19 @@ import {
12
12
  EventManager,
13
13
  EventQueue,
14
14
  IEventManager,
15
+ IStorageKeyManager,
15
16
  local,
16
17
  logger,
17
18
  Logger,
18
19
  session,
20
+ StorageKey,
19
21
  } from "./lib";
20
22
  import {
21
23
  Address,
22
24
  ChainID,
23
25
  Config,
24
26
  EIP1193Provider,
27
+ IFormoAnalytics,
25
28
  IFormoEventContext,
26
29
  IFormoEventProperties,
27
30
  Options,
@@ -32,94 +35,18 @@ import {
32
35
  } from "./types";
33
36
  import { isAddress, isLocalhost } from "./validators";
34
37
 
35
- interface IFormoAnalytics {
36
- page(
37
- category?: string,
38
- name?: string,
39
- properties?: IFormoEventProperties,
40
- context?: IFormoEventContext,
41
- callback?: (...args: unknown[]) => void
42
- ): void;
43
- reset(): void;
44
- detect(
45
- params: { rdns: string; providerName: string },
46
- properties?: IFormoEventProperties,
47
- context?: IFormoEventContext,
48
- callback?: (...args: unknown[]) => void
49
- ): Promise<void>;
50
- connect(
51
- params: { chainId: ChainID; address: Address },
52
- properties?: IFormoEventProperties,
53
- context?: IFormoEventContext,
54
- callback?: (...args: unknown[]) => void
55
- ): Promise<void>;
56
- disconnect(
57
- params?: { chainId?: ChainID; address?: Address },
58
- properties?: IFormoEventProperties,
59
- context?: IFormoEventContext,
60
- callback?: (...args: unknown[]) => void
61
- ): Promise<void>;
62
- chain(
63
- params: { chainId: ChainID; address?: Address },
64
- properties?: IFormoEventProperties,
65
- context?: IFormoEventContext,
66
- callback?: (...args: unknown[]) => void
67
- ): Promise<void>;
68
- signature(
69
- params: {
70
- status: SignatureStatus;
71
- chainId?: ChainID;
72
- address: Address;
73
- message: string;
74
- signatureHash?: string;
75
- },
76
- properties?: IFormoEventProperties,
77
- context?: IFormoEventContext,
78
- callback?: (...args: unknown[]) => void
79
- ): Promise<void>;
80
- transaction(
81
- params: {
82
- status: TransactionStatus;
83
- chainId: ChainID;
84
- address: Address;
85
- data?: string;
86
- to?: string;
87
- value?: string;
88
- transactionHash?: string;
89
- },
90
- properties?: IFormoEventProperties,
91
- context?: IFormoEventContext,
92
- callback?: (...args: unknown[]) => void
93
- ): Promise<void>;
94
- identify(
95
- params: {
96
- address: Address;
97
- providerName?: string;
98
- userId?: string;
99
- rdns?: string;
100
- },
101
- properties?: IFormoEventProperties,
102
- context?: IFormoEventContext,
103
- callback?: (...args: unknown[]) => void
104
- ): Promise<void>;
105
- track(
106
- event: string,
107
- properties?: IFormoEventProperties,
108
- context?: IFormoEventContext,
109
- callback?: (...args: unknown[]) => void
110
- ): Promise<void>;
111
- }
112
-
113
38
  export class FormoAnalytics implements IFormoAnalytics {
114
39
  private _provider?: EIP1193Provider;
115
40
  private _providerListeners: Record<string, (...args: unknown[]) => void> = {};
116
41
  private session: FormoAnalyticsSession;
117
42
  private eventManager: IEventManager;
43
+ private storageKeyManager: IStorageKeyManager;
44
+ private _providers: readonly EIP6963ProviderDetail[] = [];
118
45
 
119
46
  config: Config;
120
47
  currentChainId?: ChainID;
121
- currentAddress?: Address;
122
- currentUserId?: string;
48
+ currentAddress?: Address = "";
49
+ currentUserId?: string = "";
123
50
 
124
51
  private constructor(
125
52
  public readonly writeKey: string,
@@ -130,9 +57,22 @@ export class FormoAnalytics implements IFormoAnalytics {
130
57
  trackLocalhost: options.trackLocalhost || false,
131
58
  };
132
59
 
133
- this.session = new FormoAnalyticsSession();
60
+ this.storageKeyManager = new StorageKey(this.config.writeKey);
61
+
62
+ this.session = new FormoAnalyticsSession(this.storageKeyManager);
134
63
  this.currentUserId =
135
- (session.get(SESSION_USER_ID_KEY) as string) || undefined;
64
+ (session.get(
65
+ this.storageKeyManager.getKey(SESSION_USER_ID_KEY)
66
+ ) as string) || undefined;
67
+
68
+ this.identify = this.identify.bind(this);
69
+ this.connect = this.connect.bind(this);
70
+ this.disconnect = this.disconnect.bind(this);
71
+ this.chain = this.chain.bind(this);
72
+ this.signature = this.signature.bind(this);
73
+ this.transaction = this.transaction.bind(this);
74
+ this.detect = this.detect.bind(this);
75
+ this.track = this.track.bind(this);
136
76
 
137
77
  // Initialize logger with configuration from options
138
78
  Logger.init({
@@ -147,7 +87,8 @@ export class FormoAnalytics implements IFormoAnalytics {
147
87
  retryCount: options.retryCount,
148
88
  maxQueueSize: options.maxQueueSize,
149
89
  flushInterval: options.flushInterval,
150
- })
90
+ }),
91
+ this.storageKeyManager
151
92
  );
152
93
 
153
94
  // TODO: replace with eip6963
@@ -167,8 +108,8 @@ export class FormoAnalytics implements IFormoAnalytics {
167
108
  const analytics = new FormoAnalytics(writeKey, options);
168
109
 
169
110
  // Auto-detect wallet provider
170
- const providers = await analytics.getProviders();
171
- await analytics.detectWallets(providers);
111
+ analytics._providers = await analytics.getProviders();
112
+ await analytics.detectWallets(analytics._providers);
172
113
 
173
114
  return analytics;
174
115
  }
@@ -200,8 +141,8 @@ export class FormoAnalytics implements IFormoAnalytics {
200
141
  */
201
142
  public reset(): void {
202
143
  this.currentUserId = undefined;
203
- local.remove(LOCAL_ANONYMOUS_ID_KEY);
204
- session.remove(SESSION_USER_ID_KEY);
144
+ local.remove(this.storageKeyManager.getKey(LOCAL_ANONYMOUS_ID_KEY));
145
+ session.remove(this.storageKeyManager.getKey(SESSION_USER_ID_KEY));
205
146
  }
206
147
 
207
148
  /**
@@ -429,17 +370,17 @@ export class FormoAnalytics implements IFormoAnalytics {
429
370
 
430
371
  /**
431
372
  * Emits an identify event with current wallet address and provider info.
432
- * @param {string} params.providerName
433
- * @param {string} params.rdns
434
- * @param {string} params.userId
435
373
  * @param {string} params.address
374
+ * @param {string} params.userId
375
+ * @param {string} params.rdns
376
+ * @param {string} params.providerName
436
377
  * @param {IFormoEventProperties} properties
437
378
  * @param {IFormoEventContext} context
438
379
  * @param {(...args: unknown[]) => void} callback
439
380
  * @returns {Promise<void>}
440
381
  */
441
- public async identify(
442
- params: {
382
+ async identify(
383
+ params?: {
443
384
  address?: Address;
444
385
  providerName?: string;
445
386
  userId?: string;
@@ -449,26 +390,52 @@ export class FormoAnalytics implements IFormoAnalytics {
449
390
  context?: IFormoEventContext,
450
391
  callback?: (...args: unknown[]) => void
451
392
  ): Promise<void> {
452
- const { userId, address, providerName, rdns } = params;
393
+ try {
394
+ if (!params) { // If no params provided, auto-identify
395
+ for (const providerDetail of this._providers) {
396
+ const provider = providerDetail.provider;
397
+ if (!provider) continue;
398
+
399
+ try {
400
+ const address = await this.getAddress(provider);
401
+ if (address) {
402
+ // NOTE: do not set this.currentAddress without explicit connect or identify
403
+ await this.identify({
404
+ address,
405
+ providerName: providerDetail.info.name,
406
+ rdns: providerDetail.info.rdns,
407
+ }, properties, context, callback);
408
+ }
409
+ } catch (err) {
410
+ logger.error(`Failed to identify provider ${providerDetail.info.name}:`, err);
411
+ }
412
+ }
413
+ return;
414
+ }
453
415
 
454
- this.currentAddress = address;
455
- if (userId) {
456
- this.currentUserId = userId;
457
- session.set(SESSION_USER_ID_KEY, userId);
458
- }
416
+ // Explicit identify
417
+ const { userId, address, providerName, rdns } = params;
418
+ if (address) this.currentAddress = address;
419
+ if (userId) {
420
+ this.currentUserId = userId;
421
+ session.set(this.storageKeyManager.getKey(SESSION_USER_ID_KEY), userId);
422
+ }
459
423
 
460
- await this.trackEvent(
461
- EventType.IDENTIFY,
462
- {
463
- address,
464
- providerName,
465
- userId,
466
- rdns,
467
- },
468
- properties,
469
- context,
470
- callback
471
- );
424
+ await this.trackEvent(
425
+ EventType.IDENTIFY,
426
+ {
427
+ address,
428
+ providerName,
429
+ userId,
430
+ rdns,
431
+ },
432
+ properties,
433
+ context,
434
+ callback
435
+ );
436
+ } catch (e) {
437
+ logger.log("identify error", e);
438
+ }
472
439
  }
473
440
 
474
441
  /**
@@ -734,7 +701,7 @@ export class FormoAnalytics implements IFormoAnalytics {
734
701
  };
735
702
  this.currentChainId = undefined;
736
703
  this.currentAddress = undefined;
737
- session.remove(SESSION_USER_ID_KEY);
704
+ session.remove(this.storageKeyManager.getKey(SESSION_USER_ID_KEY));
738
705
 
739
706
  await this.trackEvent(
740
707
  EventType.DISCONNECT,
@@ -783,8 +750,14 @@ export class FormoAnalytics implements IFormoAnalytics {
783
750
  }
784
751
 
785
752
  private async trackFirstPageHit(): Promise<void> {
786
- if (session.get(SESSION_CURRENT_URL_KEY) === null) {
787
- session.set(SESSION_CURRENT_URL_KEY, window.location.href);
753
+ if (
754
+ session.get(this.storageKeyManager.getKey(SESSION_CURRENT_URL_KEY)) ===
755
+ null
756
+ ) {
757
+ session.set(
758
+ this.storageKeyManager.getKey(SESSION_CURRENT_URL_KEY),
759
+ window.location.href
760
+ );
788
761
  }
789
762
 
790
763
  return this.trackPageHit();
@@ -810,10 +783,15 @@ export class FormoAnalytics implements IFormoAnalytics {
810
783
  }
811
784
 
812
785
  private async onLocationChange(): Promise<void> {
813
- const currentUrl = session.get(SESSION_CURRENT_URL_KEY);
786
+ const currentUrl = session.get(
787
+ this.storageKeyManager.getKey(SESSION_CURRENT_URL_KEY)
788
+ );
814
789
 
815
790
  if (currentUrl !== window.location.href) {
816
- session.set(SESSION_CURRENT_URL_KEY, window.location.href);
791
+ session.set(
792
+ this.storageKeyManager.getKey(SESSION_CURRENT_URL_KEY),
793
+ window.location.href
794
+ );
817
795
  this.trackPageHit();
818
796
  }
819
797
  }
@@ -876,16 +854,24 @@ export class FormoAnalytics implements IFormoAnalytics {
876
854
  private async getProviders(): Promise<readonly EIP6963ProviderDetail[]> {
877
855
  const store = createStore();
878
856
  let providers = store.getProviders();
879
- // TODO: consider using store.subscribe to detect changes to providers list
880
- store.subscribe((providerDetails) => (providers = providerDetails));
857
+ store.subscribe((providerDetails) => {
858
+ providers = providerDetails;
859
+ this._providers = providers;
860
+ });
881
861
 
882
862
  // Fallback to injected provider if no providers are found
883
863
  if (providers.length === 0) {
884
- return window?.ethereum ? [window.ethereum] : [];
864
+ this._providers = window?.ethereum ? [window.ethereum] : [];
865
+ return this._providers;
885
866
  }
867
+ this._providers = providers;
886
868
  return providers;
887
869
  }
888
870
 
871
+ get providers(): readonly EIP6963ProviderDetail[] {
872
+ return this._providers;
873
+ }
874
+
889
875
  private async detectWallets(
890
876
  providers: readonly EIP6963ProviderDetail[]
891
877
  ): Promise<void> {
@@ -905,15 +891,16 @@ export class FormoAnalytics implements IFormoAnalytics {
905
891
  return this._provider;
906
892
  }
907
893
 
908
- private async getAddress(): Promise<Address | null> {
894
+ private async getAddress(provider?: EIP1193Provider): Promise<Address | null> {
909
895
  if (this.currentAddress) return this.currentAddress;
910
- if (!this?.provider) {
896
+ const p = provider || this.provider;
897
+ if (!p) {
911
898
  logger.info("The provider is not set");
912
899
  return null;
913
900
  }
914
901
 
915
902
  try {
916
- const accounts = await this.getAccounts();
903
+ const accounts = await this.getAccounts(p);
917
904
  if (accounts && accounts.length > 0) {
918
905
  if (isAddress(accounts[0])) {
919
906
  return accounts[0];
@@ -1023,16 +1010,28 @@ interface IFormoAnalyticsSession {
1023
1010
  }
1024
1011
 
1025
1012
  class FormoAnalyticsSession implements IFormoAnalyticsSession {
1026
- constructor() {}
1013
+ private storageKeyManager: IStorageKeyManager;
1014
+ constructor(storageKeyManager: IStorageKeyManager) {
1015
+ this.storageKeyManager = storageKeyManager;
1016
+ }
1027
1017
 
1028
1018
  public isWalletDetected(rdns: string): boolean {
1029
- const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
1019
+ const rdnses =
1020
+ (session.get(
1021
+ this.storageKeyManager.getKey(SESSION_WALLET_DETECTED_KEY)
1022
+ ) as string[]) || [];
1030
1023
  return rdnses.includes(rdns);
1031
1024
  }
1032
1025
 
1033
1026
  public markWalletDetected(rdns: string): void {
1034
- const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
1027
+ const rdnses =
1028
+ (session.get(
1029
+ this.storageKeyManager.getKey(SESSION_WALLET_DETECTED_KEY)
1030
+ ) as string[]) || [];
1035
1031
  rdnses.push(rdns);
1036
- session.set(SESSION_WALLET_DETECTED_KEY, rdnses);
1032
+ session.set(
1033
+ this.storageKeyManager.getKey(SESSION_WALLET_DETECTED_KEY),
1034
+ rdnses
1035
+ );
1037
1036
  }
1038
1037
  }
@@ -1,11 +1,23 @@
1
- import { createContext, useContext, useEffect, useState, useRef } from "react";
1
+ import { createContext, useContext, useEffect, useRef, useState } from "react";
2
2
  import { FormoAnalytics } from "./FormoAnalytics";
3
- import { FormoAnalyticsProviderProps } from "./types";
4
3
  import { logger } from "./lib";
4
+ import { FormoAnalyticsProviderProps, IFormoAnalytics } from "./types";
5
5
 
6
- export const FormoAnalyticsContext = createContext<FormoAnalytics | undefined>(
7
- undefined
8
- );
6
+ const defaultContext: IFormoAnalytics = {
7
+ chain: () => Promise.resolve(),
8
+ page: () => Promise.resolve(),
9
+ reset: () => Promise.resolve(),
10
+ detect: () => Promise.resolve(),
11
+ connect: () => Promise.resolve(),
12
+ disconnect: () => Promise.resolve(),
13
+ signature: () => Promise.resolve(),
14
+ transaction: () => Promise.resolve(),
15
+ identify: () => Promise.resolve(),
16
+ track: () => Promise.resolve(),
17
+ };
18
+
19
+ export const FormoAnalyticsContext =
20
+ createContext<IFormoAnalytics>(defaultContext);
9
21
 
10
22
  export const FormoAnalyticsProvider = (props: FormoAnalyticsProviderProps) => {
11
23
  const { writeKey, disabled = false, children } = props;
@@ -29,7 +41,7 @@ const InitializedAnalytics = ({
29
41
  options,
30
42
  children,
31
43
  }: FormoAnalyticsProviderProps) => {
32
- const [sdk, setSdk] = useState<FormoAnalytics | undefined>();
44
+ const [sdk, setSdk] = useState<IFormoAnalytics>(defaultContext);
33
45
  const initializedStartedRef = useRef(false);
34
46
 
35
47
  const initializeFormoAnalytics = async (writeKey: string, options: any) => {
@@ -1,13 +1,6 @@
1
- const STORAGE_PREFIX = "formo-";
1
+ export const SESSION_TRAFFIC_SOURCE_KEY = "traffic-source";
2
+ export const SESSION_WALLET_DETECTED_KEY = "wallet-detected";
3
+ export const SESSION_CURRENT_URL_KEY = "analytics-current-url";
4
+ export const SESSION_USER_ID_KEY = "user-id";
2
5
 
3
- const generateStoragePrefix = (prefix: string) => `${STORAGE_PREFIX}${prefix}`;
4
-
5
- export const SESSION_WALLET_DETECTED_KEY = generateStoragePrefix(
6
- "session-wallet-detected"
7
- );
8
- export const SESSION_CURRENT_URL_KEY = generateStoragePrefix(
9
- "analytics-current-url"
10
- );
11
- export const SESSION_USER_ID_KEY = generateStoragePrefix("user-id");
12
-
13
- export const LOCAL_ANONYMOUS_ID_KEY = generateStoragePrefix("anonymous-id");
6
+ export const LOCAL_ANONYMOUS_ID_KEY = "anonymous-id";
@@ -1,4 +1,8 @@
1
- import { COUNTRY_LIST } from "../../constants";
1
+ import {
2
+ COUNTRY_LIST,
3
+ LOCAL_ANONYMOUS_ID_KEY,
4
+ SESSION_TRAFFIC_SOURCE_KEY,
5
+ } from "../../constants";
2
6
  import {
3
7
  Address,
4
8
  APIEvent,
@@ -6,6 +10,7 @@ import {
6
10
  IFormoEvent,
7
11
  IFormoEventContext,
8
12
  IFormoEventProperties,
13
+ ITrafficSource,
9
14
  Nullable,
10
15
  SignatureStatus,
11
16
  TransactionStatus,
@@ -20,14 +25,17 @@ import { getCurrentTimeFormatted } from "../../utils/timestamp";
20
25
  import { isUndefined } from "../../validators";
21
26
  import { logger } from "../logger";
22
27
  import mergeDeepRight from "../ramda/mergeDeepRight";
23
- import { local } from "../storage";
28
+ import { IStorageKeyManager, local, session } from "../storage";
24
29
  import { version } from "../version";
25
30
  import { CHANNEL, VERSION } from "./constants";
26
31
  import { IEventFactory } from "./type";
27
32
  import { generateAnonymousId } from "./utils";
28
33
 
29
34
  class EventFactory implements IEventFactory {
30
- constructor() {}
35
+ private storageKeyManager: IStorageKeyManager;
36
+ constructor(storageKeyManager: IStorageKeyManager) {
37
+ this.storageKeyManager = storageKeyManager;
38
+ }
31
39
 
32
40
  private getTimezone(): string {
33
41
  try {
@@ -68,23 +76,84 @@ class EventFactory implements IEventFactory {
68
76
  }
69
77
 
70
78
  private extractUTMParameters = (url: string): UTMParameters => {
71
- const result: UTMParameters = {};
79
+ const result: UTMParameters = {
80
+ utm_campaign: "",
81
+ utm_content: "",
82
+ utm_medium: "",
83
+ utm_source: "",
84
+ utm_term: "",
85
+ };
72
86
  try {
73
87
  const urlObj = new URL(url);
74
88
  const UTM_PREFIX = "utm_";
75
89
  urlObj.searchParams.forEach((value, sParam) => {
76
90
  if (sParam.startsWith(UTM_PREFIX)) {
77
- result[sParam] = value.trim() || "";
91
+ result[sParam as keyof UTMParameters] = value.trim();
78
92
  }
79
93
  });
80
94
  } catch (error) {}
81
95
  return result;
82
96
  };
83
97
 
98
+ private getTrafficSources = (url: string): ITrafficSource => {
99
+ const urlObj = new URL(url);
100
+ const contextTrafficSources: ITrafficSource = {
101
+ ...this.extractUTMParameters(url),
102
+ ref: urlObj.searchParams.get("ref")?.trim() || "",
103
+ referrer: document.referrer,
104
+ };
105
+ const storedTrafficSources =
106
+ (session.get(
107
+ this.storageKeyManager.getKey(SESSION_TRAFFIC_SOURCE_KEY)
108
+ ) as ITrafficSource) || {};
109
+
110
+ const finalTrafficSources: ITrafficSource = {
111
+ ref: contextTrafficSources.ref || storedTrafficSources?.ref || "",
112
+ referrer:
113
+ contextTrafficSources.referrer || storedTrafficSources?.referrer,
114
+ utm_campaign:
115
+ contextTrafficSources.utm_campaign ||
116
+ storedTrafficSources?.utm_campaign ||
117
+ "",
118
+ utm_content:
119
+ contextTrafficSources.utm_content ||
120
+ storedTrafficSources?.utm_content ||
121
+ "",
122
+ utm_medium:
123
+ contextTrafficSources.utm_medium ||
124
+ storedTrafficSources?.utm_medium ||
125
+ "",
126
+ utm_source:
127
+ contextTrafficSources.utm_source ||
128
+ storedTrafficSources?.utm_source ||
129
+ "",
130
+ utm_term:
131
+ contextTrafficSources.utm_term || storedTrafficSources?.utm_term || "",
132
+ };
133
+
134
+ // Store to session
135
+ const sessionStoredTrafficSources = Object.keys(finalTrafficSources).reduce(
136
+ (res: any, key: any) => {
137
+ const value = finalTrafficSources[key as keyof ITrafficSource];
138
+ if (!isUndefined(value) && value !== "") {
139
+ res[key as keyof ITrafficSource] = value;
140
+ }
141
+ return res;
142
+ },
143
+ {}
144
+ );
145
+
146
+ if (Object.keys(sessionStoredTrafficSources).length)
147
+ session.set(
148
+ this.storageKeyManager.getKey(SESSION_TRAFFIC_SOURCE_KEY),
149
+ sessionStoredTrafficSources
150
+ );
151
+
152
+ return finalTrafficSources;
153
+ };
154
+
84
155
  // Contextual fields that are automatically collected and populated by the Formo SDK
85
156
  private generateContext(context?: IFormoEventContext): IFormoEventContext {
86
- const url = new URL(globalThis.location.href);
87
- const params = new URLSearchParams(url.search);
88
157
  const path = globalThis.location.pathname;
89
158
  const language = this.getLanguage();
90
159
  const timezone = this.getTimezone();
@@ -97,12 +166,10 @@ class EventFactory implements IEventFactory {
97
166
  locale: language,
98
167
  timezone,
99
168
  location,
100
- referrer: document.referrer,
101
- ...this.extractUTMParameters(globalThis.location.href),
102
- ref: params.get("ref")?.trim() || "",
169
+ ...this.getTrafficSources(globalThis.location.href),
103
170
  page_path: path,
104
171
  page_title: document.title,
105
- page_url: url.href,
172
+ page_url: globalThis.location.href,
106
173
  library_name: "Formo Web SDK",
107
174
  library_version,
108
175
  };
@@ -156,7 +223,9 @@ class EventFactory implements IEventFactory {
156
223
  if (!local.isAvailable()) {
157
224
  commonEventData.anonymous_id = generateNativeUUID();
158
225
  } else {
159
- commonEventData.anonymous_id = generateAnonymousId();
226
+ commonEventData.anonymous_id = generateAnonymousId(
227
+ this.storageKeyManager.getKey(LOCAL_ANONYMOUS_ID_KEY)
228
+ );
160
229
  }
161
230
 
162
231
  if (formoEvent.address) {
@@ -354,11 +423,16 @@ class EventFactory implements IEventFactory {
354
423
  const trackEvent: Partial<IFormoEvent> = {
355
424
  properties: {
356
425
  ...properties,
357
- ...(properties?.revenue !== undefined && {
426
+ ...(properties?.revenue !== undefined && {
358
427
  revenue: Number(properties.revenue),
359
- currency: (typeof properties?.currency === "string" ? properties.currency : "USD").toLowerCase()
428
+ currency: (typeof properties?.currency === "string"
429
+ ? properties.currency
430
+ : "USD"
431
+ ).toLowerCase(),
432
+ }),
433
+ ...(properties?.points !== undefined && {
434
+ points: Number(properties.points),
360
435
  }),
361
- ...(properties?.points !== undefined && { points: Number(properties.points) }),
362
436
  },
363
437
  event,
364
438
  type: "track",
@@ -1,6 +1,7 @@
1
1
  import { Address, APIEvent } from "../../types";
2
2
  import { logger } from "../logger";
3
3
  import { IEventQueue } from "../queue";
4
+ import { IStorageKeyManager } from "../storage";
4
5
  import { EventFactory } from "./EventFactory";
5
6
  import { IEventFactory, IEventManager } from "./type";
6
7
 
@@ -15,9 +16,9 @@ class EventManager implements IEventManager {
15
16
  *
16
17
  * @param eventQueue Event queue instance
17
18
  */
18
- constructor(eventQueue: IEventQueue) {
19
+ constructor(eventQueue: IEventQueue, storageKeyManager: IStorageKeyManager) {
19
20
  this.eventQueue = eventQueue;
20
- this.eventFactory = new EventFactory();
21
+ this.eventFactory = new EventFactory(storageKeyManager);
21
22
  }
22
23
 
23
24
  /**
@@ -1,14 +1,13 @@
1
- import { LOCAL_ANONYMOUS_ID_KEY } from "../../constants";
2
1
  import { AnonymousID } from "../../types";
3
2
  import { generateNativeUUID } from "../../utils";
4
3
  import { local } from "../storage";
5
4
 
6
- const generateAnonymousId = (): AnonymousID => {
7
- const storedAnonymousId = local.get(LOCAL_ANONYMOUS_ID_KEY);
5
+ const generateAnonymousId = (key: string): AnonymousID => {
6
+ const storedAnonymousId = local.get(key);
8
7
  if (storedAnonymousId && typeof storedAnonymousId === "string")
9
8
  return storedAnonymousId as AnonymousID;
10
9
  const newAnonymousId = generateNativeUUID();
11
- local.set(LOCAL_ANONYMOUS_ID_KEY, newAnonymousId);
10
+ local.set(key, newAnonymousId);
12
11
  return newAnonymousId;
13
12
  };
14
13
 
@@ -1,2 +1,4 @@
1
+ export { StorageKey } from "./key";
1
2
  export { default as local } from "./local";
2
3
  export { default as session } from "./session";
4
+ export * from "./type";