| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import 'reflect-metadata';
- import { ValidationPipe } from '@nestjs/common';
- import { ConfigService } from '@nestjs/config';
- import { NestFactory } from '@nestjs/core';
- import {
- FastifyAdapter,
- NestFastifyApplication,
- } from '@nestjs/platform-fastify';
- import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
- import { Logger } from 'nestjs-pino';
- import multipart from '@fastify/multipart';
- import { AppModule } from './app.module';
- import fastifyStatic from '@fastify/static';
- import * as path from 'path';
- // @ts-expect-error: allow JSON.stringify(BigInt)
- BigInt.prototype.toJSON = function () {
- const value = this as bigint;
- if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
- return this.toString();
- }
- return Number(this);
- };
- async function bootstrap() {
- const fastifyAdapter = new FastifyAdapter() as FastifyAdapter;
- // multipart for file upload (e.g. OSS, S3)
- await fastifyAdapter.register(multipart as any, {
- limits: {
- fileSize: 30 * 1024 * 1024, // 30 MB
- },
- });
- // after creating fastifyAdapter but before NestFactory.create:
- // Read allowed origin from env (fallback to '*')
- const corsOrg = process.env.APP_CORS_ORIGIN || '*';
- // await fastifyAdapter.register(fastifyStatic as any, {
- // root: path.resolve(process.env.IMAGE_ROOT_PATH || '/data/box-images'),
- // prefix: '/images/',
- // setHeaders: (res: any, pathName: any, stat: any) => {
- // // CORS
- // res.setHeader('Access-Control-Allow-Origin', corsOrg);
- // res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
- // res.setHeader(
- // 'Access-Control-Allow-Headers',
- // 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
- // );
- // },
- // });
- const app = await NestFactory.create<NestFastifyApplication>(
- AppModule,
- fastifyAdapter,
- {
- bufferLogs: true,
- snapshot: true,
- },
- );
- // nestjs-pino logger
- app.useLogger(app.get(Logger));
- // Global API prefix; mgnt routes stay under /api/v1/mgnt/*
- app.setGlobalPrefix('api/v1');
- app.useGlobalPipes(
- new ValidationPipe({
- transform: true,
- whitelist: true,
- forbidNonWhitelisted: false,
- }),
- );
- const configService = app.get(ConfigService);
- const host =
- configService.get<string>('MGNT_HOST') ??
- configService.get<string>('MGNT_HOST') ??
- '0.0.0.0';
- const port =
- configService.get<number>('MGNT_PORT') ?? Number(process.env.PORT ?? 3300);
- const corsOrigin = configService.get<string>('MGNT_CORS_ORIGIN') ?? '*';
- const corsOriginOption =
- corsOrigin === '*'
- ? true
- : corsOrigin
- .split(',')
- .map((o) => o.trim())
- .filter(Boolean);
- app.enableCors({
- origin: corsOriginOption,
- methods: 'GET,PUT,PATCH,POST,DELETE',
- credentials: true,
- });
- if (process.env.NODE_ENV !== 'production') {
- const swaggerConfig = new DocumentBuilder()
- .setTitle('盒子管理系统管理后台 API 文档')
- .setDescription('盒子管理系统管理后台接口 (api/v1/mgnt/*)')
- .setVersion('1.0')
- .addBearerAuth()
- .addServer(`http://${host}:${port}`, '本地开发环境')
- .addTag('系统 - 授权', '管理后台授权相关接口 (mgnt/auth)')
- .addTag('系统 - 用户', '管理后台用户管理接口 (mgnt/users)')
- .addTag('系统 - 角色', '管理后台角色管理接口 (mgnt/roles)')
- .addTag('系统 - 菜单', '管理后台菜单管理接口 (mgnt/menus)')
- .build();
- const swaggerDocument = SwaggerModule.createDocument(app, swaggerConfig);
- SwaggerModule.setup('api-docs', app, swaggerDocument, {
- jsonDocumentUrl: '/api-docs-json',
- swaggerOptions: {
- docExpansion: 'none',
- tagsSorter: 'alpha',
- operationsSorter: 'alpha',
- },
- });
- // Prevent Swagger UI/JSON from being cached (browser + proxies)
- const fastify = app.getHttpAdapter().getInstance();
- fastify.addHook('onSend', (request, reply, payload, done) => {
- if (
- request.url?.startsWith('/api-docs') ||
- request.url === '/api-docs-json'
- ) {
- reply.header(
- 'Cache-Control',
- 'no-store, no-cache, must-revalidate, proxy-revalidate',
- );
- reply.header('Pragma', 'no-cache');
- reply.header('Expires', '0');
- }
- done(null, payload);
- });
- }
- await app.listen(port, host);
- const url = `http://${host}:${port}`;
- console.log(`🚀 box-mgnt-api is running at: ${url}`);
- console.log(`📚 API Documentation: ${url}/api-docs`);
- console.log(`📄 Swagger JSON: ${url}/api-docs-json`);
- console.log(`🔧 Management APIs: ${url}/api/v1/mgnt/*`);
- }
- bootstrap();
|