@visulima/connect 1.3.4 → 1.3.5
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/CHANGELOG.md +7 -0
- package/README.md +194 -199
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## @visulima/connect [1.3.5](https://github.com/visulima/visulima/compare/@visulima/connect@1.3.4...@visulima/connect@1.3.5) (2023-05-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **nextra-theme-docs:** updates theme to be nextra compatible ([#87](https://github.com/visulima/visulima/issues/87)) ([b9fbeb2](https://github.com/visulima/visulima/commit/b9fbeb2e59d842a8755b0c8f19a67f93778ba979))
|
|
7
|
+
|
|
1
8
|
## @visulima/connect [1.3.4](https://github.com/visulima/visulima/compare/@visulima/connect@1.3.3...@visulima/connect@1.3.4) (2023-05-25)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
<p>
|
|
4
4
|
The promise-based method routing and middleware layer with zod validation for <a href="https://nextjs.org/" title="Next.js">Next.js</a> (API Routes, Edge API Routes, getServerSideProps, Middleware) and many other frameworks is built on top of
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
[next-connect](https://github.com/hoangvvo/next-connect),
|
|
7
|
+
[http-errors](https://github.com/jshttp/http-errors),
|
|
8
|
+
[regexparam](https://github.com/lukeed/regexparam)
|
|
10
9
|
|
|
11
10
|
</p>
|
|
12
11
|
</div>
|
|
@@ -33,11 +32,11 @@
|
|
|
33
32
|
|
|
34
33
|
## Features
|
|
35
34
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
35
|
+
- Async middleware
|
|
36
|
+
- [Lightweight](https://bundlephobia.com/scan-results?packages=express,@visulima/connect,koa,micro) => Suitable for serverless environment
|
|
37
|
+
- [way faster](https://github.com/visulima/packages/connect/tree/main/bench) than Express.js. Compatible with Express.js via [a wrapper](#expressjs-compatibility).
|
|
38
|
+
- Works with async handlers (with error catching)
|
|
39
|
+
- TypeScript support
|
|
41
40
|
|
|
42
41
|
## Installation
|
|
43
42
|
|
|
@@ -72,44 +71,44 @@ import cors from "cors";
|
|
|
72
71
|
// Default Req and Res are IncomingMessage and ServerResponse
|
|
73
72
|
// You may want to pass in NextApiRequest and NextApiResponse
|
|
74
73
|
const router = createNodeRouter<NextApiRequest, NextApiResponse>({
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
onError: (err, req, res) => {
|
|
75
|
+
console.error(err.stack);
|
|
76
|
+
res.status(500).end("Something broke!");
|
|
77
|
+
},
|
|
78
|
+
onNoMatch: (req, res) => {
|
|
79
|
+
res.status(404).end("Page is not found");
|
|
80
|
+
},
|
|
82
81
|
});
|
|
83
82
|
|
|
84
83
|
router
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
84
|
+
.use(expressWrapper(cors())) // express middleware are supported if you wrap it with expressWrapper
|
|
85
|
+
.use(async (req, res, next) => {
|
|
86
|
+
const start = Date.now();
|
|
87
|
+
await next(); // call next in chain
|
|
88
|
+
const end = Date.now();
|
|
89
|
+
console.log(`Request took ${end - start}ms`);
|
|
90
|
+
})
|
|
91
|
+
.get((req, res) => {
|
|
92
|
+
res.send("Hello world");
|
|
93
|
+
})
|
|
94
|
+
.post(async (req, res) => {
|
|
95
|
+
// use async/await
|
|
96
|
+
const user = await insertUser(req.body.user);
|
|
97
|
+
res.json({ user });
|
|
98
|
+
})
|
|
99
|
+
.put(
|
|
100
|
+
async (req, res, next) => {
|
|
101
|
+
// You may want to pass in NextApiRequest & { isLoggedIn: true }
|
|
102
|
+
// in createNodeRouter generics to define this extra property
|
|
103
|
+
if (!req.isLoggedIn) throw new Error("thrown stuff will be caught");
|
|
104
|
+
// go to the next in chain
|
|
105
|
+
return next();
|
|
106
|
+
},
|
|
107
|
+
async (req, res) => {
|
|
108
|
+
const user = await updateUser(req.body.user);
|
|
109
|
+
res.json({ user });
|
|
110
|
+
},
|
|
111
|
+
);
|
|
113
112
|
|
|
114
113
|
export default router.nodeHandler();
|
|
115
114
|
```
|
|
@@ -121,45 +120,45 @@ export default router.nodeHandler();
|
|
|
121
120
|
import { createNodeRouter } from "@visulima/connect";
|
|
122
121
|
|
|
123
122
|
export default function Page({ user, updated }) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
123
|
+
return (
|
|
124
|
+
<div>
|
|
125
|
+
{updated && <p>User has been updated</p>}
|
|
126
|
+
<div>{JSON.stringify(user)}</div>
|
|
127
|
+
<form method="POST">{/* User update form */}</form>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
const router = createNodeRouter()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
133
|
+
.use(async (req, res, next) => {
|
|
134
|
+
// this serve as the error handling middleware
|
|
135
|
+
try {
|
|
136
|
+
return await next();
|
|
137
|
+
} catch (e) {
|
|
138
|
+
return {
|
|
139
|
+
props: { error: e.message },
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
.use(async (req, res, next) => {
|
|
144
|
+
logRequest(req);
|
|
145
|
+
return next();
|
|
146
|
+
})
|
|
147
|
+
.get(async (req, res) => {
|
|
148
|
+
const user = await getUser(req.params.id);
|
|
149
|
+
if (!user) {
|
|
150
|
+
// https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#notfound
|
|
151
|
+
return { props: { notFound: true } };
|
|
152
|
+
}
|
|
153
|
+
return { props: { user } };
|
|
154
|
+
})
|
|
155
|
+
.post(async (req, res) => {
|
|
156
|
+
const user = await updateUser(req);
|
|
157
|
+
return { props: { user, updated: true } };
|
|
158
|
+
});
|
|
160
159
|
|
|
161
160
|
export async function getServerSideProps({ req, res }) {
|
|
162
|
-
|
|
161
|
+
return router.run(req, res);
|
|
163
162
|
}
|
|
164
163
|
```
|
|
165
164
|
|
|
@@ -175,50 +174,50 @@ import cors from "cors";
|
|
|
175
174
|
// Default Req and Evt are Request and unknown
|
|
176
175
|
// You may want to pass in NextRequest and NextFetchEvent
|
|
177
176
|
const router = createEdgeRouter<NextRequest, NextFetchEvent>({
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
177
|
+
onError: (err, req, evt) => {
|
|
178
|
+
console.error(err.stack);
|
|
179
|
+
return new NextResponse("Something broke!", {
|
|
180
|
+
status: 500,
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
onNoMatch: (req, res) => {
|
|
184
|
+
return new NextResponse("Page is not found", {
|
|
185
|
+
status: 404,
|
|
186
|
+
});
|
|
187
|
+
},
|
|
189
188
|
});
|
|
190
189
|
|
|
191
190
|
router
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
191
|
+
.use(expressWrapper(cors())) // express middleware are supported if you wrap it with expressWrapper
|
|
192
|
+
.use(async (req, evt, next) => {
|
|
193
|
+
const start = Date.now();
|
|
194
|
+
await next(); // call next in chain
|
|
195
|
+
const end = Date.now();
|
|
196
|
+
console.log(`Request took ${end - start}ms`);
|
|
197
|
+
})
|
|
198
|
+
.get((req, res) => {
|
|
199
|
+
return new Response("Hello world");
|
|
200
|
+
})
|
|
201
|
+
.post(async (req, res) => {
|
|
202
|
+
// use async/await
|
|
203
|
+
const user = await insertUser(req.body.user);
|
|
204
|
+
res.json({ user });
|
|
205
|
+
return new Response(JSON.stringify({ user }), {
|
|
206
|
+
status: 200,
|
|
207
|
+
headerList: {
|
|
208
|
+
"content-type": "application/json",
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
})
|
|
212
|
+
.put(async (req, res) => {
|
|
213
|
+
const user = await updateUser(req.body.user);
|
|
214
|
+
return new Response(JSON.stringify({ user }), {
|
|
215
|
+
status: 200,
|
|
216
|
+
headerList: {
|
|
217
|
+
"content-type": "application/json",
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
220
|
});
|
|
221
|
-
});
|
|
222
221
|
|
|
223
222
|
export default router.nodeHandler();
|
|
224
223
|
```
|
|
@@ -238,28 +237,28 @@ import { createEdgeRouter } from "@visulima/connect";
|
|
|
238
237
|
const router = createEdgeRouter<NextRequest, NextFetchEvent>();
|
|
239
238
|
|
|
240
239
|
router.use(async (request, _, next) => {
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
await logRequest(request);
|
|
241
|
+
return next();
|
|
243
242
|
});
|
|
244
243
|
|
|
245
244
|
router.get("/about", (request) => {
|
|
246
|
-
|
|
245
|
+
return NextResponse.redirect(new URL("/about-2", request.url));
|
|
247
246
|
});
|
|
248
247
|
|
|
249
248
|
router.use("/dashboard", (request) => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
if (!isAuthenticated(request)) {
|
|
250
|
+
return NextResponse.redirect(new URL("/login", request.url));
|
|
251
|
+
}
|
|
252
|
+
return NextResponse.next();
|
|
254
253
|
});
|
|
255
254
|
|
|
256
255
|
router.all((request) => {
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
// default if none of the above matches
|
|
257
|
+
return NextResponse.next();
|
|
259
258
|
});
|
|
260
259
|
|
|
261
260
|
export function middleware(request: NextRequest) {
|
|
262
|
-
|
|
261
|
+
return NextResponse.redirect(new URL("/about-2", request.url));
|
|
263
262
|
}
|
|
264
263
|
```
|
|
265
264
|
|
|
@@ -277,8 +276,8 @@ Create an instance Node.js router.
|
|
|
277
276
|
|
|
278
277
|
`fn`(s) can either be:
|
|
279
278
|
|
|
280
|
-
-
|
|
281
|
-
-
|
|
279
|
+
- functions of `(req, res[, next])`
|
|
280
|
+
- **or** a router instance
|
|
282
281
|
|
|
283
282
|
```javascript
|
|
284
283
|
// Mount a middleware function
|
|
@@ -294,11 +293,7 @@ router2.use("/foo", fn); // Only run in /foo/**
|
|
|
294
293
|
// mount an instance of router
|
|
295
294
|
const sub1 = createNodeRouter().use(fn1, fn2);
|
|
296
295
|
const sub2 = createNodeRouter().use("/dashboard", auth);
|
|
297
|
-
const sub3 = createNodeRouter()
|
|
298
|
-
.use("/waldo", subby)
|
|
299
|
-
.get(getty)
|
|
300
|
-
.post("/baz", posty)
|
|
301
|
-
.put("/", putty);
|
|
296
|
+
const sub3 = createNodeRouter().use("/waldo", subby).get(getty).post("/baz", posty).put("/", putty);
|
|
302
297
|
router3
|
|
303
298
|
// - fn1 and fn2 always run
|
|
304
299
|
// - auth runs only on /dashboard
|
|
@@ -320,20 +315,20 @@ router3
|
|
|
320
315
|
|
|
321
316
|
```javascript
|
|
322
317
|
router.get("/api/user", (req, res, next) => {
|
|
323
|
-
|
|
318
|
+
res.json(req.user);
|
|
324
319
|
});
|
|
325
320
|
router.post("/api/users", (req, res, next) => {
|
|
326
|
-
|
|
321
|
+
res.end("User created");
|
|
327
322
|
});
|
|
328
323
|
router.put("/api/user/:id", (req, res, next) => {
|
|
329
|
-
|
|
330
|
-
|
|
324
|
+
// https://nextjs.org/docs/routing/dynamic-routes
|
|
325
|
+
res.end(`User ${req.params.id} updated`);
|
|
331
326
|
});
|
|
332
327
|
|
|
333
328
|
// Next.js already handles routing (including dynamic routes), we often
|
|
334
329
|
// omit `pattern` in `.METHOD`
|
|
335
330
|
router.get((req, res, next) => {
|
|
336
|
-
|
|
331
|
+
res.end("This matches whatever route");
|
|
337
332
|
});
|
|
338
333
|
```
|
|
339
334
|
|
|
@@ -361,7 +356,7 @@ function onError(err, req, res) {
|
|
|
361
356
|
res.status(500).end("Internal server error");
|
|
362
357
|
}
|
|
363
358
|
|
|
364
|
-
const router = createNodeRouter({onError});
|
|
359
|
+
const router = createNodeRouter({ onError });
|
|
365
360
|
|
|
366
361
|
export default router.nodeHandler();
|
|
367
362
|
```
|
|
@@ -376,7 +371,7 @@ function onNoMatch(req, res) {
|
|
|
376
371
|
res.status(404).end("page is not found... or is it!?");
|
|
377
372
|
}
|
|
378
373
|
|
|
379
|
-
const router = createNodeRouter({onNoMatch});
|
|
374
|
+
const router = createNodeRouter({ onNoMatch });
|
|
380
375
|
|
|
381
376
|
export default router.nodeHandler();
|
|
382
377
|
```
|
|
@@ -387,15 +382,15 @@ Runs `req` and `res` through the middleware chain and returns a **promise**. It
|
|
|
387
382
|
|
|
388
383
|
```js
|
|
389
384
|
router
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
385
|
+
.use(async (req, res, next) => {
|
|
386
|
+
return (await next()) + 1;
|
|
387
|
+
})
|
|
388
|
+
.use(async () => {
|
|
389
|
+
return (await next()) + 2;
|
|
390
|
+
})
|
|
391
|
+
.use(async () => {
|
|
392
|
+
return 3;
|
|
393
|
+
});
|
|
399
394
|
|
|
400
395
|
console.log(await router.run(req, res));
|
|
401
396
|
// The above will print "6"
|
|
@@ -405,10 +400,10 @@ If an error in thrown within the chain, `router.run` will reject. You can also a
|
|
|
405
400
|
|
|
406
401
|
```js
|
|
407
402
|
router
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
403
|
+
.use(async (req, res, next) => {
|
|
404
|
+
return next().catch(errorHandler);
|
|
405
|
+
})
|
|
406
|
+
.use(thisMiddlewarewareMightThrow);
|
|
412
407
|
|
|
413
408
|
await router.run(req, res);
|
|
414
409
|
```
|
|
@@ -424,56 +419,56 @@ If `next()` is not awaited, errors will not be caught if they are thrown in asyn
|
|
|
424
419
|
```javascript
|
|
425
420
|
// OK: we don't use async so no need to await
|
|
426
421
|
router
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
422
|
+
.use((req, res, next) => {
|
|
423
|
+
next();
|
|
424
|
+
})
|
|
425
|
+
.use((req, res, next) => {
|
|
426
|
+
next();
|
|
427
|
+
})
|
|
428
|
+
.use(() => {
|
|
429
|
+
throw new Error("💥");
|
|
430
|
+
});
|
|
436
431
|
|
|
437
432
|
// BAD: This will lead to UnhandledPromiseRejection
|
|
438
433
|
router
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
434
|
+
.use(async (req, res, next) => {
|
|
435
|
+
next();
|
|
436
|
+
})
|
|
437
|
+
.use(async (req, res, next) => {
|
|
438
|
+
next();
|
|
439
|
+
})
|
|
440
|
+
.use(async () => {
|
|
441
|
+
throw new Error("💥");
|
|
442
|
+
});
|
|
448
443
|
|
|
449
444
|
// GOOD
|
|
450
445
|
router
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
446
|
+
.use(async (req, res, next) => {
|
|
447
|
+
await next(); // next() is awaited, so errors are caught properly
|
|
448
|
+
})
|
|
449
|
+
.use((req, res, next) => {
|
|
450
|
+
return next(); // this works as well since we forward the rejected promise
|
|
451
|
+
})
|
|
452
|
+
.use(async () => {
|
|
453
|
+
throw new Error("💥");
|
|
454
|
+
// return new Promise.reject("💥");
|
|
455
|
+
});
|
|
461
456
|
```
|
|
462
457
|
|
|
463
458
|
Another issue is that the nodeHandler would resolve before all the code in each layer runs.
|
|
464
459
|
|
|
465
460
|
```javascript
|
|
466
461
|
const nodeHandler = router
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
462
|
+
.use(async (req, res, next) => {
|
|
463
|
+
next(); // this is not returned or await
|
|
464
|
+
})
|
|
465
|
+
.get(async () => {
|
|
466
|
+
// simulate a long task
|
|
467
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
468
|
+
res.send("ok");
|
|
469
|
+
console.log("request is completed");
|
|
470
|
+
})
|
|
471
|
+
.nodeHandler();
|
|
477
472
|
|
|
478
473
|
await nodeHandler(req, res);
|
|
479
474
|
console.log("finally"); // this will run before the get layer gets to finish
|
|
@@ -533,7 +528,7 @@ const nodeHandler = createNodeRouter()
|
|
|
533
528
|
res.end("bar");
|
|
534
529
|
});
|
|
535
530
|
|
|
536
|
-
export async function getServerSideProps({req, res}) {
|
|
531
|
+
export async function getServerSideProps({ req, res }) {
|
|
537
532
|
await router.run(req, res);
|
|
538
533
|
return {
|
|
539
534
|
props: {},
|
|
@@ -548,7 +543,7 @@ export async function getServerSideProps({req, res}) {
|
|
|
548
543
|
const router = createNodeRouter().use(foo).use(bar);
|
|
549
544
|
const nodeHandler = router.nodeHandler();
|
|
550
545
|
|
|
551
|
-
export async function getServerSideProps({req, res}) {
|
|
546
|
+
export async function getServerSideProps({ req, res }) {
|
|
552
547
|
await nodeHandler(req, res); // BAD: You should call router.run(req, res);
|
|
553
548
|
return {
|
|
554
549
|
props: {},
|
|
@@ -572,10 +567,10 @@ If you need to create all handlers for all routes in one file (similar to `Expre
|
|
|
572
567
|
import { createNodeRouter } from "@visulima/connect";
|
|
573
568
|
|
|
574
569
|
const router = createNodeRouter()
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
570
|
+
.use("/api/hello", someMiddleware())
|
|
571
|
+
.get("/api/user/:userId", (req, res) => {
|
|
572
|
+
res.send(`Hello ${req.params.userId}`);
|
|
573
|
+
});
|
|
579
574
|
|
|
580
575
|
export default router.nodeHandler();
|
|
581
576
|
```
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["createHttpError","ZodError","withZod","schema","handler","request","response","next","transformedRequest","error","message","issue","with_zod_default","parse","Router","base","routes","method","route","fns","keys","pattern","function_","arguments_","index","pathname","middleOnly","parameters","isHead","matched","matches","key","parameterKey","stripPathname","result","onNoMatch","onError","getPathname","EdgeRouter","options","__publicField","routeOrFunction","zodOrRouteOrFunction","findResult","r","context_","createEdgeRouter","expressWrapper","resolve","reject","express_default","_request","url","queryIndex","NodeRouter","createRouter","sendJson","statusCode","jsonBody","send_json_default"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\nimport { ZodError } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request,\n Response,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n public constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: Nextable<H> | RouteMatch, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: Nextable<H> | RouteMatch | Router<H>, ...fns: (Nextable<H> | Router<H>)[]): this {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string): Router<H> {\n return new Router<H>(base, [...this.routes]);\n }\n\n public static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n public find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-expect-error @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-expect-error @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const { base } = function_;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (!stripPathname.startsWith(\"/\")) {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }): string {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl ?? new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len,@typescript-eslint/no-invalid-void-type\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n ?? (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<R, Context>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<R, Context>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>> | RouteMatch,\n ...fns: (EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base as EdgeRouter<R, Context>);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): EdgeRouter<R, Context, RResponse, Schema> {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: R, context_: Context): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n public handler(): (request: R, context_: Context) => Promise<any> | ReturnType<FunctionLike> | ValueOrPromise<RResponse> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n): EdgeRouter<R, Context> {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch;\n this.onError = options.onError ?? onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<Request, Response>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<Request, Response>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema> | RouteMatch,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): NodeRouter<Request, Response, Schema> {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n public handler(): (request: Request, response: Response) => Promise<void> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ): NodeRouter<Request, Response, Schema> => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: unknown): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["createHttpError","ZodError","withZod","schema","handler","request","response","next","transformedRequest","error","message","issue","with_zod_default","parse","Router","base","routes","method","route","fns","keys","pattern","function_","arguments_","index","pathname","middleOnly","parameters","isHead","matched","matches","key","parameterKey","stripPathname","result","onNoMatch","onError","getPathname","EdgeRouter","options","__publicField","routeOrFunction","zodOrRouteOrFunction","findResult","r","context_","createEdgeRouter","expressWrapper","resolve","reject","express_default","_request","url","queryIndex","NodeRouter","createRouter","sendJson","statusCode","jsonBody","send_json_default"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\nimport { ZodError } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\n// eslint-disable-next-line max-len\nconst withZod = <Request, Response, Handler extends Nextable<any>, Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>>(\n schema: Schema,\n handler: Handler,\n): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n public constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: Nextable<H> | RouteMatch, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: Nextable<H> | RouteMatch | Router<H>, ...fns: (Nextable<H> | Router<H>)[]): this {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string): Router<H> {\n return new Router<H>(base, [...this.routes]);\n }\n\n public static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n public find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-expect-error @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-expect-error @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const { base } = function_;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (!stripPathname.startsWith(\"/\")) {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }): string {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl ?? new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len,@typescript-eslint/no-invalid-void-type\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? (onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>);\n this.onError = options.onError\n ?? (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<R, Context>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<R, Context>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>> | RouteMatch,\n ...fns: (EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base as EdgeRouter<R, Context>);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): EdgeRouter<R, Context, RResponse, Schema> {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: R, context_: Context): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n public handler(): (request: R, context_: Context) => Promise<any> | ReturnType<FunctionLike> | ValueOrPromise<RResponse> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n): EdgeRouter<R, Context> {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch;\n this.onError = options.onError ?? onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<Request, Response>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<Request, Response>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema> | RouteMatch,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): NodeRouter<Request, Response, Schema> {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n public handler(): (request: Request, response: Response) => Promise<void> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ): NodeRouter<Request, Response, Schema> => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: unknown): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["createHttpError","ZodError","withZod","schema","handler","request","response","next","transformedRequest","error","message","issue","with_zod_default","parse","Router","base","routes","method","route","fns","keys","pattern","function_","arguments_","index","pathname","middleOnly","parameters","isHead","matched","matches","key","parameterKey","stripPathname","result","onNoMatch","onError","getPathname","EdgeRouter","options","__publicField","routeOrFunction","zodOrRouteOrFunction","findResult","r","context_","createEdgeRouter","expressWrapper","resolve","reject","express_default","_request","url","queryIndex","NodeRouter","createRouter","sendJson","statusCode","jsonBody","send_json_default"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\nimport { ZodError } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request,\n Response,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n public constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: Nextable<H> | RouteMatch, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: Nextable<H> | RouteMatch | Router<H>, ...fns: (Nextable<H> | Router<H>)[]): this {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string): Router<H> {\n return new Router<H>(base, [...this.routes]);\n }\n\n public static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n public find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-expect-error @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-expect-error @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const { base } = function_;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (!stripPathname.startsWith(\"/\")) {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }): string {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl ?? new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len,@typescript-eslint/no-invalid-void-type\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n ?? (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<R, Context>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<R, Context>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>> | RouteMatch,\n ...fns: (EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base as EdgeRouter<R, Context>);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): EdgeRouter<R, Context, RResponse, Schema> {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: R, context_: Context): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n public handler(): (request: R, context_: Context) => Promise<any> | ReturnType<FunctionLike> | ValueOrPromise<RResponse> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n): EdgeRouter<R, Context> {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch;\n this.onError = options.onError ?? onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<Request, Response>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<Request, Response>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema> | RouteMatch,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): NodeRouter<Request, Response, Schema> {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n public handler(): (request: Request, response: Response) => Promise<void> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ): NodeRouter<Request, Response, Schema> => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: unknown): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["createHttpError","ZodError","withZod","schema","handler","request","response","next","transformedRequest","error","message","issue","with_zod_default","parse","Router","base","routes","method","route","fns","keys","pattern","function_","arguments_","index","pathname","middleOnly","parameters","isHead","matched","matches","key","parameterKey","stripPathname","result","onNoMatch","onError","getPathname","EdgeRouter","options","__publicField","routeOrFunction","zodOrRouteOrFunction","findResult","r","context_","createEdgeRouter","expressWrapper","resolve","reject","express_default","_request","url","queryIndex","NodeRouter","createRouter","sendJson","statusCode","jsonBody","send_json_default"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\nimport { ZodError } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\n// eslint-disable-next-line max-len\nconst withZod = <Request, Response, Handler extends Nextable<any>, Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>>(\n schema: Schema,\n handler: Handler,\n): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n public constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: Nextable<H> | RouteMatch, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: Nextable<H> | RouteMatch | Router<H>, ...fns: (Nextable<H> | Router<H>)[]): this {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string): Router<H> {\n return new Router<H>(base, [...this.routes]);\n }\n\n public static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n public find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line sonarjs/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-expect-error @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-expect-error @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const { base } = function_;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (!stripPathname.startsWith(\"/\")) {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }): string {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl ?? new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len,@typescript-eslint/no-invalid-void-type\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? (onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>);\n this.onError = options.onError\n ?? (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<R, Context>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<R, Context>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>> | RouteMatch,\n ...fns: (EdgeRouter<R, Context> | Nextable<RequestHandler<R, Context>>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base as EdgeRouter<R, Context>);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): EdgeRouter<R, Context, RResponse, Schema> {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: R, context_: Context): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n public handler(): (request: R, context_: Context) => Promise<any> | ReturnType<FunctionLike> | ValueOrPromise<RResponse> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n): EdgeRouter<R, Context> {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject, ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string): string {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n public constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch ?? onNoMatch;\n this.onError = options.onError ?? onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: Nextable<RequestHandler<Request, Response>> | RouteMatch,\n zodOrRouteOrFunction?: Nextable<RequestHandler<Request, Response>> | RouteMatch | Schema,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema> | RouteMatch,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ): this {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone(): NodeRouter<Request, Response, Schema> {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n public async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n public handler(): (request: Request, response: Response) => Promise<void> {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ): NodeRouter<Request, Response, Schema> => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: unknown): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/connect",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"description": "The minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2 with support for zod validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"javascript",
|
|
@@ -77,11 +77,11 @@
|
|
|
77
77
|
"@anolilab/semantic-release-preset": "^2.2.1",
|
|
78
78
|
"@rushstack/eslint-plugin-security": "^0.6.0",
|
|
79
79
|
"@types/http-errors": "^2.0.1",
|
|
80
|
-
"@types/node": "18.16.
|
|
80
|
+
"@types/node": "18.16.16",
|
|
81
81
|
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
|
82
82
|
"@typescript-eslint/parser": "^5.59.7",
|
|
83
83
|
"@vitest/coverage-c8": "^0.31.1",
|
|
84
|
-
"c8": "^7.
|
|
84
|
+
"c8": "^7.14.0",
|
|
85
85
|
"cross-env": "^7.0.3",
|
|
86
86
|
"eslint": "^8.41.0",
|
|
87
87
|
"eslint-plugin-compat": "^4.1.4",
|
|
@@ -107,7 +107,6 @@
|
|
|
107
107
|
"fastify": "^4.17.0",
|
|
108
108
|
"isomorphic-fetch": "^3.0.0",
|
|
109
109
|
"prettier": "^2.8.8",
|
|
110
|
-
"read-pkg": "^8.0.0",
|
|
111
110
|
"rimraf": "^5.0.1",
|
|
112
111
|
"semantic-release": "^21.0.2",
|
|
113
112
|
"tsup": "^6.7.0",
|