import http from 'node:http'; import { timingSafeEqual } from 'node:crypto'; import { WebSocketServer } from 'ws'; import { openStore } from './store.mjs'; import { handleAdmin } from './admin.mjs'; import { handleTurn } from './turns.mjs'; const { DEVICE_TOKEN, ELEVENLABS_API_KEY, LLM_MODE = 'openrouter', OPENROUTER_API_KEY, PORT = '3000', HOST = '127.0.0.1' } = process.env; if (!DEVICE_TOKEN || !ELEVENLABS_API_KEY || !['openrouter', 'echo'].includes(LLM_MODE) || (LLM_MODE === 'openrouter' && !OPENROUTER_API_KEY)) { console.error('Missing required configuration or invalid LLM_MODE'); process.exit(1); } const store = openStore(); const server = http.createServer(async (req, res) => { try { if (req.method === 'GET' && req.url === '/healthz') { res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end('{"ok":true}'); return; } if (await handleAdmin(req, res, store)) return; res.writeHead(404); res.end(); } catch { if (!res.headersSent) res.writeHead(500); res.end(); } }); const sockets = new WebSocketServer({ noServer: true, maxPayload: 128 * 1024, perMessageDeflate: false }); let active = false; server.on('upgrade', (req, socket, head) => { const token = req.headers.authorization?.startsWith('Bearer ') ? req.headers.authorization.slice(7) : ''; const a = Buffer.from(token), b = Buffer.from(DEVICE_TOKEN); if (req.url !== '/v1/voice' || a.length !== b.length || !timingSafeEqual(a, b)) { socket.end('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n'); return; } if (active) { socket.end('HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n'); return; } sockets.handleUpgrade(req, socket, head, ws => { active = true; ws.once('close', () => { active = false; }); handleTurn(ws, store); }); }); server.listen(Number(PORT), HOST, () => console.log(`Voice server listening on ${HOST}:${PORT}`));