Files
iddaai-be/src/main.ts
T
2026-04-24 01:15:05 +03:00

121 lines
4.1 KiB
TypeScript
Executable File

import { NestFactory } from "@nestjs/core";
import { ValidationPipe, Logger as NestLogger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { AppModule } from "./app.module";
import helmet from "helmet";
import * as express from "express";
import { Logger, LoggerErrorInterceptor } from "nestjs-pino";
import { SanitizeInterceptor } from "./common/interceptors/sanitize.interceptor";
// BigInt serialization polyfill — Prisma returns BigInt for mstUtc etc.
(BigInt.prototype as unknown as { toJSON: () => string }).toJSON = function () {
return this.toString();
};
async function bootstrap() {
const logger = new NestLogger("Bootstrap");
logger.log("🔄 Starting application...");
const app = await NestFactory.create(AppModule, { bufferLogs: false });
// Use Pino Logger
app.useLogger(app.get(Logger));
app.useGlobalInterceptors(
new LoggerErrorInterceptor(),
new SanitizeInterceptor(),
);
// Security Headers
app.use(helmet());
// Request payload size limit
app.use(express.json({ limit: "1mb" }));
app.use(express.urlencoded({ extended: true, limit: "1mb" }));
// Graceful Shutdown (Prisma & Docker)
app.enableShutdownHooks();
// Get config service
const configService = app.get(ConfigService);
const port = configService.get<number>("PORT", 3005);
const nodeEnv = configService.get("NODE_ENV", "development");
// Enable CORS
app.enableCors({
origin:
nodeEnv === "production"
? [
"https://ui-suggestbet.bilgich.com",
"https://suggestbet.bilgich.com",
"https://iddaai.com",
"https://www.iddaai.com",
"http://localhost:6195",
]
: true,
credentials: true,
});
// Global prefix
app.setGlobalPrefix("api");
// Validation pipe (Strict)
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
transformOptions: {
enableImplicitConversion: true,
},
}),
);
// Swagger setup — hidden in production
if (nodeEnv !== "production") {
const swaggerConfig = new DocumentBuilder()
.setTitle("Suggest-Bet API")
.setDescription(
"AI-driven sports betting prediction engine with smart coupon generation",
)
.setVersion("1.0")
.addBearerAuth()
.addTag("Auth", "Authentication endpoints")
.addTag("Users", "User management endpoints")
.addTag("Admin", "Admin management endpoints")
.addTag("Health", "Health check endpoints")
.addTag("Matches", "Match listing and detail endpoints")
.addTag("Leagues", "League, country, and team discovery endpoints")
.addTag("Analysis", "AI analysis and analysis history endpoints")
.addTag("Coupon", "Coupon generation and coupon management endpoints")
.addTag("Predictions", "Prediction and smart-coupon endpoints")
.build();
logger.log("Initializing Swagger...");
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup("api/docs", app, document, {
swaggerOptions: {
persistAuthorization: true,
},
});
logger.log("Swagger initialized");
}
logger.log(`Attempting to listen on port ${port}...`);
await app.listen(port, "0.0.0.0");
logger.log("═══════════════════════════════════════════════════════════");
logger.log(`🚀 Server is running on: http://localhost:${port}/api`);
logger.log(`📚 Swagger documentation: http://localhost:${port}/api/docs`);
logger.log(`💚 Health check: http://localhost:${port}/api/health`);
logger.log(`🌍 Environment: ${nodeEnv.toUpperCase()}`);
logger.log("═══════════════════════════════════════════════════════════");
if (nodeEnv === "development") {
logger.warn("⚠️ Running in development mode");
}
}
void bootstrap();