woodland 18.2.4 → 18.2.6

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/LICENSE CHANGED
@@ -1,27 +1,27 @@
1
- Copyright (c) 2023, Jason Mulligan
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
-
7
- * Redistributions of source code must retain the above copyright notice, this
8
- list of conditions and the following disclaimer.
9
-
10
- * Redistributions in binary form must reproduce the above copyright notice,
11
- this list of conditions and the following disclaimer in the documentation
12
- and/or other materials provided with the distribution.
13
-
14
- * Neither the name of woodland nor the names of its
15
- contributors may be used to endorse or promote products derived from
16
- this software without specific prior written permission.
17
-
18
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1
+ Copyright (c) 2024, Jason Mulligan
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of woodland nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,251 +1,251 @@
1
- <img src="https://avoidwork.github.io/woodland/logo.svg" width="108" />
2
-
3
- # Woodland
4
-
5
- Lightweight HTTP framework with automatic headers. Routes can use parameter syntax, i.e. `/users/:id`, or `RegExp` syntax. Route parameters are not sanitized. If 2+ routes with parameters match a request the first route will be used to extract parameters. All HTTP methods are supported.
6
-
7
- `CORS` (Cross Origin Resource Sharing) is automatically handled, and indicated with `cors` Boolean on the `request` Object for middleware.
8
-
9
- Middleware arguments can be `req, res, next` or `error, req, res, next`. If no `Error` handling middleware is registered woodland will handle it.
10
-
11
- ## Using the factory
12
-
13
- ```javascript
14
- import {createServer} from "node:http";
15
- import {woodland} from "woodland";
16
-
17
- const app = woodland({
18
- defaultHeaders: {
19
- "cache-control": "public, max-age=3600",
20
- "content-type": "text/plain"
21
- },
22
- time: true
23
- });
24
-
25
- app.get("/", (req, res) => res.send("Custom greeting at '/:user', try it out!"));
26
- app.get("/:user", (req, res) => res.send(`Hello ${req.params.user}!`));
27
- createServer(app.route).listen(8000);
28
- ```
29
-
30
- ## Using the Class
31
-
32
- ```javascript
33
- import {Woodland} from "woodland";
34
- class MyFramework extends Woodland {};
35
- ```
36
-
37
- ## Testing
38
-
39
- Woodland has 100% code coverage with its tests; the missing 0.22% is hard to reach conditions.
40
-
41
- ```console
42
- --------------|---------|----------|---------|---------|-------------------------------
43
- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
44
- --------------|---------|----------|---------|---------|-------------------------------
45
- All files | 99.78 | 76.02 | 98.57 | 100 |
46
- woodland.cjs | 99.78 | 76.02 | 98.57 | 100 | ...214,254,275-285,314-328,...
47
- --------------|---------|----------|---------|---------|-------------------------------
48
- ```
49
-
50
- ## Benchmark
51
- Please benchmark `woodland` on your target hardware to understand the overhead which is expected to be <15% with etags disabled, or <25% with etags enabled. E.g. if `http` can handle 50k req/s, then `woodland` should handle 43k req/s.
52
-
53
- 1. Clone repository from [GitHub](https://github.com/avoidwork/woodland).
54
- 1. Install dependencies with `npm` or `yarn`.
55
- 1. Execute `benchmark` script with `npm` or `yarn`.
56
-
57
- Results with node.js 20.8.0 & an Intel i9-12900HX (mobile) on Windows 11, with etags disabled.
58
-
59
- ```console
60
- > node benchmark.js
61
-
62
- http
63
- ┌─────────┬──────┬──────┬───────┬───────┬──────────┬──────────┬───────┐
64
- │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
65
- ├─────────┼──────┼──────┼───────┼───────┼──────────┼──────────┼───────┤
66
- │ Latency │ 1 ms │ 8 ms │ 42 ms │ 47 ms │ 10.81 ms │ 10.26 ms │ 88 ms │
67
- └─────────┴──────┴──────┴───────┴───────┴──────────┴──────────┴───────┘
68
- ┌───────────┬─────────┬─────────┬───────┬───────┬─────────┬─────────┬─────────┐
69
- │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
70
- ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
71
- │ Req/Sec │ 75967 │ 75967 │ 88703 │ 93823 │ 88409.6 │ 4152.76 │ 75952 │
72
- ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
73
- │ Bytes/Sec │ 15.4 MB │ 15.4 MB │ 18 MB │ 19 MB │ 17.9 MB │ 841 kB │ 15.4 MB │
74
- └───────────┴─────────┴─────────┴───────┴───────┴─────────┴─────────┴─────────┘
75
-
76
- woodland
77
- ┌─────────┬──────┬──────┬───────┬───────┬──────────┬──────────┬────────┐
78
- │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
79
- ├─────────┼──────┼──────┼───────┼───────┼──────────┼──────────┼────────┤
80
- │ Latency │ 2 ms │ 9 ms │ 57 ms │ 67 ms │ 12.82 ms │ 13.04 ms │ 119 ms │
81
- └─────────┴──────┴──────┴───────┴───────┴──────────┴──────────┴────────┘
82
- ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
83
- │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
84
- ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
85
- │ Req/Sec │ 66687 │ 66687 │ 75263 │ 76095 │ 75041.61 │ 1482.92 │ 66667 │
86
- ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
87
- │ Bytes/Sec │ 14.1 MB │ 14.1 MB │ 15.9 MB │ 16.1 MB │ 15.8 MB │ 312 kB │ 14.1 MB │
88
- └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘
89
-
90
- ```
91
-
92
- ## API
93
- ### constructor ({...})
94
- Returns a woodland instance. Enable directory browsing & traversal with `autoindex`. Create an automatic `x-response-time` response header with `time` & `digit`. Customize `etag` response header with `seed`.
95
-
96
- #### Configuration
97
-
98
- ```json
99
- {
100
- "autoindex": false,
101
- "cacheSize": 1000,
102
- "cacheTTL": 300000,
103
- "charset": "utf-8",
104
- "corsExpose": "",
105
- "defaultHeaders": {},
106
- "digit": 3,
107
- "etags": true,
108
- "indexes": [
109
- "index.htm",
110
- "index.html"
111
- ],
112
- "logging": {
113
- "enabled": true,
114
- "format": "%h %l %u %t \"%r\" %>s %b",
115
- "level": "info"
116
- },
117
- "origins": [
118
- "*"
119
- ],
120
- "silent": false,
121
- "time": false
122
- }
123
- ```
124
-
125
- ### allowed (method, uri, override = false)
126
- Calls `routes()` and returns a `Boolean` to indicate if `method` is allowed for `uri`.
127
-
128
- ### allows (uri, override = false)
129
- Returns a `String` for the `Allow` header. Caches value, & will update cache if `override` is `true`.
130
-
131
- ### always (path, fn)
132
- Registers middleware for a route for all HTTP methods; runs first. `path` is a regular expression (as a string), and if not passed it defaults to `/.*`.
133
-
134
- Execute `ignore(fn)` if you do not want the middleware included for calculating the `Allow` header.
135
-
136
- ### ignore (fn)
137
- Ignores `fn` for calculating the return of `allows()`.
138
-
139
- ### decorate (req, res)
140
- Decorates `allow, body, cors, host, ip, params, & parsed` on `req` and `error(status[, body, headers]), header(key, value), json(body[, status, headers]), locals{} & redirect(url[, perm = false])` on `res`.
141
-
142
- ### etag (...args)
143
- Returns a String to be used as an etag response header value.
144
-
145
- ### list (method = "get", type = "array")
146
- Returns an `Array` or `Object` of routes for the specified method.
147
-
148
- ### log (msg = "", level = "debug")
149
- Logs to `stdout` or `stderr` depending on the `level`, & what the minimum log level is set to.
150
-
151
- ### onsend (req, res, body, status, headers)
152
- **Override** to customize response `body`, `status`, or `headers`. Must return `[body, status, headers]`!
153
-
154
- ### route (req, res)
155
- Function for `http.createServer()` or `https.createServer()`.
156
-
157
- ### routes (uri, method, override = false)
158
- Returns an `Array` of middleware for the request. Caches value, & will update cache if `override` is `true`.
159
-
160
- ### serve (req, res, localFilePath, folderPath, indexes = this.indexes)
161
- Serve static files on disk. Use a route parameter or remove `folderPath` from `req.parsed.pathname` to create `localFilePath`.
162
-
163
- #### Without `autoindex`
164
- ```javascript
165
- app.use("/files/:file", (req, res) => app.serve(req, res, req.params.file, path.join(__dirname, "files")));
166
- ```
167
-
168
- #### With `autoindex`
169
- ```javascript
170
- app.use("/files(/.*)?", (req, res) => app.serve(req, res, req.parsed.pathname.replace(/^\/files\/?/, ""), join(__dirname, "files")));
171
- ```
172
-
173
- ### staticFiles (root = "/")
174
- Serve static files on disk. Calls `this.serve()`.
175
-
176
- ### use ([path = "/.*",] ...fn[, method = "GET"])
177
- Registers middleware for a route. `path` is a regular expression (as a string), and if not passed it defaults to `/.*`. See `always()` if you want the middleware to be used for all HTTP methods.
178
-
179
- All HTTP methods are available on the prototype (partial application of the third argument), e.g. `get([path,] ...fn)` & `options([path,] ...fn)`.
180
-
181
- ## Command Line Interface (CLI)
182
- When woodland is installed as a global module you can serve the contents of a folder by executing `woodland` in a shell. Optional parameters are `--ip=127.0.0.1` & `--port=8000`.
183
-
184
- ```console
185
- Node.js v20.8.0
186
- PS C:\Users\jason\Projects> npm install -g woodland
187
-
188
- changed 6 packages in 1s
189
- PS C:\Users\jason\Projects> woodland
190
- id=woodland, hostname=localhost, ip=127.0.0.1, port=8000
191
- 127.0.0.1 - [7/Oct/2023:15:18:18 -0400] "GET / HTTP/1.1" 200 1327
192
- 127.0.0.1 - [7/Oct/2023:15:18:26 -0400] "GET /woodland/ HTTP/1.1" 200 2167
193
- 127.0.0.1 - [7/Oct/2023:15:18:29 -0400] "GET /woodland/dist/ HTTP/1.1" 200 913
194
- 127.0.0.1 - [7/Oct/2023:15:18:32 -0400] "GET /woodland/dist/woodland.js HTTP/1.1" 200 26385
195
- 127.0.0.1 - [7/Oct/2023:15:18:47 -0400] "GET /woodland/benchmark.js HTTP/1.1" 200 1657
196
- 127.0.0.1 - [7/Oct/2023:15:18:58 -0400] "GET /woodland/sample.js HTTP/1.1" 200 845
197
- 127.0.0.1 - [7/Oct/2023:15:19:07 -0400] "GET /woodland/sample.js HTTP/1.1" 304 0
198
- ```
199
-
200
- ## Event Handlers
201
- Event Emitter syntax for the following events:
202
-
203
- ```javascript
204
- app.on("connect", (req, res) => res.header("x-custom-header", "abc-def"));
205
- ```
206
-
207
- ### connect (req, res)
208
- Executes after the connection has been decorated, but before the middleware executes.
209
-
210
- ### error (req, res, err)
211
- Executes after the response has been sent.
212
-
213
- ### finish (req, res)
214
- Executes after the response has been sent.
215
-
216
- ## Helpers
217
- `req` & `res` are decorated with helper functions to simplify responding.
218
-
219
- ### res.error(status[, body, headers])
220
- Sends an error response.
221
-
222
- ### res.header(key, value)
223
- Shorthand of `res.setHeader()`.
224
-
225
- ### res.json(body, [status = 200, headers])
226
- Sends a JSON response.
227
-
228
- ### res.last(req, res, next)
229
- Last middleware of the route for the HTTP method as a way to "skip" to the middleware which sends a response.
230
-
231
- ### res.redirect(uri[, perm = false])
232
- Sends a redirection response.
233
-
234
- ### res.send(body, [status = 200, headers = {}])
235
- Sends a response. `Range` header is ignored on `stream` responses.
236
-
237
- ### res.set(headers = {})
238
- Shorthand of `res.setHeaders()` which accepts `Object`, `Map`, or `Headers` instances.
239
-
240
- ### res.status(arg)
241
- Sets the response `statusCode` property.
242
-
243
- ## Logging
244
- Woodland defaults to [Common Log Format](https://en.wikipedia.org/wiki/Common_Log_Format) but supports [Common Log Format with Virtual Host](https://httpd.apache.org/docs/trunk/mod/mod_log_config.html), & [NCSA extended/combined log format](https://httpd.apache.org/docs/trunk/mod/mod_log_config.html) with an `info` level by default. You can change the `stdout` output by changing `logging.format` with valid placeholders.
245
-
246
- You can disable woodland's logging by configuration with `{logging: {enabled: false}}`.
247
-
248
- ## License
249
- Copyright (c) 2023 Jason Mulligan
250
-
251
- Licensed under the BSD-3 license.
1
+ <img src="https://avoidwork.github.io/woodland/logo.svg" width="108" />
2
+
3
+ # Woodland
4
+
5
+ Lightweight HTTP framework with automatic headers. Routes can use parameter syntax, i.e. `/users/:id`, or `RegExp` syntax. Route parameters are not sanitized. If 2+ routes with parameters match a request the first route will be used to extract parameters. All HTTP methods are supported.
6
+
7
+ `CORS` (Cross Origin Resource Sharing) is automatically handled, and indicated with `cors` Boolean on the `request` Object for middleware.
8
+
9
+ Middleware arguments can be `req, res, next` or `error, req, res, next`. If no `Error` handling middleware is registered woodland will handle it.
10
+
11
+ ## Using the factory
12
+
13
+ ```javascript
14
+ import {createServer} from "node:http";
15
+ import {woodland} from "woodland";
16
+
17
+ const app = woodland({
18
+ defaultHeaders: {
19
+ "cache-control": "public, max-age=3600",
20
+ "content-type": "text/plain"
21
+ },
22
+ time: true
23
+ });
24
+
25
+ app.get("/", (req, res) => res.send("Custom greeting at '/:user', try it out!"));
26
+ app.get("/:user", (req, res) => res.send(`Hello ${req.params.user}!`));
27
+ createServer(app.route).listen(8000);
28
+ ```
29
+
30
+ ## Using the Class
31
+
32
+ ```javascript
33
+ import {Woodland} from "woodland";
34
+ class MyFramework extends Woodland {};
35
+ ```
36
+
37
+ ## Testing
38
+
39
+ Woodland has 100% code coverage with its tests; the missing 0.22% is hard to reach conditions.
40
+
41
+ ```console
42
+ --------------|---------|----------|---------|---------|-------------------------------
43
+ File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
44
+ --------------|---------|----------|---------|---------|-------------------------------
45
+ All files | 99.78 | 76.02 | 98.57 | 100 |
46
+ woodland.cjs | 99.78 | 76.02 | 98.57 | 100 | ...214,254,275-285,314-328,...
47
+ --------------|---------|----------|---------|---------|-------------------------------
48
+ ```
49
+
50
+ ## Benchmark
51
+ Please benchmark `woodland` on your target hardware to understand the overhead which is expected to be <15% with etags disabled, or <25% with etags enabled. E.g. if `http` can handle 50k req/s, then `woodland` should handle 43k req/s.
52
+
53
+ 1. Clone repository from [GitHub](https://github.com/avoidwork/woodland).
54
+ 1. Install dependencies with `npm` or `yarn`.
55
+ 1. Execute `benchmark` script with `npm` or `yarn`.
56
+
57
+ Results with node.js 20.8.0 & an Intel i9-12900HX (mobile) on Windows 11, with etags disabled.
58
+
59
+ ```console
60
+ > node benchmark.js
61
+
62
+ http
63
+ ┌─────────┬──────┬──────┬───────┬───────┬──────────┬──────────┬───────┐
64
+ │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
65
+ ├─────────┼──────┼──────┼───────┼───────┼──────────┼──────────┼───────┤
66
+ │ Latency │ 1 ms │ 8 ms │ 42 ms │ 47 ms │ 10.81 ms │ 10.26 ms │ 88 ms │
67
+ └─────────┴──────┴──────┴───────┴───────┴──────────┴──────────┴───────┘
68
+ ┌───────────┬─────────┬─────────┬───────┬───────┬─────────┬─────────┬─────────┐
69
+ │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
70
+ ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
71
+ │ Req/Sec │ 75967 │ 75967 │ 88703 │ 93823 │ 88409.6 │ 4152.76 │ 75952 │
72
+ ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
73
+ │ Bytes/Sec │ 15.4 MB │ 15.4 MB │ 18 MB │ 19 MB │ 17.9 MB │ 841 kB │ 15.4 MB │
74
+ └───────────┴─────────┴─────────┴───────┴───────┴─────────┴─────────┴─────────┘
75
+
76
+ woodland
77
+ ┌─────────┬──────┬──────┬───────┬───────┬──────────┬──────────┬────────┐
78
+ │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
79
+ ├─────────┼──────┼──────┼───────┼───────┼──────────┼──────────┼────────┤
80
+ │ Latency │ 2 ms │ 9 ms │ 57 ms │ 67 ms │ 12.82 ms │ 13.04 ms │ 119 ms │
81
+ └─────────┴──────┴──────┴───────┴───────┴──────────┴──────────┴────────┘
82
+ ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
83
+ │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
84
+ ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
85
+ │ Req/Sec │ 66687 │ 66687 │ 75263 │ 76095 │ 75041.61 │ 1482.92 │ 66667 │
86
+ ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
87
+ │ Bytes/Sec │ 14.1 MB │ 14.1 MB │ 15.9 MB │ 16.1 MB │ 15.8 MB │ 312 kB │ 14.1 MB │
88
+ └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘
89
+
90
+ ```
91
+
92
+ ## API
93
+ ### constructor ({...})
94
+ Returns a woodland instance. Enable directory browsing & traversal with `autoindex`. Create an automatic `x-response-time` response header with `time` & `digit`. Customize `etag` response header with `seed`.
95
+
96
+ #### Configuration
97
+
98
+ ```json
99
+ {
100
+ "autoindex": false,
101
+ "cacheSize": 1000,
102
+ "cacheTTL": 300000,
103
+ "charset": "utf-8",
104
+ "corsExpose": "",
105
+ "defaultHeaders": {},
106
+ "digit": 3,
107
+ "etags": true,
108
+ "indexes": [
109
+ "index.htm",
110
+ "index.html"
111
+ ],
112
+ "logging": {
113
+ "enabled": true,
114
+ "format": "%h %l %u %t \"%r\" %>s %b",
115
+ "level": "info"
116
+ },
117
+ "origins": [
118
+ "*"
119
+ ],
120
+ "silent": false,
121
+ "time": false
122
+ }
123
+ ```
124
+
125
+ ### allowed (method, uri, override = false)
126
+ Calls `routes()` and returns a `Boolean` to indicate if `method` is allowed for `uri`.
127
+
128
+ ### allows (uri, override = false)
129
+ Returns a `String` for the `Allow` header. Caches value, & will update cache if `override` is `true`.
130
+
131
+ ### always (path, fn)
132
+ Registers middleware for a route for all HTTP methods; runs first. `path` is a regular expression (as a string), and if not passed it defaults to `/.*`.
133
+
134
+ Execute `ignore(fn)` if you do not want the middleware included for calculating the `Allow` header.
135
+
136
+ ### ignore (fn)
137
+ Ignores `fn` for calculating the return of `allows()`.
138
+
139
+ ### decorate (req, res)
140
+ Decorates `allow, body, cors, host, ip, params, & parsed` on `req` and `error(status[, body, headers]), header(key, value), json(body[, status, headers]), locals{} & redirect(url[, perm = false])` on `res`.
141
+
142
+ ### etag (...args)
143
+ Returns a String to be used as an etag response header value.
144
+
145
+ ### list (method = "get", type = "array")
146
+ Returns an `Array` or `Object` of routes for the specified method.
147
+
148
+ ### log (msg = "", level = "debug")
149
+ Logs to `stdout` or `stderr` depending on the `level`, & what the minimum log level is set to.
150
+
151
+ ### onsend (req, res, body, status, headers)
152
+ **Override** to customize response `body`, `status`, or `headers`. Must return `[body, status, headers]`!
153
+
154
+ ### route (req, res)
155
+ Function for `http.createServer()` or `https.createServer()`.
156
+
157
+ ### routes (uri, method, override = false)
158
+ Returns an `Array` of middleware for the request. Caches value, & will update cache if `override` is `true`.
159
+
160
+ ### serve (req, res, localFilePath, folderPath, indexes = this.indexes)
161
+ Serve static files on disk. Use a route parameter or remove `folderPath` from `req.parsed.pathname` to create `localFilePath`.
162
+
163
+ #### Without `autoindex`
164
+ ```javascript
165
+ app.use("/files/:file", (req, res) => app.serve(req, res, req.params.file, path.join(__dirname, "files")));
166
+ ```
167
+
168
+ #### With `autoindex`
169
+ ```javascript
170
+ app.use("/files(/.*)?", (req, res) => app.serve(req, res, req.parsed.pathname.replace(/^\/files\/?/, ""), join(__dirname, "files")));
171
+ ```
172
+
173
+ ### staticFiles (root = "/")
174
+ Serve static files on disk. Calls `this.serve()`.
175
+
176
+ ### use ([path = "/.*",] ...fn[, method = "GET"])
177
+ Registers middleware for a route. `path` is a regular expression (as a string), and if not passed it defaults to `/.*`. See `always()` if you want the middleware to be used for all HTTP methods.
178
+
179
+ All HTTP methods are available on the prototype (partial application of the third argument), e.g. `get([path,] ...fn)` & `options([path,] ...fn)`.
180
+
181
+ ## Command Line Interface (CLI)
182
+ When woodland is installed as a global module you can serve the contents of a folder by executing `woodland` in a shell. Optional parameters are `--ip=127.0.0.1` & `--port=8000`.
183
+
184
+ ```console
185
+ Node.js v20.8.0
186
+ PS C:\Users\jason\Projects> npm install -g woodland
187
+
188
+ changed 6 packages in 1s
189
+ PS C:\Users\jason\Projects> woodland
190
+ id=woodland, hostname=localhost, ip=127.0.0.1, port=8000
191
+ 127.0.0.1 - [7/Oct/2023:15:18:18 -0400] "GET / HTTP/1.1" 200 1327
192
+ 127.0.0.1 - [7/Oct/2023:15:18:26 -0400] "GET /woodland/ HTTP/1.1" 200 2167
193
+ 127.0.0.1 - [7/Oct/2023:15:18:29 -0400] "GET /woodland/dist/ HTTP/1.1" 200 913
194
+ 127.0.0.1 - [7/Oct/2023:15:18:32 -0400] "GET /woodland/dist/woodland.js HTTP/1.1" 200 26385
195
+ 127.0.0.1 - [7/Oct/2023:15:18:47 -0400] "GET /woodland/benchmark.js HTTP/1.1" 200 1657
196
+ 127.0.0.1 - [7/Oct/2023:15:18:58 -0400] "GET /woodland/sample.js HTTP/1.1" 200 845
197
+ 127.0.0.1 - [7/Oct/2023:15:19:07 -0400] "GET /woodland/sample.js HTTP/1.1" 304 0
198
+ ```
199
+
200
+ ## Event Handlers
201
+ Event Emitter syntax for the following events:
202
+
203
+ ```javascript
204
+ app.on("connect", (req, res) => res.header("x-custom-header", "abc-def"));
205
+ ```
206
+
207
+ ### connect (req, res)
208
+ Executes after the connection has been decorated, but before the middleware executes.
209
+
210
+ ### error (req, res, err)
211
+ Executes after the response has been sent.
212
+
213
+ ### finish (req, res)
214
+ Executes after the response has been sent.
215
+
216
+ ## Helpers
217
+ `req` & `res` are decorated with helper functions to simplify responding.
218
+
219
+ ### res.error(status[, body, headers])
220
+ Sends an error response.
221
+
222
+ ### res.header(key, value)
223
+ Shorthand of `res.setHeader()`.
224
+
225
+ ### res.json(body, [status = 200, headers])
226
+ Sends a JSON response.
227
+
228
+ ### res.last(req, res, next)
229
+ Last middleware of the route for the HTTP method as a way to "skip" to the middleware which sends a response.
230
+
231
+ ### res.redirect(uri[, perm = false])
232
+ Sends a redirection response.
233
+
234
+ ### res.send(body, [status = 200, headers = {}])
235
+ Sends a response. `Range` header is ignored on `stream` responses.
236
+
237
+ ### res.set(headers = {})
238
+ Shorthand of `res.setHeaders()` which accepts `Object`, `Map`, or `Headers` instances.
239
+
240
+ ### res.status(arg)
241
+ Sets the response `statusCode` property.
242
+
243
+ ## Logging
244
+ Woodland defaults to [Common Log Format](https://en.wikipedia.org/wiki/Common_Log_Format) but supports [Common Log Format with Virtual Host](https://httpd.apache.org/docs/trunk/mod/mod_log_config.html), & [NCSA extended/combined log format](https://httpd.apache.org/docs/trunk/mod/mod_log_config.html) with an `info` level by default. You can change the `stdout` output by changing `logging.format` with valid placeholders.
245
+
246
+ You can disable woodland's logging by configuration with `{logging: {enabled: false}}`.
247
+
248
+ ## License
249
+ Copyright (c) 2024 Jason Mulligan
250
+
251
+ Licensed under the BSD-3 license.