import { z } from "zod"; import { desc, eq, sql } from "drizzle-orm"; import { NextResponse } from "next/server"; import { withUser, parseBody, json, ApiError } from "@/lib/api"; import { isAdmin } from "@/lib/session"; import { registryStats, syncAllWithEnvKeys, syncProvider } from "@/lib/ai/registry"; import { getDb, providerConnections, usageRecords, users, models } from "@/db"; import { PROVIDER_IDS, isProviderId } from "@/lib/ai/core/types"; import { ownerKey } from "@/lib/ai/providers/env-keys"; export const dynamic = "force-dynamic"; /** Owner-only diagnostics: provider status, model sync, discovered models, latency, errors. */ export const GET = withUser(async ({ user }) => { if (!isAdmin(user)) throw new ApiError(403, "Admins only", "FORBIDDEN"); const db = getDb(); const stats = await registryStats(); const [userCount] = await db.select({ n: sql`count(*)::int` }).from(users); const connections = await db.select({ provider: providerConnections.provider, status: providerConnections.status, n: sql`count(*)::int` }).from(providerConnections).groupBy(providerConnections.provider, providerConnections.status); const errors = await db .select({ provider: usageRecords.provider, errorCode: usageRecords.errorCode, n: sql`count(*)::int` }) .from(usageRecords) .where(sql`${usageRecords.status} = 'error' and ${usageRecords.createdAt} > now() - interval '7 days'`) .groupBy(usageRecords.provider, usageRecords.errorCode) .orderBy(desc(sql`count(*)`)) .limit(30); const latency = await db .select({ provider: usageRecords.provider, avgLatencyMs: sql`coalesce(avg(${usageRecords.latencyMs}),0)::float8`, avgTtftMs: sql`coalesce(avg(${usageRecords.ttftMs}),0)::float8`, requests: sql`count(*)::int` }) .from(usageRecords) .where(sql`${usageRecords.createdAt} > now() - interval '7 days'`) .groupBy(usageRecords.provider); const perProvider = await Promise.all( PROVIDER_IDS.map(async (p) => { const rows = await db.select({ key: models.key, displayName: models.displayName, status: models.status, hidden: models.hidden, lastSeenAt: models.lastSeenAt, source: models.source }).from(models).where(eq(models.provider, p)).orderBy(desc(models.sortWeight)); return { provider: p, envKeyConfigured: Boolean(ownerKey(p)), models: rows.map((r) => ({ ...r, lastSeenAt: r.lastSeenAt.toISOString() })) }; }), ); return json({ users: userCount.n, connections, counts: stats.counts, syncRuns: stats.lastRuns.map((r) => ({ ...r, startedAt: r.startedAt.toISOString(), finishedAt: r.finishedAt?.toISOString() ?? null })), errors, latency, providers: perProvider, }); }); export const POST = withUser(async ({ req, user }) => { if (!isAdmin(user)) throw new ApiError(403, "Admins only", "FORBIDDEN"); const body = await parseBody(req, z.object({ action: z.literal("sync"), provider: z.string().optional() })); if (body.provider) { if (!isProviderId(body.provider)) throw new ApiError(400, "Unknown provider"); const key = ownerKey(body.provider); if (!key) return NextResponse.json({ error: { code: "NO_ENV_KEY", message: "No owner key configured for this provider" } }, { status: 400 }); return json({ results: [await syncProvider(body.provider, key, "admin")] }); } return json({ results: await syncAllWithEnvKeys("admin") }); });