import { INestApplication } from '@nestjs/common'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { HttpErrorCode } from './common/error-code'; import { MoexErrorCode } from './integrations/moex/moex.client'; import { NcrErrorCode } from './integrations/ncr/ncr-ratings.client'; import { TbankErrorCode } from './integrations/tbank/tbank-error-code'; import { AuthErrorCode } from './modules/auth/application/auth-error-code'; import { BankErrorCode } from './modules/banking/bank-cards/application/bank-card-input'; import { IncomeErrorCode } from './modules/investments/income/income-period'; import { InstrumentErrorCode } from './modules/investments/instruments/domain/instrument-error-code'; import { OperationErrorCode } from './modules/investments/operations/domain/operation-error-code'; import { EventsErrorCode } from './modules/investments/upcoming-events/upcoming-events.api'; export const API_PREFIX = 'api/v1'; // Nest Swagger cannot express additionalProperties on a class, so closed request // bodies are restored here after generation; the runtime allowlist stays in the controller. const CLOSED_SCHEMAS = ['StockScreenerCriteriaDto']; // Every code HttpExceptionFilter can emit. Assembled at the composition root so // common/ProblemDetailsDto does not depend on modules. export const PROBLEM_CODES = [ ...Object.values(HttpErrorCode), ...Object.values(AuthErrorCode), ...Object.values(OperationErrorCode), ...Object.values(InstrumentErrorCode), ...Object.values(TbankErrorCode), ...Object.values(BankErrorCode), ...Object.values(MoexErrorCode), ...Object.values(NcrErrorCode), ...Object.values(EventsErrorCode), ...Object.values(IncomeErrorCode), ]; export function createOpenApiDocument(app: INestApplication) { const document = SwaggerModule.createDocument( app, new DocumentBuilder().setTitle('WealthLedger API').setVersion('v1').build(), ); const schemas = document.components?.schemas ?? {}; for (const [name, schema] of Object.entries(schemas)) { if (CLOSED_SCHEMAS.includes(name) && 'properties' in schema) { schema.additionalProperties = false; } } const problem = schemas.ProblemDetailsDto; const problemCode = problem && 'properties' in problem ? problem.properties?.code : undefined; if (problemCode && !('$ref' in problemCode)) problemCode.enum = PROBLEM_CODES; return document; }