From 6aa31cef9e76e0de54c09441a0b588aa0b262a28 Mon Sep 17 00:00:00 2001 From: Taku Amano Date: Sun, 23 Jun 2024 21:44:18 +0900 Subject: [PATCH 1/3] feat(request): enable to get "matchResult" object for internal use --- src/request.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/request.ts b/src/request.ts index 64801ef53..74261e6e4 100644 --- a/src/request.ts +++ b/src/request.ts @@ -358,6 +358,10 @@ export class HonoRequest

{ return this.raw.method } + get matchResult(): Result<[unknown, RouterRoute]> { + return this.#matchResult + } + /** * `.matchedRoutes()` can return a matched route in the handler * From a507bc3e6c71205c2c12468639bafddb32401f0b Mon Sep 17 00:00:00 2001 From: Taku Amano Date: Sun, 23 Jun 2024 21:45:05 +0900 Subject: [PATCH 2/3] feat(middleware/hook): introduce hook middleware --- src/middleware/hook/index.ts | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/middleware/hook/index.ts diff --git a/src/middleware/hook/index.ts b/src/middleware/hook/index.ts new file mode 100644 index 000000000..65552bd23 --- /dev/null +++ b/src/middleware/hook/index.ts @@ -0,0 +1,53 @@ +import type { Context } from '../../context' +import type { Env, Handler, MiddlewareHandler, Next } from '../../types' + +const isWrapped = Symbol() + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type Hook = (c: Context, handler: Handler, handlerContext: Record) => void +export const hook = ( + options: { + before?: Hook + beforeNext?: Hook + afterNext?: Hook + after?: Hook + } = {} +): MiddlewareHandler => { + function hook(c: Context, next: Next) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ;(c.req.matchResult[0] as unknown as [[any]][]).forEach((routeData) => { + if (routeData[0][0][isWrapped]) { + return + } + + const handler = routeData[0][0] + const name = handler.name || '' + routeData[0][0] = { + [name]: function (c: Context, next: Next) { + const handlerContext = Object.create(null) + + if (options.before) { + options.before?.(c, handler, handlerContext) + } + const internalNext = () => { + options.beforeNext?.(c, handler, handlerContext) + const res = next() + res.finally(() => options.afterNext?.(c, handler, handlerContext)) + return res + } + const res = handler(c, internalNext) + if (res instanceof Promise) { + res.finally(() => options.after?.(c, handler, handlerContext)) + } else { + options.after?.(c, handler, handlerContext) + } + return res + }, + }[name] + routeData[0][0][isWrapped] = true + }) + return next() + } + hook[isWrapped] = true + return hook +} From 36267e21de4e3d6e51795d0f11d32622a208e547 Mon Sep 17 00:00:00 2001 From: Taku Amano Date: Sun, 23 Jun 2024 22:36:27 +0900 Subject: [PATCH 3/3] feat(middleware/hook): assign traceId to each request --- src/middleware/hook/index.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/middleware/hook/index.ts b/src/middleware/hook/index.ts index 65552bd23..719468c0a 100644 --- a/src/middleware/hook/index.ts +++ b/src/middleware/hook/index.ts @@ -3,8 +3,13 @@ import type { Env, Handler, MiddlewareHandler, Next } from '../../types' const isWrapped = Symbol() -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Hook = (c: Context, handler: Handler, handlerContext: Record) => void +export type Hook = ( + c: Context, + handler: Handler, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handlerContext: Record, + traceId: string +) => void export const hook = ( options: { before?: Hook @@ -14,6 +19,9 @@ export const hook = ( } = {} ): MiddlewareHandler => { function hook(c: Context, next: Next) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + c.set('middleware-hook-trace-id' as any, Math.random().toString(16).slice(2)) + // eslint-disable-next-line @typescript-eslint/no-explicit-any ;(c.req.matchResult[0] as unknown as [[any]][]).forEach((routeData) => { if (routeData[0][0][isWrapped]) { @@ -25,21 +33,22 @@ export const hook = ( routeData[0][0] = { [name]: function (c: Context, next: Next) { const handlerContext = Object.create(null) + const traceId = c.get('middleware-hook-trace-id') if (options.before) { - options.before?.(c, handler, handlerContext) + options.before?.(c, handler, handlerContext, traceId) } const internalNext = () => { - options.beforeNext?.(c, handler, handlerContext) + options.beforeNext?.(c, handler, handlerContext, traceId) const res = next() - res.finally(() => options.afterNext?.(c, handler, handlerContext)) + res.finally(() => options.afterNext?.(c, handler, handlerContext, traceId)) return res } const res = handler(c, internalNext) if (res instanceof Promise) { - res.finally(() => options.after?.(c, handler, handlerContext)) + res.finally(() => options.after?.(c, handler, handlerContext, traceId)) } else { - options.after?.(c, handler, handlerContext) + options.after?.(c, handler, handlerContext, traceId) } return res },