import { Type } from 'class-transformer'; import { IsArray, IsISO8601, IsObject, IsOptional, IsString, ValidateNested, } from 'class-validator'; class ScopeDto { @IsString() orgId!: string; @IsString() appId!: string; @IsOptional() @IsString() buId?: string; @IsOptional() @IsString() tenantId?: string; @IsOptional() @IsString() workspaceId?: string; @IsOptional() @IsString() projectId?: string; @IsOptional() @IsString() userScopeId?: string; } class ChannelDto { @IsString() type!: string; @IsOptional() @IsString() externalChannelId?: string; @IsOptional() @IsObject() capabilityContract?: Record; } class SourceDto { @IsString() handleKind!: string; @IsString() externalId!: string; @IsOptional() @IsString() displayName?: string; } class ThreadDto { @IsOptional() @IsString() externalThreadId?: string; @IsOptional() @IsString() subject?: string; } class PartDto { @IsString() kind!: string; @IsOptional() @IsString() bodyText?: string; @IsOptional() @IsString() contentRef?: string; @IsOptional() @IsString() mimeType?: string; } /** Validates the POST /v1/interactions/ingest body (conforms to IngestInteractionRequest). */ export class IngestRequestDto { @ValidateNested() @Type(() => ScopeDto) scope!: ScopeDto; @ValidateNested() @Type(() => ChannelDto) channel!: ChannelDto; @ValidateNested() @Type(() => SourceDto) source!: SourceDto; @IsOptional() @IsString() kind?: string; @IsOptional() @ValidateNested() @Type(() => ThreadDto) thread?: ThreadDto; @IsArray() @ValidateNested({ each: true }) @Type(() => PartDto) parts!: PartDto[]; @IsISO8601() occurredAt!: string; @IsOptional() @IsString() providerEventId?: string; @IsOptional() @IsObject() metadata?: Record; }