@intranefr/superbackend 1.6.5 → 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 +108 -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/llm.service.js +1 -0
- package/src/services/plugins.service.js +50 -16
- 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,9 +96,16 @@ 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 {
|
|
103
|
+
if (options.plugins?.extraRoots) {
|
|
104
|
+
const roots = Array.isArray(options.plugins.extraRoots) ? options.plugins.extraRoots : [];
|
|
105
|
+
for (const root of roots) {
|
|
106
|
+
await pluginsService.loadAllPluginsFromFolder(root, { context: {} });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
102
109
|
const superbackend = globalThis.superbackend || globalThis.saasbackend || {};
|
|
103
110
|
await pluginsService.bootstrap({
|
|
104
111
|
context: {
|
|
@@ -203,6 +210,11 @@ function createMiddleware(options = {}) {
|
|
|
203
210
|
attachExperimentsWebsocketServer,
|
|
204
211
|
} = require("./services/experimentsWs.service");
|
|
205
212
|
attachExperimentsWebsocketServer(server);
|
|
213
|
+
|
|
214
|
+
const {
|
|
215
|
+
attachSuperDemosWebsocketServer,
|
|
216
|
+
} = require("./services/superDemosWs.service");
|
|
217
|
+
attachSuperDemosWebsocketServer(server);
|
|
206
218
|
};
|
|
207
219
|
|
|
208
220
|
if (!errorCaptureInitialized) {
|
|
@@ -237,19 +249,19 @@ function createMiddleware(options = {}) {
|
|
|
237
249
|
console.log("✅ Middleware: Connected to MongoDB");
|
|
238
250
|
|
|
239
251
|
// Start cron scheduler after DB connection (only if enabled)
|
|
240
|
-
if (options.cron?.enabled !== false) {
|
|
252
|
+
if (!isJest && options.cron?.enabled !== false) {
|
|
241
253
|
await cronScheduler.start();
|
|
242
254
|
await healthChecksScheduler.start();
|
|
243
255
|
await healthChecksBootstrap.bootstrap();
|
|
244
256
|
await blogCronsBootstrap.bootstrap();
|
|
245
257
|
await require("./services/experimentsCronsBootstrap.service").bootstrap();
|
|
246
258
|
} else {
|
|
247
|
-
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled);
|
|
259
|
+
console.log("🔍 Cron scheduler disabled - cron.enabled:", options.cron?.enabled, isJest ? '(jest)' : '');
|
|
248
260
|
}
|
|
249
261
|
|
|
250
262
|
// Initialize Telegram bots (check telegram config)
|
|
251
263
|
const telegramEnabled = options.telegram?.enabled !== false;
|
|
252
|
-
if (telegramEnabled) {
|
|
264
|
+
if (!isJest && telegramEnabled) {
|
|
253
265
|
const telegramInitializer =
|
|
254
266
|
(telegramService && typeof telegramService.initialize === "function"
|
|
255
267
|
? telegramService.initialize.bind(telegramService)
|
|
@@ -267,7 +279,9 @@ function createMiddleware(options = {}) {
|
|
|
267
279
|
console.log("🔍 Telegram bots disabled - telegram.enabled:", options.telegram?.enabled);
|
|
268
280
|
}
|
|
269
281
|
|
|
270
|
-
|
|
282
|
+
if (!isJest) {
|
|
283
|
+
await bootstrapPluginsRuntime();
|
|
284
|
+
}
|
|
271
285
|
|
|
272
286
|
// Console manager is already initialized early in the middleware
|
|
273
287
|
console.log("[Console Manager] MongoDB connection established");
|
|
@@ -381,7 +395,7 @@ function createMiddleware(options = {}) {
|
|
|
381
395
|
console.log("✅ Middleware: Using existing MongoDB connection");
|
|
382
396
|
|
|
383
397
|
// Start cron scheduler for existing connection (only if enabled)
|
|
384
|
-
if (options.cron?.enabled !== false) {
|
|
398
|
+
if (!isJest && options.cron?.enabled !== false) {
|
|
385
399
|
cronScheduler.start().catch((err) => {
|
|
386
400
|
console.error("Failed to start cron scheduler:", err);
|
|
387
401
|
});
|
|
@@ -401,12 +415,12 @@ function createMiddleware(options = {}) {
|
|
|
401
415
|
console.error("Failed to bootstrap experiments crons:", err);
|
|
402
416
|
});
|
|
403
417
|
} else {
|
|
404
|
-
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)' : '');
|
|
405
419
|
}
|
|
406
420
|
|
|
407
421
|
// Initialize Telegram bots for existing connection (check telegram config)
|
|
408
422
|
const telegramEnabled = options.telegram?.enabled !== false;
|
|
409
|
-
if (telegramEnabled) {
|
|
423
|
+
if (!isJest && telegramEnabled) {
|
|
410
424
|
const telegramInitializer =
|
|
411
425
|
(telegramService && typeof telegramService.initialize === "function"
|
|
412
426
|
? telegramService.initialize.bind(telegramService)
|
|
@@ -426,9 +440,11 @@ function createMiddleware(options = {}) {
|
|
|
426
440
|
console.log("🔍 Telegram bots disabled - telegram.enabled:", options.telegram?.enabled, "(existing connection)");
|
|
427
441
|
}
|
|
428
442
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
443
|
+
if (!isJest) {
|
|
444
|
+
bootstrapPluginsRuntime().catch((err) => {
|
|
445
|
+
console.error("Failed to bootstrap plugins runtime (existing connection):", err);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
432
448
|
|
|
433
449
|
// Initialize console manager AFTER database is already connected
|
|
434
450
|
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
@@ -524,6 +540,15 @@ function createMiddleware(options = {}) {
|
|
|
524
540
|
}
|
|
525
541
|
|
|
526
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
|
+
|
|
527
552
|
const sessionMiddleware = session({
|
|
528
553
|
secret: process.env.SESSION_SECRET || 'superbackend-session-secret-fallback',
|
|
529
554
|
resave: false,
|
|
@@ -534,11 +559,7 @@ function createMiddleware(options = {}) {
|
|
|
534
559
|
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
535
560
|
sameSite: 'lax'
|
|
536
561
|
},
|
|
537
|
-
store:
|
|
538
|
-
mongoUrl: options.mongodbUri || process.env.MONGODB_URI,
|
|
539
|
-
collectionName: 'admin_sessions',
|
|
540
|
-
ttl: 24 * 60 * 60 // 24 hours in seconds
|
|
541
|
-
}),
|
|
562
|
+
store: sessionStore,
|
|
542
563
|
name: 'superbackend.admin.session'
|
|
543
564
|
});
|
|
544
565
|
|
|
@@ -852,7 +873,8 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
852
873
|
baseUrl: req.baseUrl,
|
|
853
874
|
adminPath,
|
|
854
875
|
endpointRegistry,
|
|
855
|
-
isIframe: req.isIframe || false
|
|
876
|
+
isIframe: req.isIframe || false,
|
|
877
|
+
serverPort: process.env.PORT || 3000
|
|
856
878
|
},
|
|
857
879
|
{
|
|
858
880
|
filename: templatePath,
|
|
@@ -1104,6 +1126,10 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1104
1126
|
"/api/admin/ui-components",
|
|
1105
1127
|
require("./routes/adminUiComponents.routes"),
|
|
1106
1128
|
);
|
|
1129
|
+
router.use(
|
|
1130
|
+
"/api/admin/superdemos",
|
|
1131
|
+
require("./routes/adminSuperDemos.routes"),
|
|
1132
|
+
);
|
|
1107
1133
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
1108
1134
|
router.use(
|
|
1109
1135
|
"/api/admin/errors",
|
|
@@ -1145,6 +1171,7 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1145
1171
|
router.use("/api/log", require("./routes/log.routes"));
|
|
1146
1172
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
1147
1173
|
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
1174
|
+
router.use("/api/superdemos", require("./routes/superDemos.routes"));
|
|
1148
1175
|
router.use("/api/rbac", require("./routes/rbac.routes"));
|
|
1149
1176
|
router.use("/registry", require("./routes/registry.routes"));
|
|
1150
1177
|
router.use("/api/file-manager", require("./routes/fileManager.routes"));
|
|
@@ -1175,13 +1202,36 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1175
1202
|
}, require("./routes/adminLogin.routes"));
|
|
1176
1203
|
|
|
1177
1204
|
// Admin dashboard (redirect to login if not authenticated)
|
|
1178
|
-
router.get(adminPath, adminSessionAuth, (req, res) => {
|
|
1205
|
+
router.get(adminPath, adminSessionAuth, async (req, res) => {
|
|
1179
1206
|
const templatePath = path.join(
|
|
1180
1207
|
__dirname,
|
|
1181
1208
|
"..",
|
|
1182
1209
|
"views",
|
|
1183
1210
|
"admin-dashboard.ejs",
|
|
1184
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
|
+
|
|
1185
1235
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1186
1236
|
if (err) {
|
|
1187
1237
|
console.error("Error reading template:", err);
|
|
@@ -1190,7 +1240,12 @@ router.get(`${adminPath}/stats/dashboard-home`, checkIframeAuth, (req, res) => {
|
|
|
1190
1240
|
try {
|
|
1191
1241
|
const html = ejs.render(
|
|
1192
1242
|
template,
|
|
1193
|
-
{
|
|
1243
|
+
{
|
|
1244
|
+
baseUrl: req.baseUrl,
|
|
1245
|
+
adminPath,
|
|
1246
|
+
isIframe: req.isIframe || false,
|
|
1247
|
+
maxTabs
|
|
1248
|
+
},
|
|
1194
1249
|
{ filename: templatePath },
|
|
1195
1250
|
);
|
|
1196
1251
|
res.send(html);
|
|
@@ -1723,6 +1778,40 @@ router.get(`${adminPath}/file-manager`, requireModuleAccessWithIframe('file-mana
|
|
|
1723
1778
|
});
|
|
1724
1779
|
});
|
|
1725
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
|
+
|
|
1726
1815
|
// Admin JSON configs page (protected by basic auth)
|
|
1727
1816
|
router.get(`${adminPath}/json-configs`, requireModuleAccessWithIframe('json-configs', 'read'), (req, res) => {
|
|
1728
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;
|