/** * Client-side telemetry for the tracker dashboard. * * Delegates to @bytelyst/telemetry-client shared package. * Sends events via /api/telemetry/ingest proxy. * * Privacy: No PII. Only page paths, action names, and timing metrics. * See docs/WINDSURF/CLIENT_TELEMETRY_DESIGN.md */ import { createTelemetryClient, type TelemetryClient } from '@bytelyst/telemetry-client'; // Product ID resolved from env var set by the deploying product. // Each product sets NEXT_PUBLIC_PRODUCT_ID in its .env (e.g. 'lysnrai', 'chronomind', 'nomgap'). const PRODUCT_ID = process.env.NEXT_PUBLIC_PRODUCT_ID || 'unknown'; let _client: TelemetryClient | null = null; function getClient(): TelemetryClient { if (!_client) { _client = createTelemetryClient({ productId: PRODUCT_ID, baseUrl: '', endpoint: '/api/telemetry/ingest', platform: 'web', channel: 'web_app', transport: 'beacon', appVersion: '0.0.0', buildNumber: '0', releaseChannel: 'beta', }); } return _client; } export function trackEvent( eventType: 'debug' | 'info' | 'warn' | 'error', module: string, eventName: string, options?: { feature?: string; message?: string; tags?: Record; metrics?: Record; } ): void { if (typeof window === 'undefined') return; getClient().trackEvent(eventType, module, eventName, options); } export function trackPageView(path: string): void { trackEvent('info', 'navigation', 'page_view', { tags: { path }, }); } export function flush(): void { if (typeof window === 'undefined') return; getClient().flush(); } export function initTelemetry(): void { if (typeof window === 'undefined') return; getClient().init(); }