type EventMap = { "finished": number; "progress": number; }; export class ProgressReadable extends EventTarget { readable: ReadableStream; readed: number; error?: unknown; constructor(readable: ReadableStream) { super(); this.readed = 0; const reader = readable.getReader(); this.readable = new ReadableStream({ pull: (c) => { if (c.byobRequest) { throw Error("Unimplemented."); } else { reader.read().then((v) => { if (v.done) { this.dispatchEvent("finished", this.readed); c.close(); return; } else { this.readed += v.value.byteLength; this.dispatchEvent("progress", this.readed); c.enqueue(v.value); } }).catch((e) => { c.close(); this.error = e; }); } }, cancel: (reason) => { try { readable.cancel(reason); } catch (_) { null; } }, type: "bytes", }); } // @ts-ignore Checked type addEventListener( type: T, callback: (e: CustomEvent) => void | Promise, options?: boolean | AddEventListenerOptions, ): void { super.addEventListener(type, callback, options); } // @ts-ignore Checked type dispatchEvent(type: T, detail: EventMap[T]) { return super.dispatchEvent(new CustomEvent(type, { detail })); } // @ts-ignore Checked type removeEventListener( type: T, callback: (e: CustomEvent) => void | Promise, options?: boolean | EventListenerOptions, ): void { super.removeEventListener( type, callback, options, ); } }