web-listener 0.1.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/LICENSE +45 -0
- package/README.md +168 -0
- package/index.d.ts +1147 -0
- package/index.js +1 -0
- package/package.json +28 -0
- package/run.js +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 David Evans
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The distributable version of this library includes a bundled copy of busboy
|
|
24
|
+
and streamsearch (with minification and tree shaking applied), which are also
|
|
25
|
+
available under the MIT License:
|
|
26
|
+
|
|
27
|
+
Copyright Brian White. All rights reserved.
|
|
28
|
+
|
|
29
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
30
|
+
of this software and associated documentation files (the "Software"), to
|
|
31
|
+
deal in the Software without restriction, including without limitation the
|
|
32
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
33
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
34
|
+
furnished to do so, subject to the following conditions:
|
|
35
|
+
|
|
36
|
+
The above copyright notice and this permission notice shall be included in
|
|
37
|
+
all copies or substantial portions of the Software.
|
|
38
|
+
|
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
40
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
41
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
42
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
43
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
44
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
45
|
+
IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Web Listener
|
|
2
|
+
|
|
3
|
+
A small server abstraction for creating API and resource endpoints with middleware. Supports
|
|
4
|
+
HTTP/1.1 and upgrade requests.
|
|
5
|
+
|
|
6
|
+
`web-listener` is designed to be tree-shakable so that it provides a minimal framework for those who
|
|
7
|
+
want something simple, while still being able to deliver advanced capabilities for those who need
|
|
8
|
+
them. By removing unused features at build time, `web-listener` is able to have a much smaller
|
|
9
|
+
memory footprint at runtime than alternatives which provide features via object methods.
|
|
10
|
+
|
|
11
|
+
The core API shares concepts with `express`, but uses helper functions rather than adding methods to
|
|
12
|
+
the request and response objects. For example, to define a route with a path parameter:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import { WebListener, Router, getPathParameter } from 'web-listener';
|
|
16
|
+
|
|
17
|
+
const router = new Router();
|
|
18
|
+
|
|
19
|
+
router.get('/things/:id', (req, res) => {
|
|
20
|
+
const id = getPathParameter(req, 'id');
|
|
21
|
+
res.end(`You asked for item ${id}`);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
new WebListener(router).listen(3000);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- Production ready
|
|
30
|
+
- Protected against attacks such as directory traversal, path confusion, and compression bombs
|
|
31
|
+
- Performant techniques used to receive and send data
|
|
32
|
+
- Supports "hardened" runtime environments (e.g. `--disable-proto=throw`, `--no-addons`, and
|
|
33
|
+
`--disallow-code-generation-from-strings`)
|
|
34
|
+
- Comprehensively tested
|
|
35
|
+
- Full support for TypeScript and type safety
|
|
36
|
+
- Written entirely in TypeScript, and full type definitions are included
|
|
37
|
+
- Complex features such as path parameters are correctly typed (including for sub-routers)
|
|
38
|
+
- Small size and memory footprint
|
|
39
|
+
- Existing object prototypes are not modified; all features are available as imported functions
|
|
40
|
+
- Unused features can removed via tree-shaking / dead-code-analysis during the build (via any of
|
|
41
|
+
the major bundlers and minifiers) to reduce runtime size even further
|
|
42
|
+
- No package dependencies (bundles a minified copy of `busboy` for form data handling)
|
|
43
|
+
- Very low runtime memory requirements; only minimal book-keeping is needed to track each request,
|
|
44
|
+
and the standard handlers are designed to have low working-memory requirements. Minified code
|
|
45
|
+
means little runtime memory is occupied by the source code (Node.js keeps a copy of all source
|
|
46
|
+
code in memory for debugging).
|
|
47
|
+
- Flexible and customisable
|
|
48
|
+
- Most parts of the API can be swapped out for alternatives
|
|
49
|
+
- All internal values and timeouts are configurable to support specific needs
|
|
50
|
+
- Default configuration matches Node.js wherever possible to avoid surprises, and
|
|
51
|
+
`web-listener`-specific options have sensible defaults to enable getting started quickly
|
|
52
|
+
- Command-line helper for local development
|
|
53
|
+
- Serve content from a directory
|
|
54
|
+
- Proxy content from another server
|
|
55
|
+
- Serve specific fixtures
|
|
56
|
+
- Run multiple servers from a single command
|
|
57
|
+
- Path routing
|
|
58
|
+
- Path parameters (individual components, sub-components, multiple components)
|
|
59
|
+
- Optional path components
|
|
60
|
+
- Error handling
|
|
61
|
+
- Thrown errors can be caught by later middleware, or handled automatically
|
|
62
|
+
- `HTTPError` and `WebSocketError` make it easy to close the connection at any point with specific
|
|
63
|
+
error codes, and can include custom messages and headers
|
|
64
|
+
- Upgrade handling
|
|
65
|
+
- WebSockets (bring-your-own-library, e.g. `ws`)
|
|
66
|
+
- Custom upgrades
|
|
67
|
+
- Automatic support for `shouldUpgradeCallback` in Node.js 24.9+ to enable support for specific
|
|
68
|
+
upgrade protocols without breaking requests that ask for unrelated protocols
|
|
69
|
+
- Request header helpers
|
|
70
|
+
- Parsers for common headers and header formats
|
|
71
|
+
- Client information (e.g. IP) with support for trusted proxies
|
|
72
|
+
- Request body parsing
|
|
73
|
+
- Raw binary data
|
|
74
|
+
- Compressed requests (deflate, gzip, brotli, zstd)
|
|
75
|
+
- Streaming data
|
|
76
|
+
- Configurable size limits for both raw content and uncompressed data
|
|
77
|
+
- Optional custom `Expect: 100-continue` handling
|
|
78
|
+
- `text/*`
|
|
79
|
+
- `application/json` (including charset detection)
|
|
80
|
+
- `application/x-www-url-encoded`
|
|
81
|
+
- `multipart/form-data`, including file uploads to a temporary location
|
|
82
|
+
- Uses built-in `TextDecoderStream` for character set support, and allows registering additional /
|
|
83
|
+
replacement character sets (bring-your-own-library)
|
|
84
|
+
- Static file serving
|
|
85
|
+
- Compression (via pre-compressed files)
|
|
86
|
+
- Range requests
|
|
87
|
+
- Cache control, etags (strong and weak), and modified times
|
|
88
|
+
- Automatic serving of content in a directory
|
|
89
|
+
- Manual serving of any file with a path or `Readable` (requires byte size and last modified time)
|
|
90
|
+
- Common file extension MIME types handled out-of-the-box, more can be registered if needed
|
|
91
|
+
- Response helpers
|
|
92
|
+
- Server Sent Events helper class
|
|
93
|
+
- JSON, including streaming entities which contain async iterators or streams
|
|
94
|
+
- CSV
|
|
95
|
+
- Request proxying
|
|
96
|
+
- Hooks for templating
|
|
97
|
+
- `onReturn` can be used to integrate templating engines (bring-your-own-library), or used for
|
|
98
|
+
peace-of-mind tasks like automatically closing responses when handlers return.
|
|
99
|
+
- Modern and interoperable APIs
|
|
100
|
+
- Request handlers match `http.Server`'s 'request' event signature
|
|
101
|
+
- Upgrade handlers match `http.Server`'s 'upgrade' event signature
|
|
102
|
+
- Web Streams used for streaming data (also accepts Node.js streams)
|
|
103
|
+
- Promises used and supported in most places
|
|
104
|
+
|
|
105
|
+
## Install dependency
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
npm install --save web-listener
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or to just serve static content from a directory:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
npx web-listener . -p 8080
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Getting Started Examples
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
import { WebListener, Router, getPathParameter, HTTPError, CONTINUE } from 'web-listener';
|
|
121
|
+
|
|
122
|
+
const r = new Router();
|
|
123
|
+
|
|
124
|
+
r.get('/things/:id', async (req, res) => {
|
|
125
|
+
const id = getPathParameter(req, 'id');
|
|
126
|
+
const myObject = await loadObject(id);
|
|
127
|
+
res.write(JSON.stringify(myObject)).end();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const authCheck = (req, res) => {
|
|
131
|
+
if (req.headers['authorization'] !== 'Please') {
|
|
132
|
+
throw new HTTPError(401, { body: "You didn't say the magic word" });
|
|
133
|
+
}
|
|
134
|
+
return CONTINUE;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
r.get('/private-things/:id', authCheck, async (req, res) => {
|
|
138
|
+
const id = getPathParameter(req, 'id');
|
|
139
|
+
const myObject = await loadPrivateObject(id);
|
|
140
|
+
res.write(JSON.stringify(myObject)).end();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
r.get('/{*path}', (req, res) => {
|
|
144
|
+
const path = getPathParameter(req, 'path');
|
|
145
|
+
res.write(`You requested ${path.join('/')}`).end();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const weblistener = new WebListener(r);
|
|
149
|
+
const server = await weblistener.listen(8080, 'localhost');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
To run with a HTTPS server:
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
import { createServer } from 'node:https';
|
|
156
|
+
|
|
157
|
+
// setup weblistener as before
|
|
158
|
+
|
|
159
|
+
const server = createServer({
|
|
160
|
+
/* ... */
|
|
161
|
+
});
|
|
162
|
+
weblistener.attach(server);
|
|
163
|
+
server.listen(8080, 'localhost');
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## API Documentation
|
|
167
|
+
|
|
168
|
+
TODO: write API documentation
|