import { ArrayMaxSize, IsArray, IsBoolean, IsOptional, IsString, MaxLength, ValidateNested, } from 'class-validator'; import { Type } from 'class-transformer'; // Guild C-2: the slash-command catalog is guild-global and rendered by the // frontend `/` autocomplete. Without a strict schema + caps a single // authenticated caller could poison it or blow up the DB / clients. // The global ValidationPipe runs with { whitelist, forbidNonWhitelisted }, // so any unknown field is rejected. class CommandChoiceDto { @IsString() @MaxLength(200) value!: string; @IsString() @MaxLength(200) label!: string; } class CommandArgDto { @IsString() @MaxLength(100) name!: string; @IsOptional() @IsString() @MaxLength(500) description?: string; @IsOptional() @IsString() @MaxLength(40) type?: string; @IsOptional() @IsBoolean() required?: boolean; @IsOptional() @IsBoolean() captureRemaining?: boolean; @IsOptional() @IsBoolean() preferAutocomplete?: boolean; // null when there are no choices (plugin sends explicit null). @IsOptional() @IsArray() @ArrayMaxSize(100) @ValidateNested({ each: true }) @Type(() => CommandChoiceDto) choices?: CommandChoiceDto[] | null; } class CommandSpecDto { @IsString() @MaxLength(100) name!: string; @IsOptional() @IsString() @MaxLength(100) nativeName?: string; @IsOptional() @IsString() @MaxLength(500) description?: string; @IsOptional() @IsBoolean() acceptsArgs?: boolean; @IsOptional() @IsArray() @ArrayMaxSize(50) @ValidateNested({ each: true }) @Type(() => CommandArgDto) args?: CommandArgDto[]; @IsOptional() @IsString() @MaxLength(20) argsParsing?: string; } export class SyncCommandsDto { @IsArray() @ArrayMaxSize(200) @ValidateNested({ each: true }) @Type(() => CommandSpecDto) commands!: CommandSpecDto[]; }