@intranefr/superbackend 1.4.4 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -0
- package/README.md +11 -0
- package/index.js +39 -1
- package/package.json +11 -3
- package/public/sdk/ui-components.iife.js +191 -0
- package/sdk/ui-components/browser/src/index.js +228 -0
- package/src/admin/endpointRegistry.js +120 -0
- package/src/controllers/admin.controller.js +111 -5
- package/src/controllers/adminBlockDefinitions.controller.js +127 -0
- package/src/controllers/adminBlockDefinitionsAi.controller.js +54 -0
- package/src/controllers/adminCache.controller.js +342 -0
- package/src/controllers/adminContextBlockDefinitions.controller.js +141 -0
- package/src/controllers/adminCrons.controller.js +388 -0
- package/src/controllers/adminDbBrowser.controller.js +124 -0
- package/src/controllers/adminEjsVirtual.controller.js +13 -3
- package/src/controllers/adminHeadless.controller.js +91 -2
- package/src/controllers/adminHealthChecks.controller.js +570 -0
- package/src/controllers/adminI18n.controller.js +51 -29
- package/src/controllers/adminLlm.controller.js +126 -2
- package/src/controllers/adminPages.controller.js +720 -0
- package/src/controllers/adminPagesContextBlocksAi.controller.js +54 -0
- package/src/controllers/adminProxy.controller.js +113 -0
- package/src/controllers/adminRateLimits.controller.js +138 -0
- package/src/controllers/adminRbac.controller.js +803 -0
- package/src/controllers/adminScripts.controller.js +320 -0
- package/src/controllers/adminSeoConfig.controller.js +71 -48
- package/src/controllers/adminTerminals.controller.js +39 -0
- package/src/controllers/adminUiComponents.controller.js +315 -0
- package/src/controllers/adminUiComponentsAi.controller.js +34 -0
- package/src/controllers/blogAdmin.controller.js +279 -0
- package/src/controllers/blogAiAdmin.controller.js +224 -0
- package/src/controllers/blogAutomationAdmin.controller.js +141 -0
- package/src/controllers/blogInternal.controller.js +26 -0
- package/src/controllers/blogPublic.controller.js +89 -0
- package/src/controllers/fileManager.controller.js +190 -0
- package/src/controllers/fileManagerStoragePolicy.controller.js +23 -0
- package/src/controllers/healthChecksPublic.controller.js +196 -0
- package/src/controllers/metrics.controller.js +64 -4
- package/src/controllers/orgAdmin.controller.js +366 -0
- package/src/controllers/uiComponentsPublic.controller.js +118 -0
- package/src/middleware/auth.js +7 -0
- package/src/middleware/internalCronAuth.js +29 -0
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +879 -56
- package/src/models/BlockDefinition.js +27 -0
- package/src/models/BlogAutomationLock.js +14 -0
- package/src/models/BlogAutomationRun.js +39 -0
- package/src/models/BlogPost.js +42 -0
- package/src/models/CacheEntry.js +26 -0
- package/src/models/ConsoleEntry.js +32 -0
- package/src/models/ConsoleLog.js +23 -0
- package/src/models/ContextBlockDefinition.js +33 -0
- package/src/models/CronExecution.js +47 -0
- package/src/models/CronJob.js +70 -0
- package/src/models/ExternalDbConnection.js +49 -0
- package/src/models/FileEntry.js +22 -0
- package/src/models/HeadlessModelDefinition.js +10 -0
- package/src/models/HealthAutoHealAttempt.js +57 -0
- package/src/models/HealthCheck.js +132 -0
- package/src/models/HealthCheckRun.js +51 -0
- package/src/models/HealthIncident.js +49 -0
- package/src/models/Page.js +95 -0
- package/src/models/PageCollection.js +42 -0
- package/src/models/ProxyEntry.js +66 -0
- package/src/models/RateLimitCounter.js +19 -0
- package/src/models/RateLimitMetricBucket.js +20 -0
- package/src/models/RbacGrant.js +25 -0
- package/src/models/RbacGroup.js +16 -0
- package/src/models/RbacGroupMember.js +13 -0
- package/src/models/RbacGroupRole.js +13 -0
- package/src/models/RbacRole.js +25 -0
- package/src/models/RbacUserRole.js +13 -0
- package/src/models/ScriptDefinition.js +42 -0
- package/src/models/ScriptRun.js +22 -0
- package/src/models/UiComponent.js +29 -0
- package/src/models/UiComponentProject.js +26 -0
- package/src/models/UiComponentProjectComponent.js +18 -0
- package/src/routes/admin.routes.js +1 -0
- package/src/routes/adminBlog.routes.js +21 -0
- package/src/routes/adminBlogAi.routes.js +16 -0
- package/src/routes/adminBlogAutomation.routes.js +27 -0
- package/src/routes/adminCache.routes.js +20 -0
- package/src/routes/adminConsoleManager.routes.js +302 -0
- package/src/routes/adminCrons.routes.js +25 -0
- package/src/routes/adminDbBrowser.routes.js +65 -0
- package/src/routes/adminEjsVirtual.routes.js +2 -1
- package/src/routes/adminHeadless.routes.js +8 -1
- package/src/routes/adminHealthChecks.routes.js +28 -0
- package/src/routes/adminI18n.routes.js +4 -3
- package/src/routes/adminLlm.routes.js +4 -2
- package/src/routes/adminPages.routes.js +55 -0
- package/src/routes/adminProxy.routes.js +15 -0
- package/src/routes/adminRateLimits.routes.js +17 -0
- package/src/routes/adminRbac.routes.js +38 -0
- package/src/routes/adminScripts.routes.js +21 -0
- package/src/routes/adminSeoConfig.routes.js +5 -4
- package/src/routes/adminTerminals.routes.js +13 -0
- package/src/routes/adminUiComponents.routes.js +30 -0
- package/src/routes/blogInternal.routes.js +14 -0
- package/src/routes/blogPublic.routes.js +9 -0
- package/src/routes/fileManager.routes.js +62 -0
- package/src/routes/fileManagerStoragePolicy.routes.js +9 -0
- package/src/routes/healthChecksPublic.routes.js +9 -0
- package/src/routes/log.routes.js +43 -60
- package/src/routes/metrics.routes.js +4 -2
- package/src/routes/orgAdmin.routes.js +6 -0
- package/src/routes/pages.routes.js +123 -0
- package/src/routes/proxy.routes.js +46 -0
- package/src/routes/rbac.routes.js +47 -0
- package/src/routes/uiComponentsPublic.routes.js +9 -0
- package/src/routes/webhook.routes.js +2 -1
- package/src/routes/workflows.routes.js +4 -0
- package/src/services/blockDefinitionsAi.service.js +247 -0
- package/src/services/blog.service.js +99 -0
- package/src/services/blogAutomation.service.js +978 -0
- package/src/services/blogCronsBootstrap.service.js +184 -0
- package/src/services/blogPublishing.service.js +58 -0
- package/src/services/cacheLayer.service.js +696 -0
- package/src/services/consoleManager.service.js +700 -0
- package/src/services/consoleOverride.service.js +6 -1
- package/src/services/cronScheduler.service.js +350 -0
- package/src/services/dbBrowser.service.js +536 -0
- package/src/services/ejsVirtual.service.js +102 -32
- package/src/services/fileManager.service.js +475 -0
- package/src/services/fileManagerStoragePolicy.service.js +285 -0
- package/src/services/headlessExternalModels.service.js +292 -0
- package/src/services/headlessModels.service.js +26 -6
- package/src/services/healthChecks.service.js +650 -0
- package/src/services/healthChecksBootstrap.service.js +109 -0
- package/src/services/healthChecksScheduler.service.js +106 -0
- package/src/services/llmDefaults.service.js +190 -0
- package/src/services/migrationAssets/s3.js +2 -2
- package/src/services/pages.service.js +602 -0
- package/src/services/pagesContext.service.js +331 -0
- package/src/services/pagesContextBlocksAi.service.js +349 -0
- package/src/services/proxy.service.js +535 -0
- package/src/services/rateLimiter.service.js +623 -0
- package/src/services/rbac.service.js +212 -0
- package/src/services/scriptsRunner.service.js +259 -0
- package/src/services/terminals.service.js +152 -0
- package/src/services/terminalsWs.service.js +100 -0
- package/src/services/uiComponentsAi.service.js +299 -0
- package/src/services/uiComponentsCrypto.service.js +39 -0
- package/src/services/workflow.service.js +23 -8
- package/src/utils/orgRoles.js +14 -0
- package/src/utils/rbac/engine.js +60 -0
- package/src/utils/rbac/rightsRegistry.js +29 -0
- package/views/admin-blog-automation.ejs +877 -0
- package/views/admin-blog-edit.ejs +542 -0
- package/views/admin-blog.ejs +399 -0
- package/views/admin-cache.ejs +681 -0
- package/views/admin-console-manager.ejs +680 -0
- package/views/admin-crons.ejs +645 -0
- package/views/admin-db-browser.ejs +445 -0
- package/views/admin-ejs-virtual.ejs +16 -10
- package/views/admin-file-manager.ejs +942 -0
- package/views/admin-headless.ejs +294 -24
- package/views/admin-health-checks.ejs +725 -0
- package/views/admin-i18n.ejs +59 -5
- package/views/admin-llm.ejs +99 -1
- package/views/admin-organizations.ejs +528 -10
- package/views/admin-pages.ejs +2424 -0
- package/views/admin-proxy.ejs +491 -0
- package/views/admin-rate-limiter.ejs +625 -0
- package/views/admin-rbac.ejs +1331 -0
- package/views/admin-scripts.ejs +497 -0
- package/views/admin-seo-config.ejs +61 -7
- package/views/admin-terminals.ejs +328 -0
- package/views/admin-ui-components.ejs +741 -0
- package/views/admin-users.ejs +261 -4
- package/views/admin-workflows.ejs +7 -7
- package/views/file-manager.ejs +866 -0
- package/views/pages/blocks/contact.ejs +27 -0
- package/views/pages/blocks/cta.ejs +18 -0
- package/views/pages/blocks/faq.ejs +20 -0
- package/views/pages/blocks/features.ejs +19 -0
- package/views/pages/blocks/hero.ejs +13 -0
- package/views/pages/blocks/html.ejs +5 -0
- package/views/pages/blocks/image.ejs +14 -0
- package/views/pages/blocks/testimonials.ejs +26 -0
- package/views/pages/blocks/text.ejs +10 -0
- package/views/pages/layouts/default.ejs +51 -0
- package/views/pages/layouts/minimal.ejs +42 -0
- package/views/pages/layouts/sidebar.ejs +54 -0
- package/views/pages/partials/footer.ejs +13 -0
- package/views/pages/partials/header.ejs +12 -0
- package/views/pages/partials/sidebar.ejs +8 -0
- package/views/pages/runtime/page.ejs +10 -0
- package/views/pages/templates/article.ejs +20 -0
- package/views/pages/templates/default.ejs +12 -0
- package/views/pages/templates/landing.ejs +14 -0
- package/views/pages/templates/listing.ejs +15 -0
- package/views/partials/admin-image-upload-modal.ejs +221 -0
- package/views/partials/dashboard/nav-items.ejs +14 -0
- package/views/partials/llm-provider-model-picker.ejs +183 -0
package/src/middleware.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
const consoleOverride = require("./services/consoleOverride.service");
|
|
2
|
+
const consoleManager = require("./services/consoleManager.service");
|
|
3
|
+
|
|
4
|
+
// Initialize console override service early to capture all logs
|
|
5
|
+
// Avoid keeping timers/streams alive during Jest runs.
|
|
6
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
7
|
+
consoleOverride.init()
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
const express = require("express");
|
|
2
11
|
const path = require("path");
|
|
3
12
|
const mongoose = require("mongoose");
|
|
@@ -6,17 +15,54 @@ const fs = require("fs");
|
|
|
6
15
|
const ejs = require("ejs");
|
|
7
16
|
const { basicAuth } = require("./middleware/auth");
|
|
8
17
|
const endpointRegistry = require("./admin/endpointRegistry");
|
|
9
|
-
const {
|
|
10
|
-
|
|
18
|
+
const {
|
|
19
|
+
createFeatureFlagsEjsMiddleware,
|
|
20
|
+
} = require("./services/featureFlags.service");
|
|
21
|
+
const globalSettingsService = require("./services/globalSettings.service");
|
|
22
|
+
const cronScheduler = require("./services/cronScheduler.service");
|
|
23
|
+
const healthChecksScheduler = require("./services/healthChecksScheduler.service");
|
|
24
|
+
const healthChecksBootstrap = require("./services/healthChecksBootstrap.service");
|
|
25
|
+
const blogCronsBootstrap = require("./services/blogCronsBootstrap.service");
|
|
11
26
|
const {
|
|
12
27
|
hookConsoleError,
|
|
13
28
|
setupProcessHandlers,
|
|
14
29
|
expressErrorMiddleware,
|
|
15
30
|
requestIdMiddleware,
|
|
16
31
|
} = require("./middleware/errorCapture");
|
|
32
|
+
const rateLimiter = require("./services/rateLimiter.service");
|
|
17
33
|
|
|
18
34
|
let errorCaptureInitialized = false;
|
|
19
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Check if console manager should be enabled based on environment variable and global settings
|
|
38
|
+
* Priority: Environment Variable > Global Settings > Default (true)
|
|
39
|
+
* @returns {Promise<boolean>} Whether console manager should be enabled
|
|
40
|
+
*/
|
|
41
|
+
async function isConsoleManagerEnabled() {
|
|
42
|
+
// Environment variable takes highest priority
|
|
43
|
+
const envEnabled = process.env.CONSOLE_MANAGER_ENABLED;
|
|
44
|
+
if (envEnabled !== undefined) {
|
|
45
|
+
const enabled = String(envEnabled).toLowerCase() !== 'false';
|
|
46
|
+
console.log(`[Console Manager] Environment variable CONSOLE_MANAGER_ENABLED=${envEnabled}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
47
|
+
return enabled;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check global settings if environment variable not set
|
|
51
|
+
try {
|
|
52
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
53
|
+
"CONSOLE_MANAGER_ENABLED",
|
|
54
|
+
"true"
|
|
55
|
+
);
|
|
56
|
+
const enabled = String(enabledRaw) === "true";
|
|
57
|
+
console.log(`[Console Manager] Global setting CONSOLE_MANAGER_ENABLED=${enabledRaw}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
58
|
+
return enabled;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("[Console Manager] Error loading global setting:", error);
|
|
61
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
62
|
+
return true; // Fallback to enabled on error
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
20
66
|
/**
|
|
21
67
|
* Creates and configures the SaaS backend middleware
|
|
22
68
|
* @param {Object} options - Configuration options
|
|
@@ -30,9 +76,50 @@ let errorCaptureInitialized = false;
|
|
|
30
76
|
function createMiddleware(options = {}) {
|
|
31
77
|
const router = express.Router();
|
|
32
78
|
const adminPath = options.adminPath || "/admin";
|
|
79
|
+
const pagesPrefix = options.pagesPrefix || "/";
|
|
80
|
+
|
|
81
|
+
const normalizeBasePath = (value) => {
|
|
82
|
+
const v = String(value || "").trim();
|
|
83
|
+
if (!v) return "/files";
|
|
84
|
+
return v.startsWith("/") ? v : `/${v}`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const fileManagerPublicConfig = {
|
|
88
|
+
enabled: false,
|
|
89
|
+
basePath: "/files",
|
|
90
|
+
loaded: false,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Restart-required behavior: we load settings once and keep the values in memory.
|
|
94
|
+
(async () => {
|
|
95
|
+
try {
|
|
96
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
97
|
+
"FILE_MANAGER_ENABLED",
|
|
98
|
+
"false",
|
|
99
|
+
);
|
|
100
|
+
const basePathRaw = await globalSettingsService.getSettingValue(
|
|
101
|
+
"FILE_MANAGER_BASE_PATH",
|
|
102
|
+
"/files",
|
|
103
|
+
);
|
|
33
104
|
|
|
34
|
-
|
|
35
|
-
|
|
105
|
+
fileManagerPublicConfig.enabled = String(enabledRaw) === "true";
|
|
106
|
+
fileManagerPublicConfig.basePath = normalizeBasePath(basePathRaw);
|
|
107
|
+
fileManagerPublicConfig.loaded = true;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error("Error loading File Manager public config:", error);
|
|
110
|
+
fileManagerPublicConfig.loaded = true;
|
|
111
|
+
}
|
|
112
|
+
})();
|
|
113
|
+
|
|
114
|
+
// Expose adminPath, pagesPrefix and WS attachment helper
|
|
115
|
+
router.adminPath = adminPath;
|
|
116
|
+
router.pagesPrefix = pagesPrefix;
|
|
117
|
+
router.attachWs = (server) => {
|
|
118
|
+
const {
|
|
119
|
+
attachTerminalWebsocketServer,
|
|
120
|
+
} = require("./services/terminalsWs.service");
|
|
121
|
+
attachTerminalWebsocketServer(server, { basePathPrefix: adminPath });
|
|
122
|
+
};
|
|
36
123
|
|
|
37
124
|
if (!errorCaptureInitialized) {
|
|
38
125
|
errorCaptureInitialized = true;
|
|
@@ -40,9 +127,14 @@ function createMiddleware(options = {}) {
|
|
|
40
127
|
setupProcessHandlers();
|
|
41
128
|
}
|
|
42
129
|
|
|
130
|
+
// Console manager will be initialized after database connection
|
|
131
|
+
|
|
43
132
|
// Database connection
|
|
44
133
|
const mongoUri =
|
|
45
|
-
options.mongodbUri ||
|
|
134
|
+
options.mongodbUri ||
|
|
135
|
+
options.dbConnection ||
|
|
136
|
+
process.env.MONGODB_URI ||
|
|
137
|
+
process.env.MONGO_URI;
|
|
46
138
|
|
|
47
139
|
if (!mongoUri && mongoose.connection.readyState !== 1) {
|
|
48
140
|
console.warn(
|
|
@@ -53,23 +145,132 @@ function createMiddleware(options = {}) {
|
|
|
53
145
|
serverSelectionTimeoutMS: 5000,
|
|
54
146
|
maxPoolSize: 10,
|
|
55
147
|
};
|
|
56
|
-
|
|
148
|
+
|
|
57
149
|
// Return a promise that resolves when connection is established
|
|
58
150
|
const connectionPromise = mongoose
|
|
59
151
|
.connect(mongoUri, connectionOptions)
|
|
60
|
-
.then(() => {
|
|
152
|
+
.then(async () => {
|
|
61
153
|
console.log("✅ Middleware: Connected to MongoDB");
|
|
154
|
+
// Start cron scheduler after DB connection
|
|
155
|
+
await cronScheduler.start();
|
|
156
|
+
await healthChecksScheduler.start();
|
|
157
|
+
await healthChecksBootstrap.bootstrap();
|
|
158
|
+
await blogCronsBootstrap.bootstrap();
|
|
159
|
+
|
|
160
|
+
// Initialize console manager AFTER database is connected
|
|
161
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
162
|
+
const consoleManagerEnabled = await isConsoleManagerEnabled();
|
|
163
|
+
if (consoleManagerEnabled) {
|
|
164
|
+
consoleManager.init();
|
|
165
|
+
console.log("[Console Manager] Initialized");
|
|
166
|
+
} else {
|
|
167
|
+
console.log("[Console Manager] Disabled - console methods not overridden");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
62
171
|
return true;
|
|
63
172
|
})
|
|
64
173
|
.catch((err) => {
|
|
65
174
|
console.error("❌ Middleware: MongoDB connection error:", err);
|
|
66
175
|
return false;
|
|
67
176
|
});
|
|
68
|
-
|
|
177
|
+
|
|
178
|
+
router.get(`${adminPath}/health-checks`, basicAuth, (req, res) => {
|
|
179
|
+
const templatePath = path.join(
|
|
180
|
+
__dirname,
|
|
181
|
+
"..",
|
|
182
|
+
"views",
|
|
183
|
+
"admin-health-checks.ejs",
|
|
184
|
+
);
|
|
185
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
186
|
+
if (err) {
|
|
187
|
+
console.error("Error reading template:", err);
|
|
188
|
+
return res.status(500).send("Error loading page");
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const html = ejs.render(
|
|
192
|
+
template,
|
|
193
|
+
{
|
|
194
|
+
baseUrl: req.baseUrl,
|
|
195
|
+
adminPath,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
filename: templatePath,
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
res.send(html);
|
|
202
|
+
} catch (renderErr) {
|
|
203
|
+
console.error("Error rendering template:", renderErr);
|
|
204
|
+
res.status(500).send("Error rendering page");
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
router.get(`${adminPath}/console-manager`, basicAuth, (req, res) => {
|
|
210
|
+
const templatePath = path.join(
|
|
211
|
+
__dirname,
|
|
212
|
+
"..",
|
|
213
|
+
"views",
|
|
214
|
+
"admin-console-manager.ejs",
|
|
215
|
+
);
|
|
216
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
217
|
+
if (err) {
|
|
218
|
+
console.error("Error reading template:", err);
|
|
219
|
+
return res.status(500).send("Error loading page");
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const html = ejs.render(
|
|
223
|
+
template,
|
|
224
|
+
{
|
|
225
|
+
baseUrl: req.baseUrl,
|
|
226
|
+
adminPath,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
filename: templatePath,
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
res.send(html);
|
|
233
|
+
} catch (renderErr) {
|
|
234
|
+
console.error("Error rendering template:", renderErr);
|
|
235
|
+
res.status(500).send("Error rendering page");
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
69
240
|
// Store the promise so it can be awaited if needed
|
|
70
241
|
router.connectionPromise = connectionPromise;
|
|
71
242
|
} else if (mongoose.connection.readyState === 1) {
|
|
72
243
|
console.log("✅ Middleware: Using existing MongoDB connection");
|
|
244
|
+
// Start cron scheduler for existing connection
|
|
245
|
+
cronScheduler.start().catch((err) => {
|
|
246
|
+
console.error("Failed to start cron scheduler:", err);
|
|
247
|
+
});
|
|
248
|
+
healthChecksScheduler.start().catch((err) => {
|
|
249
|
+
console.error("Failed to start health checks scheduler:", err);
|
|
250
|
+
});
|
|
251
|
+
healthChecksBootstrap.bootstrap().catch((err) => {
|
|
252
|
+
console.error("Failed to bootstrap health checks:", err);
|
|
253
|
+
});
|
|
254
|
+
blogCronsBootstrap.bootstrap().catch((err) => {
|
|
255
|
+
console.error("Failed to bootstrap blog crons:", err);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Initialize console manager AFTER database is already connected
|
|
259
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
260
|
+
isConsoleManagerEnabled().then(consoleManagerEnabled => {
|
|
261
|
+
if (consoleManagerEnabled) {
|
|
262
|
+
consoleManager.init();
|
|
263
|
+
console.log("[Console Manager] Initialized");
|
|
264
|
+
} else {
|
|
265
|
+
console.log("[Console Manager] Disabled - console methods not overridden");
|
|
266
|
+
}
|
|
267
|
+
}).catch(error => {
|
|
268
|
+
console.error("[Console Manager] Error checking enabled status:", error);
|
|
269
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
270
|
+
consoleManager.init();
|
|
271
|
+
console.log("[Console Manager] Initialized (fallback)");
|
|
272
|
+
});
|
|
273
|
+
}
|
|
73
274
|
}
|
|
74
275
|
|
|
75
276
|
// CORS configuration
|
|
@@ -131,6 +332,12 @@ function createMiddleware(options = {}) {
|
|
|
131
332
|
webhookHandler,
|
|
132
333
|
);
|
|
133
334
|
|
|
335
|
+
router.use(
|
|
336
|
+
"/proxy",
|
|
337
|
+
express.raw({ type: "*/*", limit: "10mb" }),
|
|
338
|
+
require("./routes/proxy.routes"),
|
|
339
|
+
);
|
|
340
|
+
|
|
134
341
|
// Regular JSON parsing for other routes (skip if parent app already handles it)
|
|
135
342
|
if (!options.skipBodyParser) {
|
|
136
343
|
router.use(express.json());
|
|
@@ -139,9 +346,17 @@ function createMiddleware(options = {}) {
|
|
|
139
346
|
|
|
140
347
|
router.use(requestIdMiddleware);
|
|
141
348
|
|
|
349
|
+
router.use("/api", rateLimiter.limit("globalApiLimiter"));
|
|
350
|
+
|
|
142
351
|
// Serve public static files (e.g. /og/og-default.png)
|
|
143
352
|
router.use(express.static(path.join(__dirname, "..", "public")));
|
|
144
353
|
|
|
354
|
+
// Serve browser SDK bundles
|
|
355
|
+
router.use(
|
|
356
|
+
"/public/sdk",
|
|
357
|
+
express.static(path.join(__dirname, "..", "public", "sdk")),
|
|
358
|
+
);
|
|
359
|
+
|
|
145
360
|
// Serve static files for admin views
|
|
146
361
|
router.use(
|
|
147
362
|
`${adminPath}/assets`,
|
|
@@ -151,6 +366,53 @@ function createMiddleware(options = {}) {
|
|
|
151
366
|
// EJS locals: feature flags for server-rendered pages
|
|
152
367
|
router.use(createFeatureFlagsEjsMiddleware());
|
|
153
368
|
|
|
369
|
+
// Public File Manager SPA (gated by global settings; restart required)
|
|
370
|
+
router.get("*", (req, res, next) => {
|
|
371
|
+
try {
|
|
372
|
+
if (!fileManagerPublicConfig.enabled) return next();
|
|
373
|
+
|
|
374
|
+
const basePath = fileManagerPublicConfig.basePath || "/files";
|
|
375
|
+
const reqPath = req.path;
|
|
376
|
+
const matches =
|
|
377
|
+
reqPath === basePath ||
|
|
378
|
+
reqPath === `${basePath}/` ||
|
|
379
|
+
reqPath.startsWith(`${basePath}/`);
|
|
380
|
+
|
|
381
|
+
if (!matches) return next();
|
|
382
|
+
if (req.method !== "GET") return next();
|
|
383
|
+
|
|
384
|
+
const templatePath = path.join(
|
|
385
|
+
__dirname,
|
|
386
|
+
"..",
|
|
387
|
+
"views",
|
|
388
|
+
"file-manager.ejs",
|
|
389
|
+
);
|
|
390
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
391
|
+
if (err) {
|
|
392
|
+
console.error("Error reading template:", err);
|
|
393
|
+
return res.status(500).send("Error loading page");
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const html = ejs.render(
|
|
397
|
+
template,
|
|
398
|
+
{
|
|
399
|
+
baseUrl: req.baseUrl,
|
|
400
|
+
fileManagerBasePath: basePath,
|
|
401
|
+
},
|
|
402
|
+
{ filename: templatePath },
|
|
403
|
+
);
|
|
404
|
+
res.send(html);
|
|
405
|
+
} catch (renderErr) {
|
|
406
|
+
console.error("Error rendering template:", renderErr);
|
|
407
|
+
res.status(500).send("Error rendering page");
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error("Error serving File Manager SPA:", error);
|
|
412
|
+
next();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
154
416
|
// API Routes
|
|
155
417
|
router.use("/api/auth", require("./routes/auth.routes"));
|
|
156
418
|
router.use("/api/billing", require("./routes/billing.routes"));
|
|
@@ -164,22 +426,212 @@ function createMiddleware(options = {}) {
|
|
|
164
426
|
);
|
|
165
427
|
router.use("/api/admin/orgs", require("./routes/orgAdmin.routes"));
|
|
166
428
|
router.use("/api/admin/users", require("./routes/userAdmin.routes"));
|
|
167
|
-
router.use("/api/admin/
|
|
429
|
+
router.use("/api/admin/rbac", require("./routes/adminRbac.routes"));
|
|
430
|
+
router.use(
|
|
431
|
+
"/api/admin/notifications",
|
|
432
|
+
require("./routes/notificationAdmin.routes"),
|
|
433
|
+
);
|
|
168
434
|
router.use("/api/admin/stripe", require("./routes/stripeAdmin.routes"));
|
|
169
|
-
|
|
435
|
+
|
|
170
436
|
// Stats Routes
|
|
171
437
|
const adminStatsController = require("./controllers/adminStats.controller");
|
|
172
|
-
router.get(
|
|
173
|
-
|
|
438
|
+
router.get(
|
|
439
|
+
"/api/admin/stats/overview",
|
|
440
|
+
basicAuth,
|
|
441
|
+
adminStatsController.getOverviewStats,
|
|
442
|
+
);
|
|
443
|
+
|
|
174
444
|
router.get(`${adminPath}/stats/dashboard-home`, basicAuth, (req, res) => {
|
|
175
|
-
const templatePath = path.join(
|
|
445
|
+
const templatePath = path.join(
|
|
446
|
+
__dirname,
|
|
447
|
+
"..",
|
|
448
|
+
"views",
|
|
449
|
+
"admin-dashboard-home.ejs",
|
|
450
|
+
);
|
|
451
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
452
|
+
if (err) {
|
|
453
|
+
console.error("Error reading template:", err);
|
|
454
|
+
return res.status(500).send("Error loading page");
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const html = ejs.render(
|
|
458
|
+
template,
|
|
459
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
460
|
+
{ filename: templatePath },
|
|
461
|
+
);
|
|
462
|
+
res.send(html);
|
|
463
|
+
} catch (renderErr) {
|
|
464
|
+
console.error("Error rendering template:", renderErr);
|
|
465
|
+
res.status(500).send("Error rendering page");
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
router.get(`${adminPath}/rbac`, basicAuth, (req, res) => {
|
|
471
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-rbac.ejs");
|
|
472
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
473
|
+
if (err) {
|
|
474
|
+
console.error("Error reading template:", err);
|
|
475
|
+
return res.status(500).send("Error loading page");
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
const html = ejs.render(
|
|
479
|
+
template,
|
|
480
|
+
{
|
|
481
|
+
baseUrl: req.baseUrl,
|
|
482
|
+
adminPath,
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
filename: templatePath,
|
|
486
|
+
},
|
|
487
|
+
);
|
|
488
|
+
res.send(html);
|
|
489
|
+
} catch (renderErr) {
|
|
490
|
+
console.error("Error rendering template:", renderErr);
|
|
491
|
+
res.status(500).send("Error rendering page");
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
router.get(`${adminPath}/terminals`, basicAuth, (req, res) => {
|
|
497
|
+
const templatePath = path.join(
|
|
498
|
+
__dirname,
|
|
499
|
+
"..",
|
|
500
|
+
"views",
|
|
501
|
+
"admin-terminals.ejs",
|
|
502
|
+
);
|
|
503
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
504
|
+
if (err) {
|
|
505
|
+
console.error("Error reading template:", err);
|
|
506
|
+
return res.status(500).send("Error loading page");
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
const html = ejs.render(
|
|
510
|
+
template,
|
|
511
|
+
{
|
|
512
|
+
baseUrl: req.baseUrl,
|
|
513
|
+
adminPath,
|
|
514
|
+
endpointRegistry,
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
filename: templatePath,
|
|
518
|
+
},
|
|
519
|
+
);
|
|
520
|
+
res.send(html);
|
|
521
|
+
} catch (renderErr) {
|
|
522
|
+
console.error("Error rendering template:", renderErr);
|
|
523
|
+
res.status(500).send("Error rendering page");
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
router.get(`${adminPath}/scripts`, basicAuth, (req, res) => {
|
|
529
|
+
const templatePath = path.join(
|
|
530
|
+
__dirname,
|
|
531
|
+
"..",
|
|
532
|
+
"views",
|
|
533
|
+
"admin-scripts.ejs",
|
|
534
|
+
);
|
|
535
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
536
|
+
if (err) {
|
|
537
|
+
console.error("Error reading template:", err);
|
|
538
|
+
return res.status(500).send("Error loading page");
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
const html = ejs.render(
|
|
542
|
+
template,
|
|
543
|
+
{
|
|
544
|
+
baseUrl: req.baseUrl,
|
|
545
|
+
adminPath,
|
|
546
|
+
endpointRegistry,
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
filename: templatePath,
|
|
550
|
+
},
|
|
551
|
+
);
|
|
552
|
+
res.send(html);
|
|
553
|
+
} catch (renderErr) {
|
|
554
|
+
console.error("Error rendering template:", renderErr);
|
|
555
|
+
res.status(500).send("Error rendering page");
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
router.get(`${adminPath}/crons`, basicAuth, (req, res) => {
|
|
561
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-crons.ejs");
|
|
176
562
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
177
563
|
if (err) {
|
|
178
564
|
console.error("Error reading template:", err);
|
|
179
565
|
return res.status(500).send("Error loading page");
|
|
180
566
|
}
|
|
181
567
|
try {
|
|
182
|
-
const html = ejs.render(
|
|
568
|
+
const html = ejs.render(
|
|
569
|
+
template,
|
|
570
|
+
{
|
|
571
|
+
baseUrl: req.baseUrl,
|
|
572
|
+
adminPath,
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
filename: templatePath,
|
|
576
|
+
},
|
|
577
|
+
);
|
|
578
|
+
res.send(html);
|
|
579
|
+
} catch (renderErr) {
|
|
580
|
+
console.error("Error rendering template:", renderErr);
|
|
581
|
+
res.status(500).send("Error rendering page");
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
router.get(`${adminPath}/cache`, basicAuth, (req, res) => {
|
|
587
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-cache.ejs");
|
|
588
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
589
|
+
if (err) {
|
|
590
|
+
console.error("Error reading template:", err);
|
|
591
|
+
return res.status(500).send("Error loading page");
|
|
592
|
+
}
|
|
593
|
+
try {
|
|
594
|
+
const html = ejs.render(
|
|
595
|
+
template,
|
|
596
|
+
{
|
|
597
|
+
baseUrl: req.baseUrl,
|
|
598
|
+
adminPath,
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
filename: templatePath,
|
|
602
|
+
},
|
|
603
|
+
);
|
|
604
|
+
res.send(html);
|
|
605
|
+
} catch (renderErr) {
|
|
606
|
+
console.error("Error rendering template:", renderErr);
|
|
607
|
+
res.status(500).send("Error rendering page");
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
router.get(`${adminPath}/db-browser`, basicAuth, (req, res) => {
|
|
613
|
+
const templatePath = path.join(
|
|
614
|
+
__dirname,
|
|
615
|
+
"..",
|
|
616
|
+
"views",
|
|
617
|
+
"admin-db-browser.ejs",
|
|
618
|
+
);
|
|
619
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
620
|
+
if (err) {
|
|
621
|
+
console.error("Error reading template:", err);
|
|
622
|
+
return res.status(500).send("Error loading page");
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
const html = ejs.render(
|
|
626
|
+
template,
|
|
627
|
+
{
|
|
628
|
+
baseUrl: req.baseUrl,
|
|
629
|
+
adminPath,
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
filename: templatePath,
|
|
633
|
+
},
|
|
634
|
+
);
|
|
183
635
|
res.send(html);
|
|
184
636
|
} catch (renderErr) {
|
|
185
637
|
console.error("Error rendering template:", renderErr);
|
|
@@ -198,23 +650,63 @@ function createMiddleware(options = {}) {
|
|
|
198
650
|
"/api/admin/json-configs",
|
|
199
651
|
require("./routes/adminJsonConfigs.routes"),
|
|
200
652
|
);
|
|
653
|
+
router.use(
|
|
654
|
+
"/api/admin/rate-limits",
|
|
655
|
+
require("./routes/adminRateLimits.routes"),
|
|
656
|
+
);
|
|
657
|
+
router.use("/api/admin/proxy", require("./routes/adminProxy.routes"));
|
|
201
658
|
router.use(
|
|
202
659
|
"/api/admin/seo-config",
|
|
203
660
|
require("./routes/adminSeoConfig.routes"),
|
|
204
661
|
);
|
|
205
662
|
router.use("/api/admin/i18n", require("./routes/adminI18n.routes"));
|
|
206
663
|
router.use("/api/admin/headless", require("./routes/adminHeadless.routes"));
|
|
664
|
+
router.use("/api/admin/scripts", require("./routes/adminScripts.routes"));
|
|
665
|
+
router.use("/api/admin/crons", require("./routes/adminCrons.routes"));
|
|
666
|
+
router.use(
|
|
667
|
+
"/api/admin/health-checks",
|
|
668
|
+
require("./routes/adminHealthChecks.routes"),
|
|
669
|
+
);
|
|
670
|
+
router.use("/api/admin/cache", require("./routes/adminCache.routes"));
|
|
671
|
+
router.use(
|
|
672
|
+
"/api/admin/console-manager",
|
|
673
|
+
require("./routes/adminConsoleManager.routes"),
|
|
674
|
+
);
|
|
675
|
+
router.use(
|
|
676
|
+
"/api/admin/db-browser",
|
|
677
|
+
require("./routes/adminDbBrowser.routes"),
|
|
678
|
+
);
|
|
679
|
+
router.use("/api/admin/terminals", require("./routes/adminTerminals.routes"));
|
|
207
680
|
router.use("/api/admin/assets", require("./routes/adminAssets.routes"));
|
|
208
681
|
router.use(
|
|
209
682
|
"/api/admin/upload-namespaces",
|
|
210
683
|
require("./routes/adminUploadNamespaces.routes"),
|
|
211
684
|
);
|
|
685
|
+
router.use(
|
|
686
|
+
"/api/admin/ui-components",
|
|
687
|
+
require("./routes/adminUiComponents.routes"),
|
|
688
|
+
);
|
|
212
689
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
213
|
-
router.use(
|
|
214
|
-
|
|
690
|
+
router.use(
|
|
691
|
+
"/api/admin/errors",
|
|
692
|
+
basicAuth,
|
|
693
|
+
require("./routes/adminErrors.routes"),
|
|
694
|
+
);
|
|
695
|
+
router.use(
|
|
696
|
+
"/api/admin/audit",
|
|
697
|
+
basicAuth,
|
|
698
|
+
require("./routes/adminAudit.routes"),
|
|
699
|
+
);
|
|
215
700
|
router.use("/api/admin/llm", require("./routes/adminLlm.routes"));
|
|
216
|
-
router.use(
|
|
217
|
-
|
|
701
|
+
router.use(
|
|
702
|
+
"/api/admin/ejs-virtual",
|
|
703
|
+
require("./routes/adminEjsVirtual.routes"),
|
|
704
|
+
);
|
|
705
|
+
router.use("/api/admin/pages", require("./routes/adminPages.routes"));
|
|
706
|
+
router.use("/api/admin", require("./routes/adminBlog.routes"));
|
|
707
|
+
router.use("/api/admin", require("./routes/adminBlogAi.routes"));
|
|
708
|
+
router.use("/api/admin", require("./routes/adminBlogAutomation.routes"));
|
|
709
|
+
router.use("/api/admin/workflows", basicAuth, require("./routes/workflows.routes"));
|
|
218
710
|
router.use("/w", require("./routes/workflowWebhook.routes"));
|
|
219
711
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
220
712
|
router.use("/api/settings", require("./routes/globalSettings.routes"));
|
|
@@ -229,20 +721,104 @@ function createMiddleware(options = {}) {
|
|
|
229
721
|
router.use("/api/invites", require("./routes/invite.routes"));
|
|
230
722
|
router.use("/api/log", require("./routes/log.routes"));
|
|
231
723
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
724
|
+
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
725
|
+
router.use("/api/rbac", require("./routes/rbac.routes"));
|
|
726
|
+
router.use("/api/file-manager", require("./routes/fileManager.routes"));
|
|
727
|
+
|
|
728
|
+
// Public blog APIs (headless)
|
|
729
|
+
router.use("/api", require("./routes/blogPublic.routes"));
|
|
730
|
+
|
|
731
|
+
// Internal blog endpoints (used by HTTP CronJobs)
|
|
732
|
+
router.use("/api/internal", require("./routes/blogInternal.routes"));
|
|
733
|
+
|
|
734
|
+
// Public health checks status (gated by global setting)
|
|
735
|
+
router.use(
|
|
736
|
+
"/api/health-checks",
|
|
737
|
+
require("./routes/healthChecksPublic.routes"),
|
|
738
|
+
);
|
|
232
739
|
|
|
233
740
|
// Public assets proxy
|
|
234
741
|
router.use("/public/assets", require("./routes/publicAssets.routes"));
|
|
235
742
|
|
|
236
|
-
// Admin dashboard (polished view)
|
|
237
|
-
router.get(adminPath, basicAuth, (req, res) => {
|
|
238
|
-
const templatePath = path.join(
|
|
743
|
+
// Admin dashboard (polished view)
|
|
744
|
+
router.get(adminPath, basicAuth, (req, res) => {
|
|
745
|
+
const templatePath = path.join(
|
|
746
|
+
__dirname,
|
|
747
|
+
"..",
|
|
748
|
+
"views",
|
|
749
|
+
"admin-dashboard.ejs",
|
|
750
|
+
);
|
|
751
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
752
|
+
if (err) {
|
|
753
|
+
console.error("Error reading template:", err);
|
|
754
|
+
return res.status(500).send("Error loading page");
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
const html = ejs.render(
|
|
758
|
+
template,
|
|
759
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
760
|
+
{ filename: templatePath },
|
|
761
|
+
);
|
|
762
|
+
res.send(html);
|
|
763
|
+
} catch (renderErr) {
|
|
764
|
+
console.error("Error rendering template:", renderErr);
|
|
765
|
+
res.status(500).send("Error rendering page");
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
// Admin technical API test page (protected by basic auth)
|
|
771
|
+
router.get(`${adminPath}/api/test`, basicAuth, (req, res) => {
|
|
772
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-test.ejs");
|
|
773
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
774
|
+
if (err) {
|
|
775
|
+
console.error("Error reading template:", err);
|
|
776
|
+
return res.status(500).send("Error loading page");
|
|
777
|
+
}
|
|
778
|
+
try {
|
|
779
|
+
const html = ejs.render(
|
|
780
|
+
template,
|
|
781
|
+
{
|
|
782
|
+
baseUrl: req.baseUrl,
|
|
783
|
+
adminPath,
|
|
784
|
+
endpointRegistry,
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
filename: templatePath,
|
|
788
|
+
},
|
|
789
|
+
);
|
|
790
|
+
res.send(html);
|
|
791
|
+
} catch (renderErr) {
|
|
792
|
+
console.error("Error rendering template:", renderErr);
|
|
793
|
+
res.status(500).send("Error rendering page");
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
router.get(`${adminPath}/migration`, basicAuth, (req, res) => {
|
|
799
|
+
const templatePath = path.join(
|
|
800
|
+
__dirname,
|
|
801
|
+
"..",
|
|
802
|
+
"views",
|
|
803
|
+
"admin-migration.ejs",
|
|
804
|
+
);
|
|
239
805
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
240
806
|
if (err) {
|
|
241
807
|
console.error("Error reading template:", err);
|
|
242
808
|
return res.status(500).send("Error loading page");
|
|
243
809
|
}
|
|
244
810
|
try {
|
|
245
|
-
const html = ejs.render(
|
|
811
|
+
const html = ejs.render(
|
|
812
|
+
template,
|
|
813
|
+
{
|
|
814
|
+
baseUrl: req.baseUrl,
|
|
815
|
+
adminPath,
|
|
816
|
+
endpointRegistry,
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
filename: templatePath,
|
|
820
|
+
},
|
|
821
|
+
);
|
|
246
822
|
res.send(html);
|
|
247
823
|
} catch (renderErr) {
|
|
248
824
|
console.error("Error rendering template:", renderErr);
|
|
@@ -251,9 +827,9 @@ function createMiddleware(options = {}) {
|
|
|
251
827
|
});
|
|
252
828
|
});
|
|
253
829
|
|
|
254
|
-
// Admin
|
|
255
|
-
router.get(`${adminPath}/
|
|
256
|
-
const templatePath = path.join(__dirname, "..", "views", "admin-
|
|
830
|
+
// Admin LLM/AI page (protected by basic auth)
|
|
831
|
+
router.get(`${adminPath}/admin-llm`, basicAuth, (req, res) => {
|
|
832
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-llm.ejs");
|
|
257
833
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
258
834
|
if (err) {
|
|
259
835
|
console.error("Error reading template:", err);
|
|
@@ -265,7 +841,6 @@ function createMiddleware(options = {}) {
|
|
|
265
841
|
{
|
|
266
842
|
baseUrl: req.baseUrl,
|
|
267
843
|
adminPath,
|
|
268
|
-
endpointRegistry,
|
|
269
844
|
},
|
|
270
845
|
{
|
|
271
846
|
filename: templatePath,
|
|
@@ -279,8 +854,34 @@ function createMiddleware(options = {}) {
|
|
|
279
854
|
});
|
|
280
855
|
});
|
|
281
856
|
|
|
282
|
-
router.get(`${adminPath}/
|
|
283
|
-
const templatePath = path.join(
|
|
857
|
+
router.get(`${adminPath}/workflows/:id`, basicAuth, (req, res) => {
|
|
858
|
+
const templatePath = path.join(
|
|
859
|
+
__dirname,
|
|
860
|
+
"..",
|
|
861
|
+
"views",
|
|
862
|
+
"admin-workflows.ejs",
|
|
863
|
+
);
|
|
864
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
865
|
+
if (err) {
|
|
866
|
+
console.error("Error reading template:", err);
|
|
867
|
+
return res.status(500).send("Error loading page");
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const html = ejs.render(
|
|
871
|
+
template,
|
|
872
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
873
|
+
{ filename: templatePath },
|
|
874
|
+
);
|
|
875
|
+
res.send(html);
|
|
876
|
+
} catch (renderErr) {
|
|
877
|
+
console.error("Error rendering template:", renderErr);
|
|
878
|
+
res.status(500).send("Error rendering page");
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
router.get(`${adminPath}/pages`, basicAuth, (req, res) => {
|
|
884
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-pages.ejs");
|
|
284
885
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
285
886
|
if (err) {
|
|
286
887
|
console.error("Error reading template:", err);
|
|
@@ -292,7 +893,6 @@ function createMiddleware(options = {}) {
|
|
|
292
893
|
{
|
|
293
894
|
baseUrl: req.baseUrl,
|
|
294
895
|
adminPath,
|
|
295
|
-
endpointRegistry,
|
|
296
896
|
},
|
|
297
897
|
{
|
|
298
898
|
filename: templatePath,
|
|
@@ -306,13 +906,85 @@ function createMiddleware(options = {}) {
|
|
|
306
906
|
});
|
|
307
907
|
});
|
|
308
908
|
|
|
309
|
-
|
|
310
|
-
|
|
909
|
+
router.get(`${adminPath}/blog`, basicAuth, (req, res) => {
|
|
910
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-blog.ejs");
|
|
911
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
912
|
+
if (err) {
|
|
913
|
+
console.error("Error reading template:", err);
|
|
914
|
+
return res.status(500).send("Error loading page");
|
|
915
|
+
}
|
|
916
|
+
try {
|
|
917
|
+
const html = ejs.render(
|
|
918
|
+
template,
|
|
919
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
920
|
+
{ filename: templatePath },
|
|
921
|
+
);
|
|
922
|
+
res.send(html);
|
|
923
|
+
} catch (renderErr) {
|
|
924
|
+
console.error("Error rendering template:", renderErr);
|
|
925
|
+
res.status(500).send("Error rendering page");
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
router.get(`${adminPath}/blog-automation`, basicAuth, (req, res) => {
|
|
931
|
+
const templatePath = path.join(
|
|
932
|
+
__dirname,
|
|
933
|
+
"..",
|
|
934
|
+
"views",
|
|
935
|
+
"admin-blog-automation.ejs",
|
|
936
|
+
);
|
|
937
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
938
|
+
if (err) {
|
|
939
|
+
console.error("Error reading template:", err);
|
|
940
|
+
return res.status(500).send("Error loading page");
|
|
941
|
+
}
|
|
942
|
+
try {
|
|
943
|
+
const html = ejs.render(
|
|
944
|
+
template,
|
|
945
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
946
|
+
{ filename: templatePath },
|
|
947
|
+
);
|
|
948
|
+
res.send(html);
|
|
949
|
+
} catch (renderErr) {
|
|
950
|
+
console.error("Error rendering template:", renderErr);
|
|
951
|
+
res.status(500).send("Error rendering page");
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
router.get(`${adminPath}/blog/new`, basicAuth, (req, res) => {
|
|
957
|
+
const templatePath = path.join(
|
|
958
|
+
__dirname,
|
|
959
|
+
"..",
|
|
960
|
+
"views",
|
|
961
|
+
"admin-blog-edit.ejs",
|
|
962
|
+
);
|
|
963
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
964
|
+
if (err) {
|
|
965
|
+
console.error("Error reading template:", err);
|
|
966
|
+
return res.status(500).send("Error loading page");
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
const html = ejs.render(
|
|
970
|
+
template,
|
|
971
|
+
{ baseUrl: req.baseUrl, adminPath, postId: "", mode: "new" },
|
|
972
|
+
{ filename: templatePath },
|
|
973
|
+
);
|
|
974
|
+
res.send(html);
|
|
975
|
+
} catch (renderErr) {
|
|
976
|
+
console.error("Error rendering template:", renderErr);
|
|
977
|
+
res.status(500).send("Error rendering page");
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
router.get(`${adminPath}/blog/edit/:id`, basicAuth, (req, res) => {
|
|
311
983
|
const templatePath = path.join(
|
|
312
984
|
__dirname,
|
|
313
985
|
"..",
|
|
314
986
|
"views",
|
|
315
|
-
"admin-
|
|
987
|
+
"admin-blog-edit.ejs",
|
|
316
988
|
);
|
|
317
989
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
318
990
|
if (err) {
|
|
@@ -325,10 +997,10 @@ function createMiddleware(options = {}) {
|
|
|
325
997
|
{
|
|
326
998
|
baseUrl: req.baseUrl,
|
|
327
999
|
adminPath,
|
|
1000
|
+
postId: String(req.params.id || ""),
|
|
1001
|
+
mode: "edit",
|
|
328
1002
|
},
|
|
329
|
-
{
|
|
330
|
-
filename: templatePath,
|
|
331
|
-
},
|
|
1003
|
+
{ filename: templatePath },
|
|
332
1004
|
);
|
|
333
1005
|
res.send(html);
|
|
334
1006
|
} catch (renderErr) {
|
|
@@ -338,15 +1010,29 @@ function createMiddleware(options = {}) {
|
|
|
338
1010
|
});
|
|
339
1011
|
});
|
|
340
1012
|
|
|
341
|
-
router.get(`${adminPath}/
|
|
342
|
-
const templatePath = path.join(
|
|
1013
|
+
router.get(`${adminPath}/file-manager`, basicAuth, (req, res) => {
|
|
1014
|
+
const templatePath = path.join(
|
|
1015
|
+
__dirname,
|
|
1016
|
+
"..",
|
|
1017
|
+
"views",
|
|
1018
|
+
"admin-file-manager.ejs",
|
|
1019
|
+
);
|
|
343
1020
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
344
1021
|
if (err) {
|
|
345
1022
|
console.error("Error reading template:", err);
|
|
346
1023
|
return res.status(500).send("Error loading page");
|
|
347
1024
|
}
|
|
348
1025
|
try {
|
|
349
|
-
const html = ejs.render(
|
|
1026
|
+
const html = ejs.render(
|
|
1027
|
+
template,
|
|
1028
|
+
{
|
|
1029
|
+
baseUrl: req.baseUrl,
|
|
1030
|
+
adminPath,
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
filename: templatePath,
|
|
1034
|
+
},
|
|
1035
|
+
);
|
|
350
1036
|
res.send(html);
|
|
351
1037
|
} catch (renderErr) {
|
|
352
1038
|
console.error("Error rendering template:", renderErr);
|
|
@@ -356,7 +1042,12 @@ function createMiddleware(options = {}) {
|
|
|
356
1042
|
});
|
|
357
1043
|
|
|
358
1044
|
router.get(`${adminPath}/ejs-virtual`, basicAuth, (req, res) => {
|
|
359
|
-
const templatePath = path.join(
|
|
1045
|
+
const templatePath = path.join(
|
|
1046
|
+
__dirname,
|
|
1047
|
+
"..",
|
|
1048
|
+
"views",
|
|
1049
|
+
"admin-ejs-virtual.ejs",
|
|
1050
|
+
);
|
|
360
1051
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
361
1052
|
if (err) {
|
|
362
1053
|
console.error("Error reading template:", err);
|
|
@@ -382,7 +1073,12 @@ function createMiddleware(options = {}) {
|
|
|
382
1073
|
});
|
|
383
1074
|
|
|
384
1075
|
router.get(`${adminPath}/seo-config`, basicAuth, (req, res) => {
|
|
385
|
-
const templatePath = path.join(
|
|
1076
|
+
const templatePath = path.join(
|
|
1077
|
+
__dirname,
|
|
1078
|
+
"..",
|
|
1079
|
+
"views",
|
|
1080
|
+
"admin-seo-config.ejs",
|
|
1081
|
+
);
|
|
386
1082
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
387
1083
|
if (err) {
|
|
388
1084
|
console.error("Error reading template:", err);
|
|
@@ -416,7 +1112,11 @@ function createMiddleware(options = {}) {
|
|
|
416
1112
|
return res.status(500).send("Error loading page");
|
|
417
1113
|
}
|
|
418
1114
|
try {
|
|
419
|
-
const html = ejs.render(
|
|
1115
|
+
const html = ejs.render(
|
|
1116
|
+
template,
|
|
1117
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1118
|
+
{ filename: templatePath },
|
|
1119
|
+
);
|
|
420
1120
|
res.send(html);
|
|
421
1121
|
} catch (renderErr) {
|
|
422
1122
|
console.error("Error rendering template:", renderErr);
|
|
@@ -438,7 +1138,11 @@ function createMiddleware(options = {}) {
|
|
|
438
1138
|
return res.status(500).send("Error loading page");
|
|
439
1139
|
}
|
|
440
1140
|
try {
|
|
441
|
-
const html = ejs.render(
|
|
1141
|
+
const html = ejs.render(
|
|
1142
|
+
template,
|
|
1143
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1144
|
+
{ filename: templatePath },
|
|
1145
|
+
);
|
|
442
1146
|
res.send(html);
|
|
443
1147
|
} catch (renderErr) {
|
|
444
1148
|
console.error("Error rendering template:", renderErr);
|
|
@@ -541,6 +1245,39 @@ function createMiddleware(options = {}) {
|
|
|
541
1245
|
});
|
|
542
1246
|
});
|
|
543
1247
|
|
|
1248
|
+
// Admin UI Components page (protected by basic auth)
|
|
1249
|
+
router.get(`${adminPath}/ui-components`, basicAuth, (req, res) => {
|
|
1250
|
+
const templatePath = path.join(
|
|
1251
|
+
__dirname,
|
|
1252
|
+
"..",
|
|
1253
|
+
"views",
|
|
1254
|
+
"admin-ui-components.ejs",
|
|
1255
|
+
);
|
|
1256
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1257
|
+
if (err) {
|
|
1258
|
+
console.error("Error reading template:", err);
|
|
1259
|
+
return res.status(500).send("Error loading page");
|
|
1260
|
+
}
|
|
1261
|
+
try {
|
|
1262
|
+
const html = ejs.render(
|
|
1263
|
+
template,
|
|
1264
|
+
{
|
|
1265
|
+
baseUrl: req.baseUrl,
|
|
1266
|
+
adminPath,
|
|
1267
|
+
endpointRegistry,
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
filename: templatePath,
|
|
1271
|
+
},
|
|
1272
|
+
);
|
|
1273
|
+
res.send(html);
|
|
1274
|
+
} catch (renderErr) {
|
|
1275
|
+
console.error("Error rendering template:", renderErr);
|
|
1276
|
+
res.status(500).send("Error rendering page");
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
|
|
544
1281
|
// Admin JSON configs page (protected by basic auth)
|
|
545
1282
|
router.get(`${adminPath}/json-configs`, basicAuth, (req, res) => {
|
|
546
1283
|
const templatePath = path.join(
|
|
@@ -669,12 +1406,7 @@ function createMiddleware(options = {}) {
|
|
|
669
1406
|
|
|
670
1407
|
// Admin users page (protected by basic auth)
|
|
671
1408
|
router.get(`${adminPath}/users`, basicAuth, (req, res) => {
|
|
672
|
-
const templatePath = path.join(
|
|
673
|
-
__dirname,
|
|
674
|
-
"..",
|
|
675
|
-
"views",
|
|
676
|
-
"admin-users.ejs",
|
|
677
|
-
);
|
|
1409
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-users.ejs");
|
|
678
1410
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
679
1411
|
if (err) {
|
|
680
1412
|
console.error("Error reading template:", err);
|
|
@@ -793,6 +1525,31 @@ function createMiddleware(options = {}) {
|
|
|
793
1525
|
});
|
|
794
1526
|
});
|
|
795
1527
|
|
|
1528
|
+
router.get(`${adminPath}/rate-limiter`, basicAuth, (req, res) => {
|
|
1529
|
+
const templatePath = path.join(
|
|
1530
|
+
__dirname,
|
|
1531
|
+
"..",
|
|
1532
|
+
"views",
|
|
1533
|
+
"admin-rate-limiter.ejs",
|
|
1534
|
+
);
|
|
1535
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1536
|
+
if (err) {
|
|
1537
|
+
console.error("Error reading template:", err);
|
|
1538
|
+
return res.status(500).send("Error loading page");
|
|
1539
|
+
}
|
|
1540
|
+
try {
|
|
1541
|
+
const html = ejs.render(template, {
|
|
1542
|
+
baseUrl: req.baseUrl,
|
|
1543
|
+
adminPath,
|
|
1544
|
+
});
|
|
1545
|
+
res.send(html);
|
|
1546
|
+
} catch (renderErr) {
|
|
1547
|
+
console.error("Error rendering template:", renderErr);
|
|
1548
|
+
res.status(500).send("Error rendering page");
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
});
|
|
1552
|
+
|
|
796
1553
|
// Admin global settings page (protected by basic auth) - render manually
|
|
797
1554
|
router.get(`${adminPath}/global-settings`, basicAuth, (req, res) => {
|
|
798
1555
|
const templatePath = path.join(
|
|
@@ -817,14 +1574,23 @@ function createMiddleware(options = {}) {
|
|
|
817
1574
|
});
|
|
818
1575
|
|
|
819
1576
|
router.get(`${adminPath}/errors`, basicAuth, (req, res) => {
|
|
820
|
-
const templatePath = path.join(
|
|
1577
|
+
const templatePath = path.join(
|
|
1578
|
+
__dirname,
|
|
1579
|
+
"..",
|
|
1580
|
+
"views",
|
|
1581
|
+
"admin-errors.ejs",
|
|
1582
|
+
);
|
|
821
1583
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
822
1584
|
if (err) {
|
|
823
1585
|
console.error("Error reading template:", err);
|
|
824
1586
|
return res.status(500).send("Error loading page");
|
|
825
1587
|
}
|
|
826
1588
|
try {
|
|
827
|
-
const html = ejs.render(
|
|
1589
|
+
const html = ejs.render(
|
|
1590
|
+
template,
|
|
1591
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1592
|
+
{ filename: templatePath },
|
|
1593
|
+
);
|
|
828
1594
|
res.send(html);
|
|
829
1595
|
} catch (renderErr) {
|
|
830
1596
|
console.error("Error rendering template:", renderErr);
|
|
@@ -841,7 +1607,11 @@ function createMiddleware(options = {}) {
|
|
|
841
1607
|
return res.status(500).send("Error loading page");
|
|
842
1608
|
}
|
|
843
1609
|
try {
|
|
844
|
-
const html = ejs.render(
|
|
1610
|
+
const html = ejs.render(
|
|
1611
|
+
template,
|
|
1612
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1613
|
+
{ filename: templatePath },
|
|
1614
|
+
);
|
|
845
1615
|
res.send(html);
|
|
846
1616
|
} catch (renderErr) {
|
|
847
1617
|
console.error("Error rendering template:", renderErr);
|
|
@@ -851,14 +1621,44 @@ function createMiddleware(options = {}) {
|
|
|
851
1621
|
});
|
|
852
1622
|
|
|
853
1623
|
router.get(`${adminPath}/coolify-deploy`, basicAuth, (req, res) => {
|
|
854
|
-
const templatePath = path.join(
|
|
1624
|
+
const templatePath = path.join(
|
|
1625
|
+
__dirname,
|
|
1626
|
+
"..",
|
|
1627
|
+
"views",
|
|
1628
|
+
"admin-coolify-deploy.ejs",
|
|
1629
|
+
);
|
|
1630
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1631
|
+
if (err) {
|
|
1632
|
+
console.error("Error reading template:", err);
|
|
1633
|
+
return res.status(500).send("Error loading page");
|
|
1634
|
+
}
|
|
1635
|
+
try {
|
|
1636
|
+
const html = ejs.render(
|
|
1637
|
+
template,
|
|
1638
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1639
|
+
{ filename: templatePath },
|
|
1640
|
+
);
|
|
1641
|
+
res.send(html);
|
|
1642
|
+
} catch (renderErr) {
|
|
1643
|
+
console.error("Error rendering template:", renderErr);
|
|
1644
|
+
res.status(500).send("Error rendering page");
|
|
1645
|
+
}
|
|
1646
|
+
});
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
router.get(`${adminPath}/proxy`, basicAuth, (req, res) => {
|
|
1650
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-proxy.ejs");
|
|
855
1651
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
856
1652
|
if (err) {
|
|
857
1653
|
console.error("Error reading template:", err);
|
|
858
1654
|
return res.status(500).send("Error loading page");
|
|
859
1655
|
}
|
|
860
1656
|
try {
|
|
861
|
-
const html = ejs.render(
|
|
1657
|
+
const html = ejs.render(
|
|
1658
|
+
template,
|
|
1659
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1660
|
+
{ filename: templatePath },
|
|
1661
|
+
);
|
|
862
1662
|
res.send(html);
|
|
863
1663
|
} catch (renderErr) {
|
|
864
1664
|
console.error("Error rendering template:", renderErr);
|
|
@@ -868,14 +1668,23 @@ function createMiddleware(options = {}) {
|
|
|
868
1668
|
});
|
|
869
1669
|
|
|
870
1670
|
router.get(`${adminPath}/webhooks`, basicAuth, (req, res) => {
|
|
871
|
-
const templatePath = path.join(
|
|
1671
|
+
const templatePath = path.join(
|
|
1672
|
+
__dirname,
|
|
1673
|
+
"..",
|
|
1674
|
+
"views",
|
|
1675
|
+
"admin-webhooks.ejs",
|
|
1676
|
+
);
|
|
872
1677
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
873
1678
|
if (err) {
|
|
874
1679
|
console.error("Error reading template:", err);
|
|
875
1680
|
return res.status(500).send("Error loading page");
|
|
876
1681
|
}
|
|
877
1682
|
try {
|
|
878
|
-
const html = ejs.render(
|
|
1683
|
+
const html = ejs.render(
|
|
1684
|
+
template,
|
|
1685
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1686
|
+
{ filename: templatePath },
|
|
1687
|
+
);
|
|
879
1688
|
res.send(html);
|
|
880
1689
|
} catch (renderErr) {
|
|
881
1690
|
console.error("Error rendering template:", renderErr);
|
|
@@ -884,7 +1693,7 @@ function createMiddleware(options = {}) {
|
|
|
884
1693
|
});
|
|
885
1694
|
});
|
|
886
1695
|
|
|
887
|
-
router.get("/health", (req, res) => {
|
|
1696
|
+
router.get("/health", rateLimiter.limit("healthRateLimiter"), (req, res) => {
|
|
888
1697
|
res.json({
|
|
889
1698
|
status: "ok",
|
|
890
1699
|
mode: "middleware",
|
|
@@ -896,6 +1705,20 @@ function createMiddleware(options = {}) {
|
|
|
896
1705
|
router.use("/api/ejs-virtual", require("./routes/adminEjsVirtual.routes"));
|
|
897
1706
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
898
1707
|
|
|
1708
|
+
// Store pagesPrefix and adminPath on app for pages router
|
|
1709
|
+
router.use((req, res, next) => {
|
|
1710
|
+
if (!req.app.get("pagesPrefix")) {
|
|
1711
|
+
req.app.set("pagesPrefix", pagesPrefix);
|
|
1712
|
+
}
|
|
1713
|
+
if (!req.app.get("adminPath")) {
|
|
1714
|
+
req.app.set("adminPath", adminPath);
|
|
1715
|
+
}
|
|
1716
|
+
next();
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1719
|
+
// Public pages router (catch-all, must be last before error handler)
|
|
1720
|
+
router.use(require("./routes/pages.routes"));
|
|
1721
|
+
|
|
899
1722
|
// Error handling middleware
|
|
900
1723
|
router.use(expressErrorMiddleware);
|
|
901
1724
|
|