"use client"; // Media (attachment) helpers over the be-crm data door (crm.media.*). The browser transfers bytes // DIRECTLY to IIOS storage via the signed URLs — be-crm only mints them. Used by Messenger + Mail. import { useCallback } from "react"; import { useAppShell } from "@abe-kap/appshell-sdk/react"; export interface UploadedAttachment { contentRef: string; mimeType: string; sizeBytes: number; filename: string } export const MAX_ATTACHMENT_BYTES = 26 * 1024 * 1024; // matches IIOS's cap export function isImage(mime?: string | null): boolean { return !!mime && mime.startsWith("image/"); } // Some types (notably .md) have no OS-registered MIME, so the browser reports an empty file.type. // Fall back to the extension for the text types IIOS allows, else a generic binary. const EXT_MIME: Record = { md: "text/markdown", markdown: "text/markdown", html: "text/html", htm: "text/html", txt: "text/plain", csv: "text/csv", }; function mimeForFile(file: File): string { if (file.type) return file.type; const ext = file.name.toLowerCase().split(".").pop() ?? ""; return EXT_MIME[ext] ?? "application/octet-stream"; } /** Upload a File → { contentRef, mimeType, sizeBytes, filename }. Throws on oversize / failure. */ export function useUploadAttachment() { const { sdk } = useAppShell(); return useCallback(async (file: File): Promise => { if (file.size > MAX_ATTACHMENT_BYTES) throw new Error("File is too large (max 25 MB)."); const mime = mimeForFile(file); const { objectKey, uploadUrl } = (await sdk.command("crm.media.presignUpload", { mime, sizeBytes: file.size })) as { objectKey: string; uploadUrl: string }; const res = await fetch(uploadUrl, { method: "PUT", body: file }); if (!res.ok) throw new Error(`Upload failed (${res.status}).`); return { contentRef: objectKey, mimeType: mime, sizeBytes: file.size, filename: file.name }; }, [sdk]); } /** Mint a short-lived signed URL to display/download an attachment by its contentRef. */ export function useDownloadUrl() { const { sdk } = useAppShell(); return useCallback(async (contentRef: string, mime?: string): Promise => { const { url } = (await sdk.command("crm.media.presignDownload", { contentRef, ...(mime ? { mime } : {}) })) as { url: string }; return url; }, [sdk]); }