Skip to content

Commit 644edd2

Browse files
committed
fix: wrap findRoute with tracing wrapper
1 parent e2f8cbd commit 644edd2

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

src/tracing.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ export function tracingPlugin(traceOpts?: TracingPluginOptions): H3Plugin {
8383
} satisfies H3Route;
8484
});
8585

86+
// Wrap route handlers returned by ~findRoute so frameworks that resolve
87+
// routes at request time (e.g. nitro file-based routes) without pushing
88+
// into ~routes still emit route traces. Use a getter/setter so later
89+
// reassignment of ~findRoute remains wrapped.
90+
let originalFindRoute = h3["~findRoute"];
91+
const wrappedFindRoute = (event: H3Event) => {
92+
const route = originalFindRoute.call(h3, event);
93+
if (route?.data.handler) {
94+
route.data.handler = wrapEventHandler(route.data.handler);
95+
}
96+
if (route?.data.middleware) {
97+
route.data.middleware = route.data.middleware.map((m) => wrapMiddleware(m));
98+
}
99+
return route;
100+
};
101+
Object.defineProperty(h3, "~findRoute", {
102+
configurable: true,
103+
enumerable: true,
104+
get: () => wrappedFindRoute,
105+
set: (fn: typeof originalFindRoute) => {
106+
originalFindRoute = fn;
107+
},
108+
});
109+
86110
if ("on" in h3 && typeof h3.on === "function") {
87111
const originalOn = h3.on;
88112

test/tracing.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,4 +1156,50 @@ describe("tracing channels for H3Core instances", () => {
11561156
listener.cleanup();
11571157
}
11581158
});
1159+
1160+
it("traces handlers returned from a custom ~findRoute (nitro-style file routes)", async () => {
1161+
const listener = createTracingListener();
1162+
const { H3Core } = await import("../src/h3.ts");
1163+
const { tracingPlugin } = await import("../src/tracing.ts");
1164+
const { H3Event } = await import("../src/event.ts");
1165+
1166+
try {
1167+
const app = new H3Core();
1168+
const routeHandler = () => "file-based response";
1169+
1170+
// Simulate a framework that resolves routes at request time and never
1171+
// pushes them into app["~routes"]. The handler only exists inside the
1172+
// custom ~findRoute implementation.
1173+
app["~findRoute"] = (event: any) => {
1174+
if (event.url.pathname === "/file-route" && event.req.method === "GET") {
1175+
return {
1176+
data: {
1177+
method: "GET",
1178+
route: "/file-route",
1179+
handler: routeHandler,
1180+
},
1181+
params: {},
1182+
};
1183+
}
1184+
return undefined;
1185+
};
1186+
1187+
// Apply tracing plugin after ~findRoute is set (mirrors the order
1188+
// documented in the suggested fix).
1189+
tracingPlugin()(app as any);
1190+
1191+
const request = new Request("http://localhost/file-route", { method: "GET" });
1192+
const event = new H3Event(request, undefined, app as any);
1193+
1194+
await app.handler(event);
1195+
1196+
await new Promise((resolve) => setTimeout(resolve, 10));
1197+
1198+
const routeEvents = listener.events.filter((e) => e.asyncStart?.data.type === "route");
1199+
1200+
expect(routeEvents.length).toBeGreaterThan(0);
1201+
} finally {
1202+
listener.cleanup();
1203+
}
1204+
});
11591205
});

0 commit comments

Comments
 (0)