From 1c0d765182a7484926415fbfe36030c9f9085c47 Mon Sep 17 00:00:00 2001 From: Hermes Date: Wed, 10 Jun 2026 16:20:51 -0700 Subject: [PATCH] fix: app route path nesting (deploy/remove/templates), server.js fetchT import, lifetime license expiry, workflows path prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - routes/apps/index.js: mount sub-routers at '/' to avoid double-nesting (was /deploy/deploy, now /deploy) - server.js: add fetchT import for workflow engine init - license-manager.js: fix isExpired() for lifetime licenses (null expiresAt → always expired) - src/app.js: add '/workflows' path prefix to prevent requirePremium gating all routes - app-templates.js: fix 10 templates missing volumes/healthCheck - routes/apps/index.js: add e.stack to error logging for better debugging --- dashcaddy-api/license-manager.js | 3 +++ dashcaddy-api/routes/apps/index.js | 20 ++++++++++---------- dashcaddy-api/server.js | 3 +++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/dashcaddy-api/license-manager.js b/dashcaddy-api/license-manager.js index 341b743..2eea3b0 100644 --- a/dashcaddy-api/license-manager.js +++ b/dashcaddy-api/license-manager.js @@ -317,6 +317,9 @@ class LicenseManager { */ isExpired() { if (!this.activation) return true; + // Lifetime licenses never expire + if (this.activation.lifetime || this.activation.durationDays === 0) return false; + if (!this.activation.expiresAt) return false; // No expiry set = lifetime return Date.now() > new Date(this.activation.expiresAt).getTime(); } diff --git a/dashcaddy-api/routes/apps/index.js b/dashcaddy-api/routes/apps/index.js index aeaabef..52483df 100644 --- a/dashcaddy-api/routes/apps/index.js +++ b/dashcaddy-api/routes/apps/index.js @@ -46,20 +46,20 @@ module.exports = function(ctx) { // Mount sub-routes — pass full ctx so sub-routes can reference ctx.* properties const subCtx = Object.assign({}, ctx, { helpers }); - try { router.use('/deploy', initDeploy(subCtx)); } - catch(e) { (ctx.log || console).error('[apps] deploy routes init failed:', e.message); } + try { router.use('/', initDeploy(subCtx)); } + catch(e) { (ctx.log || console).error('[apps] deploy routes init failed:', e.message, e.stack); } - try { router.use('/remove', initRemoval(subCtx)); } - catch(e) { (ctx.log || console).error('[apps] removal routes init failed:', e.message); } + try { router.use('/', initRemoval(subCtx)); } + catch(e) { (ctx.log || console).error('[apps] removal routes init failed:', e.message, e.stack); } - try { router.use('/apps', initTemplates(subCtx)); } - catch(e) { (ctx.log || console).error('[apps] templates routes init failed:', e.message); } + try { router.use('/', initTemplates(subCtx)); } + catch(e) { (ctx.log || console).error('[apps] templates routes init failed:', e.message, e.stack); } - try { router.use('/restore', initRestore(Object.assign({}, subCtx, { backupManager: ctx.backupManager }))); } - catch(e) { (ctx.log || console).error('[apps] restore routes init failed:', e.message); } + try { router.use('/', initRestore(Object.assign({}, subCtx, { backupManager: ctx.backupManager }))); } + catch(e) { (ctx.log || console).error('[apps] restore routes init failed:', e.message, e.stack); } - try { router.use('/compose', initCompose(subCtx)); } - catch(e) { (ctx.log || console).error('[apps] compose routes init failed:', e.message); } + try { router.use('/', initCompose(subCtx)); } + catch(e) { (ctx.log || console).error('[apps] compose routes init failed:', e.message, e.stack); } return router; }; diff --git a/dashcaddy-api/server.js b/dashcaddy-api/server.js index 421b6e5..f3eb421 100644 --- a/dashcaddy-api/server.js +++ b/dashcaddy-api/server.js @@ -73,9 +73,12 @@ process.on('uncaughtException', (error) => { try { bundledWorkflows = require('./bundled-workflows'); } catch { /* optional */ } // Initialize workflow engine if bundled-workflows is available + // NOTE: createApp() already initializes the workflow engine in src/app.js + // This block is kept for backward compat with entry points that don't use createApp() let workflowEngine = null; if (bundledWorkflows) { try { + const { fetchT } = require('./src/utils/http'); const { WorkflowEngine } = bundledWorkflows; // Create a context with needed services const workflowCtx = {