interface BlobWritable { getWriter: () => { abort: () => Promise; close: () => Promise; closed: Promise; desiredSize: number | null; ready: Promise; releaseLock: () => void; write: (chunk: Uint8Array) => Promise; }; locked: boolean; abort: () => Promise; close: () => Promise; } function getBlobWritable(filename: string, onClose: (result: Blob) => void): BlobWritable { let blobParts: Uint8Array[] = []; return { getWriter: () => { return { abort: async () => { blobParts = []; }, close: async () => { onClose(new File(blobParts, filename)); }, closed: Promise.resolve(undefined), desiredSize: 3 * 1024 * 1024, ready: Promise.resolve(undefined), releaseLock: () => { // no op }, write: async (chunk) => { blobParts.push(chunk); }, }; }, locked: false, abort: async () => { blobParts = []; }, close: async () => { onClose(new File(blobParts, filename)); }, }; } async function pipe(readable: ReadableStream, writable: BlobWritable): Promise { const reader = readable.getReader(); const writer = writable.getWriter(); let done = false; while (!done) { const status = await reader.read(); if (!status.done) { await writer.write(status.value); } done = status.done; } await reader.closed; await writer.close(); } // (source.pipeTo && source.pipeTo(destination, { signal: abortController?.signal })) || pipe(source, destination)