@jsenv/server 17.6.1 → 17.6.2

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.
Files changed (52) hide show
  1. package/README.md +47 -48
  2. package/dist/jsenv_server.js +1332 -1269
  3. package/package.json +2 -2
  4. package/src/content_negotiation/pick_content_encoding.js +11 -1
  5. package/src/content_negotiation/pick_content_language.js +11 -1
  6. package/src/content_negotiation/pick_content_type.js +11 -1
  7. package/src/content_negotiation/pick_content_version.js +1 -1
  8. package/src/interfacing_with_node/from_node_request.js +154 -178
  9. package/src/interfacing_with_node/observable_from_file_handle.js +1 -18
  10. package/src/interfacing_with_node/observable_from_node_stream.js +29 -65
  11. package/src/interfacing_with_node/write_node_response.js +59 -103
  12. package/src/internal/allowed_hosts.js +85 -0
  13. package/src/internal/escape_html.js +11 -0
  14. package/src/internal/{headersFromObject.js → headers_from_object.js} +2 -2
  15. package/src/internal/listen.js +32 -5
  16. package/src/internal/{listenRequest.js → listen_request.js} +1 -1
  17. package/src/internal/{listenServerConnectionError.js → listen_server_connection_error.js} +1 -1
  18. package/src/internal/{multiple-header.js → multiple_header.js} +32 -10
  19. package/src/internal/reason_phrase.js +17 -0
  20. package/src/internal/response_composition.js +11 -2
  21. package/src/internal/secure_server.js +22 -0
  22. package/src/internal/server_origins.js +78 -0
  23. package/src/internal/{server-polyglot.js → server_polyglot.js} +13 -38
  24. package/src/internal/track_server_pending_connections.js +50 -0
  25. package/src/internal/track_server_pending_requests.js +47 -0
  26. package/src/plugins/cors/server_plugin_cors.js +39 -6
  27. package/src/plugins/default_body_4xx_5xx/server_plugin_default_body_4xx_5xx.js +37 -29
  28. package/src/plugins/error_handler/server_plugin_error_handler.js +26 -10
  29. package/src/plugins/filesystem/fetch_directory.js +16 -3
  30. package/src/plugins/filesystem/fetch_file.js +80 -21
  31. package/src/plugins/filesystem/filesystem_error_to_response.js +12 -6
  32. package/src/plugins/request_aliases/server_plugin_request_aliases.js +8 -0
  33. package/src/plugins/response_acceptance_check/server_plugin_response_acceptance_check.js +11 -6
  34. package/src/plugins/route_inspector/server_plugin_route_inspector.js +11 -5
  35. package/src/plugins/server_plugins_controller.js +27 -13
  36. package/src/progressive_response.js +24 -0
  37. package/src/router/permissions.js +52 -0
  38. package/src/router/router.js +14 -79
  39. package/src/server_events.js +3 -1
  40. package/src/server_timing/timing_header.js +1 -1
  41. package/src/start_server.js +266 -416
  42. package/src/internal/headersFromString.js +0 -21
  43. package/src/internal/headersToObject.js +0 -7
  44. package/src/internal/headersToString.js +0 -16
  45. package/src/internal/listenClientError.js +0 -27
  46. package/src/internal/trackServerPendingConnections.js +0 -145
  47. package/src/internal/trackServerPendingRequests.js +0 -68
  48. package/src/request_body_handling.js +0 -22
  49. /package/src/internal/{colorizeResponseStatus.js → colorize_response_status.js} +0 -0
  50. /package/src/internal/{listenEvent.js → listen_event.js} +0 -0
  51. /package/src/internal/{normalizeHeaderName.js → normalize_header_name.js} +0 -0
  52. /package/src/internal/{normalizeHeaderValue.js → normalize_header_value.js} +0 -0
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # server [![npm package](https://img.shields.io/npm/v/@jsenv/server.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/server)
2
2
 
