Files
SerpentRace/SerpentRace_Backend/dist/Api/index.js
T

225 lines
8.6 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.webSocketService = void 0;
const express_1 = __importDefault(require("express"));
const http_1 = require("http");
const cookie_parser_1 = __importDefault(require("cookie-parser"));
const helmet_1 = __importDefault(require("helmet"));
const ormconfig_1 = require("../Infrastructure/ormconfig");
const userRouter_1 = __importDefault(require("./routers/userRouter"));
const organizationRouter_1 = __importDefault(require("./routers/organizationRouter"));
const deckRouter_1 = __importDefault(require("./routers/deckRouter"));
const chatRouter_1 = __importDefault(require("./routers/chatRouter"));
const contactRouter_1 = __importDefault(require("./routers/contactRouter"));
const adminRouter_1 = __importDefault(require("./routers/adminRouter"));
const deckImportExportRouter_1 = __importDefault(require("./routers/deckImportExportRouter"));
const Logger_1 = require("../Application/Services/Logger");
const WebSocketService_1 = require("../Application/Services/WebSocketService");
const swaggerUiSetup_1 = require("./swagger/swaggerUiSetup");
const app = (0, express_1.default)();
const httpServer = (0, http_1.createServer)(app);
const PORT = process.env.PORT || 3000;
const isDevelopment = process.env.NODE_ENV === 'development';
const loggingService = Logger_1.LoggingService.getInstance();
(0, Logger_1.logStartup)('SerpentRace Backend starting up', {
environment: process.env.NODE_ENV || 'development',
port: PORT,
nodeVersion: process.version,
chatInactivityTimeout: process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES || '30'
});
app.use((0, helmet_1.default)({
contentSecurityPolicy: isDevelopment ? false : undefined
}));
app.use(express_1.default.json({ limit: '10mb' }));
app.use(express_1.default.urlencoded({ extended: true, limit: '10mb' }));
app.use((0, cookie_parser_1.default)());
app.use(loggingService.requestLoggingMiddleware());
app.use((req, res, next) => {
const origin = req.headers.origin;
const allowedOrigins = ['http://localhost:3000', 'http://localhost:3001', 'http://localhost:8080'];
if (!origin || allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin || '*');
}
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Cookie');
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
next();
});
if (isDevelopment) {
app.use((req, res, next) => {
(0, Logger_1.logRequest)(`${req.method} ${req.path}`, req, res);
next();
});
}
// Setup Swagger documentation
(0, swaggerUiSetup_1.setupSwagger)(app);
app.get('/', (req, res) => {
res.json({
service: 'SerpentRace Backend API',
status: 'running',
version: '1.0.0',
endpoints: {
swagger: '/api-docs',
users: '/api/users',
organizations: '/api/organizations',
decks: '/api/decks',
chats: '/api/chats',
contacts: '/api/contacts',
admin: '/api/admin',
deckImportExport: '/api/deck-import-export',
health: '/health'
},
websocket: {
enabled: true,
events: [
'chat:join', 'chat:leave', 'message:send',
'group:create', 'chat:direct', 'game:chat:create',
'chat:history'
]
}
});
});
app.get('/health', async (req, res) => {
try {
const isDbConnected = ormconfig_1.AppDataSource.isInitialized;
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
service: 'SerpentRace Backend API',
version: '1.0.0',
environment: process.env.NODE_ENV || 'development',
database: {
connected: isDbConnected,
type: ormconfig_1.AppDataSource.options.type
},
websocket: {
enabled: true
},
uptime: process.uptime()
});
}
catch (error) {
res.status(503).json({
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: 'Service health check failed'
});
}
});
// API Routes
app.use('/api/users', userRouter_1.default);
app.use('/api/organizations', organizationRouter_1.default);
app.use('/api/decks', deckRouter_1.default);
app.use('/api/chats', chatRouter_1.default);
app.use('/api/contacts', contactRouter_1.default);
app.use('/api/admin', adminRouter_1.default);
app.use('/api/deck-import-export', deckImportExportRouter_1.default);
// Global error handler (must be after routes)
app.use(loggingService.errorLoggingMiddleware());
app.use((error, req, res, next) => {
(0, Logger_1.logError)('Global error handler caught unhandled error', error, req, res);
// Don't expose internal error details in production
const isDevelopment = process.env.NODE_ENV === 'development';
res.status(500).json({
error: 'Internal server error',
timestamp: new Date().toISOString(),
...(isDevelopment && { details: error.message, stack: error.stack })
});
});
// Handle 404 routes
app.use((req, res) => {
res.status(404).json({
error: 'Route not found',
path: req.originalUrl,
method: req.method,
timestamp: new Date().toISOString()
});
});
// Initialize WebSocket service after database connection
let webSocketService;
// Initialize database connection
ormconfig_1.AppDataSource.initialize()
.then(() => {
const dbOptions = ormconfig_1.AppDataSource.options;
(0, Logger_1.logConnection)('Database connection established', 'postgresql', 'success', {
type: dbOptions.type,
host: dbOptions.host,
database: dbOptions.database
});
// Initialize WebSocket service after database is connected
exports.webSocketService = webSocketService = new WebSocketService_1.WebSocketService(httpServer);
(0, Logger_1.logStartup)('WebSocket service initialized', {
chatInactivityTimeout: process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES || '30'
});
})
.catch((error) => {
const dbOptions = ormconfig_1.AppDataSource.options;
(0, Logger_1.logConnection)('Database connection failed', 'postgresql', 'failure', {
error: error.message,
type: dbOptions.type,
host: dbOptions.host,
database: dbOptions.database
});
process.exit(1);
});
// Start server with WebSocket support
const server = httpServer.listen(PORT, () => {
(0, Logger_1.logStartup)('Server started successfully', {
port: PORT,
environment: process.env.NODE_ENV || 'development',
timestamp: new Date().toISOString(),
endpoints: {
health: `/health`,
swagger: `/api-docs`,
users: `/api/users`,
organizations: `/api/organizations`,
decks: `/api/decks`,
chats: `/api/chats`
},
websocket: {
enabled: true,
chatInactivityTimeout: `${process.env.CHAT_INACTIVITY_TIMEOUT_MINUTES || '30'} minutes`
}
});
});
// Graceful shutdown
const gracefulShutdown = async (signal) => {
(0, Logger_1.logStartup)(`Received ${signal}. Shutting down gracefully...`);
server.close(() => {
(0, Logger_1.logStartup)('HTTP server closed');
if (ormconfig_1.AppDataSource.isInitialized) {
ormconfig_1.AppDataSource.destroy()
.then(() => {
(0, Logger_1.logConnection)('Database connection closed', 'postgresql', 'success');
process.exit(0);
})
.catch((error) => {
(0, Logger_1.logError)('Error during database shutdown', error);
process.exit(1);
});
}
else {
process.exit(0);
}
});
};
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
(0, Logger_1.logError)('Uncaught Exception - Server will shut down', error);
process.exit(1);
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
(0, Logger_1.logError)('Unhandled Rejection - Server will shut down', new Error(String(reason)), undefined, undefined);
process.exit(1);
});
//# sourceMappingURL=index.js.map