UNPKG

@nestjsvn/swagger-sse

Version:

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

150 lines (149 loc) 5.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateSseOptions = validateSseOptions; exports.eventNameToSchemaName = eventNameToSchemaName; exports.hasSwaggerDecorators = hasSwaggerDecorators; exports.getDefaultSseContentType = getDefaultSseContentType; exports.createSseEventExample = createSseEventExample; exports.getSseMetadata = getSseMetadata; const constants_1 = require("./constants"); /** * Validate ApiSse decorator options * * @param options SSE configuration options * @throws Error if options are invalid */ function validateSseOptions(options) { if (!options) { throw new Error('ApiSse options are required'); } if (!options.events) { throw new Error('ApiSse options must include events mapping'); } if (typeof options.events !== 'object' || Array.isArray(options.events)) { throw new Error('ApiSse events must be an object mapping event names to DTO classes'); } const eventNames = Object.keys(options.events); if (eventNames.length === 0) { throw new Error('ApiSse events mapping cannot be empty'); } // Validate each event mapping Object.entries(options.events).forEach(([eventName, eventType]) => { if (!eventName || typeof eventName !== 'string') { throw new Error('Event names must be non-empty strings'); } // Validate event type according to ApiSseOptions interface if (!eventType || (typeof eventType !== 'function' && typeof eventType !== 'string' && !Array.isArray(eventType))) { throw new Error(`Invalid event type for event '${eventName}': must be a class constructor, string, or array of class constructors`); } // Validate array types if (Array.isArray(eventType)) { const arrayType = eventType; if (arrayType.length === 0) { throw new Error(`Invalid array event type for event '${eventName}': array cannot be empty`); } if (typeof arrayType[0] !== 'function') { throw new Error(`Invalid array event type for event '${eventName}': array must contain class constructors`); } } }); // Validate optional properties if (options.produces && typeof options.produces !== 'string') { throw new Error('produces must be a string'); } if (options.summary && typeof options.summary !== 'string') { throw new Error('summary must be a string'); } if (options.description && typeof options.description !== 'string') { throw new Error('description must be a string'); } if (options.operationId && typeof options.operationId !== 'string') { throw new Error('operationId must be a string'); } if (options.tags && !Array.isArray(options.tags)) { throw new Error('tags must be an array of strings'); } if (options.tags) { options.tags.forEach((tag, index) => { if (typeof tag !== 'string') { throw new Error(`Tag at index ${index} must be a string`); } }); } if (options.deprecated !== undefined && typeof options.deprecated !== 'boolean') { throw new Error('deprecated must be a boolean'); } if (options.security && !Array.isArray(options.security)) { throw new Error('security must be an array of security requirement objects'); } } /** * Convert event name to a valid schema name * * @param eventName Event name (e.g., 'user-created') * @returns Schema name (e.g., 'UserCreated') */ function eventNameToSchemaName(eventName) { return eventName .split('-') .map(part => part.charAt(0).toUpperCase() + part.slice(1)) .join(''); } /** * Check if a class has Swagger decorators * * @param dtoClass DTO class constructor * @returns True if the class has Swagger metadata */ function hasSwaggerDecorators(dtoClass) { if (!dtoClass || typeof dtoClass !== 'function') { return false; } // Check for common Swagger metadata keys const metadataKeys = [ 'swagger/apiModelPropertiesArray', 'swagger/apiModelProperties', 'swagger/apiModel', ]; return metadataKeys.some(key => Reflect.hasMetadata(key, dtoClass) || // eslint-disable-next-line @typescript-eslint/no-unsafe-argument Reflect.hasMetadata(key, Object.getPrototypeOf(dtoClass.prototype))); } /** * Get default content type for SSE * * @returns Default SSE content type */ function getDefaultSseContentType() { return 'text/event-stream'; } /** * Create example SSE event data * * @param eventName Event name * @param data Event data * @returns Formatted SSE event string */ function createSseEventExample(eventName, data) { const lines = []; if (eventName) { lines.push(`event: ${eventName}`); } lines.push(`data: ${JSON.stringify(data)}`); lines.push(''); // Empty line to end the event return lines.join('\n'); } /** * Get SSE metadata from a method * * @param target Target class * @param propertyKey Method name * @returns SSE metadata or undefined */ function getSseMetadata(target, propertyKey) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return Reflect.getMetadata(constants_1.METADATA_KEYS.API_SSE, target, propertyKey); }