import http from 'http'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PORT = process.env.PORT || 8080; const DIST_DIR = path.join(__dirname, 'dist'); const CONFIG_DIR = path.join(__dirname, 'data'); const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json'); // Ensure config dir exists if (!fs.existsSync(CONFIG_DIR)) { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } const MIME_TYPES = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon', }; const server = http.createServer((req, res) => { // CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; } // API Config GET if (req.url === '/api/config' && req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); if (fs.existsSync(CONFIG_FILE)) { try { const data = fs.readFileSync(CONFIG_FILE, 'utf-8'); res.end(data); return; } catch (err) { // Fallback } } res.end(JSON.stringify({})); return; } // API Config POST if (req.url === '/api/config' && req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { try { const parsed = JSON.parse(body); fs.writeFileSync(CONFIG_FILE, JSON.stringify(parsed, null, 2), 'utf-8'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true })); } catch (err) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Invalid JSON or write error' })); } }); return; } // Serve static files let filePath = path.join(DIST_DIR, req.url === '/' ? 'index.html' : req.url); // If path doesn't exist, fallback to index.html (SPA routing) if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) { filePath = path.join(DIST_DIR, 'index.html'); } const ext = path.extname(filePath); const contentType = MIME_TYPES[ext] || 'application/octet-stream'; fs.readFile(filePath, (err, content) => { if (err) { res.writeHead(500); res.end('Server Error'); } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content); } }); }); server.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });