diff --git a/CHANGELOG.md b/CHANGELOG.md index 1188bdd7..3dee3c41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.4.28 - 3 Mar 2026 +Bug fix: +- conditional set headers of String and Object when no set.headers is set + # 1.4.27 - 1 Mar 2026 Bug fix: - getSchemaValidator: handle TypeBox as sub type diff --git a/example/a.ts b/example/a.ts index 07958600..5bddd460 100644 --- a/example/a.ts +++ b/example/a.ts @@ -1,3 +1,22 @@ import { Elysia } from '../src' +import { mapEarlyResponse } from '../src/adapter/web-standard/handler' -new Elysia().get('/', 'Hi').listen(3000) +const body = { + name: 'Shiroko' +} + +const context = { + headers: { + 'x-powered-by': 'Elysia', + 'coffee-scheme': 'Coffee' + }, + status: 418, + cookie: {} +} + +const response = await mapEarlyResponse( + new Promise((resolve) => resolve(body)), + context +) + +console.log(response?.headers) diff --git a/src/adapter/web-standard/handler.ts b/src/adapter/web-standard/handler.ts index a679eb34..9dc90ed3 100644 --- a/src/adapter/web-standard/handler.ts +++ b/src/adapter/web-standard/handler.ts @@ -58,12 +58,16 @@ export const mapResponse = ( switch (response?.constructor?.name) { case 'String': - set.headers['content-type'] = 'text/plain' + if (!set.headers['content-type']) + set.headers['content-type'] = 'text/plain' + return new Response(response as string, set as any) case 'Array': case 'Object': - set.headers['content-type'] = 'application/json' + if (!set.headers['content-type']) + set.headers['content-type'] = 'application/json' + return new Response(JSON.stringify(response), set as any) case 'ElysiaFile': @@ -208,12 +212,16 @@ export const mapEarlyResponse = ( switch (response?.constructor?.name) { case 'String': - set.headers['content-type'] = 'text/plain' + if (!set.headers['content-type']) + set.headers['content-type'] = 'text/plain' + return new Response(response as string, set as any) case 'Array': case 'Object': - set.headers['content-type'] = 'application/json' + if (!set.headers['content-type']) + set.headers['content-type'] = 'application/json' + return new Response(JSON.stringify(response), set as any) case 'ElysiaFile': @@ -335,12 +343,16 @@ export const mapEarlyResponse = ( } else switch (response?.constructor?.name) { case 'String': - set.headers['content-type'] = 'text/plain' + if (!set.headers['content-type']) + set.headers['content-type'] = 'text/plain' + return new Response(response as string) case 'Array': case 'Object': - set.headers['content-type'] = 'application/json' + if (!set.headers['content-type']) + set.headers['content-type'] = 'application/json' + return new Response(JSON.stringify(response), set as any) case 'ElysiaFile': diff --git a/test/adapter/web-standard/map-early-response.test.ts b/test/adapter/web-standard/map-early-response.test.ts index 527a9cc5..ae99c826 100644 --- a/test/adapter/web-standard/map-early-response.test.ts +++ b/test/adapter/web-standard/map-early-response.test.ts @@ -10,14 +10,14 @@ const defaultContext = { cookie: {} } -const context = { +const createContext = () => ({ headers: { 'x-powered-by': 'Elysia', 'coffee-scheme': 'Coffee' }, status: 418, cookie: {} -} +}) class Student { constructor(public name: string) {} @@ -160,6 +160,7 @@ describe('Web Standard - Map Early Response', () => { }) it('map primitive with custom context', async () => { + const context = createContext() const response = mapEarlyResponse('Shiroko', context) expect(response).toBeInstanceOf(Response) @@ -169,6 +170,7 @@ describe('Web Standard - Map Early Response', () => { }) it('map Function with custom context', async () => { + const context = createContext() const response = await mapEarlyResponse(() => 1, context) expect(response).toBeInstanceOf(Response) @@ -180,6 +182,8 @@ describe('Web Standard - Map Early Response', () => { }) it('map Promise with custom context', async () => { + const context = createContext() + const body = { name: 'Shiroko' } @@ -199,6 +203,7 @@ describe('Web Standard - Map Early Response', () => { }) it('map Error with custom context', async () => { + const context = createContext() const response = mapEarlyResponse(new Error('Hello'), context) expect(response).toBeInstanceOf(Response) @@ -211,6 +216,7 @@ describe('Web Standard - Map Early Response', () => { }) it('map Response with custom context', async () => { + const context = createContext() const response = await mapEarlyResponse( new Response('Shiroko'), context @@ -223,6 +229,8 @@ describe('Web Standard - Map Early Response', () => { }) it('map Response and merge Headers', async () => { + const context = createContext() + const response = await mapEarlyResponse( new Response('Shiroko', { headers: { diff --git a/test/adapter/web-standard/map-response.test.ts b/test/adapter/web-standard/map-response.test.ts index ae827fc7..cc5cbc53 100644 --- a/test/adapter/web-standard/map-response.test.ts +++ b/test/adapter/web-standard/map-response.test.ts @@ -12,15 +12,6 @@ const createContext = () => ({ status: 200 }) -const context = { - cookie: {}, - headers: { - 'x-powered-by': 'Elysia', - 'coffee-scheme': 'Coffee' - }, - status: 418 -} - class Student { constructor(public name: string) {} @@ -186,33 +177,37 @@ describe('Web Standard - Map Response', () => { }) it('map primitive with custom context', async () => { + const context = createContext() const response = mapResponse('Shiroko', context) expect(response).toBeInstanceOf(Response) expect(await response.text()).toBe('Shiroko') expect(response.headers.toJSON()).toEqual(context.headers) - expect(response.status).toBe(418) + expect(response.status).toBe(200) }) it('map undefined with context', async () => { + const context = createContext() const response = mapResponse(undefined, context) expect(response).toBeInstanceOf(Response) expect(await response.text()).toEqual('') expect(response.headers.toJSON()).toEqual(context.headers) - expect(response.status).toBe(418) + expect(response.status).toBe(200) }) it('map null with custom context', async () => { + const context = createContext() const response = mapResponse(null, context) expect(response).toBeInstanceOf(Response) expect(await response.text()).toEqual('') expect(response.headers.toJSON()).toEqual(context.headers) - expect(response.status).toBe(418) + expect(response.status).toBe(200) }) it('map Function with custom context', async () => { + const context = createContext() const response = await mapResponse(() => 1, context) expect(response).toBeInstanceOf(Response) @@ -220,10 +215,12 @@ describe('Web Standard - Map Response', () => { expect(response.headers.toJSON()).toEqual({ ...context.headers }) - expect(response.status).toBe(418) + expect(response.status).toBe(200) }) it('map Promise with custom context', async () => { + const context = createContext() + const body = { name: 'Shiroko' } @@ -239,10 +236,12 @@ describe('Web Standard - Map Response', () => { ...context.headers, 'content-type': 'application/json' }) - expect(response.status).toBe(418) + expect(response.status).toBe(200) }) it('map Error with custom context', async () => { + const context = createContext() + const response = mapResponse(new Error('Hello'), context) expect(response).toBeInstanceOf(Response) @@ -251,10 +250,12 @@ describe('Web Standard - Map Response', () => { message: 'Hello' }) expect(response.headers.toJSON()).toEqual(context.headers) - expect(response.status).toBe(418) + expect(response.status).toBe(500) }) it('map Response with custom context', async () => { + const context = createContext() + const response = await mapResponse(new Response('Shiroko'), context) const headers = response.headers.toJSON() @@ -264,6 +265,8 @@ describe('Web Standard - Map Response', () => { }) it('map Response and merge Headers', async () => { + const context = createContext() + const response = await mapResponse( new Response('Shiroko', { headers: { @@ -438,4 +441,20 @@ describe('Web Standard - Map Response', () => { expect(response).toBe('b') }) + + it('respect set.headers on string response', async () => { + const app = new Elysia() + .onAfterHandle(({ set }) => { + set.headers['content-type'] = 'text/html; charset=utf8' + + return '

