const express = require('express'); const router = express.Router(); const fs = require('fs'); const path = require('path'); const HISTORY_PATH = path.join(__dirname, '..', 'HISTORY.md'); let pkg; try { pkg = require('../package.json'); } catch { pkg = { version: '0.1.0' }; } /** * Parses HISTORY.md and returns the latest version's structured notes. * Reads from disk on every call so the file can be updated without restart. */ function parseHistory() { if (!fs.existsSync(HISTORY_PATH)) { return { version: '0.1', notes: [] }; } const content = fs.readFileSync(HISTORY_PATH, 'utf8'); // Match first (topmost) version block const blockMatch = content.match(/## (v[\d.]+)\n([\s\S]*?)(?=\n## v|\s*$)/); if (!blockMatch) return { version: '0.1', notes: [] }; const version = blockMatch[1].slice(1); // strip the 'v' const body = blockMatch[2]; // Parse ### Added / Changed / Fixed / Removed sections const notes = []; const sectionRe = /### (Added|Changed|Fixed|Removed|Deprecated|Security)\n([\s\S]*?)(?=###|\s*$)/g; let m; while ((m = sectionRe.exec(body)) !== null) { const category = m[1]; const items = m[2] .split('\n') .filter(l => l.trim().startsWith('- ')) .map(l => ({ category, text: l.trim().slice(2).trim() })); notes.push(...items); } return { version, notes }; } // GET /api/version — version always comes from package.json; notes from HISTORY.md router.get('/', (req, res) => { const { notes } = parseHistory(); res.json({ version: pkg.version, notes }); }); // GET /api/version/history router.get('/history', (req, res) => { try { if (!fs.existsSync(HISTORY_PATH)) { return res.status(404).json({ error: 'Release history not found', version: pkg.version, history: '', updated_at: null, }); } const history = fs.readFileSync(HISTORY_PATH, 'utf8'); let updatedAt = null; try { updatedAt = fs.statSync(HISTORY_PATH).mtime.toISOString(); } catch { updatedAt = null; } res.json({ version: pkg.version, history, updated_at: updatedAt, }); } catch (err) { res.status(500).json({ error: 'Failed to read release history' }); } }); // GET /api/version/update-status — public, returns cached update check (no force-refresh) const { checkForUpdates } = require('../services/updateCheckService'); router.get('/update-status', async (req, res) => { try { res.json(await checkForUpdates(false)); } catch (err) { res.json({ current_version: pkg.version, latest_version: null, up_to_date: null, has_update: false, error: 'Update check unavailable' }); } }); module.exports = router;