From 6f621067b91aeaf9411a9632dcd11560c53968f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Br=C3=BCckner?= Date: Mon, 8 Jun 2026 14:37:33 +0200 Subject: [PATCH] fix(server): register SPA catch-all last so /api GET routes are reachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The static/SPA fallback (app.get('*')) was registered before the Caddy routes, so every GET /api/caddy/* request was swallowed by the catch-all and returned index.html instead of JSON. POST/PUT/DELETE still worked because app.get('*') only matches GET — which is why adding routes worked but the list was always empty. Move the static block to just before app.listen, and add Cache-Control: no-store on /api so stale HTML can't be served via 304. --- server.ts | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/server.ts b/server.ts index fffbf9b..ddab153 100644 --- a/server.ts +++ b/server.ts @@ -160,6 +160,13 @@ async function startServer() { app.use(express.json()); + // API responses must never be cached by the browser — otherwise a stale + // (or HTML fallback) response can get served from cache via a 304. + app.use('/api', (_req, res, next) => { + res.set('Cache-Control', 'no-store'); + next(); + }); + // ------------------------------------------------------------- // AUTH API // ------------------------------------------------------------- @@ -871,23 +878,6 @@ async function startServer() { } ); - // ------------------------------------------------------------- - // VITE / STATIC SERVING - // ------------------------------------------------------------- - if (process.env.NODE_ENV !== 'production') { - const vite = await createViteServer({ - server: { middlewareMode: true }, - appType: 'spa', - }); - app.use(vite.middlewares); - } else { - const distPath = path.join(process.cwd(), 'dist'); - app.use(express.static(distPath)); - app.get('*', (_req, res) => { - res.sendFile(path.join(distPath, 'index.html')); - }); - } - // ------------------------------------------------------------- // CYCLIC CHECKMK STATUS SYNC // Looks up each device by IP address in CheckMK's host_config collection, @@ -1244,6 +1234,24 @@ async function startServer() { pushCaddyConfig().catch(err => console.warn('[Caddy] Could not push config on startup:', err.message)); + // ------------------------------------------------------------- + // VITE / STATIC SERVING — registered LAST so the SPA catch-all ('*') + // never shadows the /api routes registered above it. + // ------------------------------------------------------------- + if (process.env.NODE_ENV !== 'production') { + const vite = await createViteServer({ + server: { middlewareMode: true }, + appType: 'spa', + }); + app.use(vite.middlewares); + } else { + const distPath = path.join(process.cwd(), 'dist'); + app.use(express.static(distPath)); + app.get('*', (_req, res) => { + res.sendFile(path.join(distPath, 'index.html')); + }); + } + app.listen(PORT, '0.0.0.0', () => { console.log(`[Server] Core Server running at http://0.0.0.0:${PORT}`); });