import { db } from '#lib/server/db/index.js'; import { requireOwner } from '#lib/server/owner.js'; import { parseCsv, toPayload, validatePayload, writeRows } from '#lib/server/health-import.js'; import { error, json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; const MAX_BYTES = 2_000_000; // Owner-only import. Same formats as scripts/health-import.ts: // POST application/json {"vaccinations":[...], "sleep":[...]} or [...] with ?table= // POST text/csv header row + rows, with ?table= // ?dry_run=1 validate only // Only JSON/CSV content types are accepted, so a cross-site form can't post here // (browsers preflight these types, and we never send CORS headers). export const POST: RequestHandler = async (event) => { requireOwner(event); const type = (event.request.headers.get('content-type') ?? '').split(';')[0].trim().toLowerCase(); if (type !== 'application/json' && type !== 'text/csv') error(415, 'Use application/json or text/csv'); const text = await event.request.text(); if (text.length > MAX_BYTES) error(413, 'Body too large'); const table = event.url.searchParams.get('table'); let payload; try { payload = type === 'text/csv' ? toPayload(parseCsv(text), table) : toPayload(JSON.parse(text), table); } catch (e) { return json( { ok: false, error: e instanceof Error ? e.message : 'Bad input' }, { status: 400 } ); } const { clean, errors } = validatePayload(payload); if (errors.length) return json({ ok: false, errors: errors.slice(0, 100) }, { status: 400 }); const rows = Object.fromEntries(Object.entries(clean).map(([t, r]) => [t, r.length])); if (event.url.searchParams.get('dry_run') === '1') return json({ ok: true, dryRun: true, rows }); try { return json({ ok: true, counts: await writeRows(db, clean) }); } catch (e) { return json( { ok: false, error: e instanceof Error ? e.message : 'Import failed' }, { status: 400 } ); } }; // Any other method: still 404 for non-owners (no 405 that would reveal the endpoint). export const fallback: RequestHandler = (event) => { requireOwner(event); error(405, 'Use POST'); };