import { NextResponse } from "next/server"; import { eq } from "drizzle-orm"; import { getDb, models } from "@/db"; import { curatePublicModels, PUBLIC_MODELS_MAX } from "@/lib/marketing/public-models"; import { log } from "@/lib/log"; export const dynamic = "force-dynamic"; const CACHE = "public, max-age=600, s-maxage=600, stale-while-revalidate=300"; /** * GET /api/public/models — unauthenticated, cached 10 minutes. * A compact list (≤ 40) of active/preview models from the registry for the marketing site: * key, displayName, provider, contextTokens, inputPerMillion, outputPerMillion, status, firstSeenAt. * No user data, no favorites, no keys — the same facts the public /models page shows. */ export async function GET() { try { const rows = await getDb() .select({ key: models.key, displayName: models.displayName, provider: models.provider, limits: models.limits, pricing: models.pricing, status: models.status, sortWeight: models.sortWeight, firstSeenAt: models.firstSeenAt, hidden: models.hidden, }) .from(models) .where(eq(models.hidden, false)); const list = curatePublicModels( rows.map((r) => ({ key: r.key, displayName: r.displayName, provider: r.provider, contextTokens: r.limits?.contextTokens ?? null, inputPerMillion: r.pricing?.inputPerMillion ?? null, outputPerMillion: r.pricing?.outputPerMillion ?? null, status: r.status, sortWeight: r.sortWeight, firstSeenAt: r.firstSeenAt, hidden: r.hidden, })), new Date(), PUBLIC_MODELS_MAX, ); return NextResponse.json({ models: list, total: rows.length, generatedAt: new Date().toISOString() }, { headers: { "Cache-Control": CACHE } }); } catch (e) { log.warn("public models failed", { error: (e as Error).message }); return NextResponse.json({ models: [], total: 0, generatedAt: new Date().toISOString() }, { status: 503, headers: { "Cache-Control": "public, max-age=60" } }); } }