export const streamChunk = function* (chunk, chunkSize) { let len = chunk.byteLength; if (!chunkSize || len < chunkSize) { yield chunk; return; } let pos = 0; let end; while (pos < len) { end = pos + chunkSize; yield chunk.slice(pos, end); pos = end; } } export const readBytes = async function* (iterable, chunkSize, encode) { for await (const chunk of iterable) { yield* streamChunk(ArrayBuffer.isView(chunk) ? chunk : (await encode(String(chunk))), chunkSize); } } export const trackStream = (stream, chunkSize, onProgress, onFinish, encode) => { const iterator = readBytes(stream, chunkSize, encode); let bytes = 0; return new ReadableStream({ type: 'bytes', async pull(controller) { const {done, value} = await iterator.next(); if (done) { controller.close(); onFinish(); return; } let len = value.byteLength; onProgress && onProgress(bytes += len); controller.enqueue(new Uint8Array(value)); }, cancel(reason) { onFinish(reason); return iterator.return(); } }, { highWaterMark: 2 }) }