TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import { NextResponse } from "next/server";2import { eq } from "drizzle-orm";3import { getDb, models } from "@/db";4import { curatePublicModels, PUBLIC_MODELS_MAX } from "@/lib/marketing/public-models";5import { log } from "@/lib/log";67export const dynamic = "force-dynamic";89const CACHE = "public, max-age=600, s-maxage=600, stale-while-revalidate=300";1011/**12 * GET /api/public/models — unauthenticated, cached 10 minutes.13 * A compact list (≤ 40) of active/preview models from the registry for the marketing site:14 * key, displayName, provider, contextTokens, inputPerMillion, outputPerMillion, status, firstSeenAt.15 * No user data, no favorites, no keys — the same facts the public /models page shows.16 */17export async function GET() {18 try {19 const rows = await getDb()20 .select({21 key: models.key,22 displayName: models.displayName,23 provider: models.provider,24 limits: models.limits,25 pricing: models.pricing,26 status: models.status,27 sortWeight: models.sortWeight,28 firstSeenAt: models.firstSeenAt,29 hidden: models.hidden,30 })31 .from(models)32 .where(eq(models.hidden, false));3334 const list = curatePublicModels(35 rows.map((r) => ({36 key: r.key,37 displayName: r.displayName,38 provider: r.provider,39 contextTokens: r.limits?.contextTokens ?? null,40 inputPerMillion: r.pricing?.inputPerMillion ?? null,41 outputPerMillion: r.pricing?.outputPerMillion ?? null,42 status: r.status,43 sortWeight: r.sortWeight,44 firstSeenAt: r.firstSeenAt,45 hidden: r.hidden,46 })),47 new Date(),48 PUBLIC_MODELS_MAX,49 );5051 return NextResponse.json({ models: list, total: rows.length, generatedAt: new Date().toISOString() }, { headers: { "Cache-Control": CACHE } });52 } catch (e) {53 log.warn("public models failed", { error: (e as Error).message });54 return NextResponse.json({ models: [], total: 0, generatedAt: new Date().toISOString() }, { status: 503, headers: { "Cache-Control": "public, max-age=60" } });55 }56}57