import { isEpisode, parsePhraseQuery, searchPhrases, MAX_TERMS } from "@/lib/phrases"; export const dynamic = "force-dynamic"; // The MECHANISM surface. /browse/find calls searchPhrases() directly and never // touches this route -- a page that fetched its own API would serialise a // render behind a round trip to itself for nothing. // // This exists so the e2e suite and a script can ask the same question the page // asks, and get the same answer from the same parser. If the two ever drifted, // the suite would be testing a second implementation instead of the one that // ships; parsePhraseQuery is shared precisely so they cannot. export async function GET(request: Request) { const url = new URL(request.url); const { query, errors } = parsePhraseQuery(url.searchParams); if (!query.q.trim()) { return Response.json({ error: "q is required" }, { status: 400 }); } if (errors.length) { return Response.json({ error: errors[0].message, errors, maxTerms: MAX_TERMS }, { status: 400 }); } if (query.video && !(await isEpisode(query.video))) { return Response.json({ error: `no episode called ${query.video}` }, { status: 404 }); } return Response.json(await searchPhrases(query), { headers: { "cache-control": "no-store" }, }); }