import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; const SWAGGER_BASIC_AUTH_USER = process.env.SWAGGER_USER || 'admin'; const SWAGGER_BASIC_AUTH_PASSWORD = process.env.SWAGGER_PASSWORD || 'change_me'; function isLocalhost(url: string): boolean { return url.includes('localhost') || url.includes('127.0.0.1'); } function isSwaggerEnabled(): boolean { if (process.env.NODE_ENV === 'production') { return process.env.ENABLE_SWAGGER === 'true'; } return process.env.ENABLE_SWAGGER !== 'false'; } function needsBasicAuth(): boolean { if (process.env.NODE_ENV === 'production') { return process.env.ENABLE_SWAGGER === 'true'; } return false; } function createBasicAuthMiddleware() { return (req: any, res: any, next: any) => { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Basic ')) { res.setHeader('WWW-Authenticate', 'Basic realm="Swagger API Docs"'); res.status(401).send('Authentication required'); return; } const base64Credentials = authHeader.split(' ')[1]; const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8'); const [username, password] = credentials.split(':'); if (username === SWAGGER_BASIC_AUTH_USER && password === SWAGGER_BASIC_AUTH_PASSWORD) { next(); } else { res.status(401).send('Invalid credentials'); } }; } async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors({ origin: ['https://longde.cloud', 'http://localhost:4321'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], credentials: true, }); if (isSwaggerEnabled()) { const config = new DocumentBuilder() .setTitle('龙de AI 学习产品 API') .setDescription('AI 学习产品后端 API 文档(v0.1),包含用户管理、学习路径、AI 对话、反馈等功能。') .setVersion('0.1.0') .addTag('health', '服务健康检查') .addTag('auth', '用户认证') .addTag('users', '用户管理') .addTag('knowledge', '知识库') .addTag('learning', '学习路径与进度') .addTag('ai', 'AI 分析与对话') .addTag('review', '复习任务') .addTag('feedback', '用户反馈') .addTag('waitlist', '等待名单') .build(); const document = SwaggerModule.createDocument(app, config); if (needsBasicAuth()) { app.use('/api-docs', createBasicAuthMiddleware() as any); app.use('/api-docs-json', createBasicAuthMiddleware() as any); } SwaggerModule.setup('api-docs', app, document, { swaggerOptions: { persistAuthorization: true, }, customCss: '.swagger-ui .topbar { display: none }', customSiteTitle: '龙de API 文档', }); app.getHttpAdapter().get('/api-docs-json', (_req: any, res: any) => { res.json(document); }); console.log('[Swagger] API 文档已启用'); if (needsBasicAuth()) { console.log(`[Swagger] Basic Auth 已启用 (${SWAGGER_BASIC_AUTH_USER})`); } } else { console.log('[Swagger] API 文档已禁用'); } const port = process.env.PORT ?? 3000; await app.listen(port); console.log(`[API] Server running on http://localhost:${port}`); } bootstrap();