11import { FastResponse as Response } from 'srvx'
22import type { ReadStream } from 'fs'
33
4- import { isNotEmpty } from 'elysia/utils'
4+ import { isNotEmpty , StatusMap } from 'elysia/utils'
55import type { Context } from 'elysia/context'
66import {
77 createStreamHandler ,
@@ -84,17 +84,57 @@ interface CreateHandlerParameter {
8484 mapCompactResponse ( response : unknown , request ?: Request ) : Response
8585}
8686
87+ // Merge header by allocating a new one
88+ // In Bun, response.headers can be mutable
89+ // while in Node and Cloudflare Worker is not
90+ // default to creating a new one instead
91+ export function mergeHeaders (
92+ responseHeaders : Headers ,
93+ setHeaders : Context [ 'set' ] [ 'headers' ]
94+ ) {
95+ // @ts -ignore
96+ const headers = new Headers ( Object . fromEntries ( responseHeaders . entries ( ) ) )
97+
98+ // Merge headers: Response headers take precedence, set.headers fill in non-conflicting ones
99+ if ( setHeaders instanceof Headers )
100+ // @ts -ignore
101+ for ( const key of setHeaders . keys ( ) ) {
102+ if ( key === 'set-cookie' ) {
103+ if ( headers . has ( 'set-cookie' ) ) continue
104+
105+ for ( const cookie of setHeaders . getSetCookie ( ) )
106+ headers . append ( 'set-cookie' , cookie )
107+ } else if ( ! responseHeaders . has ( key ) )
108+ headers . set ( key , setHeaders ?. get ( key ) ?? '' )
109+ }
110+ else
111+ for ( const key in setHeaders )
112+ if ( key === 'set-cookie' )
113+ headers . append ( key , setHeaders [ key ] as any )
114+ else if ( ! responseHeaders . has ( key ) )
115+ headers . set ( key , setHeaders [ key ] as any )
116+
117+ return headers
118+ }
119+
120+ export function mergeStatus (
121+ responseStatus : number ,
122+ setStatus : Context [ 'set' ] [ 'status' ]
123+ ) {
124+ if ( typeof setStatus === 'string' ) setStatus = StatusMap [ setStatus ]
125+
126+ if ( responseStatus === 200 ) return setStatus
127+
128+ return responseStatus
129+ }
130+
87131export const createResponseHandler = ( handler : CreateHandlerParameter ) => {
88132 const handleStream = createStreamHandler ( handler )
89133
90134 return ( response : Response , set : Context [ 'set' ] , request ?: Request ) => {
91135 const newResponse = new Response ( response . body , {
92- headers : Object . assign (
93- // @ts -ignore
94- Object . fromEntries ( response . headers . entries ( ) ) ,
95- set . headers
96- ) ,
97- status : response . status ?? set . status
136+ headers : mergeHeaders ( response . headers , set . headers ) ,
137+ status : mergeStatus ( response . status , set . status )
98138 } )
99139
100140 if (
@@ -105,7 +145,9 @@ export const createResponseHandler = (handler: CreateHandlerParameter) => {
105145 return handleStream (
106146 streamResponse ( newResponse as Response ) ,
107147 responseToSetHeaders ( newResponse as Response , set ) ,
108- request
148+ request ,
149+ // @ts -ignore
150+ true // don't auto-format SSE for pre-formatted Response
109151 ) as any
110152
111153 return newResponse
0 commit comments