import { PostHog } from 'posthog-node' import { env } from '@sourcebot/shared' import { env as clientEnv } from '@sourcebot/shared/client'; import { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies'; import * as Sentry from "@sentry/nextjs"; import { PosthogEvent, PosthogEventMap } from './posthogEvents'; import { cookies, headers } from 'next/headers'; import { auth } from '@/auth'; import { getVerifiedApiObject } from '@/withAuthV2'; /** * @note: This is a subset of the properties stored in the * ph_phc__posthog cookie. */ export type PostHogCookie = { distinct_id: string; } const isPostHogCookie = (cookie: unknown): cookie is PostHogCookie => { return typeof cookie === 'object' && cookie !== null && 'distinct_id' in cookie; } /** * Attempts to retrieve the PostHog cookie from the given cookie store, returning * undefined if the cookie is not found or is invalid. */ const getPostHogCookie = (cookieStore: Pick): PostHogCookie | undefined => { const phCookieKey = `ph_${env.POSTHOG_PAPIK}_posthog`; const cookie = cookieStore.get(phCookieKey); if (!cookie) { return undefined; } const parsedCookie = (() => { try { return JSON.parse(cookie.value); } catch (e) { Sentry.captureException(e); return null; } })(); if (isPostHogCookie(parsedCookie)) { return parsedCookie; } return undefined; } /** * Attempts to retrieve the distinct id of the current user. */ const tryGetDistinctId = async () => { // First, attempt to retrieve the distinct id from the cookie. const cookieStore = await cookies(); const cookie = getPostHogCookie(cookieStore); if (cookie) { return cookie.distinct_id; } // Next, from the session. const session = await auth(); if (session) { return session.user.id; } // Finally, from the api key. const headersList = await headers(); const apiKeyString = headersList.get("X-Sourcebot-Api-Key") ?? undefined; if (!apiKeyString) { return undefined; } const apiKey = await getVerifiedApiObject(apiKeyString); return apiKey?.createdById; } export async function captureEvent(event: E, properties: PosthogEventMap[E]) { if (env.SOURCEBOT_TELEMETRY_DISABLED === 'true') { return; } const distinctId = await tryGetDistinctId(); const posthog = new PostHog(env.POSTHOG_PAPIK, { host: 'https://us.i.posthog.com', flushAt: 1, flushInterval: 0 }) posthog.capture({ event, properties: { ...properties, sourcebot_version: clientEnv.NEXT_PUBLIC_SOURCEBOT_VERSION, install_id: env.SOURCEBOT_INSTALL_ID, }, distinctId, }); }