import { createLogger, getRequestContext } from '@sim/logger' import type { PostHog } from 'posthog-node' import type { PostHogEventMap, PostHogEventName } from '@/lib/posthog/events' const logger = createLogger('PostHogServer') let _client: PostHog | null = null let _disabled = false export function getPostHogClient(): PostHog | null { return getClient() } function getClient(): PostHog | null { if (_disabled) return null if (_client) return _client const key = process.env.NEXT_PUBLIC_POSTHOG_KEY const enabled = process.env.NEXT_PUBLIC_POSTHOG_ENABLED if (!key || !enabled || enabled === 'false' || enabled === '0') { _disabled = true return null } // eslint-disable-next-line @typescript-eslint/no-require-imports const { PostHog } = require('posthog-node') as typeof import('posthog-node') _client = new PostHog(key, { host: 'https://us.i.posthog.com', flushAt: 20, flushInterval: 10_000, }) return _client } type PersonProperties = Record interface CaptureOptions { /** * Associate this event with workspace-level group analytics. * Pass `{ workspace: workspaceId }`. */ groups?: Record /** * Person properties to update on every capture (`$set`). * Use for mutable state like `plan`, `total_workflows`. */ set?: PersonProperties /** * Person properties to set only once (`$set_once`). * Use for immutable milestones like `first_execution_at`. */ setOnce?: PersonProperties } /** * Capture a server-side PostHog event. Fire-and-forget — never throws. * * @param distinctId - The user (or workspace/org) ID to associate the event with. * @param event - Typed event name from {@link PostHogEventMap}. * @param properties - Strongly-typed property bag for this event. * @param options - Optional groups, $set, and $set_once person properties. */ export function captureServerEvent( distinctId: string, event: E, properties: PostHogEventMap[E], options?: CaptureOptions ): void { try { const client = getClient() if (!client) return const contextRequestId = getRequestContext()?.requestId const props = properties as Record client.capture({ distinctId, event, properties: { ...properties, ...(contextRequestId && !('request_id' in props) ? { request_id: contextRequestId } : {}), ...(options?.groups ? { $groups: options.groups } : {}), ...(options?.set ? { $set: options.set } : {}), ...(options?.setOnce ? { $set_once: options.setOnce } : {}), }, }) } catch (error) { logger.warn('Failed to capture PostHog server event', { event, error }) } }