@intranefr/superbackend 1.6.6 → 1.6.7
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 +4 -0
- package/README.md +18 -0
- package/package.json +6 -1
- package/public/js/admin-superdemos.js +396 -0
- package/public/sdk/superdemos.iife.js +614 -0
- package/public/superdemos-qa.html +324 -0
- package/sdk/superdemos/browser/src/index.js +719 -0
- package/src/cli/agent-chat.js +369 -0
- package/src/cli/agent-list.js +42 -0
- package/src/controllers/adminAgentsChat.controller.js +172 -0
- package/src/controllers/adminSuperDemos.controller.js +382 -0
- package/src/controllers/superDemosPublic.controller.js +126 -0
- package/src/middleware.js +102 -19
- package/src/models/BlogAutomationLock.js +4 -4
- package/src/models/BlogPost.js +16 -16
- package/src/models/CacheEntry.js +17 -6
- package/src/models/JsonConfig.js +2 -4
- package/src/models/RateLimitMetricBucket.js +10 -5
- package/src/models/SuperDemo.js +38 -0
- package/src/models/SuperDemoProject.js +32 -0
- package/src/models/SuperDemoStep.js +27 -0
- package/src/routes/adminAgents.routes.js +10 -0
- package/src/routes/adminMarkdowns.routes.js +3 -0
- package/src/routes/adminSuperDemos.routes.js +31 -0
- package/src/routes/superDemos.routes.js +9 -0
- package/src/services/auditLogger.js +75 -37
- package/src/services/email.service.js +18 -3
- package/src/services/superDemosAuthoringSessions.service.js +132 -0
- package/src/services/superDemosWs.service.js +164 -0
- package/src/services/terminalsWs.service.js +35 -3
- package/src/utils/rbac/rightsRegistry.js +2 -0
- package/views/admin-agents.ejs +261 -11
- package/views/admin-dashboard.ejs +78 -8
- package/views/admin-superdemos.ejs +335 -0
- package/views/admin-terminals.ejs +462 -34
- package/views/partials/admin/agents-chat.ejs +80 -0
- package/views/partials/dashboard/nav-items.ejs +1 -0
- package/views/partials/dashboard/tab-bar.ejs +6 -0
- package/cookies.txt +0 -6
- package/cookies1.txt +0 -6
- package/cookies2.txt +0 -6
- package/cookies3.txt +0 -6
- package/cookies4.txt +0 -5
- package/cookies_old.txt +0 -5
- package/cookies_old_test.txt +0 -6
- package/cookies_super.txt +0 -5
- package/cookies_super_test.txt +0 -6
- package/cookies_test.txt +0 -6
- package/test-access.js +0 -63
- package/test-iframe-fix.html +0 -63
- package/test-iframe.html +0 -14
package/src/middleware.js
CHANGED
|
@@ -26,7 +26,7 @@ const ejs = require("ejs");
|
|
|
26
26
|
const session = require("express-session");
|
|
27
27
|
const MongoStore = require("connect-mongo");
|
|
28
28
|
const { adminSessionAuth } = require("./middleware/auth");
|
|
29
|
-
const { requireModuleAccess } = require("./middleware/rbac");
|
|
29
|
+
const { requireModuleAccess, isBasicAuthSuperAdmin } = require("./middleware/rbac");
|
|
30
30
|
const endpointRegistry = require("./admin/endpointRegistry");
|
|
31
31
|
const {
|
|
32
32
|
createFeatureFlagsEjsMiddleware,
|
|
@@ -96,6 +96,7 @@ function createMiddleware(options = {}) {
|
|
|
96
96
|
const router = express.Router();
|
|
97
97
|
const adminPath = options.adminPath || "/admin";
|
|
98
98
|
const pagesPrefix = options.pagesPrefix || "/";
|
|
99
|
+
const isJest = Boolean(process.env.JEST_WORKER_ID);
|
|
99
100
|
|
|
100
101
|
const bootstrapPluginsRuntime = async () => {
|
|
101
102
|
try {
|
|
@@ -209,6 +210,11 @@ function createMiddleware(options = {}) {
|
|
|
209
210
|
attachExperimentsWebsocketServer,
|
|
210
211
|
} = require("./services/experimentsWs.service");
|
|
211
212
|
attachExperimentsWebsocketServer(server);
|
|
213
|
+
|
|
214
|
+
const {
|
|
215
|
+
attachSuperDemosWebsocketServer,
|
|
216
|
+
} = require("./services/superDemosWs.service");
|
|
217
|
+
attachSuperDemosWebsocketServer(server);
|
|
212
218
|
};
|
|
213
219
|
|
|
214
220
|
if (!errorCaptureInitialized) {
|
|
@@ -243,19 +249,19 @@ function createMiddleware(options = {}) {
|
|
|
243
249
|
console.log("✅ Middleware: Connected to MongoDB");
|
|
244
250
|
|
|
245
251
|
// Start cron scheduler after DB connection (only if enabled)
|
|
246
|
-
if (options.cron?.enabled !== false) {
|
|
252
|
+
if (!isJest && options.cron?.enabled !== false) {
|
|
247
253
|
await cronScheduler.start();
|
|
248
254
|
await healthChecksScheduler.start();
|
|
249
255
|
await healthChecksBootstrap.bootstrap();
|
|
250
256
|
await blogCronsBootstrap.bootstrap();
|
|
251
257
|
await require("./services/experimentsCronsBootstrap.service").bootstrap();
|
|
252
258
|
} else {
|
|
253
|
-
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled);
|
|
259
|
+
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled, isJest ? '(jest)' : '');
|
|
254
260
|
}
|
|
255
261
|
|
|
256
262
|
// Initialize Telegram bots (check telegram config)
|
|
257
263
|
const telegramEnabled = options.telegram?.enabled !== false;
|
|
258
|
-
if (telegramEnabled) {
|
|
264
|
+
if (!isJest && telegramEnabled) {
|
|
259
265
|
const telegramInitializer =
|
|
260
266
|
(telegramService && typeof telegramService.initialize === "function"
|
|
261
267
|
? telegramService.initialize.bind(telegramService)
|
|
@@ -273,7 +279,9 @@ function createMiddleware(options = {}) {
|
|
|
273
279
|
console.log("🔍 Telegram bots disabled - telegram.enabled:", options.telegram?.enabled);
|
|
274
280
|
}
|
|
275
281
|
|
|
276
|
-
|
|
282
|
+
if (!isJest) {
|
|
283
|
+
await bootstrapPluginsRuntime();
|
|
284
|
+
}
|
|
277
285
|
|
|
278
286
|
// Console manager is already initialized early in the middleware
|
|
279
287
|
console.log("[Console Manager] MongoDB connection established");
|
|
@@ -387,7 +395,7 @@ function createMiddleware(options = {}) {
|
|
|
387
395
|
console.log("✅ Middleware: Using existing MongoDB connection");
|
|
388
396
|
|
|
389
397
|
// Start cron scheduler for existing connection (only if enabled)
|
|
390
|
-
if (options.cron?.enabled !== false) {
|
|
398
|
+
if (!isJest && options.cron?.enabled !== false) {
|
|
391
399
|
cronScheduler.start().catch((err) => {
|
|
392
400
|
console.error("Failed to start cron scheduler:", err);
|
|
393
401
|
});
|
|
@@ -407,12 +415,12 @@ function createMiddleware(options = {}) {
|
|
|
407
415
|
console.error("Failed to bootstrap experiments crons:", err);
|
|
408
416
|
});
|
|
409
417
|
} else {
|
|
410
|
-
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled, "(existing connection)");
|
|
418
|
+
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled, "(existing connection)", isJest ? '(jest)' : '');
|
|
411
419
|
}
|
|
412
420
|
|
|
413
421
|
// Initialize Telegram bots for existing connection (check telegram config)
|
|
414
422
|
const telegramEnabled = options.telegram?.enabled !== false;
|
|
415
|
-
if (telegramEnabled) {
|
|
423
|
+
if (!isJest && telegramEnabled) {
|
|
416
424
|
const telegramInitializer =
|
|
417
425
|
(telegramService && typeof telegramService.initialize === "function"
|
|
418
426
|
? telegramService.initialize.bind(telegramService)
|
|
@@ -432,9 +440,11 @@ function createMiddleware(options = {}) {
|
|
|
432
440
|
console.log("🔍 Telegram bots disabled - telegram.enabled:", options.telegram?.enabled, "(existing connection)");
|
|
433
441
|
}
|
|
434
442
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
443
|
+
if (!isJest) {
|
|
444
|
+
bootstrapPluginsRuntime().catch((err) => {
|
|
445
|
+
console.error("Failed to bootstrap plugins runtime (existing connection):", err);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
438
448
|
|
|
439
449
|
// Initialize console manager AFTER database is already connected
|
|
440
450
|
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
@@ -530,6 +540,15 @@ function createMiddleware(options = {}) {
|
|
|
530
540
|
}
|
|
531
541
|
|
|
532
542
|
// Session middleware for admin authentication
|
|
543
|
+
const sessionMongoUrl = options.mongodbUri || process.env.MONGODB_URI || process.env.MONGO_URI;
|
|
544
|
+
const sessionStore = !isJest && sessionMongoUrl
|
|
545
|
+
? MongoStore.create({
|
|
546
|
+
mongoUrl: sessionMongoUrl,
|
|
547
|
+
collectionName: 'admin_sessions',
|
|
548
|
+
ttl: 24 * 60 * 60 // 24 hours in seconds
|
|
549
|
+
})
|
|
550
|
+
: undefined;
|
|
551
|
+
|
|
533
552
|
const sessionMiddleware = session({
|
|
534
553
|
secret: process.env.SESSION_SECRET || 'superbackend-session-secret-fallback',
|
|
535
554
|
resave: false,
|
|
@@ -540,11 +559,7 @@ function createMiddleware(options = {}) {
|
|
|
540
559
|
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
541
560
|
sameSite: 'lax'
|
|
542
561
|
},
|
|
543
|
-
store:
|
|
544
|
-
mongoUrl: options.mongodbUri || process.env.MONGODB_URI,
|
|
545
|
-
collectionName: 'admin_sessions',
|
|
546
|
-
ttl: 24 * 60 * 60 // 24 hours in seconds
|
|
547
|
-
}),
|
|
562
|
+
store: sessionStore,
|
|
548
563
|
name: 'superbackend.admin.session'
|
|
549
564
|
});
|
|
550
565
|
|
|
@@ -858,7 +873,8 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
858
873
|
baseUrl: req.baseUrl,
|
|
859
874
|
adminPath,
|
|
860
875
|
endpointRegistry,
|
|
861
|
-
isIframe: req.isIframe || false
|
|
876
|
+
isIframe: req.isIframe || false,
|
|
877
|
+
serverPort: process.env.PORT || 3000
|
|
862
878
|
},
|
|
863
879
|
{
|
|
864
880
|
filename: templatePath,
|
|
@@ -1110,6 +1126,10 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1110
1126
|
"/api/admin/ui-components",
|
|
1111
1127
|
require("./routes/adminUiComponents.routes"),
|
|
1112
1128
|
);
|
|
1129
|
+
router.use(
|
|
1130
|
+
"/api/admin/superdemos",
|
|
1131
|
+
require("./routes/adminSuperDemos.routes"),
|
|
1132
|
+
);
|
|
1113
1133
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
1114
1134
|
router.use(
|
|
1115
1135
|
"/api/admin/errors",
|
|
@@ -1151,6 +1171,7 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1151
1171
|
router.use("/api/log", require("./routes/log.routes"));
|
|
1152
1172
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
1153
1173
|
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
1174
|
+
router.use("/api/superdemos", require("./routes/superDemos.routes"));
|
|
1154
1175
|
router.use("/api/rbac", require("./routes/rbac.routes"));
|
|
1155
1176
|
router.use("/registry", require("./routes/registry.routes"));
|
|
1156
1177
|
router.use("/api/file-manager", require("./routes/fileManager.routes"));
|
|
@@ -1181,13 +1202,36 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1181
1202
|
}, require("./routes/adminLogin.routes"));
|
|
1182
1203
|
|
|
1183
1204
|
// Admin dashboard (redirect to login if not authenticated)
|
|
1184
|
-
router.get(adminPath, adminSessionAuth, (req, res) => {
|
|
1205
|
+
router.get(adminPath, adminSessionAuth, async (req, res) => {
|
|
1185
1206
|
const templatePath = path.join(
|
|
1186
1207
|
__dirname,
|
|
1187
1208
|
"..",
|
|
1188
1209
|
"views",
|
|
1189
1210
|
"admin-dashboard.ejs",
|
|
1190
1211
|
);
|
|
1212
|
+
|
|
1213
|
+
// Get max tabs configuration
|
|
1214
|
+
let maxTabs = 5; // default
|
|
1215
|
+
try {
|
|
1216
|
+
// Environment variable takes priority
|
|
1217
|
+
if (process.env.ADMIN_MAX_TABS) {
|
|
1218
|
+
const envValue = parseInt(process.env.ADMIN_MAX_TABS, 10);
|
|
1219
|
+
if (!isNaN(envValue) && envValue > 0) {
|
|
1220
|
+
maxTabs = envValue;
|
|
1221
|
+
}
|
|
1222
|
+
} else {
|
|
1223
|
+
// Fallback to global settings
|
|
1224
|
+
const settingValue = await globalSettingsService.getSettingValue("ADMIN_MAX_TABS", "5");
|
|
1225
|
+
const parsedValue = parseInt(settingValue, 10);
|
|
1226
|
+
if (!isNaN(parsedValue) && parsedValue > 0) {
|
|
1227
|
+
maxTabs = parsedValue;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
console.error("Error fetching max tabs configuration:", error);
|
|
1232
|
+
// Use default value
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1191
1235
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1192
1236
|
if (err) {
|
|
1193
1237
|
console.error("Error reading template:", err);
|
|
@@ -1196,7 +1240,12 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1196
1240
|
try {
|
|
1197
1241
|
const html = ejs.render(
|
|
1198
1242
|
template,
|
|
1199
|
-
{
|
|
1243
|
+
{
|
|
1244
|
+
baseUrl: req.baseUrl,
|
|
1245
|
+
adminPath,
|
|
1246
|
+
isIframe: req.isIframe || false,
|
|
1247
|
+
maxTabs
|
|
1248
|
+
},
|
|
1200
1249
|
{ filename: templatePath },
|
|
1201
1250
|
);
|
|
1202
1251
|
res.send(html);
|
|
@@ -1729,6 +1778,40 @@ router.get(`${adminPath}/file-manager`, requireModuleAccessWithIframe('file-mana
|
|
|
1729
1778
|
});
|
|
1730
1779
|
});
|
|
1731
1780
|
|
|
1781
|
+
// Admin SuperDemos page
|
|
1782
|
+
router.get(`${adminPath}/superdemos`, requireModuleAccessWithIframe('superdemos', 'read'), (req, res) => {
|
|
1783
|
+
const templatePath = path.join(
|
|
1784
|
+
__dirname,
|
|
1785
|
+
"..",
|
|
1786
|
+
"views",
|
|
1787
|
+
"admin-superdemos.ejs",
|
|
1788
|
+
);
|
|
1789
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1790
|
+
if (err) {
|
|
1791
|
+
console.error("Error reading template:", err);
|
|
1792
|
+
return res.status(500).send("Error loading page");
|
|
1793
|
+
}
|
|
1794
|
+
try {
|
|
1795
|
+
const html = ejs.render(
|
|
1796
|
+
template,
|
|
1797
|
+
{
|
|
1798
|
+
baseUrl: req.baseUrl || '',
|
|
1799
|
+
adminPath,
|
|
1800
|
+
endpointRegistry,
|
|
1801
|
+
isIframe: req.isIframe || false,
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
filename: templatePath,
|
|
1805
|
+
},
|
|
1806
|
+
);
|
|
1807
|
+
res.send(html);
|
|
1808
|
+
} catch (renderErr) {
|
|
1809
|
+
console.error("Error rendering template:", renderErr);
|
|
1810
|
+
res.status(500).send("Error rendering page");
|
|
1811
|
+
}
|
|
1812
|
+
});
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1732
1815
|
// Admin JSON configs page (protected by basic auth)
|
|
1733
1816
|
router.get(`${adminPath}/json-configs`, requireModuleAccessWithIframe('json-configs', 'read'), (req, res) => {
|
|
1734
1817
|
const templatePath = path.join(
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const mongoose = require(
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
2
|
|
|
3
3
|
const blogAutomationLockSchema = new mongoose.Schema(
|
|
4
4
|
{
|
|
5
|
-
key: { type: String, required: true, unique: true
|
|
5
|
+
key: { type: String, required: true, unique: true },
|
|
6
6
|
lockedUntil: { type: Date, required: true },
|
|
7
7
|
ownerId: { type: String, required: true },
|
|
8
8
|
},
|
|
9
|
-
{ timestamps: true, collection:
|
|
9
|
+
{ timestamps: true, collection: "blog_automation_locks" },
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
module.exports =
|
|
13
13
|
mongoose.models.BlogAutomationLock ||
|
|
14
|
-
mongoose.model(
|
|
14
|
+
mongoose.model("BlogAutomationLock", blogAutomationLockSchema);
|
package/src/models/BlogPost.js
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
const mongoose = require(
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
2
|
|
|
3
3
|
const blogPostSchema = new mongoose.Schema(
|
|
4
4
|
{
|
|
5
5
|
title: { type: String, required: true },
|
|
6
|
-
slug: { type: String, required: true
|
|
6
|
+
slug: { type: String, required: true },
|
|
7
7
|
status: {
|
|
8
8
|
type: String,
|
|
9
|
-
enum: [
|
|
10
|
-
default:
|
|
11
|
-
index: true,
|
|
9
|
+
enum: ["draft", "scheduled", "published", "archived"],
|
|
10
|
+
default: "draft",
|
|
12
11
|
},
|
|
13
|
-
excerpt: { type: String, default:
|
|
14
|
-
markdown: { type: String, default:
|
|
15
|
-
html: { type: String, default:
|
|
16
|
-
coverImageUrl: { type: String, default:
|
|
17
|
-
category: { type: String, default:
|
|
12
|
+
excerpt: { type: String, default: "" },
|
|
13
|
+
markdown: { type: String, default: "" },
|
|
14
|
+
html: { type: String, default: "" },
|
|
15
|
+
coverImageUrl: { type: String, default: "" },
|
|
16
|
+
category: { type: String, default: "" },
|
|
18
17
|
tags: { type: [String], default: [] },
|
|
19
|
-
authorName: { type: String, default:
|
|
20
|
-
seoTitle: { type: String, default:
|
|
21
|
-
seoDescription: { type: String, default:
|
|
18
|
+
authorName: { type: String, default: "" },
|
|
19
|
+
seoTitle: { type: String, default: "" },
|
|
20
|
+
seoDescription: { type: String, default: "" },
|
|
22
21
|
scheduledAt: { type: Date },
|
|
23
22
|
publishedAt: { type: Date },
|
|
24
23
|
},
|
|
25
|
-
{ timestamps: true, collection:
|
|
24
|
+
{ timestamps: true, collection: "blog_posts" },
|
|
26
25
|
);
|
|
27
26
|
|
|
28
27
|
blogPostSchema.index({ status: 1, publishedAt: -1 });
|
|
@@ -34,9 +33,10 @@ blogPostSchema.index(
|
|
|
34
33
|
{
|
|
35
34
|
unique: true,
|
|
36
35
|
partialFilterExpression: {
|
|
37
|
-
status: { $in: [
|
|
36
|
+
status: { $in: ["draft", "scheduled", "published"] },
|
|
38
37
|
},
|
|
39
38
|
},
|
|
40
39
|
);
|
|
41
40
|
|
|
42
|
-
module.exports =
|
|
41
|
+
module.exports =
|
|
42
|
+
mongoose.models.BlogPost || mongoose.model("BlogPost", blogPostSchema);
|
package/src/models/CacheEntry.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
const mongoose = require(
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
2
|
|
|
3
3
|
const cacheEntrySchema = new mongoose.Schema(
|
|
4
4
|
{
|
|
5
5
|
namespace: { type: String, required: true, index: true },
|
|
6
|
-
key: { type: String, required: true
|
|
6
|
+
key: { type: String, required: true },
|
|
7
7
|
|
|
8
8
|
value: { type: String, required: true },
|
|
9
|
-
atRestFormat: {
|
|
9
|
+
atRestFormat: {
|
|
10
|
+
type: String,
|
|
11
|
+
enum: ["string", "base64"],
|
|
12
|
+
default: "string",
|
|
13
|
+
index: true,
|
|
14
|
+
},
|
|
10
15
|
|
|
11
16
|
sizeBytes: { type: Number, default: 0 },
|
|
12
17
|
|
|
@@ -15,12 +20,18 @@ const cacheEntrySchema = new mongoose.Schema(
|
|
|
15
20
|
hits: { type: Number, default: 0 },
|
|
16
21
|
lastAccessAt: { type: Date, default: null },
|
|
17
22
|
|
|
18
|
-
source: {
|
|
23
|
+
source: {
|
|
24
|
+
type: String,
|
|
25
|
+
enum: ["offloaded", "manual"],
|
|
26
|
+
default: "manual",
|
|
27
|
+
index: true,
|
|
28
|
+
},
|
|
19
29
|
},
|
|
20
|
-
{ timestamps: true, collection:
|
|
30
|
+
{ timestamps: true, collection: "cache_entries" },
|
|
21
31
|
);
|
|
22
32
|
|
|
23
33
|
cacheEntrySchema.index({ namespace: 1, key: 1 }, { unique: true });
|
|
24
34
|
cacheEntrySchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
25
35
|
|
|
26
|
-
module.exports =
|
|
36
|
+
module.exports =
|
|
37
|
+
mongoose.models.CacheEntry || mongoose.model("CacheEntry", cacheEntrySchema);
|
package/src/models/JsonConfig.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const mongoose = require(
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
2
|
|
|
3
3
|
const jsonConfigSchema = new mongoose.Schema(
|
|
4
4
|
{
|
|
@@ -10,13 +10,11 @@ const jsonConfigSchema = new mongoose.Schema(
|
|
|
10
10
|
type: String,
|
|
11
11
|
required: true,
|
|
12
12
|
unique: true,
|
|
13
|
-
index: true,
|
|
14
13
|
},
|
|
15
14
|
alias: {
|
|
16
15
|
type: String,
|
|
17
16
|
unique: true,
|
|
18
17
|
sparse: true,
|
|
19
|
-
index: true,
|
|
20
18
|
},
|
|
21
19
|
publicEnabled: {
|
|
22
20
|
type: Boolean,
|
|
@@ -43,4 +41,4 @@ const jsonConfigSchema = new mongoose.Schema(
|
|
|
43
41
|
// jsonConfigSchema.index({ slug: 1 }); // Removed duplicate index
|
|
44
42
|
// jsonConfigSchema.index({ alias: 1 }); // Removed duplicate index
|
|
45
43
|
|
|
46
|
-
module.exports = mongoose.model(
|
|
44
|
+
module.exports = mongoose.model("JsonConfig", jsonConfigSchema);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const mongoose = require(
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
2
|
|
|
3
3
|
const rateLimitMetricBucketSchema = new mongoose.Schema(
|
|
4
4
|
{
|
|
@@ -9,12 +9,17 @@ const rateLimitMetricBucketSchema = new mongoose.Schema(
|
|
|
9
9
|
allowed: { type: Number, default: 0 },
|
|
10
10
|
blocked: { type: Number, default: 0 },
|
|
11
11
|
|
|
12
|
-
expiresAt: { type: Date, default: null
|
|
12
|
+
expiresAt: { type: Date, default: null },
|
|
13
13
|
},
|
|
14
|
-
{ timestamps: true, collection:
|
|
14
|
+
{ timestamps: true, collection: "rate_limit_metric_buckets" },
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
rateLimitMetricBucketSchema.index(
|
|
17
|
+
rateLimitMetricBucketSchema.index(
|
|
18
|
+
{ limiterId: 1, bucketStart: 1 },
|
|
19
|
+
{ unique: true },
|
|
20
|
+
);
|
|
18
21
|
rateLimitMetricBucketSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
19
22
|
|
|
20
|
-
module.exports =
|
|
23
|
+
module.exports =
|
|
24
|
+
mongoose.models.RateLimitMetricBucket ||
|
|
25
|
+
mongoose.model("RateLimitMetricBucket", rateLimitMetricBucketSchema);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const superDemoSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
demoId: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
unique: true,
|
|
9
|
+
index: true,
|
|
10
|
+
trim: true,
|
|
11
|
+
match: [/^demo_[a-z0-9]{8,32}$/, 'Invalid demoId'],
|
|
12
|
+
},
|
|
13
|
+
projectId: { type: String, required: true, index: true, trim: true },
|
|
14
|
+
|
|
15
|
+
name: { type: String, required: true, trim: true },
|
|
16
|
+
|
|
17
|
+
status: {
|
|
18
|
+
type: String,
|
|
19
|
+
enum: ['draft', 'published'],
|
|
20
|
+
default: 'draft',
|
|
21
|
+
index: true,
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
publishedVersion: { type: Number, default: 0 },
|
|
25
|
+
publishedAt: { type: Date, default: null },
|
|
26
|
+
|
|
27
|
+
// Minimal targeting for v1.
|
|
28
|
+
// Interpreted as a substring match against window.location.href unless otherwise specified.
|
|
29
|
+
startUrlPattern: { type: String, default: null },
|
|
30
|
+
|
|
31
|
+
isActive: { type: Boolean, default: true, index: true },
|
|
32
|
+
},
|
|
33
|
+
{ timestamps: true, collection: 'super_demos' },
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
superDemoSchema.index({ projectId: 1, status: 1, isActive: 1 });
|
|
37
|
+
|
|
38
|
+
module.exports = mongoose.models.SuperDemo || mongoose.model('SuperDemo', superDemoSchema);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const superDemoProjectSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
projectId: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
unique: true,
|
|
9
|
+
index: true,
|
|
10
|
+
trim: true,
|
|
11
|
+
match: [/^sdp_[a-z0-9]{8,32}$/, 'Invalid projectId'],
|
|
12
|
+
},
|
|
13
|
+
name: { type: String, required: true, trim: true },
|
|
14
|
+
|
|
15
|
+
isPublic: { type: Boolean, default: true, index: true },
|
|
16
|
+
apiKeyHash: { type: String, default: null },
|
|
17
|
+
|
|
18
|
+
allowedOrigins: { type: [String], default: [] },
|
|
19
|
+
stylePreset: {
|
|
20
|
+
type: String,
|
|
21
|
+
enum: ['default', 'glass-dark', 'high-contrast', 'soft-purple'],
|
|
22
|
+
default: 'default',
|
|
23
|
+
},
|
|
24
|
+
styleOverrides: { type: String, default: '' },
|
|
25
|
+
|
|
26
|
+
isActive: { type: Boolean, default: true, index: true },
|
|
27
|
+
},
|
|
28
|
+
{ timestamps: true, collection: 'super_demo_projects' },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
module.exports = mongoose.models.SuperDemoProject ||
|
|
32
|
+
mongoose.model('SuperDemoProject', superDemoProjectSchema);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const superDemoStepSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
demoId: { type: String, required: true, index: true, trim: true },
|
|
6
|
+
order: { type: Number, required: true, index: true },
|
|
7
|
+
|
|
8
|
+
selector: { type: String, required: true },
|
|
9
|
+
selectorHints: { type: mongoose.Schema.Types.Mixed, default: null },
|
|
10
|
+
|
|
11
|
+
message: { type: String, required: true },
|
|
12
|
+
placement: {
|
|
13
|
+
type: String,
|
|
14
|
+
enum: ['top', 'bottom', 'left', 'right', 'auto'],
|
|
15
|
+
default: 'auto',
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
waitFor: { type: mongoose.Schema.Types.Mixed, default: null },
|
|
19
|
+
advance: { type: mongoose.Schema.Types.Mixed, default: { type: 'manualNext' } },
|
|
20
|
+
},
|
|
21
|
+
{ timestamps: true, collection: 'super_demo_steps' },
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
superDemoStepSchema.index({ demoId: 1, order: 1 }, { unique: true });
|
|
25
|
+
|
|
26
|
+
module.exports = mongoose.models.SuperDemoStep ||
|
|
27
|
+
mongoose.model('SuperDemoStep', superDemoStepSchema);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
3
|
const adminAgentsController = require('../controllers/adminAgents.controller');
|
|
4
|
+
const adminAgentsChatController = require('../controllers/adminAgentsChat.controller');
|
|
4
5
|
const { adminSessionAuth } = require('../middleware/auth');
|
|
5
6
|
|
|
6
7
|
router.use(adminSessionAuth);
|
|
@@ -10,4 +11,13 @@ router.post('/', adminAgentsController.createAgent);
|
|
|
10
11
|
router.put('/:id', adminAgentsController.updateAgent);
|
|
11
12
|
router.delete('/:id', adminAgentsController.deleteAgent);
|
|
12
13
|
|
|
14
|
+
router.post('/chat/session/new', adminAgentsChatController.newSession);
|
|
15
|
+
router.get('/chat/sessions', adminAgentsChatController.listSessions);
|
|
16
|
+
router.post('/chat/session/rename', adminAgentsChatController.renameSession);
|
|
17
|
+
router.post('/chat/session/compact', adminAgentsChatController.compactSession);
|
|
18
|
+
router.get('/chat/session/:chatId/messages', adminAgentsChatController.loadSessionMessages);
|
|
19
|
+
router.post('/chat/message', adminAgentsChatController.sendMessage);
|
|
20
|
+
router.post('/chat/stream', adminAgentsChatController.streamMessage);
|
|
21
|
+
router.get('/chat/health', adminAgentsChatController.chatHealth);
|
|
22
|
+
|
|
13
23
|
module.exports = router;
|
|
@@ -5,6 +5,9 @@ const { adminSessionAuth } = require('../middleware/auth');
|
|
|
5
5
|
const adminMarkdownsController = require('../controllers/adminMarkdowns.controller');
|
|
6
6
|
|
|
7
7
|
router.use(adminSessionAuth);
|
|
8
|
+
router.get('/', adminMarkdownsController.list);
|
|
9
|
+
router.get('/group-codes/:category', adminMarkdownsController.getGroupCodes);
|
|
10
|
+
router.get('/folder/:category/:group_code', adminMarkdownsController.getFolderContents);
|
|
8
11
|
router.post('/validate-path', adminSessionAuth, adminMarkdownsController.validatePath);
|
|
9
12
|
|
|
10
13
|
module.exports = router;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const { adminSessionAuth } = require('../middleware/auth');
|
|
5
|
+
const controller = require('../controllers/adminSuperDemos.controller');
|
|
6
|
+
|
|
7
|
+
router.use(express.json({ limit: '1mb' }));
|
|
8
|
+
router.use(adminSessionAuth);
|
|
9
|
+
|
|
10
|
+
// Projects
|
|
11
|
+
router.get('/projects', controller.listProjects);
|
|
12
|
+
router.post('/projects', controller.createProject);
|
|
13
|
+
router.put('/projects/:projectId', controller.updateProject);
|
|
14
|
+
router.post('/projects/:projectId/rotate-key', controller.rotateProjectKey);
|
|
15
|
+
|
|
16
|
+
// Demos
|
|
17
|
+
router.get('/projects/:projectId/demos', controller.listProjectDemos);
|
|
18
|
+
router.post('/projects/:projectId/demos', controller.createDemo);
|
|
19
|
+
router.get('/demos/:demoId', controller.getDemo);
|
|
20
|
+
router.put('/demos/:demoId', controller.updateDemo);
|
|
21
|
+
router.post('/demos/:demoId/publish', controller.publishDemo);
|
|
22
|
+
|
|
23
|
+
// Steps
|
|
24
|
+
router.get('/demos/:demoId/steps', controller.listSteps);
|
|
25
|
+
router.put('/demos/:demoId/steps', controller.replaceSteps);
|
|
26
|
+
|
|
27
|
+
// Authoring sessions
|
|
28
|
+
router.post('/authoring-sessions', controller.createAuthoringSession);
|
|
29
|
+
router.delete('/authoring-sessions/:sessionId', controller.deleteAuthoringSession);
|
|
30
|
+
|
|
31
|
+
module.exports = router;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const controller = require('../controllers/superDemosPublic.controller');
|
|
5
|
+
|
|
6
|
+
router.get('/projects/:projectId/demos/published', controller.listPublishedDemos);
|
|
7
|
+
router.get('/demos/:demoId/definition', controller.getPublishedDemoDefinition);
|
|
8
|
+
|
|
9
|
+
module.exports = router;
|