3
- > A modern, flexible Node.js HTTP server with declarative routing, content negotiation, and WebSocket support.
4
-
5
- `@jsenv/server` simplifies server development with a declarative API that handles common web server needs like routing, content negotiation, file serving, and real-time communication.
3
+ > A Node.js HTTP server with declarative routing, content negotiation, file serving, WebSocket and Server-Sent Events.
6
4
 
7
5
  ```js
8
6
  import { startServer } from "@jsenv/server";
@@ -12,7 +10,7 @@ await startServer({
12
10
  routes: [
13
11
  {
14
12
  endpoint: "GET *",
15
- response: () => new Response("Hello world"),
13
+ fetch: () => new Response("Hello world"),
16
14
  },
17
15
  ],
18
16
  });
@@ -20,16 +18,15 @@ await startServer({
20
18
 
21
19
  # Features
22
20
 
23
- - [*] Declarative routing with path parameters and pattern matching
24
- - [*] Content negotiation for type, language, version and encoding
25
- - [*] Real-time communication via WebSockets and Server-Sent Events
26
- - [*] File serving with ETags, conditional requests, and compression
27
- - [*] Security with HTTPS and automatic HTTP-to-HTTPS redirection
28
- - [*] HTTP/2 support including server push
29
- - [*] CORS handling built-in
30
- - [*] Performance monitoring with server timing
31
- - [*] Sacalability through cluster mode for multi-core utilization
32
- - [ ] Request authentification with JWT, OAuth etc
21
+ - Declarative routing: `"GET /users/:id"`, the first route returning a response wins
22
+ - 404, 405, 406, 415 and OPTIONS responses derived from the routes
23
+ - Content negotiation for media type, language, version and encoding
24
+ - File serving with etag/mtime client cache and compression
25
+ - WebSocket and Server-Sent Events, with a broadcast helper
26
+ - HTTPS, with http → https redirection; http2 as an option
27
+ - CORS, server timing and error pages as plugins
28
+ - Host header check (DNS rebinding) and bounded request bodies
29
+ - A route inspector at `/.internal/route_inspector`
33
30
 
34
31
  # Installation
35
32
 
@@ -37,14 +34,11 @@ await startServer({
37
34
  npm install @jsenv/server
38
35
  ```
39
36
 
40
- **Requirements:**
41
-
42
- - Node.js 22.13.1 or higher
43
- - ES modules support
37
+ Requires Node.js 22.13.1 or higher.
44
38
 
45
- # Quick Examples
39
+ # Quick examples
46
40
 
47
- **Basic API Server**
41
+ **API server**
48
42
 
49
43
  ```js
50
44
  import { startServer } from "@jsenv/server";
@@ -54,37 +48,44 @@ await startServer({
54
48
  routes: [
55
49
  {
56
50
  endpoint: "GET /api/users",
57
- response: () => Response.json([{ id: 1, name: "John" }]),
51
+ fetch: () => Response.json([{ id: 1, name: "John" }]),
58
52
  },
59
53
  {
60
54
  endpoint: "GET /api/users/:id",
61
- response: (request) =>
55
+ fetch: (request) =>
62
56
  Response.json({ id: request.params.id, name: "John" }),
63
57
  },
64
58
  {
65
- endpoint: "GET *",
66
- response: () => new Response("Not found", { status: 404 }),
59
+ endpoint: "POST /api/users",
60
+ acceptedMediaTypes: ["application/json"],
61
+ fetch: async (request) => {
62
+ const user = await request.json();
63
+ return Response.json(user, { status: 201 });
64
+ },
67
65
  },
68
66
  ],
69
67
  });
70
68
  ```
71
69
 
72
- **Static File Server**
70
+ **Static file server**
73
71
 
74
72
  ```js
75
- import { startServer, createFileSystemFetch } from "@jsenv/server";
73
+ import { createFileSystemFetch, startServer } from "@jsenv/server";
76
74
 
77
75
  await startServer({
78
76
  routes: [
79
77
  {
80
78
  endpoint: "GET *",
81
- response: createFileSystemFetch(import.meta.resolve("./")),
79
+ fetch: createFileSystemFetch(import.meta.resolve("./public/"), {
80
+ etagEnabled: true,
81
+ compressionEnabled: true,
82
+ }),
82
83
  },
83
84
  ],
84
85
  });
85
86
  ```
