@intranefr/superbackend 1.4.3

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.
Files changed (188) hide show
  1. package/.commiat +4 -0
  2. package/.env.example +47 -0
  3. package/README.md +110 -0
  4. package/index.js +94 -0
  5. package/package.json +67 -0
  6. package/public/css/styles.css +139 -0
  7. package/public/js/animations.js +41 -0
  8. package/sdk/error-tracking/browser/package.json +16 -0
  9. package/sdk/error-tracking/browser/src/core.js +270 -0
  10. package/sdk/error-tracking/browser/src/embed.js +18 -0
  11. package/sdk/error-tracking/browser/src/index.js +1 -0
  12. package/server.js +5 -0
  13. package/src/admin/endpointRegistry.js +300 -0
  14. package/src/controllers/admin.controller.js +321 -0
  15. package/src/controllers/adminAssets.controller.js +530 -0
  16. package/src/controllers/adminAssetsStorage.controller.js +260 -0
  17. package/src/controllers/adminEjsVirtual.controller.js +354 -0
  18. package/src/controllers/adminFeatureFlags.controller.js +155 -0
  19. package/src/controllers/adminHeadless.controller.js +1071 -0
  20. package/src/controllers/adminI18n.controller.js +604 -0
  21. package/src/controllers/adminJsonConfigs.controller.js +97 -0
  22. package/src/controllers/adminLlm.controller.js +273 -0
  23. package/src/controllers/adminMigration.controller.js +257 -0
  24. package/src/controllers/adminSeoConfig.controller.js +515 -0
  25. package/src/controllers/adminStats.controller.js +121 -0
  26. package/src/controllers/adminUploadNamespaces.controller.js +208 -0
  27. package/src/controllers/assets.controller.js +248 -0
  28. package/src/controllers/auth.controller.js +93 -0
  29. package/src/controllers/billing.controller.js +223 -0
  30. package/src/controllers/featureFlags.controller.js +35 -0
  31. package/src/controllers/forms.controller.js +217 -0
  32. package/src/controllers/globalSettings.controller.js +252 -0
  33. package/src/controllers/headlessCrud.controller.js +126 -0
  34. package/src/controllers/i18n.controller.js +12 -0
  35. package/src/controllers/invite.controller.js +249 -0
  36. package/src/controllers/jsonConfigs.controller.js +19 -0
  37. package/src/controllers/metrics.controller.js +149 -0
  38. package/src/controllers/notificationAdmin.controller.js +264 -0
  39. package/src/controllers/notifications.controller.js +131 -0
  40. package/src/controllers/org.controller.js +357 -0
  41. package/src/controllers/orgAdmin.controller.js +491 -0
  42. package/src/controllers/stripeAdmin.controller.js +410 -0
  43. package/src/controllers/user.controller.js +361 -0
  44. package/src/controllers/userAdmin.controller.js +277 -0
  45. package/src/controllers/waitingList.controller.js +167 -0
  46. package/src/controllers/webhook.controller.js +200 -0
  47. package/src/middleware/auth.js +66 -0
  48. package/src/middleware/errorCapture.js +170 -0
  49. package/src/middleware/headlessApiTokenAuth.js +57 -0
  50. package/src/middleware/org.js +108 -0
  51. package/src/middleware.js +901 -0
  52. package/src/models/ActionEvent.js +31 -0
  53. package/src/models/ActivityLog.js +41 -0
  54. package/src/models/Asset.js +84 -0
  55. package/src/models/AuditEvent.js +93 -0
  56. package/src/models/EmailLog.js +28 -0
  57. package/src/models/ErrorAggregate.js +72 -0
  58. package/src/models/FormSubmission.js +41 -0
  59. package/src/models/GlobalSetting.js +38 -0
  60. package/src/models/HeadlessApiToken.js +24 -0
  61. package/src/models/HeadlessModelDefinition.js +41 -0
  62. package/src/models/I18nEntry.js +77 -0
  63. package/src/models/I18nLocale.js +33 -0
  64. package/src/models/Invite.js +70 -0
  65. package/src/models/JsonConfig.js +46 -0
  66. package/src/models/Notification.js +60 -0
  67. package/src/models/Organization.js +57 -0
  68. package/src/models/OrganizationMember.js +43 -0
  69. package/src/models/StripeCatalogItem.js +77 -0
  70. package/src/models/StripeWebhookEvent.js +57 -0
  71. package/src/models/User.js +89 -0
  72. package/src/models/VirtualEjsFile.js +60 -0
  73. package/src/models/VirtualEjsFileVersion.js +43 -0
  74. package/src/models/VirtualEjsGroupChange.js +32 -0
  75. package/src/models/WaitingList.js +41 -0
  76. package/src/models/Webhook.js +63 -0
  77. package/src/models/Workflow.js +29 -0
  78. package/src/models/WorkflowExecution.js +12 -0
  79. package/src/routes/admin.routes.js +26 -0
  80. package/src/routes/adminAssets.routes.js +28 -0
  81. package/src/routes/adminAssetsStorage.routes.js +13 -0
  82. package/src/routes/adminAudit.routes.js +196 -0
  83. package/src/routes/adminEjsVirtual.routes.js +17 -0
  84. package/src/routes/adminErrors.routes.js +164 -0
  85. package/src/routes/adminFeatureFlags.routes.js +12 -0
  86. package/src/routes/adminHeadless.routes.js +38 -0
  87. package/src/routes/adminI18n.routes.js +22 -0
  88. package/src/routes/adminJsonConfigs.routes.js +15 -0
  89. package/src/routes/adminLlm.routes.js +12 -0
  90. package/src/routes/adminMigration.routes.js +81 -0
  91. package/src/routes/adminSeoConfig.routes.js +20 -0
  92. package/src/routes/adminUploadNamespaces.routes.js +13 -0
  93. package/src/routes/assets.routes.js +21 -0
  94. package/src/routes/auth.routes.js +12 -0
  95. package/src/routes/billing.routes.js +11 -0
  96. package/src/routes/errorTracking.routes.js +31 -0
  97. package/src/routes/featureFlags.routes.js +9 -0
  98. package/src/routes/forms.routes.js +9 -0
  99. package/src/routes/formsAdmin.routes.js +13 -0
  100. package/src/routes/globalSettings.routes.js +18 -0
  101. package/src/routes/headless.routes.js +15 -0
  102. package/src/routes/i18n.routes.js +8 -0
  103. package/src/routes/invite.routes.js +9 -0
  104. package/src/routes/jsonConfigs.routes.js +8 -0
  105. package/src/routes/log.routes.js +111 -0
  106. package/src/routes/metrics.routes.js +9 -0
  107. package/src/routes/notificationAdmin.routes.js +15 -0
  108. package/src/routes/notifications.routes.js +12 -0
  109. package/src/routes/org.routes.js +31 -0
  110. package/src/routes/orgAdmin.routes.js +20 -0
  111. package/src/routes/publicAssets.routes.js +7 -0
  112. package/src/routes/stripeAdmin.routes.js +20 -0
  113. package/src/routes/user.routes.js +22 -0
  114. package/src/routes/userAdmin.routes.js +15 -0
  115. package/src/routes/waitingList.routes.js +13 -0
  116. package/src/routes/waitingListAdmin.routes.js +9 -0
  117. package/src/routes/webhook.routes.js +32 -0
  118. package/src/routes/workflowWebhook.routes.js +54 -0
  119. package/src/routes/workflows.routes.js +110 -0
  120. package/src/services/assets.service.js +110 -0
  121. package/src/services/audit.service.js +62 -0
  122. package/src/services/auditLogger.js +165 -0
  123. package/src/services/ejsVirtual.service.js +614 -0
  124. package/src/services/email.service.js +351 -0
  125. package/src/services/errorLogger.js +221 -0
  126. package/src/services/featureFlags.service.js +202 -0
  127. package/src/services/forms.service.js +214 -0
  128. package/src/services/globalSettings.service.js +49 -0
  129. package/src/services/headlessApiTokens.service.js +158 -0
  130. package/src/services/headlessCrypto.service.js +31 -0
  131. package/src/services/headlessModels.service.js +356 -0
  132. package/src/services/i18n.service.js +314 -0
  133. package/src/services/i18nInferredKeys.service.js +337 -0
  134. package/src/services/jsonConfigs.service.js +392 -0
  135. package/src/services/llm.service.js +749 -0
  136. package/src/services/migration.service.js +581 -0
  137. package/src/services/migrationAssets/fsLocal.js +58 -0
  138. package/src/services/migrationAssets/index.js +134 -0
  139. package/src/services/migrationAssets/s3.js +75 -0
  140. package/src/services/migrationAssets/sftp.js +92 -0
  141. package/src/services/notification.service.js +212 -0
  142. package/src/services/objectStorage.service.js +514 -0
  143. package/src/services/seoConfig.service.js +402 -0
  144. package/src/services/storage.js +150 -0
  145. package/src/services/stripe.service.js +185 -0
  146. package/src/services/stripeHelper.service.js +264 -0
  147. package/src/services/uploadNamespaces.service.js +326 -0
  148. package/src/services/webhook.service.js +157 -0
  149. package/src/services/workflow.service.js +271 -0
  150. package/src/utils/asyncHandler.js +5 -0
  151. package/src/utils/encryption.js +80 -0
  152. package/src/utils/jwt.js +40 -0
  153. package/src/utils/orgRoles.js +156 -0
  154. package/src/utils/validation.js +26 -0
  155. package/src/utils/webhookRetry.js +93 -0
  156. package/views/admin-assets.ejs +444 -0
  157. package/views/admin-audit.ejs +283 -0
  158. package/views/admin-coolify-deploy.ejs +207 -0
  159. package/views/admin-dashboard-home.ejs +291 -0
  160. package/views/admin-dashboard.ejs +397 -0
  161. package/views/admin-ejs-virtual.ejs +280 -0
  162. package/views/admin-errors.ejs +368 -0
  163. package/views/admin-feature-flags.ejs +390 -0
  164. package/views/admin-forms.ejs +526 -0
  165. package/views/admin-global-settings.ejs +436 -0
  166. package/views/admin-headless.ejs +2020 -0
  167. package/views/admin-i18n-locales.ejs +221 -0
  168. package/views/admin-i18n.ejs +728 -0
  169. package/views/admin-json-configs.ejs +410 -0
  170. package/views/admin-llm.ejs +884 -0
  171. package/views/admin-metrics.ejs +274 -0
  172. package/views/admin-migration.ejs +814 -0
  173. package/views/admin-notifications.ejs +430 -0
  174. package/views/admin-organizations.ejs +984 -0
  175. package/views/admin-seo-config.ejs +673 -0
  176. package/views/admin-stripe-pricing.ejs +558 -0
  177. package/views/admin-test.ejs +342 -0
  178. package/views/admin-users.ejs +452 -0
  179. package/views/admin-waiting-list.ejs +547 -0
  180. package/views/admin-webhooks.ejs +329 -0
  181. package/views/admin-workflows.ejs +310 -0
  182. package/views/partials/admin-assets-script.ejs +2022 -0
  183. package/views/partials/admin-test-sidebar.ejs +14 -0
  184. package/views/partials/dashboard/nav-items.ejs +66 -0
  185. package/views/partials/dashboard/palette.ejs +63 -0
  186. package/views/partials/dashboard/sidebar.ejs +21 -0
  187. package/views/partials/dashboard/tab-bar.ejs +26 -0
  188. package/views/partials/footer.ejs +3 -0
