/** * Compression control decorators (@Compress, @NoCompress) * * These decorators allow per-route control over compression: * - @Compress(options?) - Force compression with optional settings * - @NoCompress() - Disable compression for this route (useful for SSE, streaming) */ import { getControllerMetadata } from './decorators.metadata.js'; import type { IRouteCompressionOptions } from './decorators.types.js'; /** * Set compression options for a route */ function setRouteCompression( target: any, methodName: string | symbol, options: IRouteCompressionOptions ): void { const metadata = getControllerMetadata(target.constructor); let route = metadata.routes.get(methodName); if (!route) { // Create placeholder route (will be completed by @Get/@Post/etc.) route = { method: 'GET', path: '', methodName, interceptors: [], options: {}, }; metadata.routes.set(methodName, route); } route.compression = options; } /** * @Compress decorator - Force compression on a route with optional settings * * @example * ```typescript * @Controller('/api') * class ApiController { * @Get('/heavy-data') * @Compress({ level: 11 }) // Max brotli compression * getHeavyData() { * return massiveJsonData; * } * * @Get('/data') * @Compress() // Use default settings * getData() { * return jsonData; * } * } * ``` */ export function Compress(options?: { level?: number }) { return function ( target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext Return> ) { context.addInitializer(function (this: This) { setRouteCompression(this, context.name, { enabled: true, level: options?.level, }); }); return target; }; } /** * @NoCompress decorator - Disable compression for a route * * Useful for: * - Server-Sent Events (SSE) * - Streaming responses * - Already-compressed content * - Real-time data where latency is critical * * @example * ```typescript * @Controller('/api') * class EventController { * @Get('/events') * @NoCompress() // SSE should not be compressed * getEvents() { * return new Response(eventStream, { * headers: { 'Content-Type': 'text/event-stream' } * }); * } * * @Get('/video/:id') * @NoCompress() // Already compressed media * getVideo() { * return videoStream; * } * } * ``` */ export function NoCompress() { return function ( target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext Return> ) { context.addInitializer(function (this: This) { setRouteCompression(this, context.name, { enabled: false, }); }); return target; }; }