275 lines · 10.8 KB
/**
 * Browser analytics (PostHog). Everything here is a no-op unless the server sent a config, which it only does
 * when POSTHOG_KEY is set. posthog-js is loaded lazily, so instances without analytics never download it.
 *
 * Privacy rules enforced here:
 * - Honors Do Not Track and Global Privacy Control, and a per-browser opt-out (setAnalyticsOptOut).
 * - Runs only on the forge's own origin, never on editor, user-content, sites or pages origins.
 * - URLs lose query strings and fragments; repository paths are redacted unless the repo is known public.
 * - Autocapture never records element text or attributes; inputs are masked in replays, and replays pause on
 *   private repositories and on account, settings and auth pages.
 */
import type { PostHog } from "posthog-js";

export type ClientAnalyticsConfig = { key: string; host: string; origin: string; personEmail: boolean };
export type AnalyticsViewer = { id: string; email?: string; isAdmin?: boolean } | null;

const OPT_OUT_KEY = "gitfor:analytics-opt-out";
const REDACTED = "[private]";

/** First path segments that are app pages, not account names. */
const APP_ROOTS = new Set([
  "",
  "abuse",
  "admin",
  "explore",
  "features",
  "forgot-password",
  "login",
  "new",
  "notifications",
  "orgs",
  "projects",
  "reset-password",
  "search",
  "self-host",
  "settings",
  "signup",
  "verify-email",
  "api",
  "auth",