import http from 'node:http'; import { fileURLToPath } from 'node:url'; import { handleApi } from './api.js'; import { SECURITY_HEADERS } from './security.js'; import { createStaticHandler } from './static.js'; const PORT = Number(process.env.PORT) || 8080; const HOST = process.env.HOST || '0.0.0.0'; const PUBLIC_DIR = fileURLToPath(new URL('../public/', import.meta.url)); const serveStatic = createStaticHandler(PUBLIC_DIR); const server = http.createServer(async (req, res) => { try { if (req.method !== 'GET' && req.method !== 'HEAD') { res.writeHead(405, { ...SECURITY_HEADERS, Allow: 'GET, HEAD' }); return res.end(); } const { pathname } = new URL(req.url, 'http://localhost'); if (pathname === '/healthz') { res.writeHead(200, { ...SECURITY_HEADERS, 'Content-Type': 'text/plain' }); return res.end('ok'); } if (pathname.startsWith('/api/')) { const payload = await handleApi(PUBLIC_DIR, pathname); if (payload === undefined) { res.writeHead(404, { ...SECURITY_HEADERS, 'Content-Type': 'application/json' }); return res.end('{"error":"not_found"}'); } res.writeHead(200, { ...SECURITY_HEADERS, 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store', }); return res.end(req.method === 'HEAD' ? undefined : JSON.stringify(payload)); } return await serveStatic(req, res, pathname, SECURITY_HEADERS); } catch (err) { console.error(err); if (!res.headersSent) res.writeHead(500, SECURITY_HEADERS); res.end(); } }); server.listen(PORT, HOST, () => console.log(`Idle Clicker listening on http://${HOST}:${PORT}`)); for (const signal of ['SIGINT', 'SIGTERM']) { process.on(signal, () => server.close(() => process.exit(0))); }