@@ -12,7 +12,7 @@ import renderer from "./renderer.ts";
12
12
import { content , type CookieOptions , json , setCookieHeader } from "./response.ts" ;
13
13
import { importRouteModule , initRoutes , revive } from "./routing.ts" ;
14
14
import clientModuleTransformer from "./transformer.ts" ;
15
- import type { AlephConfig , FetchHandler , Middleware , MiddlewareCallback } from "./types.ts" ;
15
+ import type { AlephConfig , FetchHandler , Middleware } from "./types.ts" ;
16
16
17
17
export type ServerOptions = ServeInit & {
18
18
certFile ?: string ;
@@ -23,10 +23,11 @@ export type ServerOptions = ServeInit & {
23
23
middlewares ?: Middleware [ ] ;
24
24
fetch ?: FetchHandler ;
25
25
ssr ?: SSR ;
26
+ onError ?( error : unknown ) : Promise < Response > | Response ;
26
27
} ;
27
28
28
29
export const serve = ( options : ServerOptions = { } ) => {
29
- const { config, middlewares, fetch, ssr, logLevel } = options ;
30
+ const { config, middlewares, fetch, ssr, logLevel, onError } = options ;
30
31
const isDev = Deno . env . get ( "ALEPH_ENV" ) === "development" ;
31
32
const importMapPromise = loadImportMap ( ) ;
32
33
const jsxConfigPromise = importMapPromise . then ( ( importMap ) => loadJSXConfig ( importMap ) ) ;
@@ -50,32 +51,39 @@ export const serve = (options: ServerOptions = {}) => {
50
51
51
52
// transform client modules
52
53
if ( clientModuleTransformer . test ( pathname ) ) {
53
- const [ buildHash , jsxConfig , importMap ] = await Promise . all ( [
54
- buildHashPromise ,
55
- jsxConfigPromise ,
56
- importMapPromise ,
57
- ] ) ;
58
- return clientModuleTransformer . fetch ( req , {
59
- importMap,
60
- jsxConfig,
61
- buildHash,
62
- buildTarget : config ?. build ?. target ,
63
- isDev,
64
- } ) ;
54
+ try {
55
+ const [ buildHash , jsxConfig , importMap ] = await Promise . all ( [
56
+ buildHashPromise ,
57
+ jsxConfigPromise ,
58
+ importMapPromise ,
59
+ ] ) ;
60
+ return await clientModuleTransformer . fetch ( req , {
61
+ importMap,
62
+ jsxConfig,
63
+ buildHash,
64
+ buildTarget : config ?. build ?. target ,
65
+ isDev,
66
+ } ) ;
67
+ } catch ( err ) {
68
+ if ( ! ( err instanceof Deno . errors . NotFound ) ) {
69
+ log . error ( err ) ;
70
+ return onError ?.( err ) ?? new Response ( err . message , { status : 500 } ) ;
71
+ }
72
+ }
65
73
}
66
74
67
75
// use loader to load modules
68
76
const moduleLoaders = await moduleLoadersPromise ;
69
77
const loader = moduleLoaders . find ( ( loader ) => loader . test ( pathname ) ) ;
70
78
if ( loader ) {
71
- const [ buildHash , jsxConfig , importMap ] = await Promise . all ( [
72
- buildHashPromise ,
73
- jsxConfigPromise ,
74
- importMapPromise ,
75
- ] ) ;
76
79
try {
80
+ const [ buildHash , jsxConfig , importMap ] = await Promise . all ( [
81
+ buildHashPromise ,
82
+ jsxConfigPromise ,
83
+ importMapPromise ,
84
+ ] ) ;
77
85
const loaded = await loader . load ( pathname , { isDev, importMap } ) ;
78
- return clientModuleTransformer . fetch ( req , {
86
+ return await clientModuleTransformer . fetch ( req , {
79
87
loaded,
80
88
importMap,
81
89
jsxConfig,
@@ -86,7 +94,7 @@ export const serve = (options: ServerOptions = {}) => {
86
94
} catch ( err ) {
87
95
if ( ! ( err instanceof Deno . errors . NotFound ) ) {
88
96
log . error ( err ) ;
89
- return new Response ( err . message , { status : 500 } ) ;
97
+ return onError ?. ( err ) ?? new Response ( err . message , { status : 500 } ) ;
90
98
}
91
99
}
92
100
}
@@ -123,7 +131,7 @@ export const serve = (options: ServerOptions = {}) => {
123
131
} catch ( err ) {
124
132
if ( ! ( err instanceof Deno . errors . NotFound ) ) {
125
133
log . error ( err ) ;
126
- return new Response ( "Internal Server Error" , { status : 500 } ) ;
134
+ return onError ?. ( err ) ?? new Response ( err . message , { status : 500 } ) ;
127
135
}
128
136
}
129
137
}
@@ -205,24 +213,24 @@ export const serve = (options: ServerOptions = {}) => {
205
213
206
214
// use middlewares
207
215
if ( Array . isArray ( middlewares ) && middlewares . length > 0 ) {
208
- const callbacks : MiddlewareCallback [ ] = [ ] ;
209
- for ( const mw of middlewares ) {
210
- const handler = mw . fetch ;
211
- if ( typeof handler === "function" ) {
212
- let res = handler ( req , ctx ) ;
213
- if ( res instanceof Promise ) {
214
- res = await res ;
215
- }
216
- if ( res instanceof Response ) {
217
- return res ;
218
- }
219
- if ( typeof res === "function" ) {
220
- callbacks . push ( res ) ;
216
+ try {
217
+ for ( const mw of middlewares ) {
218
+ const handler = mw . fetch ;
219
+ if ( typeof handler === "function" ) {
220
+ let res = handler ( req , ctx ) ;
221
+ if ( res instanceof Promise ) {
222
+ res = await res ;
223
+ }
224
+ if ( res instanceof Response ) {
225
+ return res ;
226
+ }
227
+ if ( typeof res === "function" ) {
228
+ setTimeout ( res , 0 ) ;
229
+ }
221
230
}
222
231
}
223
- }
224
- for ( const callback of callbacks ) {
225
- await callback ( ) ;
232
+ } catch ( err ) {
233
+ return onError ?.( err ) ?? new Response ( err . message , { status : 500 } ) ;
226
234
}
227
235
}
228
236
@@ -241,7 +249,23 @@ export const serve = (options: ServerOptions = {}) => {
241
249
) {
242
250
const fetcher = dataConfig [ req . method . toLowerCase ( ) ] ;
243
251
if ( typeof fetcher === "function" ) {
244
- return fetcher ( req , { ...ctx , params : ret . pathname . groups } ) ;
252
+ const res = await fetcher ( req , { ...ctx , params : ret . pathname . groups } ) ;
253
+ console . log ( res ) ;
254
+ if ( res instanceof Response ) {
255
+ return res ;
256
+ }
257
+ if (
258
+ typeof res === "string" || res instanceof ArrayBuffer || res instanceof ReadableStream
259
+ ) {
260
+ return new Response ( res ) ;
261
+ }
262
+ if ( res instanceof Blob ) {
263
+ return new Response ( res , { headers : { "Content-Type" : res . type } } ) ;
264
+ }
265
+ if ( util . isPlainObject ( res ) || Array . isArray ( res ) || res === null ) {
266
+ return json ( res ) ;
267
+ }
268
+ return new Response ( null ) ;
245
269
}
246
270
return new Response ( "Method not allowed" , { status : 405 } ) ;
247
271
}
@@ -277,7 +301,7 @@ export const serve = (options: ServerOptions = {}) => {
277
301
indexHtml = null ;
278
302
} else {
279
303
log . error ( "read index.html:" , err ) ;
280
- return new Response ( "Internal Server Error" , { status : 500 } ) ;
304
+ return onError ?. ( err ) ?? new Response ( err . message , { status : 500 } ) ;
281
305
}
282
306
}
283
307
}
0 commit comments