I had this in my new heat project but wasnt using it anymore and didnt want to just delete it or keep it in the codebase as a comment, so a gist it is.
export async function fetchWithProgress(
url: string,
onProgress?: (progress: number) => void
) {
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not ok");
}
const contentLength = response.headers.get("Content-Length");
if (!contentLength) {
throw new Error("Content-Length response header is missing");
}
const total = parseInt(contentLength, 10);
let loaded = 0;
if (!response.body) {
throw new Error("There is no body in this request");
}
const reader = response.body.getReader();
const stream = new ReadableStream({
start(controller) {
function push() {
reader
.read()
.then(({ done, value }) => {
if (done) {
controller.close();
return;
}
loaded += value.byteLength;
if (onProgress) onProgress((loaded / total) * 100);
controller.enqueue(value);
push();
})
.catch((error) => {
console.error("Stream reading error:", error);
controller.error(error);
});
}
push();
},
});
const newResponse = new Response(stream);
const data = await newResponse.json();
return data;
}