@intranefr/superbackend 1.4.3 → 1.5.0
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 +6 -1
- package/README.md +5 -5
- package/index.js +23 -5
- package/package.json +5 -2
- package/public/sdk/ui-components.iife.js +191 -0
- package/sdk/error-tracking/browser/package.json +4 -3
- package/sdk/error-tracking/browser/src/embed.js +29 -0
- package/sdk/ui-components/browser/src/index.js +228 -0
- package/src/controllers/admin.controller.js +139 -1
- package/src/controllers/adminHeadless.controller.js +82 -0
- package/src/controllers/adminMigration.controller.js +5 -1
- package/src/controllers/adminScripts.controller.js +229 -0
- package/src/controllers/adminTerminals.controller.js +39 -0
- package/src/controllers/adminUiComponents.controller.js +315 -0
- package/src/controllers/adminUiComponentsAi.controller.js +34 -0
- package/src/controllers/orgAdmin.controller.js +286 -0
- package/src/controllers/uiComponentsPublic.controller.js +118 -0
- package/src/middleware/auth.js +7 -0
- package/src/middleware.js +119 -0
- package/src/models/HeadlessModelDefinition.js +10 -0
- package/src/models/ScriptDefinition.js +42 -0
- package/src/models/ScriptRun.js +22 -0
- package/src/models/UiComponent.js +29 -0
- package/src/models/UiComponentProject.js +26 -0
- package/src/models/UiComponentProjectComponent.js +18 -0
- package/src/routes/admin.routes.js +2 -0
- package/src/routes/adminHeadless.routes.js +6 -0
- package/src/routes/adminScripts.routes.js +21 -0
- package/src/routes/adminTerminals.routes.js +13 -0
- package/src/routes/adminUiComponents.routes.js +29 -0
- package/src/routes/llmUi.routes.js +26 -0
- package/src/routes/orgAdmin.routes.js +5 -0
- package/src/routes/uiComponentsPublic.routes.js +9 -0
- package/src/services/consoleOverride.service.js +291 -0
- package/src/services/email.service.js +17 -1
- package/src/services/headlessExternalModels.service.js +292 -0
- package/src/services/headlessModels.service.js +26 -6
- package/src/services/scriptsRunner.service.js +259 -0
- package/src/services/terminals.service.js +152 -0
- package/src/services/terminalsWs.service.js +100 -0
- package/src/services/uiComponentsAi.service.js +312 -0
- package/src/services/uiComponentsCrypto.service.js +39 -0
- package/src/services/webhook.service.js +2 -2
- package/src/services/workflow.service.js +1 -1
- package/src/utils/encryption.js +5 -3
- package/views/admin-coolify-deploy.ejs +1 -1
- package/views/admin-dashboard-home.ejs +1 -1
- package/views/admin-dashboard.ejs +1 -1
- package/views/admin-errors.ejs +2 -2
- package/views/admin-global-settings.ejs +3 -3
- package/views/admin-headless.ejs +294 -24
- package/views/admin-json-configs.ejs +8 -1
- package/views/admin-llm.ejs +2 -2
- package/views/admin-organizations.ejs +365 -9
- package/views/admin-scripts.ejs +497 -0
- package/views/admin-seo-config.ejs +1 -1
- package/views/admin-terminals.ejs +328 -0
- package/views/admin-test.ejs +3 -3
- package/views/admin-ui-components.ejs +709 -0
- package/views/admin-users.ejs +440 -4
- package/views/admin-webhooks.ejs +1 -1
- package/views/admin-workflows.ejs +1 -1
- package/views/partials/admin-assets-script.ejs +3 -3
- package/views/partials/dashboard/nav-items.ejs +3 -0
- package/views/partials/dashboard/palette.ejs +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const UiComponent = require('../models/UiComponent');
|
|
2
|
+
const UiComponentProject = require('../models/UiComponentProject');
|
|
3
|
+
const UiComponentProjectComponent = require('../models/UiComponentProjectComponent');
|
|
4
|
+
|
|
5
|
+
const { verifyKey } = require('../services/uiComponentsCrypto.service');
|
|
6
|
+
|
|
7
|
+
function extractProjectKey(req) {
|
|
8
|
+
const headerToken = req.headers['x-project-key'] || req.headers['x-api-key'];
|
|
9
|
+
if (headerToken) return String(headerToken).trim();
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function loadAndAuthorizeProject(req, res, projectId) {
|
|
14
|
+
const project = await UiComponentProject.findOne({ projectId: String(projectId), isActive: true }).lean();
|
|
15
|
+
if (!project) {
|
|
16
|
+
res.status(404).json({ error: 'Project not found' });
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!project.isPublic) {
|
|
21
|
+
const key = extractProjectKey(req);
|
|
22
|
+
const ok = project.apiKeyHash && verifyKey(key, project.apiKeyHash);
|
|
23
|
+
if (!ok) {
|
|
24
|
+
res.status(401).json({ error: 'Invalid project key' });
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return project;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
exports.getManifest = async (req, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const { projectId } = req.params;
|
|
35
|
+
const project = await loadAndAuthorizeProject(req, res, projectId);
|
|
36
|
+
if (!project) return;
|
|
37
|
+
|
|
38
|
+
const assignments = await UiComponentProjectComponent.find({ projectId: project.projectId, enabled: true }).lean();
|
|
39
|
+
const codes = assignments.map((a) => a.componentCode);
|
|
40
|
+
|
|
41
|
+
const components = await UiComponent.find({
|
|
42
|
+
code: { $in: codes },
|
|
43
|
+
isActive: true,
|
|
44
|
+
})
|
|
45
|
+
.sort({ code: 1 })
|
|
46
|
+
.lean();
|
|
47
|
+
|
|
48
|
+
const docsOnly = String(req.query.docs || '').toLowerCase() === 'true';
|
|
49
|
+
|
|
50
|
+
const out = components.map((c) => {
|
|
51
|
+
const base = {
|
|
52
|
+
code: c.code,
|
|
53
|
+
name: c.name,
|
|
54
|
+
version: c.version,
|
|
55
|
+
};
|
|
56
|
+
if (docsOnly) {
|
|
57
|
+
base.usageMarkdown = c.usageMarkdown;
|
|
58
|
+
} else {
|
|
59
|
+
base.html = c.html;
|
|
60
|
+
base.js = c.js;
|
|
61
|
+
base.css = c.css;
|
|
62
|
+
}
|
|
63
|
+
return base;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return res.json({
|
|
67
|
+
project: {
|
|
68
|
+
projectId: project.projectId,
|
|
69
|
+
name: project.name,
|
|
70
|
+
isPublic: project.isPublic,
|
|
71
|
+
allowedOrigins: project.allowedOrigins || [],
|
|
72
|
+
},
|
|
73
|
+
components: out,
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('UI Components getManifest error:', error);
|
|
77
|
+
return res.status(500).json({ error: 'Failed to load manifest' });
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
exports.getComponent = async (req, res) => {
|
|
82
|
+
try {
|
|
83
|
+
const { projectId, code } = req.params;
|
|
84
|
+
const project = await loadAndAuthorizeProject(req, res, projectId);
|
|
85
|
+
if (!project) return;
|
|
86
|
+
|
|
87
|
+
const componentCode = String(code || '').trim().toLowerCase();
|
|
88
|
+
|
|
89
|
+
const assignment = await UiComponentProjectComponent.findOne({
|
|
90
|
+
projectId: project.projectId,
|
|
91
|
+
componentCode,
|
|
92
|
+
enabled: true,
|
|
93
|
+
}).lean();
|
|
94
|
+
|
|
95
|
+
if (!assignment) return res.status(404).json({ error: 'Component not enabled for this project' });
|
|
96
|
+
|
|
97
|
+
const component = await UiComponent.findOne({ code: componentCode, isActive: true }).lean();
|
|
98
|
+
if (!component) return res.status(404).json({ error: 'Component not found' });
|
|
99
|
+
|
|
100
|
+
return res.json({
|
|
101
|
+
project: {
|
|
102
|
+
projectId: project.projectId,
|
|
103
|
+
isPublic: project.isPublic,
|
|
104
|
+
},
|
|
105
|
+
component: {
|
|
106
|
+
code: component.code,
|
|
107
|
+
name: component.name,
|
|
108
|
+
version: component.version,
|
|
109
|
+
html: component.html,
|
|
110
|
+
js: component.js,
|
|
111
|
+
css: component.css,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error('UI Components getComponent error:', error);
|
|
116
|
+
return res.status(500).json({ error: 'Failed to load component' });
|
|
117
|
+
}
|
|
118
|
+
};
|
package/src/middleware/auth.js
CHANGED
|
@@ -19,6 +19,7 @@ const authenticate = async (req, res, next) => {
|
|
|
19
19
|
req.user = user;
|
|
20
20
|
next();
|
|
21
21
|
} catch (error) {
|
|
22
|
+
console.error("api authenticate error:", error);
|
|
22
23
|
return res
|
|
23
24
|
.status(401)
|
|
24
25
|
.json({ error: error.message || "Authentication failed" });
|
|
@@ -45,6 +46,12 @@ const basicAuth = (req, res, next) => {
|
|
|
45
46
|
if (username === adminUsername && password === adminPassword) {
|
|
46
47
|
next();
|
|
47
48
|
} else {
|
|
49
|
+
console.error("api basicAuth error:", {
|
|
50
|
+
username,
|
|
51
|
+
password,
|
|
52
|
+
adminUsername,
|
|
53
|
+
adminPassword,
|
|
54
|
+
});
|
|
48
55
|
res.setHeader("WWW-Authenticate", 'Basic realm="Admin Area"');
|
|
49
56
|
return res.status(401).json({ error: "Invalid credentials" });
|
|
50
57
|
}
|
package/src/middleware.js
CHANGED
|
@@ -7,6 +7,7 @@ const ejs = require("ejs");
|
|
|
7
7
|
const { basicAuth } = require("./middleware/auth");
|
|
8
8
|
const endpointRegistry = require("./admin/endpointRegistry");
|
|
9
9
|
const { createFeatureFlagsEjsMiddleware } = require("./services/featureFlags.service");
|
|
10
|
+
const consoleOverride = require("./services/consoleOverride.service");
|
|
10
11
|
const {
|
|
11
12
|
hookConsoleError,
|
|
12
13
|
setupProcessHandlers,
|
|
@@ -30,6 +31,16 @@ function createMiddleware(options = {}) {
|
|
|
30
31
|
const router = express.Router();
|
|
31
32
|
const adminPath = options.adminPath || "/admin";
|
|
32
33
|
|
|
34
|
+
// Expose adminPath and WS attachment helper
|
|
35
|
+
router.adminPath = adminPath;
|
|
36
|
+
router.attachWs = (server) => {
|
|
37
|
+
const { attachTerminalWebsocketServer } = require('./services/terminalsWs.service');
|
|
38
|
+
attachTerminalWebsocketServer(server, { basePathPrefix: adminPath });
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Initialize console override service early to capture all logs
|
|
42
|
+
consoleOverride.init();
|
|
43
|
+
|
|
33
44
|
if (!errorCaptureInitialized) {
|
|
34
45
|
errorCaptureInitialized = true;
|
|
35
46
|
hookConsoleError();
|
|
@@ -138,6 +149,12 @@ function createMiddleware(options = {}) {
|
|
|
138
149
|
// Serve public static files (e.g. /og/og-default.png)
|
|
139
150
|
router.use(express.static(path.join(__dirname, "..", "public")));
|
|
140
151
|
|
|
152
|
+
// Serve browser SDK bundles
|
|
153
|
+
router.use(
|
|
154
|
+
"/public/sdk",
|
|
155
|
+
express.static(path.join(__dirname, "..", "public", "sdk")),
|
|
156
|
+
);
|
|
157
|
+
|
|
141
158
|
// Serve static files for admin views
|
|
142
159
|
router.use(
|
|
143
160
|
`${adminPath}/assets`,
|
|
@@ -184,6 +201,70 @@ function createMiddleware(options = {}) {
|
|
|
184
201
|
});
|
|
185
202
|
});
|
|
186
203
|
|
|
204
|
+
router.get(`${adminPath}/terminals`, basicAuth, (req, res) => {
|
|
205
|
+
const templatePath = path.join(
|
|
206
|
+
__dirname,
|
|
207
|
+
"..",
|
|
208
|
+
"views",
|
|
209
|
+
"admin-terminals.ejs",
|
|
210
|
+
);
|
|
211
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
212
|
+
if (err) {
|
|
213
|
+
console.error("Error reading template:", err);
|
|
214
|
+
return res.status(500).send("Error loading page");
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const html = ejs.render(
|
|
218
|
+
template,
|
|
219
|
+
{
|
|
220
|
+
baseUrl: req.baseUrl,
|
|
221
|
+
adminPath,
|
|
222
|
+
endpointRegistry,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
filename: templatePath,
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
res.send(html);
|
|
229
|
+
} catch (renderErr) {
|
|
230
|
+
console.error("Error rendering template:", renderErr);
|
|
231
|
+
res.status(500).send("Error rendering page");
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
router.get(`${adminPath}/scripts`, basicAuth, (req, res) => {
|
|
237
|
+
const templatePath = path.join(
|
|
238
|
+
__dirname,
|
|
239
|
+
"..",
|
|
240
|
+
"views",
|
|
241
|
+
"admin-scripts.ejs",
|
|
242
|
+
);
|
|
243
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
244
|
+
if (err) {
|
|
245
|
+
console.error("Error reading template:", err);
|
|
246
|
+
return res.status(500).send("Error loading page");
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const html = ejs.render(
|
|
250
|
+
template,
|
|
251
|
+
{
|
|
252
|
+
baseUrl: req.baseUrl,
|
|
253
|
+
adminPath,
|
|
254
|
+
endpointRegistry,
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
filename: templatePath,
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
res.send(html);
|
|
261
|
+
} catch (renderErr) {
|
|
262
|
+
console.error("Error rendering template:", renderErr);
|
|
263
|
+
res.status(500).send("Error rendering page");
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
187
268
|
router.use("/api/admin", require("./routes/admin.routes"));
|
|
188
269
|
router.use("/api/admin/settings", require("./routes/globalSettings.routes"));
|
|
189
270
|
router.use(
|
|
@@ -200,11 +281,14 @@ function createMiddleware(options = {}) {
|
|
|
200
281
|
);
|
|
201
282
|
router.use("/api/admin/i18n", require("./routes/adminI18n.routes"));
|
|
202
283
|
router.use("/api/admin/headless", require("./routes/adminHeadless.routes"));
|
|
284
|
+
router.use("/api/admin/scripts", require("./routes/adminScripts.routes"));
|
|
285
|
+
router.use("/api/admin/terminals", require("./routes/adminTerminals.routes"));
|
|
203
286
|
router.use("/api/admin/assets", require("./routes/adminAssets.routes"));
|
|
204
287
|
router.use(
|
|
205
288
|
"/api/admin/upload-namespaces",
|
|
206
289
|
require("./routes/adminUploadNamespaces.routes"),
|
|
207
290
|
);
|
|
291
|
+
router.use("/api/admin/ui-components", require("./routes/adminUiComponents.routes"));
|
|
208
292
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
209
293
|
router.use("/api/admin/errors", basicAuth, require("./routes/adminErrors.routes"));
|
|
210
294
|
router.use("/api/admin/audit", basicAuth, require("./routes/adminAudit.routes"));
|
|
@@ -225,6 +309,8 @@ function createMiddleware(options = {}) {
|
|
|
225
309
|
router.use("/api/invites", require("./routes/invite.routes"));
|
|
226
310
|
router.use("/api/log", require("./routes/log.routes"));
|
|
227
311
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
312
|
+
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
313
|
+
router.use("/api/llm/ui", require("./routes/llmUi.routes"));
|
|
228
314
|
|
|
229
315
|
// Public assets proxy
|
|
230
316
|
router.use("/public/assets", require("./routes/publicAssets.routes"));
|
|
@@ -537,6 +623,39 @@ function createMiddleware(options = {}) {
|
|
|
537
623
|
});
|
|
538
624
|
});
|
|
539
625
|
|
|
626
|
+
// Admin UI Components page (protected by basic auth)
|
|
627
|
+
router.get(`${adminPath}/ui-components`, basicAuth, (req, res) => {
|
|
628
|
+
const templatePath = path.join(
|
|
629
|
+
__dirname,
|
|
630
|
+
"..",
|
|
631
|
+
"views",
|
|
632
|
+
"admin-ui-components.ejs",
|
|
633
|
+
);
|
|
634
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
635
|
+
if (err) {
|
|
636
|
+
console.error("Error reading template:", err);
|
|
637
|
+
return res.status(500).send("Error loading page");
|
|
638
|
+
}
|
|
639
|
+
try {
|
|
640
|
+
const html = ejs.render(
|
|
641
|
+
template,
|
|
642
|
+
{
|
|
643
|
+
baseUrl: req.baseUrl,
|
|
644
|
+
adminPath,
|
|
645
|
+
endpointRegistry,
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
filename: templatePath,
|
|
649
|
+
},
|
|
650
|
+
);
|
|
651
|
+
res.send(html);
|
|
652
|
+
} catch (renderErr) {
|
|
653
|
+
console.error("Error rendering template:", renderErr);
|
|
654
|
+
res.status(500).send("Error rendering page");
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
540
659
|
// Admin JSON configs page (protected by basic auth)
|
|
541
660
|
router.get(`${adminPath}/json-configs`, basicAuth, (req, res) => {
|
|
542
661
|
const templatePath = path.join(
|
|
@@ -28,6 +28,16 @@ const headlessModelDefinitionSchema = new mongoose.Schema(
|
|
|
28
28
|
description: { type: String, default: '' },
|
|
29
29
|
fields: { type: [headlessFieldSchema], default: [] },
|
|
30
30
|
indexes: { type: [headlessIndexSchema], default: [] },
|
|
31
|
+
sourceType: { type: String, enum: ['internal', 'external'], default: 'internal', index: true },
|
|
32
|
+
sourceCollectionName: { type: String, default: null, index: true },
|
|
33
|
+
isExternal: { type: Boolean, default: false, index: true },
|
|
34
|
+
inference: {
|
|
35
|
+
enabled: { type: Boolean, default: false },
|
|
36
|
+
lastInferredAt: { type: Date, default: null },
|
|
37
|
+
sampleSize: { type: Number, default: null },
|
|
38
|
+
warnings: { type: [String], default: [] },
|
|
39
|
+
stats: { type: mongoose.Schema.Types.Mixed, default: null },
|
|
40
|
+
},
|
|
31
41
|
isActive: { type: Boolean, default: true, index: true },
|
|
32
42
|
version: { type: Number, default: 1 },
|
|
33
43
|
fieldsHash: { type: String, default: null },
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const envVarSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
key: { type: String, required: true },
|
|
6
|
+
value: { type: String, required: true },
|
|
7
|
+
},
|
|
8
|
+
{ _id: false },
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const scriptDefinitionSchema = new mongoose.Schema(
|
|
12
|
+
{
|
|
13
|
+
name: { type: String, required: true },
|
|
14
|
+
codeIdentifier: { type: String, required: true, unique: true, index: true },
|
|
15
|
+
description: { type: String, default: '' },
|
|
16
|
+
type: { type: String, enum: ['bash', 'node', 'browser'], required: true },
|
|
17
|
+
runner: { type: String, enum: ['host', 'vm2', 'browser'], required: true },
|
|
18
|
+
script: { type: String, required: true },
|
|
19
|
+
defaultWorkingDirectory: { type: String, default: '' },
|
|
20
|
+
env: { type: [envVarSchema], default: [] },
|
|
21
|
+
timeoutMs: { type: Number, default: 5 * 60 * 1000 },
|
|
22
|
+
enabled: { type: Boolean, default: true, index: true },
|
|
23
|
+
},
|
|
24
|
+
{ timestamps: true, collection: 'script_definitions' },
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
function normalizeCodeIdentifier(codeIdentifier) {
|
|
28
|
+
return String(codeIdentifier || '')
|
|
29
|
+
.trim()
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replace(/\s+/g, '-')
|
|
32
|
+
.replace(/[^a-z0-9_-]/g, '');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
scriptDefinitionSchema.pre('validate', function preValidate(next) {
|
|
36
|
+
this.codeIdentifier = normalizeCodeIdentifier(this.codeIdentifier);
|
|
37
|
+
next();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
module.exports =
|
|
41
|
+
mongoose.models.ScriptDefinition ||
|
|
42
|
+
mongoose.model('ScriptDefinition', scriptDefinitionSchema);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const scriptRunSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
scriptId: { type: mongoose.Schema.Types.ObjectId, ref: 'ScriptDefinition', required: true, index: true },
|
|
6
|
+
status: {
|
|
7
|
+
type: String,
|
|
8
|
+
enum: ['queued', 'running', 'succeeded', 'failed', 'canceled', 'timed_out'],
|
|
9
|
+
default: 'queued',
|
|
10
|
+
index: true,
|
|
11
|
+
},
|
|
12
|
+
trigger: { type: String, enum: ['manual', 'schedule', 'api'], default: 'manual', index: true },
|
|
13
|
+
startedAt: { type: Date, default: null },
|
|
14
|
+
finishedAt: { type: Date, default: null },
|
|
15
|
+
exitCode: { type: Number, default: null },
|
|
16
|
+
outputTail: { type: String, default: '' },
|
|
17
|
+
meta: { type: mongoose.Schema.Types.Mixed, default: null },
|
|
18
|
+
},
|
|
19
|
+
{ timestamps: true, collection: 'script_runs' },
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
module.exports = mongoose.models.ScriptRun || mongoose.model('ScriptRun', scriptRunSchema);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const uiComponentSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
code: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
unique: true,
|
|
9
|
+
index: true,
|
|
10
|
+
trim: true,
|
|
11
|
+
lowercase: true,
|
|
12
|
+
match: [/^[a-z][a-z0-9_-]{1,63}$/, 'Invalid component code'],
|
|
13
|
+
},
|
|
14
|
+
name: { type: String, required: true, trim: true },
|
|
15
|
+
|
|
16
|
+
html: { type: String, default: '' },
|
|
17
|
+
js: { type: String, default: '' },
|
|
18
|
+
css: { type: String, default: '' },
|
|
19
|
+
|
|
20
|
+
api: { type: mongoose.Schema.Types.Mixed, default: null },
|
|
21
|
+
usageMarkdown: { type: String, default: '' },
|
|
22
|
+
|
|
23
|
+
version: { type: Number, default: 1 },
|
|
24
|
+
isActive: { type: Boolean, default: true, index: true },
|
|
25
|
+
},
|
|
26
|
+
{ timestamps: true, collection: 'ui_components' },
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
module.exports = mongoose.models.UiComponent || mongoose.model('UiComponent', uiComponentSchema);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const uiComponentProjectSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
projectId: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
unique: true,
|
|
9
|
+
index: true,
|
|
10
|
+
trim: true,
|
|
11
|
+
match: [/^prj_[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
|
+
|
|
20
|
+
isActive: { type: Boolean, default: true, index: true },
|
|
21
|
+
},
|
|
22
|
+
{ timestamps: true, collection: 'ui_component_projects' },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
module.exports = mongoose.models.UiComponentProject ||
|
|
26
|
+
mongoose.model('UiComponentProject', uiComponentProjectSchema);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const uiComponentProjectComponentSchema = new mongoose.Schema(
|
|
4
|
+
{
|
|
5
|
+
projectId: { type: String, required: true, index: true },
|
|
6
|
+
componentCode: { type: String, required: true, index: true },
|
|
7
|
+
enabled: { type: Boolean, default: true, index: true },
|
|
8
|
+
},
|
|
9
|
+
{ timestamps: true, collection: 'ui_component_project_components' },
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
uiComponentProjectComponentSchema.index(
|
|
13
|
+
{ projectId: 1, componentCode: 1 },
|
|
14
|
+
{ unique: true },
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
module.exports = mongoose.models.UiComponentProjectComponent ||
|
|
18
|
+
mongoose.model('UiComponentProjectComponent', uiComponentProjectComponentSchema);
|
|
@@ -7,9 +7,11 @@ const { basicAuth } = require('../middleware/auth');
|
|
|
7
7
|
router.use(basicAuth);
|
|
8
8
|
|
|
9
9
|
router.get('/users', adminController.getUsers);
|
|
10
|
+
router.post('/users/register', adminController.registerUser);
|
|
10
11
|
router.get('/users/:id', adminController.getUser);
|
|
11
12
|
router.put('/users/:id/subscription', adminController.updateUserSubscription);
|
|
12
13
|
router.patch('/users/:id', adminController.updateUserPassword);
|
|
14
|
+
router.delete('/users/:id', adminController.deleteUser);
|
|
13
15
|
router.post('/users/:id/reconcile', adminController.reconcileUser);
|
|
14
16
|
router.post('/generate-token', adminController.generateToken);
|
|
15
17
|
|
|
@@ -13,6 +13,12 @@ router.post('/models', adminHeadlessController.createModel);
|
|
|
13
13
|
router.put('/models/:codeIdentifier', adminHeadlessController.updateModel);
|
|
14
14
|
router.delete('/models/:codeIdentifier', adminHeadlessController.deleteModel);
|
|
15
15
|
|
|
16
|
+
// External models (Mongo collections)
|
|
17
|
+
router.get('/external/collections', adminHeadlessController.listExternalCollections);
|
|
18
|
+
router.post('/external/infer', adminHeadlessController.inferExternalCollection);
|
|
19
|
+
router.post('/external/import', adminHeadlessController.importExternalModel);
|
|
20
|
+
router.post('/models/:codeIdentifier/sync', adminHeadlessController.syncExternalModel);
|
|
21
|
+
|
|
16
22
|
// Advanced JSON / bulk helpers
|
|
17
23
|
router.post('/models/validate', adminHeadlessController.validateModelDefinition);
|
|
18
24
|
router.post('/models/apply', adminHeadlessController.applyModelProposal);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const { basicAuth } = require('../middleware/auth');
|
|
5
|
+
const controller = require('../controllers/adminScripts.controller');
|
|
6
|
+
|
|
7
|
+
router.use(basicAuth);
|
|
8
|
+
|
|
9
|
+
router.get('/', controller.listScripts);
|
|
10
|
+
router.post('/', controller.createScript);
|
|
11
|
+
router.get('/runs', controller.listRuns);
|
|
12
|
+
router.get('/runs/:runId', controller.getRun);
|
|
13
|
+
router.get('/runs/:runId/stream', controller.streamRun);
|
|
14
|
+
|
|
15
|
+
router.get('/:id', controller.getScript);
|
|
16
|
+
router.put('/:id', controller.updateScript);
|
|
17
|
+
router.delete('/:id', controller.deleteScript);
|
|
18
|
+
|
|
19
|
+
router.post('/:id/run', controller.runScript);
|
|
20
|
+
|
|
21
|
+
module.exports = router;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const { basicAuth } = require('../middleware/auth');
|
|
5
|
+
const controller = require('../controllers/adminTerminals.controller');
|
|
6
|
+
|
|
7
|
+
router.use(basicAuth);
|
|
8
|
+
|
|
9
|
+
router.post('/sessions', controller.createSession);
|
|
10
|
+
router.get('/sessions', controller.listSessions);
|
|
11
|
+
router.delete('/sessions/:sessionId', controller.killSession);
|
|
12
|
+
|
|
13
|
+
module.exports = router;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const { basicAuth } = require('../middleware/auth');
|
|
5
|
+
const adminUiComponentsController = require('../controllers/adminUiComponents.controller');
|
|
6
|
+
const adminUiComponentsAiController = require('../controllers/adminUiComponentsAi.controller');
|
|
7
|
+
|
|
8
|
+
router.use(basicAuth);
|
|
9
|
+
|
|
10
|
+
router.get('/projects', adminUiComponentsController.listProjects);
|
|
11
|
+
router.post('/projects', adminUiComponentsController.createProject);
|
|
12
|
+
router.get('/projects/:projectId', adminUiComponentsController.getProject);
|
|
13
|
+
router.put('/projects/:projectId', adminUiComponentsController.updateProject);
|
|
14
|
+
router.delete('/projects/:projectId', adminUiComponentsController.deleteProject);
|
|
15
|
+
router.post('/projects/:projectId/rotate-key', adminUiComponentsController.rotateProjectKey);
|
|
16
|
+
|
|
17
|
+
router.get('/components', adminUiComponentsController.listComponents);
|
|
18
|
+
router.post('/components', adminUiComponentsController.createComponent);
|
|
19
|
+
router.get('/components/:code', adminUiComponentsController.getComponent);
|
|
20
|
+
router.put('/components/:code', adminUiComponentsController.updateComponent);
|
|
21
|
+
router.delete('/components/:code', adminUiComponentsController.deleteComponent);
|
|
22
|
+
|
|
23
|
+
router.get('/projects/:projectId/components', adminUiComponentsController.listProjectAssignments);
|
|
24
|
+
router.post('/projects/:projectId/components/:code', adminUiComponentsController.setAssignment);
|
|
25
|
+
router.delete('/projects/:projectId/components/:code', adminUiComponentsController.deleteAssignment);
|
|
26
|
+
|
|
27
|
+
router.post('/ai/components/:code/propose', adminUiComponentsAiController.propose);
|
|
28
|
+
|
|
29
|
+
module.exports = router;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const { basicAuth } = require('../middleware/auth');
|
|
5
|
+
const adminUiComponentsController = require('../controllers/adminUiComponents.controller');
|
|
6
|
+
|
|
7
|
+
router.use(basicAuth);
|
|
8
|
+
|
|
9
|
+
router.get('/projects', adminUiComponentsController.listProjects);
|
|
10
|
+
router.post('/projects', adminUiComponentsController.createProject);
|
|
11
|
+
router.get('/projects/:projectId', adminUiComponentsController.getProject);
|
|
12
|
+
router.put('/projects/:projectId', adminUiComponentsController.updateProject);
|
|
13
|
+
router.delete('/projects/:projectId', adminUiComponentsController.deleteProject);
|
|
14
|
+
router.post('/projects/:projectId/rotate-key', adminUiComponentsController.rotateProjectKey);
|
|
15
|
+
|
|
16
|
+
router.get('/components', adminUiComponentsController.listComponents);
|
|
17
|
+
router.post('/components', adminUiComponentsController.createComponent);
|
|
18
|
+
router.get('/components/:code', adminUiComponentsController.getComponent);
|
|
19
|
+
router.put('/components/:code', adminUiComponentsController.updateComponent);
|
|
20
|
+
router.delete('/components/:code', adminUiComponentsController.deleteComponent);
|
|
21
|
+
|
|
22
|
+
router.get('/projects/:projectId/components', adminUiComponentsController.listProjectAssignments);
|
|
23
|
+
router.post('/projects/:projectId/components/:code', adminUiComponentsController.setAssignment);
|
|
24
|
+
router.delete('/projects/:projectId/components/:code', adminUiComponentsController.deleteAssignment);
|
|
25
|
+
|
|
26
|
+
module.exports = router;
|
|
@@ -6,7 +6,12 @@ const orgAdminController = require('../controllers/orgAdmin.controller');
|
|
|
6
6
|
const asyncHandler = require('../utils/asyncHandler');
|
|
7
7
|
|
|
8
8
|
router.get('/', basicAuth, asyncHandler(orgAdminController.listOrgs));
|
|
9
|
+
router.post('/', basicAuth, asyncHandler(orgAdminController.createOrganization));
|
|
9
10
|
router.get('/:orgId', basicAuth, asyncHandler(orgAdminController.getOrg));
|
|
11
|
+
router.put('/:orgId', basicAuth, asyncHandler(orgAdminController.updateOrganization));
|
|
12
|
+
router.patch('/:orgId/disable', basicAuth, asyncHandler(orgAdminController.disableOrganization));
|
|
13
|
+
router.patch('/:orgId/enable', basicAuth, asyncHandler(orgAdminController.enableOrganization));
|
|
14
|
+
router.delete('/:orgId', basicAuth, asyncHandler(orgAdminController.deleteOrganization));
|
|
10
15
|
|
|
11
16
|
router.get('/:orgId/members', basicAuth, asyncHandler(orgAdminController.listMembers));
|
|
12
17
|
router.patch('/:orgId/members/:memberId', basicAuth, asyncHandler(orgAdminController.updateMember));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
const uiComponentsPublicController = require('../controllers/uiComponentsPublic.controller');
|
|
5
|
+
|
|
6
|
+
router.get('/projects/:projectId/manifest', uiComponentsPublicController.getManifest);
|
|
7
|
+
router.get('/projects/:projectId/components/:code', uiComponentsPublicController.getComponent);
|
|
8
|
+
|
|
9
|
+
module.exports = router;
|