This commit is contained in:
Viktoria Polyakova
2026-01-25 08:57:38 +00:00
commit 4fb101c5db
7657 changed files with 497012 additions and 0 deletions

116
backend/src/main.ts Normal file
View File

@@ -0,0 +1,116 @@
import { webcrypto } from 'crypto';
import { NestFactory } from '@nestjs/core';
// Polyfill crypto for @nestjs/typeorm
if (!global.crypto) {
global.crypto = webcrypto as any;
}
import { Logger, ValidationPipe } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { utilities, WinstonModule } from 'nest-winston';
import winston from 'winston';
import helmet from 'helmet';
//import rateLimit from 'express-rate-limit';
import cookieParser from 'cookie-parser';
import { AppModule } from './app.module';
import { ApiDocumentation } from './documentation';
import { extractSubdomain, LoggingInterceptor } from './common';
function getLogger() {
return process.env.WINSTON_ENABLED === 'true'
? WinstonModule.createLogger({
level: 'debug',
transports: [
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
utilities.format.nestLike(process.env.APPLICATION_NAME, { colors: true, prettyPrint: true }),
),
}),
],
})
: undefined;
}
async function bootstrap() {
if (process.env.NEW_RELIC_ENABLED === 'true') {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('newrelic');
}
const app = await NestFactory.create<NestExpressApplication>(AppModule, { rawBody: true, logger: getLogger() });
// Security headers
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "blob:"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "blob:", "https://*"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
connectSrc: ["'self'"],
frameSrc: ["'self'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
referrerPolicy: { policy: 'strict-origin-when-cross-origin' }
}));
// Rate limiting disabled to eliminate 429 errors
// app.use(
// rateLimit({
// windowMs: 15 * 60 * 1000, // 15 minutes
// max: 1000, // limit each IP to 1000 requests per windowMs
// message: 'Too many requests from this IP, please try again later.',
// standardHeaders: true,
// legacyHeaders: false,
// }),
// );
// CORS with restrictions
app.enableCors({
origin: process.env['FRONTEND_URL'] || 'http://localhost:3000',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token']
});
app.set('trust proxy', true);
app.use(cookieParser());
app.use(extractSubdomain);
app.setGlobalPrefix('api');
// Global validation
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: false,
transform: true,
disableErrorMessages: process.env['NODE_ENV'] === 'production'
}));
app.useGlobalInterceptors(new LoggingInterceptor());
ApiDocumentation.configure(app);
const logger = new Logger('main');
process.on('uncaughtException', (error) => {
logger.error(`Uncaught Exception`, error.stack);
});
await app.listen(process.env.APPLICATION_PORT, '127.0.0.1');
logger.log(`Application is running on: ${await app.getUrl()}`);
logger.log(`Application version is: ${process.env.npm_package_version}`);
}
bootstrap();