@@ -12,6 +12,7 @@ import type {
1212 RoutingResult , 
1313}  from  "types/open-next" ; 
1414
15+ import  type  {  AssetResolver  }  from  "types/overrides" ; 
1516import  {  debug ,  error  }  from  "../adapters/logger" ; 
1617import  {  cacheInterceptor  }  from  "./routing/cacheInterceptor" ; 
1718import  {  detectLocale  }  from  "./routing/i18n" ; 
@@ -47,23 +48,31 @@ const geoHeaderToNextHeader = {
4748 "x-open-next-longitude" : "x-vercel-ip-longitude" , 
4849} ; 
4950
51+ /** 
52+  * Adds the middleware headers to an event or result. 
53+  * 
54+  * @param  eventOrResult 
55+  * @param  middlewareHeaders 
56+  */ 
5057function  applyMiddlewareHeaders ( 
51-  eventHeaders :  Record < string ,   string   |   string [ ] > , 
58+  eventOrResult :  InternalEvent   |   InternalResult , 
5259 middlewareHeaders : Record < string ,  string  |  string [ ]  |  undefined > , 
53-  setPrefix  =  true , 
5460)  { 
55-  const  keyPrefix  =  setPrefix  ? MIDDLEWARE_HEADER_PREFIX  : "" ; 
61+  // Use the `MIDDLEWARE_HEADER_PREFIX` prefix for events, they will be processed by the request handler later. 
62+  // Results do not go through the request handler and should not be prefixed. 
63+  const  isResult  =  isInternalResult ( eventOrResult ) ; 
64+  const  headers  =  eventOrResult . headers ; 
65+  const  keyPrefix  =  isResult  ? ""  : MIDDLEWARE_HEADER_PREFIX ; 
5666 Object . entries ( middlewareHeaders ) . forEach ( ( [ key ,  value ] )  =>  { 
5767 if  ( value )  { 
58-  eventHeaders [ keyPrefix  +  key ]  =  Array . isArray ( value ) 
59-  ? value . join ( "," ) 
60-  : value ; 
68+  headers [ keyPrefix  +  key ]  =  Array . isArray ( value )  ? value . join ( "," )  : value ; 
6169 } 
6270 } ) ; 
6371} 
6472
6573export  default  async  function  routingHandler ( 
6674 event : InternalEvent , 
75+  {  assetResolver } : {  assetResolver ?: AssetResolver  } , 
6776) : Promise < InternalResult  |  RoutingResult >  { 
6877 try  { 
6978 // Add Next geo headers 
@@ -87,14 +96,17 @@ export default async function routingHandler(
8796 } 
8897 } 
8998
90-  const  nextHeaders  =  getNextConfigHeaders ( event ,  ConfigHeaders ) ; 
99+  // Headers from the Next config and middleware (the later are applied further down). 
100+  let  headers : Record < string ,  string  |  string [ ]  |  undefined >  = 
101+  getNextConfigHeaders ( event ,  ConfigHeaders ) ; 
91102
92-  let  internalEvent  =  fixDataPage ( event ,  BuildId ) ; 
93-  if  ( "statusCode"  in  internalEvent )  { 
94-  return  internalEvent ; 
103+  let  eventOrResult  =  fixDataPage ( event ,  BuildId ) ; 
104+ 
105+  if  ( isInternalResult ( eventOrResult ) )  { 
106+  return  eventOrResult ; 
95107 } 
96108
97-  const  redirect  =  handleRedirects ( internalEvent ,  RoutesManifest . redirects ) ; 
109+  const  redirect  =  handleRedirects ( eventOrResult ,  RoutesManifest . redirects ) ; 
98110 if  ( redirect )  { 
99111 // We need to encode the value in the Location header to make sure it is valid according to RFC 
100112 // https://stackoverflow.com/a/7654605/16587222 
@@ -105,70 +117,84 @@ export default async function routingHandler(
105117 return  redirect ; 
106118 } 
107119
108-  const  eventOrResult  =  await  handleMiddleware ( 
109-  internalEvent , 
120+  const  middlewareEventOrResult  =  await  handleMiddleware ( 
121+  eventOrResult , 
110122 // We need to pass the initial search without any decoding 
111123 // TODO: we'd need to refactor InternalEvent to include the initial querystring directly 
112124 // Should be done in another PR because it is a breaking change 
113125 new  URL ( event . url ) . search , 
114126 ) ; 
115-  const  isResult  =  "statusCode"  in  eventOrResult ; 
116-  if  ( isResult )  { 
117-  return  eventOrResult ; 
127+  if  ( isInternalResult ( middlewareEventOrResult ) )  { 
128+  return  middlewareEventOrResult ; 
118129 } 
119-  const  middlewareResponseHeaders  =  eventOrResult . responseHeaders ; 
120-  let  isExternalRewrite  =  eventOrResult . isExternalRewrite  ??  false ; 
121-  // internalEvent is `InternalEvent | MiddlewareEvent` 
122-  internalEvent  =  eventOrResult ; 
130+ 
131+  headers  =  { 
132+  ...middlewareEventOrResult . responseHeaders , 
133+  ...headers , 
134+  } ; 
135+  let  isExternalRewrite  =  middlewareEventOrResult . isExternalRewrite  ??  false ; 
136+  eventOrResult  =  middlewareEventOrResult ; 
123137
124138 if  ( ! isExternalRewrite )  { 
125139 // First rewrite to be applied 
126-  const  beforeRewrites  =  handleRewrites ( 
127-  internalEvent , 
140+  const  beforeRewrite  =  handleRewrites ( 
141+  eventOrResult , 
128142 RoutesManifest . rewrites . beforeFiles , 
129143 ) ; 
130-  internalEvent  =  beforeRewrites . internalEvent ; 
131-  isExternalRewrite  =  beforeRewrites . isExternalRewrite ; 
144+  eventOrResult  =  beforeRewrite . internalEvent ; 
145+  isExternalRewrite  =  beforeRewrite . isExternalRewrite ; 
146+  // Check for matching public files after `beforeFiles` rewrites 
147+  // See: 
148+  // - https://nextjs.org/docs/app/api-reference/file-conventions/middleware#execution-order 
149+  // - https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites 
150+  if  ( ! isExternalRewrite )  { 
151+  const  assetResult  = 
152+  await  assetResolver ?. maybeGetAssetResult ?.( eventOrResult ) ; 
153+  if  ( assetResult )  { 
154+  applyMiddlewareHeaders ( assetResult ,  headers ) ; 
155+  return  assetResult ; 
156+  } 
157+  } 
132158 } 
133-  const  foundStaticRoute  =  staticRouteMatcher ( internalEvent . rawPath ) ; 
159+  const  foundStaticRoute  =  staticRouteMatcher ( eventOrResult . rawPath ) ; 
134160 const  isStaticRoute  =  ! isExternalRewrite  &&  foundStaticRoute . length  >  0 ; 
135161
136162 if  ( ! ( isStaticRoute  ||  isExternalRewrite ) )  { 
137163 // Second rewrite to be applied 
138-  const  afterRewrites  =  handleRewrites ( 
139-  internalEvent , 
164+  const  afterRewrite  =  handleRewrites ( 
165+  eventOrResult , 
140166 RoutesManifest . rewrites . afterFiles , 
141167 ) ; 
142-  internalEvent  =  afterRewrites . internalEvent ; 
143-  isExternalRewrite  =  afterRewrites . isExternalRewrite ; 
168+  eventOrResult  =  afterRewrite . internalEvent ; 
169+  isExternalRewrite  =  afterRewrite . isExternalRewrite ; 
144170 } 
145171
146172 let  isISR  =  false ; 
147173 // We want to run this just before the dynamic route check 
148174 // We can skip it if its an external rewrite 
149175 if  ( ! isExternalRewrite )  { 
150176 const  fallbackResult  =  handleFallbackFalse ( 
151-  internalEvent , 
177+  eventOrResult , 
152178 PrerenderManifest , 
153179 ) ; 
154-  internalEvent  =  fallbackResult . event ; 
180+  eventOrResult  =  fallbackResult . event ; 
155181 isISR  =  fallbackResult . isISR ; 
156182 } 
157183
158-  const  foundDynamicRoute  =  dynamicRouteMatcher ( internalEvent . rawPath ) ; 
184+  const  foundDynamicRoute  =  dynamicRouteMatcher ( eventOrResult . rawPath ) ; 
159185 const  isDynamicRoute  =  ! isExternalRewrite  &&  foundDynamicRoute . length  >  0 ; 
160186
161187 if  ( ! ( isDynamicRoute  ||  isStaticRoute  ||  isExternalRewrite ) )  { 
162188 // Fallback rewrite to be applied 
163189 const  fallbackRewrites  =  handleRewrites ( 
164-  internalEvent , 
190+  eventOrResult , 
165191 RoutesManifest . rewrites . fallback , 
166192 ) ; 
167-  internalEvent  =  fallbackRewrites . internalEvent ; 
193+  eventOrResult  =  fallbackRewrites . internalEvent ; 
168194 isExternalRewrite  =  fallbackRewrites . isExternalRewrite ; 
169195 } 
170196
171-  const  isNextImageRoute  =  internalEvent . rawPath . startsWith ( "/_next/image" ) ; 
197+  const  isNextImageRoute  =  eventOrResult . rawPath . startsWith ( "/_next/image" ) ; 
172198
173199 const  isRouteFoundBeforeAllRewrites  = 
174200 isStaticRoute  ||  isDynamicRoute  ||  isExternalRewrite ; 
@@ -180,16 +206,16 @@ export default async function routingHandler(
180206 isRouteFoundBeforeAllRewrites  || 
181207 isNextImageRoute  || 
182208 // We need to check again once all rewrites have been applied 
183-  staticRouteMatcher ( internalEvent . rawPath ) . length  >  0  || 
184-  dynamicRouteMatcher ( internalEvent . rawPath ) . length  >  0 
209+  staticRouteMatcher ( eventOrResult . rawPath ) . length  >  0  || 
210+  dynamicRouteMatcher ( eventOrResult . rawPath ) . length  >  0 
185211 ) 
186212 )  { 
187-  internalEvent  =  { 
188-  ...internalEvent , 
213+  eventOrResult  =  { 
214+  ...eventOrResult , 
189215 rawPath : "/404" , 
190-  url : constructNextUrl ( internalEvent . url ,  "/404" ) , 
216+  url : constructNextUrl ( eventOrResult . url ,  "/404" ) , 
191217 headers : { 
192-  ...internalEvent . headers , 
218+  ...eventOrResult . headers , 
193219 "x-middleware-response-cache-control" :
194220 "private, no-cache, no-store, max-age=0, must-revalidate" , 
195221 } , 
@@ -198,28 +224,18 @@ export default async function routingHandler(
198224
199225 if  ( 
200226 globalThis . openNextConfig . dangerous ?. enableCacheInterception  && 
201-  ! ( "statusCode"   in   internalEvent ) 
227+  ! isInternalResult ( eventOrResult ) 
202228 )  { 
203229 debug ( "Cache interception enabled" ) ; 
204-  internalEvent  =  await  cacheInterceptor ( internalEvent ) ; 
205-  if  ( "statusCode"  in  internalEvent )  { 
206-  applyMiddlewareHeaders ( 
207-  internalEvent . headers , 
208-  { 
209-  ...middlewareResponseHeaders , 
210-  ...nextHeaders , 
211-  } , 
212-  false , 
213-  ) ; 
214-  return  internalEvent ; 
230+  eventOrResult  =  await  cacheInterceptor ( eventOrResult ) ; 
231+  if  ( isInternalResult ( eventOrResult ) )  { 
232+  applyMiddlewareHeaders ( eventOrResult ,  headers ) ; 
233+  return  eventOrResult ; 
215234 } 
216235 } 
217236
218237 // We apply the headers from the middleware response last 
219-  applyMiddlewareHeaders ( internalEvent . headers ,  { 
220-  ...middlewareResponseHeaders , 
221-  ...nextHeaders , 
222-  } ) ; 
238+  applyMiddlewareHeaders ( eventOrResult ,  headers ) ; 
223239
224240 const  resolvedRoutes : ResolvedRoute [ ]  =  [ 
225241 ...foundStaticRoute , 
@@ -229,14 +245,14 @@ export default async function routingHandler(
229245 debug ( "resolvedRoutes" ,  resolvedRoutes ) ; 
230246
231247 return  { 
232-  internalEvent, 
248+  internalEvent :  eventOrResult , 
233249 isExternalRewrite, 
234250 origin : false , 
235251 isISR, 
236252 resolvedRoutes, 
237253 initialURL : event . url , 
238254 locale : NextConfig . i18n 
239-  ? detectLocale ( internalEvent ,  NextConfig . i18n ) 
255+  ? detectLocale ( eventOrResult ,  NextConfig . i18n ) 
240256 : undefined , 
241257 } ; 
242258 }  catch  ( e )  { 
@@ -266,3 +282,13 @@ export default async function routingHandler(
266282 } ; 
267283 } 
268284} 
285+ 
286+ /** 
287+  * @param  eventOrResult 
288+  * @returns  Whether the event is an instance of `InternalResult` 
289+  */ 
290+ function  isInternalResult ( 
291+  eventOrResult : InternalEvent  |  InternalResult , 
292+ ) : eventOrResult  is InternalResult  { 
293+  return  eventOrResult  !=  null  &&  "statusCode"  in  eventOrResult ; 
294+ } 
0 commit comments