openclaw/apps/web/lib/telemetry.ts
kumarabhirup f9d454f5c7
feat(web): forward client identity to server and improve feedback traces
Bootstrap posthog-js with the persisted install ID from the server, forward distinctId to API routes, and restructure feedback traces to use chronological conversation order.
2026-03-05 19:09:19 -08:00

74 lines
1.9 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { join, dirname } from "node:path";
import { PostHog } from "posthog-node";
const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY || "";
const POSTHOG_HOST = "https://us.i.posthog.com";
let client: PostHog | null = null;
function ensureClient(): PostHog | null {
if (!POSTHOG_KEY) return null;
if (!client) {
client = new PostHog(POSTHOG_KEY, {
host: POSTHOG_HOST,
flushAt: 10,
flushInterval: 30_000,
});
}
return client;
}
let _cachedAnonymousId: string | null = null;
/**
* Read the persisted install-scoped anonymous ID from ~/.openclaw-dench/telemetry.json,
* generating and writing one if absent.
*/
export function getOrCreateAnonymousId(): string {
if (_cachedAnonymousId) return _cachedAnonymousId;
try {
const stateDir = join(process.env.HOME || "~", ".openclaw-dench");
const configPath = join(stateDir, "telemetry.json");
let raw: Record<string, unknown> = {};
if (existsSync(configPath)) {
raw = JSON.parse(readFileSync(configPath, "utf-8"));
}
if (typeof raw.anonymousId === "string" && raw.anonymousId) {
_cachedAnonymousId = raw.anonymousId;
return raw.anonymousId;
}
const id = randomUUID();
raw.anonymousId = id;
mkdirSync(dirname(configPath), { recursive: true });
writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
_cachedAnonymousId = id;
return id;
} catch {
const id = randomUUID();
_cachedAnonymousId = id;
return id;
}
}
export function trackServer(
event: string,
properties?: Record<string, unknown>,
distinctId?: string,
): void {
const ph = ensureClient();
if (!ph) return;
ph.capture({
distinctId: distinctId || getOrCreateAnonymousId(),
event,
properties: {
...properties,
$process_person_profile: false,
},
});
}