@@ -25,6 +25,10 @@ export { deserializeManifest } from './common.js';
2525export const pagesVirtualModuleId = '@astrojs-pages-virtual-entry' ;
2626export const resolvedPagesVirtualModuleId = '\0' + pagesVirtualModuleId ;
2727
28+ export interface MatchOptions {
29+ matchNotFound ?: boolean | undefined ;
30+ }
31+
2832export class App {
2933 #manifest: Manifest ;
3034 #manifestData: ManifestData ;
@@ -46,17 +50,30 @@ export class App {
4650 this . #routeCache = new RouteCache ( this . #logging) ;
4751 this . #streaming = streaming ;
4852 }
49- match ( request : Request ) : RouteData | undefined {
53+ match ( request : Request , { matchNotFound = false } : MatchOptions = { } ) : RouteData | undefined {
5054 const url = new URL ( request . url ) ;
5155 // ignore requests matching public assets
5256 if ( this . #manifest. assets . has ( url . pathname ) ) {
5357 return undefined ;
5458 }
55- return matchRoute ( url . pathname , this . #manifestData) ;
59+ let routeData = matchRoute ( url . pathname , this . #manifestData) ;
60+
61+ if ( routeData ) {
62+ return routeData ;
63+ } else if ( matchNotFound ) {
64+ return matchRoute ( '/404' , this . #manifestData) ;
65+ } else {
66+ return undefined ;
67+ }
5668 }
5769 async render ( request : Request , routeData ?: RouteData ) : Promise < Response > {
70+ let defaultStatus = 200 ;
5871 if ( ! routeData ) {
5972 routeData = this . match ( request ) ;
73+ if ( ! routeData ) {
74+ defaultStatus = 404 ;
75+ routeData = this . match ( request , { matchNotFound : true } ) ;
76+ }
6077 if ( ! routeData ) {
6178 return new Response ( null , {
6279 status : 404 ,
@@ -65,12 +82,25 @@ export class App {
6582 }
6683 }
6784
68- const mod = this . #manifest. pageMap . get ( routeData . component ) ! ;
85+ let mod = this . #manifest. pageMap . get ( routeData . component ) ! ;
6986
7087 if ( routeData . type === 'page' ) {
71- return this . #renderPage( request , routeData , mod ) ;
88+ let response = await this . #renderPage( request , routeData , mod , defaultStatus ) ;
89+
90+ // If there was a 500 error, try sending the 500 page.
91+ if ( response . status === 500 ) {
92+ const fiveHundredRouteData = matchRoute ( '/500' , this . #manifestData) ;
93+ if ( fiveHundredRouteData ) {
94+ mod = this . #manifest. pageMap . get ( fiveHundredRouteData . component ) ! ;
95+ try {
96+ let fiveHundredResponse = await this . #renderPage( request , fiveHundredRouteData , mod , 500 ) ;
97+ return fiveHundredResponse ;
98+ } catch { }
99+ }
100+ }
101+ return response ;
72102 } else if ( routeData . type === 'endpoint' ) {
73- return this . #callEndpoint( request , routeData , mod ) ;
103+ return this . #callEndpoint( request , routeData , mod , defaultStatus ) ;
74104 } else {
75105 throw new Error ( `Unsupported route type [${ routeData . type } ].` ) ;
76106 }
@@ -79,7 +109,8 @@ export class App {
79109 async #renderPage(
80110 request : Request ,
81111 routeData : RouteData ,
82- mod : ComponentInstance
112+ mod : ComponentInstance ,
113+ status = 200
83114 ) : Promise < Response > {
84115 const url = new URL ( request . url ) ;
85116 const manifest = this . #manifest;
@@ -128,6 +159,7 @@ export class App {
128159 ssr : true ,
129160 request,
130161 streaming : this . #streaming,
162+ status
131163 } ) ;
132164
133165 return response ;
@@ -143,7 +175,8 @@ export class App {
143175 async #callEndpoint(
144176 request : Request ,
145177 routeData : RouteData ,
146- mod : ComponentInstance
178+ mod : ComponentInstance ,
179+ status = 200
147180 ) : Promise < Response > {
148181 const url = new URL ( request . url ) ;
149182 const handler = mod as unknown as EndpointHandler ;
@@ -155,6 +188,7 @@ export class App {
155188 route : routeData ,
156189 routeCache : this . #routeCache,
157190 ssr : true ,
191+ status
158192 } ) ;
159193
160194 if ( result . type === 'response' ) {
0 commit comments