mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
feat(cli): emit sign-in lifecycle telemetry (#2000)
* feat(cli): emit sign-in lifecycle telemetry The CLI tracks command and render lifecycles but emits nothing for `auth login`, so sign-in outcomes are invisible on the observability dashboards — a completed sign-in, an abandoned browser flow, and a rejected key all look identical (absent). This leaves a blind spot in the same funnel the render events already cover. Add three events mirroring the existing `trackX` pattern: - auth_login_started (method: oauth | api_key) - auth_login_completed (method) - auth_login_failed (method, reason) `reason` is a fixed low-cardinality enum (flow_error / no_credential / rejected / invalid_input). No token, key, identity, email, or free text is ever attached — consistent with the existing anonymous telemetry and the `telemetry disable` opt-out. Wired into both the OAuth and --api-key paths in `auth login`, with unit coverage for the new events. * fix(cli): close sign-in telemetry funnel dropout gaps Follow-up so `started` reconciles to `completed + failed` on the common abandonment paths, which the first cut missed: - Interactive prompt cancel (Ctrl-C) now surfaces as a throw that the single catch in the api-key path records as `aborted`, instead of a bare exit with no event. - A stdin read that times out in non-TTY `--api-key` mode now records `aborted` before the error propagates, rather than exiting silently. - OAuth split: a timed-out browser callback (user closed the tab) is tagged `flow_timeout`, separated from real `flow_error` (IdP/network), since the walk-away timeout is the dominant non-error dropout. Also pre-plumb an optional `distinctId` on the three trackers, mirroring trackRenderComplete/trackRenderError. Unused today; it lets a later identity-level attribution be a one-line callsite change rather than a signature sweep. Coverage added for the new reasons and forwarding.
This commit is contained in:
@@ -14,6 +14,9 @@ const {
|
||||
trackFigmaImport,
|
||||
trackRenderFeedback,
|
||||
trackRenderPreflightRejected,
|
||||
trackAuthLoginStarted,
|
||||
trackAuthLoginCompleted,
|
||||
trackAuthLoginFailed,
|
||||
} = await import("./events.js");
|
||||
|
||||
describe("render telemetry events", () => {
|
||||
@@ -226,3 +229,68 @@ describe("trackFigmaImport", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("auth login telemetry events", () => {
|
||||
beforeEach(() => {
|
||||
trackEvent.mockClear();
|
||||
});
|
||||
|
||||
it("emits auth_login_started tagged with the method", () => {
|
||||
trackAuthLoginStarted("oauth");
|
||||
expect(trackEvent).toHaveBeenCalledWith("auth_login_started", { method: "oauth" }, undefined);
|
||||
});
|
||||
|
||||
it("emits auth_login_completed tagged with the method", () => {
|
||||
trackAuthLoginCompleted("api_key");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_completed",
|
||||
{ method: "api_key" },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("emits auth_login_failed with the method and a low-cardinality reason", () => {
|
||||
trackAuthLoginFailed("oauth", "flow_error");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_failed",
|
||||
{ method: "oauth", reason: "flow_error" },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("distinguishes a timed-out browser flow from a real error", () => {
|
||||
trackAuthLoginFailed("oauth", "flow_timeout");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_failed",
|
||||
{ method: "oauth", reason: "flow_timeout" },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("records an aborted prompt / stdin timeout as its own reason", () => {
|
||||
trackAuthLoginFailed("api_key", "aborted");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_failed",
|
||||
{ method: "api_key", reason: "aborted" },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("carries only method + reason — never a key, token, or free text", () => {
|
||||
trackAuthLoginFailed("api_key", "rejected");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_failed",
|
||||
{ method: "api_key", reason: "rejected" },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards an explicit distinctId to trackEvent for future user-level attribution", () => {
|
||||
trackAuthLoginCompleted("oauth", "heygen-user-123");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_completed",
|
||||
{ method: "oauth" },
|
||||
"heygen-user-123",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user