route.ts41 lines · main
1import { NextResponse } from 'next/server';
2
3import { searchDocs } from '../../../lib/docs-corpus';
4
5/**
6 * Docs search endpoint. Returns the top-N pages by word-overlap against
7 * a query. Pre-stages the AI docs assistant — when ollama is wired the
8 * inference layer reads from this same corpus + ranking, picks the top
9 * 3, and forwards them as system-prompt context.
10 *
11 * Public, no auth — it serves the same docs anyone can read at the
12 * paths in the response. Capped at 25 results so a runaway client
13 * can't pull the entire corpus in one call (the corpus is small but
14 * the response would still be ~3 KB, and a public endpoint deserves
15 * the bound).
16 */
17
18export const dynamic = 'force-dynamic';
19
20export async function GET(req: Request): Promise<Response> {
21 const { searchParams } = new URL(req.url);
22 const q = searchParams.get('q')?.trim() ?? '';
23 const limitParam = Number(searchParams.get('limit') ?? '5');
24 const limit = Number.isFinite(limitParam)
25 ? Math.min(Math.max(Math.floor(limitParam), 1), 25)
26 : 5;
27
28 if (q.length === 0) {
29 return NextResponse.json({ query: '', results: [] });
30 }
31
32 const matches = searchDocs(q, limit);
33 return NextResponse.json({
34 query: q,
35 results: matches.map((m) => ({
36 slug: m.slug,
37 title: m.title,
38 summary: m.summary,
39 })),
40 });
41}