Files
iios/packages/iios-service/src/interactions/ingest.dto.ts
T
maaz519 b164ef945c feat(mail): in-app attachments on internal mail + surface media parts in thread reads
- MailInternalDto accepts attachments[]; deposit() stores each as a media
  part (image/video→MEDIA_REF, audio→VOICE_REF, else FILE_REF)
- ingest now persists part sizeBytes; contract + DTO carry it
- threads.getMessages returns mimeType + sizeBytes so mail readers can
  render inline images / file chips
- test: internal mail stores an image attachment as a MEDIA_REF part

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 17:24:49 +05:30

59 lines
1.8 KiB
TypeScript

import { Type } from 'class-transformer';
import {
IsArray,
IsInt,
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<string, unknown>;
}
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;
@IsOptional() @IsInt() sizeBytes?: number;
}
/** 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<string, unknown>;
}