mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 23:03:09 +00:00
Merge pull request #1049 from heygen-com/fix/studio-import-meta-env-guard
fix(studio): guard import.meta.env for non-Vite bundlers
This commit is contained in:
@@ -2,20 +2,11 @@
|
|||||||
|
|
||||||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||||
|
|
||||||
// `shouldTrack()` reads `POSTHOG_API_KEY` from module-level const that's
|
// `shouldTrack()` reads module-level constants evaluated at module load time,
|
||||||
// evaluated at module load time, so changing `import.meta.env` after import
|
// so changing env after import has no effect. Each test resets module cache.
|
||||||
// has no effect on the key. Each test resets module cache and re-imports.
|
|
||||||
|
|
||||||
const OPT_OUT_KEY = "hyperframes-studio:telemetryDisabled";
|
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 {
|
function setNoTelemetry(value: string | undefined): void {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
delete (import.meta.env as Record<string, unknown>).VITE_HYPERFRAMES_NO_TELEMETRY;
|
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", () => {
|
describe("studio client shouldTrack", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setDev(false);
|
setDev(false);
|
||||||
setKey("phc_test_key");
|
|
||||||
setNoTelemetry(undefined);
|
setNoTelemetry(undefined);
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
vi.unstubAllGlobals();
|
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();
|
const shouldTrack = await loadShouldTrack();
|
||||||
expect(shouldTrack()).toBe(true);
|
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 () => {
|
it("returns false when user has opted out via localStorage", async () => {
|
||||||
localStorage.setItem(OPT_OUT_KEY, "1");
|
localStorage.setItem(OPT_OUT_KEY, "1");
|
||||||
const shouldTrack = await loadShouldTrack();
|
const shouldTrack = await loadShouldTrack();
|
||||||
@@ -93,7 +71,6 @@ describe("studio client shouldTrack", () => {
|
|||||||
it("memoizes its decision after the first call", async () => {
|
it("memoizes its decision after the first call", async () => {
|
||||||
const shouldTrack = await loadShouldTrack();
|
const shouldTrack = await loadShouldTrack();
|
||||||
const first = shouldTrack();
|
const first = shouldTrack();
|
||||||
// Flip an underlying input — memoized return must not change.
|
|
||||||
localStorage.setItem(OPT_OUT_KEY, "1");
|
localStorage.setItem(OPT_OUT_KEY, "1");
|
||||||
expect(shouldTrack()).toBe(first);
|
expect(shouldTrack()).toBe(first);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,15 +7,9 @@
|
|||||||
import { getAnonymousId, hasShownNotice, isOptedOut, markNoticeShown } from "./config";
|
import { getAnonymousId, hasShownNotice, isOptedOut, markNoticeShown } from "./config";
|
||||||
import { getBrowserSystemMeta } from "./system";
|
import { getBrowserSystemMeta } from "./system";
|
||||||
|
|
||||||
// HeyGen's PostHog project key — write-only, safe to embed in client code.
|
// Write-only PostHog project key, safe to embed in client code.
|
||||||
// OSS builds can override via `VITE_HYPERFRAMES_POSTHOG_KEY` at build time,
|
const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
|
||||||
// or set it to an empty string to disable telemetry entirely.
|
const POSTHOG_HOST = "https://us.i.posthog.com";
|
||||||
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";
|
|
||||||
const FLUSH_INTERVAL_MS = 1_000;
|
const FLUSH_INTERVAL_MS = 1_000;
|
||||||
|
|
||||||
type EventProperties = Record<string, string | number | boolean | undefined>;
|
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
|
// 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
|
// 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".
|
// 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 {
|
function isBuildTimeOptOut(): boolean {
|
||||||
const v = import.meta.env.VITE_HYPERFRAMES_NO_TELEMETRY as string | undefined;
|
try {
|
||||||
return v === "1" || v === "true";
|
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
|
// `import.meta.env.DEV` is true under `vite dev` / `vite preview`. Auto-suppress
|
||||||
// so developers running `hyperframes preview` don't pollute production telemetry.
|
// so developers running `hyperframes preview` don't pollute production telemetry.
|
||||||
function isViteDevMode(): boolean {
|
function isViteDevMode(): boolean {
|
||||||
return import.meta.env.DEV === true;
|
try {
|
||||||
|
return import.meta.env.DEV === true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldTrack(): boolean {
|
export function shouldTrack(): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user