SPB Git
1.5 KB · 18 lines typescript
1/** Deterministic public export (JSON + CSV) → exports/. Same shape as the content schema; re-importable. */2import "./_env";3import { writeFileSync, mkdirSync } from "node:fs";4import { join } from "node:path";5import Papa from "papaparse";6import { sql, closeDb } from "../src/db";7import { getToolRecord } from "../src/lib/admin/tools";8const dir = join(import.meta.dirname, "..", "exports"); mkdirSync(dir, { recursive: true });9const ids = await sql<{ id: string }[]>`SELECT id FROM tools WHERE visibility='public' AND editorial_status='published' AND duplicate_of IS NULL ORDER BY slug`;10const records: any[] = [];11for (const r of ids) { const rec = await getToolRecord(r.id); if (!rec) continue; const { id: _i, quality_score: _q, link_state: _l, checked_at: _c, published_at: _p, updated_at: _u, duplicate_of: _d, ...rest } = rec; records.push(rest); }12writeFileSync(join(dir, "tools-public.json"), JSON.stringify(records, null, 2));13const flat = records.map((r) => 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])));14writeFileSync(join(dir, "tools-public.csv"), Papa.unparse(flat));15writeFileSync(join(dir, "sample-export.json"), JSON.stringify(records.slice(0, 3), null, 2));16console.log(`exported ${records.length} public records → exports/tools-public.{json,csv} (+ sample-export.json)`);17await closeDb();18
Files · laptop-initial-20261102
Menu

Theme