121 lines
4.1 KiB
TypeScript
Executable File
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();
|