feat: First iteration, multi themes, I18N

This commit is contained in:
gauvainboiche
2026-10-08 11:58:18 +02:00
parent 9240fa3c3c
commit aa9721ac2a
53 changed files with 3363 additions and 1 deletions
+53
View File
@@ -0,0 +1,53 @@
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)));
}