import { createServer } from "node:http"; import { promises as fs } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const statsFilePath = path.resolve(__dirname, "../data/generation-stats.json"); const port = Number(process.env.PORT || 3001); const defaultStats = { total: 0, byTemplate: {}, updatedAt: null, }; let writeQueue = Promise.resolve(); async function ensureStatsFile() { await fs.mkdir(path.dirname(statsFilePath), { recursive: true }); try { await fs.access(statsFilePath); } catch { await fs.writeFile(statsFilePath, JSON.stringify(defaultStats, null, 2), "utf8"); } } async function readStats() { await ensureStatsFile(); const raw = await fs.readFile(statsFilePath, "utf8"); try { const parsed = JSON.parse(raw); return { total: Number(parsed.total || 0), byTemplate: parsed.byTemplate && typeof parsed.byTemplate === "object" ? parsed.byTemplate : {}, updatedAt: parsed.updatedAt || null, }; } catch { return { ...defaultStats }; } } function writeStats(nextStats) { writeQueue = writeQueue.then(() => fs.writeFile(statsFilePath, JSON.stringify(nextStats, null, 2), "utf8"), ); return writeQueue; } function sendJson(res, statusCode, payload) { res.writeHead(statusCode, { "Content-Type": "application/json; charset=utf-8", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET,POST,OPTIONS", "Access-Control-Allow-Headers": "Content-Type", }); res.end(JSON.stringify(payload)); } function readRequestBody(req) { return new Promise((resolve, reject) => { let body = ""; req.on("data", (chunk) => { body += chunk; }); req.on("end", () => { if (!body) { resolve({}); return; } try { resolve(JSON.parse(body)); } catch (error) { reject(error); } }); req.on("error", reject); }); } const server = createServer(async (req, res) => { if (!req.url || !req.method) { sendJson(res, 400, { error: "Invalid request." }); return; } if (req.method === "OPTIONS") { sendJson(res, 204, {}); return; } const url = new URL(req.url, `http://${req.headers.host || "localhost"}`); try { if (req.method === "GET" && url.pathname === "/api/stats") { const stats = await readStats(); sendJson(res, 200, stats); return; } if (req.method === "POST" && url.pathname === "/api/generate-count") { const body = await readRequestBody(req); const templateId = typeof body.templateId === "string" && body.templateId.trim() ? body.templateId.trim() : "unknown"; const stats = await readStats(); const nextStats = { total: stats.total + 1, byTemplate: { ...stats.byTemplate, [templateId]: Number(stats.byTemplate[templateId] || 0) + 1, }, updatedAt: new Date().toISOString(), }; await writeStats(nextStats); sendJson(res, 200, nextStats); return; } if (req.method === "GET" && url.pathname === "/api/health") { sendJson(res, 200, { ok: true }); return; } sendJson(res, 404, { error: "Not found." }); } catch (error) { sendJson(res, 500, { error: error instanceof Error ? error.message : "Internal server error.", }); } }); server.listen(port, async () => { await ensureStatsFile(); console.log(`Stats server listening on http://localhost:${port}`); });