/** Role-scoped export. scope=public → published public records only (safe to share). scope=all → everything incl. private/owner notes (owner only). format=json|csv */ import Papa from "papaparse"; import { requireUser, jsonError, HttpError } from "@/lib/auth/guard"; import { sql } from "@/db"; import { getToolRecord } from "@/lib/admin/tools"; export async function GET(req: Request) { try { const s = await requireUser(); const p = new URL(req.url).searchParams; const scope = p.get("scope") ?? "public"; const format = p.get("format") ?? "json"; if (scope === "all" && s.role !== "owner") throw new HttpError(403, "Owner only"); const ids = await sql<{ id: string }[]>`SELECT id FROM tools WHERE duplicate_of IS NULL ${scope === "all" ? sql`` : sql`AND visibility='public' AND editorial_status='published'`} ORDER BY slug`; const records = []; for (const r of ids) { const rec = await getToolRecord(r.id); if (!rec) continue; const { id: _i, quality_score, link_state, checked_at, published_at, updated_at, duplicate_of: _d, ...rest } = rec; records.push(scope === "all" ? { ...rest, _meta: { quality_score, link_state, checked_at, published_at, updated_at } } : rest); } if (scope === "all") { const notes = await sql`SELECT t.slug, o.* FROM owner_notes o JOIN tools t ON t.id=o.tool_id`; (records as any).push({ _owner_notes: notes }); } const stamp = new Date().toISOString().slice(0, 10); if (format === "csv") { const flat = records.filter((r: any) => !r._owner_notes).map((r: any) => Object.fromEntries(Object.entries(r).map(([k, v]) => [k, Array.isArray(v) ? (k === "categories" ? v.map((c: any) => c.slug).join("|") : k === "sources" ? v.map((x: any) => `${x.url}^${x.type}`).join("|") : v.join("|")) : typeof v === "object" && v ? (k === "vendor" ? (v as any).name : JSON.stringify(v)) : v]))); return new Response(Papa.unparse(flat), { headers: { "content-type": "text/csv; charset=utf-8", "content-disposition": `attachment; filename="tools-${scope}-${stamp}.csv"` } }); } return new Response(JSON.stringify(records, null, 2), { headers: { "content-type": "application/json", "content-disposition": `attachment; filename="tools-${scope}-${stamp}.json"` } }); } catch (e) { return jsonError(e); } }