import { IsArray, IsEnum, IsNotEmpty, IsObject, IsString, Validate, ValidatorConstraint, type ValidationArguments, type ValidatorConstraintInterface } from 'class-validator'; import { ShopFiatCurrency } from '../../../types/ShopFiatCurrency'; @ValidatorConstraint({ name: 'coingeckoResponse' }) class CoingeckoResponseConstraint implements ValidatorConstraintInterface { validate(response: Record, args: ValidationArguments): boolean { const { shopFiatCurrency, coinIds } = args.object as CoingeckoSimplePriceResponseDto; if (!shopFiatCurrency || coinIds.length === 0) { return false; } const fiatKey = shopFiatCurrency.toLowerCase(); return coinIds.every(coinId => { const coin = response[coinId]; if (typeof coin !== 'object' || coin === null) { return false; } const rate = coin[fiatKey]; return typeof rate === 'number' && Number.isFinite(rate) && rate > 0; }); } defaultMessage(): string { return 'CoinGecko coin fiat rate must be a positive number'; } } export class CoingeckoSimplePriceResponseDto { @IsEnum(ShopFiatCurrency) shopFiatCurrency: ShopFiatCurrency; @IsArray() @IsString({ each: true }) coinIds: string[]; @IsNotEmpty() @IsObject() @Validate(CoingeckoResponseConstraint) response: Record>; }