import type { BetterAuthOptions } from "@better-auth/core"; import { ENV, getBooleanEnvVar, isTest, logger } from "@better-auth/core/env"; import { betterFetch } from "@better-fetch/fetch"; import { getTelemetryAuthConfig } from "./detectors/detect-auth-config"; import { detectDatabase } from "./detectors/detect-database"; import { detectFramework } from "./detectors/detect-framework"; import { detectPackageManager } from "./detectors/detect-project-info"; import { detectEnvironment, detectRuntime } from "./detectors/detect-runtime"; import { detectSystemInfo } from "./detectors/detect-system-info"; import { getProjectId } from "./project-id"; import type { TelemetryContext, TelemetryEvent } from "./types"; export { getTelemetryAuthConfig }; export type { TelemetryEvent } from "./types"; const noop: (event: TelemetryEvent) => Promise = async function noop() {}; export async function createTelemetry( options: BetterAuthOptions, context?: TelemetryContext | undefined, ) { const debugEnabled = options.telemetry?.debug || getBooleanEnvVar("BETTER_AUTH_TELEMETRY_DEBUG", false); const telemetryEndpoint = ENV.BETTER_AUTH_TELEMETRY_ENDPOINT; // Return noop if no endpoint and no custom track function if (!telemetryEndpoint && !context?.customTrack) { return { publish: noop, }; } const track = async (event: TelemetryEvent) => { if (context?.customTrack) { await context.customTrack(event).catch(logger.error); } else if (telemetryEndpoint) { if (debugEnabled) { logger.info("telemetry event", JSON.stringify(event, null, 2)); } else { await betterFetch(telemetryEndpoint, { method: "POST", body: event, }).catch(logger.error); } } }; const isEnabled = async () => { const telemetryEnabled = options.telemetry?.enabled !== undefined ? options.telemetry.enabled : false; const envEnabled = getBooleanEnvVar("BETTER_AUTH_TELEMETRY", false); return ( (envEnabled || telemetryEnabled) && (context?.skipTestCheck || !isTest()) ); }; const enabled = await isEnabled(); let anonymousId: string | undefined; if (enabled) { anonymousId = await getProjectId( typeof options.baseURL === "string" ? options.baseURL : undefined, ); const payload = { config: await getTelemetryAuthConfig(options, context), runtime: detectRuntime(), database: await detectDatabase(), framework: await detectFramework(), environment: detectEnvironment(), systemInfo: await detectSystemInfo(), packageManager: detectPackageManager(), }; void track({ type: "init", payload, anonymousId }); } return { publish: async (event: TelemetryEvent) => { if (!enabled) return; if (!anonymousId) { anonymousId = await getProjectId( typeof options.baseURL === "string" ? options.baseURL : undefined, ); } await track({ type: event.type, payload: event.payload, anonymousId, }); }, }; }