@jagilber-org/index-server 1.22.0 → 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.
Files changed (189) hide show
  1. package/CHANGELOG.md +87 -2
  2. package/CODE_OF_CONDUCT.md +2 -0
  3. package/CONTRIBUTING.md +32 -2
  4. package/README.md +83 -20
  5. package/SECURITY.md +17 -5
  6. package/dist/config/dashboardConfig.d.ts +3 -0
  7. package/dist/config/dashboardConfig.js +3 -0
  8. package/dist/config/defaultValues.d.ts +1 -1
  9. package/dist/config/defaultValues.js +1 -1
  10. package/dist/config/featureConfig.d.ts +2 -0
  11. package/dist/config/featureConfig.js +6 -1
  12. package/dist/config/runtimeConfig.d.ts +1 -1
  13. package/dist/config/runtimeConfig.js +8 -9
  14. package/dist/dashboard/client/admin.html +173 -54
  15. package/dist/dashboard/client/css/admin.css +151 -0
  16. package/dist/dashboard/client/js/admin.auth.js +25 -11
  17. package/dist/dashboard/client/js/admin.config.js +1 -1
  18. package/dist/dashboard/client/js/admin.feedback.js +328 -0
  19. package/dist/dashboard/client/js/admin.graph.js +120 -18
  20. package/dist/dashboard/client/js/admin.instructions.js +27 -13
  21. package/dist/dashboard/client/js/admin.logs.js +1 -5
  22. package/dist/dashboard/client/js/admin.maintenance.js +53 -8
  23. package/dist/dashboard/client/js/admin.messaging.js +1 -4
  24. package/dist/dashboard/client/js/admin.overview.js +5 -1
  25. package/dist/dashboard/client/js/admin.sessions.js +1 -1
  26. package/dist/dashboard/client/js/admin.utils.js +43 -1
  27. package/dist/dashboard/client/js/mermaid.min.js +813 -537
  28. package/dist/dashboard/export/DataExporter.js +2 -1
  29. package/dist/dashboard/server/AdminPanel.d.ts +3 -0
  30. package/dist/dashboard/server/AdminPanel.js +132 -35
  31. package/dist/dashboard/server/ApiRoutes.js +40 -9
  32. package/dist/dashboard/server/DashboardServer.js +1 -1
  33. package/dist/dashboard/server/FileMetricsStorage.d.ts +19 -0
  34. package/dist/dashboard/server/FileMetricsStorage.js +52 -5
  35. package/dist/dashboard/server/HttpTransport.js +6 -0
  36. package/dist/dashboard/server/InstanceManager.js +7 -2
  37. package/dist/dashboard/server/KnowledgeStore.js +7 -2
  38. package/dist/dashboard/server/MetricsCollector.d.ts +16 -0
  39. package/dist/dashboard/server/MetricsCollector.js +113 -17
  40. package/dist/dashboard/server/legacyDashboardHtml.js +7 -2
  41. package/dist/dashboard/server/middleware/ensureLoadedMiddleware.d.ts +1 -1
  42. package/dist/dashboard/server/middleware/ensureLoadedMiddleware.js +8 -3
  43. package/dist/dashboard/server/routes/admin.feedback.routes.d.ts +15 -0
  44. package/dist/dashboard/server/routes/admin.feedback.routes.js +188 -0
  45. package/dist/dashboard/server/routes/admin.routes.js +35 -27
  46. package/dist/dashboard/server/routes/alerts.routes.js +4 -3
  47. package/dist/dashboard/server/routes/api.feedback.routes.js +2 -1
  48. package/dist/dashboard/server/routes/api.usage.routes.js +8 -7
  49. package/dist/dashboard/server/routes/embeddings.routes.d.ts +2 -1
  50. package/dist/dashboard/server/routes/embeddings.routes.js +18 -9
  51. package/dist/dashboard/server/routes/graph.routes.js +10 -13
  52. package/dist/dashboard/server/routes/index.d.ts +1 -0
  53. package/dist/dashboard/server/routes/index.js +74 -39
  54. package/dist/dashboard/server/routes/instances.routes.js +2 -1
  55. package/dist/dashboard/server/routes/instructions.routes.js +46 -27
  56. package/dist/dashboard/server/routes/knowledge.routes.js +4 -3
  57. package/dist/dashboard/server/routes/logs.routes.js +5 -4
  58. package/dist/dashboard/server/routes/messaging.routes.js +15 -14
  59. package/dist/dashboard/server/routes/metrics.routes.js +14 -13
  60. package/dist/dashboard/server/routes/scripts.routes.js +6 -3
  61. package/dist/dashboard/server/routes/status.routes.js +25 -6
  62. package/dist/dashboard/server/routes/synthetic.routes.js +3 -2
  63. package/dist/dashboard/server/routes/usage.routes.js +2 -1
  64. package/dist/dashboard/server/utils/escapeHtml.d.ts +1 -0
  65. package/dist/dashboard/server/utils/escapeHtml.js +11 -0
  66. package/dist/dashboard/server/utils/pathContainment.d.ts +1 -0
  67. package/dist/dashboard/server/utils/pathContainment.js +15 -0
  68. package/dist/dashboard/server/wsInit.js +2 -2
  69. package/dist/lib/mcpStdioLogging.d.ts +165 -0
  70. package/dist/lib/mcpStdioLogging.js +287 -0
  71. package/dist/schemas/index.d.ts +37 -2
  72. package/dist/schemas/index.js +27 -3
  73. package/dist/server/backgroundServicesStartup.d.ts +7 -1
  74. package/dist/server/backgroundServicesStartup.js +25 -8
  75. package/dist/server/certInit.d.ts +97 -0
  76. package/dist/server/certInit.js +359 -0
  77. package/dist/server/certInit.types.d.ts +92 -0
  78. package/dist/server/certInit.types.js +34 -0
  79. package/dist/server/handshake/fallbackFrames.d.ts +31 -0
  80. package/dist/server/handshake/fallbackFrames.js +38 -0
  81. package/dist/server/handshake/initializeDetector.d.ts +31 -0
  82. package/dist/server/handshake/initializeDetector.js +88 -0
  83. package/dist/server/handshake/protocol.d.ts +15 -0
  84. package/dist/server/handshake/protocol.js +37 -0
  85. package/dist/server/handshake/readyEmitter.d.ts +6 -0
  86. package/dist/server/handshake/readyEmitter.js +88 -0
  87. package/dist/server/handshake/safetyFallbacks.d.ts +1 -0
  88. package/dist/server/handshake/safetyFallbacks.js +134 -0
  89. package/dist/server/handshake/stdinSniffer.d.ts +1 -0
  90. package/dist/server/handshake/stdinSniffer.js +260 -0
  91. package/dist/server/handshake/tracing.d.ts +16 -0
  92. package/dist/server/handshake/tracing.js +95 -0
  93. package/dist/server/handshakeManager.d.ts +23 -23
  94. package/dist/server/handshakeManager.js +36 -466
  95. package/dist/server/index-server.d.ts +23 -0
  96. package/dist/server/index-server.js +194 -9
  97. package/dist/server/mcpReadOnlySurfaces.d.ts +44 -0
  98. package/dist/server/mcpReadOnlySurfaces.js +297 -0
  99. package/dist/server/sdkServer.js +69 -7
  100. package/dist/server/transport.d.ts +5 -6
  101. package/dist/server/transport.js +46 -64
  102. package/dist/server/transportFactory.d.ts +3 -9
  103. package/dist/server/transportFactory.js +18 -380
  104. package/dist/services/atomicFs.d.ts +3 -0
  105. package/dist/services/atomicFs.js +171 -13
  106. package/dist/services/auditLog.d.ts +17 -2
  107. package/dist/services/auditLog.js +75 -14
  108. package/dist/services/bootstrapGating.js +1 -1
  109. package/dist/services/categoryRules.d.ts +10 -0
  110. package/dist/services/categoryRules.js +17 -0
  111. package/dist/services/classificationService.js +7 -5
  112. package/dist/services/embeddingService.d.ts +27 -11
  113. package/dist/services/embeddingService.js +51 -14
  114. package/dist/services/feedbackStorage.d.ts +39 -0
  115. package/dist/services/feedbackStorage.js +88 -0
  116. package/dist/services/handlers/instructions.add.js +429 -317
  117. package/dist/services/handlers/instructions.groom.js +128 -31
  118. package/dist/services/handlers/instructions.import.js +56 -23
  119. package/dist/services/handlers/instructions.patch.js +43 -32
  120. package/dist/services/handlers/instructions.query.js +20 -29
  121. package/dist/services/handlers/instructions.shared.d.ts +54 -0
  122. package/dist/services/handlers/instructions.shared.js +126 -1
  123. package/dist/services/handlers.activation.js +83 -81
  124. package/dist/services/handlers.dashboardConfig.d.ts +2 -2
  125. package/dist/services/handlers.dashboardConfig.js +1 -2
  126. package/dist/services/handlers.diagnostics.js +75 -54
  127. package/dist/services/handlers.feedback.d.ts +4 -11
  128. package/dist/services/handlers.feedback.js +11 -333
  129. package/dist/services/handlers.gates.js +69 -37
  130. package/dist/services/handlers.graph.js +2 -2
  131. package/dist/services/handlers.help.js +2 -2
  132. package/dist/services/handlers.instructionSchema.js +4 -2
  133. package/dist/services/handlers.integrity.js +42 -22
  134. package/dist/services/handlers.messaging.js +1 -1
  135. package/dist/services/handlers.metrics.js +51 -6
  136. package/dist/services/handlers.prompt.js +10 -2
  137. package/dist/services/handlers.search.js +94 -44
  138. package/dist/services/handlers.trace.js +1 -1
  139. package/dist/services/handlers.usage.js +38 -7
  140. package/dist/services/indexContext.d.ts +21 -1
  141. package/dist/services/indexContext.js +267 -82
  142. package/dist/services/indexLoader.d.ts +1 -0
  143. package/dist/services/indexLoader.js +28 -8
  144. package/dist/services/instructionRecordValidation.d.ts +39 -0
  145. package/dist/services/instructionRecordValidation.js +388 -0
  146. package/dist/services/instructions.dispatcher.js +4 -4
  147. package/dist/services/loaderSchemaValidator.d.ts +15 -0
  148. package/dist/services/loaderSchemaValidator.js +69 -0
  149. package/dist/services/logger.js +11 -2
  150. package/dist/services/mcpLogBridge.d.ts +49 -0
  151. package/dist/services/mcpLogBridge.js +83 -0
  152. package/dist/services/ownershipService.js +18 -8
  153. package/dist/services/performanceBaseline.js +23 -22
  154. package/dist/services/promptReviewService.d.ts +3 -1
  155. package/dist/services/promptReviewService.js +41 -13
  156. package/dist/services/regexSafety.d.ts +6 -0
  157. package/dist/services/regexSafety.js +46 -0
  158. package/dist/services/seedBootstrap.js +4 -4
  159. package/dist/services/storage/factory.d.ts +14 -1
  160. package/dist/services/storage/factory.js +61 -1
  161. package/dist/services/storage/jsonEmbeddingStore.d.ts +15 -0
  162. package/dist/services/storage/jsonEmbeddingStore.js +83 -0
  163. package/dist/services/storage/jsonFileStore.d.ts +3 -1
  164. package/dist/services/storage/jsonFileStore.js +8 -6
  165. package/dist/services/storage/migrationEngine.d.ts +13 -0
  166. package/dist/services/storage/migrationEngine.js +31 -0
  167. package/dist/services/storage/sqliteEmbeddingStore.d.ts +30 -0
  168. package/dist/services/storage/sqliteEmbeddingStore.js +222 -0
  169. package/dist/services/storage/sqliteStore.d.ts +3 -1
  170. package/dist/services/storage/sqliteStore.js +2 -2
  171. package/dist/services/storage/types.d.ts +48 -1
  172. package/dist/services/toolRegistry.js +77 -67
  173. package/dist/services/toolRegistry.zod.js +89 -86
  174. package/dist/services/tracing.js +5 -4
  175. package/dist/utils/envUtils.d.ts +4 -0
  176. package/dist/utils/envUtils.js +7 -0
  177. package/dist/utils/memoryMonitor.js +11 -10
  178. package/package.json +11 -4
  179. package/schemas/instruction.schema.json +38 -1
  180. package/scripts/copy-dashboard-assets.mjs +1 -1
  181. package/scripts/dist/README.md +1 -1
  182. package/scripts/setup-wizard.mjs +781 -0
  183. package/server.json +1 -0
  184. package/dist/externalClientLib.d.ts +0 -1
  185. package/dist/externalClientLib.js +0 -2
  186. package/dist/portableClientWrapper.d.ts +0 -1
  187. package/dist/portableClientWrapper.js +0 -2
  188. package/dist/services/indexingService.d.ts +0 -1
  189. 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
