@@ -3,6 +3,7 @@ import { Writable } from "node:stream";
33
44import cookieParser from "cookie" ;
55
6+ import { parseSetCookieHeader } from "@/http/util" ;
67import type { InternalEvent , InternalResult , MiddlewareResult , StreamCreator } from "@/types/open-next" ;
78import type { Converter } from "@/types/overrides" ;
89
@@ -54,8 +55,12 @@ const converter: Converter<InternalEvent, InternalResult | MiddlewareResult> = {
5455 const url = new URL ( request . url ) ;
5556 const { promise : output , resolve : resolveOutput } = Promise . withResolvers < Response > ( ) ;
5657 const abortSignal = ( context as { abortSignal ?: AbortSignal } | undefined ) ?. abortSignal ;
58+ // Not every handler streams its response: the external middleware handler returns the
59+ // result directly. We track whether the stream was used to know which one to return.
60+ let isStreamed = false ;
5761 const streamCreator : StreamCreator = {
5862 writeHeaders ( prelude ) {
63+ isStreamed = true ;
5964 const responseHeaders = new Headers ( prelude . headers ) ;
6065 for ( const cookie of prelude . cookies ) {
6166 responseHeaders . append ( "Set-Cookie" , cookie ) ;
@@ -119,16 +124,48 @@ const converter: Converter<InternalEvent, InternalResult | MiddlewareResult> = {
119124 streamCreator,
120125 output,
121126 data : async ( result ) => {
122- if ( ! ( "internalEvent" in result ) ) {
123- return undefined ;
127+ if ( "internalEvent" in result ) {
128+ return convertMiddlewareResult ( result ) ;
124129 }
125- return convertMiddlewareResult ( result ) ;
130+ // When the handler streamed the response, `output` already holds it.
131+ return isStreamed ? undefined : convertInternalResult ( result ) ;
126132 } ,
127133 } ;
128134 } ,
129135 name : "edge" ,
130136} ;
131137
138+ function convertInternalResult ( result : InternalResult ) : Response {
139+ const headers = new Headers ( ) ;
140+ for ( const [ key , value ] of Object . entries ( result . headers ) ) {
141+ if ( key === "set-cookie" && typeof value === "string" ) {
142+ // If the value is a string, we need to parse it into an array
143+ // This is the case for middleware direct result
144+ for ( const cookie of parseSetCookieHeader ( value ) ) {
145+ headers . append ( key , cookie ) ;
146+ }
147+ continue ;
148+ }
149+ if ( Array . isArray ( value ) ) {
150+ for ( const v of value ) {
151+ headers . append ( key , v ) ;
152+ }
153+ } else {
154+ headers . set ( key , value ) ;
155+ }
156+ }
157+
158+ // We should not return a body for statusCode's that doesn't allow bodies
159+ const body = NULL_BODY_STATUSES . has ( result . statusCode )
160+ ? null
161+ : ( ( result . body ?? null ) as ReadableStream | null ) ;
162+
163+ return new Response ( body , {
164+ status : result . statusCode ,
165+ headers,
166+ } ) ;
167+ }
168+
132169async function convertMiddlewareResult (
133170 result : MiddlewareResult
134171) : Promise < Response | Request | { initialResponse : InternalResult ; request : Request } > {
0 commit comments