From 8f9c1b40b8464f6e2b16ad405f635b072fd8ce6b Mon Sep 17 00:00:00 2001 From: fhgffy <102001626+fhgffy@users.noreply.github.com> Date: Mon, 5 Oct 2026 23:33:28 +0800 Subject: [PATCH] fix(fetch): keep draining SSE data after ping comments --- packages/fetch/src/stream.test.ts | 45 +++++++++++++++++++++++++++++++ packages/fetch/src/stream.ts | 3 --- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/fetch/src/stream.test.ts b/packages/fetch/src/stream.test.ts index 084002ac54a..87610ad0a36 100644 --- a/packages/fetch/src/stream.test.ts +++ b/packages/fetch/src/stream.test.ts @@ -54,6 +54,51 @@ describe("streamSse", () => { expect(results).toEqual([{ foo: "bar" }, { baz: 42 }]); }); + it.each([ + { + name: "a leading ping", + chunks: [': ping\n\ndata: {"foo":"bar"}\n\ndata: {"baz":42}\n\n'], + }, + { + name: "an interleaved ping", + chunks: ['data: {"foo":"bar"}\n\n: ping\n\ndata: {"baz":42}\n\n'], + }, + { + name: "a ping split across chunks", + chunks: [": pi", 'ng\n\ndata: {"foo":"bar"}\n\ndata: {"baz":42}\n\n'], + }, + { + name: "consecutive pings", + chunks: [ + ': ping\n\n: ping\n\ndata: {"foo":"bar"}\n\ndata: {"baz":42}\n\n', + ], + }, + { + name: "a trailing ping", + chunks: ['data: {"foo":"bar"}\n\ndata: {"baz":42}\n\n: ping\n\n'], + }, + { + name: "another comment", + chunks: [': heartbeat\n\ndata: {"foo":"bar"}\n\ndata: {"baz":42}\n\n'], + }, + ])("keeps draining data after $name", async ({ chunks }) => { + const body = new ReadableStream({ + start(controller) { + const encoder = new TextEncoder(); + for (const chunk of chunks) { + controller.enqueue(encoder.encode(chunk)); + } + controller.close(); + }, + }); + const results = []; + for await (const data of streamSse(new Response(body))) { + results.push(data); + } + + expect(results).toEqual([{ foo: "bar" }, { baz: 42 }]); + }); + it("throws on malformed JSON", async () => { const sseLines = ['data: {"foo": "bar"', "data:[DONE]"]; const response = createMockResponse(sseLines); diff --git a/packages/fetch/src/stream.ts b/packages/fetch/src/stream.ts index f73d61dbafc..71fd824e984 100644 --- a/packages/fetch/src/stream.ts +++ b/packages/fetch/src/stream.ts @@ -115,9 +115,6 @@ function parseSseLine(line: string): { done: boolean; data: any } { if (line.startsWith("data:")) { return { done: false, data: parseDataLine(line) }; } - if (line.startsWith(": ping")) { - return { done: true, data: undefined }; - } return { done: false, data: undefined }; }