From 4e96c62708f7bec6b88dab42b19b98410b194ed8 Mon Sep 17 00:00:00 2001 From: Krystie Date: Sun, 29 Mar 2026 20:05:06 -0700 Subject: [PATCH] refactor(routes): Phase 3.1 - standardize updates.js (explicit deps) --- dashcaddy-api/routes/updates.js | 79 ++++++++++++++++++--------------- dashcaddy-api/src/app.js | 7 ++- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/dashcaddy-api/routes/updates.js b/dashcaddy-api/routes/updates.js index 2fa22b2..f055623 100644 --- a/dashcaddy-api/routes/updates.js +++ b/dashcaddy-api/routes/updates.js @@ -2,87 +2,96 @@ const express = require('express'); const { paginate, parsePaginationParams } = require('../pagination'); const { ValidationError } = require('../errors'); -module.exports = function(ctx) { +/** + * Updates route factory + * @param {Object} deps - Explicit dependencies + * @param {Object} deps.updateManager - Container update manager + * @param {Object} deps.selfUpdater - DashCaddy self-update manager + * @param {Function} deps.asyncHandler - Async route handler wrapper + * @param {Function} deps.logError - Error logging function + * @returns {express.Router} + */ +module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }) { const router = express.Router(); // ===== UPDATE MANAGEMENT ENDPOINTS ===== // Check for updates - router.post('/updates/check', ctx.asyncHandler(async (req, res) => { - await ctx.updateManager.checkForUpdates(); - const updates = ctx.updateManager.getAvailableUpdates(); + router.post('/updates/check', asyncHandler(async (req, res) => { + await updateManager.checkForUpdates(); + const updates = updateManager.getAvailableUpdates(); res.json({ success: true, updates, count: updates.length }); }, 'updates-check')); // Get available updates - router.get('/updates/available', ctx.asyncHandler(async (req, res) => { - const updates = ctx.updateManager.getAvailableUpdates(); + router.get('/updates/available', asyncHandler(async (req, res) => { + const updates = updateManager.getAvailableUpdates(); const paginationParams = parsePaginationParams(req.query); const result = paginate(updates, paginationParams); res.json({ success: true, updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) }); }, 'updates-available')); // Update a container - router.post('/updates/update/:containerId', ctx.asyncHandler(async (req, res) => { - const result = await ctx.updateManager.updateContainer(req.params.containerId, req.body); + router.post('/updates/update/:containerId', asyncHandler(async (req, res) => { + const result = await updateManager.updateContainer(req.params.containerId, req.body); res.json({ success: true, result }); }, 'updates-update')); // Rollback update - router.post('/updates/rollback/:containerId', ctx.asyncHandler(async (req, res) => { - await ctx.updateManager.rollbackUpdate(req.params.containerId); + router.post('/updates/rollback/:containerId', asyncHandler(async (req, res) => { + await updateManager.rollbackUpdate(req.params.containerId); res.json({ success: true, message: 'Rollback completed' }); }, 'updates-rollback')); // Get update history - router.get('/updates/history', ctx.asyncHandler(async (req, res) => { + router.get('/updates/history', asyncHandler(async (req, res) => { const paginationParams = parsePaginationParams(req.query); // When paginating, fetch all history so pagination can slice correctly const fetchLimit = paginationParams ? Number.MAX_SAFE_INTEGER : (parseInt(req.query.limit) || 50); - const history = ctx.updateManager.getHistory(fetchLimit); + const history = updateManager.getHistory(fetchLimit); const result = paginate(history, paginationParams); res.json({ success: true, history: result.data, ...(result.pagination && { pagination: result.pagination }) }); }, 'updates-history')); // Configure auto-update - router.post('/updates/auto-update/:containerId', ctx.asyncHandler(async (req, res) => { - ctx.updateManager.configureAutoUpdate(req.params.containerId, req.body); + router.post('/updates/auto-update/:containerId', asyncHandler(async (req, res) => { + updateManager.configureAutoUpdate(req.params.containerId, req.body); res.json({ success: true, message: 'Auto-update configured' }); }, 'updates-auto-update')); // Schedule update - router.post('/updates/schedule/:containerId', ctx.asyncHandler(async (req, res) => { + router.post('/updates/schedule/:containerId', asyncHandler(async (req, res) => { const { scheduledTime } = req.body; if (!scheduledTime) { throw new ValidationError('scheduledTime is required'); } - ctx.updateManager.scheduleUpdate(req.params.containerId, scheduledTime); + updateManager.scheduleUpdate(req.params.containerId, scheduledTime); res.json({ success: true, message: 'Update scheduled', scheduledTime }); }, 'updates-schedule')); // ===== DASHCADDY SELF-UPDATE ENDPOINTS ===== // Get current version - router.get('/system/version', ctx.asyncHandler(async (req, res) => { - const local = ctx.selfUpdater.getLocalVersion(); + router.get('/system/version', asyncHandler(async (req, res) => { + const local = selfUpdater.getLocalVersion(); res.json({ success: true, name: 'DashCaddy', version: local.version, commit: local.commit }); }, 'system-version')); // Check for DashCaddy update - router.get('/system/update-check', ctx.asyncHandler(async (req, res) => { - const result = await ctx.selfUpdater.checkForUpdate(); + router.get('/system/update-check', asyncHandler(async (req, res) => { + const result = await selfUpdater.checkForUpdate(); res.json({ success: true, ...result }); }, 'system-update-check')); // Apply available update - router.post('/system/update-apply', ctx.asyncHandler(async (req, res) => { - const check = await ctx.selfUpdater.checkForUpdate(); + router.post('/system/update-apply', asyncHandler(async (req, res) => { + const check = await selfUpdater.checkForUpdate(); if (!check.available) { return res.json({ success: true, message: 'Already up to date' }); } // Start async — container may restart - ctx.selfUpdater.applyUpdate(check.remote).catch(err => { - ctx.logError('self-update', err); + selfUpdater.applyUpdate(check.remote).catch(err => { + logError('self-update', err); }); res.json({ success: true, @@ -93,33 +102,33 @@ module.exports = function(ctx) { }, 'system-update-apply')); // Get update status - router.get('/system/update-status', ctx.asyncHandler(async (req, res) => { + router.get('/system/update-status', asyncHandler(async (req, res) => { res.json({ success: true, - status: ctx.selfUpdater.getStatus(), - lastCheck: ctx.selfUpdater.lastCheckTime, - lastResult: ctx.selfUpdater.lastCheckResult, + status: selfUpdater.getStatus(), + lastCheck: selfUpdater.lastCheckTime, + lastResult: selfUpdater.lastCheckResult, }); }, 'system-update-status')); // Get self-update history - router.get('/system/update-history', ctx.asyncHandler(async (req, res) => { - const history = ctx.selfUpdater.getUpdateHistory(); + router.get('/system/update-history', asyncHandler(async (req, res) => { + const history = selfUpdater.getUpdateHistory(); res.json({ success: true, history }); }, 'system-update-history')); // List rollback versions - router.get('/system/rollback-versions', ctx.asyncHandler(async (req, res) => { - const versions = ctx.selfUpdater.getAvailableRollbacks(); + router.get('/system/rollback-versions', asyncHandler(async (req, res) => { + const versions = selfUpdater.getAvailableRollbacks(); res.json({ success: true, versions }); }, 'system-rollback-versions')); // Rollback to a previous version - router.post('/system/rollback', ctx.asyncHandler(async (req, res) => { + router.post('/system/rollback', asyncHandler(async (req, res) => { const { version } = req.body; if (!version) throw new ValidationError('version is required'); - ctx.selfUpdater.rollbackToVersion(version).catch(err => { - ctx.logError('self-rollback', err); + selfUpdater.rollbackToVersion(version).catch(err => { + logError('self-rollback', err); }); res.json({ success: true, message: `Rollback to ${version} initiated` }); }, 'system-rollback')); diff --git a/dashcaddy-api/src/app.js b/dashcaddy-api/src/app.js index ca45e4a..dfb7cdf 100644 --- a/dashcaddy-api/src/app.js +++ b/dashcaddy-api/src/app.js @@ -339,7 +339,12 @@ async function createApp() { docker: ctx.docker, asyncHandler: ctx.asyncHandler })); - apiRouter.use(updatesRoutes(ctx)); + apiRouter.use(updatesRoutes({ + updateManager: ctx.updateManager, + selfUpdater: ctx.selfUpdater, + asyncHandler: ctx.asyncHandler, + logError: ctx.logError + })); apiRouter.use('/tailscale', tailscaleRoutes(ctx)); apiRouter.use(sitesRoutes(ctx)); apiRouter.use(credentialsRoutes({