Skip to content

Commit 09ff659

Browse files
committed
feat: added h3 core support
1 parent 318bbdd commit 09ff659

3 files changed

Lines changed: 477 additions & 48 deletions

File tree

src/event.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export interface HTTPEvent<
3232

3333
export class H3Event<
3434
_RequestT extends EventHandlerRequest = EventHandlerRequest,
35-
> implements HTTPEvent<_RequestT> {
35+
> implements HTTPEvent<_RequestT>
36+
{
3637
/**
3738
* Access to the H3 application instance.
3839
*/

src/tracing.ts

Lines changed: 52 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { H3Event } from "./event.ts";
2-
import type { H3 } from "./h3.ts";
2+
import type { H3, H3Core } from "./h3.ts";
33
import {
44
type H3Plugin,
55
type H3Route,
@@ -36,8 +36,7 @@ export interface TracingPluginOptions {
3636
* Enables tracing for H3 apps.
3737
*/
3838
export function tracingPlugin(traceOpts?: TracingPluginOptions): H3Plugin {
39-
// TODO: Support H3Core (Nitro)
40-
return (h3: H3) => {
39+
return (h3: H3 | H3Core) => {
4140
const { tracingChannel } =
4241
globalThis.process.getBuiltinModule?.("diagnostics_channel") ?? {};
4342

@@ -97,57 +96,63 @@ export function tracingPlugin(traceOpts?: TracingPluginOptions): H3Plugin {
9796
} satisfies H3Route;
9897
});
9998

100-
const originalOn = h3.on;
101-
102-
h3.on = (...args) => {
103-
const instance = originalOn.apply(h3, args);
104-
// Since it uses route push, we can wrap the last route handler added
105-
// Wrapping the handler at the arg level is problematic because we need the `event` to be passed to the tracePromise.
106-
// Which is only available with `toEventHandler` and it is already called in the `on` method.
107-
// eslint-disable-next-line unicorn/prefer-at
108-
const lastRoute = instance["~routes"][instance["~routes"].length - 1];
109-
if (lastRoute) {
110-
lastRoute.handler = wrapEventHandler(lastRoute.handler);
111-
lastRoute.middleware = lastRoute.middleware?.map((m) =>
112-
wrapMiddleware(m),
113-
);
114-
}
115-
116-
return instance;
117-
};
99+
if ("on" in h3 && typeof h3.on === "function") {
100+
const originalOn = h3.on;
101+
102+
h3.on = (...args) => {
103+
const instance = originalOn.apply(h3, args);
104+
// Since it uses route push, we can wrap the last route handler added
105+
// Wrapping the handler at the arg level is problematic because we need the `event` to be passed to the tracePromise.
106+
// Which is only available with `toEventHandler` and it is already called in the `on` method.
107+
// eslint-disable-next-line unicorn/prefer-at
108+
const lastRoute = instance["~routes"][instance["~routes"].length - 1];
109+
if (lastRoute) {
110+
lastRoute.handler = wrapEventHandler(lastRoute.handler);
111+
lastRoute.middleware = lastRoute.middleware?.map((m) =>
112+
wrapMiddleware(m),
113+
);
114+
}
115+
116+
return instance;
117+
};
118+
}
118119

119-
const originalUse = h3.use;
120-
h3.use = (arg1: unknown, arg2?: unknown, arg3?: unknown) => {
121-
// Middlewares should be wrapped at the arg level to avoid creating trace events for skipped wrappers added by h3
122-
let route: string | undefined;
123-
let fn: Middleware;
124-
let opts: MiddlewareOptions | undefined;
120+
if ("use" in h3 && typeof h3.use === "function") {
121+
const originalUse = h3.use;
122+
h3.use = (arg1: unknown, arg2?: unknown, arg3?: unknown) => {
123+
// Middlewares should be wrapped at the arg level to avoid creating trace events for skipped wrappers added by h3
124+
let route: string | undefined;
125+
let fn: Middleware;
126+
let opts: MiddlewareOptions | undefined;
125127

126-
if (typeof arg1 === "string") {
127-
route = arg1 as string;
128-
fn = arg2 as Middleware;
129-
opts = arg3 as MiddlewareOptions;
128+
if (typeof arg1 === "string") {
129+
route = arg1 as string;
130+
fn = arg2 as Middleware;
131+
opts = arg3 as MiddlewareOptions;
130132

131-
// @ts-expect-error - call not accepting the route signature
132-
return originalUse.call(h3, route, wrapMiddleware(fn), opts);
133-
}
133+
// @ts-expect-error - call not accepting the route signature
134+
return originalUse.call(h3, route, wrapMiddleware(fn), opts);
135+
}
134136

135-
fn = arg1 as Middleware;
136-
opts = arg2 as MiddlewareOptions;
137+
fn = arg1 as Middleware;
138+
opts = arg2 as MiddlewareOptions;
137139

138-
return originalUse.call(h3, wrapMiddleware(fn), opts);
139-
};
140+
return originalUse.call(h3, wrapMiddleware(fn), opts);
141+
};
142+
}
140143

141-
const originalMount = h3.mount;
142-
h3.mount = (base, input) => {
143-
// If the input is an H3 instance
144-
// then we can register the tracing plugin on it to propagate the tracing to the nested app
145-
if ("register" in input) {
146-
input.register(tracingPlugin(traceOpts));
147-
}
144+
if ("mount" in h3 && typeof h3.mount === "function") {
145+
const originalMount = h3.mount;
146+
h3.mount = (base, input) => {
147+
// If the input is an H3 instance
148+
// then we can register the tracing plugin on it to propagate the tracing to the nested app
149+
if ("register" in input) {
150+
input.register(tracingPlugin(traceOpts));
151+
}
148152

149-
return originalMount.call(h3, base, input);
150-
};
153+
return originalMount.call(h3, base, input);
154+
};
155+
}
151156

152157
return h3;
153158
};

0 commit comments

Comments
 (0)