diff --git a/CHANGELOG.md b/CHANGELOG.md index 007a48c..2031120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.7.27] - 2026-05-27 + +### Fixed + +- **Frontend Dashboard Serve Regression (Issue #57)** — Resolved a critical regression where the Vite-built frontend dashboard UI was not served. Consolidated Express configurations by migrating static files serving and SPA routing into the `createApp` factory in `server/app.js`. Cleaned up `server/index.js` to import and instantiate the app from the factory, successfully eliminating over 300 lines of duplicate route and middleware registrations, and ensuring alignment between development testing and production runtime configurations. + ## [1.7.26] - 2026-05-27 ### Fixed diff --git a/package-lock.json b/package-lock.json index b5c9722..1863455 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sofarr", - "version": "1.7.26", + "version": "1.7.27", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sofarr", - "version": "1.7.26", + "version": "1.7.27", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/package.json b/package.json index 6b9c4c7..390dbef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sofarr", - "version": "1.7.26", + "version": "1.7.27", "description": "A personal media download dashboard that shows your downloads 'so far' while you relax on the sofa waiting for your *arr services to finish", "main": "server/index.js", "scripts": { diff --git a/server/app.js b/server/app.js index 22637fc..9490b9f 100644 --- a/server/app.js +++ b/server/app.js @@ -15,6 +15,7 @@ const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); const YAML = require('yamljs'); const path = require('path'); +const fs = require('fs'); const { version } = require('../package.json'); const sabnzbdRoutes = require('./routes/sabnzbd'); @@ -132,7 +133,7 @@ function createApp({ skipRateLimits = false } = {}) { * version: * type: string * description: sofarr version - * example: "1.7.25" + * example: "1.7.27" * x-code-samples: * - lang: curl * label: cURL @@ -232,6 +233,44 @@ function createApp({ skipRateLimits = false } = {}) { app.use('/api/status', statusRoutes); app.use('/api/history', historyRoutes); + // --------------------------------------------------------------------------- + // Static files — served before API routes + // index.html is served manually so we can inject the CSP nonce + // --------------------------------------------------------------------------- + const PUBLIC_DIR = path.join(__dirname, '../public'); + const INDEX_HTML = path.join(PUBLIC_DIR, 'index.html'); + + // Serve all static assets (js, css, images, icons) except index.html. + // JS and CSS get no-cache so browsers revalidate on every load (ETag still + // avoids re-downloading unchanged files; only a deploy changes the ETag). + app.use(express.static(PUBLIC_DIR, { + index: false, + setHeaders(res, filePath) { + if (filePath.endsWith('.js') || filePath.endsWith('.css')) { + res.setHeader('Cache-Control', 'no-cache'); + } + } + })); + + // Serve index.html with CSP nonce injected into