Files
dashcaddy/dashcaddy-api/routes/recipes/index.js
T
Hermes 53680c4c74
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
v1.13.4: Standardize all route responses to use response helpers
Convert ~160 raw res.json()/res.status().json() calls across 32+ files
to use centralized helpers from src/utils/responses.js (ok, errorResponse,
successMessage, notFound, validationError, forbidden, unauthorized, conflict).

No behavior changes — response shapes are identical. Future schema changes
(e.g., requestId envelope) only need to update one module.

Fix error vs errorResponse signature mismatch in routes/health.js CA cert
endpoint where error(res, message, statusCode) was being called with
errorResponse(res, statusCode, message, extras) argument order.

Files changed: middleware.js, csrf-protection.js, error-handler.js,
license-manager.js, src/app.js, and 27 route files.

Test suite: 755 pass / 4 pre-existing failures (services credential tests).
2026-06-11 00:48:13 -07:00

77 lines
2.7 KiB
JavaScript

const express = require('express');
const deployRoutes = require('./deploy');
const manageRoutes = require('./manage');
const { NotFoundError } = require('../../errors');
const { ok } = require('../../src/utils/responses');
/**
* Recipes routes aggregator
* @param {Object} ctx - Application context (for backward compatibility)
* @returns {express.Router}
*/
module.exports = function(ctx) {
const router = express.Router();
const deps = {
docker: ctx.docker,
credentialManager: ctx.credentialManager,
servicesStateManager: ctx.servicesStateManager,
asyncHandler: ctx.asyncHandler,
errorResponse: ctx.errorResponse,
log: ctx.log,
notification: ctx.notification,
buildDomain: ctx.buildDomain,
caddy: ctx.caddy,
addServiceToConfig: ctx.addServiceToConfig,
APP_TEMPLATES: ctx.APP_TEMPLATES,
siteConfig: ctx.siteConfig
};
// All recipe routes require premium license
router.use(ctx.licenseManager.requirePremium('recipes'));
// GET /api/recipes/templates — list all recipe templates
router.get('/templates', deps.asyncHandler(async (req, res) => {
const { RECIPE_TEMPLATES, RECIPE_CATEGORIES } = require('../../recipe-templates');
const templates = Object.entries(RECIPE_TEMPLATES).map(([id, recipe]) => ({
id,
name: recipe.name,
description: recipe.description,
icon: recipe.icon,
category: recipe.category,
type: 'recipe',
difficulty: recipe.difficulty,
popularity: recipe.popularity,
componentCount: recipe.components.length,
requiredCount: recipe.components.filter(c => c.required).length,
optionalCount: recipe.components.filter(c => !c.required).length,
components: recipe.components.map(c => ({
id: c.id,
role: c.role,
required: c.required,
internal: c.internal || false,
templateRef: c.templateRef || null,
note: c.note || null
})),
setupInstructions: recipe.setupInstructions
}));
ok(res, { templates, categories: RECIPE_CATEGORIES });
}, 'recipe-templates'));
// GET /api/recipes/templates/:recipeId — get single recipe template detail
router.get('/templates/:recipeId', deps.asyncHandler(async (req, res) => {
const { RECIPE_TEMPLATES } = require('../../recipe-templates');
const recipe = RECIPE_TEMPLATES[req.params.recipeId];
if (!recipe) throw new NotFoundError(`Recipe template ${req.params.recipeId}`);
ok(res, { recipe: { id: req.params.recipeId, ...recipe } });
}, 'recipe-template-detail'));
// Mount deploy and manage sub-routes — pass full ctx for sub-routes that reference ctx.*
router.use(deployRoutes(ctx));
router.use(manageRoutes(ctx));
return router;
};