import type { ColineFileUploadInput, ColineUploadData } from "./types"; /** * Upload encoding shared by every transport. Bytes cross JSON transports * as base64; the sandbox bridge sends an ArrayBuffer and the host encodes * it. The server re-checks size and sniffs the type independently. */ export const MAX_INLINE_UPLOAD_BYTES = 25 * 1024 * 1024; export interface EncodedUpload { name: string; mimeType: string | null; base64: string; size: number; driveId?: string; parentId?: string | null; } export async function uploadDataToBytes(data: ColineUploadData): Promise { if (data instanceof Uint8Array) return data; if (data instanceof ArrayBuffer) return new Uint8Array(data); if (typeof Blob !== "undefined" && data instanceof Blob) { return new Uint8Array(await data.arrayBuffer()); } if (typeof data === "object" && data !== null && "base64" in data) { return base64ToBytes(data.base64); } throw new TypeError("files.upload expects Uint8Array, ArrayBuffer, Blob, or { base64 }."); } export function bytesToBase64(bytes: Uint8Array): string { let binary = ""; const chunk = 0x8000; for (let index = 0; index < bytes.length; index += chunk) { binary += String.fromCharCode(...bytes.subarray(index, index + chunk)); } return btoa(binary); } export function base64ToBytes(value: string): Uint8Array { const binary = atob(value); const bytes = new Uint8Array(binary.length); for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index); return bytes; } export async function encodeUpload(input: ColineFileUploadInput): Promise { const bytes = await uploadDataToBytes(input.data); if (bytes.byteLength > MAX_INLINE_UPLOAD_BYTES) { throw Object.assign( new Error("files.upload accepts up to 25 MB. Use files.createUpload for larger files."), { code: "upload_too_large" }, ); } const blobType = typeof Blob !== "undefined" && input.data instanceof Blob ? input.data.type || null : null; return { name: input.name, mimeType: input.mimeType ?? blobType, base64: bytesToBase64(bytes), size: bytes.byteLength, ...(input.driveId ? { driveId: input.driveId } : {}), ...(input.parentId !== undefined ? { parentId: input.parentId } : {}), }; }