-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmiddleware.ts
More file actions
84 lines (76 loc) · 2.64 KB
/
Copy pathmiddleware.ts
File metadata and controls
84 lines (76 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// basic middleware utility to wrap routes with middlewares
// inspired from https://github.com/oven-sh/bun/issues/17608
import type { BunRequest, Serve, Server } from "bun";
type Route<R extends string, Path extends R> = Serve.Routes<any, R>[Path];
export type RequestMiddleware<Path extends string> = (
req: BunRequest<Path>,
server: Server<any>,
handler: Serve.Handler<BunRequest<Path>, any, any>,
) => Response | Promise<Response>;
export type ResponseMiddleware = (
response: Response,
request: Request,
server: Server<any>,
) => Response | Promise<Response>;
export function withMiddlewares<R extends string, Path extends R>(
routes: Serve.Routes<any, R>,
middlewares: {
beforeRequest: RequestMiddleware<Path>[];
beforeResponse: ResponseMiddleware[];
} = { beforeRequest: [], beforeResponse: [] },
config: { corsEnabled?: boolean } = {},
): Serve.Routes<any, R> {
function wrapRoute<R extends string, Path extends R>(
value: Route<R, Path>,
route: R,
): Route<R, Path> {
if (typeof value === "function") {
return wrapRouteHandler(value) as Route<R, Path>;
} else if (value instanceof Response) {
return wrapRouteHandler(() => value) as Route<R, Path>;
} else if (Object.getPrototypeOf(value) === Object.prototype) {
// Value is an object with HTTP method properties
const methods = Object.entries(value);
if (config.corsEnabled) {
methods.push(["OPTIONS", () => {}]); // declare the OPTIONS route. It will be processed by CORS middleware
}
return Object.fromEntries(
methods.map(([method, val]) => [method, wrapRoute(val, method)]),
) as Route<R, Path>;
}
throw new Error(
`Unsupported route value type: ${typeof value} for route ${value}`,
);
}
function wrapRouteHandler<Path extends string>(
handler: Serve.Handler<BunRequest<Path>, any, any>,
): Serve.Handler<BunRequest<Path>, any, any> {
return async (req: BunRequest<Path>, server: Server<any>) => {
for (const middleware of middlewares.beforeRequest) {
const result = await middleware(
req as BunRequest<any>,
server,
handler as Serve.Handler<BunRequest<any>, any, any>,
);
if (result instanceof Response) {
return result;
}
}
const response = await handler(req, server);
let finalResponse = response;
for (const middleware of middlewares.beforeResponse) {
const result = await middleware(finalResponse, req, server);
if (result instanceof Response) {
finalResponse = result;
}
}
return finalResponse;
};
}
return Object.fromEntries(
Object.entries(routes).map(([route, value]) => [
route,
wrapRoute(value, route as keyof R & string),
]),
) as Serve.Routes<any, R>;
}