/** * Generic browser-side download helpers. * * - `downloadTextFile` for plain-text payloads (X12, JSON, CSV, ...). * Mirrors `downloadCsv` in `./csv.ts` but takes an explicit MIME type * so the same code path can serve any text format without growing a * one-off helper per format. * * - `downloadBlob` for binary payloads (the resubmit ZIP, future PDF * exports, etc.) where the caller already has a `Blob` and just needs * it handed to the browser. * * Both implementations skip the BOM prepend that `downloadCsv` uses (we * want byte-faithful X12 and ZIP — a BOM would corrupt the ISA segment * and confuse ZIP readers respectively). * * Safe to call from SSR/Node — guards against a missing `document`. */ export function downloadTextFile( filename: string, mimeType: string, text: string, ): void { downloadBlob(filename, new Blob([text], { type: `${mimeType};charset=utf-8` })); } export function downloadBlob(filename: string, blob: Blob): void { if (typeof document === "undefined" || typeof URL === "undefined") return; const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; // Some browsers require the link to be in the DOM before .click() works. a.style.display = "none"; document.body.appendChild(a); a.click(); document.body.removeChild(a); // Defer revoke so the browser has the URL handle when the download kicks off. queueMicrotask(() => URL.revokeObjectURL(url)); }