main.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import 'reflect-metadata';
  2. import { ValidationPipe } from '@nestjs/common';
  3. import { ConfigService } from '@nestjs/config';
  4. import { NestFactory } from '@nestjs/core';
  5. import {
  6. FastifyAdapter,
  7. NestFastifyApplication,
  8. } from '@nestjs/platform-fastify';
  9. import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
  10. import { Logger } from 'nestjs-pino';
  11. import multipart from '@fastify/multipart';
  12. import { AppModule } from './app.module';
  13. // @ts-expect-error: allow JSON.stringify(BigInt)
  14. BigInt.prototype.toJSON = function () {
  15. const value = this as bigint;
  16. if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
  17. return this.toString();
  18. }
  19. return Number(this);
  20. };
  21. async function bootstrap() {
  22. const fastifyAdapter = new FastifyAdapter() as FastifyAdapter;
  23. // multipart for file upload (e.g. OSS, S3)
  24. await fastifyAdapter.register(multipart as any, {
  25. limits: {
  26. fileSize: 30 * 1024 * 1024, // 30 MB
  27. },
  28. });
  29. const app = await NestFactory.create<NestFastifyApplication>(
  30. AppModule,
  31. fastifyAdapter,
  32. {
  33. bufferLogs: true,
  34. snapshot: true,
  35. },
  36. );
  37. // nestjs-pino logger
  38. app.useLogger(app.get(Logger));
  39. // Global API prefix; mgnt routes stay under /api/v1/mgnt/*
  40. app.setGlobalPrefix('api/v1');
  41. app.useGlobalPipes(
  42. new ValidationPipe({
  43. transform: true,
  44. whitelist: true,
  45. forbidNonWhitelisted: false,
  46. }),
  47. );
  48. const configService = app.get(ConfigService);
  49. const host =
  50. configService.get<string>('APP_HOST') ??
  51. configService.get<string>('HOST') ??
  52. '0.0.0.0';
  53. const port =
  54. configService.get<number>('APP_PORT') ?? Number(process.env.PORT ?? 3300);
  55. const crossOrigin =
  56. configService.get<string>('APP_CROSS_ORIGIN') ??
  57. configService.get<string>('CROSS_ORIGIN') ??
  58. '*';
  59. app.enableCors({
  60. origin:
  61. crossOrigin === '*' ? true : crossOrigin.split(',').map((o) => o.trim()),
  62. methods: 'GET,PUT,PATCH,POST,DELETE',
  63. });
  64. if (process.env.NODE_ENV !== 'production') {
  65. const config = new DocumentBuilder()
  66. .setTitle('盒子管理系统管理后台 API 文档')
  67. .setDescription('盒子管理系统管理后台接口 (api/v1/mgnt/*)')
  68. .setVersion('1.0')
  69. .addBearerAuth()
  70. .addServer(`http://${host}:${port}`, '本地开发环境')
  71. .addTag('系统 - 授权', '管理后台授权相关接口 (mgnt/auth)')
  72. .addTag('系统 - 用户', '管理后台用户管理接口 (mgnt/users)')
  73. .addTag('系统 - 角色', '管理后台角色管理接口 (mgnt/roles)')
  74. .addTag('系统 - 菜单', '管理后台菜单管理接口 (mgnt/menus)')
  75. .build();
  76. const document = SwaggerModule.createDocument(app, config);
  77. SwaggerModule.setup('api-docs', app, document, {
  78. swaggerOptions: {
  79. docExpansion: 'none',
  80. tagsSorter: 'alpha',
  81. operationsSorter: 'alpha',
  82. },
  83. });
  84. }
  85. await app.listen(port, host);
  86. const url = `http://${host}:${port}`;
  87. console.log(`🚀 box-mgnt-api is running at: ${url}`);
  88. console.log(`📚 API Documentation: ${url}/api-docs`);
  89. console.log(`🔧 Management APIs: ${url}/api/v1/mgnt/*`);
  90. }
  91. bootstrap();