UNPKG

@nestjsvn/swagger-sse

Version:

OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints

148 lines (147 loc) 5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApiSse = ApiSse; require("reflect-metadata"); const common_1 = require("@nestjs/common"); const swagger_1 = require("@nestjs/swagger"); const constants_1 = require("../utils/constants"); const generator_1 = require("../schema/generator"); const helpers_1 = require("../utils/helpers"); /** * Extract model types from events parameter for automatic registration * * @param events Event name to DTO type mapping * @returns Array of model types to register */ function extractModelTypes(events) { const modelTypes = []; for (const eventType of Object.values(events)) { if (typeof eventType === 'function') { // Direct class constructor modelTypes.push(eventType); } else if (Array.isArray(eventType) && eventType.length > 0 && typeof eventType[0] === 'function') { // Array of class constructors (for array types) modelTypes.push(eventType[0]); } // Skip string types as they don't need model registration } return modelTypes; } /** * Create API operation options from SSE options * * @param options SSE options * @returns API operation options object */ function createApiOperationOptions(options) { const operationOptions = {}; if (options.summary) { operationOptions.summary = options.summary; } if (options.operationId) { operationOptions.operationId = options.operationId; } if (options.deprecated !== undefined) { operationOptions.deprecated = options.deprecated; } if (options.description) { operationOptions.description = options.description; } return operationOptions; } /** * Create basic API decorators for SSE endpoint * * @param options SSE options * @returns Array of basic decorators */ function createBasicApiDecorators(options) { return [ (0, swagger_1.ApiProduces)(options.produces ?? 'text/event-stream'), (0, swagger_1.ApiExtension)('x-sse-endpoint', true), (0, swagger_1.ApiResponse)({ status: 200, description: options.description ?? 'Server-Sent Events stream', content: { [options.produces ?? 'text/event-stream']: { schema: (0, generator_1.generateSseSchema)(options), }, }, }), ]; } /** * Create model registration decorators * * @param options SSE options * @returns Array of model registration decorators */ function createModelRegistrationDecorators(options) { const decorators = []; // Automatically register model types from events parameter const modelTypes = extractModelTypes(options.events); if (modelTypes.length > 0) { decorators.push((0, swagger_1.ApiExtraModels)(...modelTypes)); } // Also register defaultEvent if it's a model type if (options.defaultEvent && typeof options.defaultEvent === 'function') { decorators.push((0, swagger_1.ApiExtraModels)(options.defaultEvent)); } else if (options.defaultEvent && Array.isArray(options.defaultEvent) && options.defaultEvent.length > 0 && typeof options.defaultEvent[0] === 'function') { decorators.push((0, swagger_1.ApiExtraModels)(options.defaultEvent[0])); } return decorators; } /** * Decorator for documenting Server-Sent Events endpoints in OpenAPI * * @param options Configuration options for the SSE endpoint * @returns Method decorator that applies OpenAPI documentation * * @example * ```typescript * @ApiSse({ * events: { * 'user-created': UserCreatedDto, * 'user-updated': UserUpdatedDto * }, * summary: 'User events stream' * }) * @Sse('users') * streamUserEvents(): Observable<MessageEvent> { * // Implementation * } * ``` */ function ApiSse(options) { (0, helpers_1.validateSseOptions)(options); return (target, propertyKey, descriptor) => { const decorators = [ ...createModelRegistrationDecorators(options), ...createBasicApiDecorators(options), ]; // Add ApiOperation if needed const operationOptions = createApiOperationOptions(options); if (Object.keys(operationOptions).length > 0) { decorators.push((0, swagger_1.ApiOperation)(operationOptions)); } // Add tags if provided if (options.tags && options.tags.length > 0) { decorators.push((0, swagger_1.ApiTags)(...options.tags)); } // Apply all decorators const combinedDecorator = (0, common_1.applyDecorators)(...decorators); combinedDecorator(target, propertyKey, descriptor); // Store metadata for schema generation and plugin use if (propertyKey) { Reflect.defineMetadata(constants_1.METADATA_KEYS.API_SSE, options, target, propertyKey); } return descriptor; }; }