import { CallHandler, ExecutionContext, Injectable, NestInterceptor, StreamableFile, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { PAGINATION_RESPONSE, RAW_RESPONSE } from './constants'; import { createPaginationResponse, resolvePaginationQuery, } from './pagination-meta.helper'; /** * Applies pagination enveloping when a handler is marked with `@Pagination()`. * * Non-paginated handlers pass through unchanged. `@RawResponse()`, empty * bodies, and `StreamableFile` downloads are never wrapped. */ @Injectable() export class TransformInterceptor implements NestInterceptor { constructor(private readonly reflector: Reflector) {} intercept(context: ExecutionContext, next: CallHandler): Observable { const isRaw = this.reflector.getAllAndOverride(RAW_RESPONSE, [ context.getHandler(), context.getClass(), ]); if (isRaw) { return next.handle(); } const isPagination = this.reflector.getAllAndOverride( PAGINATION_RESPONSE, [context.getHandler(), context.getClass()], ); if (!isPagination) { return next.handle(); } const request = context.switchToHttp().getRequest<{ query: Record; }>(); const { page, limit } = resolvePaginationQuery(request.query); return next.handle().pipe( map((payload: unknown): unknown => { if (payload == null || payload instanceof StreamableFile) { return payload; } return createPaginationResponse(payload, page, limit); }), ); } }