@jagilber-org/index-server 1.22.1 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -2
- package/CODE_OF_CONDUCT.md +2 -0
- package/CONTRIBUTING.md +32 -2
- package/README.md +82 -19
- package/SECURITY.md +17 -5
- package/dist/config/dashboardConfig.d.ts +3 -0
- package/dist/config/dashboardConfig.js +3 -0
- package/dist/config/defaultValues.d.ts +1 -1
- package/dist/config/defaultValues.js +1 -1
- package/dist/config/featureConfig.d.ts +2 -0
- package/dist/config/featureConfig.js +6 -1
- package/dist/config/runtimeConfig.d.ts +1 -1
- package/dist/config/runtimeConfig.js +8 -9
- package/dist/dashboard/client/admin.html +170 -53
- package/dist/dashboard/client/css/admin.css +132 -0
- package/dist/dashboard/client/js/admin.auth.js +25 -11
- package/dist/dashboard/client/js/admin.config.js +1 -1
- package/dist/dashboard/client/js/admin.feedback.js +328 -0
- package/dist/dashboard/client/js/admin.graph.js +120 -18
- package/dist/dashboard/client/js/admin.instructions.js +27 -13
- package/dist/dashboard/client/js/admin.logs.js +1 -5
- package/dist/dashboard/client/js/admin.maintenance.js +53 -8
- package/dist/dashboard/client/js/admin.messaging.js +1 -4
- package/dist/dashboard/client/js/admin.overview.js +5 -1
- package/dist/dashboard/client/js/admin.sessions.js +1 -1
- package/dist/dashboard/client/js/admin.utils.js +43 -1
- package/dist/dashboard/client/js/mermaid.min.js +813 -537
- package/dist/dashboard/export/DataExporter.js +2 -1
- package/dist/dashboard/server/AdminPanel.d.ts +3 -0
- package/dist/dashboard/server/AdminPanel.js +132 -35
- package/dist/dashboard/server/ApiRoutes.js +40 -9
- package/dist/dashboard/server/DashboardServer.js +1 -1
- package/dist/dashboard/server/FileMetricsStorage.d.ts +19 -0
- package/dist/dashboard/server/FileMetricsStorage.js +52 -5
- package/dist/dashboard/server/HttpTransport.js +6 -0
- package/dist/dashboard/server/InstanceManager.js +7 -2
- package/dist/dashboard/server/KnowledgeStore.js +7 -2
- package/dist/dashboard/server/MetricsCollector.d.ts +16 -0
- package/dist/dashboard/server/MetricsCollector.js +113 -17
- package/dist/dashboard/server/legacyDashboardHtml.js +7 -2
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.d.ts +1 -1
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.js +8 -3
- package/dist/dashboard/server/routes/admin.feedback.routes.d.ts +15 -0
- package/dist/dashboard/server/routes/admin.feedback.routes.js +188 -0
- package/dist/dashboard/server/routes/admin.routes.js +35 -27
- package/dist/dashboard/server/routes/alerts.routes.js +4 -3
- package/dist/dashboard/server/routes/api.feedback.routes.js +2 -1
- package/dist/dashboard/server/routes/api.usage.routes.js +8 -7
- package/dist/dashboard/server/routes/embeddings.routes.d.ts +2 -1
- package/dist/dashboard/server/routes/embeddings.routes.js +18 -9
- package/dist/dashboard/server/routes/graph.routes.js +10 -13
- package/dist/dashboard/server/routes/index.d.ts +1 -0
- package/dist/dashboard/server/routes/index.js +74 -39
- package/dist/dashboard/server/routes/instances.routes.js +2 -1
- package/dist/dashboard/server/routes/instructions.routes.js +46 -27
- package/dist/dashboard/server/routes/knowledge.routes.js +4 -3
- package/dist/dashboard/server/routes/logs.routes.js +5 -4
- package/dist/dashboard/server/routes/messaging.routes.js +15 -14
- package/dist/dashboard/server/routes/metrics.routes.js +14 -13
- package/dist/dashboard/server/routes/scripts.routes.js +6 -3
- package/dist/dashboard/server/routes/status.routes.js +5 -4
- package/dist/dashboard/server/routes/synthetic.routes.js +3 -2
- package/dist/dashboard/server/routes/usage.routes.js +2 -1
- package/dist/dashboard/server/utils/escapeHtml.d.ts +1 -0
- package/dist/dashboard/server/utils/escapeHtml.js +11 -0
- package/dist/dashboard/server/utils/pathContainment.d.ts +1 -0
- package/dist/dashboard/server/utils/pathContainment.js +15 -0
- package/dist/dashboard/server/wsInit.js +2 -2
- package/dist/lib/mcpStdioLogging.d.ts +165 -0
- package/dist/lib/mcpStdioLogging.js +287 -0
- package/dist/schemas/index.d.ts +37 -2
- package/dist/schemas/index.js +27 -3
- package/dist/server/backgroundServicesStartup.d.ts +7 -1
- package/dist/server/backgroundServicesStartup.js +25 -8
- package/dist/server/certInit.d.ts +97 -0
- package/dist/server/certInit.js +359 -0
- package/dist/server/certInit.types.d.ts +92 -0
- package/dist/server/certInit.types.js +34 -0
- package/dist/server/handshake/fallbackFrames.d.ts +31 -0
- package/dist/server/handshake/fallbackFrames.js +38 -0
- package/dist/server/handshake/initializeDetector.d.ts +31 -0
- package/dist/server/handshake/initializeDetector.js +88 -0
- package/dist/server/handshake/protocol.d.ts +15 -0
- package/dist/server/handshake/protocol.js +37 -0
- package/dist/server/handshake/readyEmitter.d.ts +6 -0
- package/dist/server/handshake/readyEmitter.js +88 -0
- package/dist/server/handshake/safetyFallbacks.d.ts +1 -0
- package/dist/server/handshake/safetyFallbacks.js +134 -0
- package/dist/server/handshake/stdinSniffer.d.ts +1 -0
- package/dist/server/handshake/stdinSniffer.js +260 -0
- package/dist/server/handshake/tracing.d.ts +16 -0
- package/dist/server/handshake/tracing.js +95 -0
- package/dist/server/handshakeManager.d.ts +23 -23
- package/dist/server/handshakeManager.js +36 -466
- package/dist/server/index-server.d.ts +23 -0
- package/dist/server/index-server.js +194 -9
- package/dist/server/mcpReadOnlySurfaces.d.ts +44 -0
- package/dist/server/mcpReadOnlySurfaces.js +297 -0
- package/dist/server/sdkServer.js +69 -7
- package/dist/server/transport.d.ts +5 -6
- package/dist/server/transport.js +46 -64
- package/dist/server/transportFactory.d.ts +3 -9
- package/dist/server/transportFactory.js +18 -380
- package/dist/services/atomicFs.d.ts +3 -0
- package/dist/services/atomicFs.js +171 -13
- package/dist/services/auditLog.d.ts +17 -2
- package/dist/services/auditLog.js +75 -14
- package/dist/services/bootstrapGating.js +1 -1
- package/dist/services/categoryRules.d.ts +10 -0
- package/dist/services/categoryRules.js +17 -0
- package/dist/services/classificationService.js +7 -5
- package/dist/services/embeddingService.d.ts +27 -11
- package/dist/services/embeddingService.js +51 -14
- package/dist/services/feedbackStorage.d.ts +39 -0
- package/dist/services/feedbackStorage.js +88 -0
- package/dist/services/handlers/instructions.add.js +429 -317
- package/dist/services/handlers/instructions.groom.js +128 -31
- package/dist/services/handlers/instructions.import.js +56 -23
- package/dist/services/handlers/instructions.patch.js +43 -32
- package/dist/services/handlers/instructions.query.js +20 -29
- package/dist/services/handlers/instructions.shared.d.ts +54 -0
- package/dist/services/handlers/instructions.shared.js +126 -1
- package/dist/services/handlers.activation.js +83 -81
- package/dist/services/handlers.dashboardConfig.d.ts +2 -2
- package/dist/services/handlers.dashboardConfig.js +1 -2
- package/dist/services/handlers.diagnostics.js +75 -54
- package/dist/services/handlers.feedback.d.ts +4 -11
- package/dist/services/handlers.feedback.js +11 -333
- package/dist/services/handlers.gates.js +69 -37
- package/dist/services/handlers.graph.js +2 -2
- package/dist/services/handlers.help.js +2 -2
- package/dist/services/handlers.instructionSchema.js +4 -2
- package/dist/services/handlers.integrity.js +42 -22
- package/dist/services/handlers.messaging.js +1 -1
- package/dist/services/handlers.metrics.js +51 -6
- package/dist/services/handlers.prompt.js +10 -2
- package/dist/services/handlers.search.js +94 -44
- package/dist/services/handlers.trace.js +1 -1
- package/dist/services/handlers.usage.js +38 -7
- package/dist/services/indexContext.d.ts +21 -1
- package/dist/services/indexContext.js +263 -78
- package/dist/services/indexLoader.d.ts +1 -0
- package/dist/services/indexLoader.js +28 -8
- package/dist/services/instructionRecordValidation.d.ts +39 -0
- package/dist/services/instructionRecordValidation.js +388 -0
- package/dist/services/instructions.dispatcher.js +4 -4
- package/dist/services/loaderSchemaValidator.d.ts +15 -0
- package/dist/services/loaderSchemaValidator.js +69 -0
- package/dist/services/logger.js +11 -2
- package/dist/services/mcpLogBridge.d.ts +49 -0
- package/dist/services/mcpLogBridge.js +83 -0
- package/dist/services/ownershipService.js +18 -8
- package/dist/services/performanceBaseline.js +23 -22
- package/dist/services/promptReviewService.d.ts +3 -1
- package/dist/services/promptReviewService.js +41 -13
- package/dist/services/regexSafety.d.ts +6 -0
- package/dist/services/regexSafety.js +46 -0
- package/dist/services/seedBootstrap.js +1 -1
- package/dist/services/storage/factory.d.ts +14 -1
- package/dist/services/storage/factory.js +61 -1
- package/dist/services/storage/jsonEmbeddingStore.d.ts +15 -0
- package/dist/services/storage/jsonEmbeddingStore.js +83 -0
- package/dist/services/storage/jsonFileStore.d.ts +3 -1
- package/dist/services/storage/jsonFileStore.js +8 -6
- package/dist/services/storage/migrationEngine.d.ts +13 -0
- package/dist/services/storage/migrationEngine.js +31 -0
- package/dist/services/storage/sqliteEmbeddingStore.d.ts +30 -0
- package/dist/services/storage/sqliteEmbeddingStore.js +222 -0
- package/dist/services/storage/sqliteStore.d.ts +3 -1
- package/dist/services/storage/sqliteStore.js +2 -2
- package/dist/services/storage/types.d.ts +48 -1
- package/dist/services/toolRegistry.js +77 -67
- package/dist/services/toolRegistry.zod.js +89 -86
- package/dist/services/tracing.js +5 -4
- package/dist/utils/envUtils.d.ts +4 -0
- package/dist/utils/envUtils.js +7 -0
- package/dist/utils/memoryMonitor.js +11 -10
- package/package.json +11 -4
- package/schemas/instruction.schema.json +38 -1
- package/scripts/copy-dashboard-assets.mjs +1 -1
- package/scripts/dist/README.md +1 -1
- package/scripts/setup-wizard.mjs +781 -0
- package/server.json +1 -0
- package/dist/externalClientLib.d.ts +0 -1
- package/dist/externalClientLib.js +0 -2
- package/dist/portableClientWrapper.d.ts +0 -1
- package/dist/portableClientWrapper.js +0 -2
- package/dist/services/indexingService.d.ts +0 -1
- package/dist/services/indexingService.js +0 -2
|
@@ -6,14 +6,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.createSqliteRoutes = exports.createMessagingRoutes = exports.createScriptsRoutes = exports.createUsageRoutes = exports.createEmbeddingsRoutes = exports.createToolsRoutes = exports.createInstancesRoutes = exports.createSyntheticRoutes = exports.createLogsRoutes = exports.createAlertsRoutes = exports.createKnowledgeRoutes = exports.createInstructionsRoutes = exports.createGraphRoutes = exports.createAdminRoutes = exports.createMetricsRoutes = exports.createStatusRoutes = void 0;
|
|
9
|
+
exports.createAdminFeedbackRoutes = exports.createSqliteRoutes = exports.createMessagingRoutes = exports.createScriptsRoutes = exports.createUsageRoutes = exports.createEmbeddingsRoutes = exports.createToolsRoutes = exports.createInstancesRoutes = exports.createSyntheticRoutes = exports.createLogsRoutes = exports.createAlertsRoutes = exports.createKnowledgeRoutes = exports.createInstructionsRoutes = exports.createGraphRoutes = exports.createAdminRoutes = exports.createMetricsRoutes = exports.createStatusRoutes = void 0;
|
|
10
10
|
exports.renderPanelMarkdownHtml = renderPanelMarkdownHtml;
|
|
11
11
|
exports.mountDashboardRoutes = mountDashboardRoutes;
|
|
12
12
|
const promises_1 = require("fs/promises");
|
|
13
13
|
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
14
15
|
const ApiRoutes_js_1 = require("../ApiRoutes.js");
|
|
15
16
|
const legacyDashboardHtml_js_1 = require("../legacyDashboardHtml.js");
|
|
16
17
|
const registry_js_1 = require("../../../server/registry.js");
|
|
18
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
19
|
+
const escapeHtml_js_1 = require("../utils/escapeHtml.js");
|
|
20
|
+
const pathContainment_js_1 = require("../utils/pathContainment.js");
|
|
21
|
+
const runtimeConfig_js_1 = require("../../../config/runtimeConfig.js");
|
|
22
|
+
/**
|
|
23
|
+
* Strict allowlist for static-asset path parameters. Returns the matched
|
|
24
|
+
* filename only if it matches the allowlist regex; otherwise null. Using a
|
|
25
|
+
* fresh string from RegExp.exec() avoids passing the original tainted
|
|
26
|
+
* req.params.name down the file-access chain.
|
|
27
|
+
*/
|
|
28
|
+
function safeAssetName(raw, pattern) {
|
|
29
|
+
const match = pattern.exec(String(raw || ''));
|
|
30
|
+
return match ? match[0] : null;
|
|
31
|
+
}
|
|
17
32
|
var status_routes_js_1 = require("./status.routes.js");
|
|
18
33
|
Object.defineProperty(exports, "createStatusRoutes", { enumerable: true, get: function () { return status_routes_js_1.createStatusRoutes; } });
|
|
19
34
|
var metrics_routes_js_1 = require("./metrics.routes.js");
|
|
@@ -46,14 +61,8 @@ var messaging_routes_js_1 = require("./messaging.routes.js");
|
|
|
46
61
|
Object.defineProperty(exports, "createMessagingRoutes", { enumerable: true, get: function () { return messaging_routes_js_1.createMessagingRoutes; } });
|
|
47
62
|
var sqlite_routes_js_1 = require("./sqlite.routes.js");
|
|
48
63
|
Object.defineProperty(exports, "createSqliteRoutes", { enumerable: true, get: function () { return sqlite_routes_js_1.createSqliteRoutes; } });
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.replace(/&/g, '&')
|
|
52
|
-
.replace(/</g, '<')
|
|
53
|
-
.replace(/>/g, '>')
|
|
54
|
-
.replace(/"/g, '"')
|
|
55
|
-
.replace(/'/g, ''');
|
|
56
|
-
}
|
|
64
|
+
var admin_feedback_routes_js_1 = require("./admin.feedback.routes.js");
|
|
65
|
+
Object.defineProperty(exports, "createAdminFeedbackRoutes", { enumerable: true, get: function () { return admin_feedback_routes_js_1.createAdminFeedbackRoutes; } });
|
|
57
66
|
function sanitizeDocUrl(rawUrl, allowDataImage = false) {
|
|
58
67
|
const url = rawUrl.trim();
|
|
59
68
|
if (!url)
|
|
@@ -65,7 +74,7 @@ function sanitizeDocUrl(rawUrl, allowDataImage = false) {
|
|
|
65
74
|
return '#';
|
|
66
75
|
}
|
|
67
76
|
function renderPanelMarkdownHtml(name, markdown) {
|
|
68
|
-
const bodyHtml = escapeHtml(markdown)
|
|
77
|
+
const bodyHtml = (0, escapeHtml_js_1.escapeHtml)(markdown)
|
|
69
78
|
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
|
70
79
|
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
|
71
80
|
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
|
@@ -90,13 +99,33 @@ function renderPanelMarkdownHtml(name, markdown) {
|
|
|
90
99
|
.replace(/^- (.+)$/gm, '<li>$1</li>')
|
|
91
100
|
.replace(/((?:<li>.*<\/li>\n?)+)/g, '<ul>$1</ul>')
|
|
92
101
|
.replace(/\n{2,}/g, '\n<br>\n');
|
|
93
|
-
return `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${escapeHtml(name)} - Panel Docs</title><style>body{background:#0b0f19;color:#e3ebf5;font-family:'Segoe UI',system-ui,sans-serif;padding:24px 32px;max-width:800px;margin:0 auto;line-height:1.6;}h1{color:#667eea;border-bottom:1px solid #1f2a3a;padding-bottom:8px;}h2{color:#9fb5cc;margin-top:24px;}h3{color:#b0c4de;}table{width:100%;border-collapse:collapse;margin:12px 0;}td{padding:6px 10px;border:1px solid #1f2a3a;font-size:13px;}tr:first-child td{background:#101726;font-weight:600;}code{background:#182234;padding:2px 6px;border-radius:4px;font-size:12px;}a{color:#667eea;}hr{border:none;border-top:1px solid #1f2a3a;margin:20px 0;}ul{padding-left:20px;}li{margin:4px 0;}</style></head><body>${bodyHtml}</body></html>`;
|
|
102
|
+
return `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${(0, escapeHtml_js_1.escapeHtml)(name)} - Panel Docs</title><style>body{background:#0b0f19;color:#e3ebf5;font-family:'Segoe UI',system-ui,sans-serif;padding:24px 32px;max-width:800px;margin:0 auto;line-height:1.6;}h1{color:#667eea;border-bottom:1px solid #1f2a3a;padding-bottom:8px;}h2{color:#9fb5cc;margin-top:24px;}h3{color:#b0c4de;}table{width:100%;border-collapse:collapse;margin:12px 0;}td{padding:6px 10px;border:1px solid #1f2a3a;font-size:13px;}tr:first-child td{background:#101726;font-weight:600;}code{background:#182234;padding:2px 6px;border-radius:4px;font-size:12px;}a{color:#667eea;}hr{border:none;border-top:1px solid #1f2a3a;margin:20px 0;}ul{padding-left:20px;}li{margin:4px 0;}</style></head><body>${bodyHtml}</body></html>`;
|
|
94
103
|
}
|
|
95
104
|
/**
|
|
96
105
|
* Registers all top-level dashboard routes on the given Express app.
|
|
97
106
|
* Called once during DashboardServer construction after middleware is set up.
|
|
98
107
|
*/
|
|
99
108
|
function mountDashboardRoutes(app, ctx) {
|
|
109
|
+
// Build a per-route rate limiter using the same dashboard.http.rateLimit*
|
|
110
|
+
// configuration as the /api router. Re-uses the same window/max so behavior
|
|
111
|
+
// is consistent across the dashboard. Disabled if rateLimitEnabled is false.
|
|
112
|
+
const httpCfg = (0, runtimeConfig_js_1.getRuntimeConfig)().dashboard.http;
|
|
113
|
+
const dashboardLimiter = (0, express_rate_limit_1.default)({
|
|
114
|
+
windowMs: Math.max(1, httpCfg.rateLimitWindowMs),
|
|
115
|
+
max: Math.max(1, httpCfg.rateLimitMax),
|
|
116
|
+
standardHeaders: true,
|
|
117
|
+
legacyHeaders: false,
|
|
118
|
+
validate: { ip: false },
|
|
119
|
+
skip: () => !httpCfg.rateLimitEnabled,
|
|
120
|
+
handler: (_req, res) => {
|
|
121
|
+
const retryAfter = Number(res.getHeader('Retry-After') || Math.ceil(httpCfg.rateLimitWindowMs / 1000));
|
|
122
|
+
res.status(429).json({
|
|
123
|
+
error: 'Too Many Requests',
|
|
124
|
+
message: `Rate limit exceeded. Try again in ${retryAfter} second(s).`,
|
|
125
|
+
retryAfterSeconds: retryAfter,
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
});
|
|
100
129
|
// Redirect root to admin panel (v2 dashboard)
|
|
101
130
|
app.get('/', (_req, res) => {
|
|
102
131
|
res.redirect('/admin');
|
|
@@ -112,7 +141,7 @@ function mountDashboardRoutes(app, ctx) {
|
|
|
112
141
|
res.send((0, legacyDashboardHtml_js_1.generateDashboardHtml)(nonce, snapshot, webSocketUrl));
|
|
113
142
|
});
|
|
114
143
|
// Admin Panel (v2 dashboard — primary UI)
|
|
115
|
-
app.get('/admin', async (_req, res) => {
|
|
144
|
+
app.get('/admin', dashboardLimiter, async (_req, res) => {
|
|
116
145
|
try {
|
|
117
146
|
// __dirname here is src/dashboard/server/routes — step up two levels to reach client/
|
|
118
147
|
const adminHtmlPath = path_1.default.join(__dirname, '..', '..', 'client', 'admin.html');
|
|
@@ -121,13 +150,16 @@ function mountDashboardRoutes(app, ctx) {
|
|
|
121
150
|
adminHtml = (0, legacyDashboardHtml_js_1.stripGraphTab)(adminHtml);
|
|
122
151
|
}
|
|
123
152
|
const nonce = res.locals.cspNonce;
|
|
124
|
-
|
|
125
|
-
|
|
153
|
+
// Inject the CSP nonce by replacing literal opening <script> tokens
|
|
154
|
+
// with the nonce-bearing variant. The nonce is server-generated via
|
|
155
|
+
// crypto and never user-controlled. Avoid open-ended tag regex by
|
|
156
|
+
// matching only the exact literal opening forms used in admin.html.
|
|
157
|
+
adminHtml = adminHtml.split('<script>').join(`<script nonce="${nonce}">`);
|
|
158
|
+
adminHtml = adminHtml.split('<script defer ').join(`<script nonce="${nonce}" defer `);
|
|
126
159
|
res.type('html').send(adminHtml);
|
|
127
160
|
}
|
|
128
161
|
catch (error) {
|
|
129
|
-
|
|
130
|
-
console.error('[Dashboard] Admin panel load error:', error);
|
|
162
|
+
(0, logger_js_1.logError)('[Dashboard] Admin panel load error:', error);
|
|
131
163
|
res.status(500).send('<h1>500 - Admin Panel Error</h1><p>Failed to load admin panel</p>');
|
|
132
164
|
}
|
|
133
165
|
});
|
|
@@ -142,53 +174,57 @@ function mountDashboardRoutes(app, ctx) {
|
|
|
142
174
|
});
|
|
143
175
|
});
|
|
144
176
|
// Panel documentation — serves markdown rendered as styled HTML
|
|
145
|
-
app.get('/api/docs/:name', async (req, res) => {
|
|
146
|
-
|
|
177
|
+
app.get('/api/docs/:name', dashboardLimiter, async (req, res) => {
|
|
178
|
+
// Strict basename allowlist: a–z0–9_- only, 1–64 chars. Returns a fresh
|
|
179
|
+
// string from RegExp.exec; the original tainted req.params.name never
|
|
180
|
+
// reaches path.resolve. validatePathContainment is retained as
|
|
181
|
+
// defense-in-depth.
|
|
182
|
+
const name = safeAssetName(req.params.name, /^[a-z0-9_-]{1,64}$/i);
|
|
147
183
|
if (!name) {
|
|
148
184
|
res.status(400).send('Invalid doc name');
|
|
149
185
|
return;
|
|
150
186
|
}
|
|
151
187
|
const docsDir = path_1.default.resolve(__dirname, '..', '..', '..', '..', 'docs', 'panels');
|
|
152
|
-
const docPath = path_1.default.resolve(docsDir, `${name}.md`); // lgtm[js/path-injection] — startsWith guard on next line
|
|
153
|
-
// Security: verify resolved path stays inside the allowed docs directory
|
|
154
|
-
if (!docPath.startsWith(docsDir + path_1.default.sep) && docPath !== docsDir) {
|
|
155
|
-
res.status(400).send('Invalid doc name');
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
188
|
try {
|
|
189
|
+
const docPath = (0, pathContainment_js_1.validatePathContainment)(path_1.default.resolve(docsDir, `${name}.md`), docsDir);
|
|
159
190
|
const md = await (0, promises_1.readFile)(docPath, 'utf-8');
|
|
160
191
|
res.type('html').send(renderPanelMarkdownHtml(name, md));
|
|
161
192
|
}
|
|
162
|
-
catch {
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (error instanceof Error && error.message.startsWith('Path escapes allowed base:')) {
|
|
195
|
+
res.status(400).send('Invalid doc name');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
163
198
|
res.status(404).send('<h1>404</h1><p>Panel documentation not found.</p><p><a href="/admin">Back to Admin</a></p>');
|
|
164
199
|
}
|
|
165
200
|
});
|
|
166
201
|
// Panel screenshot — serves PNG images from docs/screenshots/
|
|
167
|
-
app.get('/api/screenshots/:name', async (req, res) => {
|
|
168
|
-
|
|
169
|
-
|
|
202
|
+
app.get('/api/screenshots/:name', dashboardLimiter, async (req, res) => {
|
|
203
|
+
// Strict basename allowlist: a–z0–9._- only, must end in .png, 1–80 chars.
|
|
204
|
+
const fileName = safeAssetName(req.params.name, /^[a-z0-9._-]{1,80}\.png$/i);
|
|
205
|
+
if (!fileName) {
|
|
170
206
|
res.status(400).send('Invalid');
|
|
171
207
|
return;
|
|
172
208
|
}
|
|
173
209
|
const screenshotsDir = path_1.default.resolve(__dirname, '..', '..', '..', '..', 'docs', 'screenshots');
|
|
174
|
-
const filePath = path_1.default.resolve(screenshotsDir, fileName);
|
|
175
|
-
// Security: verify resolved path stays inside the allowed screenshots directory
|
|
176
|
-
if (!filePath.startsWith(screenshotsDir + path_1.default.sep)) {
|
|
177
|
-
res.status(400).send('Invalid path');
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
210
|
try {
|
|
211
|
+
const filePath = (0, pathContainment_js_1.validatePathContainment)(path_1.default.resolve(screenshotsDir, fileName), screenshotsDir);
|
|
181
212
|
const data = await (0, promises_1.readFile)(filePath);
|
|
182
213
|
res.setHeader('Content-Type', 'image/png');
|
|
183
214
|
res.setHeader('Cache-Control', 'public, max-age=3600');
|
|
184
215
|
res.send(data);
|
|
185
216
|
}
|
|
186
|
-
catch {
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (error instanceof Error && error.message.startsWith('Path escapes allowed base:')) {
|
|
219
|
+
res.status(400).send('Invalid path');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
187
222
|
res.status(404).send('Screenshot not found');
|
|
188
223
|
}
|
|
189
224
|
});
|
|
190
|
-
// API sub-routes (mounted at /api)
|
|
191
|
-
|
|
225
|
+
// API sub-routes (mounted at /api). Rate limits sourced from runtimeConfig
|
|
226
|
+
// (INDEX_SERVER_RATE_LIMIT_*) — see ApiRoutes.createApiRoutes.
|
|
227
|
+
app.use('/api', (0, ApiRoutes_js_1.createApiRoutes)({ enableCors: ctx.enableCors }));
|
|
192
228
|
// Back-compat: legacy tests expect /tools.json at dashboard root
|
|
193
229
|
app.get('/tools.json', (_req, res) => {
|
|
194
230
|
try {
|
|
@@ -209,8 +245,7 @@ function mountDashboardRoutes(app, ctx) {
|
|
|
209
245
|
res.json({ tools: enrichedTools, totalTools: tools.length, timestamp: Date.now(), legacy: true });
|
|
210
246
|
}
|
|
211
247
|
catch (error) {
|
|
212
|
-
|
|
213
|
-
console.error('[Dashboard] /tools.json route error:', error);
|
|
248
|
+
(0, logger_js_1.logError)('[Dashboard] /tools.json route error:', error);
|
|
214
249
|
res.status(500).json({ error: 'Failed to get tools list' });
|
|
215
250
|
}
|
|
216
251
|
});
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.createInstancesRoutes = createInstancesRoutes;
|
|
8
8
|
const express_1 = require("express");
|
|
9
9
|
const InstanceManager_js_1 = require("../InstanceManager.js");
|
|
10
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
10
11
|
function createInstancesRoutes() {
|
|
11
12
|
const router = (0, express_1.Router)();
|
|
12
13
|
/**
|
|
@@ -24,7 +25,7 @@ function createInstancesRoutes() {
|
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
catch (error) {
|
|
27
|
-
|
|
28
|
+
(0, logger_js_1.logError)('[API] Failed to list instances:', error);
|
|
28
29
|
res.status(500).json({
|
|
29
30
|
error: 'Failed to list instances',
|
|
30
31
|
timestamp: Date.now(),
|
|
@@ -16,16 +16,14 @@ const registry_js_1 = require("../../../server/registry.js");
|
|
|
16
16
|
const indexContext_js_1 = require("../../../services/indexContext.js");
|
|
17
17
|
const adminAuth_js_1 = require("./adminAuth.js");
|
|
18
18
|
const handlers_search_js_1 = require("../../../services/handlers.search.js");
|
|
19
|
+
const instructionRecordValidation_js_1 = require("../../../services/instructionRecordValidation.js");
|
|
20
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
21
|
+
const pathContainment_js_1 = require("../utils/pathContainment.js");
|
|
19
22
|
/** Sanitize an instruction name with defense-in-depth path-traversal guard. */
|
|
20
23
|
function safeName(name) {
|
|
21
24
|
const sanitized = String(name).replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
22
|
-
// Defense-in-depth: verify the resolved path stays inside the instructions directory
|
|
23
25
|
const base = (0, indexContext_js_1.getInstructionsDir)();
|
|
24
|
-
|
|
25
|
-
const normalized = node_path_1.default.normalize(resolved);
|
|
26
|
-
if (!normalized.startsWith(node_path_1.default.normalize(base) + node_path_1.default.sep) && normalized !== node_path_1.default.normalize(base)) {
|
|
27
|
-
throw new Error('Path traversal detected');
|
|
28
|
-
}
|
|
26
|
+
(0, pathContainment_js_1.validatePathContainment)(node_path_1.default.resolve(base, `${sanitized}.json`), base);
|
|
29
27
|
return sanitized;
|
|
30
28
|
}
|
|
31
29
|
function createInstructionsRoutes() {
|
|
@@ -85,7 +83,7 @@ function createInstructionsRoutes() {
|
|
|
85
83
|
res.json({ success: true, instructions, count: instructions.length, timestamp: Date.now() });
|
|
86
84
|
}
|
|
87
85
|
catch (error) {
|
|
88
|
-
|
|
86
|
+
(0, logger_js_1.logError)('[API] Failed to list instructions:', error);
|
|
89
87
|
res.status(500).json({ success: false, error: 'Failed to list instructions' });
|
|
90
88
|
}
|
|
91
89
|
});
|
|
@@ -134,7 +132,7 @@ function createInstructionsRoutes() {
|
|
|
134
132
|
res.json({ success: true, query, count: results.length, results, timestamp: Date.now() });
|
|
135
133
|
}
|
|
136
134
|
catch (error) {
|
|
137
|
-
|
|
135
|
+
(0, logger_js_1.logError)('[API] instructions search error:', error);
|
|
138
136
|
res.status(500).json({ success: false, error: 'search_failed' });
|
|
139
137
|
}
|
|
140
138
|
});
|
|
@@ -158,7 +156,7 @@ function createInstructionsRoutes() {
|
|
|
158
156
|
});
|
|
159
157
|
}
|
|
160
158
|
catch (error) {
|
|
161
|
-
|
|
159
|
+
(0, logger_js_1.logError)('[API] Failed to get categories:', error);
|
|
162
160
|
res.status(500).json({
|
|
163
161
|
success: false,
|
|
164
162
|
error: 'Failed to get categories',
|
|
@@ -178,7 +176,7 @@ function createInstructionsRoutes() {
|
|
|
178
176
|
res.json({ success: true, content: entry, timestamp: Date.now() });
|
|
179
177
|
}
|
|
180
178
|
catch (error) {
|
|
181
|
-
|
|
179
|
+
(0, logger_js_1.logError)('[API] Failed to load instruction:', error);
|
|
182
180
|
res.status(500).json({ success: false, error: 'Failed to load instruction' });
|
|
183
181
|
}
|
|
184
182
|
});
|
|
@@ -186,7 +184,7 @@ function createInstructionsRoutes() {
|
|
|
186
184
|
* POST /api/instructions - create new instruction
|
|
187
185
|
* body: { name, content }
|
|
188
186
|
*/
|
|
189
|
-
router.post('/instructions', adminAuth_js_1.dashboardAdminAuth, (req, res) => {
|
|
187
|
+
router.post('/instructions', adminAuth_js_1.dashboardAdminAuth, async (req, res) => {
|
|
190
188
|
try {
|
|
191
189
|
const { name, content } = req.body || {};
|
|
192
190
|
if (!name || !content)
|
|
@@ -195,29 +193,42 @@ function createInstructionsRoutes() {
|
|
|
195
193
|
const st = res.locals.indexState;
|
|
196
194
|
if (st.byId.has(id))
|
|
197
195
|
return res.status(409).json({ success: false, error: 'Instruction already exists' });
|
|
196
|
+
const contentObj = typeof content === 'object' && content !== null ? content : {}; // lgtm[js/comparison-between-incompatible-types] — idiomatic typeof-object plus null check (typeof null === 'object' in JS)
|
|
198
197
|
const entry = {
|
|
199
|
-
...
|
|
198
|
+
...contentObj,
|
|
200
199
|
id,
|
|
201
|
-
title:
|
|
202
|
-
body:
|
|
200
|
+
title: contentObj.title || id,
|
|
201
|
+
body: contentObj.body || (typeof content === 'string' ? content : ''),
|
|
202
|
+
categories: Array.isArray(contentObj.categories) ? contentObj.categories : [],
|
|
203
|
+
priority: typeof contentObj.priority === 'number' ? contentObj.priority : 50,
|
|
204
|
+
audience: contentObj.audience || 'all',
|
|
205
|
+
requirement: contentObj.requirement || 'optional',
|
|
203
206
|
createdAt: new Date().toISOString(),
|
|
204
207
|
updatedAt: new Date().toISOString(),
|
|
205
208
|
};
|
|
206
|
-
(0, indexContext_js_1.
|
|
209
|
+
await (0, indexContext_js_1.writeEntryAsync)(entry); // lgtm[js/http-to-file-access] — writes to config-controlled instructions directory
|
|
207
210
|
(0, indexContext_js_1.touchIndexVersion)();
|
|
208
211
|
(0, indexContext_js_1.invalidate)();
|
|
209
|
-
(0, indexContext_js_1.
|
|
210
|
-
|
|
212
|
+
const reloaded = await (0, indexContext_js_1.ensureLoadedAsync)();
|
|
213
|
+
const verified = reloaded.byId.has(id);
|
|
214
|
+
if (!verified) {
|
|
215
|
+
(0, logger_js_1.logError)('[API] Instruction written but NOT visible after reload', { id });
|
|
216
|
+
return res.status(500).json({ success: false, error: 'Instruction written but failed read-back verification' });
|
|
217
|
+
}
|
|
218
|
+
res.json({ success: true, message: 'Instruction created', name: id, verified, timestamp: Date.now() });
|
|
211
219
|
}
|
|
212
220
|
catch (error) {
|
|
213
|
-
|
|
221
|
+
if ((0, instructionRecordValidation_js_1.isInstructionValidationError)(error)) {
|
|
222
|
+
return res.status(400).json({ success: false, error: 'invalid_instruction', validationErrors: error.validationErrors });
|
|
223
|
+
}
|
|
224
|
+
(0, logger_js_1.logError)('[API] Failed to create instruction:', error);
|
|
214
225
|
res.status(500).json({ success: false, error: 'Failed to create instruction' });
|
|
215
226
|
}
|
|
216
227
|
});
|
|
217
228
|
/**
|
|
218
229
|
* PUT /api/instructions/:name - update existing instruction
|
|
219
230
|
*/
|
|
220
|
-
router.put('/instructions/:name', adminAuth_js_1.dashboardAdminAuth, (req, res) => {
|
|
231
|
+
router.put('/instructions/:name', adminAuth_js_1.dashboardAdminAuth, async (req, res) => {
|
|
221
232
|
try {
|
|
222
233
|
const { content } = req.body || {};
|
|
223
234
|
const id = safeName(req.params.name);
|
|
@@ -229,25 +240,33 @@ function createInstructionsRoutes() {
|
|
|
229
240
|
return res.status(404).json({ success: false, error: 'Not found' });
|
|
230
241
|
const updated = {
|
|
231
242
|
...existing,
|
|
232
|
-
...(typeof content === 'object' && content !== null ? content : {}),
|
|
243
|
+
...(typeof content === 'object' && content !== null ? content : {}), // lgtm[js/comparison-between-incompatible-types] — idiomatic typeof-object plus null check (typeof null === 'object' in JS)
|
|
233
244
|
id, // preserve id
|
|
234
245
|
updatedAt: new Date().toISOString(),
|
|
235
246
|
};
|
|
236
|
-
(0, indexContext_js_1.
|
|
247
|
+
await (0, indexContext_js_1.writeEntryAsync)(updated); // lgtm[js/http-to-file-access] — writes to config-controlled instructions directory
|
|
237
248
|
(0, indexContext_js_1.touchIndexVersion)();
|
|
238
249
|
(0, indexContext_js_1.invalidate)();
|
|
239
|
-
(0, indexContext_js_1.
|
|
240
|
-
|
|
250
|
+
const reloaded = await (0, indexContext_js_1.ensureLoadedAsync)();
|
|
251
|
+
const verified = reloaded.byId.has(id);
|
|
252
|
+
if (!verified) {
|
|
253
|
+
(0, logger_js_1.logError)('[API] Instruction updated but NOT visible after reload', { id });
|
|
254
|
+
return res.status(500).json({ success: false, error: 'Instruction updated but failed read-back verification' });
|
|
255
|
+
}
|
|
256
|
+
res.json({ success: true, message: 'Instruction updated', verified, timestamp: Date.now() });
|
|
241
257
|
}
|
|
242
258
|
catch (error) {
|
|
243
|
-
|
|
259
|
+
if ((0, instructionRecordValidation_js_1.isInstructionValidationError)(error)) {
|
|
260
|
+
return res.status(400).json({ success: false, error: 'invalid_instruction', validationErrors: error.validationErrors });
|
|
261
|
+
}
|
|
262
|
+
(0, logger_js_1.logError)('[API] Failed to update instruction:', error);
|
|
244
263
|
res.status(500).json({ success: false, error: 'Failed to update instruction' });
|
|
245
264
|
}
|
|
246
265
|
});
|
|
247
266
|
/**
|
|
248
267
|
* DELETE /api/instructions/:name - delete instruction
|
|
249
268
|
*/
|
|
250
|
-
router.delete('/instructions/:name', adminAuth_js_1.dashboardAdminAuth, (req, res) => {
|
|
269
|
+
router.delete('/instructions/:name', adminAuth_js_1.dashboardAdminAuth, async (req, res) => {
|
|
251
270
|
try {
|
|
252
271
|
const id = safeName(req.params.name);
|
|
253
272
|
const st = res.locals.indexState;
|
|
@@ -256,11 +275,11 @@ function createInstructionsRoutes() {
|
|
|
256
275
|
(0, indexContext_js_1.removeEntry)(id);
|
|
257
276
|
(0, indexContext_js_1.touchIndexVersion)();
|
|
258
277
|
(0, indexContext_js_1.invalidate)();
|
|
259
|
-
(0, indexContext_js_1.
|
|
278
|
+
await (0, indexContext_js_1.ensureLoadedAsync)();
|
|
260
279
|
res.json({ success: true, message: 'Instruction deleted', timestamp: Date.now() });
|
|
261
280
|
}
|
|
262
281
|
catch (error) {
|
|
263
|
-
|
|
282
|
+
(0, logger_js_1.logError)('[API] Failed to delete instruction:', error);
|
|
264
283
|
res.status(500).json({ success: false, error: 'Failed to delete instruction' });
|
|
265
284
|
}
|
|
266
285
|
});
|
|
@@ -8,6 +8,7 @@ exports.createKnowledgeRoutes = createKnowledgeRoutes;
|
|
|
8
8
|
const express_1 = require("express");
|
|
9
9
|
const KnowledgeStore_js_1 = require("../KnowledgeStore.js");
|
|
10
10
|
const adminAuth_js_1 = require("./adminAuth.js");
|
|
11
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
11
12
|
function createKnowledgeRoutes() {
|
|
12
13
|
const router = (0, express_1.Router)();
|
|
13
14
|
/**
|
|
@@ -28,7 +29,7 @@ function createKnowledgeRoutes() {
|
|
|
28
29
|
res.json({ success: true, entry, timestamp: Date.now() });
|
|
29
30
|
}
|
|
30
31
|
catch (error) {
|
|
31
|
-
|
|
32
|
+
(0, logger_js_1.logError)('[API] Knowledge store error:', error);
|
|
32
33
|
res.status(500).json({
|
|
33
34
|
success: false,
|
|
34
35
|
error: 'Failed to store knowledge entry',
|
|
@@ -54,7 +55,7 @@ function createKnowledgeRoutes() {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
catch (error) {
|
|
57
|
-
|
|
58
|
+
(0, logger_js_1.logError)('[API] Knowledge search error:', error);
|
|
58
59
|
res.status(500).json({ success: false, error: 'Failed to search knowledge' });
|
|
59
60
|
}
|
|
60
61
|
});
|
|
@@ -72,7 +73,7 @@ function createKnowledgeRoutes() {
|
|
|
72
73
|
res.json({ success: true, ...entry, timestamp: Date.now() });
|
|
73
74
|
}
|
|
74
75
|
catch (error) {
|
|
75
|
-
|
|
76
|
+
(0, logger_js_1.logError)('[API] Knowledge get error:', error);
|
|
76
77
|
res.status(500).json({ success: false, error: 'Failed to get knowledge entry' });
|
|
77
78
|
}
|
|
78
79
|
});
|
|
@@ -11,6 +11,7 @@ exports.createLogsRoutes = createLogsRoutes;
|
|
|
11
11
|
const express_1 = require("express");
|
|
12
12
|
const fs_1 = __importDefault(require("fs"));
|
|
13
13
|
const runtimeConfig_js_1 = require("../../../config/runtimeConfig.js");
|
|
14
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
14
15
|
function createLogsRoutes() {
|
|
15
16
|
const router = (0, express_1.Router)();
|
|
16
17
|
/**
|
|
@@ -53,7 +54,7 @@ function createLogsRoutes() {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
catch (error) {
|
|
56
|
-
|
|
57
|
+
(0, logger_js_1.logError)('[API] Logs error:', error);
|
|
57
58
|
res.status(500).json({
|
|
58
59
|
error: 'Failed to read logs',
|
|
59
60
|
timestamp: Date.now()
|
|
@@ -120,7 +121,7 @@ function createLogsRoutes() {
|
|
|
120
121
|
lastSize = currentStats.size;
|
|
121
122
|
});
|
|
122
123
|
stream.on('error', (error) => {
|
|
123
|
-
|
|
124
|
+
(0, logger_js_1.logError)('[Logs] Stream read error:', error);
|
|
124
125
|
res.write(`data: ${JSON.stringify({
|
|
125
126
|
type: 'error',
|
|
126
127
|
message: 'Failed to read log stream',
|
|
@@ -130,7 +131,7 @@ function createLogsRoutes() {
|
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
catch (error) {
|
|
133
|
-
|
|
134
|
+
(0, logger_js_1.logError)('[Logs] Stream poll error:', error);
|
|
134
135
|
res.write(`data: ${JSON.stringify({
|
|
135
136
|
type: 'error',
|
|
136
137
|
message: 'Failed to poll log file',
|
|
@@ -154,7 +155,7 @@ function createLogsRoutes() {
|
|
|
154
155
|
});
|
|
155
156
|
}
|
|
156
157
|
catch (error) {
|
|
157
|
-
|
|
158
|
+
(0, logger_js_1.logError)('[Logs] Failed to start log streaming:', error);
|
|
158
159
|
res.write(`data: ${JSON.stringify({
|
|
159
160
|
type: 'error',
|
|
160
161
|
message: 'Failed to start log streaming',
|
|
@@ -21,6 +21,7 @@ const runtimeConfig_js_1 = require("../../../config/runtimeConfig.js");
|
|
|
21
21
|
const messagingTypes_js_1 = require("../../../services/messaging/messagingTypes.js");
|
|
22
22
|
const WebSocketManager_js_1 = require("../WebSocketManager.js");
|
|
23
23
|
const adminAuth_js_1 = require("./adminAuth.js");
|
|
24
|
+
const logger_js_1 = require("../../../services/logger.js");
|
|
24
25
|
let _mailbox = null;
|
|
25
26
|
function getMailbox() {
|
|
26
27
|
if (!_mailbox) {
|
|
@@ -68,12 +69,12 @@ function createMessagingRoutes() {
|
|
|
68
69
|
status: 'sent',
|
|
69
70
|
});
|
|
70
71
|
}).catch(err => {
|
|
71
|
-
|
|
72
|
+
(0, logger_js_1.logError)('[Messaging] Send failed:', err);
|
|
72
73
|
res.status(500).json({ success: false, error: 'Send failed' });
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
76
|
catch (error) {
|
|
76
|
-
|
|
77
|
+
(0, logger_js_1.logError)('[Messaging] Failed to send message:', error);
|
|
77
78
|
res.status(500).json({ success: false, error: 'Failed to send message' });
|
|
78
79
|
}
|
|
79
80
|
});
|
|
@@ -85,7 +86,7 @@ function createMessagingRoutes() {
|
|
|
85
86
|
res.json({ success: true, count: channels.length, channels });
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
88
|
-
|
|
89
|
+
(0, logger_js_1.logError)('[Messaging] Failed to list channels:', error);
|
|
89
90
|
res.status(500).json({ success: false, error: 'Failed to list channels' });
|
|
90
91
|
}
|
|
91
92
|
});
|
|
@@ -98,7 +99,7 @@ function createMessagingRoutes() {
|
|
|
98
99
|
res.json({ success: true, reader, ...stats });
|
|
99
100
|
}
|
|
100
101
|
catch (error) {
|
|
101
|
-
|
|
102
|
+
(0, logger_js_1.logError)('[Messaging] Failed to get stats:', error);
|
|
102
103
|
res.status(500).json({ success: false, error: 'Failed to get stats' });
|
|
103
104
|
}
|
|
104
105
|
});
|
|
@@ -114,7 +115,7 @@ function createMessagingRoutes() {
|
|
|
114
115
|
res.json({ success: true, message });
|
|
115
116
|
}
|
|
116
117
|
catch (error) {
|
|
117
|
-
|
|
118
|
+
(0, logger_js_1.logError)('[Messaging] Failed to get message:', error);
|
|
118
119
|
res.status(500).json({ success: false, error: 'Failed to get message' });
|
|
119
120
|
}
|
|
120
121
|
});
|
|
@@ -139,7 +140,7 @@ function createMessagingRoutes() {
|
|
|
139
140
|
res.json({ success: true, message: updated });
|
|
140
141
|
}
|
|
141
142
|
catch (error) {
|
|
142
|
-
|
|
143
|
+
(0, logger_js_1.logError)('[Messaging] Failed to update message:', error);
|
|
143
144
|
res.status(500).json({ success: false, error: 'Failed to update message' });
|
|
144
145
|
}
|
|
145
146
|
});
|
|
@@ -156,7 +157,7 @@ function createMessagingRoutes() {
|
|
|
156
157
|
res.json({ success: true, parentId, count: thread.length, messages: thread });
|
|
157
158
|
}
|
|
158
159
|
catch (error) {
|
|
159
|
-
|
|
160
|
+
(0, logger_js_1.logError)('[Messaging] Failed to get thread:', error);
|
|
160
161
|
res.status(500).json({ success: false, error: 'Failed to get thread' });
|
|
161
162
|
}
|
|
162
163
|
});
|
|
@@ -175,7 +176,7 @@ function createMessagingRoutes() {
|
|
|
175
176
|
res.json({ success: true, channel, reader, count: messages.length, messages });
|
|
176
177
|
}
|
|
177
178
|
catch (error) {
|
|
178
|
-
|
|
179
|
+
(0, logger_js_1.logError)('[Messaging] Failed to read messages:', error);
|
|
179
180
|
res.status(500).json({ success: false, error: 'Failed to read messages' });
|
|
180
181
|
}
|
|
181
182
|
});
|
|
@@ -200,7 +201,7 @@ function createMessagingRoutes() {
|
|
|
200
201
|
res.json({ success: true, acknowledged, reader });
|
|
201
202
|
}
|
|
202
203
|
catch (error) {
|
|
203
|
-
|
|
204
|
+
(0, logger_js_1.logError)('[Messaging] Failed to acknowledge messages:', error);
|
|
204
205
|
res.status(500).json({ success: false, error: 'Failed to acknowledge messages' });
|
|
205
206
|
}
|
|
206
207
|
});
|
|
@@ -209,7 +210,7 @@ function createMessagingRoutes() {
|
|
|
209
210
|
try {
|
|
210
211
|
const mailbox = getMailbox();
|
|
211
212
|
let removed;
|
|
212
|
-
let action
|
|
213
|
+
let action;
|
|
213
214
|
if (req.body?.messageIds?.length) {
|
|
214
215
|
removed = mailbox.deleteMessages(req.body.messageIds);
|
|
215
216
|
action = 'delete_by_ids';
|
|
@@ -229,7 +230,7 @@ function createMessagingRoutes() {
|
|
|
229
230
|
res.json({ success: true, action, purged: removed });
|
|
230
231
|
}
|
|
231
232
|
catch (error) {
|
|
232
|
-
|
|
233
|
+
(0, logger_js_1.logError)('[Messaging] Failed to purge messages:', error);
|
|
233
234
|
res.status(500).json({ success: false, error: 'Failed to purge messages' });
|
|
234
235
|
}
|
|
235
236
|
});
|
|
@@ -267,12 +268,12 @@ function createMessagingRoutes() {
|
|
|
267
268
|
catch { /* ws optional */ }
|
|
268
269
|
res.json({ success: true, status: 'received' });
|
|
269
270
|
}).catch(err => {
|
|
270
|
-
|
|
271
|
+
(0, logger_js_1.logError)('[Messaging] Inbound failed:', err);
|
|
271
272
|
res.status(500).json({ success: false, error: 'Inbound failed' });
|
|
272
273
|
});
|
|
273
274
|
}
|
|
274
275
|
catch (error) {
|
|
275
|
-
|
|
276
|
+
(0, logger_js_1.logError)('[Messaging] Failed to process inbound message:', error);
|
|
276
277
|
res.status(500).json({ success: false, error: 'Failed to process inbound message' });
|
|
277
278
|
}
|
|
278
279
|
});
|
|
@@ -297,7 +298,7 @@ function createMessagingRoutes() {
|
|
|
297
298
|
res.json({ success: true, message: result });
|
|
298
299
|
}
|
|
299
300
|
catch (error) {
|
|
300
|
-
|
|
301
|
+
(0, logger_js_1.logError)('[Messaging] Failed to reply to message:', error);
|
|
301
302
|
const isNotFound = error instanceof Error && error.message.includes('not found');
|
|
302
303
|
const status = isNotFound ? 404 : 500;
|
|
303
304
|
res.status(status).json({ success: false, error: isNotFound ? 'Parent message not found' : 'Failed to reply to message' });
|