import { NextResponse } from "next/server"; import { z } from "zod"; import { prisma } from "@/lib/prisma"; const QuerySchema = z.object({ query: z.string().trim().min(1).max(200).optional(), entity: z.string().trim().min(1).max(120).optional(), // entity slug tag: z.string().trim().min(1).max(120).optional(), // tag slug model: z.string().trim().min(1).max(120).optional(), // model slug sort: z.enum(["new", "popular"]).optional().default("new"), limit: z.coerce.number().int().min(1).max(50).optional().default(20), offset: z.coerce.number().int().min(0).max(5000).optional().default(0), }); export async function GET(req: Request) { const url = new URL(req.url); const parsed = QuerySchema.safeParse({ query: url.searchParams.get("query") ?? undefined, entity: url.searchParams.get("entity") ?? undefined, tag: url.searchParams.get("tag") ?? undefined, model: url.searchParams.get("model") ?? undefined, sort: url.searchParams.get("sort") ?? undefined, limit: url.searchParams.get("limit") ?? undefined, offset: url.searchParams.get("offset") ?? undefined, }); if (!parsed.success) { return NextResponse.json( { ok: false, error: "INVALID_QUERY", detail: parsed.error.flatten() }, { status: 400 }, ); } const { query, entity, tag, model, sort, limit, offset } = parsed.data; const where = { isPublished: true, ...(entity ? { entity: { slug: entity } } : {}), ...(model ? { model: { slug: model } } : {}), ...(tag ? { tags: { some: { tag: { slug: tag } } } } : {}), ...(query ? { OR: [ { title: { contains: query, mode: "insensitive" as const } }, { descriptionMd: { contains: query, mode: "insensitive" as const }, }, ], } : {}), }; const orderBy = sort === "popular" ? ({ likes: { _count: "desc" } } as const) : ({ createdAt: "desc" } as const); const prompts = await prisma.prompt.findMany({ where, orderBy, take: limit, skip: offset, select: { id: true, title: true, descriptionMd: true, createdAt: true, updatedAt: true, entity: { select: { slug: true, name: true } }, model: { select: { slug: true, name: true, provider: true } }, tags: { select: { tag: { select: { slug: true, name: true } } } }, _count: { select: { likes: true, comments: true, bookmarks: true } }, }, }); return NextResponse.json({ ok: true, items: prompts }); }