codenuk_backend_mine/generated-projects/premium_invoice_generation/backend/src/app.js

131 lines
4.0 KiB
JavaScript

const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const compression = require('compression');
const mongoSanitize = require('express-mongo-sanitize');
const hpp = require('hpp');
const { errorHandler } = require('./middleware/errorHandler');
const { requestLogger } = require('./middleware/requestLogger');
const { authMiddleware, roleCheck } = require('./middleware/auth');
const { validateRequest } = require('./middleware/validation');
const { correlationIdMiddleware } = require('./middleware/correlationId');
const { metricsMiddleware } = require('./middleware/metrics');
const { rateLimiterRedis } = require('./utils/rateLimiter');
const { cache } = require('./utils/cache');
const routes = require('./routes');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
const logger = require('./utils/logger');
const { AppError } = require('./utils/errors');
const app = express();
app.use(helmet({
contentSecurityPolicy: {
useDefaults: true,
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'"],
frameSrc: ["'none'"],
objectSrc: ["'none'"]
}
},
crossOriginEmbedderPolicy: true,
crossOriginOpenerPolicy: true,
crossOriginResourcePolicy: { policy: 'same-origin' },
dnsPrefetchControl: { allow: false },
frameguard: { action: 'deny' },
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
ieNoOpen: true,
noSniff: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
xssFilter: true,
permittedCrossDomainPolicies: { permittedPolicies: 'none' }
}));
app.use(cors({
origin: async (origin, callback) => {
try {
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
throw new AppError('Not allowed by CORS', 403);
}
} catch (error) {
callback(error);
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Correlation-ID'],
credentials: true,
maxAge: parseInt(process.env.CORS_MAX_AGE) || 86400
}));
app.use(compression());
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(mongoSanitize());
app.use(hpp());
app.use(correlationIdMiddleware);
app.use(metricsMiddleware);
app.use(rateLimiterRedis);
app.use(requestLogger);
app.use(cache);
app.get('/health', async (req, res) => {
try {
const healthData = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memoryUsage: process.memoryUsage(),
version: process.env.npm_package_version
};
res.status(200).json(healthData);
} catch (error) {
logger.error('Health check failed:', { error: error.message, stack: error.stack });
res.status(503).json({ status: 'error', message: 'Service unavailable' });
}
});
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, {
explorer: true,
customCss: '.swagger-ui .topbar { display: none }',
swaggerOptions: {
persistAuthorization: true,
docExpansion: 'none',
filter: true
}
}));
app.use('/api', authMiddleware, validateRequest, roleCheck, routes);
app.use('*', (req, res) => {
res.status(404).json({
status: 'error',
message: 'Resource not found',
path: req.originalUrl
});
});
app.use(errorHandler);
process.on('unhandledRejection', (err) => {
logger.error('Unhandled Rejection:', { error: err.message, stack: err.stack });
if (process.env.NODE_ENV === 'production') {
process.exit(1);
}
});
process.on('uncaughtException', (err) => {
logger.error('Uncaught Exception:', { error: err.message, stack: err.stack });
if (process.env.NODE_ENV === 'production') {
process.exit(1);
}
});
module.exports = app;