Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default defineBuildConfig({
"src/cli.ts",
"src/static.ts",
"src/log.ts",
"src/tracing.ts",
...[
"deno",
"bun",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"./cli": "./dist/cli.mjs",
"./static": "./dist/static.mjs",
"./log": "./dist/log.mjs",
"./tracing": "./dist/tracing.mjs",
".": {
"types": "./dist/types.d.mts",
"deno": "./dist/adapters/deno.mjs",
Expand Down
37 changes: 31 additions & 6 deletions src/_middleware.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { traceCall } from "./tracing.ts";
import type {
Server,
ServerRequest,
Expand All @@ -8,21 +9,45 @@ import type {
export function wrapFetch(server: Server): ServerHandler {
const fetchHandler = server.options.fetch;
const middleware = server.options.middleware || [];
return middleware.length === 0
? fetchHandler
: (request) => callMiddleware(request, fetchHandler, middleware, 0);

if (middleware.length === 0) {
return (request) =>
traceCall("fetch", async () => await fetchHandler(request), {
request,
server,
});
}

return (request) =>
callMiddleware(server, request, fetchHandler, middleware, 0);
}

function callMiddleware(
server: Server,
request: ServerRequest,
fetchHandler: ServerHandler,
middleware: ServerMiddleware[],
index: number,
): Response | Promise<Response> {
if (index === middleware.length) {
return fetchHandler(request);
return traceCall("fetch", async () => await fetchHandler(request), {
request,
server,
});
}
return middleware[index](request, () =>
callMiddleware(request, fetchHandler, middleware, index + 1),

const currentMiddleware = middleware[index];
const next = () =>
callMiddleware(server, request, fetchHandler, middleware, index + 1);

return traceCall(
"middleware",
async () => await currentMiddleware(request, next),
{
request,
server,
index,
name: currentMiddleware?.name,
},
);
}
42 changes: 42 additions & 0 deletions src/tracing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { tracingChannel, type TracingChannel } from "node:diagnostics_channel";
import type { Server, ServerRequest } from "./types.ts";

export type TraceDataMap = {
fetch: { request: ServerRequest; server: Server };
middleware: {
request: ServerRequest;
server: Server;
index: number;
name?: string;
};
};

export type TraceChannelName = keyof TraceDataMap;

const channels: Record<
TraceChannelName,
TracingChannel<unknown, TraceDataMap[TraceChannelName]>
> = {
fetch: tracingChannel("srvx.fetch"),
middleware: tracingChannel("srvx.middleware"),
};

export function traceCall<
TChannel extends TraceChannelName,
TReturn,
TData extends TraceDataMap[TChannel],
>(
channel: TChannel,
exec: () => Promise<TReturn>,
data: TData,
): Promise<TReturn> {
return channels[channel].tracePromise(exec, data);
}

export function traceSync<
TChannel extends TraceChannelName,
TReturn,
TData extends TraceDataMap[TChannel],
>(channel: TChannel, exec: () => TReturn, data: TData): TReturn {
return channels[channel].traceSync(exec, data);
}
Loading