diff --git a/opax-web/backend/routes/consoleApi.js b/opax-web/backend/routes/consoleApi.js index a209fee..9416c18 100644 --- a/opax-web/backend/routes/consoleApi.js +++ b/opax-web/backend/routes/consoleApi.js @@ -1,5 +1,5 @@ -const { Router } = require('express'); -const { callAgent } = require('../agentClient'); +import { Router } from 'express'; +import { callAgent } from '../agentClient.js'; const router = Router(); @@ -67,4 +67,4 @@ router.get('/approvals', (req, res) => { }); }); -module.exports = router; +export default router; diff --git a/opax-web/backend/server.js b/opax-web/backend/server.js index 0664765..cf6556e 100644 --- a/opax-web/backend/server.js +++ b/opax-web/backend/server.js @@ -9,6 +9,7 @@ import { createServer } from 'node:http'; import { Server } from 'socket.io'; import path from 'path'; import { fileURLToPath } from 'url'; +import consoleApiRouter from './routes/consoleApi.js'; const app = express(); const http = createServer(app); @@ -72,7 +73,6 @@ const ensureAuthenticated = (req, res, next) => { res.status(401).end(); }; -const consoleApiRouter = require('./routes/consoleApi.js'); app.use('/api/console', ensureAuthenticated, consoleApiRouter); diff --git a/opax-web/frontend/src/pages/OperationsConsole.tsx b/opax-web/frontend/src/pages/OperationsConsole.tsx index 9dec221..7de4721 100644 --- a/opax-web/frontend/src/pages/OperationsConsole.tsx +++ b/opax-web/frontend/src/pages/OperationsConsole.tsx @@ -33,22 +33,41 @@ const unavailableItem: ConsoleStatusItem = { }; // --- Normalizer Function --- -function normalizeStatusResponse(raw: any): ConsoleStatusResponse { - let health = unavailableItem; - - if (raw?.health?.status === 'success' && - raw.health.summary?.status === 'ok' && - typeof raw.health.summary.service === 'string' && - typeof raw.health.summary.version === 'string') { - health = { - status: 'success', - summary: { - status: 'ok', - service: raw.health.summary.service, - version: raw.health.summary.version, - }, - message: 'Available', - }; +type UnknownRecord = Record; + +function isRecord(value: unknown): value is UnknownRecord { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +function isHealthSummary(value: unknown): value is SafeHealthSummary { + return ( + isRecord(value) && + value.status === 'ok' && + typeof value.service === 'string' && + typeof value.version === 'string' + ); +} + +function normalizeStatusResponse(raw: unknown): ConsoleStatusResponse { + let health: ConsoleStatusItem = unavailableItem; + + if (isRecord(raw) && isRecord(raw.health)) { + const healthItem = raw.health; + + if ( + healthItem.status === 'success' && + isHealthSummary(healthItem.summary) + ) { + health = { + status: 'success', + summary: { + status: 'ok', + service: healthItem.summary.service, + version: healthItem.summary.version, + }, + message: 'Available', + }; + } } return { @@ -81,7 +100,7 @@ const OperationsConsole = () => { const rawData = await res.json(); setStatusData(normalizeStatusResponse(rawData)); setLastRefreshed(new Date().toLocaleTimeString()); - } catch (e: any) { + } catch { setError('Console data is unavailable. Please try again.'); } finally { setLoading(false);