All files / src/common/guards throttler-logger.guard.ts

68.75% Statements 11/16
54.16% Branches 13/24
66.66% Functions 2/3
64.28% Lines 9/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 4012x 12x 12x 12x     12x         1x   1x         1x 1x                                        
import { Injectable, ExecutionContext, Inject } from '@nestjs/common';
import { ThrottlerGuard, ThrottlerException, ThrottlerModuleOptions, ThrottlerStorage } from '@nestjs/throttler';
import { Reflector } from '@nestjs/core';
import { LoggerService } from '@app/common/services/logger.service';
 
@Injectable()
export class ThrottlerLoggerGuard extends ThrottlerGuard {
  constructor(
    @Inject('THROTTLER_OPTIONS') options: ThrottlerModuleOptions,
    @Inject('THROTTLER_STORAGE') storageService: ThrottlerStorage,
    reflector: Reflector,
    private readonly logger: LoggerService,
  ) {
    super(options, storageService, reflector);
  }
 
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // In test runs, disable throttling to ensure deterministic, non-flaky tests
    if (process.env.TEST_MODE === '1' || process.env.NODE_ENV === 'test') {
      return true;
    }
    return super.canActivate(context) as any;
  }
 
  protected async throwThrottlingException(context: ExecutionContext, throttlerLimitDetail: any): Promise<void> {
    const req = this.getRequestResponse(context).req;
    // Try to get userId if available (JWT, session, etc.)
    const userId = req.user?.id || req.user?.sub || undefined;
    this.logger.warn('Rate limit exceeded', {
      ip: req.ip,
      path: req.originalUrl || req.url,
      userId,
      method: req.method,
      limit: throttlerLimitDetail?.limit,
      ttl: throttlerLimitDetail?.ttl,
      timestamp: new Date().toISOString(),
    });
    throw new ThrottlerException('Too many requests. Please try again later.');
  }
}