import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } export function formatNumber(n: number | null | undefined, opts: Intl.NumberFormatOptions = {}): string { if (n === null || n === undefined || Number.isNaN(n)) return "—"; return new Intl.NumberFormat("en-US", { maximumFractionDigits: 0, ...opts }).format(n); } export function formatCompact(n: number | null | undefined): string { if (n === null || n === undefined) return "—"; if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1)}M`; if (n >= 1_000) return `${(n / 1_000).toFixed(n % 1_000 === 0 ? 0 : 0)}K`; return String(n); } export function formatTokens(n: number | null | undefined): string { if (n === null || n === undefined) return "—"; if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(2).replace(/\.?0+$/, "")}M`; if (n >= 10_000) return `${(n / 1_000).toFixed(1).replace(/\.?0+$/, "")}K`; return new Intl.NumberFormat("en-US").format(n); } export function formatUsd(n: number | null | undefined, opts: { precise?: boolean } = {}): string { if (n === null || n === undefined || Number.isNaN(n)) return "—"; if (n === 0) return "$0.00"; if (n < 0.01 || opts.precise) return `$${n.toFixed(n < 0.001 ? 5 : 4)}`; return `$${n.toFixed(2)}`; } export function formatMs(ms: number | null | undefined): string { if (ms === null || ms === undefined) return "—"; if (ms < 1000) return `${Math.round(ms)} ms`; return `${(ms / 1000).toFixed(ms < 10_000 ? 2 : 1)} s`; } export function formatRelative(date: Date | string | null | undefined): string { if (!date) return "—"; const d = typeof date === "string" ? new Date(date) : date; const diff = Date.now() - d.getTime(); const s = Math.round(diff / 1000); if (s < 45) return "just now"; const m = Math.round(s / 60); if (m < 60) return `${m} min ago`; const h = Math.round(m / 60); if (h < 24) return `${h} h ago`; const days = Math.round(h / 24); if (days < 7) return `${days} d ago`; return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: d.getFullYear() === new Date().getFullYear() ? undefined : "numeric" }); } export function truncate(s: string, n: number): string { return s.length > n ? `${s.slice(0, n - 1)}…` : s; } export function sleep(ms: number, signal?: AbortSignal): Promise { return new Promise((resolve, reject) => { const t = setTimeout(resolve, ms); signal?.addEventListener( "abort", () => { clearTimeout(t); reject(new DOMException("Aborted", "AbortError")); }, { once: true }, ); }); }