import { NextRequest, NextResponse } from 'next/server'; import { getSetting } from '@/lib/db'; import { applyBackup, fetchBackup, fetchBackupList } from '@/lib/backup-restore'; /** * Restore-from-master for the settings page. * * The browser talks to this route and this route talks to the master with the * machine's own stored master_dashboard_url + master_backup_token, so the * token never reaches the browser. * * GET — the available backups, for the picker. * POST { id } — pull that backup and apply it, adopting its identity. * The process must be restarted afterwards; the response says so. */ function config(): { masterUrl: string; token: string } | NextResponse { const masterUrl = getSetting('master_dashboard_url'); const token = getSetting('master_backup_token'); if (!masterUrl) return NextResponse.json({ error: 'master_dashboard_url is not set' }, { status: 400 }); if (!token) return NextResponse.json({ error: 'master_backup_token is not set' }, { status: 400 }); return { masterUrl, token }; } export async function GET() { const cfg = config(); if (cfg instanceof NextResponse) return cfg; try { const backups = await fetchBackupList(cfg.masterUrl, cfg.token); return NextResponse.json({ backups }); } catch (err) { const error = err instanceof Error ? err.message : String(err); return NextResponse.json({ error }, { status: 502 }); } } export async function POST(req: NextRequest) { const cfg = config(); if (cfg instanceof NextResponse) return cfg; let id = ''; try { const body = await req.json(); id = typeof body?.id === 'string' ? body.id.trim() : ''; } catch { /* falls through to the check below */ } if (!id) return NextResponse.json({ error: 'id is required' }, { status: 400 }); try { const payload = await fetchBackup(cfg.masterUrl, cfg.token, id); const restored = applyBackup(payload); return NextResponse.json({ ok: true, restored, savedAt: payload.savedAt, adopted: { name: payload.settings.instance_name ?? '', id: payload.settings.instance_id ?? '', }, // Live platform clients, the master link's hello and the proxy all // predate the restore — a restart is the only honest way in. restartRequired: true, }); } catch (err) { const error = err instanceof Error ? err.message : String(err); return NextResponse.json({ error }, { status: 502 }); } }