DC-010: convert res.json({success:true,...}) → ok() in updates/notifications/tailscale
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled

Routes converted: updates.js (17), notifications.js (8), tailscale.js (12).
All 3 routes now receive ok() through the factory destructure; wired in app.js.

notifications.js: kept 2 res.json() calls for genuine partial-failure semantics
  - POST /test with ?provider=X: success reflects actual delivery
  - POST /send: success reflects per-provider results
  ok() hardcodes success:true and would lose that semantic; documented why.

tailscale.js: dropped unused 'fs' and unused 'NotFoundError' top-level imports
  (NotFoundError is still required() lazily inside the protect-service handler).
  Net change: 12 calls cleaned up, 2 lint warnings fixed.

750/750 tests still pass.
This commit is contained in:
Hermes
2026-06-25 14:29:27 -07:00
parent bf515e5415
commit c509f6ff10
4 changed files with 62 additions and 64 deletions
+20 -18
View File
@@ -9,9 +9,10 @@ const { ValidationError } = require('../errors');
* @param {Object} deps - Explicit dependencies
* @param {Object} deps.notification - Notification manager
* @param {Function} deps.asyncHandler - Async route handler wrapper
* @param {Function} deps.ok - Success response helper
* @returns {express.Router}
*/
module.exports = function({ notification, asyncHandler }) {
module.exports = function({ notification, asyncHandler, ok }) {
const router = express.Router();
// GET /config — Get notification configuration (sensitive data redacted)
@@ -44,7 +45,7 @@ module.exports = function({ notification, asyncHandler }) {
events: notificationConfig.events,
healthCheck: notificationConfig.healthCheck
};
res.json({ success: true, config: safeConfig });
ok(res, { config: safeConfig });
}, 'notifications-config-get'));
// POST /config — Update notification configuration
@@ -150,7 +151,7 @@ module.exports = function({ notification, asyncHandler }) {
}
await notification.saveConfig();
res.json({ success: true, message: 'Notification config updated' });
ok(res, { message: 'Notification config updated' });
}, 'notifications-config-update'));
// POST /test — Test notification delivery
@@ -176,11 +177,13 @@ module.exports = function({ notification, asyncHandler }) {
default:
throw new ValidationError('Unknown provider');
}
// result.success reflects actual delivery; keep that semantic by using
// res.json directly (ok() hardcodes success:true).
res.json({ success: result.success, provider, error: result.error });
} else {
// Test all enabled providers
const result = await notification.send('test', 'Test Notification', 'This is a test notification from DashCaddy.', 'info');
res.json({ success: true, ...result });
ok(res, { ...result });
}
}, 'notifications-test'));
@@ -190,11 +193,10 @@ module.exports = function({ notification, asyncHandler }) {
const paginationParams = parsePaginationParams(req.query);
if (paginationParams) {
const result = paginate(notificationHistory, paginationParams);
res.json({ success: true, history: result.data, total: notificationHistory.length, pagination: result.pagination });
ok(res, { history: result.data, total: notificationHistory.length, pagination: result.pagination });
} else {
const limit = parseInt(req.query.limit) || 50;
res.json({
success: true,
ok(res, {
history: notificationHistory.slice(0, limit),
total: notificationHistory.length
});
@@ -204,15 +206,14 @@ module.exports = function({ notification, asyncHandler }) {
// DELETE /history — Clear notification history
router.delete('/history', asyncHandler(async (req, res) => {
notification.clearHistory();
res.json({ success: true, message: 'Notification history cleared' });
ok(res, { message: 'Notification history cleared' });
}, 'notifications-history-clear'));
// POST /health-check — Manually trigger health check
router.post('/health-check', asyncHandler(async (req, res) => {
await notification.checkHealth();
const notificationConfig = notification.getConfig();
res.json({
success: true,
ok(res, {
lastCheck: notificationConfig.healthCheck.lastCheck,
containersMonitored: Object.keys(notification.getHealthState()).length
});
@@ -222,9 +223,8 @@ module.exports = function({ notification, asyncHandler }) {
router.get('/status', asyncHandler(async (req, res) => {
const notificationConfig = notification.getConfig();
const providers = notificationConfig.providers || {};
res.json({
success: true,
ok(res, {
enabled: notificationConfig.enabled,
providers: {
discord: providers.discord?.enabled && !!providers.discord?.webhookUrl,
@@ -244,18 +244,20 @@ module.exports = function({ notification, asyncHandler }) {
// POST /send — Manual test send (used by frontend "Send Test" button)
router.post('/send', asyncHandler(async (req, res) => {
const { event, data, type } = req.body;
if (!event) {
throw new ValidationError('Event type is required');
}
// Use 'test' as the event for manual sends
const result = await notification.send(event, data || {}, type || 'info');
res.json({
success: result.success,
// result.success reflects actual per-provider delivery; ok() hardcodes true,
// so use res.json to preserve the partial-failure semantic.
res.json({
success: result.success,
event,
results: result.results
results: result.results
});
}, 'notifications-send'));