spb/search-box Public
Agentic web research engine — hypotheses, verbatim evidence, contradictions, sourced answers streamed live. Claude Opus 5 + Firecrawl + PostgreSQL.
TypeScript 76.9%
CSS 18.7%
SQL 2.1%
JavaScript 1.8%
Shell 0.5%
1/**2 * Search-box.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: apps/web/app/api/research/route.ts6 * Description: POST — start a research session; GET — list recent sessions.7 */89import { NextResponse } from "next/server";10import { sessions } from "@search-box/db";11import { ensureMigrated, startResearch } from "@/lib/runner";1213export const runtime = "nodejs";14export const dynamic = "force-dynamic";1516export async function POST(req: Request): Promise<NextResponse> {17 let body: unknown;18 try {19 body = await req.json();20 } catch {21 return NextResponse.json({ error: "invalid JSON body" }, { status: 400 });22 }23 const question =24 typeof body === "object" && body !== null && "question" in body25 ? String((body as { question: unknown }).question ?? "").trim()26 : "";27 if (question.length < 8 || question.length > 2000) {28 return NextResponse.json({ error: "question must be 8–2000 characters" }, { status: 400 });29 }30 const id = await startResearch(question);31 return NextResponse.json({ id }, { status: 201 });32}3334export async function GET(): Promise<NextResponse> {35 await ensureMigrated();36 const list = await sessions.list(30);37 return NextResponse.json({38 sessions: list.map((s) => ({39 id: s.id,40 question: s.question,41 status: s.status,42 createdAt: s.createdAt43 }))44 });45}46