Implement enriched agent directory endpoint for onboarding and discovery. Returns all agents with activity status, social channels, and profile information. Features: - All required fields: id, name, urlKey, role, description, specialties - Activity tracking: lastActivityAt from audit_events - Status calculation: active (<5min), idle (<60min), offline (>60min) - Social channels: top 3 by post count per agent - Profile URL: /BARAAA/agents/:urlKey - Pagination: ?limit=N (default 50, max 100) - Role filter: ?role=admin|agent - Auth: x-agent-id header required (401 if missing) Implementation: - src/routes/directory.ts: endpoint logic - src/app.ts: register directory routes Fixes BARAAA-91 Co-Authored-By: Paperclip <noreply@paperclip.ing>
81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import Fastify, { type FastifyInstance } from 'fastify';
|
|
import type { AppConfig } from './config.js';
|
|
import { pool } from './db/pool.js';
|
|
import { registerSecurityPlugins } from './lib/security.js';
|
|
import { registerInstrumentation } from './lib/instrumentation.js';
|
|
import { registerAgentRoutes } from './routes/agents.js';
|
|
import { registerTokenRoutes } from './routes/tokens.js';
|
|
import { registerSessionRoutes } from './routes/sessions.js';
|
|
import { registerRoomRoutes } from './routes/rooms.js';
|
|
import { registerSocialRoutes } from './routes/social.js';
|
|
import { registerDirectoryRoutes } from './routes/directory.js';
|
|
import { setupSocketIO } from './socket/index.js';
|
|
import { register as metricsRegister } from './lib/metrics.js';
|
|
import { startMetricsCollector } from './services/metrics-collector.js';
|
|
|
|
export interface BuildAppOptions {
|
|
config: AppConfig;
|
|
}
|
|
|
|
export async function buildApp({ config }: BuildAppOptions): Promise<FastifyInstance> {
|
|
const app = Fastify({
|
|
logger: { level: config.LOG_LEVEL },
|
|
disableRequestLogging: config.NODE_ENV === 'test',
|
|
});
|
|
|
|
// Register security plugins first
|
|
await registerSecurityPlugins(app, config);
|
|
|
|
// Register instrumentation for metrics
|
|
await registerInstrumentation(app);
|
|
|
|
app.get('/healthz', async () => {
|
|
return { status: 'ok', uptime: process.uptime() };
|
|
});
|
|
|
|
app.get('/readyz', async (_req, reply) => {
|
|
const start = Date.now();
|
|
try {
|
|
// Check DB connectivity
|
|
await pool.query('SELECT 1');
|
|
|
|
const elapsed = Date.now() - start;
|
|
return { status: 'ready', checks: { db: 'ok' }, responseTime: elapsed };
|
|
} catch (err) {
|
|
reply.status(503);
|
|
return {
|
|
status: 'not_ready',
|
|
checks: { db: 'failed' },
|
|
error: err instanceof Error ? err.message : 'unknown',
|
|
};
|
|
}
|
|
});
|
|
|
|
app.get('/metrics', async (_req, reply) => {
|
|
reply.header('Content-Type', metricsRegister.contentType);
|
|
return metricsRegister.metrics();
|
|
});
|
|
|
|
// Register API routes
|
|
await registerAgentRoutes(app, pool);
|
|
await registerTokenRoutes(app, pool);
|
|
await registerSessionRoutes(app, pool, config);
|
|
await registerRoomRoutes(app, pool);
|
|
await registerSocialRoutes(app, pool);
|
|
await registerDirectoryRoutes(app, pool);
|
|
|
|
// Setup socket.io after app is ready (if feature enabled)
|
|
await app.ready();
|
|
if (config.FEATURE_MESSAGING_ENABLED) {
|
|
setupSocketIO(app.server, pool, config);
|
|
app.log.info('✅ Socket.IO messaging enabled');
|
|
} else {
|
|
app.log.warn('⚠️ Socket.IO messaging disabled (FEATURE_MESSAGING_ENABLED=false)');
|
|
}
|
|
|
|
// Start metrics collector (updates room metrics every 30s)
|
|
startMetricsCollector(pool);
|
|
app.log.info('✅ Metrics collector started');
|
|
|
|
return app;
|
|
}
|