Hina

' + }) + .get('/', () => 'a') + + const response = await app.handle(req('/')) + + expect(response.headers.get('content-type')).toBe( + 'text/html; charset=utf8' + ) + }) }) diff --git a/test/core/native-static.test.ts b/test/core/native-static.test.ts index 227f121a..b6b5a12b 100644 --- a/test/core/native-static.test.ts +++ b/test/core/native-static.test.ts @@ -31,17 +31,11 @@ describe('Native Static Response', () => { .get('/', 'Static Content') expect(app.router.response['/'].GET).toBeInstanceOf(Response) - expect(app.router.response['/'].GET.headers.toJSON()).toEqual({ - 'content-type': 'text/plain', - server: 'Elysia' - }) + expect(app.router.response['/'].GET.headers.get('server')).toBe('Elysia') expect(await app.router.response['/'].GET.text()).toEqual('Static Content') expect(app.router.response['/plugin'].GET).toBeInstanceOf(Response) - expect(app.router.response['/plugin'].GET.headers.toJSON()).toEqual({ - 'content-type': 'text/plain', - server: 'Elysia' - }) + expect(app.router.response['/plugin'].GET.headers.get('server')).toBe('Elysia') expect(await app.router.response['/plugin'].GET.text()).toEqual('Plugin') })