From 2e23e93cecc4e7cdb1f34d55cffbf464115875db Mon Sep 17 00:00:00 2001 From: Gancho Radkov Date: Mon, 9 Sep 2024 14:24:36 +0300 Subject: [PATCH 1/4] feat: init event --- packages/core/src/controllers/events.ts | 49 ++++++++++++++++++++----- packages/core/src/core.ts | 1 + packages/core/test/events.spec.ts | 22 +++++++++++ packages/types/src/core/events.ts | 2 + packages/types/src/core/relayer.ts | 4 ++ 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/packages/core/src/controllers/events.ts b/packages/core/src/controllers/events.ts index fd073c832..e635743be 100644 --- a/packages/core/src/controllers/events.ts +++ b/packages/core/src/controllers/events.ts @@ -1,6 +1,6 @@ import { generateChildLogger, Logger } from "@walletconnect/logger"; import { ICore, IEventClient, EventClientTypes } from "@walletconnect/types"; -import { uuidv4 } from "@walletconnect/utils"; +import { formatUA, uuidv4 } from "@walletconnect/utils"; import { CORE_STORAGE_PREFIX, EVENTS_CLIENT_API_URL, @@ -16,12 +16,12 @@ export class EventClient extends IEventClient { public readonly context = EVENTS_STORAGE_CONTEXT; private readonly storagePrefix = CORE_STORAGE_PREFIX; private readonly storageVersion = EVENTS_STORAGE_VERSION; - private events = new Map(); private shouldPersist = false; constructor(public core: ICore, public logger: Logger, telemetryEnabled = true) { super(core, logger, telemetryEnabled); this.logger = generateChildLogger(logger, this.context); + this.telemetryEnabled = telemetryEnabled; if (telemetryEnabled) { this.restore().then(async () => { await this.submit(); @@ -39,6 +39,32 @@ export class EventClient extends IEventClient { ); } + public init: IEventClient["init"] = async () => { + if (typeof process !== "undefined" && process.env.IS_VITEST === "true") return; + try { + const initEvent = { + eventId: uuidv4(), + bundleId: this.core.projectId || "", + timestamp: Date.now(), + props: { + event: "INIT", + type: "", + properties: { + client_id: await this.core.crypto.getClientId(), + user_agent: formatUA( + this.core.relayer.protocol, + this.core.relayer.version, + RELAYER_SDK_VERSION, + ), + }, + }, + }; + await this.sendPost([initEvent] as unknown as EventClientTypes.Event[]); + } catch (error) { + this.logger.warn(error); + } + }; + public createEvent: IEventClient["createEvent"] = (params) => { const { event = "ERROR", @@ -172,13 +198,7 @@ export class EventClient extends IEventClient { if (eventsToSend.length === 0) return; try { - const response = await fetch( - `${EVENTS_CLIENT_API_URL}?projectId=${this.core.projectId}&st=events_sdk&sv=js-${RELAYER_SDK_VERSION}`, - { - method: "POST", - body: JSON.stringify(eventsToSend), - }, - ); + const response = await this.sendPost(eventsToSend); if (response.ok) { for (const event of eventsToSend) { this.events.delete(event.eventId); @@ -189,4 +209,15 @@ export class EventClient extends IEventClient { this.logger.warn(error); } }; + + private sendPost = async (events: EventClientTypes.Event[]) => { + const response = await fetch( + `${EVENTS_CLIENT_API_URL}?projectId=${this.core.projectId}&st=events_sdk&sv=js-${RELAYER_SDK_VERSION}`, + { + method: "POST", + body: JSON.stringify(events), + }, + ); + return response; + }; } diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index feca3dafe..b40394dbf 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -194,6 +194,7 @@ export class Core extends ICore { await this.relayer.init(); await this.heartbeat.init(); await this.pairing.init(); + this.eventClient.init(); this.linkModeSupportedApps = (await this.storage.getItem(WALLETCONNECT_LINK_MODE_APPS)) || []; this.initialized = true; diff --git a/packages/core/test/events.spec.ts b/packages/core/test/events.spec.ts index c5928f709..563e83aab 100644 --- a/packages/core/test/events.spec.ts +++ b/packages/core/test/events.spec.ts @@ -193,4 +193,26 @@ describe("Events Client", () => { // @ts-expect-error - accessing private properties expect(core.eventClient.events.size).toBe(0); }); + + it("should send init event", async () => { + process.env.IS_VITEST = false as any; + const core = new Core({ ...TEST_CORE_OPTIONS, telemetryEnabled: false }); + let initCalled = false; + // @ts-expect-error - accessing private properties + core.eventClient.sendPost = async (payload: any) => { + initCalled = true; + expect(payload).toBeDefined(); + expect(payload.length).to.eql(1); + expect(payload[0].props.event).to.eql("INIT"); + expect(payload[0].props.properties.client_id).to.eql(await core.crypto.getClientId()); + }; + await core.start(); + await new Promise((resolve) => setTimeout(resolve, 500)); + + if (!initCalled) { + throw new Error("init not called"); + } + + process.env.IS_VITEST = true as any; + }); }); diff --git a/packages/types/src/core/events.ts b/packages/types/src/core/events.ts index 271c01153..d82699544 100644 --- a/packages/types/src/core/events.ts +++ b/packages/types/src/core/events.ts @@ -30,6 +30,8 @@ export abstract class IEventClient { constructor(public core: ICore, public logger: Logger, public telemetryEnabled: boolean) {} + public abstract init(): Promise; + public abstract createEvent(params: { event?: "ERROR"; type?: string; diff --git a/packages/types/src/core/relayer.ts b/packages/types/src/core/relayer.ts index d74afa33a..d55051ba3 100644 --- a/packages/types/src/core/relayer.ts +++ b/packages/types/src/core/relayer.ts @@ -78,6 +78,10 @@ export interface RelayerClientMetadata { } export abstract class IRelayer extends IEvents { + public abstract protocol: string; + + public abstract version: number; + public abstract core: ICore; public abstract logger: Logger; From bba14b8a149d46b15cc6ec7ce6ed01d170036911 Mon Sep 17 00:00:00 2001 From: Gancho Radkov Date: Mon, 16 Sep 2024 16:36:03 +0300 Subject: [PATCH 2/4] refactor: abstracts process checks into util --- packages/core/src/controllers/events.ts | 11 +++++------ packages/core/src/controllers/verify.ts | 4 ++-- packages/sign-client/src/controllers/engine.ts | 6 ++---- packages/utils/src/misc.ts | 4 ++++ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/core/src/controllers/events.ts b/packages/core/src/controllers/events.ts index e635743be..a16ccb193 100644 --- a/packages/core/src/controllers/events.ts +++ b/packages/core/src/controllers/events.ts @@ -1,6 +1,6 @@ import { generateChildLogger, Logger } from "@walletconnect/logger"; import { ICore, IEventClient, EventClientTypes } from "@walletconnect/types"; -import { formatUA, uuidv4 } from "@walletconnect/utils"; +import { formatUA, isTestRun, uuidv4 } from "@walletconnect/utils"; import { CORE_STORAGE_PREFIX, EVENTS_CLIENT_API_URL, @@ -40,11 +40,10 @@ export class EventClient extends IEventClient { } public init: IEventClient["init"] = async () => { - if (typeof process !== "undefined" && process.env.IS_VITEST === "true") return; + if (isTestRun()) return; try { const initEvent = { eventId: uuidv4(), - bundleId: this.core.projectId || "", timestamp: Date.now(), props: { event: "INIT", @@ -59,7 +58,7 @@ export class EventClient extends IEventClient { }, }, }; - await this.sendPost([initEvent] as unknown as EventClientTypes.Event[]); + await this.sendEvent([initEvent] as unknown as EventClientTypes.Event[]); } catch (error) { this.logger.warn(error); } @@ -198,7 +197,7 @@ export class EventClient extends IEventClient { if (eventsToSend.length === 0) return; try { - const response = await this.sendPost(eventsToSend); + const response = await this.sendEvent(eventsToSend); if (response.ok) { for (const event of eventsToSend) { this.events.delete(event.eventId); @@ -210,7 +209,7 @@ export class EventClient extends IEventClient { } }; - private sendPost = async (events: EventClientTypes.Event[]) => { + private sendEvent = async (events: EventClientTypes.Event[]) => { const response = await fetch( `${EVENTS_CLIENT_API_URL}?projectId=${this.core.projectId}&st=events_sdk&sv=js-${RELAYER_SDK_VERSION}`, { diff --git a/packages/core/src/controllers/verify.ts b/packages/core/src/controllers/verify.ts index e748be805..98f1457f8 100644 --- a/packages/core/src/controllers/verify.ts +++ b/packages/core/src/controllers/verify.ts @@ -1,6 +1,6 @@ import { generateChildLogger, getLoggerContext, Logger } from "@walletconnect/logger"; import { ICore, IVerify } from "@walletconnect/types"; -import { isBrowser, isNode, P256KeyDataType, verifyP256Jwt } from "@walletconnect/utils"; +import { isBrowser, isNode, isTestRun, P256KeyDataType, verifyP256Jwt } from "@walletconnect/utils"; import { FIVE_SECONDS, ONE_SECOND, toMiliseconds } from "@walletconnect/time"; import { getDocument } from "@walletconnect/window-getters"; import { decodeJWT } from "@walletconnect/relay-auth"; @@ -40,7 +40,7 @@ export class Verify extends IVerify { super(core, logger, store); this.logger = generateChildLogger(logger, this.name); this.abortController = new AbortController(); - this.isDevEnv = isNode() && process.env.IS_VITEST; + this.isDevEnv = isTestRun(); this.init(); } diff --git a/packages/sign-client/src/controllers/engine.ts b/packages/sign-client/src/controllers/engine.ts index c9fce87b0..fc84f6072 100644 --- a/packages/sign-client/src/controllers/engine.ts +++ b/packages/sign-client/src/controllers/engine.ts @@ -96,6 +96,7 @@ import { BASE64URL, getSearchParamFromURL, isReactNative, + isTestRun, } from "@walletconnect/utils"; import EventEmmiter from "events"; import { @@ -2914,10 +2915,7 @@ export class Engine extends IEngine { }; private registerLinkModeListeners = async () => { - if ( - (typeof process !== "undefined" && process.env.IS_VITEST) || - (isReactNative() && this.client.metadata.redirect?.linkMode) - ) { + if (isTestRun() || (isReactNative() && this.client.metadata.redirect?.linkMode)) { const linking = (global as any)?.Linking; // global.Linking is set by react-native-compat if (typeof linking !== "undefined") { diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index a352cbae1..77e0f96e8 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -441,3 +441,7 @@ export function uuidv4() { return v.toString(16); }); } + +export function isTestRun() { + return typeof process !== "undefined" && process.env.IS_VITEST === "true"; +} From da12fae198b3a39a39822d19ef3272e74d825403 Mon Sep 17 00:00:00 2001 From: Gancho Radkov Date: Mon, 16 Sep 2024 16:52:33 +0300 Subject: [PATCH 3/4] chore: rm unused var --- packages/core/src/controllers/verify.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/controllers/verify.ts b/packages/core/src/controllers/verify.ts index 98f1457f8..bcc7636e3 100644 --- a/packages/core/src/controllers/verify.ts +++ b/packages/core/src/controllers/verify.ts @@ -1,6 +1,6 @@ import { generateChildLogger, getLoggerContext, Logger } from "@walletconnect/logger"; import { ICore, IVerify } from "@walletconnect/types"; -import { isBrowser, isNode, isTestRun, P256KeyDataType, verifyP256Jwt } from "@walletconnect/utils"; +import { isBrowser, isTestRun, P256KeyDataType, verifyP256Jwt } from "@walletconnect/utils"; import { FIVE_SECONDS, ONE_SECOND, toMiliseconds } from "@walletconnect/time"; import { getDocument } from "@walletconnect/window-getters"; import { decodeJWT } from "@walletconnect/relay-auth"; From 4a96e1f19a23991351feb477df2b6a07e55e0eb5 Mon Sep 17 00:00:00 2001 From: Gancho Radkov Date: Mon, 16 Sep 2024 17:03:16 +0300 Subject: [PATCH 4/4] fix: test --- packages/core/test/events.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/events.spec.ts b/packages/core/test/events.spec.ts index 563e83aab..82666786e 100644 --- a/packages/core/test/events.spec.ts +++ b/packages/core/test/events.spec.ts @@ -199,7 +199,7 @@ describe("Events Client", () => { const core = new Core({ ...TEST_CORE_OPTIONS, telemetryEnabled: false }); let initCalled = false; // @ts-expect-error - accessing private properties - core.eventClient.sendPost = async (payload: any) => { + core.eventClient.sendEvent = async (payload: any) => { initCalled = true; expect(payload).toBeDefined(); expect(payload.length).to.eql(1);