116 lines
2.8 KiB
TypeScript
116 lines
2.8 KiB
TypeScript
/**
|
|
* 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 <This, Args extends any[], Return>(
|
|
target: (this: This, ...args: Args) => Return,
|
|
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => 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 <This, Args extends any[], Return>(
|
|
target: (this: This, ...args: Args) => Return,
|
|
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
|
|
) {
|
|
context.addInitializer(function (this: This) {
|
|
setRouteCompression(this, context.name, {
|
|
enabled: false,
|
|
});
|
|
});
|
|
return target;
|
|
};
|
|
}
|