import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { ConfigService } from '@nestjs/config'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import * as express from 'express'; import { randomUUID } from 'crypto'; import { NextFunction, Request, Response } from 'express'; import { existsSync, mkdirSync } from 'fs'; import { join } from 'path'; import { AppModule } from './app.module'; import { ResponseEnvelopeInterceptor } from './common/interceptors/response-envelope.interceptor'; async function bootstrap(): Promise { const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); const corsOrigins = configService.get('cors.origins', []); const uploadsDir = join(process.cwd(), 'uploads'); if (!existsSync(uploadsDir)) { mkdirSync(uploadsDir, { recursive: true }); } app.enableCors({ origin: corsOrigins.length ? corsOrigins : true, credentials: true, }); app.setGlobalPrefix(configService.get('globalPrefix', 'api/v1')); app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, transformOptions: { enableImplicitConversion: true }, }), ); app.use((req: Request, res: Response, next: NextFunction) => { const startedAt = Date.now(); const requestId = (req.headers['x-request-id'] as string | undefined) ?? randomUUID(); req.headers['x-request-id'] = requestId; res.setHeader('x-request-id', requestId); res.on('finish', () => { const log = { level: 'info', requestId, method: req.method, path: req.originalUrl, statusCode: res.statusCode, durationMs: Date.now() - startedAt, }; console.log(JSON.stringify(log)); }); next(); }); const responseEnvelopeEnabled = configService.get('responseEnvelopeEnabled', false); if (responseEnvelopeEnabled) { app.useGlobalInterceptors(new ResponseEnvelopeInterceptor()); } app.use('/uploads', express.static(uploadsDir)); const swaggerConfig = new DocumentBuilder() .setTitle(configService.get('swagger.title', 'Oudelaa API')) .setDescription( configService.get('swagger.description', 'Social media backend API documentation'), ) .setVersion(configService.get('swagger.version', '1.0.0')) .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, swaggerConfig); SwaggerModule.setup(configService.get('swagger.path', 'docs'), app, document); const port = configService.get('port', 4000); const host = configService.get('host', '0.0.0.0'); await app.listen(port, host); } void bootstrap();