Skip to content

Commit

Permalink
feat(app): use node handler signuture
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Mar 29, 2022
1 parent 9bdc57a commit c722091
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 28 deletions.
49 changes: 27 additions & 22 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<InputLayer>): App
(handler: RequestHandler | Handler[], options?: Partial<InputLayer>): App
(route: string | string [], handler: CompatibilityEventHandler | CompatibilityEventHandler[], options?: Partial<InputLayer>): App
(handler: CompatibilityEventHandler | CompatibilityEventHandler[], options?: Partial<InputLayer>): App
(options: InputLayer): App
}

export type ApPromisifiedHandlerr = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<any>
export type NodeHandler = (req: http.IncomingMessage, res: http.ServerResponse) => void | Promise<void>

export interface App extends ApPromisifiedHandlerr {
export interface App extends NodeHandler {
stack: Stack
_handler: PromisifiedHandler
handler: EventHandler
use: AppUse
}

Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion src/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 4 additions & 4 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTTPMethod>
const RouterMethods: Lowercase<RouterMethod>[] = ['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<Lowercase<HTTPMethod>, 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 {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
return new Promise((resolve, reject) => {
data.pipe(event.res)
data.on('end', () => resolve(undefined))
Expand Down

0 comments on commit c722091

Please sign in to comment.