context-router 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/router.ts ADDED
@@ -0,0 +1,102 @@
1
+ type HttpMethod = "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
2
+
3
+ // Request handler parameters: request data and context
4
+ export type HandlerParams<Context extends Record<string, any> = {}> = {
5
+ body: string;
6
+ urlParams: Record<string, string | undefined>;
7
+ searchParams: URLSearchParams;
8
+ } & Context;
9
+
10
+ // Route handler: accepts request data and context, returns sync or async response
11
+ export type Handler<Context extends Record<string, any> = {}> = (
12
+ params: HandlerParams<Context>,
13
+ ) => Response | Promise<Response>;
14
+
15
+ // HTTP router with URLPattern-based matching and context injection
16
+ export class Router<Context extends Record<string, any> = {}> {
17
+ private routes: Record<
18
+ HttpMethod,
19
+ { pattern: URLPattern; handler: Handler<Context> }[]
20
+ > = {
21
+ GET: [],
22
+ POST: [],
23
+ DELETE: [],
24
+ PATCH: [],
25
+ PUT: [],
26
+ };
27
+
28
+ private notFoundHandler: Handler<Context> = (
29
+ _params: HandlerParams<Context>,
30
+ ) => new Response("Not Found", { status: 404 });
31
+
32
+ // Override the not found handler
33
+ setNotFoundHandler = (handler: Handler<Context>) => {
34
+ this.notFoundHandler = handler;
35
+ return this;
36
+ };
37
+
38
+ // Register route: creates URLPattern, stores handler, enables chaining
39
+ add = (
40
+ method: HttpMethod,
41
+ pathname: string,
42
+ handler: Handler<Context>,
43
+ ): Router<Context> => {
44
+ this.routes[method].push({
45
+ pattern: new URLPattern({ pathname }),
46
+ handler,
47
+ });
48
+ return this;
49
+ };
50
+
51
+ // Match request: iterate routes by method, invoke first match
52
+ match = async (request: Request, context: Context): Promise<Response> => {
53
+ const method = request.method.toUpperCase() as HttpMethod;
54
+ const possibleRoutes = this.routes[method] || [];
55
+ const body = await request.text();
56
+ const { searchParams, pathname } = new URL(request.url);
57
+
58
+ for (const route of possibleRoutes) {
59
+ const result = route.pattern.exec({ pathname });
60
+ if (result !== null) {
61
+ return route.handler({
62
+ body,
63
+ urlParams: result.pathname.groups,
64
+ searchParams,
65
+ ...context,
66
+ });
67
+ }
68
+ }
69
+
70
+ return this.notFoundHandler({
71
+ body,
72
+ urlParams: {},
73
+ searchParams,
74
+ ...context,
75
+ });
76
+ };
77
+
78
+ // Helper method for GET requests
79
+ get = (pathname: string, handler: Handler<Context>): Router<Context> => {
80
+ return this.add("GET", pathname, handler);
81
+ };
82
+
83
+ // Helper method for POST requests
84
+ post = (pathname: string, handler: Handler<Context>): Router<Context> => {
85
+ return this.add("POST", pathname, handler);
86
+ };
87
+
88
+ // Helper method for PUT requests
89
+ put = (pathname: string, handler: Handler<Context>): Router<Context> => {
90
+ return this.add("PUT", pathname, handler);
91
+ };
92
+
93
+ // Helper method for PATCH requests
94
+ patch = (pathname: string, handler: Handler<Context>): Router<Context> => {
95
+ return this.add("PATCH", pathname, handler);
96
+ };
97
+
98
+ // Helper method for DELETE requests
99
+ delete = (pathname: string, handler: Handler<Context>): Router<Context> => {
100
+ return this.add("DELETE", pathname, handler);
101
+ };
102
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ES2020",
5
+ "moduleResolution": "node",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "./src",
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "resolveJsonModule": true,
16
+ "sourceMap": true,
17
+ "types": ["node"]
18
+ },
19
+ "include": [
20
+ "src"
21
+ ],
22
+ "exclude": [
23
+ "node_modules",
24
+ "dist"
25
+ ]
26
+ }