import { NextResponse } from 'next/server'; import { getDb } from '@/lib/db'; export const dynamic = 'force-dynamic'; export async function GET() { try { const db = await getDb(); const services = await db.all('SELECT id, name, url, created_at FROM monitored_services ORDER BY id ASC'); return NextResponse.json(services); } catch (error) { console.error('Services list error:', error); return NextResponse.json([], { status: 500 }); } } export async function POST(request: Request) { try { const { name, url } = await request.json(); if (!name || !url) { return NextResponse.json({ error: 'Name and URL are required' }, { status: 400 }); } // Basic URL validation try { new URL(url); } catch { return NextResponse.json({ error: 'Invalid URL format' }, { status: 400 }); } const db = await getDb(); const trimmedName = name.trim(); const trimmedUrl = url.trim(); await db.run('INSERT INTO monitored_services (name, url) VALUES (?, ?)', trimmedName, trimmedUrl); // Immediate ping so the service has data right away let initialStatus = 'down'; let initialLatency = 0; try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 5000); const start = performance.now(); const res = await fetch(trimmedUrl, { method: 'HEAD', signal: controller.signal, }); clearTimeout(timeout); initialLatency = Math.round(performance.now() - start); initialStatus = res.status < 500 ? 'up' : 'down'; } catch { initialStatus = 'down'; initialLatency = 0; } await db.run( 'INSERT INTO uptime_logs (service_name, url, status, latency, timestamp) VALUES (?, ?, ?, ?, ?)', trimmedName, trimmedUrl, initialStatus, initialLatency, new Date().toISOString() ); return NextResponse.json({ success: true, initialStatus, initialLatency }); } catch (error: unknown) { const msg = error instanceof Error ? error.message : 'Unknown error'; if (msg.includes('UNIQUE constraint')) { return NextResponse.json({ error: 'A service with that name already exists' }, { status: 409 }); } console.error('Service add error:', error); return NextResponse.json({ error: 'Failed to add service' }, { status: 500 }); } } export async function PATCH(request: Request) { try { const { id, name } = await request.json(); if (!id || !name) { return NextResponse.json({ error: 'ID and new name are required' }, { status: 400 }); } const db = await getDb(); const service = await db.get('SELECT name FROM monitored_services WHERE id = ?', id); if (!service) { return NextResponse.json({ error: 'Service not found' }, { status: 404 }); } const oldName = service.name; const newName = name.trim(); await db.run('UPDATE monitored_services SET name = ? WHERE id = ?', newName, id); // Update existing logs to match the new name await db.run('UPDATE uptime_logs SET service_name = ? WHERE service_name = ?', newName, oldName); return NextResponse.json({ success: true }); } catch (error: unknown) { const msg = error instanceof Error ? error.message : 'Unknown error'; if (msg.includes('UNIQUE constraint')) { return NextResponse.json({ error: 'A service with that name already exists' }, { status: 409 }); } console.error('Service rename error:', error); return NextResponse.json({ error: 'Failed to rename service' }, { status: 500 }); } } export async function DELETE(request: Request) { try { const { id } = await request.json(); if (!id) { return NextResponse.json({ error: 'Service ID is required' }, { status: 400 }); } const db = await getDb(); // Get service name before deleting so we can clean up logs const service = await db.get('SELECT name FROM monitored_services WHERE id = ?', id); if (!service) { return NextResponse.json({ error: 'Service not found' }, { status: 404 }); } await db.run('DELETE FROM monitored_services WHERE id = ?', id); await db.run('DELETE FROM uptime_logs WHERE service_name = ?', service.name); return NextResponse.json({ success: true }); } catch (error) { console.error('Service delete error:', error); return NextResponse.json({ error: 'Failed to delete service' }, { status: 500 }); } }