diff --git a/packages/cli/src/auth/client.test.ts b/packages/cli/src/auth/client.test.ts index a2343a32f..844502d77 100644 --- a/packages/cli/src/auth/client.test.ts +++ b/packages/cli/src/auth/client.test.ts @@ -84,7 +84,6 @@ describe("auth/client", () => { authorization: "Bearer at_123", [HEYGEN_CLI_SOURCE_HEADER]: HEYGEN_CLI_SOURCE, [HEYGEN_CLIENT_SOURCE_HEADER]: HEYGEN_CLIENT_SOURCE, - heygen_route: "canary", }); }); @@ -92,7 +91,6 @@ describe("auth/client", () => { expect(buildAuthHeaders(apiKeyCred())).toEqual({ "x-api-key": "hg_x", [HEYGEN_CLIENT_SOURCE_HEADER]: HEYGEN_CLIENT_SOURCE, - heygen_route: "canary", }); }); diff --git a/packages/cli/src/auth/client.ts b/packages/cli/src/auth/client.ts index 659e64e00..0bb3f92bb 100644 --- a/packages/cli/src/auth/client.ts +++ b/packages/cli/src/auth/client.ts @@ -19,7 +19,6 @@ import { ErrApi, ErrUnauthenticated, isAuthError } from "./errors.js"; import type { ResolvedCredential } from "./resolver.js"; import { scrubCredentials } from "./scrub.js"; import type { OAuthTokens } from "./store.js"; -import { withHeygenCanaryRoute } from "../utils/heygenRoute.js"; const DEFAULT_BASE_URL = "https://api.heygen.com"; export const HEYGEN_CLI_SOURCE_HEADER = "X-HeyGen-Source"; @@ -186,20 +185,17 @@ export class AuthClient { export function buildAuthHeaders(credential: ResolvedCredential): Record { if (credential.type === "oauth") { - return withHeygenCanaryRoute({ + return { authorization: `Bearer ${credential.access_token}`, [HEYGEN_CLI_SOURCE_HEADER]: HEYGEN_CLI_SOURCE, [HEYGEN_CLIENT_SOURCE_HEADER]: HEYGEN_CLIENT_SOURCE, - }); + }; } // API-key traffic keeps the normal billing path; the backend ignores the // cli-source header for it, so we don't send it (avoids a contradictory // "cli-source claim on an API-key request"). The tool-attribution header IS // sent here — an API-key hyperframes call is still hyperframes usage. - return withHeygenCanaryRoute({ - "x-api-key": credential.key, - [HEYGEN_CLIENT_SOURCE_HEADER]: HEYGEN_CLIENT_SOURCE, - }); + return { "x-api-key": credential.key, [HEYGEN_CLIENT_SOURCE_HEADER]: HEYGEN_CLIENT_SOURCE }; } async function safeText(res: Response): Promise { diff --git a/packages/cli/src/auth/oauth.test.ts b/packages/cli/src/auth/oauth.test.ts index 2c2258f6a..fcc9ac515 100644 --- a/packages/cli/src/auth/oauth.test.ts +++ b/packages/cli/src/auth/oauth.test.ts @@ -173,10 +173,8 @@ describe("auth/oauth", () => { it("posts grant_type=refresh_token and persists the response", async () => { process.env["HEYGEN_API_URL"] = "https://api.test.example"; let capturedBody: string | undefined; - let capturedHeaders: HeadersInit | undefined; const fetchImpl = (async (_url: string, init?: RequestInit) => { capturedBody = init?.body as string; - capturedHeaders = init?.headers; return new Response( JSON.stringify({ access_token: "new_at", @@ -194,7 +192,6 @@ describe("auth/oauth", () => { expect(tokens.refresh_token).toBe("new_rt"); expect(capturedBody).toContain("grant_type=refresh_token"); expect(capturedBody).toContain("refresh_token=old_rt"); - expect(capturedHeaders).toMatchObject({ heygen_route: "canary" }); // Should have persisted. const { credentials } = await readStore(); @@ -298,10 +295,8 @@ describe("auth/oauth", () => { it("sends token_type_hint when provided", async () => { let capturedBody = ""; - let capturedHeaders: HeadersInit | undefined; const fetchImpl = (async (_url: string, init?: RequestInit) => { capturedBody = init?.body as string; - capturedHeaders = init?.headers; return new Response("", { status: 200 }); }) as unknown as typeof fetch; await revokeTokens("tok", { @@ -309,7 +304,6 @@ describe("auth/oauth", () => { token_type_hint: "refresh_token", }); expect(capturedBody).toContain("token_type_hint=refresh_token"); - expect(capturedHeaders).toMatchObject({ heygen_route: "canary" }); }); it("returns silently when client_id is unconfigured (no throw)", async () => { @@ -343,21 +337,6 @@ describe("auth/oauth", () => { }); describe("startAuthorizationCodeFlow persistence", () => { - it("routes the authorization-code exchange through canary", async () => { - let capturedHeaders: HeadersInit | undefined; - const fetchImpl = (async (_url: string | URL | Request, init?: RequestInit) => { - capturedHeaders = init?.headers; - return new Response(JSON.stringify({ access_token: "new_at" }), { - status: 200, - headers: { "content-type": "application/json" }, - }); - }) as typeof fetch; - - await startAuthorizationCodeFlow({ fetchImpl }); - - expect(capturedHeaders).toMatchObject({ heygen_route: "canary" }); - }); - it("overwrites the OAuth block on fresh login (no inherited refresh_token)", async () => { // Pre-seed a prior session whose refresh_token must NOT leak into // the new login when the new response omits one. @@ -471,11 +450,7 @@ describe("auth/oauth", () => { }); it("polls pending and slow_down responses without persisting before identity verification", async () => { - const requests: Array<{ - url: string; - body: URLSearchParams; - headers: HeadersInit | undefined; - }> = []; + const requests: Array<{ url: string; body: URLSearchParams }> = []; const responses = [ new Response( JSON.stringify({ @@ -510,7 +485,6 @@ describe("auth/oauth", () => { requests.push({ url: String(url), body: new URLSearchParams(String(init?.body ?? "")), - headers: init?.headers, }); }); const sleeps: number[] = []; @@ -540,12 +514,6 @@ describe("auth/oauth", () => { expect(requests[1]?.body.get("grant_type")).toBe( "urn:ietf:params:oauth:grant-type:device_code", ); - expect(requests.map(({ headers }) => headers)).toEqual([ - expect.objectContaining({ heygen_route: "canary" }), - expect.objectContaining({ heygen_route: "canary" }), - expect.objectContaining({ heygen_route: "canary" }), - expect.objectContaining({ heygen_route: "canary" }), - ]); expect((await readStore()).source).toBe("absent"); await persistFreshOAuth(tokens); diff --git a/packages/cli/src/auth/oauth.ts b/packages/cli/src/auth/oauth.ts index 1c8a2d99a..a1c0a2047 100644 --- a/packages/cli/src/auth/oauth.ts +++ b/packages/cli/src/auth/oauth.ts @@ -54,7 +54,6 @@ import { type StoredUserInfo, } from "./store.js"; import { c } from "../ui/colors.js"; -import { withHeygenCanaryRoute } from "../utils/heygenRoute.js"; const REVOKE_TIMEOUT_MS = 5_000; const MIN_EXPIRES_IN_SECONDS = 30; @@ -256,10 +255,10 @@ async function requestDeviceAuthorization( async (signal) => { const response = await runtime.fetchImpl(deviceAuthorizationEndpoint(), { method: "POST", - headers: withHeygenCanaryRoute({ + headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json", - }), + }, body: new URLSearchParams({ client_id: runtime.clientId, scope }).toString(), signal, }); @@ -304,10 +303,10 @@ async function requestDeviceToken( async (signal) => { const response = await runtime.fetchImpl(tokenEndpoint(), { method: "POST", - headers: withHeygenCanaryRoute({ + headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json", - }), + }, body: new URLSearchParams({ grant_type: DEVICE_CODE_GRANT_TYPE, device_code: deviceCode, @@ -395,10 +394,10 @@ export async function refreshTokens( const res = await fetchImpl(tokenEndpoint(), { method: "POST", - headers: withHeygenCanaryRoute({ + headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json", - }), + }, body: body.toString(), }); @@ -447,9 +446,7 @@ export async function revokeTokens(token: string, opts: RevokeOptions = {}): Pro try { const res = await fetchImpl(revokeEndpoint(), { method: "POST", - headers: withHeygenCanaryRoute({ - "content-type": "application/x-www-form-urlencoded", - }), + headers: { "content-type": "application/x-www-form-urlencoded" }, body: body.toString(), signal: controller.signal, }); @@ -510,10 +507,10 @@ async function exchangeCodeForTokens(args: { }); const res = await fetchImpl(tokenEndpoint(), { method: "POST", - headers: withHeygenCanaryRoute({ + headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json", - }), + }, body: body.toString(), }); if (res.status === 400 || res.status === 401) { diff --git a/packages/cli/src/utils/heygenRoute.ts b/packages/cli/src/utils/heygenRoute.ts deleted file mode 100644 index 0654fab21..000000000 --- a/packages/cli/src/utils/heygenRoute.ts +++ /dev/null @@ -1,9 +0,0 @@ -const HEYGEN_ROUTE_HEADER = "heygen_route"; -const HEYGEN_CANARY_ROUTE = "canary"; - -/** Route CLI-owned HeyGen API calls through the EF canary deployment. */ -export function withHeygenCanaryRoute( - headers: Record = {}, -): Record { - return { ...headers, [HEYGEN_ROUTE_HEADER]: HEYGEN_CANARY_ROUTE }; -} diff --git a/packages/cli/src/utils/publishProject.e2e.test.ts b/packages/cli/src/utils/publishProject.e2e.test.ts index b3836c071..c8e58f164 100644 --- a/packages/cli/src/utils/publishProject.e2e.test.ts +++ b/packages/cli/src/utils/publishProject.e2e.test.ts @@ -36,7 +36,6 @@ describeE2E("publish stable-URL round trip (live server)", () => { async function fetchPublicProject(projectId: string): Promise> { const response = await fetch( `${getPublishApiBaseUrl()}/v1/hyperframes/projects/${projectId}/public`, - { headers: { heygen_route: "canary" } }, ); expect(response.ok).toBe(true); const payload = (await response.json()) as { data: Record }; diff --git a/packages/cli/src/utils/publishProject.test.ts b/packages/cli/src/utils/publishProject.test.ts index 8cff80828..2b6e62979 100644 --- a/packages/cli/src/utils/publishProject.test.ts +++ b/packages/cli/src/utils/publishProject.test.ts @@ -551,7 +551,7 @@ afterEach(() => { vi.unstubAllEnvs(); }); -const jsonHeaders = { "content-type": "application/json", heygen_route: "canary" }; +const jsonHeaders = { "content-type": "application/json" }; const signedStagedS3Url = "https://s3.example.com/upload?X-Amz-SignedHeaders=content-length;content-type;host;x-amz-server-side-encryption"; @@ -662,7 +662,7 @@ describe("publishProjectArchive", () => { expect(fetchMock).toHaveBeenCalledTimes(2); expectFetchCall(fetchMock, 2, "https://api2.heygen.com/v1/hyperframes/projects/publish", { method: "POST", - headers: { heygen_route: "canary" }, + headers: {}, }); } finally { rmSync(dir, { recursive: true, force: true }); diff --git a/packages/cli/src/utils/publishProject.ts b/packages/cli/src/utils/publishProject.ts index ab4411b26..c383b1f15 100644 --- a/packages/cli/src/utils/publishProject.ts +++ b/packages/cli/src/utils/publishProject.ts @@ -5,7 +5,6 @@ import AdmZip from "adm-zip"; import ignore, { type Ignore } from "ignore"; import { CSS_URL_RE, isNonRelativeUrl, isPathInside } from "@hyperframes/core"; import { buildAuthHeaders } from "../auth/client.js"; -import { withHeygenCanaryRoute } from "./heygenRoute.js"; import { tryResolveCredential } from "../auth/index.js"; import { writeProjectLink } from "./projectLink.js"; @@ -558,7 +557,7 @@ async function publishProjectArchiveDirect( "file", new File([archiveArrayBuffer(archive)], `${title}.zip`, { type: PUBLISH_CONTENT_TYPE }), ); - const headers = withHeygenCanaryRoute(authHeaders); + const headers: Record = { ...authHeaders }; const response = await fetchForPublish( `${apiBaseUrl}/v1/hyperframes/projects/publish`, @@ -621,10 +620,10 @@ async function publishProjectArchiveStaged( content_type: PUBLISH_CONTENT_TYPE, content_length: archive.buffer.byteLength, }), - headers: withHeygenCanaryRoute({ + headers: { ...authHeaders, "content-type": "application/json", - }), + }, signal: AbortSignal.timeout(PUBLISH_METADATA_TIMEOUT_MS), }), "Failed to prepare project upload", @@ -654,10 +653,10 @@ async function publishProjectArchiveStaged( ...(isPublic ? { is_public: true } : {}), ...(projectId ? { project_id: projectId } : {}), }), - headers: withHeygenCanaryRoute({ + headers: { ...authHeaders, "content-type": "application/json", - }), + }, signal: AbortSignal.timeout(uploadTimeoutMs(archive.buffer.byteLength)), }), "Failed to finalize project publish", diff --git a/packages/cli/src/utils/submitFeedback.test.ts b/packages/cli/src/utils/submitFeedback.test.ts index b69568f2b..608ad94ff 100644 --- a/packages/cli/src/utils/submitFeedback.test.ts +++ b/packages/cli/src/utils/submitFeedback.test.ts @@ -35,7 +35,7 @@ describe("submitFeedback", () => { "https://api.example.com/v1/hyperframes/feedback", expect.objectContaining({ method: "POST", - headers: { "content-type": "application/json", heygen_route: "canary" }, + headers: { "content-type": "application/json" }, body: JSON.stringify({ rating: 4, rating_scale: 10, diff --git a/packages/cli/src/utils/submitFeedback.ts b/packages/cli/src/utils/submitFeedback.ts index 219a01574..59d200cd8 100644 --- a/packages/cli/src/utils/submitFeedback.ts +++ b/packages/cli/src/utils/submitFeedback.ts @@ -1,6 +1,5 @@ import { getPublishApiBaseUrl } from "./publishProject.js"; import { FEEDBACK_RATING_SCALE } from "./feedbackRating.js"; -import { withHeygenCanaryRoute } from "./heygenRoute.js"; // Match the backend DTO caps (HyperframesFeedbackRequest). Truncate here so an // over-long field (e.g. a pasted stack trace) is still forwarded truncated, @@ -31,9 +30,9 @@ export async function submitFeedback(input: { cli_version: cap(input.cliVersion, MAX_CLI_VERSION), env: cap(input.env, MAX_ENV), }), - headers: withHeygenCanaryRoute({ + headers: { "content-type": "application/json", - }), + }, signal: AbortSignal.timeout(5000), }); } catch {