/** * Gzip compression/decompression utilities for D1 BLOB storage. * Uses Web Standard CompressionStream/DecompressionStream (native in CF Workers). */ import { RawMailRow } from "./models"; export async function compressText(text: string): Promise { const stream = new Blob([text]).stream().pipeThrough(new CompressionStream('gzip')); return new Response(stream).arrayBuffer(); } export async function decompressBlob(buffer: ArrayBuffer): Promise { const stream = new Blob([buffer]).stream().pipeThrough(new DecompressionStream('gzip')); return new Response(stream).text(); } /** * Resolve the raw email text from either raw_blob (gzip) or raw (plaintext) field. */ export async function resolveRawEmail(row: RawMailRow): Promise { if (row.raw_blob) { try { // D1 returns BLOB as Array, convert to ArrayBuffer for decompression return await decompressBlob(new Uint8Array(row.raw_blob as ArrayLike).buffer); } catch (e) { console.error("decompressBlob failed, fallback to raw field", e); return row.raw ?? ''; } } return row.raw ?? ''; } /** * Resolve a single row: decompress raw_blob if present, strip raw_blob from result. */ export async function resolveRawEmailRow(row: RawMailRow): Promise { const raw = await resolveRawEmail(row); const { raw_blob: _, ...rest } = row; return { ...rest, raw }; } /** * Batch resolve raw emails for list queries using Promise.all. */ export async function resolveRawEmailList(rows: RawMailRow[]): Promise { return Promise.all(rows.map(row => resolveRawEmailRow(row))); }