@formo/analytics 1.15.1 → 1.16.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.
- package/dist/cjs/src/FormoAnalytics.d.ts +9 -3
- package/dist/cjs/src/FormoAnalytics.d.ts.map +1 -1
- package/dist/cjs/src/FormoAnalytics.js +114 -122
- package/dist/cjs/src/FormoAnalytics.js.map +1 -1
- package/dist/cjs/src/constants/base.d.ts +1 -1
- package/dist/cjs/src/constants/base.d.ts.map +1 -1
- package/dist/cjs/src/constants/base.js +2 -2
- package/dist/cjs/src/constants/base.js.map +1 -1
- package/dist/cjs/src/constants/events.d.ts +1 -0
- package/dist/cjs/src/constants/events.d.ts.map +1 -1
- package/dist/cjs/src/constants/events.js +1 -0
- package/dist/cjs/src/constants/events.js.map +1 -1
- package/dist/cjs/src/lib/logger.d.ts +8 -1
- package/dist/cjs/src/lib/logger.d.ts.map +1 -1
- package/dist/cjs/src/lib/logger.js +15 -5
- package/dist/cjs/src/lib/logger.js.map +1 -1
- package/dist/cjs/src/lib/queue.d.ts +2 -2
- package/dist/cjs/src/lib/queue.d.ts.map +1 -1
- package/dist/cjs/src/lib/queue.js +14 -13
- package/dist/cjs/src/lib/queue.js.map +1 -1
- package/dist/cjs/src/types/events.d.ts +1 -1
- package/dist/cjs/src/types/events.d.ts.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/src/FormoAnalytics.d.ts +9 -3
- package/dist/esm/src/FormoAnalytics.d.ts.map +1 -1
- package/dist/esm/src/FormoAnalytics.js +117 -125
- package/dist/esm/src/FormoAnalytics.js.map +1 -1
- package/dist/esm/src/constants/base.d.ts +1 -1
- package/dist/esm/src/constants/base.d.ts.map +1 -1
- package/dist/esm/src/constants/base.js +1 -1
- package/dist/esm/src/constants/base.js.map +1 -1
- package/dist/esm/src/constants/events.d.ts +1 -0
- package/dist/esm/src/constants/events.d.ts.map +1 -1
- package/dist/esm/src/constants/events.js +1 -0
- package/dist/esm/src/constants/events.js.map +1 -1
- package/dist/esm/src/lib/logger.d.ts +8 -1
- package/dist/esm/src/lib/logger.d.ts.map +1 -1
- package/dist/esm/src/lib/logger.js +15 -5
- package/dist/esm/src/lib/logger.js.map +1 -1
- package/dist/esm/src/lib/queue.d.ts +2 -2
- package/dist/esm/src/lib/queue.d.ts.map +1 -1
- package/dist/esm/src/lib/queue.js +14 -13
- package/dist/esm/src/lib/queue.js.map +1 -1
- package/dist/esm/src/types/events.d.ts +1 -1
- package/dist/esm/src/types/events.d.ts.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/FormoAnalytics.ts +97 -84
- package/src/constants/base.ts +3 -2
- package/src/constants/events.ts +8 -7
- package/src/lib/logger.ts +28 -6
- package/src/lib/queue.ts +12 -11
- package/src/types/events.ts +1 -1
package/package.json
CHANGED
package/src/FormoAnalytics.ts
CHANGED
|
@@ -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,
|
|
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 {
|
|
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:
|
|
78
|
+
private userId: string | null = null;
|
|
81
79
|
|
|
82
80
|
config: Config;
|
|
83
81
|
currentChainId?: ChainID;
|
|
@@ -95,13 +93,10 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
95
93
|
this.session = new FormoAnalyticsSession();
|
|
96
94
|
|
|
97
95
|
// Initialize logger with configuration from options
|
|
98
|
-
|
|
99
|
-
enabled: false,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (loggerConfig.levels) {
|
|
103
|
-
logger.setEnabledLevels(loggerConfig.levels);
|
|
104
|
-
}
|
|
96
|
+
Logger.init({
|
|
97
|
+
enabled: options.logger?.enabled || false,
|
|
98
|
+
enabledLevels: options.logger?.levels || [],
|
|
99
|
+
});
|
|
105
100
|
|
|
106
101
|
this.eventQueue = new EventQueue(this.config.writeKey, {
|
|
107
102
|
url: EVENTS_API_URL,
|
|
@@ -112,7 +107,7 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
112
107
|
});
|
|
113
108
|
|
|
114
109
|
this.anonymousId = this.getAnonymousId();
|
|
115
|
-
this.
|
|
110
|
+
this.userId = session.get(SESSION_USER_ID_KEY) as string | null;
|
|
116
111
|
|
|
117
112
|
// TODO: replace with eip6963
|
|
118
113
|
const provider = options.provider || window?.ethereum;
|
|
@@ -130,9 +125,9 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
130
125
|
): Promise<FormoAnalytics> {
|
|
131
126
|
const analytics = new FormoAnalytics(writeKey, options);
|
|
132
127
|
|
|
133
|
-
//
|
|
128
|
+
// Detect
|
|
134
129
|
const providers = await analytics.getProviders();
|
|
135
|
-
await analytics.
|
|
130
|
+
await analytics.detectWallets(providers);
|
|
136
131
|
|
|
137
132
|
return analytics;
|
|
138
133
|
}
|
|
@@ -321,16 +316,15 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
321
316
|
public async identify({
|
|
322
317
|
address,
|
|
323
318
|
providerName,
|
|
319
|
+
userId,
|
|
324
320
|
rdns,
|
|
325
321
|
}: {
|
|
326
322
|
address: Address | null;
|
|
327
323
|
providerName?: string;
|
|
324
|
+
userId?: string;
|
|
328
325
|
rdns?: string;
|
|
329
326
|
}): Promise<void> {
|
|
330
|
-
if (this.
|
|
331
|
-
return logger.warn("Identify: Wallet already identified in this session");
|
|
332
|
-
|
|
333
|
-
this.session.identify();
|
|
327
|
+
if (userId) this.userId = userId || null;
|
|
334
328
|
await this.trackEvent(Event.IDENTIFY, {
|
|
335
329
|
address,
|
|
336
330
|
providerName,
|
|
@@ -338,6 +332,30 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
338
332
|
});
|
|
339
333
|
}
|
|
340
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Emits an identify event with current wallet address.
|
|
337
|
+
* @param {Address} params.address
|
|
338
|
+
* @returns {Promise<void>}
|
|
339
|
+
*/
|
|
340
|
+
private async detectWallet({
|
|
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
|
+
`detectWallet: 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
|
+
|
|
341
359
|
/**
|
|
342
360
|
* Emits a custom event with custom data.
|
|
343
361
|
* @param {string} action
|
|
@@ -498,7 +516,6 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
498
516
|
|
|
499
517
|
return;
|
|
500
518
|
} catch (error) {
|
|
501
|
-
logger.info("Transaction listener catch");
|
|
502
519
|
logger.error("Transaction error:", error);
|
|
503
520
|
const rpcError = error as RPCError;
|
|
504
521
|
if (rpcError && rpcError?.code === 4001) {
|
|
@@ -577,7 +594,6 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
577
594
|
return Promise.resolve();
|
|
578
595
|
}
|
|
579
596
|
this.currentConnectedAddress = address;
|
|
580
|
-
this.userId = await this.getUserId(address);
|
|
581
597
|
}
|
|
582
598
|
|
|
583
599
|
// Proceed only if the address exists
|
|
@@ -650,12 +666,16 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
650
666
|
private async trackEvent(action: string, payload: any): Promise<void> {
|
|
651
667
|
try {
|
|
652
668
|
const address = await this.getAddress();
|
|
653
|
-
const user_id =
|
|
669
|
+
const user_id = this.userId;
|
|
670
|
+
|
|
671
|
+
if (payload?.userId) {
|
|
672
|
+
delete payload.userId;
|
|
673
|
+
}
|
|
654
674
|
|
|
655
675
|
const requestData: RequestEvent = {
|
|
656
676
|
anonymous_id: this.anonymousId as UUID,
|
|
657
677
|
user_id,
|
|
658
|
-
address,
|
|
678
|
+
address: address?.toLowerCase() || null,
|
|
659
679
|
timestamp: new Date().toISOString(),
|
|
660
680
|
action,
|
|
661
681
|
version: "1",
|
|
@@ -689,38 +709,54 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
689
709
|
return providers;
|
|
690
710
|
}
|
|
691
711
|
|
|
692
|
-
private async
|
|
712
|
+
private async detectWallets(
|
|
693
713
|
providers: readonly EIP6963ProviderDetail[]
|
|
694
714
|
): Promise<void> {
|
|
695
715
|
try {
|
|
696
716
|
for (const eip6963ProviderDetail of providers) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
eip6963ProviderDetail?.
|
|
700
|
-
);
|
|
701
|
-
// Identify with accounts
|
|
702
|
-
if (accounts && accounts.length > 0) {
|
|
703
|
-
for (const address of accounts) {
|
|
704
|
-
await this.identify({
|
|
705
|
-
address,
|
|
706
|
-
providerName: eip6963ProviderDetail?.info.name,
|
|
707
|
-
rdns: eip6963ProviderDetail?.info.rdns,
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
} else {
|
|
711
|
-
// Identify without accounts
|
|
712
|
-
await this.identify({
|
|
713
|
-
address: null,
|
|
714
|
-
providerName: eip6963ProviderDetail?.info.name,
|
|
715
|
-
rdns: eip6963ProviderDetail?.info.rdns,
|
|
716
|
-
});
|
|
717
|
-
}
|
|
717
|
+
await this.detectWallet({
|
|
718
|
+
providerName: eip6963ProviderDetail?.info.name,
|
|
719
|
+
rdns: eip6963ProviderDetail?.info.rdns,
|
|
720
|
+
});
|
|
718
721
|
}
|
|
719
722
|
} catch (err) {
|
|
720
|
-
logger.error("Error
|
|
723
|
+
logger.error("Error detect all wallets:", err);
|
|
721
724
|
}
|
|
722
725
|
}
|
|
723
726
|
|
|
727
|
+
// TODO: Refactoring => public this function as API
|
|
728
|
+
// private async identifyAll(
|
|
729
|
+
// providers: readonly EIP6963ProviderDetail[]
|
|
730
|
+
// ): Promise<void> {
|
|
731
|
+
// try {
|
|
732
|
+
// for (const eip6963ProviderDetail of providers) {
|
|
733
|
+
// if (!eip6963ProviderDetail) continue;
|
|
734
|
+
// const accounts = await this.getAccounts(
|
|
735
|
+
// eip6963ProviderDetail?.provider
|
|
736
|
+
// );
|
|
737
|
+
// // Identify with accounts
|
|
738
|
+
// if (accounts && accounts.length > 0) {
|
|
739
|
+
// for (const address of accounts) {
|
|
740
|
+
// await this.identify({
|
|
741
|
+
// address,
|
|
742
|
+
// providerName: eip6963ProviderDetail?.info.name,
|
|
743
|
+
// rdns: eip6963ProviderDetail?.info.rdns,
|
|
744
|
+
// });
|
|
745
|
+
// }
|
|
746
|
+
// } else {
|
|
747
|
+
// // Identify without accounts
|
|
748
|
+
// await this.identify({
|
|
749
|
+
// address: null,
|
|
750
|
+
// providerName: eip6963ProviderDetail?.info.name,
|
|
751
|
+
// rdns: eip6963ProviderDetail?.info.rdns,
|
|
752
|
+
// });
|
|
753
|
+
// }
|
|
754
|
+
// }
|
|
755
|
+
// } catch (err) {
|
|
756
|
+
// logger.error("Error identifying all:", err);
|
|
757
|
+
// }
|
|
758
|
+
// }
|
|
759
|
+
|
|
724
760
|
get provider(): EIP1193Provider | undefined {
|
|
725
761
|
return this._provider;
|
|
726
762
|
}
|
|
@@ -734,31 +770,6 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
734
770
|
return newAnonymousId;
|
|
735
771
|
}
|
|
736
772
|
|
|
737
|
-
private async getUserId(address: string | null): Promise<UUID | null> {
|
|
738
|
-
const storedUserId = session.get(SESSION_USER_ID_KEY);
|
|
739
|
-
if (storedUserId && typeof storedUserId === "string")
|
|
740
|
-
return storedUserId as UUID;
|
|
741
|
-
|
|
742
|
-
if (address) {
|
|
743
|
-
const res = await fetch(`${USER_API_URL}?address=${address}`, {
|
|
744
|
-
headers: EVENTS_API_REQUEST_HEADER(this.writeKey),
|
|
745
|
-
method: "GET",
|
|
746
|
-
});
|
|
747
|
-
const data = await res.json();
|
|
748
|
-
const userId = data?.data?.[0]?.user_id;
|
|
749
|
-
if (userId) {
|
|
750
|
-
session.set(SESSION_USER_ID_KEY, userId);
|
|
751
|
-
return userId;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
const newUserId = generateNativeUUID();
|
|
755
|
-
session.set(SESSION_USER_ID_KEY, newUserId);
|
|
756
|
-
return newUserId;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
return null;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
773
|
private async getAddress(): Promise<Address | null> {
|
|
763
774
|
if (this.currentConnectedAddress) return this.currentConnectedAddress;
|
|
764
775
|
if (!this?.provider) {
|
|
@@ -769,7 +780,6 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
769
780
|
try {
|
|
770
781
|
const accounts = await this.getAccounts();
|
|
771
782
|
if (accounts && accounts.length > 0) {
|
|
772
|
-
// TODO: fetch userId if account is valid, generate userId if no userId matches address from tinybird
|
|
773
783
|
if (isAddress(accounts[0])) {
|
|
774
784
|
return accounts[0];
|
|
775
785
|
}
|
|
@@ -865,12 +875,12 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
865
875
|
locale: language,
|
|
866
876
|
location,
|
|
867
877
|
referrer: document.referrer,
|
|
868
|
-
utm_source: params.get("utm_source"),
|
|
869
|
-
utm_medium: params.get("utm_medium"),
|
|
870
|
-
utm_campaign: params.get("utm_campaign"),
|
|
871
|
-
utm_content: params.get("utm_content"),
|
|
872
|
-
utm_term: params.get("utm_term"),
|
|
873
|
-
ref: params.get("ref"),
|
|
878
|
+
utm_source: params.get("utm_source")?.trim() || "",
|
|
879
|
+
utm_medium: params.get("utm_medium")?.trim() || "",
|
|
880
|
+
utm_campaign: params.get("utm_campaign")?.trim() || "",
|
|
881
|
+
utm_content: params.get("utm_content")?.trim() || "",
|
|
882
|
+
utm_term: params.get("utm_term")?.trim() || "",
|
|
883
|
+
ref: params.get("ref")?.trim() || "",
|
|
874
884
|
...eventSpecificPayload,
|
|
875
885
|
};
|
|
876
886
|
}
|
|
@@ -925,18 +935,21 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
925
935
|
}
|
|
926
936
|
|
|
927
937
|
interface IFormoAnalyticsSession {
|
|
928
|
-
|
|
929
|
-
|
|
938
|
+
isWalletDetected(rdns: string): boolean;
|
|
939
|
+
markWalletdetected(rdns: string): void;
|
|
930
940
|
}
|
|
931
941
|
|
|
932
942
|
class FormoAnalyticsSession implements IFormoAnalyticsSession {
|
|
933
943
|
constructor() {}
|
|
934
944
|
|
|
935
|
-
public
|
|
936
|
-
|
|
945
|
+
public isWalletDetected(rdns: string): boolean {
|
|
946
|
+
const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
|
|
947
|
+
return rdnses.includes(rdns);
|
|
937
948
|
}
|
|
938
949
|
|
|
939
|
-
public
|
|
940
|
-
session.
|
|
950
|
+
public markWalletdetected(rdns: string): void {
|
|
951
|
+
const rdnses = (session.get(SESSION_WALLET_DETECTED_KEY) as string[]) || [];
|
|
952
|
+
rdnses.push(rdns);
|
|
953
|
+
session.set(SESSION_WALLET_DETECTED_KEY, rdnses);
|
|
941
954
|
}
|
|
942
955
|
}
|
package/src/constants/base.ts
CHANGED
|
@@ -2,8 +2,9 @@ const STORAGE_PREFIX = "formo-";
|
|
|
2
2
|
|
|
3
3
|
const generateStoragePrefix = (prefix: string) => `${STORAGE_PREFIX}${prefix}`;
|
|
4
4
|
|
|
5
|
-
export const
|
|
6
|
-
|
|
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
|
);
|
package/src/constants/events.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export enum Event {
|
|
2
|
-
PAGE =
|
|
3
|
-
IDENTIFY =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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/logger.ts
CHANGED
|
@@ -5,17 +5,39 @@ export class Logger {
|
|
|
5
5
|
private enabledLevels: Set<LogLevel>;
|
|
6
6
|
private enabled: boolean;
|
|
7
7
|
|
|
8
|
-
private constructor(
|
|
8
|
+
private constructor(
|
|
9
|
+
enabled: boolean = false,
|
|
10
|
+
enabledLevels: LogLevel[] = []
|
|
11
|
+
) {
|
|
9
12
|
this.enabled = enabled;
|
|
10
13
|
this.enabledLevels = new Set(enabledLevels);
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
public static
|
|
14
|
-
enabled
|
|
15
|
-
enabledLevels
|
|
16
|
-
):
|
|
16
|
+
public static init(config: {
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
enabledLevels?: LogLevel[];
|
|
19
|
+
}): void {
|
|
20
|
+
// Get or create instance
|
|
21
|
+
const instance = Logger.getInstance();
|
|
22
|
+
|
|
23
|
+
// Update configuration
|
|
24
|
+
if (config.enabled !== undefined) {
|
|
25
|
+
instance.setEnabled(config.enabled);
|
|
26
|
+
}
|
|
27
|
+
if (config.enabledLevels !== undefined) {
|
|
28
|
+
instance.setEnabledLevels(config.enabledLevels);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public static getInstance(config?: {
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
enabledLevels?: LogLevel[];
|
|
35
|
+
}): Logger {
|
|
17
36
|
if (!Logger.instance) {
|
|
18
|
-
Logger.instance = new Logger(
|
|
37
|
+
Logger.instance = new Logger(
|
|
38
|
+
config?.enabled ?? false,
|
|
39
|
+
config?.enabledLevels ?? []
|
|
40
|
+
);
|
|
19
41
|
}
|
|
20
42
|
return Logger.instance;
|
|
21
43
|
}
|
package/src/lib/queue.ts
CHANGED
|
@@ -96,16 +96,17 @@ export class EventQueue {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
//#region Public functions
|
|
99
|
-
async enqueue(
|
|
99
|
+
async enqueue(event: RequestEvent, callback?: (...args: any) => void) {
|
|
100
100
|
callback = callback || noop;
|
|
101
101
|
|
|
102
|
-
const formattedTimestamp = toDateHourMinute(new Date(
|
|
103
|
-
|
|
102
|
+
const formattedTimestamp = toDateHourMinute(new Date(event.timestamp));
|
|
103
|
+
const originTimestamp = event.timestamp;
|
|
104
|
+
event.timestamp = formattedTimestamp;
|
|
104
105
|
|
|
105
|
-
const
|
|
106
|
-
const
|
|
106
|
+
const eventString = JSON.stringify(event);
|
|
107
|
+
const eventId = await hash(eventString);
|
|
107
108
|
// check if the message already exists
|
|
108
|
-
if (await this.
|
|
109
|
+
if (await this.isDuplicate(eventId)) {
|
|
109
110
|
logger.warn(
|
|
110
111
|
`Event already enqueued, try again after ${millisecondsToSecond(
|
|
111
112
|
this.flushIntervalMs
|
|
@@ -114,10 +115,10 @@ export class EventQueue {
|
|
|
114
115
|
return;
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
this.queue.push({ message: { ...
|
|
118
|
+
this.queue.push({ message: { ...event, timestamp: originTimestamp, id: eventId }, callback });
|
|
118
119
|
|
|
119
120
|
logger.log(
|
|
120
|
-
`Event enqueued: ${getActionDescriptor(
|
|
121
|
+
`Event enqueued: ${getActionDescriptor(event.action, event.payload)}`
|
|
121
122
|
);
|
|
122
123
|
|
|
123
124
|
if (!this.flushed) {
|
|
@@ -220,11 +221,11 @@ export class EventQueue {
|
|
|
220
221
|
return false;
|
|
221
222
|
}
|
|
222
223
|
|
|
223
|
-
private async
|
|
224
|
+
private async isDuplicate(eventId: string) {
|
|
224
225
|
// check if exists a message with identical payload within 1 minute
|
|
225
|
-
if (this.payloadHashes.has(
|
|
226
|
+
if (this.payloadHashes.has(eventId)) return true;
|
|
226
227
|
|
|
227
|
-
this.payloadHashes.add(
|
|
228
|
+
this.payloadHashes.add(eventId);
|
|
228
229
|
return false;
|
|
229
230
|
}
|
|
230
231
|
|