diff --git a/src/app.ts b/src/app.ts index 5de7001f..30ed5790 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,11 +1,11 @@ import type http from 'http' import { withoutTrailingSlash } from 'ufo' import { defineLazyHandler } from './handler' -import { toEventHandler, createEvent, isEventHandler } from './event' +import { toEventHandler, createEvent, isEventHandler, defineEventHandler } from './event' import { createError, sendError } from './error' import { send, sendStream, isStream, MIMES } from './utils' -import type { Handler, LazyHandler, Middleware, PromisifiedHandler } from './types' -import type { EventHandler, CompatibilityEvent } from './event' +import type { Handler, LazyHandler, Middleware } from './types' +import type { EventHandler, CompatibilityEvent, CompatibilityEventHandler } from './event' export interface Layer { route: string @@ -30,19 +30,17 @@ export type InputStack = InputLayer[] export type Matcher = (url: string, event?: CompatibilityEvent) => boolean -export type RequestHandler = EventHandler | Handler | Middleware - export interface AppUse { - (route: string | string [], handler: RequestHandler | RequestHandler[], options?: Partial): App - (handler: RequestHandler | Handler[], options?: Partial): App + (route: string | string [], handler: CompatibilityEventHandler | CompatibilityEventHandler[], options?: Partial): App + (handler: CompatibilityEventHandler | CompatibilityEventHandler[], options?: Partial): App (options: InputLayer): App } -export type ApPromisifiedHandlerr = (req: http.IncomingMessage, res: http.ServerResponse) => Promise +export type NodeHandler = (req: http.IncomingMessage, res: http.ServerResponse) => void | Promise -export interface App extends ApPromisifiedHandlerr { +export interface App extends NodeHandler { stack: Stack - _handler: PromisifiedHandler + handler: EventHandler use: AppUse } @@ -54,20 +52,23 @@ export interface AppOptions { export function createApp (options: AppOptions = {}): App { const stack: Stack = [] - const _handler = createHandler(stack, options) + const handler = createAppEventHandler(stack, options) - const app: App = function (req, res) { + const nodeHandler: NodeHandler = async function (req, res) { const event = createEvent(req, res) - return _handler(event).catch((error: Error) => { + try { + await handler(event) + } catch (err) { if (options.onError) { - return options.onError(error, event) + await options.onError(err as Error, event) } - return sendError(event, error, !!options.debug) - }) - } as App + await sendError(event, err as Error, !!options.debug) + } + } + const app = nodeHandler as App app.stack = stack - app._handler = _handler + app.handler = handler // @ts-ignore app.use = (arg1, arg2, arg3) => use(app as App, arg1, arg2, arg3) @@ -95,11 +96,10 @@ export function use ( return app } -export function createHandler (stack: Stack, options: AppOptions) { +export function createAppEventHandler (stack: Stack, options: AppOptions) { const spacing = options.debug ? 2 : undefined - return async function handle (event: CompatibilityEvent) { + return defineEventHandler(async (event) => { event.req.originalUrl = event.req.originalUrl || event.req.url || '/' - const reqUrl = event.req.url || '/' for (const layer of stack) { if (layer.route.length > 1) { @@ -135,11 +135,16 @@ export function createHandler (stack: Stack, options: AppOptions) { if (!event.res.writableEnded) { throw createError({ statusCode: 404, statusMessage: 'Not Found' }) } - } + }) } function normalizeLayer (input: InputLayer) { let handler = input.handler + // @ts-ignore + if (handler.handler) { + // @ts-ignore + handler = handler.handler + } if (!isEventHandler(handler)) { if (input.lazy) { handler = defineLazyHandler(handler as LazyHandler) diff --git a/src/event.ts b/src/event.ts index 8b2d5aa9..1201ac24 100644 --- a/src/event.ts +++ b/src/event.ts @@ -54,7 +54,9 @@ export function isEventHandler (input: any): input is EventHandler { return '__is_handler__' in input } -export function toEventHandler (handler: EventHandler | Handler | Middleware): EventHandler { +export type CompatibilityEventHandler = EventHandler | Handler | Middleware + +export function toEventHandler (handler: CompatibilityEventHandler): EventHandler { if (isEventHandler(handler)) { return handler } diff --git a/src/router.ts b/src/router.ts index 437f9956..34b83726 100644 --- a/src/router.ts +++ b/src/router.ts @@ -2,17 +2,17 @@ import { createRouter as _createRouter } from 'radix3' import type { HTTPMethod } from './types' import { createError } from './error' import { defineEventHandler, EventHandler, toEventHandler } from './event' -import type { RequestHandler } from './app' +import type { CompatibilityEventHandler } from './event' export type RouterMethod = Lowercase const RouterMethods: Lowercase[] = ['connect', 'delete', 'get', 'head', 'options', 'post', 'put', 'trace'] -export type AddWithMethod = (path: string, handler: RequestHandler) => Router +export type AddWithMethod = (path: string, handler: CompatibilityEventHandler) => Router export type AddRouteShortcuts = Record, AddWithMethod> export interface Router extends AddRouteShortcuts { - add: (path: string, handler: RequestHandler, method?: RouterMethod | 'all') => Router - handler: RequestHandler + add: (path: string, handler: CompatibilityEventHandler, method?: RouterMethod | 'all') => Router + handler: EventHandler } interface RouteNode { diff --git a/src/utils/response.ts b/src/utils/response.ts index eb42baac..abb94401 100644 --- a/src/utils/response.ts +++ b/src/utils/response.ts @@ -47,7 +47,7 @@ export function isStream (data: any) { return data && typeof data === 'object' && typeof data.pipe === 'function' && typeof data.on === 'function' } -export function sendStream (event: CompatibilityEvent, data: any) { +export function sendStream (event: CompatibilityEvent, data: any): Promise { return new Promise((resolve, reject) => { data.pipe(event.res) data.on('end', () => resolve(undefined))