import Link from 'next/link'; import { requireAdmin } from '@/lib/admin/auth'; import { costsOverview } from '@/lib/admin/queries'; import { AdminShell, Bars, Kpi, n } from '@/components/admin/shell'; import { Table, th, td, tdNum } from '@/components/ui/primitives'; export default async function CostsPage({ searchParams }: { searchParams: Promise<{ days?: string }> }) { await requireAdmin(); const sp = await searchParams; const days = [7, 30, 90].includes(Number(sp.days)) ? Number(sp.days) : 30; const c = await costsOverview(days); const t = (c.totals ?? {}) as Record; const raw = Number((c.perRecord as Record | null)?.raw_records ?? 0); const dayMap = new Map(); for (const r of c.byDay) { const k = String(r.day); const cur = dayMap.get(k) ?? { usd: 0, credits: 0 }; cur.usd += Number(r.usd); cur.credits += Number(r.credits); dayMap.set(k, cur); } const series = [...dayMap.entries()].sort(([a], [b]) => (a < b ? -1 : 1)).map(([label, v]) => ({ label, value: v.usd })); const creditSeries = [...dayMap.entries()].sort(([a], [b]) => (a < b ? -1 : 1)).map(([label, v]) => ({ label, value: v.credits })); return ( {[7, 30, 90].map((d) => {d}d)}} >

USD per day

`$${v.toFixed(3)}`} />

Crawler credits per day

`${Math.round(v)} credits`} />

By kind / provider

{c.byKind.length === 0 ? : c.byKind.map((r, i) => )}
KindProviderCreditsUSDEvents
No cost events yet.
{String(r.kind)}{String(r.provider)}{n(r.credits, 1)}${n(r.usd, 3)}{n(r.events)}

By connector

{c.byConnector.length === 0 ? : c.byConnector.map((r, i) => )}
ConnectorCreditsUSDEvents
—
{String(r.connector_id)}{n(r.credits, 1)}${n(r.usd, 3)}{n(r.events)}

By category

{c.byCategory.length === 0 ? : c.byCategory.map((r, i) => )}
CategoryCreditsUSD
—
{String(r.category_slug)}{n(r.credits, 1)}${n(r.usd, 3)}

AI by endpoint / model

{c.byEndpoint.length === 0 ? : c.byEndpoint.map((r, i) => )}
EndpointModelCallsIn tokOut tokUSD
—
{String(r.endpoint)}{String(r.model)}{n(r.events)}{n(r.input_tokens)}{n(r.output_tokens)}${n(r.usd, 4)}
); }