const express = require('express'); const http = require('http'); const cors = require('cors'); const helmet = require('helmet'); const compression = require('compression'); const rateLimit = require('rate-limiter-flexible'); require('dotenv').config(); const logger = require('./utils/logger'); const connectDB = require('./config/database'); const authRoutes = require('./routes/auth'); const serverRoutes = require('./routes/servers'); const modsRoutes = require('./routes/mods'); const { errorHandler, notFound } = require('./middleware/errorHandler'); // Override console.error to properly log error objects const originalConsoleError = console.error; console.error = (...args) => { args.forEach(arg => { if (arg instanceof Error) { logger.error('Console Error:', { message: arg.message, stack: arg.stack, name: arg.name }); } else if (typeof arg === 'object' && arg !== null) { logger.error('Console Error Object:', arg); } else { logger.error('Console Error:', arg); } }); }; const app = express(); const server = http.createServer(app); // Middleware app.use(helmet()); app.use(compression()); app.use(cors({ origin: ["https://galaxystrike.online", "https://api.korvarix.com", "http://api.korvarix.com:3001"], credentials: true })); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // Static file serving app.use(express.static('../Website/dist')); // Rate limiting const { RateLimiterMemory } = require('rate-limiter-flexible'); const limiter = new RateLimiterMemory({ keyGenerator: (req) => req.ip, points: 100, // limit each IP to 100 requests per windowMs duration: 900, // 15 minutes blockDuration: 900, // Block for 15 minutes }); app.use('/api/', async (req, res, next) => { try { const resLimiter = await limiter.consume(req.ip); if (!resLimiter.remainingPoints) { return res.status(429).json({ error: 'Too many requests, please try again later.' }); } next(); } catch (error) { next(); } }); // Routes - API Server Only (Auth + Server Browser + Mods) app.use('/api/auth', authRoutes); app.use('/api/servers', serverRoutes); app.use('/api/mods', modsRoutes); // Health check app.get('/health', (req, res) => { res.status(200).json({ status: 'API Server OK', service: 'galaxystrikeonline-api', timestamp: new Date().toISOString(), uptime: process.uptime() }); }); // API version endpoint app.get('/api/ssc/version', (req, res) => { res.status(200).json({ version: '1.0.0', service: 'galaxystrikeonline-api', timestamp: new Date().toISOString() }); }); // Fallback route for SPA - only serve index.html for non-API routes app.get('*', (req, res) => { // Don't try to serve index.html for API routes if (req.path.startsWith('/api/')) { return res.status(404).json({ error: 'API endpoint not found' }); } // Try dist first (for built files), fallback to public (for development) const distPath = require('path').resolve(__dirname, '../dist/index.html'); const publicPath = require('path').resolve(__dirname, '../public/index.html'); const fs = require('fs'); if (fs.existsSync(distPath)) { res.sendFile(distPath); } else if (fs.existsSync(publicPath)) { res.sendFile(publicPath); } else { res.status(404).json({ error: 'Frontend not found' }); } }); // Error handling app.use(notFound); app.use(errorHandler); // Initialize database only (no game systems for API server) async function startServer() { try { // Connect to database await connectDB(); logger.info('Database connected successfully'); // Start API server const PORT = process.env.PORT || 3001; server.listen(PORT, () => { logger.info(`API Server running on port ${PORT}`); logger.info('API Server handles: Authentication, Server Browser, User Data'); }); } catch (error) { logger.error('Failed to start API server:', error); process.exit(1); } } // Handle uncaught errors process.on('uncaughtException', (error) => { logger.error('Uncaught Exception:', error); }); process.on('unhandledRejection', (reason, promise) => { logger.error('Unhandled Rejection at:', promise, 'reason:', reason); }); // Handle HTTP server errors server.on('error', (error) => { logger.error('HTTP Server error:', error); }); startServer(); module.exports = { app, server };