Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/cache/cache.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { CacheController } from './controllers/cache.controller';
url: redisUrl,
ttl,
prefix,
retryStrategy: (times: number) => {
retryStrategy: (times: number): number => {
const delay = Math.min(times * 50, 2000);
return delay;
},
Expand Down
10 changes: 5 additions & 5 deletions src/cache/cache.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class CacheService {
/**
* Generate a cache key with proper naming convention
*/
private generateKey(entity: string, action: string, params?: Record<string, any>): string {
private generateKey(entity: string, action: string, params?: Record<string, unknown>): string {
const baseKey = `${this.prefix}${entity}:${action}`;

if (!params || Object.keys(params).length === 0) {
Expand All @@ -38,7 +38,7 @@ export class CacheService {
/**
* Get data from cache
*/
async get<T>(entity: string, action: string, params?: Record<string, any>): Promise<T | null> {
async get<T>(entity: string, action: string, params?: Record<string, unknown>): Promise<T | null> {
const key = this.generateKey(entity, action, params);

try {
Expand Down Expand Up @@ -67,7 +67,7 @@ export class CacheService {
action: string,
data: T,
ttl?: number,
params?: Record<string, any>
params?: Record<string, unknown>
): Promise<void> {
const key = this.generateKey(entity, action, params);

Expand All @@ -85,7 +85,7 @@ export class CacheService {
/**
* Delete specific cache entry
*/
async delete(entity: string, action: string, params?: Record<string, any>): Promise<void> {
async delete(entity: string, action: string, params?: Record<string, unknown>): Promise<void> {
const key = this.generateKey(entity, action, params);

try {
Expand Down Expand Up @@ -154,7 +154,7 @@ export class CacheService {
/**
* Get cache statistics (if available)
*/
async getStats(): Promise<Record<string, any>> {
async getStats(): Promise<Record<string, unknown>> {
try {
// This would return Redis INFO command results in production
return {
Expand Down
8 changes: 4 additions & 4 deletions src/cache/controllers/cache.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class CacheController {
@ApiOperation({ summary: 'Get cache statistics' })
@ApiResponse({ status: 200, description: 'Cache statistics retrieved successfully' })
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async getStats() {
async getStats(): Promise<Record<string, unknown>> {
return await this.cacheService.getStats();
}

Expand All @@ -27,7 +27,7 @@ export class CacheController {
@ApiOperation({ summary: 'Clear entire cache' })
@ApiResponse({ status: 200, description: 'Cache cleared successfully' })
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async resetCache() {
async resetCache(): Promise<{ message: string }> {
await this.cacheService.reset();
return { message: 'Cache cleared successfully' };
}
Expand All @@ -38,7 +38,7 @@ export class CacheController {
@ApiOperation({ summary: 'Invalidate cache for specific entity' })
@ApiResponse({ status: 200, description: 'Entity cache invalidated successfully' })
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async invalidateEntity(entity: string) {
async invalidateEntity(entity: string): Promise<{ message: string }> {
await this.cacheService.invalidateEntity(entity);
return { message: `Cache invalidated for entity: ${entity}` };
}
Comment on lines +41 to 44
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Missing @Param decorator for route parameter.

The invalidateEntity method uses entity: string parameter but lacks the @Param('entity') decorator to bind it to the route parameter :entity (line 35). This will cause entity to be undefined at runtime.

Apply this diff:

+  async invalidateEntity(@Param('entity') entity: string): Promise<{ message: string }> {
-  async invalidateEntity(entity: string): Promise<{ message: string }> {

Import Param from @nestjs/common:

-import { Controller, Post, Get, Delete, UseGuards, HttpCode, HttpStatus } from '@nestjs/common';
+import { Controller, Post, Get, Delete, UseGuards, HttpCode, HttpStatus, Param } from '@nestjs/common';
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async invalidateEntity(entity: string): Promise<{ message: string }> {
await this.cacheService.invalidateEntity(entity);
return { message: `Cache invalidated for entity: ${entity}` };
}
++ b/src/cache/controllers/cache.controller.ts
@@ -1,7 +1,7 @@
import { Controller, Post, Get, Delete, UseGuards, HttpCode, HttpStatus, Param } from '@nestjs/common';
import { CacheService } from '../services/cache.service';
@Controller('cache')
export class CacheController {
@@ -38,7 +38,7 @@ export class CacheController {
@HttpCode(HttpStatus.OK)
async invalidateEntity(@Param('entity') entity: string): Promise<{ message: string }> {
await this.cacheService.invalidateEntity(entity);
return { message: `Cache invalidated for entity: ${entity}` };
}
πŸ€– Prompt for AI Agents
In src/cache/controllers/cache.controller.ts around lines 41 to 44, the route
handler parameter entity is missing the @Param('entity') decorator and thus will
be undefined at runtime; import Param from @nestjs/common at the top of the file
and annotate the method signature parameter with @Param('entity') so NestJS
binds the :entity route param to the entity argument, keeping the method return
and logic unchanged.

Expand All @@ -49,7 +49,7 @@ export class CacheController {
@ApiOperation({ summary: 'Invalidate cache for specific entity action' })
@ApiResponse({ status: 200, description: 'Entity action cache invalidated successfully' })
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async invalidateAction(entity: string, action: string) {
async invalidateAction(entity: string, action: string): Promise<{ message: string }> {
await this.cacheService.invalidateAction(entity, action);
return { message: `Cache invalidated for entity: ${entity}, action: ${action}` };
}
Comment on lines +52 to 55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Missing @Param decorators for route parameters.

The invalidateAction method uses entity: string and action: string parameters but lacks the @Param decorators to bind them to the route parameters :entity and :action (line 46). This will cause both parameters to be undefined at runtime.

Apply this diff:

+  async invalidateAction(@Param('entity') entity: string, @Param('action') action: string): Promise<{ message: string }> {
-  async invalidateAction(entity: string, action: string): Promise<{ message: string }> {

Ensure Param is imported from @nestjs/common (see previous comment).

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async invalidateAction(entity: string, action: string): Promise<{ message: string }> {
await this.cacheService.invalidateAction(entity, action);
return { message: `Cache invalidated for entity: ${entity}, action: ${action}` };
}
async invalidateAction(
@Param('entity') entity: string,
@Param('action') action: string
): Promise<{ message: string }> {
await this.cacheService.invalidateAction(entity, action);
return { message: `Cache invalidated for entity: ${entity}, action: ${action}` };
}
πŸ€– Prompt for AI Agents
In src/cache/controllers/cache.controller.ts around lines 52 to 55, the
invalidateAction method parameters are not bound to route params; add
@Param('entity') entity: string and @Param('action') action: string to the
method signature so NestJS injects the route values, and ensure Param is
imported from '@nestjs/common' at the top of the file.

Expand Down
12 changes: 6 additions & 6 deletions src/cache/decorators/cache.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export interface CacheOptions {
/**
* Decorator to mark a method for caching
*/
export const Cacheable = (options: CacheOptions) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
export const Cacheable = (options: CacheOptions): MethodDecorator => {
return (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => {
SetMetadata(CACHE_KEY_METADATA, {
key: options.key,
entity: options.entity,
Expand All @@ -32,8 +32,8 @@ export const Cacheable = (options: CacheOptions) => {
/**
* Decorator to mark a method that should invalidate cache
*/
export const CacheInvalidate = (entity: string, action?: string) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
export const CacheInvalidate = (entity: string, action?: string): MethodDecorator => {
return (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => {
SetMetadata('cache_invalidate', { entity, action })(target, propertyKey, descriptor);
return descriptor;
};
Expand All @@ -42,8 +42,8 @@ export const CacheInvalidate = (entity: string, action?: string) => {
/**
* Decorator to mark a method that should clear all cache
*/
export const CacheClear = () => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
export const CacheClear = (): MethodDecorator => {
return (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => {
SetMetadata('cache_clear', true)(target, propertyKey, descriptor);
return descriptor;
};
Expand Down
6 changes: 3 additions & 3 deletions src/cache/interceptors/cache.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Inject,
} from '@nestjs/common';
import { Observable, of } from 'rxjs';
import { tap, map } from 'rxjs/operators';
import { tap } from 'rxjs/operators';
import { Reflector } from '@nestjs/core';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
Expand All @@ -21,7 +21,7 @@ export class CacheInterceptor implements NestInterceptor {
private cacheService: CacheService,
) {}

async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<unknown>> {
const request = context.switchToHttp().getRequest();
const handler = context.getHandler();

Expand Down Expand Up @@ -51,7 +51,7 @@ export class CacheInterceptor implements NestInterceptor {
);
}

private generateCacheKey(metadata: any, request: any): string {
private generateCacheKey(metadata: unknown, request: unknown): string {
const { key, entity, action } = metadata;

// Extract parameters from request
Expand Down
4 changes: 2 additions & 2 deletions src/cache/tests/cache.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { CacheService } from '../cache.service';

describe('CacheService', () => {
let service: CacheService;
let mockCacheManager: any;
let mockConfigService: any;
let mockCacheManager: Record<string, unknown>;
let mockConfigService: Record<string, unknown>;

beforeEach(async () => {
mockCacheManager = {
Expand Down
10 changes: 5 additions & 5 deletions src/common/decorators/api-response.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { GlobalSuccessResponse, GlobalErrorResponse } from '../../types/global-r
export function ApiSuccessResponse(
status: number,
description: string,
model?: Type<any>,
model?: Type<unknown>,
isArray = false
) {
): MethodDecorator {
const schema = model
? {
allOf: [
Expand Down Expand Up @@ -47,7 +47,7 @@ export function ApiSuccessResponse(
* @param status - HTTP status code
* @param description - Error description
*/
export function ApiErrorResponse(status: number, description: string) {
export function ApiErrorResponse(status: number, description: string): MethodDecorator {
return applyDecorators(
ApiResponse({
status,
Expand All @@ -66,8 +66,8 @@ export function ApiErrorResponse(status: number, description: string) {
export function ApiAuthResponse(
status: number,
description: string,
model: Type<any>
) {
model: Type<unknown>
): MethodDecorator {
return applyDecorators(
ApiResponse({
status,
Expand Down
4 changes: 2 additions & 2 deletions src/common/filters/http-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import logger from '../utils/logger';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
catch(exception: unknown, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest();
Expand All @@ -29,7 +29,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
if (typeof exceptionResponse === 'string') {
message = exceptionResponse;
} else if (typeof exceptionResponse === 'object' && exceptionResponse !== null) {
message = (exceptionResponse as any).message || exception.message || message;
message = (exceptionResponse as { message?: string }).message || (exception as { message?: string }).message || message;
}
} else if (exception.message) {
message = exception.message;
Comment on lines 34 to 35
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type safety issue: accessing message on unknown type.

Line 34 accesses exception.message when exception is typed as unknown and has already been checked to not be an HttpException. TypeScript will flag this as an error since unknown doesn't have a message property.

Apply this diff to fix the type safety issue:

-    } else if (exception.message) {
-      message = exception.message;
+    } else if ((exception as { message?: string }).message) {
+      message = (exception as { message?: string }).message;
     }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (exception.message) {
message = exception.message;
} else if ((exception as { message?: string }).message) {
message = (exception as { message?: string }).message;
}
πŸ€– Prompt for AI Agents
In src/common/filters/http-exception.filter.ts around lines 34-35, avoid
accessing exception.message on an unknown-typed value; narrow the type first
(e.g., check instanceof Error and use exception.message, or check typeof
exception === 'object' && exception !== null && 'message' in exception then
coerce to string) and assign message only after that safe check so TypeScript no
longer complains about accessing a property on unknown.

Expand Down
4 changes: 2 additions & 2 deletions src/common/interceptors/response.interceptor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ describe('ResponseInterceptor', () => {
locals: {},
}),
}),
} as any;
} as ExecutionContext;

// Mock CallHandler
mockCallHandler = {
handle: jest.fn(),
} as any;
} as CallHandler;
});

it('should be defined', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/common/interceptors/response.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Response } from 'express';

@Injectable()
export class ResponseInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
intercept(context: ExecutionContext, next: CallHandler): Observable<Record<string, unknown>> {
const ctx = context.switchToHttp();
const res = ctx.getResponse<Response>();
const req = ctx.getRequest();
Expand Down Expand Up @@ -40,7 +40,7 @@ export class ResponseInterceptor implements NestInterceptor {
const token = res?.locals?.token;

// Format response with global standard
const formattedResponse: any = {
const formattedResponse: Record<string, unknown> = {
success: true,
data,
};
Expand Down
2 changes: 1 addition & 1 deletion src/dtos/ProductVariantDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ export class ProductVariantDTO {
sku: string;
price: number;
stock: number;
attributes?: any[];
attributes?: Record<string, unknown>[];
}
12 changes: 6 additions & 6 deletions src/dtos/UserDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import {
import { ApiPropertyOptional } from '@nestjs/swagger';

// Custom validator to ensure role-specific data rules
function IsRoleSpecificData(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
function IsRoleSpecificData(validationOptions?: ValidationOptions): PropertyDecorator {
return function (object: Record<string, unknown>, propertyName: string): void {
registerDecorator({
name: 'isRoleSpecificData',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
const obj = args.object as any;
validate(value: unknown, args: ValidationArguments): boolean {
const obj = args.object as Record<string, unknown>;
const role = obj.role;

if (propertyName === 'buyerData') {
Expand Down Expand Up @@ -89,7 +89,7 @@ export class CreateUserDto {
@IsRoleSpecificData({ message: 'buyerData is only allowed for buyers' })
@IsObject({ message: 'Buyer data must be an object' })
@IsOptional()
buyerData?: any;
buyerData?: Record<string, unknown>;

@ApiPropertyOptional({
description: 'Seller-specific data (only allowed if role is seller)',
Expand All @@ -98,7 +98,7 @@ export class CreateUserDto {
@IsRoleSpecificData({ message: 'sellerData is only allowed for sellers' })
@IsObject({ message: 'Seller data must be an object' })
@IsOptional()
sellerData?: any;
sellerData?: Record<string, unknown>;
}

export class UpdateUserDto {
Expand Down
2 changes: 1 addition & 1 deletion src/middleware/async-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Request, Response, NextFunction, RequestHandler } from 'express';

export const asyncHandler =
(fn: (req: Request, res: Response, next: NextFunction) => Promise<any>): RequestHandler =>
(fn: (req: Request, res: Response, next: NextFunction) => Promise<unknown>): RequestHandler =>
(req, res, next) => {
fn(req, res, next).catch(next);
};
4 changes: 2 additions & 2 deletions src/middleware/async.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Request, Response, NextFunction } from 'express';

export default function asyncHandler(
fn: (req: Request, res: Response, next: NextFunction) => Promise<void>
) {
return (req: Request, res: Response, next: NextFunction) => {
): (req: Request, res: Response, next: NextFunction) => void {
return (req: Request, res: Response, next: NextFunction): void => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
4 changes: 2 additions & 2 deletions src/middleware/auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Request, Response, NextFunction } from 'express';
import { AuthenticatedRequest } from '../types/auth-request.type';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify AuthenticatedRequest interface consistency across the codebase.

Multiple AuthenticatedRequest interface definitions exist with slightly different shapes:

  • src/types/auth-request.type.ts: id: string, includes fileProvider/fileType
  • src/modules/shared/types/auth-request.type.ts: id: string | number, includes buyerData/sellerData
  • src/modules/shared/middleware/auth.middleware.ts: Similar to shared types
  • src/types/express.d.ts: Minimal user: Express.User

This duplication can lead to type inconsistencies and runtime issues when middleware and controllers expect different shapes.

Run the following script to find all AuthenticatedRequest definitions and their usage:


🏁 Script executed:

#!/bin/bash
# Find all AuthenticatedRequest interface definitions
echo "=== AuthenticatedRequest interface definitions ==="
rg -n -A 15 "interface AuthenticatedRequest"

echo -e "\n=== AuthenticatedRequest imports ==="
rg -n "import.*AuthenticatedRequest"

Length of output: 5259


Consolidate AuthenticatedRequest into a single shared definition.
Multiple AuthenticatedRequest interfaces currently exist across the codebase (in src/types/auth-request.type.ts, src/types/express.d.ts, src/modules/shared/types/auth-request.type.ts, and src/modules/shared/middleware/auth.middleware.ts), resulting in divergent shapes and import paths. Unify these into one canonical interface (for example, in src/types/auth-request.type.ts), remove the duplicate declarations, and update all imports to reference that single source.

πŸ€– Prompt for AI Agents
In src/middleware/auth.middleware.ts around line 2, the project imports an
AuthenticatedRequest type that is duplicated in multiple places; consolidate by
keeping a single canonical interface in src/types/auth-request.type.ts, delete
the other duplicate declarations (src/types/express.d.ts,
src/modules/shared/types/auth-request.type.ts,
src/modules/shared/middleware/auth.middleware.ts), export the canonical
interface from src/types/auth-request.type.ts, and update all files to import
AuthenticatedRequest from that single path; after changes, run the TypeScript
build to fix any import paths and adjust any shape differences to match the
canonical interface.

import { Role } from '../types/role';

export const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
export const authMiddleware = (req: Request, res: Response, next: NextFunction): void => {
// ImplementaciΓ³n del middleware
next();
};

export const requireRole = (roleName: Role) => {
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
return (req: AuthenticatedRequest, res: Response, next: NextFunction): void => {
if (!req.user || !req.user.role.some(role => role === roleName)) {
return res.status(403).json({ message: 'Forbidden' });
}
Expand Down
3 changes: 2 additions & 1 deletion src/middleware/paramValidation.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { param } from 'express-validator';
import { validateRequest } from '../middleware/validateRequest.middleware';
import { Request, Response, NextFunction } from 'express';

export const paramValidators = {
isPositiveInt: param('id').isInt({ min: 1 }).toInt(),
// Agrega mΓ‘s validadores segΓΊn sea necesario
};

export const paramValidationMiddleware = (validators: Record<string, any>) => {
export const paramValidationMiddleware = (validators: Record<string, unknown>): ((req: Request, res: Response, next: NextFunction) => Promise<void>) => {
return validateRequest(Object.values(validators));
};
Comment on lines +10 to 12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify validators typing is compatible with express-validator.

The validators parameter is typed as Record<string, unknown>, but express-validator returns ValidationChain instances (e.g., from param().isInt()). The loose unknown typing may allow non-validator objects to be passed, leading to runtime errors when validateRequest tries to call .run(req) on them.

Consider constraining the type to Record<string, ValidationChain> or a similar express-validator-compatible interface.


🏁 Script executed:

#!/bin/bash
# Description: Check if ValidationChain type is imported or used elsewhere

rg -nP --type=ts 'ValidationChain|express-validator' -g '!node_modules' -g '**/middleware/*.ts' -A2 -B2

Length of output: 754


🏁 Script executed:

#!/bin/bash
sed -n '1,200p' src/middleware/validateRequest.middleware.ts

Length of output: 574


Constrain validators to ValidationChain
Change the signature in src/middleware/paramValidation.middleware.ts from

export const paramValidationMiddleware = (validators: Record<string, unknown>) => …

to

import { ValidationChain } from 'express-validator';

export const paramValidationMiddleware = (validators: Record<string, ValidationChain>) => …

and update validateRequest to accept ValidationChain[] instead of unknown[] so only valid express-validator chains are passed.

πŸ€– Prompt for AI Agents
In src/middleware/paramValidation.middleware.ts around lines 10 to 12, the
validators parameter is typed too loosely as Record<string, unknown>; import
ValidationChain from 'express-validator' and change the signature to accept
Record<string, ValidationChain>, then update validateRequest’s signature to
accept ValidationChain[] (instead of unknown[]) so Object.values(validators) is
a ValidationChain[]; ensure TypeScript types are updated where validateRequest
is declared/used to reflect the new ValidationChain[] parameter.

2 changes: 1 addition & 1 deletion src/middleware/userValidation.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Request, Response, NextFunction } from 'express';
* A validation middleware for validating request body data against a DTO class.
* @param dtoClass The DTO class to validate against.
*/
export function validationMiddleware(dtoClass: any) {
export function validationMiddleware(dtoClass: new (...args: unknown[]) => unknown): (req: Request, res: Response, next: NextFunction) => Promise<void> {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const dtoInstance = plainToInstance(dtoClass, req.body);
const errors: ValidationError[] = await validate(dtoInstance);
Expand Down
4 changes: 2 additions & 2 deletions src/middleware/validateRequest.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Request, Response, NextFunction } from 'express';
import { validationResult } from 'express-validator';

export const validateRequest = (validations: any[]) => {
return async (req: Request, res: Response, next: NextFunction) => {
export const validateRequest = (validations: unknown[]): ((req: Request, res: Response, next: NextFunction) => Promise<void>) => {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await Promise.all(validations.map((validation) => validation.run(req)));
Comment on lines +4 to 6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type safety issue: calling method on unknown type.

The validations parameter is typed as unknown[], but line 6 calls .run(req) on each element. TypeScript will error because unknown doesn't have a run method. These appear to be express-validator ValidationChain objects.

Apply this diff to fix the type safety issue:

+import { ValidationChain } from 'express-validator';
 import { Request, Response, NextFunction } from 'express';
 import { validationResult } from 'express-validator';
 
-export const validateRequest = (validations: unknown[]): ((req: Request, res: Response, next: NextFunction) => Promise<void>) => {
+export const validateRequest = (validations: ValidationChain[]): ((req: Request, res: Response, next: NextFunction) => Promise<void>) => {
   return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
     await Promise.all(validations.map((validation) => validation.run(req)));
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const validateRequest = (validations: unknown[]): ((req: Request, res: Response, next: NextFunction) => Promise<void>) => {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await Promise.all(validations.map((validation) => validation.run(req)));
import { ValidationChain } from 'express-validator';
import { Request, Response, NextFunction } from 'express';
import { validationResult } from 'express-validator';
export const validateRequest = (validations: ValidationChain[]): (req: Request, res: Response, next: NextFunction) => Promise<void> => {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await Promise.all(validations.map((validation) => validation.run(req)));
// ...
πŸ€– Prompt for AI Agents
In src/middleware/validateRequest.middleware.ts around lines 4 to 6, the
validations parameter is typed as unknown[] but the code calls
validation.run(req) on each element; change the parameter type to
ValidationChain[] from express-validator (add the import: import {
ValidationChain } from 'express-validator'), update the function signature to
accept validations: ValidationChain[], and keep the
Promise.all(validations.map(validation => validation.run(req))); this ensures
type safety and resolves the TypeScript error.


const errors = validationResult(req);
Expand Down
Loading