claude went crazy
This commit is contained in:
114
server/routes.js
Normal file
114
server/routes.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Router } from 'express';
|
||||
import {
|
||||
getInstances, getInstance, getDistinctStacks,
|
||||
createInstance, updateInstance, deleteInstance,
|
||||
} from './db.js';
|
||||
|
||||
export const router = Router();
|
||||
|
||||
// ── Validation ────────────────────────────────────────────────────────────────
|
||||
|
||||
const VALID_STATES = ['deployed', 'testing', 'degraded'];
|
||||
const VALID_STACKS = ['production', 'development'];
|
||||
const SERVICE_KEYS = ['atlas', 'argus', 'semaphore', 'patchmon', 'tailscale', 'andromeda'];
|
||||
|
||||
function validate(body) {
|
||||
const errors = [];
|
||||
if (!body.name || typeof body.name !== 'string' || !body.name.trim())
|
||||
errors.push('name is required');
|
||||
if (!Number.isInteger(body.vmid) || body.vmid < 1)
|
||||
errors.push('vmid must be a positive integer');
|
||||
if (!VALID_STATES.includes(body.state))
|
||||
errors.push(`state must be one of: ${VALID_STATES.join(', ')}`);
|
||||
if (!VALID_STACKS.includes(body.stack))
|
||||
errors.push(`stack must be one of: ${VALID_STACKS.join(', ')}`);
|
||||
return errors;
|
||||
}
|
||||
|
||||
function normalise(body) {
|
||||
const row = {
|
||||
name: body.name.trim(),
|
||||
state: body.state,
|
||||
stack: body.stack,
|
||||
vmid: body.vmid,
|
||||
tailscale_ip: (body.tailscale_ip ?? '').trim(),
|
||||
hardware_acceleration: body.hardware_acceleration ? 1 : 0,
|
||||
};
|
||||
for (const svc of SERVICE_KEYS) row[svc] = body[svc] ? 1 : 0;
|
||||
return row;
|
||||
}
|
||||
|
||||
// ── Routes ────────────────────────────────────────────────────────────────────
|
||||
|
||||
// GET /api/instances/stacks — must be declared before /:vmid
|
||||
router.get('/instances/stacks', (_req, res) => {
|
||||
res.json(getDistinctStacks());
|
||||
});
|
||||
|
||||
// GET /api/instances
|
||||
router.get('/instances', (req, res) => {
|
||||
const { search, state, stack } = req.query;
|
||||
res.json(getInstances({ search, state, stack }));
|
||||
});
|
||||
|
||||
// GET /api/instances/:vmid
|
||||
router.get('/instances/:vmid', (req, res) => {
|
||||
const vmid = parseInt(req.params.vmid, 10);
|
||||
if (!vmid) return res.status(400).json({ error: 'invalid vmid' });
|
||||
|
||||
const instance = getInstance(vmid);
|
||||
if (!instance) return res.status(404).json({ error: 'instance not found' });
|
||||
|
||||
res.json(instance);
|
||||
});
|
||||
|
||||
// POST /api/instances
|
||||
router.post('/instances', (req, res) => {
|
||||
const errors = validate(req.body);
|
||||
if (errors.length) return res.status(400).json({ errors });
|
||||
|
||||
try {
|
||||
const data = normalise(req.body);
|
||||
createInstance(data);
|
||||
const created = getInstance(data.vmid);
|
||||
res.status(201).json(created);
|
||||
} catch (e) {
|
||||
if (e.message.includes('UNIQUE')) return res.status(409).json({ error: 'vmid already exists' });
|
||||
if (e.message.includes('CHECK')) return res.status(400).json({ error: 'invalid field value' });
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/instances/:vmid
|
||||
router.put('/instances/:vmid', (req, res) => {
|
||||
const vmid = parseInt(req.params.vmid, 10);
|
||||
if (!vmid) return res.status(400).json({ error: 'invalid vmid' });
|
||||
if (!getInstance(vmid)) return res.status(404).json({ error: 'instance not found' });
|
||||
|
||||
const errors = validate(req.body);
|
||||
if (errors.length) return res.status(400).json({ errors });
|
||||
|
||||
try {
|
||||
const data = normalise(req.body);
|
||||
updateInstance(vmid, data);
|
||||
res.json(getInstance(data.vmid));
|
||||
} catch (e) {
|
||||
if (e.message.includes('UNIQUE')) return res.status(409).json({ error: 'vmid already exists' });
|
||||
if (e.message.includes('CHECK')) return res.status(400).json({ error: 'invalid field value' });
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/instances/:vmid
|
||||
router.delete('/instances/:vmid', (req, res) => {
|
||||
const vmid = parseInt(req.params.vmid, 10);
|
||||
if (!vmid) return res.status(400).json({ error: 'invalid vmid' });
|
||||
|
||||
const instance = getInstance(vmid);
|
||||
if (!instance) return res.status(404).json({ error: 'instance not found' });
|
||||
if (instance.stack !== 'development')
|
||||
return res.status(422).json({ error: 'only development instances can be deleted' });
|
||||
|
||||
deleteInstance(vmid);
|
||||
res.status(204).end();
|
||||
});
|
||||
Reference in New Issue
Block a user