From f0d01622196619b5fd22997b33d8b07e19d584c1 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Thu, 4 Sep 2025 18:02:07 +0200 Subject: [PATCH 01/10] chore: enrich and improve telemetry events --- src/extension.ts | 8 ++- src/plugins/setup.ts | 111 +++++++++++++++++++++++++++---------- src/utils/authenticate.ts | 20 ++++++- src/utils/configure-aws.ts | 18 ++++-- src/utils/install.ts | 8 +-- src/utils/license.ts | 17 ++++++ src/utils/manage.ts | 44 +++++++++++---- src/utils/telemetry.ts | 64 +++++++++++++++++---- 8 files changed, 228 insertions(+), 62 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 1eeac76..ed1f267 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,7 +10,10 @@ import statusBar from "./plugins/status-bar.ts"; import { PluginManager } from "./plugins.ts"; import { createContainerStatusTracker } from "./utils/container-status.ts"; import { createLocalStackStatusTracker } from "./utils/localstack-status.ts"; -import { getOrCreateExtensionSessionId } from "./utils/manage.ts"; +import { + getOrCreateExtensionSessionId, + getOrCreateMachineId, +} from "./utils/manage.ts"; import { createSetupStatusTracker } from "./utils/setup-status.ts"; import { createTelemetry } from "./utils/telemetry.ts"; import { createTimeTracker } from "./utils/time-tracker.ts"; @@ -78,7 +81,8 @@ export async function activate(context: ExtensionContext) { const startTelemetry = Date.now(); outputChannel.trace(`[telemetry]: Starting...`); const sessionId = await getOrCreateExtensionSessionId(context); - const telemetry = createTelemetry(outputChannel, sessionId); + const machineId = await getOrCreateMachineId(context); + const telemetry = createTelemetry(outputChannel, sessionId, machineId); const endTelemetry = Date.now(); outputChannel.trace( `[telemetry]: Completed in ${ms(endTelemetry - startTelemetry, { diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index 16e4bdf..a298705 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -5,6 +5,7 @@ import { checkIsAuthenticated, requestAuthentication, saveAuthToken, + readAuthToken, } from "../utils/authenticate.ts"; import { configureAwsProfiles } from "../utils/configure-aws.ts"; import { runInstallProcess } from "../utils/install.ts"; @@ -38,26 +39,6 @@ export default createPlugin( payload: { namespace: "onboarding", origin: origin_trigger, - expected_steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - position: 1, - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - position: 2, - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - position: 3, - }, - ], }, }); @@ -84,7 +65,7 @@ export default createPlugin( payload: { namespace: "onboarding", origin: origin_trigger, - position: 1, + step_order: 1, started_at: installationStartedAt, ended_at: new Date().toISOString(), status: "CANCELLED", @@ -113,8 +94,38 @@ export default createPlugin( name: "setup_ended", payload: { namespace: "onboarding", - steps: [1, 2, 3], + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "COMPLETED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "CANCELLED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "SKIPPED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "SKIPPED", + }, + ], status: "CANCELLED", + auth_token: await readAuthToken(), }, }); return; @@ -128,7 +139,7 @@ export default createPlugin( payload: { namespace: "onboarding", origin: origin_trigger, - position: 2, + step_order: 2, started_at: authStartedAuthAt, ended_at: new Date().toISOString(), status: "SKIPPED", @@ -153,7 +164,7 @@ export default createPlugin( payload: { namespace: "onboarding", origin: origin_trigger, - position: 2, + step_order: 2, auth_token: authToken, started_at: authStartedAuthAt, ended_at: new Date().toISOString(), @@ -174,7 +185,7 @@ export default createPlugin( payload: { namespace: "onboarding", origin: origin_trigger, - position: 2, + step_order: 2, auth_token: authToken, started_at: authStartedAuthAt, ended_at: new Date().toISOString(), @@ -193,6 +204,7 @@ export default createPlugin( // then there will be no license info to be reported by `localstack license info`. // Also, an expired license could be cached. // Activating the license pre-emptively to know its state during the setup process. + const licenseCheckStartedAt = new Date().toISOString(); const licenseIsValid = await minDelay( activateLicense(outputChannel).then(() => checkIsLicenseValid(outputChannel), @@ -209,15 +221,28 @@ export default createPlugin( await activateLicenseUntilValid( outputChannel, cancellationToken, + telemetry, + origin_trigger, + licenseCheckStartedAt, ); } if (cancellationToken.isCancellationRequested) { + telemetry.track({ + name: "license_setup_ended", + payload: { + namespace: "onboarding", + step_order: 3, + origin: origin_trigger, + auth_token: await readAuthToken(), + started_at: licenseCheckStartedAt, + ended_at: new Date().toISOString(), + status: "COMPLETED", + }, + }); return; } - //TODO add telemetry - ///////////////////////////////////////////////////////////////////// progress.report({ message: "Configuring AWS profile...", @@ -285,8 +310,38 @@ export default createPlugin( name: "setup_ended", payload: { namespace: "onboarding", - steps: [1, 2, 3], + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "COMPLETED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "COMPLETED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "COMPLETED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "COMPLETED", + }, + ], status: "COMPLETED", + auth_token: await readAuthToken(), }, }); }, diff --git a/src/utils/authenticate.ts b/src/utils/authenticate.ts index b849844..8f0bcd6 100644 --- a/src/utils/authenticate.ts +++ b/src/utils/authenticate.ts @@ -143,7 +143,7 @@ export async function checkIsAuthenticated() { return false; } return true; - } catch (error) { + } catch { return false; } } @@ -155,3 +155,21 @@ function isAuthTokenPresent(authObject: unknown) { AUTH_TOKEN_KEY in authObject ); } + +// Reads the auth token from the auth.json file for logging in the user +export async function readAuthToken(): Promise { + try { + const authJson = await fs.readFile(LOCALSTACK_AUTH_FILENAME, "utf-8"); + const authObject = JSON.parse(authJson) as unknown; + if (!isAuthTokenPresent(authObject)) { + return ""; + } + const authToken = authObject[AUTH_TOKEN_KEY]; + if (typeof authToken !== "string") { + return ""; + } + return authToken; + } catch { + return ""; + } +} diff --git a/src/utils/configure-aws.ts b/src/utils/configure-aws.ts index 44edab6..5bf81d8 100644 --- a/src/utils/configure-aws.ts +++ b/src/utils/configure-aws.ts @@ -6,6 +6,7 @@ import * as path from "node:path"; import { window } from "vscode"; import type { LogOutputChannel } from "vscode"; +import { readAuthToken } from "./authenticate.ts"; import { parseIni, serializeIni, updateIniSection } from "./ini-parser.ts"; import type { IniFile, IniSection } from "./ini-parser.ts"; import type { Telemetry } from "./telemetry.ts"; @@ -318,6 +319,8 @@ export async function configureAwsProfiles(options: { const credentialsNeedsOverride = checkIfCredentialsNeedsOverride(credentialsSection); + const authToken = await readAuthToken(); + // means sections exist, but we need to check what's inside if (credentialsSection && configSection) { if (!configNeedsOverride && !credentialsNeedsOverride) { @@ -332,10 +335,11 @@ export async function configureAwsProfiles(options: { payload: { namespace: "onboarding", origin: trigger, - position: 3, + step_order: 4, started_at: startedAt, ended_at: new Date().toISOString(), status: "COMPLETED", + auth_token: authToken, }, }); return; @@ -365,10 +369,11 @@ export async function configureAwsProfiles(options: { payload: { namespace: "onboarding", origin: trigger, - position: 3, + step_order: 4, started_at: startedAt, ended_at: new Date().toISOString(), status: "SKIPPED", + auth_token: authToken, }, }); return; @@ -399,10 +404,11 @@ export async function configureAwsProfiles(options: { payload: { namespace: "onboarding", origin: trigger, - position: 3, + step_order: 4, started_at: startedAt, ended_at: new Date().toISOString(), status: "COMPLETED", + auth_token: authToken, }, }); } else if (configNeedsOverride) { @@ -422,10 +428,11 @@ export async function configureAwsProfiles(options: { payload: { namespace: "onboarding", origin: trigger, - position: 3, + step_order: 4, started_at: startedAt, ended_at: new Date().toISOString(), status: "COMPLETED", + auth_token: authToken, }, }); } else if (credentialsNeedsOverride) { @@ -444,10 +451,11 @@ export async function configureAwsProfiles(options: { payload: { namespace: "onboarding", origin: trigger, - position: 3, + step_order: 4, started_at: startedAt, ended_at: new Date().toISOString(), status: "COMPLETED", + auth_token: authToken, }, }); } diff --git a/src/utils/install.ts b/src/utils/install.ts index 21a6220..9a332b5 100644 --- a/src/utils/install.ts +++ b/src/utils/install.ts @@ -64,7 +64,7 @@ export async function runInstallProcess( payload: { namespace: "onboarding", origin: origin_trigger, - position: 1, + step_order: 1, started_at: startedAt, ended_at: new Date().toISOString(), status: "SKIPPED", @@ -148,7 +148,7 @@ export async function runInstallProcess( payload: { namespace: "onboarding", origin: origin_trigger, - position: 1, + step_order: 1, started_at: startedAt, ended_at: new Date().toISOString(), status: "FAILED", @@ -177,7 +177,7 @@ export async function runInstallProcess( payload: { namespace: "onboarding", origin: origin_trigger, - position: 1, + step_order: 1, started_at: startedAt, ended_at: new Date().toISOString(), status: "FAILED", @@ -194,7 +194,7 @@ export async function runInstallProcess( payload: { namespace: "onboarding", origin: origin_trigger, - position: 1, + step_order: 1, started_at: startedAt, ended_at: new Date().toISOString(), status: "COMPLETED", diff --git a/src/utils/license.ts b/src/utils/license.ts index e41350f..95baf28 100644 --- a/src/utils/license.ts +++ b/src/utils/license.ts @@ -1,6 +1,8 @@ import type { CancellationToken, LogOutputChannel } from "vscode"; +import { readAuthToken } from "./authenticate.ts"; import { execLocalStack } from "./cli.ts"; +import type { Telemetry } from "./telemetry.ts"; const LICENSE_VALIDITY_MARKER = "license validity: valid"; @@ -30,6 +32,9 @@ export async function activateLicense(outputChannel: LogOutputChannel) { export async function activateLicenseUntilValid( outputChannel: LogOutputChannel, cancellationToken: CancellationToken, + telemetry: Telemetry, + origin: "manual_trigger" | "extension_startup", + startedAt: string, ): Promise { while (true) { if (cancellationToken.isCancellationRequested) { @@ -37,6 +42,18 @@ export async function activateLicenseUntilValid( } const licenseIsValid = await checkIsLicenseValid(outputChannel); if (licenseIsValid) { + telemetry.track({ + name: "license_setup_ended", + payload: { + namespace: "onboarding", + step_order: 3, + origin: origin, + auth_token: await readAuthToken(), + started_at: startedAt, + ended_at: new Date().toISOString(), + status: "COMPLETED", + }, + }); break; } await activateLicense(outputChannel); diff --git a/src/utils/manage.ts b/src/utils/manage.ts index 2a9931e..6f12aa9 100644 --- a/src/utils/manage.ts +++ b/src/utils/manage.ts @@ -1,7 +1,8 @@ -import { v7 as uuidv7 } from "uuid"; +import { v7 as uuidv7, v4 as uuidv4 } from "uuid"; import type { ExtensionContext, LogOutputChannel, MessageItem } from "vscode"; import { commands, env, Uri, window } from "vscode"; +import { readAuthToken } from "./authenticate.ts"; import { spawnLocalStack } from "./cli.ts"; import { exec } from "./exec.ts"; import { checkIsLicenseValid } from "./license.ts"; @@ -22,18 +23,21 @@ export async function fetchHealth(): Promise { return false; } } - async function fetchLocalStackSessionId(): Promise { - try { - // TODO info endpoint is not available immediately - // potentially improve this later for tracking "vscode:emulator:started" - const infoResponse = await fetch("http://127.0.0.1:4566/_localstack/info"); - if (infoResponse.ok) { - const info = (await infoResponse.json()) as { session_id?: string }; - return info.session_id ?? ""; + // retry a few times to allow LocalStack to start up and info become available + for (let attempt = 0; attempt < 10; attempt++) { + try { + const response = await fetch("http://127.0.0.1:4566/_localstack/info"); + if (response.ok) { + const json = await response.json(); + if (typeof json === "object" && json !== null && "session_id" in json) { + return typeof json.session_id === "string" ? json.session_id : ""; + } + } + } catch { + // ignore error and retry } - } catch { - // unable to fetch session id + await new Promise((resolve) => setTimeout(resolve, 1000)); } return ""; } @@ -91,6 +95,7 @@ export async function startLocalStack( command: "localstack.viewLogs", }); + const authToken = await readAuthToken(); try { await spawnLocalStack( [ @@ -129,6 +134,7 @@ export async function startLocalStack( namespace: "emulator", status: "COMPLETED", emulator_session_id: emulatorSessionId, + auth_token: authToken, }, }); } catch (error) { @@ -152,6 +158,7 @@ export async function startLocalStack( namespace: "emulator", status: "FAILED", errors: [String(error)], + auth_token: authToken, }, }); } @@ -163,6 +170,7 @@ export async function stopLocalStack( ) { void showInformationMessage("Stopping LocalStack."); + const authToken = await readAuthToken(); try { // get session id before killing container const emulatorSessionId = await fetchLocalStackSessionId(); @@ -177,6 +185,7 @@ export async function stopLocalStack( namespace: "emulator", status: "COMPLETED", emulator_session_id: emulatorSessionId, + auth_token: authToken, }, }); } catch (error) { @@ -191,6 +200,7 @@ export async function stopLocalStack( namespace: "emulator", status: "FAILED", errors: [String(error)], + auth_token: authToken, }, }); } @@ -256,3 +266,15 @@ export async function getOrCreateExtensionSessionId( } return sessionId; } + +// Checks for machine id in workspaceState, creates if missing (to avoid calling machineId multiple times) +export async function getOrCreateMachineId( + context: ExtensionContext, +): Promise { + let machineIdValue = context.workspaceState.get("machine_id"); + if (!machineIdValue) { + machineIdValue = uuidv4(); + await context.workspaceState.update("machine_id", machineIdValue); + } + return machineIdValue; +} diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index 2fd4fa4..d368270 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -3,7 +3,7 @@ import os from "node:os"; import type { LogOutputChannel } from "vscode"; import { extensions, version as vscodeVersion, workspace } from "vscode"; -const SCHEMA_VERSION = 1; +const SCHEMA_VERSION = 2; const ANALYTICS_API_URL = process.env.ANALYTICS_API_URL ?? @@ -17,12 +17,6 @@ type Events = payload: { namespace: "onboarding"; origin: "manual_trigger" | "extension_startup"; - expected_steps: { - name: string; - is_first_step: boolean; - is_last_step: boolean; - position: number; - }[]; }; } | { @@ -30,7 +24,7 @@ type Events = payload: { namespace: "onboarding"; origin: "manual_trigger" | "extension_startup"; - position: 1; + step_order: 1; started_at: string; ended_at: string; status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; @@ -43,7 +37,20 @@ type Events = payload: { namespace: "onboarding"; origin: "manual_trigger" | "extension_startup"; - position: 2; + step_order: 2; + auth_token?: string; + started_at: string; + ended_at: string; + status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; + errors?: string[]; + }; + } + | { + name: "license_setup_ended"; + payload: { + namespace: "onboarding"; + origin: "manual_trigger" | "extension_startup"; + step_order: 3; auth_token?: string; started_at: string; ended_at: string; @@ -56,19 +63,50 @@ type Events = payload: { namespace: "onboarding"; origin: "manual_trigger" | "extension_startup"; - position: 3; + step_order: 4; started_at: string; ended_at: string; status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; errors?: string[]; + auth_token: string; }; } | { name: "setup_ended"; payload: { namespace: "onboarding"; - steps: number[]; + steps: [ + { + name: "emulator_installed"; + is_first_step: true; + is_last_step: false; + step_order: 1; + status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; + }, + { + name: "auth_token_configured"; + is_first_step: false; + is_last_step: false; + step_order: 2; + status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; + }, + { + name: "license_setup_ended"; + is_first_step: false; + is_last_step: false; + step_order: 3; + status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; + }, + { + name: "aws_profile_configured"; + is_first_step: false; + is_last_step: true; + step_order: 4; + status: "COMPLETED" | "FAILED" | "SKIPPED" | "CANCELLED"; + }, + ]; status: "COMPLETED" | "FAILED" | "CANCELLED"; + auth_token: string; }; } | { @@ -78,6 +116,7 @@ type Events = status: "COMPLETED" | "FAILED"; emulator_session_id?: string; errors?: string[]; + auth_token: string; }; } | { @@ -87,6 +126,7 @@ type Events = status: "COMPLETED" | "FAILED"; emulator_session_id?: string; errors?: string[]; + auth_token: string; }; }; @@ -127,6 +167,7 @@ async function postEvent( export function createTelemetry( outputChannel: LogOutputChannel, sessionId: string, + machineId: string, ): Telemetry { return { track(event) { @@ -152,6 +193,7 @@ export function createTelemetry( schema_version: SCHEMA_VERSION, ide_version: vscodeVersion, extension_version: extensionVersion, + machine_id: machineId, operating_system: os.platform(), // if anything inside payload include it ...event.payload, From ce635998c175b153e8dfa6432fdec7b67a4b789f Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Fri, 5 Sep 2025 19:09:58 +0200 Subject: [PATCH 02/10] Fix status for cancelled license_setuo --- src/plugins/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index a298705..1f79c56 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -237,7 +237,7 @@ export default createPlugin( auth_token: await readAuthToken(), started_at: licenseCheckStartedAt, ended_at: new Date().toISOString(), - status: "COMPLETED", + status: "CANCELLED", }, }); return; From c386a7dd20d3a59c2679f6e646955086235556e6 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Sun, 7 Sep 2025 21:08:34 +0200 Subject: [PATCH 03/10] Reuse readAuthToken in checkIsAuthenticated --- src/utils/authenticate.ts | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/utils/authenticate.ts b/src/utils/authenticate.ts index 8f0bcd6..2838e92 100644 --- a/src/utils/authenticate.ts +++ b/src/utils/authenticate.ts @@ -124,30 +124,6 @@ export async function saveAuthToken( } } -/** - * Checks if the user is authenticated by validating the stored auth token. - * - * License is validated separately - * - * @returns boolean indicating if the authentication is valid - */ -export async function checkIsAuthenticated() { - try { - const authJson = await fs.readFile(LOCALSTACK_AUTH_FILENAME, "utf-8"); - const authObject = JSON.parse(authJson) as unknown; - if (!isAuthTokenPresent(authObject)) { - return false; - } - const authToken = authObject[AUTH_TOKEN_KEY]; - if (typeof authToken !== "string") { - return false; - } - return true; - } catch { - return false; - } -} - function isAuthTokenPresent(authObject: unknown) { return ( typeof authObject === "object" && @@ -173,3 +149,14 @@ export async function readAuthToken(): Promise { return ""; } } + +/** + * Checks if the user is authenticated by validating the stored auth token. + * + * License is validated separately + * + * @returns boolean indicating if the authentication is valid + */ +export async function checkIsAuthenticated() { + return (await readAuthToken()) !== ""; +} From 6f812e79a8720c648e451c1060487d0671f4f118 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Sun, 7 Sep 2025 21:11:28 +0200 Subject: [PATCH 04/10] Centralize license_setup_ended in setup.ts --- src/plugins/setup.ts | 16 +++++++++++++--- src/utils/license.ts | 15 --------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index 1f79c56..10e5565 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -221,9 +221,6 @@ export default createPlugin( await activateLicenseUntilValid( outputChannel, cancellationToken, - telemetry, - origin_trigger, - licenseCheckStartedAt, ); } @@ -243,6 +240,19 @@ export default createPlugin( return; } + telemetry.track({ + name: "license_setup_ended", + payload: { + namespace: "onboarding", + step_order: 3, + origin: origin_trigger, + auth_token: await readAuthToken(), + started_at: licenseCheckStartedAt, + ended_at: new Date().toISOString(), + status: "COMPLETED", + }, + }); + ///////////////////////////////////////////////////////////////////// progress.report({ message: "Configuring AWS profile...", diff --git a/src/utils/license.ts b/src/utils/license.ts index 95baf28..8649f49 100644 --- a/src/utils/license.ts +++ b/src/utils/license.ts @@ -32,9 +32,6 @@ export async function activateLicense(outputChannel: LogOutputChannel) { export async function activateLicenseUntilValid( outputChannel: LogOutputChannel, cancellationToken: CancellationToken, - telemetry: Telemetry, - origin: "manual_trigger" | "extension_startup", - startedAt: string, ): Promise { while (true) { if (cancellationToken.isCancellationRequested) { @@ -42,18 +39,6 @@ export async function activateLicenseUntilValid( } const licenseIsValid = await checkIsLicenseValid(outputChannel); if (licenseIsValid) { - telemetry.track({ - name: "license_setup_ended", - payload: { - namespace: "onboarding", - step_order: 3, - origin: origin, - auth_token: await readAuthToken(), - started_at: startedAt, - ended_at: new Date().toISOString(), - status: "COMPLETED", - }, - }); break; } await activateLicense(outputChannel); From e12e334c585723c612002b046f97929484ae9eb6 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Mon, 8 Sep 2025 13:11:53 +0200 Subject: [PATCH 05/10] Remove machine_id: duplicated --- src/extension.ts | 8 ++------ src/utils/manage.ts | 12 ------------ src/utils/telemetry.ts | 2 -- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index ed1f267..1eeac76 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,10 +10,7 @@ import statusBar from "./plugins/status-bar.ts"; import { PluginManager } from "./plugins.ts"; import { createContainerStatusTracker } from "./utils/container-status.ts"; import { createLocalStackStatusTracker } from "./utils/localstack-status.ts"; -import { - getOrCreateExtensionSessionId, - getOrCreateMachineId, -} from "./utils/manage.ts"; +import { getOrCreateExtensionSessionId } from "./utils/manage.ts"; import { createSetupStatusTracker } from "./utils/setup-status.ts"; import { createTelemetry } from "./utils/telemetry.ts"; import { createTimeTracker } from "./utils/time-tracker.ts"; @@ -81,8 +78,7 @@ export async function activate(context: ExtensionContext) { const startTelemetry = Date.now(); outputChannel.trace(`[telemetry]: Starting...`); const sessionId = await getOrCreateExtensionSessionId(context); - const machineId = await getOrCreateMachineId(context); - const telemetry = createTelemetry(outputChannel, sessionId, machineId); + const telemetry = createTelemetry(outputChannel, sessionId); const endTelemetry = Date.now(); outputChannel.trace( `[telemetry]: Completed in ${ms(endTelemetry - startTelemetry, { diff --git a/src/utils/manage.ts b/src/utils/manage.ts index 6f12aa9..1309f98 100644 --- a/src/utils/manage.ts +++ b/src/utils/manage.ts @@ -266,15 +266,3 @@ export async function getOrCreateExtensionSessionId( } return sessionId; } - -// Checks for machine id in workspaceState, creates if missing (to avoid calling machineId multiple times) -export async function getOrCreateMachineId( - context: ExtensionContext, -): Promise { - let machineIdValue = context.workspaceState.get("machine_id"); - if (!machineIdValue) { - machineIdValue = uuidv4(); - await context.workspaceState.update("machine_id", machineIdValue); - } - return machineIdValue; -} diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index d368270..23dc74b 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -167,7 +167,6 @@ async function postEvent( export function createTelemetry( outputChannel: LogOutputChannel, sessionId: string, - machineId: string, ): Telemetry { return { track(event) { @@ -193,7 +192,6 @@ export function createTelemetry( schema_version: SCHEMA_VERSION, ide_version: vscodeVersion, extension_version: extensionVersion, - machine_id: machineId, operating_system: os.platform(), // if anything inside payload include it ...event.payload, From 40d5111e9f15639a999b526c668671791fa878ca Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Mon, 8 Sep 2025 15:58:11 +0200 Subject: [PATCH 06/10] Consistency: track setup_ended for cancelled events --- src/plugins/setup.ts | 111 +++++++-------------- src/utils/telemetry.ts | 212 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 243 insertions(+), 80 deletions(-) diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index 10e5565..58de537 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -16,6 +16,13 @@ import { } from "../utils/license.ts"; import { minDelay } from "../utils/promises.ts"; import { updateDockerImage } from "../utils/setup.ts"; +import { + get_setup_ended_on_image_prefetch_cancelled, + get_setup_ended_on_authentication_cancelled, + get_setup_ended_on_cli_setup_cancelled, + get_setup_ended_on_license_setup_cancelled, + get_setup_ended_completed, +} from "../utils/telemetry.ts"; export default createPlugin( "setup", @@ -71,6 +78,7 @@ export default createPlugin( status: "CANCELLED", }, }); + telemetry.track(get_setup_ended_on_cli_setup_cancelled()); return; } } @@ -91,43 +99,17 @@ export default createPlugin( const authenticated = await minDelay(checkIsAuthenticated()); if (cancellationToken.isCancellationRequested) { telemetry.track({ - name: "setup_ended", + name: "auth_token_configured", payload: { namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "COMPLETED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "CANCELLED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "SKIPPED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "SKIPPED", - }, - ], + origin: origin_trigger, + step_order: 2, + started_at: authStartedAuthAt, + ended_at: new Date().toISOString(), status: "CANCELLED", - auth_token: await readAuthToken(), }, }); + telemetry.track(get_setup_ended_on_authentication_cancelled()); return; } if (authenticated) { @@ -145,6 +127,7 @@ export default createPlugin( status: "SKIPPED", }, }); + await minDelay(Promise.resolve()); } else { ///////////////////////////////////////////////////////////////////// @@ -171,6 +154,9 @@ export default createPlugin( status: "CANCELLED", }, }); + telemetry.track( + get_setup_ended_on_authentication_cancelled(), + ); return; } @@ -192,7 +178,9 @@ export default createPlugin( status: "CANCELLED", }, }); - + telemetry.track( + get_setup_ended_on_authentication_cancelled(authToken), + ); return; } } @@ -237,6 +225,11 @@ export default createPlugin( status: "CANCELLED", }, }); + telemetry.track( + get_setup_ended_on_license_setup_cancelled( + await readAuthToken(), + ), + ); return; } @@ -280,14 +273,11 @@ export default createPlugin( } if (cancellationToken.isCancellationRequested) { - telemetry.track({ - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [1, 2, 3], - status: "CANCELLED", - }, - }); + telemetry.track( + get_setup_ended_on_image_prefetch_cancelled( + await readAuthToken(), + ), + ); return; } @@ -316,44 +306,7 @@ export default createPlugin( }); } - telemetry.track({ - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "COMPLETED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "COMPLETED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "COMPLETED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "COMPLETED", - }, - ], - status: "COMPLETED", - auth_token: await readAuthToken(), - }, - }); + telemetry.track(get_setup_ended_completed(await readAuthToken())); }, ); }, diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index 23dc74b..f1eb8f1 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -106,7 +106,7 @@ type Events = }, ]; status: "COMPLETED" | "FAILED" | "CANCELLED"; - auth_token: string; + auth_token?: string; }; } | { @@ -213,3 +213,213 @@ export function createTelemetry( }, }; } + +export function get_setup_ended_on_cli_setup_cancelled(): Events { + return { + name: "setup_ended", + payload: { + namespace: "onboarding", + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "CANCELLED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "SKIPPED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "SKIPPED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "SKIPPED", + }, + ], + status: "CANCELLED", + }, + }; +} + +export function get_setup_ended_on_authentication_cancelled( + authToken: string = "", +): Events { + return { + name: "setup_ended", + payload: { + namespace: "onboarding", + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "COMPLETED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "CANCELLED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "SKIPPED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "SKIPPED", + }, + ], + status: "CANCELLED", + auth_token: authToken, + }, + }; +} + +export function get_setup_ended_on_license_setup_cancelled( + auth_token: string, +): Events { + return { + name: "setup_ended", + payload: { + namespace: "onboarding", + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "COMPLETED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "COMPLETED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "CANCELLED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "SKIPPED", + }, + ], + status: "CANCELLED", + auth_token: auth_token, + }, + }; +} + +export function get_setup_ended_on_image_prefetch_cancelled( + auth_token: string, +): Events { + return { + name: "setup_ended", + payload: { + namespace: "onboarding", + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "CANCELLED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "COMPLETED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "COMPLETED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "COMPLETED", + }, + ], + status: "CANCELLED", + auth_token: auth_token, + }, + }; +} + +export function get_setup_ended_completed(auth_token: string): Events { + return { + name: "setup_ended", + payload: { + namespace: "onboarding", + steps: [ + { + name: "emulator_installed", + is_first_step: true, + is_last_step: false, + step_order: 1, + status: "COMPLETED", + }, + { + name: "auth_token_configured", + is_first_step: false, + is_last_step: false, + step_order: 2, + status: "COMPLETED", + }, + { + name: "license_setup_ended", + is_first_step: false, + is_last_step: false, + step_order: 3, + status: "COMPLETED", + }, + { + name: "aws_profile_configured", + is_first_step: false, + is_last_step: true, + step_order: 4, + status: "COMPLETED", + }, + ], + status: "COMPLETED", + auth_token: auth_token, + }, + }; +} From a46318f8c54f40561e2c6404a1f3cbc1a3298885 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Mon, 8 Sep 2025 16:15:44 +0200 Subject: [PATCH 07/10] Remove unused imports --- src/utils/license.ts | 2 -- src/utils/manage.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/license.ts b/src/utils/license.ts index 8649f49..e41350f 100644 --- a/src/utils/license.ts +++ b/src/utils/license.ts @@ -1,8 +1,6 @@ import type { CancellationToken, LogOutputChannel } from "vscode"; -import { readAuthToken } from "./authenticate.ts"; import { execLocalStack } from "./cli.ts"; -import type { Telemetry } from "./telemetry.ts"; const LICENSE_VALIDITY_MARKER = "license validity: valid"; diff --git a/src/utils/manage.ts b/src/utils/manage.ts index 1309f98..746d369 100644 --- a/src/utils/manage.ts +++ b/src/utils/manage.ts @@ -1,4 +1,4 @@ -import { v7 as uuidv7, v4 as uuidv4 } from "uuid"; +import { v7 as uuidv7 } from "uuid"; import type { ExtensionContext, LogOutputChannel, MessageItem } from "vscode"; import { commands, env, Uri, window } from "vscode"; From 1d354ace5eab645f87abeb9acc3ebc981a39b5fc Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Tue, 9 Sep 2025 10:38:11 +0200 Subject: [PATCH 08/10] Fix: image_prefetch cancelled --- src/utils/telemetry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index f1eb8f1..640f071 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -353,7 +353,7 @@ export function get_setup_ended_on_image_prefetch_cancelled( is_first_step: true, is_last_step: false, step_order: 1, - status: "CANCELLED", + status: "COMPLETED", }, { name: "auth_token_configured", From 42a886128046bb9b558d143950680d490cc8e846 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Tue, 9 Sep 2025 12:33:34 +0200 Subject: [PATCH 09/10] Handle skipped steps --- src/plugins/setup.ts | 19 +++++++++++++++++-- src/utils/install.ts | 4 ++-- src/utils/telemetry.ts | 10 +++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index 58de537..f7163f7 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -57,15 +57,19 @@ export default createPlugin( }, async (progress, cancellationToken) => { ///////////////////////////////////////////////////////////////////// + let cliInstallSkipped: boolean = false; + let authenticationSkipped: boolean = false; { const installationStartedAt = new Date().toISOString(); - const { cancelled } = await runInstallProcess( + + const { cancelled, skipped } = await runInstallProcess( progress, cancellationToken, outputChannel, telemetry, origin_trigger, ); + cliInstallSkipped = skipped === true; if (cancelled || cancellationToken.isCancellationRequested) { telemetry.track({ name: "emulator_installed", @@ -116,6 +120,7 @@ export default createPlugin( progress.report({ message: "Skipping authentication...", }); + authenticationSkipped = true; telemetry.track({ name: "auth_token_configured", payload: { @@ -306,7 +311,17 @@ export default createPlugin( }); } - telemetry.track(get_setup_ended_completed(await readAuthToken())); + const cliStatus = cliInstallSkipped ? "SKIPPED" : "COMPLETED"; + const authenticationStatus = authenticationSkipped + ? "SKIPPED" + : "COMPLETED"; + telemetry.track( + get_setup_ended_completed( + cliStatus, + authenticationStatus, + await readAuthToken(), + ), + ); }, ); }, diff --git a/src/utils/install.ts b/src/utils/install.ts index 9a332b5..7acfaaf 100644 --- a/src/utils/install.ts +++ b/src/utils/install.ts @@ -40,7 +40,7 @@ export async function runInstallProcess( outputChannel: LogOutputChannel, telemetry: Telemetry, origin?: "extension_startup" | "manual_trigger", -): Promise<{ cancelled: boolean }> { +): Promise<{ cancelled: boolean; skipped?: boolean }> { ///////////////////////////////////////////////////////////////////// const origin_trigger = origin ? origin : "manual_trigger"; progress.report({ @@ -71,7 +71,7 @@ export async function runInstallProcess( }, }); await minDelay(); - return { cancelled: false }; + return { cancelled: false, skipped: true }; } ///////////////////////////////////////////////////////////////////// diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index 640f071..e895841 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -383,7 +383,11 @@ export function get_setup_ended_on_image_prefetch_cancelled( }; } -export function get_setup_ended_completed(auth_token: string): Events { +export function get_setup_ended_completed( + cli_status: "COMPLETED" | "SKIPPED", + authentication_status: "COMPLETED" | "SKIPPED", + auth_token: string, +): Events { return { name: "setup_ended", payload: { @@ -394,14 +398,14 @@ export function get_setup_ended_completed(auth_token: string): Events { is_first_step: true, is_last_step: false, step_order: 1, - status: "COMPLETED", + status: cli_status, }, { name: "auth_token_configured", is_first_step: false, is_last_step: false, step_order: 2, - status: "COMPLETED", + status: authentication_status, }, { name: "license_setup_ended", From 1d20bd60d59b2ebcb8c005d496e00e12abb21809 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Tue, 9 Sep 2025 13:32:20 +0200 Subject: [PATCH 10/10] Simplify tracking of setup_ended events --- src/plugins/setup.ts | 79 ++++++++++++----- src/utils/telemetry.ts | 188 +++-------------------------------------- 2 files changed, 67 insertions(+), 200 deletions(-) diff --git a/src/plugins/setup.ts b/src/plugins/setup.ts index f7163f7..631954b 100644 --- a/src/plugins/setup.ts +++ b/src/plugins/setup.ts @@ -16,13 +16,7 @@ import { } from "../utils/license.ts"; import { minDelay } from "../utils/promises.ts"; import { updateDockerImage } from "../utils/setup.ts"; -import { - get_setup_ended_on_image_prefetch_cancelled, - get_setup_ended_on_authentication_cancelled, - get_setup_ended_on_cli_setup_cancelled, - get_setup_ended_on_license_setup_cancelled, - get_setup_ended_completed, -} from "../utils/telemetry.ts"; +import { get_setup_ended } from "../utils/telemetry.ts"; export default createPlugin( "setup", @@ -57,11 +51,10 @@ export default createPlugin( }, async (progress, cancellationToken) => { ///////////////////////////////////////////////////////////////////// - let cliInstallSkipped: boolean = false; - let authenticationSkipped: boolean = false; + let cliStatus: "COMPLETED" | "SKIPPED" = "COMPLETED"; + let authenticationStatus: "COMPLETED" | "SKIPPED" = "COMPLETED"; { const installationStartedAt = new Date().toISOString(); - const { cancelled, skipped } = await runInstallProcess( progress, cancellationToken, @@ -69,7 +62,7 @@ export default createPlugin( telemetry, origin_trigger, ); - cliInstallSkipped = skipped === true; + cliStatus = skipped === true ? "SKIPPED" : "COMPLETED"; if (cancelled || cancellationToken.isCancellationRequested) { telemetry.track({ name: "emulator_installed", @@ -82,7 +75,15 @@ export default createPlugin( status: "CANCELLED", }, }); - telemetry.track(get_setup_ended_on_cli_setup_cancelled()); + telemetry.track( + get_setup_ended( + cliStatus, + "SKIPPED", + "SKIPPED", + "SKIPPED", + "CANCELLED", + ), + ); return; } } @@ -113,14 +114,23 @@ export default createPlugin( status: "CANCELLED", }, }); - telemetry.track(get_setup_ended_on_authentication_cancelled()); + telemetry.track( + get_setup_ended( + cliStatus, + "CANCELLED", + "SKIPPED", + "SKIPPED", + "CANCELLED", + await readAuthToken(), + ), + ); return; } if (authenticated) { progress.report({ message: "Skipping authentication...", }); - authenticationSkipped = true; + authenticationStatus = "SKIPPED"; telemetry.track({ name: "auth_token_configured", payload: { @@ -160,7 +170,14 @@ export default createPlugin( }, }); telemetry.track( - get_setup_ended_on_authentication_cancelled(), + get_setup_ended( + cliStatus, + "CANCELLED", + "SKIPPED", + "SKIPPED", + "CANCELLED", + await readAuthToken(), + ), ); return; } @@ -184,7 +201,14 @@ export default createPlugin( }, }); telemetry.track( - get_setup_ended_on_authentication_cancelled(authToken), + get_setup_ended( + cliStatus, + "CANCELLED", + "SKIPPED", + "SKIPPED", + "CANCELLED", + authToken, + ), ); return; } @@ -231,7 +255,12 @@ export default createPlugin( }, }); telemetry.track( - get_setup_ended_on_license_setup_cancelled( + get_setup_ended( + cliStatus, + authenticationStatus, + "CANCELLED", + "SKIPPED", + "CANCELLED", await readAuthToken(), ), ); @@ -279,7 +308,12 @@ export default createPlugin( if (cancellationToken.isCancellationRequested) { telemetry.track( - get_setup_ended_on_image_prefetch_cancelled( + get_setup_ended( + cliStatus, + authenticationStatus, + "COMPLETED", + "COMPLETED", + "CANCELLED", await readAuthToken(), ), ); @@ -311,14 +345,13 @@ export default createPlugin( }); } - const cliStatus = cliInstallSkipped ? "SKIPPED" : "COMPLETED"; - const authenticationStatus = authenticationSkipped - ? "SKIPPED" - : "COMPLETED"; telemetry.track( - get_setup_ended_completed( + get_setup_ended( cliStatus, authenticationStatus, + "COMPLETED", + "COMPLETED", + "COMPLETED", await readAuthToken(), ), ); diff --git a/src/utils/telemetry.ts b/src/utils/telemetry.ts index e895841..01a8034 100644 --- a/src/utils/telemetry.ts +++ b/src/utils/telemetry.ts @@ -214,179 +214,13 @@ export function createTelemetry( }; } -export function get_setup_ended_on_cli_setup_cancelled(): Events { - return { - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "CANCELLED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "SKIPPED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "SKIPPED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "SKIPPED", - }, - ], - status: "CANCELLED", - }, - }; -} - -export function get_setup_ended_on_authentication_cancelled( - authToken: string = "", -): Events { - return { - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "COMPLETED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "CANCELLED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "SKIPPED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "SKIPPED", - }, - ], - status: "CANCELLED", - auth_token: authToken, - }, - }; -} - -export function get_setup_ended_on_license_setup_cancelled( - auth_token: string, -): Events { - return { - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "COMPLETED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "COMPLETED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "CANCELLED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "SKIPPED", - }, - ], - status: "CANCELLED", - auth_token: auth_token, - }, - }; -} - -export function get_setup_ended_on_image_prefetch_cancelled( - auth_token: string, -): Events { - return { - name: "setup_ended", - payload: { - namespace: "onboarding", - steps: [ - { - name: "emulator_installed", - is_first_step: true, - is_last_step: false, - step_order: 1, - status: "COMPLETED", - }, - { - name: "auth_token_configured", - is_first_step: false, - is_last_step: false, - step_order: 2, - status: "COMPLETED", - }, - { - name: "license_setup_ended", - is_first_step: false, - is_last_step: false, - step_order: 3, - status: "COMPLETED", - }, - { - name: "aws_profile_configured", - is_first_step: false, - is_last_step: true, - step_order: 4, - status: "COMPLETED", - }, - ], - status: "CANCELLED", - auth_token: auth_token, - }, - }; -} - -export function get_setup_ended_completed( - cli_status: "COMPLETED" | "SKIPPED", - authentication_status: "COMPLETED" | "SKIPPED", - auth_token: string, +export function get_setup_ended( + cli_status: "COMPLETED" | "SKIPPED" | "CANCELLED", + authentication_status: "COMPLETED" | "SKIPPED" | "CANCELLED", + license_setup_status: "COMPLETED" | "SKIPPED" | "CANCELLED", + aws_profile_status: "COMPLETED" | "SKIPPED" | "CANCELLED", + overall_status: "CANCELLED" | "COMPLETED", + auth_token: string = "", ): Events { return { name: "setup_ended", @@ -412,18 +246,18 @@ export function get_setup_ended_completed( is_first_step: false, is_last_step: false, step_order: 3, - status: "COMPLETED", + status: license_setup_status, }, { name: "aws_profile_configured", is_first_step: false, is_last_step: true, step_order: 4, - status: "COMPLETED", + status: aws_profile_status, }, ], - status: "COMPLETED", - auth_token: auth_token, + status: overall_status, + auth_token, }, }; }