import { diagnosticsAllowedForCurrentProcess } from './privacy' type PackageIncompatibility = { kind: 'package_incompatibility' packageName: string packageVersion: string unsupportedApi?: string } type ErrorShape = { kind: 'error_shape' errorClass: string } export type CliDiagnostic = PackageIncompatibility | ErrorShape type Config = { apiKey: string; host: string } function loadConfig(): Config | null { if (!diagnosticsAllowedForCurrentProcess()) return null const apiKey = process.env.CONTRAST_POSTHOG_API_KEY || process.env.VITE_POSTHOG_API_KEY || '' if (!apiKey) return null const host = process.env.CONTRAST_POSTHOG_HOST || process.env.VITE_POSTHOG_HOST || 'https://us.i.posthog.com' return { apiKey, host: host.replace(/\/+$/, '') } } function bounded(value: string, max: number): string { return value.trim().slice(0, max) } export function buildCliDiagnosticEvent(diagnostic: CliDiagnostic) { const properties = diagnostic.kind === 'package_incompatibility' ? { package_name: bounded(diagnostic.packageName, 160), package_version: bounded(diagnostic.packageVersion, 80), ...(diagnostic.unsupportedApi ? { unsupported_api: bounded(diagnostic.unsupportedApi, 160) } : {}), } : { error_class: bounded(diagnostic.errorClass, 160) } return { event: diagnostic.kind, distinct_id: 'rnx-cli-diagnostic', properties, } } const queue: CliDiagnostic[] = [] export function trackCliDiagnostic(diagnostic: CliDiagnostic): void { if (!diagnosticsAllowedForCurrentProcess()) return queue.push(diagnostic) } export function trackCliError(error: unknown): void { const errorClass = error instanceof Error ? error.constructor.name : typeof error trackCliDiagnostic({ kind: 'error_shape', errorClass }) } export async function flushCliTelemetry(): Promise { if (queue.length === 0) return const config = loadConfig() if (!config) { queue.length = 0 return } const batch = queue.splice(0, queue.length).map(buildCliDiagnosticEvent) try { await fetch(`${config.host}/batch/`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ api_key: config.apiKey, batch }), signal: AbortSignal.timeout(2_000), }) } catch { // diagnostics never change a command's result. } }