fix: emit final 100% download progress for empty response body

onDownloadProgress never fired a completion event when the response
body was empty (e.g. a 200 with Content-Length: 0), since the final
callback in the transform stream's flush() was gated behind a chunk
having been read. Report the final progress unconditionally, falling
back to an empty chunk when the stream produced none.

Closes #878
This commit is contained in:
dualfroz committed 2026-08-27 23:35:07 +02:00
1 parent ee0d0d0437
commit 1cf8f269f3
2 files changed
+23 -1

No files matched your search

+3 -1
View File
@@ -70,8 +70,10 @@ const withProgress = (stream: ReadableStream<Uint8Array>, totalBytes: number, on
flush() { flush() {
if (previousChunk) { if (previousChunk) {
transferredBytes += previousChunk.byteLength; transferredBytes += previousChunk.byteLength;
onProgress?.({percent: 1, totalBytes: Math.max(totalBytes, transferredBytes), transferredBytes}, previousChunk);
} }
// Always report completion, even for an empty stream, so consumers can rely on a final 100% event.
onProgress?.({percent: 1, totalBytes: Math.max(totalBytes, transferredBytes), transferredBytes}, previousChunk ?? new Uint8Array());
}, },
})); }));
}; };
+20
View File
@@ -555,6 +555,26 @@ test('onDownloadProgress cancels original response body', async t => {
t.true(didReportProgress); t.true(didReportProgress);
}); });
test('onDownloadProgress emits final 100% progress for empty response body', async t => {
const server = await createHttpTestServer(t);
server.get('/', (_request, response) => {
response.status(200).end();
});
const progressEvents: Progress[] = [];
await ky(server.url, {
onDownloadProgress(progress) {
progressEvents.push(progress);
},
}).text();
t.true(progressEvents.length > 0, 'Should emit at least one progress event');
const finalProgress = progressEvents.at(-1);
t.truthy(finalProgress);
t.is(finalProgress!.percent, 1);
t.is(finalProgress!.transferredBytes, finalProgress!.totalBytes);
});
test('forced retry custom request keeps upload progress', async t => { test('forced retry custom request keeps upload progress', async t => {
const server = await createHttpTestServer(t, {bodyParser: false}); const server = await createHttpTestServer(t, {bodyParser: false});
let requestCount = 0; let requestCount = 0;