From b2c85f57855a8e03f8b2c310735afc8e4b299713 Mon Sep 17 00:00:00 2001 From: Markus Wolf Date: Thu, 3 Jul 2025 11:40:20 +0000 Subject: [PATCH] fix: return promise from stream.cancel() The promise returned from stream.cancel() was ignored so far. This lead to unhandled promises when the stream throws during the cancel operation. In turn the whole hono node-server was shutdown. Close #248 --- src/utils.ts | 3 +-- test/utils.test.ts | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index c704c93..1eff410 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,8 +5,7 @@ export function writeFromReadableStream(stream: ReadableStream, writ if (stream.locked) { throw new TypeError('ReadableStream is locked.') } else if (writable.destroyed) { - stream.cancel() - return + return stream.cancel() } const reader = stream.getReader() writable.on('close', cancel) diff --git a/test/utils.test.ts b/test/utils.test.ts index 3673c5f..2ba960c 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,4 +1,6 @@ -import { buildOutgoingHttpHeaders } from '../src/utils' +import { console } from 'node:inspector/promises' +import { Writable } from 'node:stream' +import { buildOutgoingHttpHeaders, writeFromReadableStream } from '../src/utils' describe('buildOutgoingHttpHeaders', () => { it('original content-type is preserved', () => { @@ -71,3 +73,18 @@ describe('buildOutgoingHttpHeaders', () => { }) }) }) + +describe('writeFromReadableStream', () => { + it('does handle rejections from canceled streams', async () => { + const stream = new ReadableStream({ + async cancel() { + throw new Error('Aborted') + }, + }) + + const destroyedWritable = new Writable() + destroyedWritable.destroy() + + await expect(writeFromReadableStream(stream, destroyedWritable)).rejects.toThrow('Aborted') + }) +})