Spaces:
Sleeping
Sleeping
import express from 'express'; | |
import cors from 'cors'; | |
import helmet from 'helmet'; | |
import dotenv from 'dotenv'; | |
import rateLimit from 'express-rate-limit'; | |
import { createServer } from 'http'; | |
import { WebSocketServer } from 'ws'; | |
import path from 'path'; | |
// Import routes | |
import authRoutes from './routes/auth'; | |
import tenantRoutes from './routes/tenants'; | |
import knowledgeBaseRoutes from './routes/knowledge-base'; | |
import chatRoutes from './routes/chat'; | |
import analyticsRoutes from './routes/analytics'; | |
import widgetRoutes from './routes/widget'; | |
// Import middleware | |
import { authenticateToken } from './middleware/auth'; | |
import { errorHandler } from './middleware/errorHandler'; | |
// Import database initialization | |
import { initializeDatabase } from './db/database'; | |
// Import WebSocket handler | |
import { setupWebSocket } from './services/websocket'; | |
dotenv.config(); | |
const app = express(); | |
const PORT = process.env.PORT || 3001; | |
// Create HTTP server for WebSocket support | |
const server = createServer(app); | |
// Initialize WebSocket | |
const wss = new WebSocketServer({ server }); | |
setupWebSocket(wss); | |
// Security middleware | |
app.use(helmet({ | |
contentSecurityPolicy: false, // Disable for development | |
crossOriginEmbedderPolicy: false | |
})); | |
// Rate limiting | |
const limiter = rateLimit({ | |
windowMs: 15 * 60 * 1000, // 15 minutes | |
max: 100, // limit each IP to 100 requests per windowMs | |
message: 'Too many requests from this IP, please try again later.' | |
}); | |
app.use('/api/', limiter); | |
// CORS configuration | |
app.use(cors({ | |
origin: [ | |
process.env.FRONTEND_URL || 'http://localhost:5173', | |
'http://localhost:3000', | |
'https://your-frontend-domain.com' // Add your production frontend URL | |
], | |
credentials: true, | |
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], | |
allowedHeaders: ['Content-Type', 'Authorization'] | |
})); | |
// Body parsing middleware | |
app.use(express.json({ limit: '50mb' })); | |
app.use(express.urlencoded({ extended: true, limit: '50mb' })); | |
// Static file serving for uploads | |
app.use('/uploads', express.static(path.join(__dirname, '../uploads'))); | |
// Health check endpoint | |
app.get('/health', (req, res) => { | |
res.json({ | |
status: 'healthy', | |
timestamp: new Date().toISOString(), | |
version: '1.0.0' | |
}); | |
}); | |
// API Routes | |
app.use('/api/auth', authRoutes); | |
app.use('/api/tenants', authenticateToken, tenantRoutes); | |
app.use('/api/knowledge-base', authenticateToken, knowledgeBaseRoutes); | |
app.use('/api/chat', chatRoutes); // No auth required for public chat widget | |
app.use('/api/analytics', authenticateToken, analyticsRoutes); | |
app.use('/api/widget', widgetRoutes); // No auth required for widget access | |
// Error handling middleware | |
app.use(errorHandler); | |
// 404 handler | |
app.use('*', (req, res) => { | |
res.status(404).json({ error: 'Endpoint not found' }); | |
}); | |
// Initialize database and start server | |
async function startServer() { | |
try { | |
await initializeDatabase(); | |
console.log('β Database initialized successfully'); | |
server.listen(PORT, () => { | |
console.log(`π Server running on port ${PORT}`); | |
console.log(`π± Health check: http://localhost:${PORT}/health`); | |
console.log(`π WebSocket server ready`); | |
console.log(`π CORS enabled for: ${process.env.FRONTEND_URL}`); | |
}); | |
} catch (error) { | |
console.error('β Failed to start server:', error); | |
process.exit(1); | |
} | |
} | |
startServer(); | |
export default app; |