cpeak 2.7.0 → 2.9.0
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/README.md +120 -72
- package/dist/index.d.ts +59 -48
- package/dist/index.js +484 -174
- package/dist/index.js.map +1 -1
- package/lib/index.ts +132 -121
- package/lib/internal/errors.ts +51 -0
- package/lib/internal/mimeTypes.ts +31 -0
- package/lib/internal/router.ts +259 -0
- package/lib/types.ts +29 -25
- package/lib/utils/render.ts +142 -59
- package/lib/utils/serveStatic.ts +35 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/cpeak)
|
|
4
4
|
|
|
5
|
-
Cpeak is a minimal and fast Node.js framework inspired by Express.js.
|
|
5
|
+
Cpeak is a minimal and fast Node.js framework inspired by Express.js & Fastify.
|
|
6
6
|
|
|
7
|
-
This project is designed to be improved until it's ready for use in complex production applications, aiming to be more performant and
|
|
7
|
+
This project is designed to be improved until it's ready for use in complex production applications, aiming to be more performant and have a cleaner structure than Express.js and other common frameworks.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Cpeak replaces Express.js, body-parser, cookie-parser, compression, CORS, Passport and more, in one zero-dependency package. You can use it as a drop-in replacement for Express.js, and many npm packages that work with Express.js will also work with Cpeak.
|
|
10
|
+
|
|
11
|
+
Cpeak currently has almost all the features of Express.js, with roughly the same performance as Fastify. Additionally, it has a codebase that you can easily navigate, audit and change if you want. *Benchmarks and test results, and videos on navigating and understanding the codebase will be added soon.*
|
|
12
|
+
|
|
13
|
+
While Cpeak is being built for production, it is also an educational project that was started as part of the [Understanding Node.js: Core Concepts](https://www.udemy.com/course/understanding-nodejs-core-concepts/?referralCode=0BC21AC4DD6958AE6A95) course. If you want to learn how to build a framework like this, and get to a point where you can build things like this yourself and beyond, check out this course!
|
|
10
14
|
|
|
11
15
|
## Why Cpeak?
|
|
12
16
|
|
|
@@ -25,9 +29,11 @@ This is an educational project that was started as part of the [Understanding No
|
|
|
25
29
|
- [Middleware](#middleware)
|
|
26
30
|
- [Route Handling](#route-handling)
|
|
27
31
|
- [Route Middleware](#route-middleware)
|
|
32
|
+
- [Fallback Handler](#fallback-handler)
|
|
28
33
|
- [URL Variables & Parameters](#url-variables--parameters)
|
|
29
34
|
- [Sending Files](#sending-files)
|
|
30
35
|
- [Redirecting](#redirecting)
|
|
36
|
+
- [MIME Types](#mime-types)
|
|
31
37
|
- [Compression](#compression)
|
|
32
38
|
- [Error Handling](#error-handling)
|
|
33
39
|
- [Listening](#listening)
|
|
@@ -60,7 +66,7 @@ import cpeak from "cpeak";
|
|
|
60
66
|
const server = cpeak();
|
|
61
67
|
|
|
62
68
|
server.route("get", "/", (req, res) => {
|
|
63
|
-
res.json({ message: "Hi there!" });
|
|
69
|
+
return res.json({ message: "Hi there!" });
|
|
64
70
|
});
|
|
65
71
|
|
|
66
72
|
server.listen(3000, () => {
|
|
@@ -127,13 +133,13 @@ server.beforeEach((req, res, next) => {
|
|
|
127
133
|
You can also add middleware functions for a particular route handler like this:
|
|
128
134
|
|
|
129
135
|
```javascript
|
|
130
|
-
const requireAuth = (req, res, next
|
|
136
|
+
const requireAuth = (req, res, next) => {
|
|
131
137
|
// Check if user is logged in, if so then:
|
|
132
138
|
req.test = "this is a test value";
|
|
133
139
|
next();
|
|
134
140
|
|
|
135
141
|
// If user is not logged in:
|
|
136
|
-
|
|
142
|
+
throw { status: 401, message: "Unauthorized" };
|
|
137
143
|
};
|
|
138
144
|
|
|
139
145
|
server.route("get", "/profile", requireAuth, (req, res) => {
|
|
@@ -168,6 +174,20 @@ server.route("patch", "/the-path-you-want", (req, res) => {
|
|
|
168
174
|
|
|
169
175
|
First add the HTTP method name you want to handle, then the path, and finally, the callback. The `req` and `res` object types are the same as in the Node.js HTTP module (`http.IncomingMessage` and `http.ServerResponse`). You can read more about them in the [official Node.js documentation](https://nodejs.org/docs/latest/api/http.html).
|
|
170
176
|
|
|
177
|
+
Under the hood, Cpeak stores your routes in a radix tree, so finding the right route for an incoming request is roughly O(log n) in your total route count. In plain terms, that means matching stays fast even when your app has hundreds or thousands of routes. You won't pay a linear scan per request as your route table grows.
|
|
178
|
+
|
|
179
|
+
### Fallback Handler
|
|
180
|
+
|
|
181
|
+
If no route or middleware matches an incoming request, Cpeak returns a default `404` message. You can replace it with your own handler using `server.fallback`:
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
server.fallback((req, res) => {
|
|
185
|
+
return res.status(404).json({ error: "not found" });
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Use this for custom 404 pages, JSON error envelopes, or serving an SPA's `index.html` for unknown paths. Static, param, and `*` wildcard routes still win when they match, the fallback only fires once the router has no match.
|
|
190
|
+
|
|
171
191
|
### URL Variables & Parameters
|
|
172
192
|
|
|
173
193
|
To be more consistent with the broader Node.js community and frameworks, we call the HTTP URL parameters (query strings) '**query**', and the path variables (route parameters) '**params**'.
|
|
@@ -198,7 +218,15 @@ server.route("get", "/testing", (req, res) => {
|
|
|
198
218
|
});
|
|
199
219
|
```
|
|
200
220
|
|
|
201
|
-
The file’s binary content will be in the HTTP response body content. Make sure you specify a correct path relative to your CWD (use the `path` module for better compatibility)
|
|
221
|
+
The file’s binary content will be in the HTTP response body content. Make sure you specify a correct path relative to your CWD (use the `path` module for better compatibility).
|
|
222
|
+
|
|
223
|
+
The MIME type argument is optional. When omitted, Cpeak infers it from the file extension using its built-in MIME registry (see [MIME Types](#mime-types)):
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
return res.status(200).sendFile("./images/sun.jpeg");
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Passing the MIME type explicitly is the fastest path, Cpeak skips the extension lookup entirely.
|
|
202
230
|
|
|
203
231
|
### Redirecting
|
|
204
232
|
|
|
@@ -208,6 +236,40 @@ If you want to redirect to a new URL, you can simply do:
|
|
|
208
236
|
res.redirect("https://whatever.com");
|
|
209
237
|
```
|
|
210
238
|
|
|
239
|
+
### MIME Types
|
|
240
|
+
|
|
241
|
+
`serveStatic`, `res.sendFile`, and `res.render` all share a single MIME type registry. Out of the box it covers the common web types:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
html: "text/html",
|
|
245
|
+
css: "text/css",
|
|
246
|
+
js: "application/javascript",
|
|
247
|
+
jpg: "image/jpeg",
|
|
248
|
+
jpeg: "image/jpeg",
|
|
249
|
+
png: "image/png",
|
|
250
|
+
svg: "image/svg+xml",
|
|
251
|
+
gif: "image/gif",
|
|
252
|
+
ico: "image/x-icon",
|
|
253
|
+
txt: "text/plain",
|
|
254
|
+
json: "application/json",
|
|
255
|
+
webmanifest: "application/manifest+json",
|
|
256
|
+
eot: "application/vnd.ms-fontobject",
|
|
257
|
+
otf: "font/otf",
|
|
258
|
+
ttf: "font/ttf",
|
|
259
|
+
woff: "font/woff",
|
|
260
|
+
woff2: "font/woff2"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
If you need to serve something else, register it once on the `cpeak()` constructor:
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
const server = cpeak({
|
|
267
|
+
mimeTypes: { mp3: "audio/mpeg", m4a: "audio/mp4" }
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
We keep this list small on purpose. Cpeak isn't going to load the [thousands of MIME types from the IANA registry](https://www.iana.org/assignments/media-types/media-types.xhtml) into your process memory on the off chance you might serve an `.apk` or a `.fla` one day. You tell us what you serve, we keep memory tight.
|
|
272
|
+
|
|
211
273
|
### Compression
|
|
212
274
|
|
|
213
275
|
You can enable HTTP response compression at construction time. Once enabled, `serveStatic`, `res.json()` and `res.sendFile()` will compress eligible responses automatically, and you also get a `res.compress()` method on the response for custom payloads.
|
|
@@ -252,9 +314,7 @@ server.route("get", "/proxy/feed", async (req, res) => {
|
|
|
252
314
|
});
|
|
253
315
|
```
|
|
254
316
|
|
|
255
|
-
You must first enable compression at construction time to use `res.compress`.
|
|
256
|
-
|
|
257
|
-
One thing to keep in mind: when compression is enabled, `res.json()` returns a `Promise` because the work runs through async streams. You don't have to await it, but you can if you want to know when the response has been fully flushed.
|
|
317
|
+
You must first enable compression at construction time to use `res.compress`.
|
|
258
318
|
|
|
259
319
|
### Error Handling
|
|
260
320
|
|
|
@@ -270,36 +330,40 @@ server.route("get", "/api/document/:title", (req, res) => {
|
|
|
270
330
|
});
|
|
271
331
|
```
|
|
272
332
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
```javascript
|
|
276
|
-
server.route("get", "/api/document/:title", (req, res, handleErr) => {
|
|
277
|
-
const title = req.params.title;
|
|
278
|
-
|
|
279
|
-
if (title.length > 500)
|
|
280
|
-
return handleErr({ status: 400, message: "Title too long." });
|
|
281
|
-
|
|
282
|
-
// The rest of your logic...
|
|
283
|
-
});
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
**Make sure** to call the `server.handleErr` and pass a function like this to have the automatic error handler work properly:
|
|
333
|
+
**Make sure** to call `server.handleErr` and pass a function like this to have the automatic error handler work properly:
|
|
287
334
|
|
|
288
335
|
```javascript
|
|
289
336
|
server.handleErr((error, req, res) => {
|
|
290
337
|
if (error && error.status) {
|
|
291
|
-
res.status(error.status).json({ error: error.message });
|
|
338
|
+
return res.status(error.status).json({ error: error.message });
|
|
292
339
|
} else {
|
|
293
340
|
// Log the unexpected errors somewhere so you can keep track of them...
|
|
294
341
|
console.error(error);
|
|
295
|
-
res.status(500).json({
|
|
342
|
+
return res.status(500).json({
|
|
296
343
|
error: "Sorry, something unexpected happened on our side."
|
|
297
344
|
});
|
|
298
345
|
}
|
|
299
346
|
});
|
|
300
347
|
```
|
|
301
348
|
|
|
302
|
-
_The error object is the object that you threw
|
|
349
|
+
_The error object is the object that you threw earlier in your routes or middleware._
|
|
350
|
+
|
|
351
|
+
One thing to keep in mind: `res.sendFile`, `res.render`, `res.compress`, and `res.json` all return a `Promise`. **Return** that promise (or `await` it in an `async` handler) so the framework can route any rejection to your `handleErr`:
|
|
352
|
+
|
|
353
|
+
```javascript
|
|
354
|
+
server.route("get", "/file", (req, res) => {
|
|
355
|
+
return res.sendFile("./images/sun.jpeg", "image/jpeg");
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Or, in an `async` handler that does other work alongside the send:
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
server.route("get", "/avatars/:id", async (req, res) => {
|
|
363
|
+
const path = await db.lookupAvatarPath(req.params.id);
|
|
364
|
+
await res.sendFile(path);
|
|
365
|
+
});
|
|
366
|
+
```
|
|
303
367
|
|
|
304
368
|
### Listening
|
|
305
369
|
|
|
@@ -311,6 +375,8 @@ server.listen(3000, () => {
|
|
|
311
375
|
});
|
|
312
376
|
```
|
|
313
377
|
|
|
378
|
+
`server.listen` accepts the same arguments as Node.js's [http.Server.listen](https://nodejs.org/docs/latest/api/net.html#serverlistenoptions-callback), so you can also pass a host, an options object, or a Unix socket path.
|
|
379
|
+
|
|
314
380
|
### Util Functions
|
|
315
381
|
|
|
316
382
|
There are utility functions that you can include and use as middleware functions. These are meant to make it easier for you to build HTTP applications. In the future, many more will be added, and you only move them into memory once you include them. No need to have many npm dependencies for simple applications!
|
|
@@ -336,44 +402,26 @@ import cpeak, { utilName } from "cpeak";
|
|
|
336
402
|
With this middleware function, you can automatically set a folder in your project to be served by Cpeak. Here’s how to set it up:
|
|
337
403
|
|
|
338
404
|
```javascript
|
|
339
|
-
server.beforeEach(
|
|
340
|
-
serveStatic("./public", {
|
|
341
|
-
mp3: "audio/mpeg"
|
|
342
|
-
})
|
|
343
|
-
);
|
|
405
|
+
server.beforeEach(serveStatic("./public"));
|
|
344
406
|
```
|
|
345
407
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
```
|
|
349
|
-
html: "text/html",
|
|
350
|
-
css: "text/css",
|
|
351
|
-
js: "application/javascript",
|
|
352
|
-
jpg: "image/jpeg",
|
|
353
|
-
jpeg: "image/jpeg",
|
|
354
|
-
png: "image/png",
|
|
355
|
-
svg: "image/svg+xml",
|
|
356
|
-
gif: "image/gif",
|
|
357
|
-
ico: "image/x-icon",
|
|
358
|
-
txt: "text/plain",
|
|
359
|
-
json: "application/json",
|
|
360
|
-
webmanifest: "application/manifest+json",
|
|
361
|
-
eot: "application/vnd.ms-fontobject",
|
|
362
|
-
otf: "font/otf",
|
|
363
|
-
ttf: "font/ttf",
|
|
364
|
-
woff: "font/woff",
|
|
365
|
-
woff2: "font/woff2"
|
|
366
|
-
```
|
|
408
|
+
`serveStatic` infers each file's MIME type from its extension. If your folder contains types that aren't in the built-in registry, register them on the `cpeak()` constructor (see [MIME Types](#mime-types)).
|
|
367
409
|
|
|
368
|
-
You can also serve your static files under a URL prefix by passing a
|
|
410
|
+
You can also serve your static files under a URL prefix by passing a `prefix` option. This is useful when you want all static assets to live under a specific path like `/static`:
|
|
369
411
|
|
|
370
412
|
```javascript
|
|
371
413
|
server.beforeEach(
|
|
372
|
-
serveStatic("./public",
|
|
414
|
+
serveStatic("./public", { prefix: "/static" })
|
|
373
415
|
);
|
|
374
416
|
```
|
|
375
417
|
|
|
376
|
-
With this setup, a file at `./public/app.js` would be served at `/static/app.js` instead of `/app.js`.
|
|
418
|
+
With this setup, a file at `./public/app.js` would be served at `/static/app.js` instead of `/app.js`.
|
|
419
|
+
|
|
420
|
+
If file names in the served folder change while the server is running (e.g. during development), pass `live: true` so the middleware stats the disk on each request instead of caching the file map at startup:
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
423
|
+
server.beforeEach(serveStatic("./public", { live: true }));
|
|
424
|
+
```
|
|
377
425
|
|
|
378
426
|
#### parseJSON
|
|
379
427
|
|
|
@@ -395,7 +443,7 @@ server.route("put", "/api/user", (req, res) => {
|
|
|
395
443
|
// rest of your logic...
|
|
396
444
|
|
|
397
445
|
// Sending JSON in the HTTP response:
|
|
398
|
-
res.status(201).json({ message: "Something was created..." });
|
|
446
|
+
return res.status(201).json({ message: "Something was created..." });
|
|
399
447
|
});
|
|
400
448
|
```
|
|
401
449
|
|
|
@@ -424,6 +472,8 @@ server.route("get", "/", (req, res, next) => {
|
|
|
424
472
|
});
|
|
425
473
|
```
|
|
426
474
|
|
|
475
|
+
The third argument (the MIME type) is optional. When omitted, Cpeak infers it from the file extension using the registry on the `cpeak()` constructor.
|
|
476
|
+
|
|
427
477
|
You can then inject the variables into your file in {{ variable_name }} like this:
|
|
428
478
|
|
|
429
479
|
```HTML
|
|
@@ -463,7 +513,7 @@ server.route("get", "/dashboard", (req, res) => {
|
|
|
463
513
|
// Signed cookies — returns false if the signature is invalid or the value was tampered with
|
|
464
514
|
const userId = req.signedCookies.userId;
|
|
465
515
|
|
|
466
|
-
res.status(200).json({ theme, userId });
|
|
516
|
+
return res.status(200).json({ theme, userId });
|
|
467
517
|
});
|
|
468
518
|
```
|
|
469
519
|
|
|
@@ -477,7 +527,7 @@ server.route("post", "/login", (req, res) => {
|
|
|
477
527
|
// A signed cookie
|
|
478
528
|
res.cookie("userId", "abc123", { signed: true, httpOnly: true, secure: true });
|
|
479
529
|
|
|
480
|
-
res.status(200).json({ message: "Logged in" });
|
|
530
|
+
return res.status(200).json({ message: "Logged in" });
|
|
481
531
|
});
|
|
482
532
|
```
|
|
483
533
|
|
|
@@ -651,13 +701,11 @@ Here you can see all the features that Cpeak offers (excluding the authenticatio
|
|
|
651
701
|
```javascript
|
|
652
702
|
import cpeak, { serveStatic, parseJSON, render, cookieParser, cors } from "cpeak";
|
|
653
703
|
|
|
654
|
-
const server = cpeak(
|
|
704
|
+
const server = cpeak({
|
|
705
|
+
mimeTypes: { mp3: "audio/mpeg" }
|
|
706
|
+
});
|
|
655
707
|
|
|
656
|
-
server.beforeEach(
|
|
657
|
-
serveStatic("./public", {
|
|
658
|
-
mp3: "audio/mpeg"
|
|
659
|
-
})
|
|
660
|
-
);
|
|
708
|
+
server.beforeEach(serveStatic("./public"));
|
|
661
709
|
|
|
662
710
|
server.beforeEach(render());
|
|
663
711
|
|
|
@@ -681,11 +729,11 @@ server.beforeEach((req, res, next) => {
|
|
|
681
729
|
});
|
|
682
730
|
|
|
683
731
|
// A middleware function that can be specified to run before some particular routes
|
|
684
|
-
const testRouteMiddleware = (req, res, next
|
|
732
|
+
const testRouteMiddleware = (req, res, next) => {
|
|
685
733
|
req.whatever = "some calculated value maybe";
|
|
686
734
|
|
|
687
735
|
if (req.params.test !== "something special") {
|
|
688
|
-
|
|
736
|
+
throw { status: 400, message: "an error message" };
|
|
689
737
|
}
|
|
690
738
|
|
|
691
739
|
next();
|
|
@@ -722,7 +770,7 @@ server.route("get", "/api/document/:title", testRouteMiddleware, (req, res) => {
|
|
|
722
770
|
throw { status: 400, message: "Invalid property." };
|
|
723
771
|
|
|
724
772
|
// Sending a JSON response
|
|
725
|
-
res.status(200).json({ message: "This is a test response" });
|
|
773
|
+
return res.status(200).json({ message: "This is a test response" });
|
|
726
774
|
});
|
|
727
775
|
|
|
728
776
|
// Reading and setting cookies
|
|
@@ -732,22 +780,22 @@ server.route("post", "/login", (req, res) => {
|
|
|
732
780
|
|
|
733
781
|
// Set a signed session cookie
|
|
734
782
|
res.cookie("sessionId", "abc123", { signed: true, httpOnly: true, secure: true });
|
|
735
|
-
res.status(200).json({ message: "Logged in" });
|
|
783
|
+
return res.status(200).json({ message: "Logged in" });
|
|
736
784
|
});
|
|
737
785
|
|
|
738
786
|
// Sending a file response
|
|
739
787
|
server.route("get", "/file", (req, res) => {
|
|
740
788
|
// Make sure to specify a correct path and MIME type...
|
|
741
|
-
res.status(200).sendFile("<path-to-file-relative-to-cwd>", "<mime-type>");
|
|
789
|
+
return res.status(200).sendFile("<path-to-file-relative-to-cwd>", "<mime-type>");
|
|
742
790
|
});
|
|
743
791
|
|
|
744
792
|
// Handle all the errors that could happen in the routes
|
|
745
793
|
server.handleErr((error, req, res) => {
|
|
746
794
|
if (error && error.status) {
|
|
747
|
-
res.status(error.status).json({ error: error.message });
|
|
795
|
+
return res.status(error.status).json({ error: error.message });
|
|
748
796
|
} else {
|
|
749
797
|
console.error(error);
|
|
750
|
-
res.status(500).json({
|
|
798
|
+
return res.status(500).json({
|
|
751
799
|
error: "Sorry, something unexpected happened from our side."
|
|
752
800
|
});
|
|
753
801
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import http, { IncomingMessage, ServerResponse, Server } from 'node:http';
|
|
2
|
+
import net from 'node:net';
|
|
3
3
|
import { Readable } from 'node:stream';
|
|
4
4
|
import { Buffer } from 'node:buffer';
|
|
5
5
|
import * as node_zlib from 'node:zlib';
|
|
6
6
|
|
|
7
|
+
declare function frameworkError(message: string, skipFn: Function, code?: string, status?: number, clientDisconnect?: boolean): Error & {
|
|
8
|
+
code?: string;
|
|
9
|
+
cpeak_err?: boolean;
|
|
10
|
+
clientDisconnect?: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare function isClientDisconnect(err: unknown): boolean;
|
|
13
|
+
declare enum ErrorCode {
|
|
14
|
+
MISSING_MIME = "CPEAK_ERR_MISSING_MIME",
|
|
15
|
+
FILE_NOT_FOUND = "CPEAK_ERR_FILE_NOT_FOUND",
|
|
16
|
+
NOT_A_FILE = "CPEAK_ERR_NOT_A_FILE",
|
|
17
|
+
SEND_FILE_FAIL = "CPEAK_ERR_SEND_FILE_FAIL",
|
|
18
|
+
INVALID_JSON = "CPEAK_ERR_INVALID_JSON",
|
|
19
|
+
PAYLOAD_TOO_LARGE = "CPEAK_ERR_PAYLOAD_TOO_LARGE",
|
|
20
|
+
WEAK_SECRET = "CPEAK_ERR_WEAK_SECRET",
|
|
21
|
+
COMPRESSION_NOT_ENABLED = "CPEAK_ERR_COMPRESSION_NOT_ENABLED",
|
|
22
|
+
RENDER_NOT_ENABLED = "CPEAK_ERR_RENDER_NOT_ENABLED",
|
|
23
|
+
DUPLICATE_ROUTE = "CPEAK_ERR_DUPLICATE_ROUTE",
|
|
24
|
+
INVALID_ROUTE = "CPEAK_ERR_INVALID_ROUTE",
|
|
25
|
+
DUPLICATE_FALLBACK = "CPEAK_ERR_DUPLICATE_FALLBACK",
|
|
26
|
+
RENDER_FAIL = "CPEAK_ERR_RENDER_FAIL"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface CompressionOptions {
|
|
30
|
+
threshold?: number;
|
|
31
|
+
brotli?: node_zlib.BrotliOptions;
|
|
32
|
+
gzip?: node_zlib.ZlibOptions;
|
|
33
|
+
deflate?: node_zlib.ZlibOptions;
|
|
34
|
+
}
|
|
35
|
+
type ResolvedCompressionConfig = Required<CompressionOptions>;
|
|
36
|
+
|
|
7
37
|
interface PbkdfOptions {
|
|
8
38
|
iterations?: number;
|
|
9
39
|
keylen?: number;
|
|
@@ -43,15 +73,11 @@ interface CorsOptions {
|
|
|
43
73
|
preflightContinue?: boolean;
|
|
44
74
|
optionsSuccessStatus?: number;
|
|
45
75
|
}
|
|
46
|
-
interface CompressionOptions {
|
|
47
|
-
threshold?: number;
|
|
48
|
-
brotli?: node_zlib.BrotliOptions;
|
|
49
|
-
gzip?: node_zlib.ZlibOptions;
|
|
50
|
-
deflate?: node_zlib.ZlibOptions;
|
|
51
|
-
}
|
|
52
76
|
|
|
77
|
+
type CpeakHttpServer = Server<typeof CpeakIncomingMessage, typeof CpeakServerResponse>;
|
|
53
78
|
interface CpeakOptions {
|
|
54
79
|
compression?: boolean | CompressionOptions;
|
|
80
|
+
mimeTypes?: StringMap;
|
|
55
81
|
}
|
|
56
82
|
type StringMap = Record<string, string>;
|
|
57
83
|
interface CpeakRequest<ReqBody = any, ReqQueries = any> extends IncomingMessage {
|
|
@@ -62,42 +88,35 @@ interface CpeakRequest<ReqBody = any, ReqQueries = any> extends IncomingMessage
|
|
|
62
88
|
signedCookies?: Record<string, string | false>;
|
|
63
89
|
[key: string]: any;
|
|
64
90
|
}
|
|
65
|
-
interface CpeakResponse extends ServerResponse {
|
|
66
|
-
sendFile: (path: string, mime
|
|
67
|
-
status: (code: number) => CpeakResponse
|
|
68
|
-
attachment: (filename?: string) => CpeakResponse
|
|
69
|
-
cookie: (name: string, value: string, options?:
|
|
91
|
+
interface CpeakResponse<ResBody = any> extends ServerResponse {
|
|
92
|
+
sendFile: (path: string, mime?: string) => Promise<void>;
|
|
93
|
+
status: (code: number) => CpeakResponse<ResBody>;
|
|
94
|
+
attachment: (filename?: string) => CpeakResponse<ResBody>;
|
|
95
|
+
cookie: (name: string, value: string, options?: CookieOptions) => CpeakResponse<ResBody>;
|
|
70
96
|
redirect: (location: string) => void;
|
|
71
|
-
json: (data:
|
|
97
|
+
json: (data: ResBody) => Promise<void>;
|
|
72
98
|
compress: (mime: string, body: Buffer | string | Readable, size?: number) => Promise<void>;
|
|
99
|
+
render: (filePath: string, data: Record<string, unknown>, mime?: string) => Promise<void>;
|
|
73
100
|
[key: string]: any;
|
|
74
101
|
}
|
|
75
102
|
type Next = (err?: any) => void;
|
|
76
|
-
type
|
|
77
|
-
type
|
|
78
|
-
type
|
|
79
|
-
type Handler<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, handleErr: HandleErr) => void | Promise<void>;
|
|
80
|
-
interface Route {
|
|
81
|
-
path: string;
|
|
82
|
-
regex: RegExp;
|
|
83
|
-
middleware: RouteMiddleware[];
|
|
84
|
-
cb: Handler;
|
|
85
|
-
}
|
|
86
|
-
interface RoutesMap {
|
|
87
|
-
[method: string]: Route[];
|
|
88
|
-
}
|
|
103
|
+
type Middleware<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, next: Next) => unknown;
|
|
104
|
+
type RouteMiddleware<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, next: Next) => unknown;
|
|
105
|
+
type Handler<ReqBody = any, ReqParams = any, ResBody = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse<ResBody>) => unknown;
|
|
89
106
|
|
|
90
107
|
declare const parseJSON: (options?: {
|
|
91
108
|
limit?: number;
|
|
92
109
|
}) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void;
|
|
93
110
|
|
|
94
|
-
declare const serveStatic: (folderPath: string,
|
|
111
|
+
declare const serveStatic: (folderPath: string, options?: {
|
|
95
112
|
prefix?: string;
|
|
113
|
+
live?: boolean;
|
|
114
|
+
exclude?: string[];
|
|
96
115
|
}) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void | Promise<void>;
|
|
97
116
|
|
|
98
117
|
declare const render: () => (req: CpeakRequest, res: CpeakResponse, next: Next) => void;
|
|
99
118
|
|
|
100
|
-
declare const swagger: (spec: object, prefix?: string) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void |
|
|
119
|
+
declare const swagger: (spec: object, prefix?: string) => (req: CpeakRequest, res: CpeakResponse, next: Next) => Promise<void> | undefined;
|
|
101
120
|
|
|
102
121
|
declare function hashPassword(password: string, options?: PbkdfOptions): Promise<string>;
|
|
103
122
|
declare function verifyPassword(password: string, stored: string): Promise<boolean>;
|
|
@@ -109,20 +128,6 @@ declare function cookieParser(options?: {
|
|
|
109
128
|
|
|
110
129
|
declare const cors: (options?: CorsOptions) => (req: CpeakRequest, res: CpeakResponse, next: Next) => Promise<void>;
|
|
111
130
|
|
|
112
|
-
declare function frameworkError(message: string, skipFn: Function, code?: string, status?: number): Error & {
|
|
113
|
-
code?: string;
|
|
114
|
-
cpeak_err?: boolean;
|
|
115
|
-
};
|
|
116
|
-
declare enum ErrorCode {
|
|
117
|
-
MISSING_MIME = "CPEAK_ERR_MISSING_MIME",
|
|
118
|
-
FILE_NOT_FOUND = "CPEAK_ERR_FILE_NOT_FOUND",
|
|
119
|
-
NOT_A_FILE = "CPEAK_ERR_NOT_A_FILE",
|
|
120
|
-
SEND_FILE_FAIL = "CPEAK_ERR_SEND_FILE_FAIL",
|
|
121
|
-
INVALID_JSON = "CPEAK_ERR_INVALID_JSON",
|
|
122
|
-
PAYLOAD_TOO_LARGE = "CPEAK_ERR_PAYLOAD_TOO_LARGE",
|
|
123
|
-
WEAK_SECRET = "CPEAK_ERR_WEAK_SECRET",
|
|
124
|
-
COMPRESSION_NOT_ENABLED = "CPEAK_ERR_COMPRESSION_NOT_ENABLED"
|
|
125
|
-
}
|
|
126
131
|
declare class CpeakIncomingMessage extends http.IncomingMessage {
|
|
127
132
|
#private;
|
|
128
133
|
body: any;
|
|
@@ -130,11 +135,13 @@ declare class CpeakIncomingMessage extends http.IncomingMessage {
|
|
|
130
135
|
get query(): StringMap;
|
|
131
136
|
}
|
|
132
137
|
declare class CpeakServerResponse extends http.ServerResponse<CpeakIncomingMessage> {
|
|
133
|
-
|
|
138
|
+
_compression?: ResolvedCompressionConfig;
|
|
139
|
+
sendFile(path: string, mime?: string): Promise<void>;
|
|
134
140
|
status(code: number): this;
|
|
135
141
|
attachment(filename?: string): this;
|
|
136
142
|
redirect(location: string): void;
|
|
137
|
-
json(data: any):
|
|
143
|
+
json(data: any): Promise<void>;
|
|
144
|
+
render(): Promise<void>;
|
|
138
145
|
compress(mime: string, body: Buffer | string | Readable, size?: number): Promise<void>;
|
|
139
146
|
}
|
|
140
147
|
declare class Cpeak {
|
|
@@ -143,11 +150,15 @@ declare class Cpeak {
|
|
|
143
150
|
route(method: string, path: string, ...args: (RouteMiddleware | Handler)[]): void;
|
|
144
151
|
beforeEach(cb: Middleware): void;
|
|
145
152
|
handleErr(cb: (err: unknown, req: CpeakRequest, res: CpeakResponse) => void): void;
|
|
146
|
-
|
|
153
|
+
fallback(cb: Handler): void;
|
|
154
|
+
listen(port: number, cb?: () => void): CpeakHttpServer;
|
|
155
|
+
listen(port: number, host: string, cb?: () => void): CpeakHttpServer;
|
|
156
|
+
listen(options: net.ListenOptions, cb?: () => void): CpeakHttpServer;
|
|
147
157
|
address(): string | net.AddressInfo | null;
|
|
148
|
-
close(cb?: (err?: Error) => void):
|
|
158
|
+
close(cb?: (err?: Error) => void): CpeakHttpServer;
|
|
159
|
+
get server(): CpeakHttpServer;
|
|
149
160
|
}
|
|
150
161
|
|
|
151
162
|
declare function cpeak(options?: CpeakOptions): Cpeak;
|
|
152
163
|
|
|
153
|
-
export { type AuthOptions, type CompressionOptions, type CookieOptions, type CorsOptions, Cpeak, CpeakIncomingMessage, type CpeakOptions, type CpeakRequest, type CpeakResponse, CpeakServerResponse, ErrorCode, type
|
|
164
|
+
export { type AuthOptions, type CompressionOptions, type CookieOptions, type CorsOptions, Cpeak, type CpeakHttpServer, CpeakIncomingMessage, type CpeakOptions, type CpeakRequest, type CpeakResponse, CpeakServerResponse, ErrorCode, type Handler, type Middleware, type Next, type PbkdfOptions, type RouteMiddleware, auth, cookieParser, cors, cpeak as default, frameworkError, hashPassword, isClientDisconnect, parseJSON, render, serveStatic, swagger, verifyPassword };
|