86
87
 
87
- **HTTPS Server**
88
+ **HTTPS server**
88
89
 
89
90
  ```js
90
91
  import { readFileSync } from "node:fs";
@@ -95,16 +96,10 @@ await startServer({
95
96
  certificate: readFileSync(new URL("./server.crt", import.meta.url), "utf8"),
96
97
  privateKey: readFileSync(new URL("./server.key", import.meta.url), "utf8"),
97
98
  },
98
- allowHttpRequestOnHttps: true, // will disable https redirection and let you handle http request
99
99
  routes: [
100
100
  {
101
101
  endpoint: "GET *",
102
- response: (request) => {
103
- const clientUsesHttp = request.origin.startsWith("http:");
104
- return new Response(
105
- clientUsesHttp ? `Welcome http user` : `Welcome https user`,
106
- );
107
- },
102
+ fetch: () => new Response("Welcome"),
108
103
  },
109
104
  ],
110
105
  });
@@ -112,16 +107,20 @@ await startServer({
112
107
 
113
108
  # Documentation
114
109
 
115
- | Topic | Description |
116
- | ---------------------------------------------------- | ------------------------------------------------ |
117
- | [Handling requests](./docs/handling_requests.md) | Process HTTP requests and generate responses |
118
- | [Handling errors](./docs/handling_errors.md) | Error handling strategies and custom responses |
119
- | [Server timing](./docs/server_timing.md) | Measure and report server performance metrics |
120
- | [CORS](./docs/cors.md) | Configure Cross-Origin Resource Sharing |
121
- | [HTTPS](./docs/https.md) | Set up secure HTTPS connections |
122
- | [Serving files](./docs/serving_files.md) | Static file serving with caching and compression |
123
- | [Content negotiation](./docs/content_negotiation.md) | Content type, language and encoding negotiation |
124
- | [Websocket](./docs/websocket.md) | Bi-directional real-time communication |
125
- | [Server Sent Events](./docs/server_sent_events.md) | Push updates to clients over HTTP |
126
- | [Cluster](./docs/cluster.md) | Scale your server across multiple CPU cores |
127
- | [HTTP/2 Push](./docs/http2_push.md) | Optimize loading with server push |
110
+ Every option is described by the JSDoc of the export (`startServer`, `createFileSystemFetch`, `serverPluginCORS`, …): hover it in your editor. The pages below explain how the pieces fit together.
111
+
112
+ | Topic | Description |
113
+ | ---------------------------------------------------- | ------------------------------------------------------ |
114
+ | [Handling requests](./docs/handling_requests.md) | Routes, the request object, the response formats |
115
+ | [Handling errors](./docs/handling_errors.md) | What happens when a route throws, error pages |
116
+ | [Plugins](./docs/plugins.md) | The hooks a server plugin can implement |
117
+ | [Serving files](./docs/serving_files.md) | Static files with client cache and compression |
118
+ | [Content negotiation](./docs/content_negotiation.md) | Media type, language, version and encoding negotiation |
119
+ | [WebSocket](./docs/websocket.md) | Accepting WebSocket connections |
120
+ | [Server-Sent Events](./docs/server_sent_events.md) | Pushing events to clients |
121
+ | [CORS](./docs/cors.md) | Cross-Origin Resource Sharing |
122
+ | [HTTPS](./docs/https.md) | HTTPS, http redirection and http2 |
123
+ | [Server timing](./docs/server_timing.md) | Reporting where the server spent its time |
124
+ | [Lifecycle](./docs/lifecycle.md) | Starting, stopping, keeping the process alive |
125
+ | [Security](./docs/security.md) | What the server protects, what it leaves to you |
126
+ | [Cluster](./docs/cluster.md) | One server per CPU core |