@nestjsvn/swagger-sse
Version:
OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints
148 lines (147 loc) • 5 kB
JavaScript
;
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;
};
}