- function escapeHtml(value) {
50
- return value
51
- .replace(/&/g, '&')
52
- .replace(/</g, '&lt;')
53
- .replace(/>/g, '&gt;')
54
- .replace(/"/g, '&quot;')
55
- .replace(/'/g, '&#39;');
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
- adminHtml = adminHtml.replace(/<script>/g, `<script nonce="${nonce}">`); // lgtm[js/bad-tag-filter] nonce is crypto-generated
125
- adminHtml = adminHtml.replace(/<script defer /g, `<script nonce="${nonce}" defer `);
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
- // eslint-disable-next-line no-console
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
- const name = req.params.name.replace(/[^a-z0-9_-]/gi, '');
177
+ app.get('/api/docs/:name', dashboardLimiter, async (req, res) => {
178
+ // Strict basename allowlist: az09_- 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
- const fileName = req.params.name.replace(/[^a-z0-9._-]/gi, '');
169
- if (!fileName || !fileName.endsWith('.png')) {
202
+ app.get('/api/screenshots/:name', dashboardLimiter, async (req, res) => {
203
+ // Strict basename allowlist: az09._- 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
- app.use('/api', (0, ApiRoutes_js_1.createApiRoutes)({ enableCors: ctx.enableCors, rateLimit: { windowMs: 60_000, max: 100 } }));
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
- // eslint-disable-next-line no-console
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
- console.error('[API] Failed to list instances:', error);
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
- const resolved = node_path_1.default.resolve(base, `${sanitized}.json`);
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
- console.error('[API] Failed to list instructions:', error);
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
- console.error('[API] instructions search error:', error);
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
- console.error('[API] Failed to get categories:', error);
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
- console.error('[API] Failed to load instruction:', error);
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
- ...(typeof content === 'object' && content !== null ? content : {}),
198
+ ...contentObj,
200
199
  id,
201
- title: (content && typeof content === 'object' ? content.title : undefined) || id,
202
- body: (content && typeof content === 'object' ? content.body : undefined) || (typeof content === 'string' ? content : ''),
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.writeEntry)(entry); // lgtm[js/http-to-file-access] — writes to config-controlled instructions directory
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.ensureLoaded)();
210
- res.json({ success: true, message: 'Instruction created', name: id, timestamp: Date.now() });
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
- console.error('[API] Failed to create instruction:', error);
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.writeEntry)(updated); // lgtm[js/http-to-file-access] — writes to config-controlled instructions directory
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.ensureLoaded)();
240
- res.json({ success: true, message: 'Instruction updated', timestamp: Date.now() });
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
- console.error('[API] Failed to update instruction:', error);
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.ensureLoaded)();
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
- console.error('[API] Failed to delete instruction:', error);
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
- console.error('[API] Knowledge store error:', error);
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
- console.error('[API] Knowledge search error:', error);
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
- console.error('[API] Knowledge get error:', error);
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
- console.error('[API] Logs error:', error);
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
- console.error('[Logs] Stream read error:', error);
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
- console.error('[Logs] Stream poll error:', error);
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
- console.error('[Logs] Failed to start log streaming:', error);
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
- console.error('[Messaging] Send failed:', err);
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
- console.error('[Messaging] Failed to send message:', error);
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
- console.error('[Messaging] Failed to list channels:', error);
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
- console.error('[Messaging] Failed to get stats:', error);
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
- console.error('[Messaging] Failed to get message:', error);
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
- console.error('[Messaging] Failed to update message:', error);
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
- console.error('[Messaging] Failed to get thread:', error);
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
- console.error('[Messaging] Failed to read messages:', error);
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
- console.error('[Messaging] Failed to acknowledge messages:', error);
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 = 'purge_all';
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
- console.error('[Messaging] Failed to purge messages:', error);
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
- console.error('[Messaging] Inbound failed:', err);
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
- console.error('[Messaging] Failed to process inbound message:', error);
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
- console.error('[Messaging] Failed to reply to message:', error);
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' });