import { serve } from '@hono/node-server'; import { Hono } from 'hono'; import { compress } from 'hono/compress'; import { secureHeaders } from 'hono/secure-headers'; import { timeout } from 'hono/timeout'; import { config } from './config'; import { corsMiddleware } from './middleware/cors'; import { loggerMiddleware, requestIdMiddleware } from './middleware/logger'; import { rateLimitMiddleware } from './middleware/rateLimit'; import { api } from './routes/api'; import { backendApi } from './routes/backend-api'; import { healthApp } from './routes/health'; const app = new Hono(); // Global middleware app.use('*', requestIdMiddleware); app.use('*', loggerMiddleware); app.use('*', corsMiddleware); app.use('*', secureHeaders()); app.use('*', compress()); // Apply rate limiting to API routes only app.use('/api/*', rateLimitMiddleware); // Apply timeout to prevent hanging requests (30 seconds, except for SSE) app.use('/api/*', async (c, next) => { if (c.req.path === '/api/chat') { // Skip timeout for SSE endpoints await next(); } else { return timeout(30000)(c, next); } }); // Mount routes - matching backend API structure at root level app.route('/', backendApi); // Also mount at /api for direct Next.js API access (optional) app.route('/api', api); // Health check app.route('/health', healthApp); // Root info endpoint app.get('/info', (c) => { return c.json({ name: 'ColPali Hono Proxy', version: '1.0.0', endpoints: { // Backend-compatible endpoints (Python API format) search: '/fetch_results', fullImage: '/full_image', suggestions: '/suggestions', similarityMaps: '/get_sim_map', chat: '/get-message', // Direct API endpoints apiSearch: '/api/colpali-search', apiFullImage: '/api/full-image', apiSuggestions: '/api/query-suggestions', apiSimilarityMaps: '/api/similarity-maps', apiChat: '/api/visual-rag-chat', health: '/health', }, }); }); // 404 handler app.notFound((c) => { return c.json({ error: 'Not found', path: c.req.path }, 404); }); // Global error handler app.onError((err, c) => { console.error(`Error handling request ${c.req.path}:`, err); if (err instanceof Error) { if (err.message.includes('timeout')) { return c.json({ error: 'Request timeout' }, 408); } } return c.json( { error: 'Internal server error', requestId: c.get('requestId'), }, 500 ); }); // Start server const port = config.port; console.log(`🚀 ColPali Hono Proxy starting...`); console.log(`📍 Backend URL: ${config.backendUrl}`); console.log(`🔒 CORS Origin: ${config.corsOrigin}`); console.log(`💾 Cache: ${config.enableCache ? 'Enabled' : 'Disabled'}`); console.log(`🚦 Rate Limit: ${config.rateLimit.max} requests per ${config.rateLimit.windowMs / 1000}s`); serve({ fetch: app.fetch, port, }, (info) => { console.log(`✅ Server running on http://localhost:${info.port}`); });