const express = require("express"); const { writeCoalescer } = require("@ignis/server-core"); const settings = require("../settings"); const bootstrapRoutes = require("./bootstrap"); const router = express.Router(); const NUMBER_KEYS = [ "contentCacheBytes", "inputCacheBytes", "inputCacheTtlMs", "writeCoalesceMs", "maxBodyBytes", ]; const LIST_KEYS = ["proxyAllowlist", "wsOrigins"]; function validate(body) { const clean = {}; for (const key of NUMBER_KEYS) { if (body[key] === undefined) { continue; } const n = body[key]; if (!Number.isInteger(n) || n < 0) { throw new Error(`${key} must be a non-negative integer`); } if (key === "maxBodyBytes" && (n < 1 || n > settings.MAX_BODY_BACKSTOP)) { throw new Error( `maxBodyBytes must be between 1 and ${settings.MAX_BODY_BACKSTOP}`, ); } clean[key] = n; } for (const key of LIST_KEYS) { if (body[key] === undefined) { continue; } const list = body[key]; if ( !Array.isArray(list) || list.some((v) => typeof v !== "string" || !v.trim()) ) { throw new Error(`${key} must be an array of non-empty strings`); } clean[key] = list.map((v) => v.trim()); } return clean; } function applySettings(effective, req) { writeCoalescer.configure({ writeCoalesceMs: effective.writeCoalesceMs }); const wss = req.app.get("wss"); if (wss && typeof wss.setOriginAllowlist === "function") { wss.setOriginAllowlist(effective.wsOrigins); } } router.get("/", (req, res) => { res.json(settings.getAll()); }); router.post("/", (req, res) => { let clean; try { clean = validate(req.body || {}); } catch (e) { return res.status(400).json({ error: e.message }); } const effective = settings.update(clean); applySettings(effective, req); // Cache sizes ride in the bootstrap response; clear it so the next page load picks up new values. bootstrapRoutes.invalidateAll(); res.json(effective); }); module.exports = router;