From d4202403d17549a0ec567dd023dc62633a518957 Mon Sep 17 00:00:00 2001 From: eli lichtblau Date: Thu, 20 Mar 2025 22:49:25 -0400 Subject: [PATCH 1/2] Fix generators --- src/handler.ts | 46 +++++++++++++++++++--------------------------- src/index.ts | 2 +- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index ad09577..c3824bf 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -140,38 +140,26 @@ const handleStream = ( set?: Context['set'], res?: HttpResponse ): ElysiaNodeResponse => { - if (!set) - set = { - status: 200, - headers: { - 'transfer-encoding': 'chunked', - 'content-type': 'text/event-stream;charset=utf8' - } - } - else { - set.headers['transfer-encoding'] = 'chunked' - set.headers['content-type'] = 'text/event-stream;charset=utf8' - } - - if (res) res.writeHead(set.status as number, set.headers) - - return [handleStreamResponse(generator, set, res), set as any] -} - -export const handleStreamResponse = ( - generator: Generator | AsyncGenerator, - set?: Context['set'], - res?: HttpResponse -) => { const readable = new Readable({ read() {} }) - - if (res) readable.pipe(res) ;(async () => { let init = generator.next() if (init instanceof Promise) init = await init - + if (!set) + set = { + status: 200, + headers: { + 'transfer-encoding': 'chunked', + 'content-type': 'text/event-stream;charset=utf8' + } + } + else { + set.headers['transfer-encoding'] = 'chunked' + set.headers['content-type'] = 'text/event-stream;charset=utf8' + } + + if (res) res.writeHead(set.status as number, set.headers) if (init.done) { if (set) return mapResponse(init.value, set, res) return mapCompactResponse(init.value, res) @@ -216,9 +204,13 @@ export const handleStreamResponse = ( readable.push(null) })() - return readable + return [readable, set as any] + + } + + export async function* streamResponse(response: Response) { const body = response.body diff --git a/src/index.ts b/src/index.ts index b170610..e04d576 100644 --- a/src/index.ts +++ b/src/index.ts @@ -410,7 +410,7 @@ export const node = () => { // @ts-expect-error private property app._handle ).listen( - typeof options === 'number' + typeof options === 'number' || typeof options === "string" ? options : { ...options, From 48b4c7a24fd5f9705caf47d3ee21a685691595cc Mon Sep 17 00:00:00 2001 From: eli lichtblau Date: Thu, 20 Mar 2025 23:32:56 -0400 Subject: [PATCH 2/2] fix --- src/handler.ts | 7 +++- test/core/generators.test.ts | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/core/generators.test.ts diff --git a/src/handler.ts b/src/handler.ts index c3824bf..a1fc2b7 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -143,6 +143,9 @@ const handleStream = ( const readable = new Readable({ read() {} }) + if (res) { + readable.pipe(res) + } ;(async () => { let init = generator.next() if (init instanceof Promise) init = await init @@ -156,7 +159,9 @@ const handleStream = ( } else { set.headers['transfer-encoding'] = 'chunked' - set.headers['content-type'] = 'text/event-stream;charset=utf8' + if (!set.headers['content-type']) { + set.headers['content-type'] = 'text/event-stream;charset=utf8' + } } if (res) res.writeHead(set.status as number, set.headers) diff --git a/test/core/generators.test.ts b/test/core/generators.test.ts new file mode 100644 index 0000000..330b486 --- /dev/null +++ b/test/core/generators.test.ts @@ -0,0 +1,65 @@ +import Elysia from 'elysia' +import { inject } from 'light-my-request' +import { describe, it, expect } from 'vitest' + +import node from '../../src' + +function delay(n: number) { + return new Promise((resolve)=>{ + setTimeout(()=>{ + resolve(null) + }, n) + }) +} + +const app = new Elysia({ adapter: node() }) + .get("/what", ()=>"feafe") + .get('/', function* gen({set}) { + set.headers["content-type"] = "application/json" + set.headers["content-disposition"] = 'attachment; filename="test.json"' + yield JSON.stringify({x: "hi"}) + }) + .get('/async-simple', async function* gen({set}) { + set.headers["content-type"] = "application/json" + set.headers["content-disposition"] = 'attachment; filename="test.json"' + await delay(100) + yield JSON.stringify({x: "hi"}) + }) + .get('/async-hard', async function* gen({set}) { + await delay(100) + set.headers["content-type"] = "application/json" + set.headers["content-disposition"] = 'attachment; filename="test.json"' + await delay(100) + yield JSON.stringify({x: "hi"}) + }) + .compile() + + +// @ts-expect-error +const handle = app._handle! + +describe("Async generators", ()=>{ + + it("handle /", async ()=>{ + await inject(handle, { path: "/"}, (error, res)=>{ + console.log(res) + expect(res?.headers["content-type"]).toBe("application/json") + expect(res?.headers["content-disposition"]).toBe('attachment; filename="test.json"') + }) + }) + + it("handle /async-simple", async ()=>{ + await inject(handle, { path: "/async-simple"}, (error, res)=>{ + expect(true).toBe(false) + expect(res?.headers["content-type"]).toBe("application/json") + expect(res?.headers["content-disposition"]).toBe('attachment; filename="test.json"') + }) + }) + + it("handle /async-hard", async ()=>{ + await inject(handle, { path: "/async-hard"}, (error, res)=>{ + expect(res?.headers["content-type"]).toBe("application/json") + expect(res?.headers["content-disposition"]).toBe('attachment; filename="test.json"') + }) + }) +})