// server.js import express from 'express'; import cors from 'cors'; import https from 'https'; import http from 'http'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import dotenv from 'dotenv'; import managerRoutes from './managerRoutes.js'; import workerRoutes from './workerRoutes.js'; import { getConnection } from './pool.js' async function startServer() { dotenv.config({ path: path.join(path.dirname(fileURLToPath(import.meta.url)), '.env') }); const app = express(); try { const connection = await getConnection(); console.log('Database connected successfully!'); connection.release(); } catch (error) { console.error('!!! DATABASE CONNECTION FAILED !!!'); console.error('Error:', error.message); process.exit(1); } const allowedOriginsFromEnv = (process.env.CORS_ALLOWED_ORIGINS || '').split(',').filter(Boolean); const defaultAllowedOrigins = ['http://localhost:5173', 'https://localhost:5173', 'capacitor://localhost', 'ionic://localhost', 'http://localhost', 'https://localhost']; const allowedOrigins = [...new Set([...defaultAllowedOrigins, ...allowedOriginsFromEnv])]; const corsOptions = { origin: (origin, callback) => { // Allow requests with no origin (like mobile apps or curl requests) if (!origin || allowedOrigins.includes(origin) || origin.startsWith('capacitor://') || origin.startsWith('ionic://')) { callback(null, true); } else { console.log('CORS blocked origin:', origin); callback(new Error('Not allowed by CORS')); } }, credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'ngrok-skip-browser-warning', 'X-User-Timezone'], //added X-User-Timezone for my development (Edison) exposedHeaders: ['Content-Range', 'X-Content-Range'], }; app.use(cors(corsOptions)); app.use(express.json()); // --- Public server time endpoints (no auth, no cache) --- const timeHandler = (req, res) => { const now = new Date(); const ymdKL = new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Kuala_Lumpur', year: 'numeric', month: '2-digit', day: '2-digit' }).format(now); // "YYYY-MM-DD" res.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate'); res.set('Pragma', 'no-cache'); res.set('Expires', '0'); res.json({ nowIso: now.toISOString(), tz: 'Asia/Kuala_Lumpur', ymdKL }); }; app.get('/time', timeHandler); // public path app.get('/api/time', timeHandler); // also under /api app.use('/api/managers', managerRoutes()); app.use('/api', workerRoutes()); const httpPort = process.env.HTTP_PORT || 3000; const httpsPort = process.env.HTTPS_PORT || 3443; const sslEnabled = process.env.SSL_ENABLED === 'true'; if (sslEnabled) { try { const currentDir = path.dirname(fileURLToPath(import.meta.url)); const keyPath = path.join(currentDir, 'key.pem'); const certPath = path.join(currentDir, 'cert.pem'); const httpsOptions = { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath), }; https.createServer(httpsOptions, app).listen(httpsPort, '0.0.0.0', () => { console.log(`🔒 HTTPS Server is running on https://localhost:${httpsPort}`); }); } catch (error) { console.error('❌ Failed to start HTTPS server:', error.message); } } http.createServer(app).listen(httpPort, '0.0.0.0', () => { console.log(`🌐 HTTP Server is running on http://localhost:${httpPort}`); }); } startServer();