Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions __tests__/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,46 @@ test("WTS node client reuses existing user.id from config", async () => {
expect(body.distinct_id).toBe(existingId);
});

test("WTS node client uses a provided distinctId as-is", async () => {
const wts = new WTS({
source: "cli",
configPath,
distinctId: "global-config-id-abc",
apiUrl: "https://t.example.com"
});
wts.track("cli-create-webiny-project-start");

await new Promise(r => setTimeout(r, 10));
const body = JSON.parse(capturedRequests[0]!.init.body as string);
expect(body.distinct_id).toBe("global-config-id-abc");
});

test("WTS node client leaves the config file untouched when distinctId is provided", async () => {
const wts = new WTS({ source: "cli", configPath, distinctId: "global-config-id-abc" });
wts.track("cli-create-webiny-project-start");

await new Promise(r => setTimeout(r, 10));
// No machine id should be minted into ~/.webiny/config when an id is injected.
expect(existsSync(configPath)).toBe(false);
});

test("WTS node client prefers distinctId over an existing user.id in config", async () => {
mkdirSync(join(tmpDir, ".webiny"), { recursive: true });
writeFileSync(configPath, JSON.stringify({ user: { id: "existing-user-id" } }));

const wts = new WTS({
source: "cli",
configPath,
distinctId: "global-config-id-abc",
apiUrl: "https://t.example.com"
});
wts.track("cli-create-webiny-project-start");

await new Promise(r => setTimeout(r, 10));
const body = JSON.parse(capturedRequests[0]!.init.body as string);
expect(body.distinct_id).toBe("global-config-id-abc");
});

test("WTS node client honors WEBINY_TELEMETRY=false env var", async () => {
process.env.WEBINY_TELEMETRY = "false";

Expand Down
17 changes: 15 additions & 2 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ const OPT_OUT_ENV = "WEBINY_TELEMETRY";
export interface NodeClientConfig extends ClientConfig {
/** Override the path to the Webiny config file. Defaults to ~/.webiny/config. */
configPath?: string;
/**
* Force a specific distinct_id instead of reading/minting the machine id in
* the Webiny config file. When provided, it's used as-is and the config file
* is left untouched. Webiny passes the canonical `@webiny/global-config` id
* here so CLI, admin, and website events share one identity; without it the
* client falls back to its own `user.id` field, which is a different UUID.
*/
distinctId?: string;
/** Number of retry attempts for transient HTTP errors. Defaults to 3. */
retries?: number;
/** Base delay in ms between retries (exponential backoff). Defaults to 200. */
Expand All @@ -28,12 +36,17 @@ export interface NodeClientConfig extends ClientConfig {
class NodeIdentity implements Identity {
private path: string;
private cached: string | null = null;
private fixedId: string | null;

constructor(configPath?: string) {
constructor(configPath?: string, fixedId?: string) {
this.path = configPath ?? join(homedir(), CONFIG_DIR, CONFIG_FILE);
this.fixedId = fixedId ?? null;
}

getDistinctId(): string | null {
if (this.fixedId) {
return this.fixedId;
}
if (this.cached) {
return this.cached;
}
Expand Down Expand Up @@ -120,7 +133,7 @@ export class WTS extends TelemetryClient {
constructor(config: NodeClientConfig) {
super(
config,
new NodeIdentity(config.configPath),
new NodeIdentity(config.configPath, config.distinctId),
new NodeTransport(config.retries ?? 3, config.retryDelay ?? 200)
);
}
Expand Down
Loading