/** * @file HTTP routes for dashboard upstream-update detection, plus the one * self-applying path: POST /apply fast-forwards, rebuilds, and restarts the * process on the user's explicit click (see `server/lib/update-check.js`'s * `applyUpdate` and `server/lib/self-restart.js`). Everywhere else, the * dashboard only ever prints a command for the user to run themselves. * @author Nguyễn Ngọc Trí Vĩ */ const { Router } = require("express"); const { getUpdatesStatus, applyUpdate } = require("../lib/update-check"); const { scheduleRestart } = require("../lib/self-restart"); const router = Router(); router.get("/status", async (_req, res) => { try { const status = await getUpdatesStatus(); res.json(status); } catch (err) { res.status(500).json({ error: { code: "UPDATE_STATUS_FAILED", message: err.message || String(err) }, }); } }); router.post("/check", async (_req, res) => { try { const status = await getUpdatesStatus(); try { const { broadcast } = require("../websocket"); broadcast("update_status", status); } catch { // WS not initialized (e.g. in isolated tests) — safe to ignore. } res.json(status); } catch (err) { res.status(500).json({ error: { code: "UPDATE_CHECK_FAILED", message: err.message || String(err) }, }); } }); router.post("/apply", async (_req, res) => { try { const result = await applyUpdate(); if (!result.applied) { res.status(409).json({ ...result, error: { code: "UPDATE_NOT_APPLICABLE", message: result.reason === "up_to_date" ? "Already up to date." : "Current branch can't be fast-forwarded automatically.", }, }); return; } res.json(result); try { const { broadcast } = require("../websocket"); broadcast("update_status", { ...result, update_available: false }); } catch { // WS not initialized (e.g. in isolated tests) — safe to ignore. } // After the response above, restart onto the freshly-built code. setImmediate(() => scheduleRestart()); } catch (err) { res.status(500).json({ error: { code: "UPDATE_APPLY_FAILED", message: err.message || String(err) }, }); } }); module.exports = router;