@jnode/server 1.0.5 → 2.0.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 +394 -34
- package/package.json +2 -2
- package/src/handlers.js +246 -0
- package/src/index.js +28 -8
- package/src/routers.js +210 -0
- package/src/server.js +203 -42
- package/src/error.js +0 -32
- package/src/final.js +0 -127
- package/src/handle.js +0 -88
- package/src/map.js +0 -50
package/README.md
CHANGED
|
@@ -1,48 +1,408 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@jnode/server`
|
|
2
|
+
|
|
2
3
|
Simple web server package for Node.js.
|
|
3
4
|
|
|
4
5
|
## Installation
|
|
5
6
|
|
|
6
|
-
```
|
|
7
|
-
npm
|
|
7
|
+
```
|
|
8
|
+
npm i @jnode/server
|
|
8
9
|
```
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Quick start
|
|
11
12
|
|
|
12
|
-
### Import
|
|
13
|
+
### Import
|
|
13
14
|
|
|
14
|
-
```
|
|
15
|
-
const {
|
|
15
|
+
```js
|
|
16
|
+
const { createServer, routerConstructors: r, handlerConstructors: h } = require('@jnode/server');
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
### Start a simple server
|
|
19
|
+
### Start a simple `Hello, world.` server
|
|
19
20
|
|
|
20
|
-
```
|
|
21
|
-
const server =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
```js
|
|
22
|
+
const server = createServer(
|
|
23
|
+
// use text handler to respond with text
|
|
24
|
+
h.Text('Hello, world.')
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// listen to port 8080
|
|
28
|
+
server.listen(8080);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Start a complex file and API server
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
let requestCount = 0;
|
|
35
|
+
|
|
36
|
+
const server = createServer(
|
|
37
|
+
// use path router to route the request
|
|
38
|
+
r.Path(
|
|
39
|
+
null, // nothing should be here because a basic path is `/`
|
|
40
|
+
{
|
|
41
|
+
// a request counter api
|
|
42
|
+
// `@` makes sure the path ends here
|
|
43
|
+
'@GET /api/request-count': h.JSON({ count: requestCount }),
|
|
44
|
+
// a static file service
|
|
45
|
+
// using `r.Function(route)` to count requests before continuing
|
|
46
|
+
'GET /files': r.Function(() => {
|
|
47
|
+
requestCount++;
|
|
48
|
+
|
|
49
|
+
// return a folder handler; it will send files for remaining path segments
|
|
50
|
+
return h.Folder('./static-files/');
|
|
51
|
+
})
|
|
28
52
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// listen to port 8080
|
|
57
|
+
server.listen(8080);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## How it works?
|
|
61
|
+
|
|
62
|
+
Our world-leading **router-handler** framework brings you a simple, fast, and extensible development experience.
|
|
63
|
+
|
|
64
|
+
Here's what `@jnode/server` (shortened as **JNS**) will do:
|
|
65
|
+
|
|
66
|
+
1. Receive a request.
|
|
67
|
+
2. Use **router**s to route for a **handler**.
|
|
68
|
+
3. Use a **handler** to complete the request.
|
|
69
|
+
|
|
70
|
+
Pretty simple, isn't it?
|
|
71
|
+
|
|
72
|
+
Further, a **router** has a method `.route(env, ctx)` which returns either another **router** (to continue routing) or a **handler** (which has a method `.handle(ctx, env)` that will be executed to complete the request).
|
|
73
|
+
|
|
74
|
+
Also, we provide some powerful built-in routers and handlers so you can start building your own web server now! (Learn more in the [reference](#reference)). And you can find more routers or handlers on [npm](https://npmjs.com) with the query `@jnode/server-<name>` (built by the JNode team) or `jns-<name>` (built by the community).
|
|
75
|
+
|
|
76
|
+
------
|
|
77
|
+
|
|
78
|
+
# Reference
|
|
79
|
+
|
|
80
|
+
## `server.createServer(router[, options])`
|
|
81
|
+
|
|
82
|
+
- `router` [router](#class-serverrouter) | [handler-extended](#handler-extended) Same as the full filled return value of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
83
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
84
|
+
- `maxRoutingSteps` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) The max steps for routing; when exceeded but still getting another router, it'll throw the client a **508** error. **Default:** `50`.
|
|
85
|
+
- `enableHTTP2` [\<boolean\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) Enable HTTP/2 support (with `node:http2` [Compatibility API](https://nodejs.org/docs/latest/api/http2.html#compatibility-api)). **Default:** `false`.
|
|
86
|
+
- Options in [`http.createServer()`](https://nodejs.org/docs/latest/api/http.html#httpcreateserveroptions-requestlistener), [`https.createServer()`](https://nodejs.org/docs/latest/api/https.html#httpscreateserveroptions-requestlistener), [`http2.createServer()`](https://nodejs.org/docs/latest/api/http2.html#http2createserveroptions-onrequesthandler), or [`http2.createSecureServer()`](https://nodejs.org/docs/latest/api/http2.html#http2createsecureserveroptions-onrequesthandler).
|
|
87
|
+
- Returns: [\<server.Server\>](#class-serverserver)
|
|
88
|
+
|
|
89
|
+
We will check if `options.key` and `options.cert` exist to decide whether to enable TLS or not. Note that most browsers reject insecure HTTP/2.
|
|
90
|
+
|
|
91
|
+
## Class: `server.Server`
|
|
92
|
+
|
|
93
|
+
- Extends: [\<EventEmitter\>](https://nodejs.org/docs/latest/api/events.html#class-eventemitter)
|
|
94
|
+
|
|
95
|
+
### `new server.Server(router[, options])`
|
|
96
|
+
|
|
97
|
+
- `router` [router](#class-serverrouter) | [handler-extended](#handler-extended) Same as the return value of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
98
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as [`server.createServer()`](#servercreateserverroute-options).
|
|
99
|
+
|
|
100
|
+
More details in [`server.createServer()`](#servercreateserverroute-options).
|
|
101
|
+
|
|
102
|
+
### Static method: `Server.route(router[, env, ctx, options])`
|
|
103
|
+
|
|
104
|
+
- `router` [router](#class-serverrouter) | [handler-extended](#handler-extended) Same as the return value of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
105
|
+
- `env` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as `env` of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
106
|
+
- `ctx` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as `ctx` of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
107
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
108
|
+
- `maxRoutingSteps` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) The max steps for routing; when exceeded but still getting another router, it'll return number `508`. **Default:** `50`.
|
|
109
|
+
- Returns: [\<Promise\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) Fulfills with a [router](#class-serverrouter) or [handler-extended](#handler-extended). Simply, anything which is not a **router**. Will return `404` if router returns `undefined` or `null`.
|
|
110
|
+
|
|
111
|
+
Please note that this function will modify `env.i` to count routing steps for safety.
|
|
112
|
+
|
|
113
|
+
### `server.listen()`
|
|
114
|
+
|
|
115
|
+
Starts the server listening for connections. This method is identical to [`server.listen()`](https://nodejs.org/docs/latest/api/net.html#serverlisten) from [`net.Server`](https://nodejs.org/docs/latest/api/net.html#class-netserver).
|
|
116
|
+
|
|
117
|
+
### `server.close(...args)`
|
|
118
|
+
|
|
119
|
+
Closes the server. This method is identical to [`server.close()`](https://nodejs.org/docs/latest/api/net.html#serverclose) from [`net.Server`](https://nodejs.org/docs/latest/api/net.html#class-netserver).
|
|
120
|
+
|
|
121
|
+
### `server.throw(...args)`
|
|
122
|
+
|
|
123
|
+
Emits an error event `'e'` with the provided arguments. Useful for custom error handling and logging.
|
|
124
|
+
|
|
125
|
+
### Event: `'e'`
|
|
126
|
+
|
|
127
|
+
Emitted when an error occurs during routing or handling. The event includes the error object, `env`, and `ctx`.
|
|
128
|
+
|
|
129
|
+
### Event: `'warn'`
|
|
130
|
+
|
|
131
|
+
Emitted when a non-critical warning occurs, such as an invalid request URL.
|
|
132
|
+
|
|
133
|
+
## Class: `server.Router`
|
|
134
|
+
|
|
135
|
+
This class is a base interface that defines the structure of a **router**; it does not contain built-in logic. Any object with method [`.route(env, ctx)`](#routerrouteenv-ctx) will be viewed as a **router**.
|
|
136
|
+
|
|
137
|
+
### `router.route(env, ctx)`
|
|
138
|
+
|
|
139
|
+
- `env` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
140
|
+
- `path` [\<string[]\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The request path split by `'/'` and excluding the first segment (which is always an empty string since the path always starts with `'/'`). E.G. `'/a/b'` will become `[ 'a', 'b' ]`, and `/a/` will become `[ 'a', '' ]`.
|
|
141
|
+
- `pathPointer` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) The path index pointer. Use it in your own router if needed to ensure capability with `PathRouter`.
|
|
142
|
+
- `host` [\<string[]\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The request host split by `.` and reversed. E.G. `'example.com'` will become `[ 'com', 'example' ]`.
|
|
143
|
+
- `hostPointer` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) The host index pointer. Use it in your own router if needed so they could be compatible with the core `HostRouter`.
|
|
144
|
+
- `codeHandlers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Keys are HTTP status codes, and values are [handlers-extended](#handler-extended).
|
|
145
|
+
- `i` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) How many routers the request has gone through; do not change it in your own routers because the main loop increments it.
|
|
146
|
+
- `ctx` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
147
|
+
- `req` [\<http.IncomingMessage\>](https://nodejs.org/docs/latest/api/http.html#class-httpincomingmessage) | [\<http2.Http2ServerRequest\>](https://nodejs.org/docs/latest/api/http2.html#class-http2http2serverrequest) The request object.
|
|
148
|
+
- `res` [\<http.ServerResponse\>](https://nodejs.org/docs/latest/api/http.html#class-httpserverresponse) | [\<http2.Http2ServerResponse\>](https://nodejs.org/docs/latest/api/http2.html#class-http2http2serverresponse) The response object.
|
|
149
|
+
- `url` [\<URL\>](https://nodejs.org/docs/latest/api/url.html#class-url) The parsed request URL.
|
|
150
|
+
- `server` [\<server.Server\>](#class-serverserver) The server instance.
|
|
151
|
+
- `path` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The request path (pathname part of the URL).
|
|
152
|
+
- `host` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The request hostname.
|
|
153
|
+
- `method` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The HTTP request method (e.g., `'GET'`, `'POST'`).
|
|
154
|
+
- `headers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) The request headers.
|
|
155
|
+
- `identity` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Identity information for the requesting client.
|
|
156
|
+
- `address` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The remote address from `req.socket.remoteAddress`, may be modified by routers to resolve the original client IP behind a proxy.
|
|
157
|
+
- `port` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) The remote port from `req.socket.remotePort`, may be modified by routers to resolve the original client port behind a proxy.
|
|
158
|
+
- `params` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) The parameters including query string parameters; could also be injected by routers.
|
|
159
|
+
- `body` [\<stream.Readable\>](https://nodejs.org/docs/latest/api/stream.html#class-streamreadable) The request body stream (same as `req`).
|
|
160
|
+
|
|
161
|
+
- Returns: [\<Promise\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) | [\<router\>](#class-serverrouter) | [handler-extended](#handler-extended) Fulfills with a [router](#class-serverrouter) or [handler-extended](#handler-extended). Promise is not strictly required; synchronous functions are also acceptable.
|
|
162
|
+
|
|
163
|
+
The `env` object contains metadata mainly for the routing process, while the `ctx` object is mainly for the handling process and used to store custom properties in most cases.
|
|
164
|
+
|
|
165
|
+
Here is an example custom router:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
const { h: handlerConstructors } = require('@jnode/server');
|
|
169
|
+
|
|
170
|
+
// meow router, always responds with the text 'Meow!' if the request path contains any 'meow'
|
|
171
|
+
// (ignore why we need this)
|
|
172
|
+
class MeowRouter {
|
|
173
|
+
constructor(next) {
|
|
174
|
+
this.next = next;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// this makes the class a router
|
|
178
|
+
route(env, ctx) {
|
|
179
|
+
if (env.path.includes('meow')) {
|
|
180
|
+
return h.Text('Meow!');
|
|
38
181
|
}
|
|
182
|
+
return this.next;
|
|
39
183
|
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
As for exporting, you could make a factory function like what we done in official routers:
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
// exporting
|
|
191
|
+
module.exports = {
|
|
192
|
+
MeowRouter, // original class
|
|
193
|
+
routerConstructors: {
|
|
194
|
+
Meow: (...args) => new MeowRouter(...args)
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
If you even want to publish your routers or handlers on [npm](https://npmjs.com) (why not?), feel free to name your package as `jns-<name>` so other developers will know it's for `@jnode/server`! E.G. `jns-meow`.
|
|
200
|
+
|
|
201
|
+
## Class: `server.Handler`
|
|
202
|
+
|
|
203
|
+
This class is a base interface that defines the structure of a **handler**; it does not contain built-in logic. Any object with method [`.handle(ctx, env)`](#handlerhandlectx-env) will be viewed as a **handler**.
|
|
204
|
+
|
|
205
|
+
### `handler.handle(ctx, env)`
|
|
206
|
+
|
|
207
|
+
- `ctx` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as `ctx` of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
208
|
+
- `env` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as `env` of [`router.route(env, ctx)`](#routerrouteenv-ctx).
|
|
209
|
+
|
|
210
|
+
Handlers can throw a numeric error code to call `codeHandlers`, e.g., `throw 404`.
|
|
211
|
+
|
|
212
|
+
Here is an example custom handler:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
// random int handler, returns a random integer
|
|
216
|
+
class RandomIntHandler {
|
|
217
|
+
constructor(from, to, options) {
|
|
218
|
+
this.from = from;
|
|
219
|
+
this.to = to;
|
|
220
|
+
this.options = options;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// this makes the class a handler
|
|
224
|
+
handle(ctx, env) {
|
|
225
|
+
const num = String(Math.floor(Math.random() * (this.to - this.from + 1)) + this.from);
|
|
226
|
+
|
|
227
|
+
const headers = this.options.headers ?? {};
|
|
228
|
+
headers['Content-Type'] = headers['Content-Type'] ?? 'text/plain';
|
|
229
|
+
headers['Content-Length'] = Buffer.byteLength(num, 'utf8');
|
|
230
|
+
|
|
231
|
+
ctx.res.writeHead(this.options.statusCode ?? 200, headers);
|
|
232
|
+
ctx.res.end(num);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `handler-extended`
|
|
238
|
+
|
|
239
|
+
`handler-extended` includes a standard [handler](#class-serverhandler) and the following types:
|
|
240
|
+
|
|
241
|
+
- Number status code, we will find the actual handler from `env.codeHandlers`.
|
|
242
|
+
- String, [`Buffer`](https://nodejs.org/docs/latest/api/buffer.html#class-buffer), [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), or [`stream.Readable`](https://nodejs.org/docs/latest/api/stream.html#class-streamreadable) as body, only for simple situations because you could not modify status code or headers.
|
|
243
|
+
- Function does the same thing as [`handler.handle(ctx, env)`](#handlerhandlectx-env).
|
|
244
|
+
|
|
245
|
+
## `server.mimeTypes`
|
|
246
|
+
|
|
247
|
+
- Type: [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
248
|
+
|
|
249
|
+
A mapping of file extensions (`.<ext>`) to their corresponding MIME types.
|
|
250
|
+
|
|
251
|
+
## Built-in routers
|
|
252
|
+
|
|
253
|
+
We provide two methods to use them:
|
|
254
|
+
|
|
255
|
+
1. `new` based, use it via `new server.<Name>Router(...)`.
|
|
256
|
+
2. Factory functions, use it via `server.routerConstructors.<Name>(...)`.
|
|
257
|
+
|
|
258
|
+
### Router: `PathRouter(end, map)`
|
|
259
|
+
|
|
260
|
+
- `end` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the path resolver came to the end (`env.pathPointer >= env.path.length`).
|
|
261
|
+
- `map` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
262
|
+
- `/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) A simple path segment routing. E.G., `'/meow': 'Meow!'` (ignoring later segments, `'/meow/something'` will also have the same result as `'/meow'`), `'/cats': r.Path(null, { '/meow': 'Meow!! Meow!!' })` or `'/cats/meow': 'Meow!! Meow!!'`.
|
|
263
|
+
- `@/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the path resolver ends here; equals to `'/<path_segment>': r.Path(<value>)`. E.G., `'@/meow': 'Meow!'` (only works for path `'/meow'` but not `'/meow/something'`).
|
|
264
|
+
- `<METHOD>/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the method matches; equals to `'/<path_segment>': r.Method({ '<METHOD>': <value> })`. E.G., `'GET/meow': 'Meow!'` (only works for HTTP method `'GET'`).
|
|
265
|
+
- `@<METHOD>/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when both the path resolver ends and the method matches; equals to `'/<path_segment>': r.Path(r.Method({ '<METHOD>': <value> }))`. E.G., `'@GET/meow': 'Meow!'` (only works for path `'/meow'` but not `'/meow/something'` and request method is `'GET'`).
|
|
266
|
+
- `*` [router](#class-serverrouter) | [handler-extended](#handler-extended) Any path segment. E.G. `'*': h.Text('Meow? Nothing here!', { statusCode: 404 })`.
|
|
267
|
+
|
|
268
|
+
`PathRouter` is probably the most important router; almost every server needs it!
|
|
269
|
+
|
|
270
|
+
By the way, we **DO NOT** support `'/*'` as a universal matching character, don't try this.
|
|
271
|
+
|
|
272
|
+
#### How it works?
|
|
273
|
+
|
|
274
|
+
This section delves into the intricacies of how `PathRouter` functions. If you’re not interested in this topic, feel free to skip it.
|
|
275
|
+
|
|
276
|
+
Everything begins with the constructor. When we receive your `map`, we parse it into an internal structure. Here's an example:
|
|
277
|
+
|
|
278
|
+
```js
|
|
279
|
+
// the map you passed in
|
|
280
|
+
map = {
|
|
281
|
+
'/a': 'A!',
|
|
282
|
+
'/a/b': 'B!',
|
|
283
|
+
'@/a/b': 'C!',
|
|
284
|
+
'GET/a': 'D!',
|
|
285
|
+
'@GET/a/b': 'E!',
|
|
286
|
+
'*': 'F!'
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// we will parse into
|
|
290
|
+
parsed = {
|
|
291
|
+
'/a': {
|
|
292
|
+
'*': { // note that the * here doesn't count for path resolver
|
|
293
|
+
// object of methods
|
|
294
|
+
'*': 'A!',
|
|
295
|
+
'GET': 'D!'
|
|
296
|
+
},
|
|
297
|
+
'/b': {
|
|
298
|
+
'*': {
|
|
299
|
+
// object of methods
|
|
300
|
+
'*': 'B!'
|
|
301
|
+
},
|
|
302
|
+
'@': {
|
|
303
|
+
'*': 'C!',
|
|
304
|
+
'GET': 'E!'
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
'*': 'F!'
|
|
309
|
+
};
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
This format enables fast and flexible path routing while keeping it simple for developers.
|
|
313
|
+
|
|
314
|
+
### Router: `HostRouter(end, map)`
|
|
315
|
+
|
|
316
|
+
- `end` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the host resolver came to the end (`env.hostPointer >= env.host.length`).
|
|
317
|
+
- `map` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
318
|
+
- `.<host_segment>[.<host_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) A simple host segment routing (reversed). E.G., `.example.com` will match `example.com`, `.localhost` will match `localhost`.
|
|
319
|
+
- `@.<host_segment>[.<host_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the host resolver ends here. E.G., `@.example.com` (only works for exactly `example.com` but not `sub.example.com`).
|
|
320
|
+
- `*` [router](#class-serverrouter) | [handler-extended](#handler-extended) Any host segment.
|
|
321
|
+
|
|
322
|
+
### Router: `MethodRouter(methodMap)`
|
|
323
|
+
|
|
324
|
+
- `methodMap` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
325
|
+
- `<METHOD>` [router](#class-serverrouter) | [handler-extended](#handler-extended) A simple method routing. E.G., `'GET': h.Text('Hello!')`, `'POST': h.JSON({ ok: true })`.
|
|
326
|
+
- `*` [router](#class-serverrouter) | [handler-extended](#handler-extended) Any method, used as fallback.
|
|
327
|
+
- Returns: [\<MethodRouter\>](#router-methodroutermethodmap) Routes based on HTTP method, returns 405 if no method matches.
|
|
328
|
+
|
|
329
|
+
### Router: `FunctionRouter(fn)`
|
|
330
|
+
|
|
331
|
+
- `fn` [\<Function\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) A function with signature `(env, ctx) => router | handler-extended`.
|
|
332
|
+
|
|
333
|
+
A simple router that allows you to implement custom routing logic.
|
|
334
|
+
|
|
335
|
+
### Router: `PathArgRouter(paramName, next)`
|
|
336
|
+
|
|
337
|
+
- `paramName` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The parameter name to save the current path segment.
|
|
338
|
+
- `next` [router](#class-serverrouter) | [handler-extended](#handler-extended) The next router or handler to call after collecting the parameter.
|
|
339
|
+
|
|
340
|
+
Collects a path segment and saves it to `ctx.params[paramName]`, then advances the path pointer and continues routing.
|
|
341
|
+
|
|
342
|
+
### Router: `HostArgRouter(paramName, next)`
|
|
343
|
+
|
|
344
|
+
- `paramName` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The parameter name to save the current host segment.
|
|
345
|
+
- `next` [router](#class-serverrouter) | [handler-extended](#handler-extended) The next router or handler to call after collecting the parameter.
|
|
346
|
+
|
|
347
|
+
Collects a host segment and saves it to `ctx.params[paramName]`, then advances the host pointer and continues routing.
|
|
348
|
+
|
|
349
|
+
## Built-in handlers
|
|
350
|
+
|
|
351
|
+
We provide two methods to use them:
|
|
352
|
+
|
|
353
|
+
1. `new` based, use it via `new server.<Name>Handler(...)`.
|
|
354
|
+
2. Factory functions, use it via `server.handlerConstructors.<Name>(...)`.
|
|
355
|
+
|
|
356
|
+
### Handler: `DataHandler(data[, options])` (alias: `TextHandler`)
|
|
357
|
+
|
|
358
|
+
- `data` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | [\<Buffer\>](https://nodejs.org/docs/latest/api/buffer.html#class-buffer) | [\<Uint8Array\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) | [\<stream.Readable\>](https://nodejs.org/docs/latest/api/stream.html#class-streamreadable) The data to send.
|
|
359
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
360
|
+
- `statusCode` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) HTTP status code. **Default:** `200`.
|
|
361
|
+
- `headers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Additional headers to send.
|
|
362
|
+
|
|
363
|
+
Sends string, buffer, or stream data as response body. Automatically sets appropriate `Content-Type` and `Content-Length` headers.
|
|
364
|
+
|
|
365
|
+
### Handler: `FileHandler(file[, options])`
|
|
366
|
+
|
|
367
|
+
- `file` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) Path to the file to serve.
|
|
368
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
369
|
+
- `statusCode` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) HTTP status code. **Default:** `200`.
|
|
370
|
+
- `headers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Additional headers to send.
|
|
371
|
+
- `cache` [\<boolean\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) | [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) Enable caching with `ETag` and `Last-Modified` headers. If `true`, uses only conditional caching. If number, also sets `Cache-Control: max-age=<value>`. **Default:** `false`.
|
|
372
|
+
- `disableRange` [\<boolean\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) Disable HTTP Range requests. Also automatically disabled when `statusCode` is not 200. **Default:** `false`.
|
|
373
|
+
- `disableHead` [\<boolean\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) Disable HEAD request support. **Default:** `false`.
|
|
374
|
+
- `highWaterMark` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) Stream high water mark in bytes. **Default:** `65536`.
|
|
375
|
+
|
|
376
|
+
Serves a single file with support for HTTP Range requests, caching headers, and ETag validation. Throws `404` if file not found or is not a regular file; throws `416` if range is invalid. Supports `304 Not Modified` responses for conditional requests.
|
|
377
|
+
|
|
378
|
+
### Handler: `FolderHandler(folder[, options])`
|
|
379
|
+
|
|
380
|
+
- `folder` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) Path to the folder to serve files from.
|
|
381
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Same as [`FileHandler` options](#handler-filehandlerfile-options).
|
|
382
|
+
|
|
383
|
+
Serves files from a folder based on remaining path segments. Automatically resolves paths and prevents directory traversal attacks. Internally uses `FileHandler`.
|
|
384
|
+
|
|
385
|
+
### Handler: `JSONHandler(obj[, options])`
|
|
386
|
+
|
|
387
|
+
- `obj` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) The object to serialize and send as JSON.
|
|
388
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
389
|
+
- `statusCode` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) HTTP status code. **Default:** `200`.
|
|
390
|
+
- `headers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Additional headers to send.
|
|
391
|
+
|
|
392
|
+
Sends a JavaScript object serialized as JSON with `Content-Type: application/json; charset=utf-8`.
|
|
393
|
+
|
|
394
|
+
### Handler: `RedirectHandler(location[, options])`
|
|
395
|
+
|
|
396
|
+
- `location` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) The redirect target URL.
|
|
397
|
+
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
398
|
+
- `statusCode` [\<number\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) HTTP status code. **Default:** `307`.
|
|
399
|
+
- `base` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) Base URL for relative redirects. If set, the redirect location will be constructed as `base + remaining path`.
|
|
400
|
+
- `headers` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) Additional headers to send.
|
|
401
|
+
|
|
402
|
+
Redirects the request to a specified location. Supports both absolute URLs and dynamic redirects based on remaining path segments.
|
|
403
|
+
|
|
404
|
+
### Handler: `FunctionHandler(func)`
|
|
405
|
+
|
|
406
|
+
- `func` [\<Function\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) A function with signature `(ctx, env) => void | Promise<void>`.
|
|
407
|
+
|
|
408
|
+
Allows you to implement custom request handling logic directly within a function.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jnode/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Simple web server package for Node.js.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,4 +25,4 @@
|
|
|
25
25
|
"url": "https://github.com/japple-jnode/server/issues"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/japple-jnode/server#readme"
|
|
28
|
-
}
|
|
28
|
+
}
|