const express = require('express'); const deployRoutes = require('./deploy'); const manageRoutes = require('./manage'); const { NotFoundError } = require('../../errors'); /** * 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 }; // 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 })); res.json({ success: true, 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}`); res.json({ success: true, 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; };