import 'reflect-metadata'; import './config/load-env'; import type { CorsOptions } from '@nestjs/common/interfaces/external/cors-options.interface'; import type { INestApplication } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { json, urlencoded } from 'express'; import { AppModule } from './app.module'; type ExpressLikeApp = { set?: (key: string, value: boolean | number | string) => void; }; function isProduction() { return process.env.NODE_ENV === 'production'; } function parseBoolean(value: string | undefined, fallback: boolean) { if (value === undefined) return fallback; const normalized = value.trim().toLowerCase(); if (['1', 'true', 'yes', 'on'].includes(normalized)) return true; if (['0', 'false', 'no', 'off'].includes(normalized)) return false; return fallback; } function parseCommaList(value: string | undefined) { return (value ?? '') .split(',') .map((item) => item.trim()) .filter(Boolean); } function createCorsOptions(): CorsOptions { const allowedOrigins = parseCommaList(process.env.CORS_ORIGINS); return { origin: allowedOrigins.length > 0 ? (origin, callback) => { if (!origin || allowedOrigins.includes(origin)) { callback(null, true); return; } callback(new Error('Origin is not allowed by CORS'), false); } : !isProduction(), methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: [ 'authorization', 'content-type', 'x-request-id', 'x-api-encrypted', 'x-api-session-id', 'x-api-client-public-key' ], exposedHeaders: ['content-disposition', 'x-request-id', 'x-api-encrypted'], maxAge: 86400 }; } function configureTrustProxy(app: INestApplication) { const express = app.getHttpAdapter().getInstance() as ExpressLikeApp; const shouldTrustProxy = parseBoolean(process.env.TRUST_PROXY, isProduction()); express.set?.('trust proxy', shouldTrustProxy); } function requestBodyLimit() { return process.env.REQUEST_BODY_LIMIT || process.env.MAX_REQUEST_BODY_SIZE || '160mb'; } async function bootstrap() { const app = await NestFactory.create(AppModule, { bodyParser: false }); const bodyLimit = requestBodyLimit(); app.use(json({ limit: bodyLimit })); app.use(urlencoded({ limit: bodyLimit, extended: true })); configureTrustProxy(app); app.enableCors(createCorsOptions()); app.setGlobalPrefix('api'); const port = Number(process.env.PORT ?? 3000); await app.listen(port, '0.0.0.0'); // eslint-disable-next-line no-console console.log(`Backend API listening on http://127.0.0.1:${port}/api`); } void bootstrap();