File size: 2,441 Bytes
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22adc79
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43813d1
 
adac7cc
 
 
 
 
 
 
 
 
 
 
c2c8c8d
adac7cc
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
865193f
c2c8c8d
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import express from 'express';
import { createServer } from 'http';
import { Server as SocketServer } from 'socket.io';
import helmet from 'helmet';
import path from 'path';
import { fileURLToPath } from 'url';
import { config } from './config/env.js';
import { corsMiddleware } from './middleware/cors.middleware.js';
import { errorHandler } from './middleware/error-handler.middleware.js';
import { apiRoutes } from './routes/index.js';
import { setupWebSocketHandlers } from './websocket/handler.js';
import { logger } from './utils/logger.js';

const app = express();
const httpServer = createServer(app);

// Socket.io setup
const io = new SocketServer(httpServer, {
  cors: {
    origin: config.CLIENT_URL === '*' ? true : config.CLIENT_URL,
    methods: ['GET', 'POST'],
    credentials: true,
  },
});

// Middleware
app.use(helmet({ contentSecurityPolicy: false }));
app.use(corsMiddleware);
app.use(express.json({ limit: '10mb' }));

// Health check
app.get('/health', (_req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// API routes
app.use('/api/v1', apiRoutes);

// Error handler
app.use(errorHandler);

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const clientPath = path.join(__dirname, '../../client/dist');

// Serve static frontend
app.use(express.static(clientPath));

// Fallback for SPA routing and root
app.get('*', (req, res) => {
  res.sendFile(path.join(clientPath, 'index.html'), (err) => {
    if (err && !res.headersSent) {
      res.status(404).send('GLMPilot: Frontend build not found. Please ensure npm run build was successful.');
    }
  });
});

// WebSocket
setupWebSocketHandlers(io);

httpServer.on('error', (err: NodeJS.ErrnoException) => {
  if (err.code === 'EADDRINUSE') {
    logger.error(
      `Port ${config.PORT} is already in use (another GLMPilot server or app is listening). ` +
        `Stop that process, or set a different PORT in .env (e.g. PORT=3002). ` +
        `Find PID: lsof -nP -iTCP:${config.PORT} -sTCP:LISTEN`
    );
  } else {
    logger.error('HTTP server failed to start', err);
  }
  process.exit(1);
});

// Start server
httpServer.listen(config.PORT, '0.0.0.0', () => {
  logger.info(`🚀 GLMPilot server running on port ${config.PORT}`);
  logger.info(`   Environment: ${config.NODE_ENV}`);
  logger.info(`   Client URL: ${config.CLIENT_URL}`);
});

export { app, httpServer, io };