evOo-local/packages/contracts/src/attachments.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

44 lines
1.3 KiB
TypeScript

export const ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
export const ATTACHMENT_MAX_COUNT = 4;
/** Base64 expands payload by 4/3; cap before decode to reject oversize uploads cheaply. */
export const ATTACHMENT_MAX_BASE64_LENGTH = Math.ceil(ATTACHMENT_MAX_BYTES / 3) * 4;
export const ATTACHMENT_IMAGE_MIME_TYPES = [
"image/jpeg",
"image/png",
"image/webp",
"image/gif",
] as const;
export const ATTACHMENT_FILE_MIME_TYPES = [
"application/pdf",
"text/plain",
"text/markdown",
"text/csv",
"application/json",
] as const;
export const ATTACHMENT_ALLOWED_MIME_TYPES = [
...ATTACHMENT_IMAGE_MIME_TYPES,
...ATTACHMENT_FILE_MIME_TYPES,
] as const;
export type AttachmentMimeType = (typeof ATTACHMENT_ALLOWED_MIME_TYPES)[number];
export function isAttachmentImageMimeType(mimeType: string): boolean {
return (ATTACHMENT_IMAGE_MIME_TYPES as readonly string[]).includes(mimeType);
}
export function isAllowedAttachmentMimeType(mimeType: string): mimeType is AttachmentMimeType {
return (ATTACHMENT_ALLOWED_MIME_TYPES as readonly string[]).includes(mimeType);
}
export function validateThreadsSendInput(input: {
text?: string;
artifactIds?: string[];
}): boolean {
const text = input.text?.trim() ?? "";
const artifactIds = input.artifactIds ?? [];
return Boolean(text || artifactIds.length);
}