@@ -0,0 +1,901 @@
1
+ const express = require("express");
2
+ const path = require("path");
3
+ const mongoose = require("mongoose");
4
+ const cors = require("cors");
5
+ const fs = require("fs");
6
+ const ejs = require("ejs");
7
+ const { basicAuth } = require("./middleware/auth");
8
+ const endpointRegistry = require("./admin/endpointRegistry");
9
+ const { createFeatureFlagsEjsMiddleware } = require("./services/featureFlags.service");
10
+ const {
11
+ hookConsoleError,
12
+ setupProcessHandlers,
13
+ expressErrorMiddleware,
14
+ requestIdMiddleware,
15
+ } = require("./middleware/errorCapture");
16
+
17
+ let errorCaptureInitialized = false;
18
+
19
+ /**
20
+ * Creates and configures the SaaS backend middleware
21
+ * @param {Object} options - Configuration options
22
+ * @param {string} options.mongodbUri - MongoDB connection string
23
+ * @param {string} options.corsOrigin - CORS origin(s)
24
+ * @param {string} options.jwtSecret - JWT secret for authentication
25
+ * @param {Object} options.dbConnection - Existing Mongoose connection
26
+ * @param {boolean} options.skipBodyParser - Skip adding body parser middleware (default: false)
27
+ * @returns {express.Router} Configured Express router
28
+ */
29
+ function createMiddleware(options = {}) {
30
+ const router = express.Router();
31
+ const adminPath = options.adminPath || "/admin";
32
+
33
+ if (!errorCaptureInitialized) {
34
+ errorCaptureInitialized = true;
35
+ hookConsoleError();
36
+ setupProcessHandlers();
37
+ }
38
+
39
+ // Database connection
40
+ const mongoUri =
41
+ options.mongodbUri || options.dbConnection || process.env.MONGODB_URI || process.env.MONGO_URI;
42
+
43
+ if (!mongoUri && mongoose.connection.readyState !== 1) {
44
+ console.warn(
45
+ "⚠️ Warning: No MongoDB connection provided to middleware. Set MONGODB_URI or MONGO_URI in environment or pass mongodbUri/dbConnection option.",
46
+ );
47
+ } else if (mongoUri && mongoose.connection.readyState !== 1) {
48
+ const connectionOptions = options.mongooseOptions || {
49
+ serverSelectionTimeoutMS: 5000,
50
+ maxPoolSize: 10,
51
+ };
52
+
53
+ // Return a promise that resolves when connection is established
54
+ const connectionPromise = mongoose
55
+ .connect(mongoUri, connectionOptions)
56
+ .then(() => {
57
+ console.log("✅ Middleware: Connected to MongoDB");
58
+ return true;
59
+ })
60
+ .catch((err) => {
61
+ console.error("❌ Middleware: MongoDB connection error:", err);
62
+ return false;
63
+ });
64
+
65
+ // Store the promise so it can be awaited if needed
66
+ router.connectionPromise = connectionPromise;
67
+ } else if (mongoose.connection.readyState === 1) {
68
+ console.log("✅ Middleware: Using existing MongoDB connection");
69
+ }
70
+
71
+ // CORS configuration
72
+ const configureCORS = () => {
73
+ const corsOrigin = options.corsOrigin || process.env.CORS_ORIGIN || "*";
74
+
75
+ // If corsOrigin is *, allow all origins
76
+ if (corsOrigin === "*") {
77
+ return {
78
+ origin: "*",
79
+ credentials: true,
80
+ optionsSuccessStatus: 200,
81
+ };
82
+ }
83
+
84
+ // If corsOrigin contains comma, split into array
85
+ if (corsOrigin.includes(",")) {
86
+ const origins = corsOrigin.split(",").map((o) => o.trim());
87
+ return {
88
+ origin: origins,
89
+ credentials: true,
90
+ optionsSuccessStatus: 200,
91
+ };
92
+ }
93
+
94
+ // Single origin
95
+ return {
96
+ origin: corsOrigin,
97
+ credentials: true,
98
+ optionsSuccessStatus: 200,
99
+ };
100
+ };
101
+
102
+ const isCorsDisabled = options.corsOrigin === false || options.cors === false;
103
+
104
+ if (!isCorsDisabled) {
105
+ const corsOptions = configureCORS();
106
+
107
+ console.log("🌐 Middleware CORS Configuration:", {
108
+ origin: corsOptions.origin,
109
+ credentials: corsOptions.credentials,
110
+ });
111
+
112
+ // Middleware
113
+ router.use(cors(corsOptions));
114
+ }
115
+
116
+ // Stripe webhook needs raw body (support both routes)
117
+ const webhookHandler =
118
+ require("./controllers/billing.controller").handleWebhook;
119
+ router.post(
120
+ "/api/stripe-webhook",
121
+ express.raw({ type: "application/json" }),
122
+ webhookHandler,
123
+ );
124
+ router.post(
125
+ "/api/stripe/webhook",
126
+ express.raw({ type: "application/json" }),
127
+ webhookHandler,
128
+ );
129
+
130
+ // Regular JSON parsing for other routes (skip if parent app already handles it)
131
+ if (!options.skipBodyParser) {
132
+ router.use(express.json());
133
+ router.use(express.urlencoded({ extended: true }));
134
+ }
135
+
136
+ router.use(requestIdMiddleware);
137
+
138
+ // Serve public static files (e.g. /og/og-default.png)
139
+ router.use(express.static(path.join(__dirname, "..", "public")));
140
+
141
+ // Serve static files for admin views
142
+ router.use(
143
+ `${adminPath}/assets`,
144
+ express.static(path.join(__dirname, "..", "public")),
145
+ );
146
+
147
+ // EJS locals: feature flags for server-rendered pages
148
+ router.use(createFeatureFlagsEjsMiddleware());
149
+
150
+ // API Routes
151
+ router.use("/api/auth", require("./routes/auth.routes"));
152
+ router.use("/api/billing", require("./routes/billing.routes"));
153
+ router.use("/api/waiting-list", require("./routes/waitingList.routes"));
154
+ router.use("/api/metrics", require("./routes/metrics.routes"));
155
+ router.use("/api/forms", require("./routes/forms.routes"));
156
+ router.use("/api/admin/forms", require("./routes/formsAdmin.routes"));
157
+ router.use(
158
+ "/api/admin/waiting-list",
159
+ require("./routes/waitingListAdmin.routes"),
160
+ );
161
+ router.use("/api/admin/orgs", require("./routes/orgAdmin.routes"));
162
+ router.use("/api/admin/users", require("./routes/userAdmin.routes"));
163
+ router.use("/api/admin/notifications", require("./routes/notificationAdmin.routes"));
164
+ router.use("/api/admin/stripe", require("./routes/stripeAdmin.routes"));
165
+
166
+ // Stats Routes
167
+ const adminStatsController = require("./controllers/adminStats.controller");
168
+ router.get("/api/admin/stats/overview", basicAuth, adminStatsController.getOverviewStats);
169
+
170
+ router.get(`${adminPath}/stats/dashboard-home`, basicAuth, (req, res) => {
171
+ const templatePath = path.join(__dirname, "..", "views", "admin-dashboard-home.ejs");
172
+ fs.readFile(templatePath, "utf8", (err, template) => {
173
+ if (err) {
174
+ console.error("Error reading template:", err);
175
+ return res.status(500).send("Error loading page");
176
+ }
177
+ try {
178
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
179
+ res.send(html);
180
+ } catch (renderErr) {
181
+ console.error("Error rendering template:", renderErr);
182
+ res.status(500).send("Error rendering page");
183
+ }
184
+ });
185
+ });
186
+
187
+ router.use("/api/admin", require("./routes/admin.routes"));
188
+ router.use("/api/admin/settings", require("./routes/globalSettings.routes"));
189
+ router.use(
190
+ "/api/admin/feature-flags",
191
+ require("./routes/adminFeatureFlags.routes"),
192
+ );
193
+ router.use(
194
+ "/api/admin/json-configs",
195
+ require("./routes/adminJsonConfigs.routes"),
196
+ );
197
+ router.use(
198
+ "/api/admin/seo-config",
199
+ require("./routes/adminSeoConfig.routes"),
200
+ );
201
+ router.use("/api/admin/i18n", require("./routes/adminI18n.routes"));
202
+ router.use("/api/admin/headless", require("./routes/adminHeadless.routes"));
203
+ router.use("/api/admin/assets", require("./routes/adminAssets.routes"));
204
+ router.use(
205
+ "/api/admin/upload-namespaces",
206
+ require("./routes/adminUploadNamespaces.routes"),
207
+ );
208
+ router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
209
+ router.use("/api/admin/errors", basicAuth, require("./routes/adminErrors.routes"));
210
+ router.use("/api/admin/audit", basicAuth, require("./routes/adminAudit.routes"));
211
+ router.use("/api/admin/llm", require("./routes/adminLlm.routes"));
212
+ router.use("/api/admin/ejs-virtual", require("./routes/adminEjsVirtual.routes"));
213
+ router.use("/api/workflows", basicAuth, require("./routes/workflows.routes"));
214
+ router.use("/w", require("./routes/workflowWebhook.routes"));
215
+ router.use("/api/webhooks", require("./routes/webhook.routes"));
216
+ router.use("/api/settings", require("./routes/globalSettings.routes"));
217
+ router.use("/api/feature-flags", require("./routes/featureFlags.routes"));
218
+ router.use("/api/json-configs", require("./routes/jsonConfigs.routes"));
219
+ router.use("/api/assets", require("./routes/assets.routes"));
220
+ router.use("/api/i18n", require("./routes/i18n.routes"));
221
+ router.use("/api/headless", require("./routes/headless.routes"));
222
+ router.use("/api", require("./routes/notifications.routes"));
223
+ router.use("/api/user", require("./routes/user.routes"));
224
+ router.use("/api/orgs", require("./routes/org.routes"));
225
+ router.use("/api/invites", require("./routes/invite.routes"));
226
+ router.use("/api/log", require("./routes/log.routes"));
227
+ router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
228
+
229
+ // Public assets proxy
230
+ router.use("/public/assets", require("./routes/publicAssets.routes"));
231
+
232
+ // Admin dashboard (polished view)
233
+ router.get(adminPath, basicAuth, (req, res) => {
234
+ const templatePath = path.join(__dirname, "..", "views", "admin-dashboard.ejs");
235
+ fs.readFile(templatePath, "utf8", (err, template) => {
236
+ if (err) {
237
+ console.error("Error reading template:", err);
238
+ return res.status(500).send("Error loading page");
239
+ }
240
+ try {
241
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
242
+ res.send(html);
243
+ } catch (renderErr) {
244
+ console.error("Error rendering template:", renderErr);
245
+ res.status(500).send("Error rendering page");
246
+ }
247
+ });
248
+ });
249
+
250
+ // Admin technical API test page (protected by basic auth)
251
+ router.get(`${adminPath}/api/test`, basicAuth, (req, res) => {
252
+ const templatePath = path.join(__dirname, "..", "views", "admin-test.ejs");
253
+ fs.readFile(templatePath, "utf8", (err, template) => {
254
+ if (err) {
255
+ console.error("Error reading template:", err);
256
+ return res.status(500).send("Error loading page");
257
+ }
258
+ try {
259
+ const html = ejs.render(
260
+ template,
261
+ {
262
+ baseUrl: req.baseUrl,
263
+ adminPath,
264
+ endpointRegistry,
265
+ },
266
+ {
267
+ filename: templatePath,
268
+ },
269
+ );
270
+ res.send(html);
271
+ } catch (renderErr) {
272
+ console.error("Error rendering template:", renderErr);
273
+ res.status(500).send("Error rendering page");
274
+ }
275
+ });
276
+ });
277
+
278
+ router.get(`${adminPath}/migration`, basicAuth, (req, res) => {
279
+ const templatePath = path.join(__dirname, "..", "views", "admin-migration.ejs");
280
+ fs.readFile(templatePath, "utf8", (err, template) => {
281
+ if (err) {
282
+ console.error("Error reading template:", err);
283
+ return res.status(500).send("Error loading page");
284
+ }
285
+ try {
286
+ const html = ejs.render(
287
+ template,
288
+ {
289
+ baseUrl: req.baseUrl,
290
+ adminPath,
291
+ endpointRegistry,
292
+ },
293
+ {
294
+ filename: templatePath,
295
+ },
296
+ );
297
+ res.send(html);
298
+ } catch (renderErr) {
299
+ console.error("Error rendering template:", renderErr);
300
+ res.status(500).send("Error rendering page");
301
+ }
302
+ });
303
+ });
304
+
305
+ // Admin LLM/AI page (protected by basic auth)
306
+ router.get(`${adminPath}/admin-llm`, basicAuth, (req, res) => {
307
+ const templatePath = path.join(
308
+ __dirname,
309
+ "..",
310
+ "views",
311
+ "admin-llm.ejs",
312
+ );
313
+ fs.readFile(templatePath, "utf8", (err, template) => {
314
+ if (err) {
315
+ console.error("Error reading template:", err);
316
+ return res.status(500).send("Error loading page");
317
+ }
318
+ try {
319
+ const html = ejs.render(
320
+ template,
321
+ {
322
+ baseUrl: req.baseUrl,
323
+ adminPath,
324
+ },
325
+ {
326
+ filename: templatePath,
327
+ },
328
+ );
329
+ res.send(html);
330
+ } catch (renderErr) {
331
+ console.error("Error rendering template:", renderErr);
332
+ res.status(500).send("Error rendering page");
333
+ }
334
+ });
335
+ });
336
+
337
+ router.get(`${adminPath}/workflows/:id`, basicAuth, (req, res) => {
338
+ const templatePath = path.join(__dirname, "..", "views", "admin-workflows.ejs");
339
+ fs.readFile(templatePath, "utf8", (err, template) => {
340
+ if (err) {
341
+ console.error("Error reading template:", err);
342
+ return res.status(500).send("Error loading page");
343
+ }
344
+ try {
345
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
346
+ res.send(html);
347
+ } catch (renderErr) {
348
+ console.error("Error rendering template:", renderErr);
349
+ res.status(500).send("Error rendering page");
350
+ }
351
+ });
352
+ });
353
+
354
+ router.get(`${adminPath}/ejs-virtual`, basicAuth, (req, res) => {
355
+ const templatePath = path.join(__dirname, "..", "views", "admin-ejs-virtual.ejs");
356
+ fs.readFile(templatePath, "utf8", (err, template) => {
357
+ if (err) {
358
+ console.error("Error reading template:", err);
359
+ return res.status(500).send("Error loading page");
360
+ }
361
+ try {
362
+ const html = ejs.render(
363
+ template,
364
+ {
365
+ baseUrl: req.baseUrl,
366
+ adminPath,
367
+ },
368
+ {
369
+ filename: templatePath,
370
+ },
371
+ );
372
+ res.send(html);
373
+ } catch (renderErr) {
374
+ console.error("Error rendering template:", renderErr);
375
+ res.status(500).send("Error rendering page");
376
+ }
377
+ });
378
+ });
379
+
380
+ router.get(`${adminPath}/seo-config`, basicAuth, (req, res) => {
381
+ const templatePath = path.join(__dirname, "..", "views", "admin-seo-config.ejs");
382
+ fs.readFile(templatePath, "utf8", (err, template) => {
383
+ if (err) {
384
+ console.error("Error reading template:", err);
385
+ return res.status(500).send("Error loading page");
386
+ }
387
+ try {
388
+ const html = ejs.render(
389
+ template,
390
+ {
391
+ baseUrl: req.baseUrl,
392
+ adminPath,
393
+ endpointRegistry,
394
+ },
395
+ {
396
+ filename: templatePath,
397
+ },
398
+ );
399
+ res.send(html);
400
+ } catch (renderErr) {
401
+ console.error("Error rendering template:", renderErr);
402
+ res.status(500).send("Error rendering page");
403
+ }
404
+ });
405
+ });
406
+
407
+ router.get(`${adminPath}/i18n`, basicAuth, (req, res) => {
408
+ const templatePath = path.join(__dirname, "..", "views", "admin-i18n.ejs");
409
+ fs.readFile(templatePath, "utf8", (err, template) => {
410
+ if (err) {
411
+ console.error("Error reading template:", err);
412
+ return res.status(500).send("Error loading page");
413
+ }
414
+ try {
415
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
416
+ res.send(html);
417
+ } catch (renderErr) {
418
+ console.error("Error rendering template:", renderErr);
419
+ res.status(500).send("Error rendering page");
420
+ }
421
+ });
422
+ });
423
+
424
+ router.get(`${adminPath}/i18n/locales`, basicAuth, (req, res) => {
425
+ const templatePath = path.join(
426
+ __dirname,
427
+ "..",
428
+ "views",
429
+ "admin-i18n-locales.ejs",
430
+ );
431
+ fs.readFile(templatePath, "utf8", (err, template) => {
432
+ if (err) {
433
+ console.error("Error reading template:", err);
434
+ return res.status(500).send("Error loading page");
435
+ }
436
+ try {
437
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
438
+ res.send(html);
439
+ } catch (renderErr) {
440
+ console.error("Error rendering template:", renderErr);
441
+ res.status(500).send("Error rendering page");
442
+ }
443
+ });
444
+ });
445
+
446
+ // Admin forms page (protected by basic auth)
447
+ router.get(`${adminPath}/forms`, basicAuth, (req, res) => {
448
+ const templatePath = path.join(__dirname, "..", "views", "admin-forms.ejs");
449
+ fs.readFile(templatePath, "utf8", (err, template) => {
450
+ if (err) {
451
+ console.error("Error reading template:", err);
452
+ return res.status(500).send("Error loading page");
453
+ }
454
+ try {
455
+ const html = ejs.render(
456
+ template,
457
+ {
458
+ baseUrl: req.baseUrl,
459
+ adminPath,
460
+ endpointRegistry,
461
+ },
462
+ {
463
+ filename: templatePath,
464
+ },
465
+ );
466
+ res.send(html);
467
+ } catch (renderErr) {
468
+ console.error("Error rendering template:", renderErr);
469
+ res.status(500).send("Error rendering page");
470
+ }
471
+ });
472
+ });
473
+
474
+ // Admin feature flags page (protected by basic auth)
475
+ router.get(`${adminPath}/feature-flags`, basicAuth, (req, res) => {
476
+ const templatePath = path.join(
477
+ __dirname,
478
+ "..",
479
+ "views",
480
+ "admin-feature-flags.ejs",
481
+ );
482
+ fs.readFile(templatePath, "utf8", (err, template) => {
483
+ if (err) {
484
+ console.error("Error reading template:", err);
485
+ return res.status(500).send("Error loading page");
486
+ }
487
+ try {
488
+ const html = ejs.render(
489
+ template,
490
+ {
491
+ baseUrl: req.baseUrl,
492
+ adminPath,
493
+ endpointRegistry,
494
+ },
495
+ {
496
+ filename: templatePath,
497
+ },
498
+ );
499
+ res.send(html);
500
+ } catch (renderErr) {
501
+ console.error("Error rendering template:", renderErr);
502
+ res.status(500).send("Error rendering page");
503
+ }
504
+ });
505
+ });
506
+
507
+ // Admin headless CMS page (protected by basic auth)
508
+ router.get(`${adminPath}/headless`, basicAuth, (req, res) => {
509
+ const templatePath = path.join(
510
+ __dirname,
511
+ "..",
512
+ "views",
513
+ "admin-headless.ejs",
514
+ );
515
+ fs.readFile(templatePath, "utf8", (err, template) => {
516
+ if (err) {
517
+ console.error("Error reading template:", err);
518
+ return res.status(500).send("Error loading page");
519
+ }
520
+ try {
521
+ const html = ejs.render(
522
+ template,
523
+ {
524
+ baseUrl: req.baseUrl,
525
+ adminPath,
526
+ endpointRegistry,
527
+ },
528
+ {
529
+ filename: templatePath,
530
+ },
531
+ );
532
+ res.send(html);
533
+ } catch (renderErr) {
534
+ console.error("Error rendering template:", renderErr);
535
+ res.status(500).send("Error rendering page");
536
+ }
537
+ });
538
+ });
539
+
540
+ // Admin JSON configs page (protected by basic auth)
541
+ router.get(`${adminPath}/json-configs`, basicAuth, (req, res) => {
542
+ const templatePath = path.join(
543
+ __dirname,
544
+ "..",
545
+ "views",
546
+ "admin-json-configs.ejs",
547
+ );
548
+ fs.readFile(templatePath, "utf8", (err, template) => {
549
+ if (err) {
550
+ console.error("Error reading template:", err);
551
+ return res.status(500).send("Error loading page");
552
+ }
553
+ try {
554
+ const html = ejs.render(
555
+ template,
556
+ {
557
+ baseUrl: req.baseUrl,
558
+ adminPath,
559
+ endpointRegistry,
560
+ },
561
+ {
562
+ filename: templatePath,
563
+ },
564
+ );
565
+ res.send(html);
566
+ } catch (renderErr) {
567
+ console.error("Error rendering template:", renderErr);
568
+ res.status(500).send("Error rendering page");
569
+ }
570
+ });
571
+ });
572
+
573
+ // Admin assets page (protected by basic auth)
574
+ router.get(`${adminPath}/assets`, basicAuth, (req, res) => {
575
+ const templatePath = path.join(
576
+ __dirname,
577
+ "..",
578
+ "views",
579
+ "admin-assets.ejs",
580
+ );
581
+ fs.readFile(templatePath, "utf8", (err, template) => {
582
+ if (err) {
583
+ console.error("Error reading template:", err);
584
+ return res.status(500).send("Error loading page");
585
+ }
586
+ try {
587
+ const html = ejs.render(
588
+ template,
589
+ {
590
+ baseUrl: req.baseUrl,
591
+ adminPath,
592
+ endpointRegistry,
593
+ },
594
+ {
595
+ filename: templatePath,
596
+ },
597
+ );
598
+ res.send(html);
599
+ } catch (renderErr) {
600
+ console.error("Error rendering template:", renderErr);
601
+ res.status(500).send("Error rendering page");
602
+ }
603
+ });
604
+ });
605
+
606
+ // Admin waiting list page (protected by basic auth)
607
+ router.get(`${adminPath}/waiting-list`, basicAuth, (req, res) => {
608
+ const templatePath = path.join(
609
+ __dirname,
610
+ "..",
611
+ "views",
612
+ "admin-waiting-list.ejs",
613
+ );
614
+ fs.readFile(templatePath, "utf8", (err, template) => {
615
+ if (err) {
616
+ console.error("Error reading template:", err);
617
+ return res.status(500).send("Error loading page");
618
+ }
619
+ try {
620
+ const html = ejs.render(template, {
621
+ baseUrl: req.baseUrl,
622
+ adminPath,
623
+ endpointRegistry,
624
+ });
625
+ res.send(html);
626
+ } catch (renderErr) {
627
+ console.error("Error rendering template:", renderErr);
628
+ res.status(500).send("Error rendering page");
629
+ }
630
+ });
631
+ });
632
+
633
+ // Admin organizations page (protected by basic auth)
634
+ router.get(`${adminPath}/organizations`, basicAuth, (req, res) => {
635
+ const templatePath = path.join(
636
+ __dirname,
637
+ "..",
638
+ "views",
639
+ "admin-organizations.ejs",
640
+ );
641
+ fs.readFile(templatePath, "utf8", (err, template) => {
642
+ if (err) {
643
+ console.error("Error reading template:", err);
644
+ return res.status(500).send("Error loading page");
645
+ }
646
+ try {
647
+ const html = ejs.render(
648
+ template,
649
+ {
650
+ baseUrl: req.baseUrl,
651
+ adminPath,
652
+ endpointRegistry,
653
+ },
654
+ {
655
+ filename: templatePath,
656
+ },
657
+ );
658
+ res.send(html);
659
+ } catch (renderErr) {
660
+ console.error("Error rendering template:", renderErr);
661
+ res.status(500).send("Error rendering page");
662
+ }
663
+ });
664
+ });
665
+
666
+ // Admin users page (protected by basic auth)
667
+ router.get(`${adminPath}/users`, basicAuth, (req, res) => {
668
+ const templatePath = path.join(
669
+ __dirname,
670
+ "..",
671
+ "views",
672
+ "admin-users.ejs",
673
+ );
674
+ fs.readFile(templatePath, "utf8", (err, template) => {
675
+ if (err) {
676
+ console.error("Error reading template:", err);
677
+ return res.status(500).send("Error loading page");
678
+ }
679
+ try {
680
+ const html = ejs.render(
681
+ template,
682
+ {
683
+ baseUrl: req.baseUrl,
684
+ adminPath,
685
+ endpointRegistry,
686
+ },
687
+ {
688
+ filename: templatePath,
689
+ },
690
+ );
691
+ res.send(html);
692
+ } catch (renderErr) {
693
+ console.error("Error rendering template:", renderErr);
694
+ res.status(500).send("Error rendering page");
695
+ }
696
+ });
697
+ });
698
+
699
+ // Admin notifications page (protected by basic auth)
700
+ router.get(`${adminPath}/notifications`, basicAuth, (req, res) => {
701
+ const templatePath = path.join(
702
+ __dirname,
703
+ "..",
704
+ "views",
705
+ "admin-notifications.ejs",
706
+ );
707
+ fs.readFile(templatePath, "utf8", (err, template) => {
708
+ if (err) {
709
+ console.error("Error reading template:", err);
710
+ return res.status(500).send("Error loading page");
711
+ }
712
+ try {
713
+ const html = ejs.render(
714
+ template,
715
+ {
716
+ baseUrl: req.baseUrl,
717
+ adminPath,
718
+ endpointRegistry,
719
+ },
720
+ {
721
+ filename: templatePath,
722
+ },
723
+ );
724
+ res.send(html);
725
+ } catch (renderErr) {
726
+ console.error("Error rendering template:", renderErr);
727
+ res.status(500).send("Error rendering page");
728
+ }
729
+ });
730
+ });
731
+
732
+ // Admin Stripe pricing page (protected by basic auth)
733
+ router.get(`${adminPath}/stripe-pricing`, basicAuth, (req, res) => {
734
+ const templatePath = path.join(
735
+ __dirname,
736
+ "..",
737
+ "views",
738
+ "admin-stripe-pricing.ejs",
739
+ );
740
+ fs.readFile(templatePath, "utf8", (err, template) => {
741
+ if (err) {
742
+ console.error("Error reading template:", err);
743
+ return res.status(500).send("Error loading page");
744
+ }
745
+ try {
746
+ const html = ejs.render(
747
+ template,
748
+ {
749
+ baseUrl: req.baseUrl,
750
+ adminPath,
751
+ endpointRegistry,
752
+ },
753
+ {
754
+ filename: templatePath,
755
+ },
756
+ );
757
+ res.send(html);
758
+ } catch (renderErr) {
759
+ console.error("Error rendering template:", renderErr);
760
+ res.status(500).send("Error rendering page");
761
+ }
762
+ });
763
+ });
764
+
765
+ // Admin metrics page (protected by basic auth)
766
+ router.get(`${adminPath}/metrics`, basicAuth, (req, res) => {
767
+ const templatePath = path.join(
768
+ __dirname,
769
+ "..",
770
+ "views",
771
+ "admin-metrics.ejs",
772
+ );
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(template, {
780
+ baseUrl: req.baseUrl,
781
+ adminPath,
782
+ endpointRegistry,
783
+ });
784
+ res.send(html);
785
+ } catch (renderErr) {
786
+ console.error("Error rendering template:", renderErr);
787
+ res.status(500).send("Error rendering page");
788
+ }
789
+ });
790
+ });
791
+
792
+ // Admin global settings page (protected by basic auth) - render manually
793
+ router.get(`${adminPath}/global-settings`, basicAuth, (req, res) => {
794
+ const templatePath = path.join(
795
+ __dirname,
796
+ "..",
797
+ "views",
798
+ "admin-global-settings.ejs",
799
+ );
800
+ fs.readFile(templatePath, "utf8", (err, template) => {
801
+ if (err) {
802
+ console.error("Error reading template:", err);
803
+ return res.status(500).send("Error loading page");
804
+ }
805
+ try {
806
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath });
807
+ res.send(html);
808
+ } catch (renderErr) {
809
+ console.error("Error rendering template:", renderErr);
810
+ res.status(500).send("Error rendering page");
811
+ }
812
+ });
813
+ });
814
+
815
+ router.get(`${adminPath}/errors`, basicAuth, (req, res) => {
816
+ const templatePath = path.join(__dirname, "..", "views", "admin-errors.ejs");
817
+ fs.readFile(templatePath, "utf8", (err, template) => {
818
+ if (err) {
819
+ console.error("Error reading template:", err);
820
+ return res.status(500).send("Error loading page");
821
+ }
822
+ try {
823
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
824
+ res.send(html);
825
+ } catch (renderErr) {
826
+ console.error("Error rendering template:", renderErr);
827
+ res.status(500).send("Error rendering page");
828
+ }
829
+ });
830
+ });
831
+
832
+ router.get(`${adminPath}/audit`, basicAuth, (req, res) => {
833
+ const templatePath = path.join(__dirname, "..", "views", "admin-audit.ejs");
834
+ fs.readFile(templatePath, "utf8", (err, template) => {
835
+ if (err) {
836
+ console.error("Error reading template:", err);
837
+ return res.status(500).send("Error loading page");
838
+ }
839
+ try {
840
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
841
+ res.send(html);
842
+ } catch (renderErr) {
843
+ console.error("Error rendering template:", renderErr);
844
+ res.status(500).send("Error rendering page");
845
+ }
846
+ });
847
+ });
848
+
849
+ router.get(`${adminPath}/coolify-deploy`, basicAuth, (req, res) => {
850
+ const templatePath = path.join(__dirname, "..", "views", "admin-coolify-deploy.ejs");
851
+ fs.readFile(templatePath, "utf8", (err, template) => {
852
+ if (err) {
853
+ console.error("Error reading template:", err);
854
+ return res.status(500).send("Error loading page");
855
+ }
856
+ try {
857
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
858
+ res.send(html);
859
+ } catch (renderErr) {
860
+ console.error("Error rendering template:", renderErr);
861
+ res.status(500).send("Error rendering page");
862
+ }
863
+ });
864
+ });
865
+
866
+ router.get(`${adminPath}/webhooks`, basicAuth, (req, res) => {
867
+ const templatePath = path.join(__dirname, "..", "views", "admin-webhooks.ejs");
868
+ fs.readFile(templatePath, "utf8", (err, template) => {
869
+ if (err) {
870
+ console.error("Error reading template:", err);
871
+ return res.status(500).send("Error loading page");
872
+ }
873
+ try {
874
+ const html = ejs.render(template, { baseUrl: req.baseUrl, adminPath }, { filename: templatePath });
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("/health", (req, res) => {
884
+ res.json({
885
+ status: "ok",
886
+ mode: "middleware",
887
+ database:
888
+ mongoose.connection.readyState === 1 ? "connected" : "disconnected",
889
+ });
890
+ });
891
+
892
+ router.use("/api/ejs-virtual", require("./routes/adminEjsVirtual.routes"));
893
+ router.use("/api/webhooks", require("./routes/webhook.routes"));
894
+
895
+ // Error handling middleware
896
+ router.use(expressErrorMiddleware);
897
+
898
+ return router;
899
+ }
900
+
901
+ module.exports = createMiddleware;