mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(studio): guard import.meta.env access for non-Vite bundlers
import.meta.env is undefined in Next.js Turbopack/Webpack, causing "Cannot read properties of undefined" when the studio telemetry client loads. Wrap accesses in try-catch so they gracefully fall back. Also hardcode the PostHog API key and host — they're public write-only values with no reason to be overridable via env.
This commit is contained in:
@@ -2,20 +2,11 @@
|
||||
|
||||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
|
||||
// `shouldTrack()` reads `POSTHOG_API_KEY` from module-level const that's
|
||||
// evaluated at module load time, so changing `import.meta.env` after import
|
||||
// has no effect on the key. Each test resets module cache and re-imports.
|
||||
// `shouldTrack()` reads module-level constants evaluated at module load time,
|
||||
// so changing env after import has no effect. Each test resets module cache.
|
||||
|
||||
const OPT_OUT_KEY = "hyperframes-studio:telemetryDisabled";
|
||||
|
||||
function setKey(value: string | undefined): void {
|
||||
if (value === undefined) {
|
||||
delete (import.meta.env as Record<string, unknown>).VITE_HYPERFRAMES_POSTHOG_KEY;
|
||||
} else {
|
||||
(import.meta.env as Record<string, unknown>).VITE_HYPERFRAMES_POSTHOG_KEY = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setNoTelemetry(value: string | undefined): void {
|
||||
if (value === undefined) {
|
||||
delete (import.meta.env as Record<string, unknown>).VITE_HYPERFRAMES_NO_TELEMETRY;
|
||||
@@ -37,29 +28,16 @@ async function loadShouldTrack(): Promise<() => boolean> {
|
||||
describe("studio client shouldTrack", () => {
|
||||
beforeEach(() => {
|
||||
setDev(false);
|
||||
setKey("phc_test_key");
|
||||
setNoTelemetry(undefined);
|
||||
localStorage.clear();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("returns true when key is configured, not in dev mode, and no opt-outs", async () => {
|
||||
it("returns true when not in dev mode and no opt-outs", async () => {
|
||||
const shouldTrack = await loadShouldTrack();
|
||||
expect(shouldTrack()).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when API key does not start with phc_", async () => {
|
||||
setKey("not_a_real_key");
|
||||
const shouldTrack = await loadShouldTrack();
|
||||
expect(shouldTrack()).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when API key is empty string", async () => {
|
||||
setKey("");
|
||||
const shouldTrack = await loadShouldTrack();
|
||||
expect(shouldTrack()).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when user has opted out via localStorage", async () => {
|
||||
localStorage.setItem(OPT_OUT_KEY, "1");
|
||||
const shouldTrack = await loadShouldTrack();
|
||||
@@ -93,7 +71,6 @@ describe("studio client shouldTrack", () => {
|
||||
it("memoizes its decision after the first call", async () => {
|
||||
const shouldTrack = await loadShouldTrack();
|
||||
const first = shouldTrack();
|
||||
// Flip an underlying input — memoized return must not change.
|
||||
localStorage.setItem(OPT_OUT_KEY, "1");
|
||||
expect(shouldTrack()).toBe(first);
|
||||
});
|
||||
|
||||
@@ -7,15 +7,9 @@
|
||||
import { getAnonymousId, hasShownNotice, isOptedOut, markNoticeShown } from "./config";
|
||||
import { getBrowserSystemMeta } from "./system";
|
||||
|
||||
// HeyGen's PostHog project key — write-only, safe to embed in client code.
|
||||
// OSS builds can override via `VITE_HYPERFRAMES_POSTHOG_KEY` at build time,
|
||||
// or set it to an empty string to disable telemetry entirely.
|
||||
const POSTHOG_API_KEY =
|
||||
(import.meta.env.VITE_HYPERFRAMES_POSTHOG_KEY as string | undefined) ??
|
||||
"phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
|
||||
const POSTHOG_HOST =
|
||||
(import.meta.env.VITE_HYPERFRAMES_POSTHOG_HOST as string | undefined) ??
|
||||
"https://us.i.posthog.com";
|
||||
// Write-only PostHog project key, safe to embed in client code.
|
||||
const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
|
||||
const POSTHOG_HOST = "https://us.i.posthog.com";
|
||||
const FLUSH_INTERVAL_MS = 1_000;
|
||||
|
||||
type EventProperties = Record<string, string | number | boolean | undefined>;
|
||||
@@ -41,15 +35,24 @@ function isApiKeyConfigured(): boolean {
|
||||
// VITE_HYPERFRAMES_NO_TELEMETRY mirrors the CLI's HYPERFRAMES_NO_TELEMETRY=1
|
||||
// opt-out so HeyGen's own dev/CI builds can suppress telemetry from the studio
|
||||
// bundle the same way. Vite injects it at build time. Accepts "1" or "true".
|
||||
// `import.meta.env` may be undefined in non-Vite bundlers (Next.js Turbopack).
|
||||
function isBuildTimeOptOut(): boolean {
|
||||
const v = import.meta.env.VITE_HYPERFRAMES_NO_TELEMETRY as string | undefined;
|
||||
return v === "1" || v === "true";
|
||||
try {
|
||||
const v = import.meta.env.VITE_HYPERFRAMES_NO_TELEMETRY as string | undefined;
|
||||
return v === "1" || v === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// `import.meta.env.DEV` is true under `vite dev` / `vite preview`. Auto-suppress
|
||||
// so developers running `hyperframes preview` don't pollute production telemetry.
|
||||
function isViteDevMode(): boolean {
|
||||
return import.meta.env.DEV === true;
|
||||
try {
|
||||
return import.meta.env.DEV === true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function shouldTrack(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user