cpeak 2.7.0 → 2.8.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 CHANGED
@@ -2,11 +2,15 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/cpeak.svg)](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 minimal than Express.js. This framework is intended for HTTP applications that primarily deal with JSON and file-based message bodies.
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
- This is 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, check out this course!
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, handleErr) => {
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
- return handleErr({ status: 401, message: "Unauthorized" });
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) and also the correct HTTP MIME type for that file.
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
- You can also make use of the `handleErr` callback function like this:
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 or passed to the `handleErr` function earlier in your routes._
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
- If you have file types in your public folder that are not one of the following, make sure to add the MIME types manually as the second argument in the function as an object where each property key is the file extension, and each value is the correct MIME type for that. You can see all the available MIME types on the [IANA website](https://www.iana.org/assignments/media-types/media-types.xhtml).
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 third argument with a `prefix` option. This is useful when you want all static assets to live under a specific path like `/static`:
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", null, { prefix: "/static" })
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`. Pass `null` as the second argument if you don’t need any custom MIME types.
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, handleErr) => {
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
- return handleErr({ status: 400, message: "an error message" });
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,57 +1,38 @@
1
- import * as net from 'net';
2
- import http, { IncomingMessage, ServerResponse } from 'node:http';
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
- interface PbkdfOptions {
8
- iterations?: number;
9
- keylen?: number;
10
- digest?: string;
11
- saltSize?: number;
12
- }
13
- interface AuthOptions extends PbkdfOptions {
14
- secret: string;
15
- saveToken: (tokenId: string, userId: string, expiresAt: Date) => Promise<void>;
16
- findToken: (tokenId: string) => Promise<{
17
- userId: string;
18
- expiresAt: Date;
19
- } | null>;
20
- tokenExpiry?: number;
21
- hmacAlgorithm?: string;
22
- tokenIdSize?: number;
23
- revokeToken?: (tokenId: string) => Promise<void>;
24
- }
25
- interface CookieOptions {
26
- signed?: boolean;
27
- httpOnly?: boolean;
28
- secure?: boolean;
29
- sameSite?: "strict" | "lax" | "none";
30
- maxAge?: number;
31
- expires?: Date;
32
- path?: string;
33
- domain?: string;
34
- }
35
- type OriginInput = string | string[] | RegExp | boolean | ((origin: string | undefined) => boolean | Promise<boolean>);
36
- interface CorsOptions {
37
- origin?: OriginInput;
38
- methods?: string | string[];
39
- allowedHeaders?: string | string[];
40
- exposedHeaders?: string | string[];
41
- credentials?: boolean;
42
- maxAge?: number;
43
- preflightContinue?: boolean;
44
- optionsSuccessStatus?: number;
7
+ declare function frameworkError(message: string, skipFn: Function, code?: string, status?: number): Error & {
8
+ code?: string;
9
+ cpeak_err?: boolean;
10
+ };
11
+ declare enum ErrorCode {
12
+ MISSING_MIME = "CPEAK_ERR_MISSING_MIME",
13
+ FILE_NOT_FOUND = "CPEAK_ERR_FILE_NOT_FOUND",
14
+ NOT_A_FILE = "CPEAK_ERR_NOT_A_FILE",
15
+ SEND_FILE_FAIL = "CPEAK_ERR_SEND_FILE_FAIL",
16
+ INVALID_JSON = "CPEAK_ERR_INVALID_JSON",
17
+ PAYLOAD_TOO_LARGE = "CPEAK_ERR_PAYLOAD_TOO_LARGE",
18
+ WEAK_SECRET = "CPEAK_ERR_WEAK_SECRET",
19
+ COMPRESSION_NOT_ENABLED = "CPEAK_ERR_COMPRESSION_NOT_ENABLED",
20
+ DUPLICATE_ROUTE = "CPEAK_ERR_DUPLICATE_ROUTE",
21
+ INVALID_ROUTE = "CPEAK_ERR_INVALID_ROUTE"
45
22
  }
23
+
46
24
  interface CompressionOptions {
47
25
  threshold?: number;
48
26
  brotli?: node_zlib.BrotliOptions;
49
27
  gzip?: node_zlib.ZlibOptions;
50
28
  deflate?: node_zlib.ZlibOptions;
51
29
  }
30
+ type ResolvedCompressionConfig = Required<CompressionOptions>;
52
31
 
32
+ type CpeakHttpServer = Server<typeof CpeakIncomingMessage, typeof CpeakServerResponse>;
53
33
  interface CpeakOptions {
54
34
  compression?: boolean | CompressionOptions;
35
+ mimeTypes?: StringMap;
55
36
  }
56
37
  type StringMap = Record<string, string>;
57
38
  interface CpeakRequest<ReqBody = any, ReqQueries = any> extends IncomingMessage {
@@ -63,41 +44,72 @@ interface CpeakRequest<ReqBody = any, ReqQueries = any> extends IncomingMessage
63
44
  [key: string]: any;
64
45
  }
65
46
  interface CpeakResponse extends ServerResponse {
66
- sendFile: (path: string, mime: string) => Promise<void>;
47
+ sendFile: (path: string, mime?: string) => Promise<void>;
67
48
  status: (code: number) => CpeakResponse;
68
49
  attachment: (filename?: string) => CpeakResponse;
69
50
  cookie: (name: string, value: string, options?: any) => CpeakResponse;
70
51
  redirect: (location: string) => void;
71
- json: (data: any) => void | Promise<void>;
52
+ json: (data: any) => Promise<void>;
72
53
  compress: (mime: string, body: Buffer | string | Readable, size?: number) => Promise<void>;
73
54
  [key: string]: any;
74
55
  }
75
56
  type Next = (err?: any) => void;
76
- type HandleErr = (err: any) => void;
77
57
  type Middleware<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, next: Next) => void;
78
- type RouteMiddleware<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, next: Next, handleErr: HandleErr) => void | Promise<void>;
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
- }
58
+ type RouteMiddleware<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse, next: Next) => void | Promise<void>;
59
+ type Handler<ReqBody = any, ReqParams = any> = (req: CpeakRequest<ReqBody, ReqParams>, res: CpeakResponse) => void | Promise<void>;
89
60
 
90
61
  declare const parseJSON: (options?: {
91
62
  limit?: number;
92
63
  }) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void;
93
64
 
94
- declare const serveStatic: (folderPath: string, newMimeTypes?: StringMap, options?: {
65
+ declare const serveStatic: (folderPath: string, options?: {
95
66
  prefix?: string;
67
+ live?: boolean;
96
68
  }) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void | Promise<void>;
97
69
 
98
70
  declare const render: () => (req: CpeakRequest, res: CpeakResponse, next: Next) => void;
99
71
 
100
- declare const swagger: (spec: object, prefix?: string) => (req: CpeakRequest, res: CpeakResponse, next: Next) => void | Promise<void>;
72
+ declare const swagger: (spec: object, prefix?: string) => (req: CpeakRequest, res: CpeakResponse, next: Next) => Promise<void> | undefined;
73
+
74
+ interface PbkdfOptions {
75
+ iterations?: number;
76
+ keylen?: number;
77
+ digest?: string;
78
+ saltSize?: number;
79
+ }
80
+ interface AuthOptions extends PbkdfOptions {
81
+ secret: string;
82
+ saveToken: (tokenId: string, userId: string, expiresAt: Date) => Promise<void>;
83
+ findToken: (tokenId: string) => Promise<{
84
+ userId: string;
85
+ expiresAt: Date;
86
+ } | null>;
87
+ tokenExpiry?: number;
88
+ hmacAlgorithm?: string;
89
+ tokenIdSize?: number;
90
+ revokeToken?: (tokenId: string) => Promise<void>;
91
+ }
92
+ interface CookieOptions {
93
+ signed?: boolean;
94
+ httpOnly?: boolean;
95
+ secure?: boolean;
96
+ sameSite?: "strict" | "lax" | "none";
97
+ maxAge?: number;
98
+ expires?: Date;
99
+ path?: string;
100
+ domain?: string;
101
+ }
102
+ type OriginInput = string | string[] | RegExp | boolean | ((origin: string | undefined) => boolean | Promise<boolean>);
103
+ interface CorsOptions {
104
+ origin?: OriginInput;
105
+ methods?: string | string[];
106
+ allowedHeaders?: string | string[];
107
+ exposedHeaders?: string | string[];
108
+ credentials?: boolean;
109
+ maxAge?: number;
110
+ preflightContinue?: boolean;
111
+ optionsSuccessStatus?: number;
112
+ }
101
113
 
102
114
  declare function hashPassword(password: string, options?: PbkdfOptions): Promise<string>;
103
115
  declare function verifyPassword(password: string, stored: string): Promise<boolean>;
@@ -109,20 +121,6 @@ declare function cookieParser(options?: {
109
121
 
110
122
  declare const cors: (options?: CorsOptions) => (req: CpeakRequest, res: CpeakResponse, next: Next) => Promise<void>;
111
123
 
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
124
  declare class CpeakIncomingMessage extends http.IncomingMessage {
127
125
  #private;
128
126
  body: any;
@@ -130,11 +128,12 @@ declare class CpeakIncomingMessage extends http.IncomingMessage {
130
128
  get query(): StringMap;
131
129
  }
132
130
  declare class CpeakServerResponse extends http.ServerResponse<CpeakIncomingMessage> {
133
- sendFile(path: string, mime: string): Promise<void>;
131
+ _compression?: ResolvedCompressionConfig;
132
+ sendFile(path: string, mime?: string): Promise<void>;
134
133
  status(code: number): this;
135
134
  attachment(filename?: string): this;
136
135
  redirect(location: string): void;
137
- json(data: any): void | Promise<void>;
136
+ json(data: any): Promise<void>;
138
137
  compress(mime: string, body: Buffer | string | Readable, size?: number): Promise<void>;
139
138
  }
140
139
  declare class Cpeak {
@@ -143,11 +142,14 @@ declare class Cpeak {
143
142
  route(method: string, path: string, ...args: (RouteMiddleware | Handler)[]): void;
144
143
  beforeEach(cb: Middleware): void;
145
144
  handleErr(cb: (err: unknown, req: CpeakRequest, res: CpeakResponse) => void): void;
146
- listen(port: number, cb?: () => void): http.Server<typeof CpeakIncomingMessage, typeof CpeakServerResponse>;
145
+ listen(port: number, cb?: () => void): CpeakHttpServer;
146
+ listen(port: number, host: string, cb?: () => void): CpeakHttpServer;
147
+ listen(options: net.ListenOptions, cb?: () => void): CpeakHttpServer;
147
148
  address(): string | net.AddressInfo | null;
148
- close(cb?: (err?: Error) => void): void;
149
+ close(cb?: (err?: Error) => void): CpeakHttpServer;
150
+ get server(): CpeakHttpServer;
149
151
  }
150
152
 
151
153
  declare function cpeak(options?: CpeakOptions): Cpeak;
152
154
 
153
- export { type AuthOptions, type CompressionOptions, type CookieOptions, type CorsOptions, Cpeak, CpeakIncomingMessage, type CpeakOptions, type CpeakRequest, type CpeakResponse, CpeakServerResponse, ErrorCode, type HandleErr, type Handler, type Middleware, type Next, type PbkdfOptions, type RouteMiddleware, type RoutesMap, auth, cookieParser, cors, cpeak as default, frameworkError, hashPassword, parseJSON, render, serveStatic, swagger, verifyPassword };
155
+ 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, parseJSON, render, serveStatic, swagger, verifyPassword };