TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import { withUser, json } from "@/lib/api";2import { searchAll, SEARCH_GROUPS, type SearchGroup } from "@/lib/search/service";3import { LIMITS } from "@/lib/rate-limit";45export const dynamic = "force-dynamic";67/**8 * GET /api/search?q=<query>&limit=12&cursor=<opaque>&groups=conversations,messages9 *10 * Query language (see src/lib/search/query.ts): free text, "quoted phrases", model:, provider:, project:, folder:,11 * after:, before:, role:user|assistant, is:pinned|archived|shared. Response: SearchResponse (grouped hits,12 * `query.terms` for client-side highlighting, `nextCursor` for conversations/messages pagination).13 */14export const GET = withUser(15 async ({ req, user }) => {16 const sp = new URL(req.url).searchParams;17 const q = (sp.get("q") ?? "").trim().slice(0, 300);18 const limitRaw = Number(sp.get("limit") ?? 12);19 const limit = Number.isFinite(limitRaw) ? limitRaw : 12;20 const cursor = sp.get("cursor");21 const groups = (sp.get("groups") ?? "")22 .split(",")23 .map((g) => g.trim())24 .filter((g): g is SearchGroup => (SEARCH_GROUPS as readonly string[]).includes(g));25 const res = await searchAll(user.id, q, { limit, cursor, groups });26 return json(res);27 },28 { limit: { ...LIMITS.search, key: "search" } },29);30