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:
Miguel Ángel
2026-05-23 13:59:08 -04:00
parent 179b09ec9d
commit 377f081941
2 changed files with 18 additions and 38 deletions
+3 -26
View File
@@ -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);
});