import { createRouter } from '../../create-router'; import { mkdir } from 'node:fs/promises'; import { join } from 'node:path'; import { DATA_PATH } from '@@/data-path'; // Bug reports land on disk and nowhere else. // // There was a Discord webhook here until 2026-08-13, behind DISCORD_BUG_REPORT_WEBHOOK. It was a // personal notification channel living in deployment config, on a self-hosted platform whose owner is // the only person filing reports — and it was never in .env.example, so the setup script wrote a // variable nothing documented. // // Nothing is lost from the report itself: the disk write below always happened first, and the webhook // was only a ping about it. export const bugReportRouter = createRouter(); bugReportRouter.post('/', async (ctx) => { const user = ctx.get('user'); const body = ctx.get('body') as Record; const description = body.description as string | undefined; const contextRaw = body.context as string | undefined; const screenshot = body.screenshot as File | undefined; if (!description?.trim()) { return ctx.text('Description is required', 400); } const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const uuid = crypto.randomUUID().slice(0, 8); const dirName = `${timestamp}-${uuid}`; const reportDir = join(DATA_PATH, 'bug-reports', dirName); await mkdir(reportDir, { recursive: true }); const context = contextRaw ? JSON.parse(contextRaw) : null; const report = { description: description.trim(), context, reporter: { id: user.id, email: user.email, name: user.name }, createdAt: new Date().toISOString(), }; await Bun.write(join(reportDir, 'report.json'), JSON.stringify(report, null, 2)); if (screenshot instanceof File) { await Bun.write(join(reportDir, 'screenshot.png'), Buffer.from(await screenshot.arrayBuffer())); } return ctx.json({ ok: true, id: dirName }); });