web-listener 0.12.0 → 0.13.1
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 +17 -128
- package/index.d.ts +143 -147
- package/index.js +2 -1
- package/package.json +1 -1
- package/run.js +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Web Listener
|
|
2
2
|
|
|
3
3
|
A small, dependency-free server abstraction for serving static files, proxying, and creating API
|
|
4
|
-
endpoints with middleware. Supports HTTP/1.1 and upgrade requests.
|
|
4
|
+
endpoints with middleware. Supports HTTP/1.1 and upgrade requests (such as WebSockets).
|
|
5
5
|
|
|
6
6
|
`web-listener` is designed to be tree-shakable so that it provides a minimal framework for those who
|
|
7
7
|
want something simple, while still being able to deliver advanced capabilities for those who need
|
|
@@ -24,84 +24,6 @@ router.get('/things/:id', (req, res) => {
|
|
|
24
24
|
new WebListener(router).listen(3000);
|
|
25
25
|
```
|
|
26
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 fork 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
27
|
## Install dependency
|
|
106
28
|
|
|
107
29
|
```sh
|
|
@@ -111,63 +33,30 @@ npm install --save web-listener
|
|
|
111
33
|
Or to just serve static content from a directory:
|
|
112
34
|
|
|
113
35
|
```sh
|
|
114
|
-
npx web-listener .
|
|
36
|
+
npx web-listener . --port 8080
|
|
115
37
|
```
|
|
116
38
|
|
|
117
|
-
|
|
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
|
-
});
|
|
39
|
+
The full CLI documentation can be found in [docs/CLI.md](docs/CLI.md).
|
|
142
40
|
|
|
143
|
-
|
|
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
|
|
41
|
+
## API Documentation
|
|
158
42
|
|
|
159
|
-
|
|
160
|
-
/* ... */
|
|
161
|
-
});
|
|
162
|
-
weblistener.attach(server);
|
|
163
|
-
server.listen(8080, 'localhost');
|
|
164
|
-
```
|
|
43
|
+
The full API documentation can be found in [docs/API.md](docs/API.md).
|
|
165
44
|
|
|
166
45
|
## TypeScript
|
|
167
46
|
|
|
168
47
|
Types are included in the library. Note that for full type safety (particularly path parameters),
|
|
169
48
|
you must set `"strict": true` (or at least `"strictFunctionTypes": true`) in your `tsconfig.json`.
|
|
170
49
|
|
|
171
|
-
##
|
|
50
|
+
## Production Considerations
|
|
51
|
+
|
|
52
|
+
This library is designed for production use and mitigates various security vulnerabilities
|
|
53
|
+
internally (see [docs/SECURITY.md](docs/SECURITY.md) for details), but you should still tune the
|
|
54
|
+
server limits to match your particular environment (all Node.js defaults, such as for server
|
|
55
|
+
creation, are preserved by this library unless explicitly configured). You should also enable Node's
|
|
56
|
+
[runtime hardening flags](docs/SECURITY.md#javascript-vulnerabilities) in production where possible,
|
|
57
|
+
and
|
|
58
|
+
[disable `SIGUSR1` handling](https://nodejs.org/en/learn/getting-started/security-best-practices#dns-rebinding-cwe-346).
|
|
172
59
|
|
|
173
|
-
|
|
60
|
+
Note that this library does not implement rate limiting of any kind, so if you have an endpoint
|
|
61
|
+
which is vulnerable to rapid requests (e.g. a password checking endpoint), you should set up your
|
|
62
|
+
own rate limiting or use a proxy such as NGINX and configure rate limiting there.
|
package/index.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ type UpgradeListener = (req: IncomingMessage, socket: Duplex, head: Buffer) => v
|
|
|
11
11
|
type ShouldUpgradeCallback = (req: IncomingMessage) => boolean;
|
|
12
12
|
|
|
13
13
|
interface Address {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
family: 'IPv4' | 'IPv6' | 'alias';
|
|
15
|
+
address: string;
|
|
16
16
|
port: number | undefined;
|
|
17
17
|
}
|
|
18
18
|
declare function parseAddress(address: string | undefined): Address | undefined;
|
|
@@ -20,7 +20,7 @@ declare function makeAddressTester(cidrRanges: string[]): (address: Address | un
|
|
|
20
20
|
|
|
21
21
|
declare class BlockingQueue<T> {
|
|
22
22
|
constructor();
|
|
23
|
-
push(
|
|
23
|
+
push(item: T): void;
|
|
24
24
|
shift(timeout?: number | undefined): Promise<T>;
|
|
25
25
|
close(reason: unknown): void;
|
|
26
26
|
fail(reason: unknown): void;
|
|
@@ -31,7 +31,7 @@ declare function findCause<T>(error: unknown, errorType: {
|
|
|
31
31
|
new (...args: any[]): T;
|
|
32
32
|
}): T | undefined;
|
|
33
33
|
|
|
34
|
-
declare function getAddressURL(
|
|
34
|
+
declare function getAddressURL(addressInfo: string | Address | AddressInfo | null | undefined, protocol?: string): string;
|
|
35
35
|
|
|
36
36
|
declare class Queue<T> {
|
|
37
37
|
constructor(initialItem?: T);
|
|
@@ -62,6 +62,7 @@ interface AcceptUpgradeResult<T> {
|
|
|
62
62
|
softCloseHandler?: SoftCloseHandler;
|
|
63
63
|
}
|
|
64
64
|
declare function acceptUpgrade<T, Req = {}>(req: IncomingMessage & Req, upgrade: AcceptUpgradeHandler<T, Req>): Promise<T>;
|
|
65
|
+
declare function delegateUpgrade(req: IncomingMessage): void;
|
|
65
66
|
|
|
66
67
|
declare class RoutingInstruction extends Error {
|
|
67
68
|
}
|
|
@@ -104,7 +105,7 @@ interface ErrorHandler<Req = {}> {
|
|
|
104
105
|
declare const errorHandler: <Req>(handler: ErrorHandler<Req> | ErrorHandlerFn<Req>) => ErrorHandler<Req>;
|
|
105
106
|
type TypedErrorHandlerFn<Error, Req = {}> = (error: Error, req: IncomingMessage & Req, response: ServerResponse) => MaybePromise<HandlerResult>;
|
|
106
107
|
declare const typedErrorHandler: <Error, Req>(ErrorClass: abstract new (...args: any[]) => Error, handler: TypedErrorHandlerFn<Error, Req>) => ErrorHandler<Req>;
|
|
107
|
-
type ConditionalErrorHandler = (<Error, Req>(
|
|
108
|
+
type ConditionalErrorHandler = (<Error, Req>(condition: (x: unknown) => x is Error, handler: TypedErrorHandlerFn<Error, Req>) => ErrorHandler<Req>) & (<Req>(condition: (x: unknown) => boolean, handler: TypedErrorHandlerFn<unknown, Req>) => ErrorHandler<Req>);
|
|
108
109
|
declare const conditionalErrorHandler: ConditionalErrorHandler;
|
|
109
110
|
type Handler<Req = {}> = Partial<RequestHandler<Req> & UpgradeHandler<Req> & ErrorHandler<Req>>;
|
|
110
111
|
type RequestReturnHandlerFn<Req = {}> = (value: ReturnHandlerParameter, req: IncomingMessage & Req, res: ServerResponse) => MaybePromise<void>;
|
|
@@ -149,7 +150,6 @@ type TypedEventTarget<This, Mapping> = {
|
|
|
149
150
|
interface ListenOptions {
|
|
150
151
|
/**
|
|
151
152
|
* `backlog` parameter sent to `server.listen`.
|
|
152
|
-
*
|
|
153
153
|
* @default 511
|
|
154
154
|
*/
|
|
155
155
|
backlog?: number | undefined;
|
|
@@ -162,24 +162,17 @@ interface ListenerOptions extends Omit<NativeListenersOptions, 'onError'> {
|
|
|
162
162
|
/**
|
|
163
163
|
* Automatically send `417 Expectation Failed` for any request with a non-standard `Expect` header.
|
|
164
164
|
* Set to `false` to allow application-specific use of this header.
|
|
165
|
-
*
|
|
166
165
|
* @default true (matching Node.js behaviour)
|
|
167
166
|
*/
|
|
168
167
|
rejectNonStandardExpect?: boolean | undefined;
|
|
169
168
|
/**
|
|
170
169
|
* Automatically send `100 Continue` for any request with `Expect: 100-continue`.
|
|
171
|
-
* If set to `false`, all handlers MUST call `acceptBody(req)` before attempting
|
|
172
|
-
* to read the body of the request (bundled body parsing middleware does this
|
|
173
|
-
* automatically).
|
|
174
|
-
*
|
|
170
|
+
* If set to `false`, all handlers MUST call `acceptBody(req)` before attempting to read the body of the request (all bundled body parsing middleware does this automatically).
|
|
175
171
|
* @default true (matching Node.js behaviour)
|
|
176
172
|
*/
|
|
177
173
|
autoContinue?: boolean | undefined;
|
|
178
174
|
/**
|
|
179
|
-
* Override the shouldUpgradeCallback of the server with one that attempts to detect whether an
|
|
180
|
-
* upgrade request would be handled by the current routes. The detection does not invoke any
|
|
181
|
-
* handlers, but checks their `shouldUpgrade` function if it is present.
|
|
182
|
-
*
|
|
175
|
+
* Override the `shouldUpgradeCallback` (Node.js 24.9+) of the server with one that attempts to detect whether an upgrade request would be handled by the current routes. The detection does not invoke any handlers, but checks their `shouldUpgrade` function if it is present.
|
|
183
176
|
* @default true
|
|
184
177
|
*/
|
|
185
178
|
overrideShouldUpgradeCallback?: boolean | undefined;
|
|
@@ -256,7 +249,7 @@ declare const getSearch: (req: IncomingMessage) => string;
|
|
|
256
249
|
/** get the query string for the URL as a URLSearchParams object */
|
|
257
250
|
declare const getSearchParams: (req: IncomingMessage) => URLSearchParams;
|
|
258
251
|
/** get a specific query parameter from the URL */
|
|
259
|
-
declare const getQuery: (req: IncomingMessage,
|
|
252
|
+
declare const getQuery: (req: IncomingMessage, name: string) => string | null;
|
|
260
253
|
|
|
261
254
|
type CommonMethod = 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE';
|
|
262
255
|
type CommonUpgrade = 'http/2' | 'http/3' | 'https' | 'h2c' | 'websocket';
|
|
@@ -316,19 +309,14 @@ declare class Router<Req = {}> implements Handler<Req> {
|
|
|
316
309
|
* routing instruction. They can be used for features like templating or ensuring connections
|
|
317
310
|
* are always closed when a handler returns.
|
|
318
311
|
*
|
|
319
|
-
* Return
|
|
312
|
+
* Return handlers are called in the order they were registered, and from the innermost router
|
|
320
313
|
* to the outermost rooter. Return handlers are not called for upgrade requests.
|
|
321
314
|
*
|
|
322
315
|
* Return handlers are not ordered with the other handlers, so they can be registered upfront if
|
|
323
316
|
* desired. If a return handler throws, the error will be passed to the next error handler after
|
|
324
317
|
* the request handler which triggered it.
|
|
325
318
|
*/
|
|
326
|
-
onReturn(...
|
|
327
|
-
/**
|
|
328
|
-
* Convenience wrapper for `.onRequest`, accepting paths with a HTTP verb at the start (separated
|
|
329
|
-
* by a space).
|
|
330
|
-
*/
|
|
331
|
-
on<Path extends string>(path: `${CommonMethod} ${Path}`, ...handlers: RelaxedRequestHandler<Req & WithPathParameters<ParametersFromPath<Path>>>[]): this;
|
|
319
|
+
onReturn(...fns: RequestReturnHandlerFn<Req>[]): this;
|
|
332
320
|
/**
|
|
333
321
|
* Registers handlers for GET requests at the given path. Note that these handlers will also
|
|
334
322
|
* be used for HEAD requests by default. To use different HEAD handling, you can register an
|
|
@@ -409,75 +397,9 @@ declare function requireBearerAuth<Req = {}, Token = JWTToken>({ realm, extractA
|
|
|
409
397
|
declare const hasAuthScope: (req: IncomingMessage, scope: string) => boolean;
|
|
410
398
|
declare const requireAuthScope: (scope: string) => RequestHandler & UpgradeHandler;
|
|
411
399
|
|
|
412
|
-
declare function generateWeakETag(contentEncoding: string | number | string[] | undefined,
|
|
400
|
+
declare function generateWeakETag(contentEncoding: string | number | string[] | undefined, fileStats: Pick<Stats, 'mtimeMs' | 'size'>): string;
|
|
413
401
|
declare function generateStrongETag(file: string | FileHandle): Promise<string>;
|
|
414
402
|
|
|
415
|
-
interface HTTPRange {
|
|
416
|
-
ranges: RangePart[];
|
|
417
|
-
totalSize?: number | undefined;
|
|
418
|
-
}
|
|
419
|
-
interface RangePart {
|
|
420
|
-
start: number;
|
|
421
|
-
end: number;
|
|
422
|
-
}
|
|
423
|
-
interface SimplifyRangeOptions {
|
|
424
|
-
forceSequential?: boolean;
|
|
425
|
-
mergeOverlapDistance?: number;
|
|
426
|
-
}
|
|
427
|
-
declare function simplifyRange(original: HTTPRange, { forceSequential, mergeOverlapDistance }?: SimplifyRangeOptions): HTTPRange;
|
|
428
|
-
|
|
429
|
-
declare function getAuthorization(req: IncomingMessage): [string, string] | undefined;
|
|
430
|
-
declare function getCharset(req: IncomingMessage): string | undefined;
|
|
431
|
-
declare function getIfRange(req: IncomingMessage): {
|
|
432
|
-
etag?: string[] | undefined;
|
|
433
|
-
modifiedSeconds?: number | undefined;
|
|
434
|
-
};
|
|
435
|
-
interface GetRangeOptions {
|
|
436
|
-
/**
|
|
437
|
-
* Maximum number of sequential, non-overlapping ranges a client can request in a
|
|
438
|
-
* single message.
|
|
439
|
-
*
|
|
440
|
-
* Typical browser clients only request a single range. In rare cases, clients may
|
|
441
|
-
* request 2 ranges. Bespoke clients may be able to make use of more ranges.
|
|
442
|
-
*
|
|
443
|
-
* @default 10
|
|
444
|
-
*/
|
|
445
|
-
maxRanges?: number;
|
|
446
|
-
/**
|
|
447
|
-
* Maximum number of ranges a client can request in a single message if any ranges are
|
|
448
|
-
* non-sequential (i.e. a later range begins at lower offset than an earlier range).
|
|
449
|
-
*
|
|
450
|
-
* As suggested in https://datatracker.ietf.org/doc/html/rfc7233, this uses a default
|
|
451
|
-
* limit of 2, as more ranges are likely to be a broken or malicious client.
|
|
452
|
-
*
|
|
453
|
-
* @default 2
|
|
454
|
-
*/
|
|
455
|
-
maxNonSequential?: number;
|
|
456
|
-
/**
|
|
457
|
-
* Maximum number of ranges a client can request in a single message if any ranges are
|
|
458
|
-
* overlapping.
|
|
459
|
-
*
|
|
460
|
-
* As suggested in https://datatracker.ietf.org/doc/html/rfc7233, this uses a default
|
|
461
|
-
* limit of 2, as more ranges are likely to be a broken or malicious client.
|
|
462
|
-
*
|
|
463
|
-
* @default 2
|
|
464
|
-
*/
|
|
465
|
-
maxWithOverlap?: number;
|
|
466
|
-
}
|
|
467
|
-
declare function getRange(req: IncomingMessage, totalSize: number, { maxRanges, maxNonSequential, maxWithOverlap }?: GetRangeOptions): HTTPRange | undefined;
|
|
468
|
-
interface QualityValue {
|
|
469
|
-
name: string;
|
|
470
|
-
specifiers: Map<string, string>;
|
|
471
|
-
specificity: number;
|
|
472
|
-
q: number;
|
|
473
|
-
}
|
|
474
|
-
declare function readHTTPUnquotedCommaSeparated(raw: LooseHeaderValue | undefined): string[] | undefined;
|
|
475
|
-
declare function readHTTPInteger(raw: string | undefined): number | undefined;
|
|
476
|
-
declare function readHTTPQualityValues(raw: string | undefined): QualityValue[] | undefined;
|
|
477
|
-
declare function readHTTPKeyValues(raw: string): Map<string, string>;
|
|
478
|
-
declare function readHTTPDateSeconds(raw: LooseHeaderValue | undefined): number | undefined;
|
|
479
|
-
type LooseHeaderValue = string | number | string[];
|
|
480
|
-
|
|
481
403
|
declare const HEADERS: {
|
|
482
404
|
mime: string;
|
|
483
405
|
language: string;
|
|
@@ -522,14 +444,7 @@ interface FileNegotiationOption {
|
|
|
522
444
|
*/
|
|
523
445
|
file: string;
|
|
524
446
|
}
|
|
525
|
-
|
|
526
|
-
zstd: string;
|
|
527
|
-
br: string;
|
|
528
|
-
gzip: string;
|
|
529
|
-
deflate: string;
|
|
530
|
-
identity: string;
|
|
531
|
-
};
|
|
532
|
-
type FileEncodingFormat = keyof typeof ENCODING_MAPPING;
|
|
447
|
+
type FileEncodingFormat = 'zstd' | 'br' | 'gzip' | 'deflate' | 'identity';
|
|
533
448
|
declare const negotiateEncoding: (options: FileEncodingFormat[] | Record<FileEncodingFormat, string>) => FileNegotiation;
|
|
534
449
|
interface NegotiationOutputInfo {
|
|
535
450
|
/** The negotiated mime type for the resolved file */
|
|
@@ -543,12 +458,33 @@ interface NegotiationOutput {
|
|
|
543
458
|
filename: string;
|
|
544
459
|
info: NegotiationOutputInfo;
|
|
545
460
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
461
|
+
declare class Negotiator {
|
|
462
|
+
readonly vary: string;
|
|
463
|
+
/**
|
|
464
|
+
* Content negotiation rules.
|
|
465
|
+
*
|
|
466
|
+
* This can be used to respond to the `Accept`, `Accept-Language`, and `Accept-Encoding` headers.
|
|
467
|
+
*
|
|
468
|
+
* For example: on a server with `foo.txt`, `foo.txt.gz`, and a negotiation rule mapping
|
|
469
|
+
* `gzip` => `{name}.gz`:
|
|
470
|
+
* - users requesting `foo.txt` may get `foo.txt.gz` with `Content-Encoding: gzip` if their
|
|
471
|
+
* client supports gzip encoding
|
|
472
|
+
* - users requesting `foo.txt` may get `foo.txt` with no `Content-Encoding` if their client
|
|
473
|
+
* does not support gzip encoding
|
|
474
|
+
*
|
|
475
|
+
* Multiple rules can match simultaneously, if a specific enough file exists (for example you might
|
|
476
|
+
* have `foo-en.txt.gz` for `Accept-Language: en` and `Accept-Encoding: gzip`).
|
|
477
|
+
*
|
|
478
|
+
* In the case of conflicting rules, earlier rules take priority (so `encoding` rules should
|
|
479
|
+
* typically be specified last)
|
|
480
|
+
*
|
|
481
|
+
* See the helper `negotiateEncoding` for a simple way to support pre-compressed files.
|
|
482
|
+
*/
|
|
483
|
+
constructor(rules: FileNegotiation[], { maxFailedAttempts }?: {
|
|
484
|
+
maxFailedAttempts?: number | undefined;
|
|
485
|
+
});
|
|
486
|
+
options(base: string, reqHeaders: IncomingHttpHeaders): Generator<NegotiationOutput, undefined, undefined>;
|
|
550
487
|
}
|
|
551
|
-
declare function makeNegotiator(rules: FileNegotiation[], maxFailedAttempts?: number): Negotiator;
|
|
552
488
|
|
|
553
489
|
interface CompressionInfo {
|
|
554
490
|
/** the path to the file */
|
|
@@ -562,8 +498,20 @@ interface CompressionInfo {
|
|
|
562
498
|
/** the number of compressed files which were saved */
|
|
563
499
|
created: number;
|
|
564
500
|
}
|
|
565
|
-
|
|
566
|
-
|
|
501
|
+
interface CompressionOptions {
|
|
502
|
+
/**
|
|
503
|
+
* the minimum compression (in bytes) which must be achieved to save the file
|
|
504
|
+
* @default 0
|
|
505
|
+
*/
|
|
506
|
+
minCompression?: number;
|
|
507
|
+
/**
|
|
508
|
+
* if `true`, existing compressed files which are no-longer relevant will be removed
|
|
509
|
+
* @default false
|
|
510
|
+
*/
|
|
511
|
+
deleteObsolete?: boolean;
|
|
512
|
+
}
|
|
513
|
+
declare function compressFileOffline(file: string, encodings: FileNegotiationOption[], { minCompression, deleteObsolete }?: CompressionOptions): Promise<CompressionInfo>;
|
|
514
|
+
declare function compressFilesInDir(dir: string, encodings: FileNegotiationOption[], options?: CompressionOptions): Promise<CompressionInfo[]>;
|
|
567
515
|
|
|
568
516
|
declare const emitError: (req: IncomingMessage, error: unknown, context?: string) => void;
|
|
569
517
|
|
|
@@ -681,41 +629,26 @@ interface FileFinderOptions {
|
|
|
681
629
|
*/
|
|
682
630
|
implicitSuffixes?: string[] | undefined;
|
|
683
631
|
/**
|
|
684
|
-
* Content negotiation
|
|
632
|
+
* Content negotiation to apply to files.
|
|
685
633
|
*
|
|
686
634
|
* This can be used to respond to the `Accept`, `Accept-Language`, and `Accept-Encoding` headers.
|
|
687
635
|
*
|
|
688
|
-
* For example: on a server with `foo.txt`, `foo.txt.gz`, and a negotiation rule mapping
|
|
689
|
-
* `gzip` => `{name}.gz`:
|
|
690
|
-
* - users requesting `foo.txt` may get `foo.txt.gz` with `Content-Encoding: gzip` if their
|
|
691
|
-
* client supports gzip encoding
|
|
692
|
-
* - users requesting `foo.txt` may get `foo.txt` with no `Content-Encoding` if their client
|
|
693
|
-
* does not support gzip encoding
|
|
694
|
-
*
|
|
695
636
|
* Note that file access is checked *before* content negotiation, so you must still provide a
|
|
696
637
|
* base "un-negotiated" file for each file you wish to serve (which will also be used in cases
|
|
697
638
|
* where users do not send any `Accept-*` headers, and where no match is found)
|
|
698
639
|
*
|
|
699
|
-
*
|
|
700
|
-
* have `foo-en.txt.gz` for `Accept-Language: en` and `Accept-Encoding: gzip`).
|
|
701
|
-
*
|
|
702
|
-
* In the case of conflicting rules, earlier rules take priority (so `encoding` rules should
|
|
703
|
-
* typically be specified last)
|
|
704
|
-
*
|
|
705
|
-
* See the helper `negotiateEncoding` for a simple way to support pre-compressed files.
|
|
706
|
-
*
|
|
707
|
-
* @default []
|
|
640
|
+
* @default undefined
|
|
708
641
|
*/
|
|
709
|
-
|
|
642
|
+
negotiator?: Negotiator | undefined;
|
|
710
643
|
}
|
|
711
644
|
interface FileFinderCore {
|
|
712
|
-
find(pathParts: string[],
|
|
645
|
+
find(pathParts: string[], reqHeaders?: IncomingHttpHeaders, warnings?: string[] | undefined): Promise<ResolvedFileInfo | null>;
|
|
713
646
|
debugAllPaths(): Promise<Set<string>>;
|
|
714
647
|
readonly vary: string;
|
|
715
648
|
}
|
|
716
649
|
declare class FileFinder implements FileFinderCore {
|
|
717
650
|
readonly vary: string;
|
|
718
|
-
static build(
|
|
651
|
+
static build(absBaseDir: string, options?: FileFinderOptions): Promise<FileFinder>;
|
|
719
652
|
toNormalisedPath(pathParts: string[]): string[];
|
|
720
653
|
/**
|
|
721
654
|
* Find a file which matches the path.
|
|
@@ -726,7 +659,7 @@ declare class FileFinder implements FileFinderCore {
|
|
|
726
659
|
* @param negotiation any client-sent negotiation options to apply
|
|
727
660
|
* @returns details about the resolved file (including an active `FileHandle`), or `null`
|
|
728
661
|
*/
|
|
729
|
-
find(pathParts: string[],
|
|
662
|
+
find(pathParts: string[], reqHeaders?: IncomingHttpHeaders, warnings?: string[] | undefined): Promise<ResolvedFileInfo | null>;
|
|
730
663
|
debugAllPaths(): Promise<Set<string>>;
|
|
731
664
|
precompute(): Promise<FileFinderCore>;
|
|
732
665
|
}
|
|
@@ -837,7 +770,7 @@ interface ProxyOptions extends AgentOptions {
|
|
|
837
770
|
*/
|
|
838
771
|
blockResponseHeaders?: string[] | undefined;
|
|
839
772
|
/**
|
|
840
|
-
* Mutators for the proxied request headers. e.g. `
|
|
773
|
+
* Mutators for the proxied request headers. e.g. `replaceForwarded`.
|
|
841
774
|
*/
|
|
842
775
|
requestHeaders?: ProxyRequestHeaderAdapter[] | undefined;
|
|
843
776
|
/**
|
|
@@ -845,7 +778,7 @@ interface ProxyOptions extends AgentOptions {
|
|
|
845
778
|
*/
|
|
846
779
|
responseHeaders?: ProxyResponseHeaderAdapter[] | undefined;
|
|
847
780
|
}
|
|
848
|
-
declare function proxy(forwardHost: string, { blockRequestHeaders, requestHeaders, blockResponseHeaders, responseHeaders, agent,
|
|
781
|
+
declare function proxy(forwardHost: string | URL, { blockRequestHeaders, requestHeaders, blockResponseHeaders, responseHeaders, agent, ...options }?: ProxyOptions): RequestHandler<unknown>;
|
|
849
782
|
|
|
850
783
|
interface Decoder {
|
|
851
784
|
decode(input: Uint8Array, options?: {
|
|
@@ -858,10 +791,10 @@ interface Charset {
|
|
|
858
791
|
decoder: (options: TextDecoderOptions) => Decoder;
|
|
859
792
|
decoderStream?: (options: TextDecoderOptions) => DecoderStream;
|
|
860
793
|
}
|
|
861
|
-
declare function registerCharset(
|
|
794
|
+
declare function registerCharset(charsetName: string, definition: Charset): void;
|
|
862
795
|
declare function registerUTF32(): void;
|
|
863
|
-
declare function getTextDecoder(
|
|
864
|
-
declare function getTextDecoderStream(
|
|
796
|
+
declare function getTextDecoder(charsetName: string, options?: TextDecoderOptions): Decoder;
|
|
797
|
+
declare function getTextDecoderStream(charsetName: string, options?: TextDecoderOptions): DecoderStream;
|
|
865
798
|
|
|
866
799
|
declare function resetMime(): void;
|
|
867
800
|
/**
|
|
@@ -875,7 +808,7 @@ declare function getMime(ext: string, charset?: string): string;
|
|
|
875
808
|
|
|
876
809
|
declare function checkIfModified(req: IncomingMessage, res: ServerResponse, fileStats: Pick<Stats, 'mtimeMs' | 'size'>): boolean;
|
|
877
810
|
declare function checkIfRange(req: IncomingMessage, res: ServerResponse, fileStats: Pick<Stats, 'mtimeMs' | 'size'>): boolean;
|
|
878
|
-
declare function compareETag(res: ServerResponse,
|
|
811
|
+
declare function compareETag(res: ServerResponse, fileStats: Pick<Stats, 'mtimeMs' | 'size'>, etags: string[]): boolean;
|
|
879
812
|
|
|
880
813
|
interface GetBodyOptions {
|
|
881
814
|
/**
|
|
@@ -985,7 +918,7 @@ declare global {
|
|
|
985
918
|
}
|
|
986
919
|
|
|
987
920
|
declare function getFormFields(req: IncomingMessage, { closeAfterErrorDelay, ...options }?: GetFormFieldsOptions): AsyncIterable<FormField, unknown, undefined>;
|
|
988
|
-
declare function getFormData(req: IncomingMessage,
|
|
921
|
+
declare function getFormData(req: IncomingMessage, options?: GetFormDataOptions): Promise<AugmentedFormData>;
|
|
989
922
|
interface GetFormFieldsOptions extends BusboyOptions {
|
|
990
923
|
/**
|
|
991
924
|
* Delay (in milliseconds) before forcibly closing the request if an error occurs (e.g. a limit is exceeded).
|
|
@@ -1033,6 +966,72 @@ interface AugmentedFormData extends FormData {
|
|
|
1033
966
|
getAllFiles(name: string): File[];
|
|
1034
967
|
}
|
|
1035
968
|
|
|
969
|
+
interface HTTPRange {
|
|
970
|
+
ranges: RangePart[];
|
|
971
|
+
totalSize?: number | undefined;
|
|
972
|
+
}
|
|
973
|
+
interface RangePart {
|
|
974
|
+
start: number;
|
|
975
|
+
end: number;
|
|
976
|
+
}
|
|
977
|
+
interface SimplifyRangeOptions {
|
|
978
|
+
forceSequential?: boolean;
|
|
979
|
+
mergeOverlapDistance?: number;
|
|
980
|
+
}
|
|
981
|
+
declare function simplifyRange(original: HTTPRange, { forceSequential, mergeOverlapDistance }?: SimplifyRangeOptions): HTTPRange;
|
|
982
|
+
|
|
983
|
+
declare function getAuthorization(req: IncomingMessage): [string, string] | undefined;
|
|
984
|
+
declare function getCharset(req: IncomingMessage): string | undefined;
|
|
985
|
+
declare function getIfRange(req: IncomingMessage): {
|
|
986
|
+
etag?: string[] | undefined;
|
|
987
|
+
modifiedSeconds?: number | undefined;
|
|
988
|
+
};
|
|
989
|
+
interface GetRangeOptions {
|
|
990
|
+
/**
|
|
991
|
+
* Maximum number of sequential, non-overlapping ranges a client can request in a
|
|
992
|
+
* single message.
|
|
993
|
+
*
|
|
994
|
+
* Typical browser clients only request a single range. In rare cases, clients may
|
|
995
|
+
* request 2 ranges. Bespoke clients may be able to make use of more ranges.
|
|
996
|
+
*
|
|
997
|
+
* @default 10
|
|
998
|
+
*/
|
|
999
|
+
maxRanges?: number;
|
|
1000
|
+
/**
|
|
1001
|
+
* Maximum number of ranges a client can request in a single message if any ranges are
|
|
1002
|
+
* non-sequential (i.e. a later range begins at lower offset than an earlier range).
|
|
1003
|
+
*
|
|
1004
|
+
* As suggested in https://datatracker.ietf.org/doc/html/rfc7233, this uses a default
|
|
1005
|
+
* limit of 2, as more ranges are likely to be a broken or malicious client.
|
|
1006
|
+
*
|
|
1007
|
+
* @default 2
|
|
1008
|
+
*/
|
|
1009
|
+
maxNonSequential?: number;
|
|
1010
|
+
/**
|
|
1011
|
+
* Maximum number of ranges a client can request in a single message if any ranges are
|
|
1012
|
+
* overlapping.
|
|
1013
|
+
*
|
|
1014
|
+
* As suggested in https://datatracker.ietf.org/doc/html/rfc7233, this uses a default
|
|
1015
|
+
* limit of 2, as more ranges are likely to be a broken or malicious client.
|
|
1016
|
+
*
|
|
1017
|
+
* @default 2
|
|
1018
|
+
*/
|
|
1019
|
+
maxWithOverlap?: number;
|
|
1020
|
+
}
|
|
1021
|
+
declare function getRange(req: IncomingMessage, totalSize: number, { maxRanges, maxNonSequential, maxWithOverlap }?: GetRangeOptions): HTTPRange | undefined;
|
|
1022
|
+
interface QualityValue {
|
|
1023
|
+
name: string;
|
|
1024
|
+
specifiers: Map<string, string>;
|
|
1025
|
+
specificity: number;
|
|
1026
|
+
q: number;
|
|
1027
|
+
}
|
|
1028
|
+
declare function readHTTPUnquotedCommaSeparated(raw: LooseHeaderValue | undefined): string[] | undefined;
|
|
1029
|
+
declare function readHTTPInteger(raw: string | undefined): number | undefined;
|
|
1030
|
+
declare function readHTTPQualityValues(raw: string | undefined): QualityValue[] | undefined;
|
|
1031
|
+
declare function readHTTPKeyValues(raw: string): Map<string, string>;
|
|
1032
|
+
declare function readHTTPDateSeconds(raw: LooseHeaderValue | undefined): number | undefined;
|
|
1033
|
+
type LooseHeaderValue = string | number | string[];
|
|
1034
|
+
|
|
1036
1035
|
declare function getRemainingPathComponents(req: IncomingMessage, { rejectPotentiallyUnsafe }?: {
|
|
1037
1036
|
rejectPotentiallyUnsafe?: boolean | undefined;
|
|
1038
1037
|
}): string[];
|
|
@@ -1083,7 +1082,7 @@ type MaybeAsyncIterable<T> = Iterable<T> | AsyncIterable<T>;
|
|
|
1083
1082
|
*/
|
|
1084
1083
|
declare function sendCSVStream(target: Writable, table: MaybeAsyncIterable<MaybeAsyncIterable<string | null | undefined>>, { delimiter, newline, quote, encoding, headerRow, end, }?: CSVOptions): Promise<void>;
|
|
1085
1084
|
|
|
1086
|
-
declare function sendFile(req: IncomingMessage, res: ServerResponse,
|
|
1085
|
+
declare function sendFile(req: IncomingMessage, res: ServerResponse, source: string | FileHandle | Readable | ReadableStream<Uint8Array>, fileStats?: Pick<Stats, 'mtimeMs' | 'size'> | null, options?: GetRangeOptions & SimplifyRangeOptions): Promise<void>;
|
|
1087
1086
|
|
|
1088
1087
|
interface JSONOptions {
|
|
1089
1088
|
/**
|
|
@@ -1095,7 +1094,7 @@ interface JSONOptions {
|
|
|
1095
1094
|
* The amount of spacing to use for indentation. If this is 0, no spacing is used anywhere.
|
|
1096
1095
|
* @default 0
|
|
1097
1096
|
*/
|
|
1098
|
-
space?: string | number;
|
|
1097
|
+
space?: string | number | null;
|
|
1099
1098
|
/**
|
|
1100
1099
|
* If the top-level value being encoded is `undefined`, setting this to `true` will output `null`. `false` will output nothing.
|
|
1101
1100
|
* @default false
|
|
@@ -1115,7 +1114,7 @@ interface JSONOptions {
|
|
|
1115
1114
|
declare function sendJSON(target: Writable, entity: unknown, { replacer, space, undefinedAsNull, encoding, end }?: JSONOptions): void;
|
|
1116
1115
|
declare function sendJSONStream(target: Writable, entity: unknown, { replacer, space, undefinedAsNull, encoding, end, }?: JSONOptions): Promise<void>;
|
|
1117
1116
|
|
|
1118
|
-
declare function sendRanges(req: IncomingMessage, res: ServerResponse,
|
|
1117
|
+
declare function sendRanges(req: IncomingMessage, res: ServerResponse, source: string | FileHandle | Readable | ReadableStream<Uint8Array>, httpRange: HTTPRange): Promise<void>;
|
|
1119
1118
|
|
|
1120
1119
|
interface ServerSentEventsOptions {
|
|
1121
1120
|
keepaliveInterval?: number;
|
|
@@ -1209,11 +1208,11 @@ interface FallbackOptions {
|
|
|
1209
1208
|
* Requests for files which are not permitted or do not exist will return NEXT_ROUTE and can be
|
|
1210
1209
|
* handled by subsequent routes.
|
|
1211
1210
|
*
|
|
1212
|
-
* @param
|
|
1211
|
+
* @param baseDir the path to the directory to serve (relative paths are to the current working directory)
|
|
1213
1212
|
* @param options custom configuration to apply
|
|
1214
1213
|
* @returns a promise of a server handler function (note this should be `await`ed before being used as a handler!)
|
|
1215
1214
|
*/
|
|
1216
|
-
declare const fileServer: (
|
|
1215
|
+
declare const fileServer: (baseDir: string, { mode, fallback, verbose, callback, ...options }?: FileServerOptions) => Promise<RequestHandler>;
|
|
1217
1216
|
declare function setDefaultCacheHeaders(req: IncomingMessage, res: ServerResponse, file: ResolvedFileInfo): void;
|
|
1218
1217
|
|
|
1219
1218
|
interface InternalWebSocketServerOptions {
|
|
@@ -1282,13 +1281,13 @@ declare const makeWebSocketFallbackTokenFetcher: <Req>(acceptWebSocket: (req: In
|
|
|
1282
1281
|
|
|
1283
1282
|
interface WebSocketErrorOptions {
|
|
1284
1283
|
message?: string;
|
|
1285
|
-
|
|
1284
|
+
closeReason?: string;
|
|
1286
1285
|
cause?: unknown;
|
|
1287
1286
|
}
|
|
1288
1287
|
declare class WebSocketError extends Error {
|
|
1289
|
-
readonly
|
|
1290
|
-
readonly
|
|
1291
|
-
constructor(
|
|
1288
|
+
readonly closeCode: number;
|
|
1289
|
+
readonly closeReason: string;
|
|
1290
|
+
constructor(closeCode: number, { message, closeReason, ...options }?: WebSocketErrorOptions);
|
|
1292
1291
|
static readonly NORMAL_CLOSURE = 1000;
|
|
1293
1292
|
static readonly GOING_AWAY = 1001;
|
|
1294
1293
|
static readonly UNSUPPORTED_DATA = 1003;
|
|
@@ -1308,9 +1307,6 @@ declare class Property<T> {
|
|
|
1308
1307
|
withValue(value: T): RequestHandler<unknown> & UpgradeHandler<unknown>;
|
|
1309
1308
|
}
|
|
1310
1309
|
declare const makeMemo: <T, Args extends any[] = []>(fn: (req: IncomingMessage, ...args: Args) => T, ...args: Args) => ((req: IncomingMessage) => T);
|
|
1311
|
-
declare function setProperty<T>(req: IncomingMessage, property: Property<T>, value: T): void;
|
|
1312
|
-
declare function getProperty<T>(req: IncomingMessage, property: Property<T>): T;
|
|
1313
|
-
declare function clearProperty<T>(req: IncomingMessage, property: Property<T>): void;
|
|
1314
1310
|
|
|
1315
|
-
export { BlockingQueue, CONTINUE, FileFinder, HTTPError, NEXT_ROUTE, NEXT_ROUTER, Property, Queue, Router, STOP, ServerSentEvents, WebListener, WebSocketError, WebSocketMessage, WebSocketMessages, acceptBody, acceptUpgrade, addTeardown, anyHandler, checkIfModified, checkIfRange,
|
|
1316
|
-
export type { AcceptUpgradeHandler, AcceptUpgradeResult, Address, AugmentedFormData, AugmentedServer, CSVOptions, CombinedServerOptions, CommonMethod, CommonUpgrade, CompressionInfo, ErrorHandler, FileFinderCore, FileFinderOptions, FileNegotiation, FileNegotiationOption, FileServerOptions, FormField, GetClient, GetClientOptions, GetFormDataOptions, GetFormFieldsOptions, GetRangeOptions, HTTPErrorOptions, HTTPRange, HandlerResult, JSONErrorHandlerOptions, JSONOptions, ListenOptions, ListenerOptions, NativeListeners,
|
|
1311
|
+
export { BlockingQueue, CONTINUE, FileFinder, HTTPError, NEXT_ROUTE, NEXT_ROUTER, Negotiator, Property, Queue, Router, STOP, ServerSentEvents, WebListener, WebSocketError, WebSocketMessage, WebSocketMessages, acceptBody, acceptUpgrade, addTeardown, anyHandler, checkIfModified, checkIfRange, compareETag, compressFileOffline, compressFilesInDir, conditionalErrorHandler, decompressMime, defer, delegateUpgrade, emitError, errorHandler, fileServer, findCause, generateStrongETag, generateWeakETag, getAbortSignal, getAbsolutePath, getAddressURL, getAuthorization, getBodyJson, getBodyStream, getBodyText, getBodyTextStream, getCharset, getFormData, getFormFields, getIfRange, getMime, getPathParameter, getPathParameters, getQuery, getRange, getRemainingPathComponents, getSearch, getSearchParams, getTextDecoder, getTextDecoderStream, getWebSocketOrigin, hasAuthScope, isSoftClosed, isWebSocketRequest, jsonErrorHandler, makeAcceptWebSocket, makeAddressTester, makeGetClient, makeMemo, makeTempFileStorage, makeWebSocketFallbackTokenFetcher, negotiateEncoding, nextWebSocketMessage, parseAddress, proxy, readHTTPDateSeconds, readHTTPInteger, readHTTPKeyValues, readHTTPQualityValues, readHTTPUnquotedCommaSeparated, readMimeTypes, registerCharset, registerMime, registerUTF32, removeForwarded, replaceForwarded, requestHandler, requireAuthScope, requireBearerAuth, resetMime, restoreAbsolutePath, sanitiseAndAppendForwarded, sendCSVStream, sendFile, sendJSON, sendJSONStream, sendRanges, setDefaultCacheHeaders, setSoftCloseHandler, simpleAppendForwarded, simplifyRange, toListeners, typedErrorHandler, upgradeHandler };
|
|
1312
|
+
export type { AcceptUpgradeHandler, AcceptUpgradeResult, Address, AugmentedFormData, AugmentedServer, CSVOptions, CombinedServerOptions, CommonMethod, CommonUpgrade, CompressionInfo, CompressionOptions, ErrorHandler, FileFinderCore, FileFinderOptions, FileNegotiation, FileNegotiationOption, FileServerOptions, FormField, GetClient, GetClientOptions, GetFormDataOptions, GetFormFieldsOptions, GetRangeOptions, HTTPErrorOptions, HTTPRange, HandlerResult, JSONErrorHandlerOptions, JSONOptions, ListenOptions, ListenerOptions, NativeListeners, NegotiationOutput, NegotiationOutputInfo, ParametersFromPath, PostCheckFile, PostCheckFileInfo, PreCheckFile, PreCheckFileInfo, ProxyChain, ProxyNode, ProxyOptions, ProxyRequestHeaderAdapter, ProxyResponseHeaderAdapter, QualityValue, RangePart, RequestHandler, ResolvedFileInfo, ServerErrorCallback, ServerGeneralErrorCallback, ServerSentEvent, SimplifyRangeOptions, TokenAuthHandler, UpgradeErrorHandler, UpgradeHandler, UpgradeListener, WithPathParameters };
|
package/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{isIPv4 as t,isIPv6 as e}from"node:net";import{STATUS_CODES as n,createServer as i,Agent as r,request as o,ServerResponse as s}from"node:http";import{createReadStream as c,constants as a,createWriteStream as f,openAsBlob as u}from"node:fs";import{createHash as h,randomUUID as l}from"node:crypto";import{pipeline as d}from"node:stream/promises";import w from"node:zlib";import{promisify as p}from"node:util";import{extname as m,join as y,dirname as g,basename as b,sep as v,resolve as E}from"node:path";import{readFile as _,writeFile as T,stat as x,readdir as S,realpath as $,open as k,mkdtemp as N,rm as O}from"node:fs/promises";import{tmpdir as A,platform as P}from"node:os";import{Agent as R,request as F}from"node:https";import{TransformStream as C,TextDecoderStream as U,DecompressionStream as M,ReadableStream as B}from"node:stream/web";import{Readable as D,Duplex as I,Writable as j}from"node:stream";function H(n){if(!n||"unknown"===n)return;const i=/^((?:\d{1,3}\.){3}\d{1,3})(?::(\d+))?$/.exec(n);if(i?.[1]&&t(i[1]))return{type:"IPv4",ip:i[1],port:i[2]?Number.parseInt(i[2]):void 0};const r=/^\[([\da-fA-F:]+)\](?::(\d+))?$|^([\da-fA-F:]+)$/.exec(n);if(r?.[1]&&e(r[1]))return{type:"IPv6",ip:r[1].toLowerCase(),port:r[2]?Number.parseInt(r[2]):void 0};if(r?.[3]&&e(r[3]))return{type:"IPv6",ip:r[3].toLowerCase(),port:void 0};const o=/^(.*?):(\d+)$/i.exec(n);return o?.[2]?{type:"alias",ip:o[1],port:Number.parseInt(o[2])}:{type:"alias",ip:n,port:void 0}}function q(t){const e=new Set,n=[],i=[];for(const r of t){const t=/^((?:\d{1,3}\.){3}\d{1,3})(?:\/(\d+))?$/.exec(r);if(t?.[1]){const e=t[2]?Number.parseInt(t[2]):32,i=e<32?4294967295>>>e:0;n.push([L(t[1])|i,i]);continue}const o=/^\[?([\da-fA-F:]+)\]?(?:\/(\d+))?$/.exec(r);if(o?.[1]){const t=z(o[1]),e=o[2]?J>>BigInt(Number.parseInt(o[2])):0n;i.push([t|e,e]);continue}e.add(r)}return t=>{switch(t?.type){case"alias":return e.has(t.ip);case"IPv4":const r=L(t.ip);return n.some(([t,e])=>(r|e)===t);case"IPv6":const o=z(t.ip);return i.some(([t,e])=>(o|e)===t);default:return!1}}}const J=/*@__PURE__*/BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");function L(t){const e=t.split(".").map(Number);return(e[0]<<24|e[1]<<16|e[2]<<8|e[3])>>>0}function z(t){const e=t.split(":").map(t=>t?Number.parseInt(t,16):-1);let n=0n;for(const t of e)t<0?n<<=16n*BigInt(9-e.length):n=n<<16n|BigInt(t);return n}class W{constructor(t){const e={t:null,i:null};this.o=e,this.u=e,void 0!==t&&this.push(t)}isEmpty(){return!this.o.i}clear(){this.o.i=null,this.o.t=null,this.u=this.o}push(t){const e={t,i:null};this.u.i=e,this.u=e}shift(){if(!this.o.i)return null;this.o=this.o.i;const t=this.o.t;return this.o.t=null,t}remove(t){for(let e=this.o;e.i;e=e.i)if(e.i.t===t){e.i=e.i.i;break}}[Symbol.iterator](){return{next:()=>{if(!this.o.i)return{value:null,done:!0};this.o=this.o.i;const t=this.o.t;return this.o.t=null,{value:t,done:!1}}}}}class G{constructor(){this.h=new W,this.l=new W,this.m=0}push(t){if(this.m)return;const e=this.l.shift();e?(e.v&&clearTimeout(e.v),e._(t)):this.h.push(t)}shift(t){return this.h.isEmpty()?this.m?Promise.reject(this.T):new Promise((e,n)=>{const i={_:e,S:n,v:null};this.l.push(i),void 0!==t&&(i.v=setTimeout(()=>{this.l.remove(i),n(new Error(`timeout after ${t}ms`))},t))}):Promise.resolve(this.h.shift())}$(t){this.T=t;for(const e of this.l)e.S(t),e.v&&clearTimeout(e.v)}close(t){this.m||(this.m=1,this.$(t))}fail(t){this.m||(this.m=2,this.$(t))}[Symbol.asyncIterator](){return{next:()=>this.shift().then(t=>({value:t,done:!1}),t=>{if(2===this.m)throw t;return{value:null,done:!0}})}}}function V(t,e){if(t instanceof e)return t;if(t&&"object"==typeof t){if("cause"in t)return V(t.cause,e);if("error"in t)return V(t.error,e)}}function Z(t,e="http"){if(!t)throw new TypeError("no address");if("string"==typeof t)return t;if("IPv4"===t.family)return`${e}://${t.address}:${t.port}`;if("IPv6"===t.family)return`${e}://[${t.address}]:${t.port}`;throw new TypeError(`unknown address family: ${t.family}`)}const X=/*@__PURE__*/Buffer.alloc(0),Y=t=>new URL("http://localhost"+(t.url??"/"));class K extends Error{constructor(t,e,n){super(n??""),this.error=t,this.suppressed=e}}const Q=globalThis.SuppressedError??K;class tt{constructor(){this.k=!1}N(t){this.k?t!==this.O&&(this.O=new Q(t,this.O)):(this.O=t,this.k=!0)}A(){this.k=!1,this.O=void 0}}const et=new WeakMap;function nt(t,e,n){const i=et.get(t);if(i)return i;const r=Y(t),o={P:t,R:r,F:decodeURIComponent(r.pathname),C:new AbortController,U:e,M:[],B:[],D:n?ot(t):null};return et.set(t,o),o}function it(t,e,n){e||(t.D=null),t.I=n;const i=async()=>{t.C.abort(n.j.writableEnded?"complete":"client abort");const e=new tt;await rt(t.M,e,t),await rt(t.B,e,t,()=>{t.H=async e=>{try{await e()}catch(e){t.U(e,"tearing down",t.P)}}}),e.k&&t.U(e.O,"tearing down",t.P)};return n.j.closed?i():n.j.once("close",i),t}async function rt(t,e,n,i){for(;n.J;)await n.J;const r=(async()=>{for(;;){const n=t.pop();if(!n)return void i?.();try{await n()}catch(t){e.N(t)}}})().then(()=>{n.J===r&&(n.J=void 0)});n.J=r,await r}function ot(t){return new Set(t.headers.upgrade?.split(",").map(t=>t.trim().toLowerCase())??[])}const st=t=>et.get(t),ct=t=>et.delete(t);function at(t){const e=st(t);if(!e)throw new RangeError("unknown request");return e}function ft(t,e,n=ft){throw t.code=e,Error.captureStackTrace(t,n),t}class ut{constructor(t){this.L=t,this.W=Object.create(null),this.G=!1}get headersSent(){return this.G}writeHead(t,e=n[t]??"-"){return this.G&&ft(new Error("Cannot write headers after they are sent to the client"),"ERR_HTTP_HEADERS_SENT"),this.L.write([`HTTP/1.1 ${t} ${dt(e)}`,...ht(this.W),"",""].join("\r\n"),"ascii"),this.G=!0,this}write(t,e="utf-8",n){return this.L.write(t,e,n)}end(t,e="utf-8",n){return this.L.end(t,e,n),this}setHeader(t,e){const n=t.toLowerCase();return this.W[n]="string"==typeof e||"number"==typeof e?e:[...e],this}setHeaders(t){for(const[e,n]of t)this.setHeader(e,n);return this}}function ht(t){const e=[];for(const[n,i]of Object.entries(t)){const t=lt(i);t&&e.push(`${dt(n)}: ${dt(t)}`)}return e}const lt=t=>"string"==typeof t?t:"number"==typeof t?String(t):t?t.join(", "):"",dt=t=>t.replaceAll(/[^ \t!-~]/g,"");function wt(t,e){const n=st(t);n&&pt(n,e)}function pt(t,e){t.V=e;const n=t.Z;n&&queueMicrotask(()=>vt(e,n,t))}const mt=t=>Boolean(st(t)?.Z);function yt(t,e,n){if(!t.Z){if(t.I&&!t.D){const e=t.I.j;e.headersSent||e.hasHeader("connection")||e.setHeader("connection","close")}t.I?.j.once("close",()=>t.P.socket.destroy()),t.Z={X:e,U:n},vt(t.V,t.Z,t),bt(t)}}function gt(t){if(t.I){if(t.D){if(!t.Y&&t.I.j.writable){const e=new ut(t.I.j);e.setHeader("connection","close"),e.writeHead(503)}}else{const e=t.I.j;e.headersSent||(e.hasHeader("connection")||e.setHeader("connection","close"),e.writeHead(503))}t.I.j.end(()=>t.P.socket.destroy())}else t.P.socket.destroy()}function bt(t){if(clearTimeout(t.K),!t.tt||t.H)return;const e=Date.now();if(e>=t.tt)return void gt(t);let n=t.tt;t.et&&!t.Z&&(e<t.et.nt?n=t.et.nt:(t.Z=t.et,vt(t.V,t.Z,t))),void 0===t.K&&t.B.push(()=>clearTimeout(t.K)),t.K=setTimeout(()=>bt(t),n-e)}async function vt(t,e,n){try{await(t?.(e.X))}catch(t){e.U(t,"soft closing",n.P),gt(n)}}const Et=(t,e)=>{const n=at(t);n.H?n.H(e):n.M.push(e)},_t=(t,e)=>{const n=at(t);n.H?n.H(e):n.B.push(e)},Tt=t=>at(t).C.signal;class xt extends Error{}const St=new xt("STOP"),$t=new xt("CONTINUE"),kt=new xt("NEXT_ROUTE"),Nt=new xt("NEXT_ROUTER");async function Ot(t,e){const n=at(t);if(!n.I)throw new TypeError("cannot call acceptUpgrade from shouldUpgrade");if(!n.D)throw new TypeError("not an upgrade request");if(3===n.Y)throw new TypeError("upgrade already delegated");if(2===n.Y)return n.it;const i=n.I.j;if(!i.readable||!i.writable)throw St;n.Y=1;const r=await e(t,i,n.I.o);return n.I.o=X,n.rt=r.onError,r.softCloseHandler&&pt(n,r.softCloseHandler),n.Y=2,n.it=r.return,r.return}const At=RegExp.escape??(t=>t.replaceAll(/[^a-zA-Z0-9_ ]/g,t=>"\\u"+t.charCodeAt(0).toString(16).padStart(4,"0"))),Pt=t=>t,Rt=t=>void 0===t?void 0:""===t?[]:t.split("/"),Ft=t=>void 0===t?void 0:""===t?[]:t.split("/").filter(t=>t);function Ct(t){const e={},n=new Map;for(const[i,r]of Object.entries(t))e[i]=!1,n.set(r,i);return t=>{const i={...e};for(let e=0;e<t.length;++e){const r=n.get(t[e]);if(!r)return[i,t.substring(e)];i[r]=!0}return[i,""]}}const Ut=/*@__PURE__*/Ct({ot:"i",st:"!"}),Mt=Object.freeze({});function Bt(t,e,n){const i=t.P.url,r=t.F,o=t.ct??Mt;return t.P.url=encodeURIComponent(e).replaceAll(/%2F/g,"/")+t.R.search,t.F=e,n.length>0&&(t.ct=Object.freeze(Object.fromEntries([...Object.entries(o),...n]))),()=>{t.P.url=i,t.F=r,t.ct=o}}function Dt(t){return st(t)?.ct??Mt}function It(t,e){return Dt(t)[e]}function jt(t){const e=st(t);return e?e.R.pathname+e.R.search:t.url??"/"}function Ht(t){const e=st(t);e&&(t.url=e.R.pathname+e.R.search)}const qt=t=>"function"==typeof t?{handleRequest:t}:t,Jt=(t,e)=>"function"==typeof t?{handleUpgrade:t,shouldUpgrade:e}:{shouldUpgrade:e,...t},Lt=(t,e=Xt)=>({handleRequest:t,handleUpgrade:t,shouldUpgrade:e}),zt=t=>"function"==typeof t?{handleError:t}:t,Wt=(t,e)=>Gt(e=>e instanceof t,e),Gt=(t,e)=>({handleError:(n,i,r)=>{if(r.response&&t(n))return e(n,i,r.response);throw n},shouldHandleError:(e,n,i)=>Boolean(i.response)&&t(e)}),Vt=t=>"function"==typeof t?{handleRequest:t}:t,Zt=t=>"function"==typeof t?{handleUpgrade:t}:t,Xt=()=>!1,Yt=Symbol("http");class Kt{constructor(){this.ft=[],this.ut=[]}N(t,e,n,i,r){const o=n?((t,e)=>{const n=["^"],i=[],r=/[{}]|\/+|\\(.)|[:*]([a-zA-Z0-9_]*)/g,[{ot:o,st:s},c]=Ut(t);if("/"!==c[0])throw new TypeError("path must begin with '/' or flags");let a=0,f=0;for(const t of c.matchAll(r)){t.index>a&&n.push(At(c.substring(a,t.index)));const e=t[0];if("{"===e)n.push("(?:"),++f;else if("}"===e){if(0===f)throw new TypeError(`unbalanced optional braces in path at ${t.index}`);--f,n.push(")?")}else if("/"===e[0])n.push(e),s||n.push("+");else if("\\"===e[0])n.push(At(t[1]));else{const r=e[0],o=t[2];if(!o)throw new TypeError(`unnamed parameter or unescaped '${r}' at ${t.index}`);"*"===r?(n.push("(.*?)"),i.push({ht:o,lt:s?Rt:Ft})):(n.push("([^/]+?)"),i.push({ht:o,lt:Pt}))}a=t.index+e.length}if(a<c.length&&n.push(At(c.substring(a))),f>0)throw new TypeError("unbalanced optional braces in path");return e&&(n.push("(?:"),s?n.push("(?:(?<=/)|/)"):n.push("(?:/+|(?<=/))"),n.push("(?<rest>.*))?")),n.push("$"),{dt:new RegExp(n.join(""),o?"i":""),wt:i}})(n,i):{dt:null,wt:[]};if(r.some(t=>t instanceof Promise))throw new TypeError("expected handler, got Promise (did you forget to await?)");return this.ft.push({yt:t,gt:"string"==typeof e?e.toLowerCase():e,bt:o.dt,vt:o.wt,Et:r}),this}use(...t){return this.N(null,null,null,!0,t.map(Vt))}mount(t,...e){return this.N(null,null,t,!0,e.map(Vt))}within(t,e){const n=new Kt;return e(n),this.mount(t,n)}at(t,...e){return this.N(null,null,t,!1,e.map(Vt))}onRequest(t,e,...n){return this.N(te(t),Yt,e,!1,n.map(Vt))}onUpgrade(t,e,n,...i){return this.N(te(t),e,n,!1,i.map(Zt))}onError(...t){return this.N(null,null,null,!0,t.map(zt))}onReturn(...t){return this.ut.push(...t),this}on(t,...e){const n=/^([A-Z]+) (\/.*)$/.exec(t);if(!n)throw new TypeError("invalid method + path spec: "+JSON.stringify(t));return this.N(n[1],Yt,n[2],!1,e.map(Vt))}get=(t,...e)=>this.N(Qt,Yt,t,!1,e.map(Vt));delete=(...t)=>this.onRequest("DELETE",...t);getOnly=(...t)=>this.onRequest("GET",...t);head=(...t)=>this.onRequest("HEAD",...t);options=(...t)=>this.onRequest("OPTIONS",...t);patch=(...t)=>this.onRequest("PATCH",...t);post=(...t)=>this.onRequest("POST",...t);put=(...t)=>this.onRequest("PUT",...t);ws=(...t)=>this.onUpgrade("GET","websocket",...t);async handleRequest(t){return this._t(t,new tt)}async handleUpgrade(t){return this._t(t,new tt)}async handleError(t,e){const n=new tt;return n.N(t),this._t(e,n)}shouldUpgrade(t){return this.Tt(at(t))}Tt(t){for(const e of this.ft){const n=ee(t,e);if(!n)continue;let i=()=>{};if(!0!==n)try{i=Bt(t,n.xt,[])}catch{continue}try{for(const n of e.Et)if(re(n,t))return!0}finally{i()}}return!1}async _t(t,e){const n=at(t),i=await this.St(n,e);if(e.k)throw e.O;return i}async St(t,e){for(const n of this.ft){const i=ee(t,n);if(!i)continue;let r=()=>{};if(!0!==i)try{const e=i.$t();r=Bt(t,i.xt,e)}catch(t){e.N(t);continue}try{const i=await ne(t,n.Et,this.ut,e);if(i===Nt)break;if(i===kt)continue;return i}finally{r()}}return $t}}const Qt=new Set(["HEAD","GET"]),te=t=>t?"string"==typeof t?t:new Set(t):null;function ee(t,e){if("string"==typeof e.yt){if(e.yt!==t.P.method)return!1}else if(null!==e.yt&&!e.yt.has(t.P.method??""))return!1;if(e.gt===Yt){if(t.D)return!1}else if(null!==e.gt&&!t.D?.has(e.gt))return!1;if(null===e.bt)return!0;const n=e.bt.exec(t.F);return!!n&&{xt:"/"+(n.groups?.rest??""),$t:()=>e.vt.map((t,e)=>[t.ht,t.lt(n[e+1])])}}async function ne(t,e,n,i){for(const r of e){let e=await ie(r,t,i);if(e!==$t){if(!t.D&&!(e instanceof xt)&&n.length)try{const i="object"==typeof e?e:void 0,r=t.P,o=t.I.j;for(const t of n)await t(i,r,o)}catch(t){i.N(t);continue}return e}}return kt}async function ie(t,e,n){if(t instanceof Kt)return t.St(e,n);let i=$t;try{if(n.k){if(t.handleError){const r=n.O,o=e.D?{socket:e.I.j,head:e.I.o,hasUpgraded:Boolean(e.Y)}:{response:e.I.j};t.shouldHandleError&&!t.shouldHandleError(r,e.P,o)||(n.A(),i=await t.handleError(r,e.P,o))}}else if(e.D){if(t.handleUpgrade){const n=e.I;i=await t.handleUpgrade(e.P,n.j,n.o)}}else t.handleRequest&&(i=await t.handleRequest(e.P,e.I.j))}catch(t){t instanceof xt?i=t:n.N(t)}finally{e.M.length&&await((t,e)=>rt(t.M,e,t))(e,n)}return i===St?void 0:i}function re(t,e){if(t instanceof Kt)return t.Tt(e);if(!t.shouldUpgrade)return Boolean(t.handleUpgrade);try{return t.shouldUpgrade(e.P)}catch(t){return e.U(t,"checking should upgrade",e.P),!1}}class oe extends Error{constructor(t,{message:e,statusMessage:i,headers:r,body:o,...s}={}){super(e??o,s),this.statusCode=0|t,this.statusMessage=i??n[this.statusCode]??"-",this.headers=(t=>{if(!t||t instanceof Headers||Array.isArray(t))return new Headers(t);const e=t instanceof Map?[...t.entries()]:Object.entries(t);return new Headers(e.map(([t,e])=>[t,lt(e)]).filter(([t,e])=>e))})(r),this.body=o??"",this.name=`HTTPError(${this.statusCode} ${this.statusMessage})`}}const se=(t,e,n)=>{const i=ce(n);if(!i)return;const r=V(t,oe)??new oe(500);i.setHeader("content-type","text/plain; charset=utf-8"),i.setHeaders(r.headers),i.setHeader("content-length",String(Buffer.byteLength(r.body,"utf-8"))),n.response||i.setHeader("connection","close"),i.writeHead(r.statusCode,r.statusMessage),i.end(r.body,"utf-8")};function ce(t){if(t.response){const e=t.response;return e.headersSent?void e.end():e}const e=t.socket;if(!t.hasUpgraded&&e.writable)return e.addListener("finish",()=>e.destroy()),new ut(e);e.destroy()}function ae(t,{onError:e=fe,socketCloseTimeout:n=500}={}){let i=0,r="",o=e;const s=[],c=new Set,a=()=>{const t=[...s];s.length=0;for(const e of t)e()},f=t=>{t&&(c.size?s.push(t):setImmediate(t))},u=t=>{c.add(t),t.B.push(()=>{c.delete(t),!c.size&&s.length&&setImmediate(a)})};return{request:async(n,s)=>{let c;try{c=nt(n,e,!1)}catch(t){return e(t,"parsing request",n),void se(new oe(400),0,{response:s})}if(it(c,!1,{j:s}),u(c),1===i)yt(c,r,o);else if(2===i)return gt(c),void ct(n);const a=new tt,f=await ie(t,c,a);a.k||f!==$t&&f!==kt&&f!==Nt||a.N(new oe(404)),a.k&&(e(a.O,"handling request",n),se(a.O,0,{response:s}),ct(n))},upgrade:async(s,c,a)=>{let f;c.once("finish",()=>{const t=setTimeout(()=>c.destroy(),n);c.once("close",()=>clearTimeout(t))});try{f=nt(s,e,!0)}catch(t){return e(t,"parsing upgrade",s),void se(new oe(400),0,{socket:c,hasUpgraded:!1})}if(it(f,!0,{j:c,o:a}),a=X,u(f),1===i)yt(f,r,o);else if(2===i)return gt(f),void ct(s);const h=new tt,l=await ie(t,f,h);h.k||l!==$t&&l!==kt&&l!==Nt||(console.warn(`Upgrade ${s.headers.upgrade} request for ${s.url} fell-through. This probably means you need to add shouldUpgrade to one of your upgrade handlers, or if this is intentional, explicitly reject the request (throw new HTTPError(404)) instead of using CONTINUE.`),h.N(new oe(404))),h.k&&(e(h.O,"handling upgrade",s),f.rt?f.rt(h.O):se(h.O,0,{socket:c,head:f.I?.o??X,hasUpgraded:Boolean(f.Y)}),ct(s))},shouldUpgrade:n=>{try{const i=nt(n,e,!0);return re(t,i)}catch{return!1}},clientError:(t,n)=>{const i=n.kt,r=t.code;n.writable&&!i?.headersSent&&n.end(he.get(r)??le),n.destroy(t),"HPE_INVALID_EOF_STATE"===r||e(t,"initialising request",void 0)},softClose(t,e,n){if(i<1){i=1,r=t,o=e;for(const n of c)yt(n,t,e)}f(n)},hardClose(t){if(i<2){i=2;for(const t of c)gt(t)}f(t)},countConnections:()=>c.size}}const fe=(t,e,n)=>{(V(t,oe)?.statusCode??500)>=500&&console.error("%s",`unhandled error while ${e} ${n?.url??"(no request information)"}:`,t)},ue=t=>Buffer.from(`HTTP/1.1 ${t} ${n[t]}\r\nConnection: close\r\n\r\n`),he=/*@__PURE__*/new Map([["HPE_HEADER_OVERFLOW",/*@__PURE__*/ue(431)],["HPE_CHUNK_EXTENSIONS_OVERFLOW",/*@__PURE__*/ue(413)],["ERR_HTTP_REQUEST_TIMEOUT",/*@__PURE__*/ue(408)]]),le=/*@__PURE__*/ue(400);class de extends EventTarget{constructor(t){super(),this.Nt=t}attach(t,e={}){const n=(e,n,i)=>{const r={server:t,error:e,context:n,request:i};this.dispatchEvent(new CustomEvent("error",{detail:r,cancelable:!0}))&&fe(e,n,i)},i=ae(this.Nt,{...e,onError:n});!1===e.autoContinue&&t.addListener("checkContinue",i.request),!1===e.rejectNonStandardExpect&&t.addListener("checkExpectation",i.request),t.addListener("request",i.request),t.addListener("upgrade",i.upgrade);const r=t.shouldUpgradeCallback??(()=>!1);!1!==e.overrideShouldUpgradeCallback&&(t.shouldUpgradeCallback=i.shouldUpgrade),t.addListener("clientError",i.clientError);let o=()=>{o=void 0,t.removeListener("checkContinue",i.request),t.removeListener("checkExpectation",i.request),t.removeListener("request",i.request),t.removeListener("upgrade",i.upgrade),t.shouldUpgradeCallback===i.shouldUpgrade&&(t.shouldUpgradeCallback=r),t.removeListener("clientError",i.clientError)};return(t="",e=-1,r=!1,s)=>{if(r||o?.(),e>0){const r=setTimeout(()=>{o?.(),i.hardClose()},e);i.softClose(t,n,()=>{o?.(),clearTimeout(r),s?.()})}else 0===e?(o?.(),i.hardClose(s)):(o?.(),s&&setImmediate(s));return i}}createServer(t={}){t.shouldUpgradeCallback&&(t={overrideShouldUpgradeCallback:!1,...t});const e=i(t),n=this.attach(e,t),r=Object.assign(e,{closeWithTimeout:(t,i)=>new Promise(r=>n(t,i,!0,()=>{e.close(()=>r()),e.closeAllConnections()}))});return r}listen(t,e,n={}){const i=this.createServer(n);return n.socketTimeout&&i.setTimeout(n.socketTimeout),new Promise((r,o)=>{i.once("error",o),i.listen(t,e,n.backlog??511,()=>{i.off("error",o),r(i)})})}}const we=t=>st(t)?.R??Y(t),pe=t=>we(t).search,me=t=>new URLSearchParams(we(t).searchParams),ye=(t,e)=>we(t).searchParams.get(e);function ge(t,e){const n=t.indexOf(e);return-1===n?[t]:[t.substring(0,n),t.substring(n+e.length)]}function be(t){const e=t.headers.authorization;if(!e)return;const[n,i]=ge(e," ");return void 0!==i?[n.trim().toLowerCase(),i.trim()]:void 0}function ve(t){const e=/^text\/.*;\s*charset=([^;]+)/i.exec(t.headers["content-type"]??"");return e?.[1]?.trim().toLowerCase()??void 0}function Ee(t){const e=t.headers["if-range"];return e&&"string"==typeof e?/^("|W\/")/.test(e)?{etag:[e]}:{modifiedSeconds:ke(e)}:{}}function _e(t,e,{maxRanges:n=10,maxNonSequential:i=2,maxWithOverlap:r=2}={}){const o=t.headers.range;if(!o||0===e)return;const[s,c]=ge(o,"=");if("bytes"!==s||!c)return;const a=new oe(416,{headers:{"content-range":`bytes */${e}`}}),f=t=>{const e=xe(t);if(void 0===e)throw a;return e},u=[];for(const t of c.split(",")){const[i,r]=ge(t.trim(),"-");if(void 0===r)throw a;let o;if(i)o={start:f(i),end:r?Math.min(f(r),e-1):e-1};else{if(!r)throw a;o={start:Math.max(e-f(r),0),end:e-1}}if(!(o.start>=e)){if(o.end<o.start||u.length>=n)throw a;u.push(o)}}if(!u.length)throw a;if(u.length>i)for(let t=0;t<u.length-1;++t)if(u[t].start>u[t+1].start)throw a;if(u.length>r)for(let t=1;t<u.length;++t){const e=u[t];for(let n=0;n<t;++n){const t=u[n];if(e.end>=t.start&&t.end>=e.start)throw a}}return{ranges:u,totalSize:e}}function Te(t){if(void 0!==t)return"number"==typeof t?[String(t)]:t.length?"string"==typeof t?t.split(",").map(t=>t.trim()):t.flatMap(t=>t.split(",").map(t=>t.trim())):[]}function xe(t){if(t&&/^\s*-?\d+\s*$/.test(t))return Number.parseInt(t,10)}function Se(t){if(t)return t.split(",").map(t=>{const[e,...n]=t.split(";"),i=new Map(n.map(t=>{const[e,n]=ge(t,"=");return[e.trim(),n?.trim()??""]})),r=e.trim(),o="*/*"===r||"*"===r?0:r.endsWith("/*")?1:2,s=Math.max(0,Math.min(1,Number.parseFloat(i.get("q")??"1")));return{name:r,specifiers:i,specificity:o,q:s}})}function $e(t){const e=new Map,n=/\s*([^=]+)=([^";]*?|"(?:[^\\"]|\\.)*")\s*(?:;|$)/y;for(;n.lastIndex<t.length;){const i=n.exec(t);if(!i)throw new oe(400,{body:"invalid HTTP key values"});const r=i[1].toLowerCase();let o=i[2];'"'===o[0]&&(o=o.substring(1,o.length-1).replaceAll(/\\(.)/g,(t,e)=>e)),e.set(r,o)}return e}function ke(t){if("string"!=typeof t)return;const e=Date.parse(t);return Number.isNaN(e)?void 0:e/1e3|0}const Ne=t=>"function"==typeof t?t:()=>t;class Oe{constructor(t=Ue){this.Ot=Ne(t)}set(t,e){Re(t,this,e)}get(t){return Fe(t,this)}clear(t){Ce(t,this)}withValue(t){return Lt(e=>(Re(e,this,t),$t))}}const Ae=(t,...e)=>{const n={Ot:n=>t(n,...e)};return t=>Fe(t,n)};function Pe(t){return t.At||(t.At=new Map),t.At}function Re(t,e,n){Pe(at(t)).set(e,n)}function Fe(t,e){const n=st(t);if(!n)return e.Ot(t);const i=Pe(n);if(i.has(e))return i.get(e);const r=e.Ot(t);return i.set(e,r),r}function Ce(t,e){const n=st(t);n?.At?.delete(e)}const Ue=()=>{throw new Error("property has not been set")};function Me({realm:t,extractAndValidateToken:e,fallbackTokenFetcher:n,closeOnExpiry:i=!0,softCloseBufferTime:r=0,onSoftCloseError:o}){const s=Ne(t);return{...Lt(async t=>{const c=Date.now(),a=await s(t),f={"www-authenticate":`Bearer realm="${a}"`},u=be(t),h="bearer"===u?.[0]?u[1]:await(n?.(t));if(!h)throw new oe(401,{headers:f,body:"no token provided"});let l;try{l=await e(h,a,t)}catch(t){throw new oe(401,{headers:f,body:"invalid token",cause:t})}if(!l)throw new oe(401,{headers:f,body:"invalid token"});if("object"==typeof l){if("nbf"in l&&"number"==typeof l.nbf&&c<1e3*l.nbf)throw new oe(401,{headers:f,body:"token not valid yet"});if("exp"in l&&"number"==typeof l.exp){const e=1e3*l.exp;if(c>=e-r)throw new oe(401,{headers:f,body:"token expired"});i&&((t,e,n,i=0,r)=>{const o=at(t),s=n-Math.max(i,0),c=o.tt??Number.POSITIVE_INFINITY,a=o.et?.nt??c;s>=a&&n>=c||(n<c&&(o.tt=n),s<a&&(o.et={nt:s,X:e,U:r??o.U}),bt(o))})(t,"token expired",e,r,o)}}return Ie.set(t,{Pt:a,Rt:!0,Ft:l,Ct:je(l)}),$t}),getTokenData:t=>{const e=Ie.get(t);if(!e.Rt)throw new TypeError("cannot use getTokenData in an unauthenticated endpoint");return e.Ft}}}const Be=(t,e)=>Ie.get(t).Ct.has(e),De=t=>Lt(e=>{const n=Ie.get(e);if(!n.Ct.has(t))throw new oe(403,{headers:{"www-authenticate":`Bearer realm="${n.Pt}", scope="${t}"`},body:`scope required: ${t}`});return $t}),Ie=/*@__PURE__*/new Oe({Pt:"",Rt:!1,Ft:null,Ct:new Set});function je(t){if(!t||"object"!=typeof t||!("scopes"in t))return new Set;const{scopes:e}=t;return Array.isArray(e)?new Set(e):"string"==typeof e?new Set([e]):e&&"object"==typeof e?new Set(Object.entries(e).filter(([t,e])=>e).map(([t])=>t)):new Set}function He(t,e){const n=`${0|e.mtimeMs} ${e.size} ${t??""}`;return`W/"${h("sha256").update(n).digest("base64").substring(0,12)}"`}async function qe(t){const e=h("sha256");return"string"==typeof t?await d(c(t),e):await d(t.createReadStream({start:0,autoClose:!1}),e),`"sha256-${e.digest("base64")}"`}const Je=(t,e)=>new RegExp(t,(t.unicodeSets?"v":t.unicode?"u":"")+(t.ignoreCase||e?"i":"")),Le={mime:"accept",language:"accept-language",encoding:"accept-encoding"},ze={zstd:"{file}.zst",br:"{file}.br",gzip:"{file}.gz",deflate:"{file}.deflate",identity:"{file}"},We=t=>{return{type:"encoding",options:(e=t,n=ze,Array.isArray(e)?e.map(t=>[t,n[t]]):Object.entries(e)).map(([t,e])=>({match:t,file:e}))};var e,n};function Ge(t,e=10){const n=t.map(t=>({Ut:t.type,Mt:t.options.map(t=>({Bt:t.file,Dt:"string"==typeof t.match?t.match.toLowerCase():Je(t.match,!0),It:t.as??("string"==typeof t.match?t.match:void 0)}))})).filter(t=>t.Mt.length>0);return{options(t,i){let r=e;const o={};return function*t(e,s){const c=n[s];if(!c)return--r,void(yield{filename:e,info:o});const a=new Set,f=(h=i[c.Ut],h?.length?1===h.length?h:[...h].sort(Ve):[]),u=[];var h;for(const t of c.Mt){const e=f.find(e=>"string"==typeof t.Dt?e.name.toLowerCase()===t.Dt:t.Dt.test(e.name));e&&u.push({...e,jt:t})}for(const n of u.sort(Ve)){const i=Ze(e,n.jt.Bt);if(!a.has(i)&&(a.add(i),o[c.Ut]=n.jt.It,yield*t(i,s+1),r<=0))return}o[c.Ut]=void 0,!a.has(e)&&r>0&&(yield*t(e,s+1))}(t,0)},vary:[...new Set(n.map(t=>Le[t.Ut]))].join(" ")}}const Ve=(t,e)=>e.q-t.q||e.specificity-t.specificity;function Ze(t,e){return e.replaceAll(/\{(?:file|base|ext)\}/g,e=>"{file}"===e?t:"{base}"===e?t.replace(/\.[^.]*$/,""):m(t))}const Xe=/*@__PURE__*/tn("bin=application/octet-stream;gz(ip),json,ogg,pdf,wasm,xml,y(a)ml,zip,zst(d)=application/{ext};aac,flac,mid(i),wav(e)=audio/{ext};mp3=audio/mpeg;oga,opus=audio/ogg;otf,ttf,woff,woff2=font/{ext};apng,avif,bmp,gif,heic,heif,jp(e)g,png,tif(f),webp=image/{ext};ico,cur=image/x-icon;svg=image/svg+xml;3mf,obj,stl,u3d=model/{ext};wrl=model/vrml;x3d=model/x3d+xml;x3db=model/x3d+binary;x3dv=model/x3d+vrml;css,csv,htm(l),rtf,vcard=text/{ext};(m)js=text/javascript;md=text/markdown;txt=text/plain;3gp(p),3g(pp)2,mp4,mp(e)g,h264=video/{ext};mov=video/quicktime;ogv=video/ogg");let Ye=/*@__PURE__*/new Map(Xe);function Ke(){Ye=new Map(Xe)}function Qe(t){const e=new Map;for(const n of t.split("\n")){const[t,...i]=n.replaceAll(/\s+/g," ").trim().split(" ");if(!t.startsWith("#"))for(const n of i)e.set(n.toLowerCase(),t)}return e}function tn(t){const e=new Map;for(const n of t.split(/[\n;]/g)){const[t,i,r]=/^ *([^=]+)=(.*)$/.exec(n)??[null,null,""];for(const t of i?.split(",")??[]){const[n,i,o="",s=""]=/^([^(]*)(?:\(([^)]*)\)(.*))?$/.exec(t),c=i+o+s,a=r.replace("{ext}",c);e.set(c.toLowerCase(),a),o&&e.set((i+s).toLowerCase(),a)}}return e}function en(t){for(const[e,n]of t)Ye.set(e.toLowerCase(),n)}function nn(t,e="utf-8"){"."===t[0]&&(t=t.substring(1));const n=Ye.get(t)??"application/octet-stream";return n.startsWith("text/")&&!n.includes("charset=")?`${n}; charset=${e}`:n}async function rn(t,e,n){const i=await _(t),r={file:t,mime:nn(m(t)),rawSize:i.byteLength,bestSize:i.byteLength,created:0};if(r.rawSize<=n)return r;if(["image","video","audio","font"].includes(r.mime.split("/")[0]))return r;for(const o of e){const e=cn.get(o.match),s=y(g(t),Ze(b(t),o.file));if(!e||s===o.file)continue;const c=await e(i);c.byteLength<=r.rawSize-n&&(await T(s,c),r.bestSize=Math.min(r.bestSize,c.byteLength),++r.created)}return r}async function on(t,e,n){const i=[];await sn(t,i);const r=new Set(i);for(const t of r)for(const n of e){const e=y(g(t),Ze(b(t),n.file));e!==t&&r.delete(e)}return Promise.all([...r].map(t=>rn(t,e,n)))}async function sn(t,e){const n=await x(t);if(n.isDirectory())for(const n of await S(t))await sn(y(t,n),e);else n.isFile()&&e.push(t)}const cn=/*@__PURE__*/new Map([["zstd",t=>p(w.zstdCompress)(t)],["br",t=>p(w.brotliCompress)(t,{params:{[w.constants.BROTLI_PARAM_QUALITY]:w.constants.BROTLI_MAX_QUALITY,[w.constants.BROTLI_PARAM_SIZE_HINT]:t.length}})],["gzip",t=>p(w.gzip)(t,{level:w.constants.Z_BEST_COMPRESSION})],["deflate",t=>p(w.deflate)(t)]]),an=(t,e,n)=>{const i=at(t);i.U(e,n??(i.D?"handling upgrade":"handling request"),t)},fn=(t,{onlyIfRequested:e=!0,emitError:n=!0,forceStatus:i,contentType:r="application/json"}={})=>({handleError:(o,s,c)=>{if(c.hasUpgraded||e&&!un(s,r))throw o;n&&an(s,o);const a=ce(c);if(!a)return;const f=V(o,oe)??new oe(500),u=JSON.stringify(t(f));a.setHeaders(f.headers),a.setHeader("content-type",r),a.setHeader("content-length",String(Buffer.byteLength(u,"utf-8"))),c.response||a.setHeader("connection","close"),i?a.writeHead(i):a.writeHead(f.statusCode,f.statusMessage),a.end(u,"utf-8")},shouldHandleError:(t,n,i)=>!i.hasUpgraded&&(!e||un(n,r))}),un=(t,e)=>Se(t.headers.accept)?.some(t=>t.name===e||"application/json"===t.name)??!1;class hn{constructor(t,{subDirectories:e=!0,caseSensitive:n="exact",allowAllDotfiles:i=!1,allowAllTildefiles:r=!1,allowDirectIndexAccess:o=!1,allow:s=[".well-known"],hide:c=[],indexFiles:a=["index.htm","index.html"],implicitSuffixes:f=[],negotiation:u}){this.Ht=t,this.qt=!0===e?Number.POSITIVE_INFINITY:e||0,this.Jt=n,this.Lt=i,this.zt=r,this.Wt=o,this.Gt=a,this.Vt=["",...f],this.Zt=new Set(s.map(t=>this.Xt(t))),this.Yt=new Set,this.Kt=[];for(const t of c)"string"==typeof t?this.Yt.add(this.Xt(t)):this.Kt.push(Je(t,!n));this.Qt=new Set(a.map(t=>this.Xt(t))),u?.length?(this.te=Ge(u),this.vary=this.te.vary):this.vary=""}static async build(t,e){return new hn(await $(t,{encoding:"utf-8"})+v,e)}Xt(t){return"exact"===this.Jt?t:t.toLowerCase()}ee(t){if(this.Zt.has(t))return!0;const e=t.trim();return!(!("~"!==e[0]&&"~"!==e[e.length-1]||this.zt)||"."===e[0]&&!this.Lt||this.Yt.has(e)||this.Kt.some(t=>t.test(e)))}toNormalisedPath(t){const e=t[t.length-1];return e&&this.Qt.has(this.Xt(e))?t.slice(0,t.length-1):t}async find(t,e={},n){let i=t.join(v);"force-lowercase"===this.Jt&&(i=i.toLowerCase());let r=E(this.Ht,i);if(!r.startsWith(this.Ht)&&r+v!==this.Ht)return n?.push(`${JSON.stringify(r)} is not inside root ${JSON.stringify(this.Ht)}`),null;let o=null,s=null;for(const t of this.Vt){const e=r+t;if(o=e.substring(this.Ht.length).split(v).filter(t=>t),o.length-1>this.qt)return n?.push(`${JSON.stringify(r)} is nested too deeply (${o.length-1} > ${this.qt})`),null;if(o.some(t=>!this.ee(this.Xt(t))))return n?.push(`${JSON.stringify(r)} is not permitted`),null;const i=o[o.length-1]??"";if(!this.Wt&&this.Qt.has(this.Xt(i))&&!this.Zt.has(this.Xt(i)))return n?.push(`${JSON.stringify(r)} is a hidden index file`),null;if(s=await $(e,{encoding:"utf-8"}).catch(()=>null),s){r=e;break}}if(!s||!o)return n?.push(`file ${JSON.stringify(r)} does not exist`),null;if(this.Xt(s)!==this.Xt(r))return n?.push(`realpath ${JSON.stringify(s)} does not match request ${JSON.stringify(r)}`),null;let c=s,a=await x(s).catch(()=>null);if(!a)return n?.push(`file ${JSON.stringify(s)} does not exist`),null;if(a.isDirectory()){if(o.length>this.qt)return n?.push(`${JSON.stringify(s)} index file is nested too deeply (${o.length} > ${this.qt})`),null;for(const t of this.Gt){const e=y(s,t);if(a=await x(e).catch(()=>null),a?.isFile()){c=e;break}}}if(!a?.isFile())return n?.push(`${JSON.stringify(s)} exists but is not a file`),null;if(this.te){const t=b(c),i=g(c);for(const r of this.te.options(t,e)){if(!r.filename||r.filename.includes(v))continue;const t=await dn({canonicalPath:c,negotiatedPath:y(i,r.filename),...r.info},n);if(t)return t}}return dn({canonicalPath:c,negotiatedPath:c},n)}async debugAllPaths(){return(await this.precompute()).debugAllPaths()}async precompute(){const t=new Map,e=(e,n)=>{const i=t.get(e);(!i||n.p>i.p)&&t.set(e,n)},n=new W({dir:[this.Ht],depth:0});for(const{dir:t,depth:i}of n){const r=await S(y(...t),{withFileTypes:!0,encoding:"utf-8"}),o=new Set(r.map(t=>this.Xt(t.name)));for(const s of r){const r=this.Xt(s.name);if(!this.ee(r))continue;const c=[...t,s.name];if(s.isDirectory())i<this.qt&&n.push({dir:c,depth:i+1}),e(this.Xt(c.slice(1).join("/")),ln);else if(s.isFile()){const n={file:y(...c),dir:y(...t),basename:r,siblings:o},i=this.Gt.indexOf(r);if(-1!==i&&(e(this.Xt(t.slice(1).join("/")),{...n,p:this.Gt.length+1-i}),!this.Wt&&!this.Zt.has(r)))continue;const a=this.Xt(c.slice(1).join("/"));for(let t=0;t<this.Vt.length;++t){const i=this.Vt[t];s.name.endsWith(i)&&e(a.substring(0,a.length-i.length),{...n,p:-t})}}}}return{find:async(e,n={},i)=>{const r=t.get(this.Xt(e.join("/")));if(!r?.file)return i?.push(`${JSON.stringify(e.join("/"))} not found in static file paths`),null;if(this.te)for(const t of this.te.options(r.basename,n)){if(!r.siblings.has(this.Xt(t.filename)))continue;const e=await dn({canonicalPath:r.file,negotiatedPath:y(r.dir,t.filename),...t.info},i);if(e)return e}return dn({canonicalPath:r.file,negotiatedPath:r.file},i)},debugAllPaths:()=>Promise.resolve(new Set([...t].filter(([t,e])=>e.file).map(([t])=>t))),vary:this.vary}}}const ln={file:"",dir:"",basename:"",siblings:new Set,p:1};async function dn(t,e){const n=await k(t.negotiatedPath,a.O_RDONLY).catch(()=>null);if(!n)return e?.push(`failed to open ${JSON.stringify(t.negotiatedPath)}`),null;const i=()=>(n.close().catch(()=>{}),null),r=await n.stat().catch(i);return r?.isFile()?{handle:n,stats:r,...t}:(e?.push(`${JSON.stringify(t.negotiatedPath)} exists but is not a file`),i())}const wn=/*@__PURE__*/Ae(async t=>{const e=Tt(t);if(e.aborted)throw St;e.throwIfAborted();const n=await N(y(A(),"upload"));_t(t,()=>O(n,{recursive:!0}));let i=0;const r=()=>{if(e.aborted)throw St;return y(n,(++i).toString(10).padStart(6,"0"))};return{dir:n,nextFile:r,save:async(t,{mode:n=384}={})=>{const i=r(),o=f(i,{mode:n});try{return await d(t,o,{signal:e}),{path:i,size:o.bytesWritten}}finally{o.close()}}}});function pn(t){const e=at(t);if(!e.I)throw new TypeError("cannot call acceptBody from shouldUpgrade");if(e.C.signal.aborted)throw St;e.ne||e.D||(e.ne=!0,"100-continue"===t.headers.expect?.trim().toLowerCase()&&e.I.j.writeContinue())}function mn(t,{blockRequestHeaders:e=["connection","expect","host","keep-alive","proxy-authorization","transfer-encoding","upgrade","via"],requestHeaders:n=[],blockResponseHeaders:i=["connection","keep-alive","transfer-encoding"],responseHeaders:s=[],agent:c,keepAlive:a=!0,maxSockets:f=10,...u}={}){let h;t.startsWith("https://")?(c??=new R({keepAlive:a,maxSockets:f,...u}),h=o):(c??=new r({keepAlive:a,maxSockets:f,...u}),h=F);const l=t.endsWith("/")?t:t+"/";return qt((r,o)=>new Promise((a,f)=>{const u=Tt(r),w=t=>f(u.aborted?St:new oe(502,{cause:t})),p=new URL(l+r.url?.substring(1)),m=p.toString();if(!m.startsWith(l)&&m!==t)return f(new oe(400,{message:"directory traversal blocked"}));pn(r);let y={...r.headers};yn(y,e);for(const t of n)y=t(r,y);const g=h(p,{agent:c,method:r.method,headers:y,signal:u});g.once("error",w),g.once("response",t=>{if(!o.headersSent){let e={...t.headers};yn(e,i);for(const n of s)e=n(r,t,e);o.writeHead(t.statusCode??200,t.statusMessage,e)}d(t,o).then(a,f)}),d(r,g).catch(w)}))}function yn(t,e){for(const e of Te(t.connection)??[])delete t[e.toLowerCase()];for(const n of e)delete t[n]}function gn({trustedProxyCount:t,trustedProxyAddresses:e,trustedHeaders:n}){const i=e?q(e):()=>!0,r=t??(e?Number.POSITIVE_INFINITY:0),o=new Set(n);return Ae(t=>{const e=e=>{if(o.has(e))return Te(t.headers[e])?.reverse()},n=e("forwarded"),s=e("x-forwarded-for"),c=e("x-forwarded-host"),a=e("x-forwarded-proto"),f=e("x-forwarded-protocol"),u=e("x-url-scheme"),h=e("via")?.map(t=>{const e=/^([^/ ]+\/)?([^ ]+) (.+)$/.exec(t);return e?.[3]?H(e[3]):void 0}),l=[bn(t)];if(n)for(const t of n)try{const e=$e(t);l.push({client:H(e.get("for")),server:H(e.get("by")),host:e.get("host"),proto:e.get("proto")})}catch{l.push({client:void 0,server:void 0,host:void 0,proto:void 0})}else if(s){const t=s.map(H),e=c??[],n=a??f??u??[];let i=l[0].client;for(let r=0;r<t.length;++r){const o=t[r];l.push({client:o,server:h?.[r]??(i?{...i,port:void 0}:void 0),host:e[r],proto:n[r]}),i=o}}else if(h)for(const t of h)l.push({client:void 0,server:t,host:void 0,proto:void 0});let d=Math.min(1+r,l.length);for(let t=0;t<d-1;++t)i(l[t].client)||(d=t+1);return Object.freeze({trusted:l.slice(0,d),untrusted:l.slice(d),outwardChain:l,edge:l[d-1]})})}const bn=t=>({client:{...H(t.socket.remoteAddress)??vn,port:t.socket.remotePort},server:{...H(t.socket.localAddress)??vn,port:t.socket.localPort},host:t.headers.host,proto:void 0}),vn={type:"alias",ip:"_disconnected",port:void 0};function En(t,e){return delete e.forwarded,delete e["x-forwarded-for"],delete e["x-forwarded-host"],delete e["x-forwarded-proto"],delete e["x-forwarded-protocol"],delete e["x-url-scheme"],e}function _n(t,e){const n=En(0,e);return n.forwarded=Sn([bn(t)]),n}const Tn=(t,{onlyTrusted:e=!1}={})=>(n,i)=>{const r=En(0,i),o=t(n);return r.forwarded=Sn([...e?o.trusted:o.outwardChain].reverse()),r};function xn(t,e){let n=t.headers.forwarded;const i=Sn([bn(t)]);n?n+=", "+i:n=i;const r=En(0,e);return r.forwarded=n,r}function Sn(t){return t.filter(t=>t.server||t.client).map(t=>Object.entries({for:t.client?.ip,by:t.server?.ip,host:t.host,proto:t.proto}).filter(([t,e])=>e).map(([t,e])=>e&&/[^a-zA-Z0-9._]/.test(e)?`${t}="${e.replaceAll("\\","\\\\").replaceAll('"','\\"').replaceAll(",","-")}"`:`${t}=${e}`).join("; ")).join(", ")}class $n{constructor(t,{fatal:e=!1}={}){this.ie=t,this.re=e,this.oe=new Uint8Array(4),this.se=new DataView(this.oe.buffer),this.ce=0}decode(t,{stream:e=!1}={}){const n=t.byteLength,i=[];let r=0;if(this.ce>0){if(r=4-this.ce,n<r)return this.oe.set(t,this.ce),this.ce+=n,"";this.oe.set(t.subarray(0,r),this.ce),i.push(this.se.getUint32(0,this.ie)),this.ce=0}const o=new DataView(t.buffer,t.byteOffset,t.byteLength);let s=r;for(const t=n-3;s<t;s+=4)i.push(o.getUint32(s,this.ie));if(e?(s<n&&this.oe.set(t.subarray(s)),this.ce=n-s):(this.ce=0,s<n&&(this.re?ft(new TypeError("The encoded data was not valid for encoding utf-32"),"ERR_ENCODING_INVALID_ENCODED_DATA"):i.push(65533))),i.length>0){try{return String.fromCodePoint(...i)}catch{this.re&&ft(new TypeError("The encoded data was not valid for encoding utf-32"),"ERR_ENCODING_INVALID_ENCODED_DATA")}for(let t=0;t<i.length;++t)i[t]>1114111&&(i[t]=65533);return String.fromCodePoint(...i)}return""}}class kn extends C{constructor(t){super({transform(e,n){try{const i=t.decode(e,{stream:!0});i&&n.enqueue(i)}catch(t){n.error(t)}},flush(e){try{const n=t.decode(X);n&&e.enqueue(n)}catch(t){e.error(t)}}})}}const Nn=new Map;function On(t,e){Nn.set(t.toLowerCase(),e)}function An(){On("utf-32be",{decoder:t=>new $n(!1,t)}),On("utf-32le",{decoder:t=>new $n(!0,t)})}function Pn(t,e={}){const n=Nn.get(t.toLowerCase());if(n)return n.decoder(e);try{return new TextDecoder(t,e)}catch{throw new oe(415,{body:`unsupported charset: ${t}`})}}function Rn(t,e={}){const n=Nn.get(t.toLowerCase());if(n)return n.decoderStream?n.decoderStream(e):new kn(n.decoder(e));try{return new U(t,e)}catch{throw new oe(415,{body:`unsupported charset: ${t}`})}}const Fn=["utf-32be",null,"utf-16be","utf-16be","utf-32le","utf-16le",null,"utf-8"];function Cn(t,e,n){const i=ke(t.headers["if-modified-since"]),r=Te(t.headers["if-none-match"]);if(r){if(Mn(e,n,r))return!1}else if(i&&(n.mtimeMs/1e3|0)<=i)return!1;return!0}function Un(t,e,n){let i=!0;const r=Ee(t);return r.etag&&(i&&=Mn(e,n,r.etag)),r.modifiedSeconds&&(i&&=(n.mtimeMs/1e3|0)===r.modifiedSeconds),i}function Mn(t,e,n){if(n.includes("*"))return!0;const i=t.getHeader("etag");if("string"==typeof i){if(n.includes(i))return!0;if(i.startsWith('W/"'))return!1}return!!n.some(t=>t.startsWith('W/"'))&&n.includes(He(t.getHeader("content-encoding"),e))}class Bn extends C{constructor(t,e){super({transform(i,r){n+=i.byteLength,n>t?r.error(e):r.enqueue(i)}});let n=0}}function Dn(t,{maxContentBytes:e=Number.POSITIVE_INFINITY,maxNetworkBytes:n=e,maxEncodingSteps:i=1}={}){const r=xe(t.headers["content-length"]);if(void 0!==r&&r>n)throw new oe(413);const o=Te(t.headers["content-encoding"])??[];if(o.length>i)throw new oe(415,{body:"too many content-encoding stages"});pn(t);let s=D.toWeb(t);void 0===r&&Number.isFinite(n)&&(s=s.pipeThrough(new Bn(n,new oe(413))));for(const t of o.reverse())s=s.pipeThrough(qn(t));return Number.isFinite(e)&&(s=s.pipeThrough(new Bn(e,new oe(413,{body:"decoded content too large"})))),s}function In(t,e={}){const n=Dn(t,e),i=ve(t)??e.defaultCharset??"utf-8";return n.pipeThrough(Rn(i,e))}async function jn(t,e={}){const n=[];for await(const i of In(t,e))n.push(i);return n.join("")}async function Hn(t,e={}){const n=await(async(t,e)=>{const n=t.getReader(),i=new Uint8Array(3);let r=0,o=null;for(;;){const t=await n.read(),e=3-r;if(t.done){0===r?(i[0]=1,i[1]=1):1===r&&(i[1]=i[0]),i[2]=i[0],o=null;break}if(o=t.value,o.byteLength>=e){i.set(o.subarray(0,e),r);break}i.set(o,r),r+=o.byteLength}const s=Fn[(i[0]?4:0)|(i[1]?2:0)|(i[2]?1:0)];if(!s)throw n.cancel(),new oe(415,{body:"invalid JSON encoding"});const c=Rn(s,e),a=c.writable.getWriter();return r&&a.write(i.subarray(0,r)),o&&a.write(o),n.releaseLock(),a.releaseLock(),t.pipeThrough(c)})(Dn(t,e),e),i=[];for await(const t of n)i.push(t);return JSON.parse(i.join(""))}function qn(t){switch(t.toLowerCase()){case"gzip":case"x-gzip":return new M("gzip");case"deflate":return new M("deflate");case"br":try{return new M("brotli")}catch{return I.toWeb(w.createBrotliDecompress())}case"zstd":try{return I.toWeb(w.createZstdDecompress())}catch{throw new oe(415,{body:"unsupported content encoding"})}default:throw new oe(415,{body:"unknown content encoding"})}}function Jn(t){if(!t)return null;const[e,n]=ge(t,";"),i=new Map;if(n){const t=/\s*([!#-'*+\-.0-:>-Z^-z|~]+)=(?:([!#-'*+\-.0-:>-Z^-z|~]+)|"((?:[^\x00-\x08\x0a-\x1f"\\\x7f]|\\.)*)")\s*(;|$)/gy;for(;t.lastIndex!==n.length;){const e=t.exec(n);if(!e)return null;const r=e[1].toLowerCase(),o=e[2]??e[3]?.replaceAll(/\\(.)/g,"$1")??"";i.has(r)||i.set(r,o)}}return{mime:e.trim().toLowerCase(),params:i}}function Ln(t,e,n,i){const r=t.byteLength;for(;e<r;){for(;e<r;++e){const n=t[e];if(32!==n&&9!==n)break}if(e===r)break;if(59!==t[e++])return!1;for(;e<r;++e){const n=t[e];if(32!==n&&9!==n)break}if(e===r)return!1;const o=e;for(;e<r;++e){const n=t[e];if(!Wn[n]){if(61===n)break;return!1}}if(e===r)return!1;const s=t.latin1Slice(o,e).toLowerCase();if("*"===s[s.length-1]){const i=++e;for(;e<r;++e){const n=t[e];if(!Vn[n]){if(39!==n)return!1;break}}if(e===r)return!1;const o=Pn(t.latin1Slice(i,e));for(++e;e<r&&39!==t[e];++e);if(e===r)return!1;if(++e===r)return!1;let c=e;const a=[];for(;e<r;++e){const n=t[e];if(1!==Gn[n]){if(37===n){let n,i;if(e+2<r&&16!==(n=Xn[t[e+1]])&&16!==(i=Xn[t[e+2]])){const r=(n<<4)+i;e>c&&a.push(o.decode(t.subarray(c,e),{stream:!0})),a.push(o.decode(Buffer.from([r]),{stream:!0})),c=(e+=2)+1;continue}return!1}break}}a.push(o.decode(t.subarray(c,e)));const f=a.join("");n.has(s)||n.set(s,f);continue}if(++e===r)return!1;if(34===t[e]){let o=++e,c=!1;const a=[];for(;e<r;++e){const n=t[e];if(92!==n){if(34===n){if(c){o=e,c=!1;continue}a.push(i.decode(t.subarray(o,e)));break}if(c&&(o=e-1,c=!1),!Zn[n])return!1}else c?(o=e,c=!1):(a.push(i.decode(t.subarray(o,e),{stream:!0})),c=!0)}if(e===r)return!1;++e,n.has(s)||n.set(s,a.join(""));continue}let c=e;for(;e<r;++e){const n=t[e];if(!Wn[n]){if(e===c)return!1;break}}n.has(s)||n.set(s,i.decode(t.subarray(c,e)))}return!0}const zn=[1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],Wn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,...zn,0,1,0,1],33),t})(),Gn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,0,1,0,0,0,0,1,0,1,1,0,...zn,0,1,0,1],33),t})(),Vn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,...zn,1,0,1,1],33),t})(),Zn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.fill(1,32,256),t[9]=1,t[34]=0,t[92]=0,t[127]=0,t})(),Xn=/*@__PURE__*/(()=>{const t=new Uint8Array(256).fill(16);for(let e=0;e<10;++e)t[48+e]=e;for(let e=0;e<6;++e)t[65+e]=e+10,t[97+e]=e+10;return t})();class Yn{constructor(t,e){const n=t.byteLength;if(!n||n>65535)throw new RangeError("invalid needle");this.ae=t,this.fe=e,this.ue=null,this.he=0,this.le=null}push(t){let e=0;const n=t.byteLength,i=this.ae,r=i.byteLength-1,o=n-r;let s=-this.he;if(this.he){const c=this.le,a=this.ue,f=i[r];if(o>0){const n=t[s+r];n!==f||t.compare(i,-s,r,0,s+r)?s+=c[n]:(this.fe(!0,X,0,0,!0),this.he=0,e=s+=r+1)}const u=o<0?o:0;for(;s<u;){const n=t[s+r];if(n===f&&!a.compare(i,0,-s,this.he+s,this.he)&&!t.compare(i,-s,r,0,s+r)){this.fe(!0,a,0,this.he+s,!1),this.he=0,e=s+=r+1;break}s+=c[n]}const h=this.he;if(h>0){const e=i[0];for(;s<0;){const r=a.subarray(0,h).indexOf(e,h+s);if(-1===r){s=0;break}const o=h-r;if(!a.compare(i,1,o,r+1,h)&&!t.compare(i,o,o+n))return r&&(this.fe(!1,a,0,r,!1),a.copy(a,0,r,o)),a.set(t,o),void(this.he+=n-r);s=r+1-h}this.fe(!1,a,0,h,!1),this.he=0}}for(;s<o;){const n=t.indexOf(i,s);if(-1!==n){if(this.fe(!0,t,e,n,!0),n===o+1)return;e=s=n+r+1}else s=o}const c=i[0];for(;s<n;){const o=t.indexOf(c,s);if(-1===o)return void this.fe(!1,t,e,n,!0);if(!t.compare(i,1,n-o,o+1)){if(!this.ue){this.ue=Buffer.allocUnsafe(r),this.le=new Uint16Array(256).fill(r+1);for(let t=0;t<r;++t)this.le[i[t]]=r-t}return t.copy(this.ue,0,o),this.he=n-o,void(o>e&&this.fe(!1,t,e,o,!0))}s=o+1}n>e&&this.fe(!1,t,e,n,!0)}destroy(){const t=this.he;t&&this.ue&&this.fe(!1,this.ue,0,t,!1),this.he=0}}class Kn extends j{constructor({limits:t={},preservePath:e,highWaterMark:n,fileHwm:i,defParamCharset:r="utf-8",defCharset:o="utf-8"},s){super({autoDestroy:!0,emitClose:!0,highWaterMark:n,write:Qn,destroy:ti,final:ei});const c=s.get("boundary");if(!c)throw new oe(400,{body:"multipart boundary not found"});if(c.length>70)throw new oe(400,{body:"multipart boundary too long"});const a=Pn(r),f={autoDestroy:!0,emitClose:!0,highWaterMark:i},u=t.fieldSize??1048576,h=t.fileSize??Number.POSITIVE_INFINITY,l=t.fieldNameSize??100,d=t.files??Number.POSITIVE_INFINITY,w=t.fields??Number.POSITIVE_INFINITY,p=t.parts??Number.POSITIVE_INFINITY;let m,y,g,b,v,E=0,_=0,T=0,x=-1;this.de=0,this.we=!1;let S=!1;const $=new ni(t=>{this.pe=void 0;const n=t["content-disposition"];if(!n)return void(x=-1);const i=((t,e)=>{if(!t.byteLength)return null;const n=new Map;let i=0;for(;i<t.byteLength;++i)if(!Wn[t[i]]){if(!Ln(t,i,n,e))return null;break}return{type:t.latin1Slice(0,i).toLowerCase(),params:n}})(Buffer.from(n,"latin1"),a);if("form-data"!==i?.type)return void(x=-1);v=i.params.get("name")??"",S=v.length>l,S&&(v=v.substring(0,l));let r=i.params.get("filename*")??i.params.get("filename");void 0===r||e||(r=(t=>{for(let e=t.length;e-- >0;)if("/"===t[e]||"\\"===t[e]){t=t.slice(e+1);break}return".."===t||"."===t?"":t})(r));const s=Jn(t["content-type"]);b=s?.mime??"text/plain";const c=s?.params.get("charset")?.toLowerCase()??o;if(y=Pn(c),g=t["content-transfer-encoding"]?.toLowerCase()??"7bit","application/octet-stream"===b||void 0!==r){if(T++===d&&this.emit("filesLimit"),T>d||0===this.listenerCount("file"))return void(x=-1);this.me=new ii(f,this),++this.de,this.emit("file",v,this.me,{nameTruncated:S,filename:r,encoding:g,mimeType:b}),x=h}else{if(_++===w&&this.emit("fieldsLimit"),_>w||0===this.listenerCount("field"))return void(x=-1);m="",x=u}});let k=0;const N=Buffer.from(`\r\n--${c}`,"latin1");this.ye=new Yn(N,(t,e,n,i,r)=>{try{if(n===i)return;if(k){if(1===k){if(13===e[n])k=2;else{if(45!==e[n])return void(k=0);k=3}if(++n===i)return}if(2!==k){if(k=0,45!==e[n])return;return this.we=!0,void(this.ye=oi)}if(k=0,10!==e[n++])return;if(E++===p&&this.emit("partsLimit"),E>p)return;if(this.pe=$,n===i)return}if(this.pe){const t=this.pe.push(e,n,i);if(-1===t)return this.pe=void 0,$.reset(),void this.emit("error",new oe(400,{body:"malformed part header"}));if(t===i)return;n=t}if(x>=0){const t=Math.min(i,n+x);if(x-=i-n,this.me){if(t>n){let i;r?i=e.subarray(n,t):(i=Buffer.allocUnsafe(t-n),e.copy(i,0,n,t)),this.me.push(i)||(this.me.ge??=this.be,this.be=void 0)}x<0&&(this.me.emit("limit"),this.me.truncated=!0)}else void 0!==m&&(m+=e.latin1Slice(n,t))}}finally{t&&(this.pe?(this.emit("error",new oe(400,{body:"unexpected end of headers"})),this.pe=void 0):this.me?(this.me.push(null),this.me=void 0):void 0!==m&&(this.emit("field",v,y.decode(Buffer.from(m,"latin1")),{nameTruncated:S,valueTruncated:x<0,encoding:g,mimeType:b}),m=void 0),k=1,x=-1)}}),this.write(si)}ve(){if(this.pe)return new oe(400,{body:"malformed part header"});const t=this.me;return t&&(this.me=void 0,t.destroy(new oe(400,{body:"unexpected end of file"}))),this.we?null:new oe(400,{body:"unexpected end of form"})}}function Qn(t,e,n){this.be=n,this.ye.push(t);const i=this.be;i&&(this.be=void 0,i())}function ti(t,e){this.pe=void 0,this.ye=oi,t??=this.ve();const n=this.me;n&&(this.me=void 0,n.destroy(t??void 0)),e(t)}function ei(t){if(this.ye.destroy(),!this.we)return t(new oe(400,{body:"unexpected end of form"}));this.de?this.Ee=()=>t(this.ve()):t(this.ve())}class ni{constructor(t){this._e=Object.create(null),this.Te=0,this.xe=0,this.m=0,this.ht="",this.Se="",this.$e=0,this.fe=t}reset(){this._e=Object.create(null),this.Te=0,this.xe=0,this.m=0,this.ht="",this.Se="",this.$e=0}push(t,e,n){let i=e,r=e;const o=Math.min(n,e+16384-this.xe);for(;r<o;)switch(this.m){case 0:for(;r<o&&Wn[t[r]];++r);if(r>i&&(this.ht+=t.latin1Slice(i,r)),r<o){if(58!==t[r])return-1;if(!this.ht)return-1;++r,this.m=1}break;case 1:for(;r<o;++r){const e=t[r];if(32!==e&&9!==e){i=r,this.m=2;break}}break;case 2:switch(this.$e){case 0:for(;r<o;++r){const e=t[r];if(e<32||127===e){if(13!==e)return-1;++this.$e;break}}this.Se+=t.latin1Slice(i,r),++r;break;case 1:if(10!==t[r++])return-1;++this.$e;break;case 2:{const e=t[r];32===e||9===e?(i=r,this.$e=0):(++this.Te<2e3&&(this._e[this.ht.toLowerCase()]??=this.Se),13===e?(++this.$e,++r):(i=r,this.$e=0,this.m=0,this.ht="",this.Se=""));break}case 3:{if(10!==t[r++])return-1;const e=this._e;return this.reset(),this.fe(e),r}}}return o<n?-1:(this.xe+=o-e,o)}}class ii extends D{constructor(t,e){super({...t,read:ri}),this.truncated=!1,this.once("end",()=>{if(ri.call(this),0===--e.de&&e.Ee){const t=e.Ee;e.Ee=void 0,process.nextTick(t)}})}}function ri(t){const e=this.ge;e&&(this.ge=void 0,e())}const oi={push:()=>{},destroy:()=>{}},si=/*@__PURE__*/Buffer.from("\r\n");class ci extends j{constructor({limits:t={},highWaterMark:e,defCharset:n="utf-8"},i){super({autoDestroy:!0,emitClose:!0,highWaterMark:e,write:ai,final:fi}),this.ke=i.get("charset")??n,this.Ne=t.fieldSize??1048576,this.Oe=t.fields??Number.POSITIVE_INFINITY,this.Ae=t.fieldNameSize??100,this.Pe=0,this.Re=!0,this.Fe="",this.Ce=this.Ae,this.Ue=0,this.Me="",this.Be=!1,this.De=-2,this.Ie=/^utf-?8$/i.test(this.ke)?1:/^(latin-?1|iso[\-_]?8859-?1|(us-)?ascii)$/i.test(this.ke)?2:0,this.je=Pn(this.ke)}}function ai(t,e,n){if(!t.byteLength)return n();if(this.Pe>=this.Oe)return this.Pe||t===pi||(++this.Pe,this.emit("fieldsLimit")),n();const i=t.byteLength;let r=0,o=this.De;if(-2!==o){if(-1===o){if(16===(o=Xn[t[r++]]))return n(new oe(400,{body:"malformed urlencoded form"}));if(this.Ue|=o,r===i)return this.De=o,n()}const e=Xn[t[r++]];if(16===e)return n(new oe(400,{body:"malformed urlencoded form"}));if(this.Fe+=String.fromCharCode((o<<4)+e),this.De=-2,r===i)return n()}for(wi[ui]=1,wi[hi]=1,wi[li]=1,wi[di]=this.Re?1:0;;){const e=r;for(;r<i&&!wi[t[r]];++r);if(r>e&&this.Ce>=0&&((this.Ce-=r-e)<0?this.Fe+=t.latin1Slice(e,r+this.Ce):this.Fe+=t.latin1Slice(e,r)),r===i)return n();switch(t[r++]){case ui:for(;;){if(--this.Ce<0){wi[ui]=0,wi[li]=0;break}if(r===i)return this.De=-1,n();const e=Xn[t[r++]];if(16===e)return n(new oe(400,{body:"malformed urlencoded form"}));if(this.Ue|=e,r===i)return this.De=e,n();const o=Xn[t[r++]];if(16===o)return n(new oe(400,{body:"malformed urlencoded form"}));if(this.Fe+=String.fromCharCode((e<<4)+o),r===i)return n();if(t[r]!==ui)break;r++}break;case hi:const e=!this.Ie||1===this.Ie&&8&this.Ue?this.je.decode(Buffer.from(this.Fe,"latin1")):this.Fe;if(this.Re?(e||this.Ce<0)&&this.emit("field",this.Fe,"",{nameTruncated:this.Ce<0,valueTruncated:!1,encoding:this.ke,mimeType:"text/plain"}):(this.emit("field",this.Me,e,{nameTruncated:this.Be,valueTruncated:this.Ce<0,encoding:this.ke,mimeType:"text/plain"}),this.Me="",this.Be=!1,this.Re=!0,wi[di]=1),wi[ui]=1,wi[li]=1,this.Fe="",this.Ce=this.Ae,this.Ue=0,++this.Pe===this.Oe&&t!==pi)return this.emit("fieldsLimit"),n();break;case li:--this.Ce<0?(wi[ui]=0,wi[li]=0):this.Fe+=" ";break;case di:this.Me=!this.Ie||1===this.Ie&&8&this.Ue?this.je.decode(Buffer.from(this.Fe,"latin1")):this.Fe,this.Be=this.Ce<0,this.Re=!1,wi[di]=0,wi[ui]=1,wi[li]=1,this.Fe="",this.Ue=0,this.Ce=this.Ne}if(r===i)return n()}}function fi(t){ai.call(this,pi,void 0,t)}const ui=37,hi=38,li=43,di=61,wi=/*@__PURE__*/new Uint8Array(256),pi=/*@__PURE__*/Buffer.from([hi]);function mi(t,{closeAfterErrorDelay:e=500,...n}={}){const i=((t,e={})=>{const n=t["content-type"];if(!n)throw new oe(400,{body:"missing content-type"});const i=Jn(n);if(!i)throw new oe(400,{body:"malformed content-type"});const r="application/x-www-form-urlencoded"===i.mime?ci:"multipart/form-data"!==i.mime||e.blockMultipart?null:Kn;if(!r)throw new oe(415);return new r(e,i.params)})(t.headers,n);pn(t);const r=new G,o=(n,o)=>{if(r.fail(new oe(n,o)),i.removeAllListeners(),t.unpipe(i),t.resume(),e>=0){const n=setTimeout(()=>t.socket.destroy(),e);t.once("end",()=>clearTimeout(n))}};i.on("field",(t,e,{nameTruncated:n,valueTruncated:i,encoding:s,mimeType:c})=>t?n?o(400,{body:`field name ${JSON.stringify(t)}... too long`}):i?o(400,{body:`value for ${JSON.stringify(t)} too long`}):void r.push({name:t,encoding:s,mimeType:c,type:"string",value:e}):o(400,{body:"missing field name"})),i.on("file",(t,e,{nameTruncated:n,filename:i,encoding:s,mimeType:c})=>t?n?o(400,{body:`field name ${JSON.stringify(t)}... too long`}):void(i?(e.once("limit",()=>o(400,{body:`uploaded file for ${JSON.stringify(t)}: ${JSON.stringify(i)} too large`})),r.push({name:t,encoding:s,mimeType:c,type:"file",value:e,filename:i})):e.resume()):o(400,{body:"missing field name"})),t.once("error",e=>{t.readableAborted?r.fail(St):o(500,{body:"request error",headers:{connection:"close"},cause:e})}),i.once("error",t=>o(400,{body:"error parsing form data",cause:t})),i.once("partsLimit",()=>o(400,{body:"too many parts"})),i.once("filesLimit",()=>o(400,{body:"too many files"})),i.once("fieldsLimit",()=>o(400,{body:"too many fields"}));const s=()=>r.close("complete");return i.once("close",s),_t(t,s),t.pipe(i),r}async function yi(t,e={}){const n=new FormData,i=new Map;for await(const r of mi(t,e))if("file"===r.type){const o=r.value;let s=await(e.preCheckFile?.({fieldName:r.name,filename:r.filename,encoding:r.encoding,mimeType:r.mimeType,maxBytes:e.limits?.fileSize}));const c=t=>{if("function"==typeof s){const e=s;return s=void 0,e({actualBytes:t})}};_t(t,()=>c(0));const a=await wn(t),f=await a.save(o,{mode:384});await c(f.size);const h=new File([await u(f.path)],r.filename,{type:r.mimeType});i.set(h,f.path),n.append(r.name,h)}else{let t=r.value;e.trimAllValues&&(t=t.trim()),n.append(r.name,t)}return Object.assign(n,{getTempFilePath(t){const e=i.get(t);if(!e)throw new RangeError("unknown file");return e},getBoolean(t){const e=n.get(t);return null===e?null:"true"===e||"on"===e},getString(t){const e=n.get(t);return"string"==typeof e?e:null},getAllStrings:t=>n.getAll(t).filter(t=>"string"==typeof t),getFile(t){const e=n.get(t);return"string"==typeof e?null:e},getAllFiles:t=>n.getAll(t).filter(t=>"string"!=typeof t)})}const gi="win32"===/*@__PURE__*/P();function bi(t,{rejectPotentiallyUnsafe:e=!0}={}){let n=[];const i=st(t);if(i){if("/"===i.F)return[];n=i.F.split("/")}else{const e=Y(t).pathname;if("/"===e)return[];n=e.split("/").map(decodeURIComponent)}if(""!==n[0])throw new oe(400,{body:"invalid path"});if(n.shift(),e){const t=gi?Ei:vi;if(n.some(e=>t.test(e)||e.includes(v)))throw new oe(400,{body:"invalid path"});if(n.slice(0,n.length-1).includes(""))throw new oe(400,{body:"invalid path"})}return n}const vi=/[\x00-\x1F\x7F/]|^(\.\.?|~)$/,Ei=/[\x00-\x1F"*/:<>?\\|\x7F]|^[\s.]*$|^(CON|PRN|AUX|NUL|(COM|LPT)[\d\xB9\xB2\xB3])(\.|$)/i,_i=t=>new Promise(e=>{const n=()=>{t.cork(),e()};t instanceof s?t.write(X,n):t.once("drain",n),t.uncork()});async function Ti(t,e,{delimiter:n=",",newline:i="\n",quote:r='"',encoding:o="utf-8",headerRow:c,end:a=!0}={}){"string"==typeof n&&(n=Buffer.from(n,o)),"string"==typeof i&&(i=Buffer.from(i,o));const f="string"==typeof r?Buffer.from(r,o):r,u=r+r,h=e=>{if(!e)return!0;const n=e.includes(r);return!n&&xi.test(e)?t.write(e,o):(t.write(f),n?t.write(e.replaceAll(r,u),o):t.write(e,o),t.write(f))};t instanceof s&&!t.headersSent&&!t.hasHeader("content-type")&&t.setHeader("content-type","text/csv; charset="+o+(c?"; header=present":!1===c?"; header=absent":"")),t.cork();try{t.write(X);for await(const r of e){if(t.writableAborted)break;let e=0;if(Symbol.iterator in r)for(const i of r)e&&t.write(n),h(i)||await _i(t),++e;else for await(const i of r)e&&t.write(n),h(i)||await _i(t),++e;t.write(i)||await _i(t)}}finally{t.uncork()}a&&t.end()}const xi=/^[^"':;,\\\r\n\t ]*$/i;function Si(t){if(!t||"object"!=typeof t)return!1;const e=t;return"number"==typeof e.fd&&"function"==typeof e.stat&&"function"==typeof e.createReadStream}class $i{constructor(t){(t=>"He"in t&&"function"==typeof t.pipe)(t)&&(t=D.toWeb(t)),this.lt=t.getReader(),this.qe=null,this.Je=0,this.m=0}getRange(t,e){if(e<t)throw new RangeError("invalid range");if(t<this.Je)throw new RangeError("non-sequential range");if(this.m)throw new TypeError("previous range still active");let n=e-t+1,i=t-this.Je;this.Je=e+1,this.m=1;const r=this,o=(t,e)=>{const r=t.byteLength;r<=i?i-=r:r>i+n?(this.qe=t.subarray(i+n),e.enqueue(t.subarray(i,i+n)),n=0):i>0?(e.enqueue(t.subarray(i)),n-=r-i,i=0):(e.enqueue(t),n-=r)};return new B({start(t){if(r.qe){const e=r.qe;r.qe=null,o(e,t)}},async pull(t){if(n<=0)return r.m=0,void t.close();const e=await r.lt.read();e.done?t.error(new RangeError("range exceeds content")):"string"==typeof e.value?o(Buffer.from(e.value,"utf-8"),t):e.value instanceof Uint8Array?o(e.value,t):t.error(new TypeError("invalid stream type: must contain bytes or UTF-8 text"))}})}async close(){await this.lt.cancel(),this.lt.releaseLock()}}function ki(t,{forceSequential:e=!1,mergeOverlapDistance:n=100}={}){const i=[];if(n>=0)for(const e of t.ranges){let t=null,r=0;for(let o=0;o<i.length;++o){const s=i[o];e.end>=s.start-n-1&&s.end>=e.start-n-1?t?(++r,t.start=Math.min(t.start,s.start),t.end=Math.max(t.end,s.end)):(t=s,t.start=Math.min(t.start,e.start),t.end=Math.max(t.end,e.end)):r>0&&(i[o-r]=s)}t?i.length-=r:i.push({...e})}else i.push(...t.ranges);if(e)for(let t=0;t<i.length-1;++t)if(i[t].start>i[t+1].start){i.sort((t,e)=>t.start-e.start);break}return{ranges:i,totalSize:t.totalSize}}async function Ni(t,e,n,i){if("string"==typeof n||Si(n)||(i=ki(i,{mergeOverlapDistance:0,forceSequential:!0})),1===i.ranges.length){const r=i.ranges[0];if(e.setHeader("content-length",r.end-r.start+1),e.setHeader("content-range",`bytes ${r.start}-${r.end}/${i.totalSize??"*"}`),e.writeHead(206),"HEAD"===t.method)return void e.end();const o=await Oi(n);return await d(o.Le(r.start,r.end),e),void(o.ze&&await o.ze())}const r=e.getHeader("content-type"),o=l()+l()+"ABCDEFGHIJKLMNOPQRSTUVWXYZ";e.setHeader("content-type",`multipart/byteranges; boundary=${o}`);const s=i.ranges.map(t=>({o:[`--${o}`,...ht({"content-type":r,"content-range":`bytes ${t.start}-${t.end}/${i.totalSize??"*"}`}),"",""].join("\r\n"),We:t})),c=`--${o}--`;let a=c.length;for(const{o:t,We:e}of s)a+=t.length+e.end-e.start+1+2;if(e.setHeader("content-length",a),"HEAD"===t.method)return void e.end();let f="";const u=await Oi(n);try{for(const{o:t,We:n}of s)e.write(f+t,"ascii"),await d(u.Le(n.start,n.end),e,{end:!1}),f="\r\n";e.end(f+c)}finally{u.ze&&await u.ze()}}async function Oi(t){if("string"==typeof t){const e=await k(t,"r");return{Le:(t,n)=>e.createReadStream({start:t,end:n,autoClose:!1}),ze:()=>e.close()}}if(Si(t))return{Le:(e,n)=>t.createReadStream({start:e,end:n,autoClose:!1})};{const e=new $i(t);return{Le:(t,n)=>e.getRange(t,n),ze:()=>e.close()}}}async function Ai(t,e,n,i,r){if(i||("string"==typeof n?i=await x(n):Si(n)&&(i=await n.stat())),i){if("GET"===t.method||"HEAD"===t.method){if(!Cn(t,e,i))return void e.writeHead(304).end();e.setHeader("accept-ranges","bytes");const o=_e(t,i.size,r);if(o&&Un(t,e,i))return Ni(t,e,n,ki(o,r))}e.setHeader("content-length",i.size)}if(e.writeHead(e.statusCode,e.statusMessage),"HEAD"!==t.method)return"string"==typeof n?n=c(n):Si(n)&&(n=n.createReadStream({start:0,autoClose:!1})),d(n,e);e.end()}function Pi(t,e,{replacer:n,space:i,undefinedAsNull:r=!1,encoding:o="utf-8",end:c=!0}={}){const a=JSON.stringify(e,n,i)??(r?"null":void 0);t instanceof s&&!t.headersSent&&(t.hasHeader("content-type")||t.setHeader("content-type","application/json"),c&&t.setHeader("content-length",Buffer.byteLength(a,o))),c?t.end(a,o):a&&t.write(a,o)}async function Ri(t,e,{replacer:n=null,space:i="",undefinedAsNull:r=!1,encoding:o="utf-8",end:c=!0}={}){if(Array.isArray(n)){const t=new Set(n.map(t=>String(t)));n=function(e,n){return null===this||Array.isArray(this)||t.has(e)?n:void 0}}"number"==typeof i&&(i=" ".substring(0,i));const a={Ge:e=>t.write(e,o),Ve:()=>_i(t),Ze:n,Xe:i};if(t instanceof s&&!t.headersSent&&!t.hasHeader("content-type")&&t.setHeader("content-type","application/json"),e=Ci(null,"",e,a),Ui(e))r&&a.Ge("null");else{t.cork(),t.write(X);try{await Fi(a,e,i?"\n":"")}finally{t.uncork()}}c&&t.end()}async function Fi(t,e,n){const i=(i,r,o)=>{t.Ge(i);const s=n+t.Xe,c=t.Xe?": ":":";let a=!0;return{i:async(n,i)=>{const r=Ci(e,n,i,t);o&&Ui(r)||(a?a=!1:t.Ge(","),t.Ge(s),o&&(t.Ge(JSON.stringify(n))||await t.Ve(),t.Ge(c)),await Fi(t,r,s))},ze:()=>{a||t.Ge(n),t.Ge(r)}}};if(null===e||"object"!=typeof e||e instanceof String||e instanceof Number||e instanceof Boolean||e instanceof Function||e instanceof Symbol||e instanceof BigInt||Mi(e))t.Ge(JSON.stringify(e)??"null")||await t.Ve();else if(e instanceof D){t.Ge('"');for await(const n of e){if("string"!=typeof n)throw new TypeError("Readables must have an encoding");const e=JSON.stringify(n);t.Ge(e.substring(1,e.length-1))||await t.Ve()}t.Ge('"')}else if(e instanceof Map){const t=i("{","}",!0);for(const[n,i]of e)await t.i(n,i);t.ze()}else if(Bi(e)){let t=0;const n=i("[","]",!1);for(const i of e)await n.i(String(t++),i);n.ze()}else if(Di(e)){let t=0;const n=i("[","]",!1);for await(const i of e)await n.i(String(t++),i);n.ze()}else{const t=i("{","}",!0);for(const[n,i]of Object.entries(e))await t.i(n,i);t.ze()}}function Ci(t,e,n,i){return i.Ze&&(n=i.Ze.call(t,e,n)),n&&"object"==typeof n&&"function"==typeof n.toJSON&&(n=n.toJSON(e)),n}const Ui=t=>void 0===t||"function"==typeof t||"symbol"==typeof t||t instanceof Function||t instanceof Symbol,Mi=t=>JSON.isRawJSON?.(t)??!1,Bi=t=>Symbol.iterator in t,Di=t=>Symbol.asyncIterator in t;class Ii{constructor(t,e,{keepaliveInterval:n=15e3,softCloseReconnectDelay:i=500,softCloseReconnectStagger:r=2e3}={}){this.Ye=e,this.Ke=n??0,this.C=new AbortController,e.setHeader("content-type","text/event-stream"),e.setHeader("x-accel-buffering","no"),e.setHeader("cache-control","no-store"),e.writeHead(200),e.flushHeaders(),this.ping=this.ping.bind(this),this.Qe(),t.once("close",()=>this.close()),wt(t,()=>this.close(i,r))}get signal(){return this.C.signal}get open(){return!this.C.signal.aborted}Qe(){this.Ke&&(this.tn=setTimeout(this.ping,this.Ke))}ping(){!this.C.signal.aborted&&this.Ye.writable&&(clearTimeout(this.tn),this.Ye.write(":\n\n",()=>this.Qe()))}send({event:t,id:e,data:n,reconnectDelay:i=-1}){return this.sendFields([["event",t],["id",e],["data",n],["retry",i>=0?String(0|i):void 0]])}async sendFields(t){let e;this.C.signal.throwIfAborted(),this.Ye.cork();try{let n=!1;for(const[e,i]of t){if(void 0===i)continue;const t=i.split(/(?<=\n)|(?<=\r)(?!\n)/g);for(let n of t)this.Ye.write(e)," "===n[0]?this.Ye.write(": "):this.Ye.write(":"),this.Ye.write(n);/[\r\n]$/.test(i)?(this.Ye.write(e),this.Ye.write(":\n")):this.Ye.write("\n"),n=!0}if(!n)return;clearTimeout(this.tn),this.Ye.write("\n",()=>e())}finally{this.Ye.uncork()}await new Promise(t=>{e=t}),this.Qe()}async close(t=0,e=0){if(this.C.signal.aborted){if(this.Ye.closed)return;return new Promise(t=>this.Ye.once("close",t))}this.Ke=0,clearTimeout(this.tn),this.C.abort(new Error("ServerSentEvents closed")),await new Promise(n=>{if(this.Ye.writable&&(t>0||e>0)){const i=t+Math.random()*e;this.Ye.end(`retry:${0|i}\n\n`,n)}else this.Ye.end(n)})}}const ji=async(t,{mode:e="dynamic",fallback:n,verbose:i,callback:r=Hi,...o}={})=>{const s=await hn.build(E(process.cwd(),t),o);let c=null;const a=n?.statusCode??200;if(n){let t=n.filePath;t.startsWith("/")&&(t=t.substring(1)),c=s.toNormalisedPath(t.split("/"))}const f="dynamic"===e?{}:{rejectPotentiallyUnsafe:!1},u="dynamic"===e?s:await s.precompute();return{handleRequest:async(t,e)=>{if("GET"!==t.method&&"HEAD"!==t.method)return $t;let n=!1;const o=bi(t,f),s={mime:Se(t.headers.accept),language:Se(t.headers["accept-language"]),encoding:Se(t.headers["accept-encoding"])},h=[];let l=await u.find(o,s,i?h:void 0);if(!l){if(!c)return i&&an(t,new Error(h.join(", ")),"serving static content"),$t;if(n=!0,l=await u.find(c,s,h),!l)throw new oe(500,{message:`failed to find fallback file: ${h.join(", ")}`})}try{n&&(e.statusCode=a),e.setHeader("content-type",l.mime??nn(m(l.canonicalPath))),l.encoding&&"identity"!==l.encoding&&e.setHeader("content-encoding",l.encoding);const i=u.vary;if(i){const t=e.getHeader("vary")??"";e.setHeader("vary",(t?t+", ":"")+i)}await r(t,e,l,n),await Ai(t,e,l.handle,l.stats)}finally{l.handle.close().catch(()=>{})}}}};function Hi(t,e,n){e.setHeader("etag",He(e.getHeader("content-encoding"),n.stats)),e.setHeader("last-modified",n.stats.mtime.toUTCString())}class qi extends Error{constructor(t,{message:e,statusMessage:n,...i}={}){super(e,i),this.statusCode=0|t,this.statusMessage=n??"",this.name=`WebSocketError(${this.statusCode} ${this.statusMessage})`}static NORMAL_CLOSURE=1e3;static GOING_AWAY=1001;static UNSUPPORTED_DATA=1003;static POLICY_VIOLATION=1008;static MESSAGE_TOO_BIG=1009;static INTERNAL_SERVER_ERROR=1011;static SERVICE_RESTART=1012;static TRY_AGAIN_LATER=1013;static BAD_GATEWAY=1014}function Ji(t,{softCloseStatusCode:e=qi.GOING_AWAY,...n}={}){const i=(i,r,o)=>new Promise((s,c)=>{const a=new t({...n,noServer:!0,clientTracking:!1});a.once("wsClientError",c),a.handleUpgrade(i,r,o,t=>{a.off("wsClientError",c),o=X,s({return:t,onError:e=>{const n=V(e,qi);if(n)return void t.close(n.statusCode,n.statusMessage);const i=V(e,oe)??new oe(500),r=i.statusCode>=500?qi.INTERNAL_SERVER_ERROR:4e3+i.statusCode;t.close(r,i.statusMessage)},softCloseHandler:n=>t.close(e,n)})})});return t=>Ot(t,i)}class Li{constructor(t,e){this.data=t,this.isBinary=e}get text(){if(this.isBinary)throw new qi(qi.UNSUPPORTED_DATA,{statusMessage:"expected text"});return this.data.toString("utf-8")}get binary(){if(!this.isBinary)throw new qi(qi.UNSUPPORTED_DATA,{statusMessage:"expected binary"});return this.data}}class zi{constructor(t,{limit:e=-1,signal:n}={}){this.en=new G;const i=e=>{t.off("message",o),t.off("close",r),this.en.close(new Error(e))},r=()=>i("connection closed"),o=(t,n)=>{void 0!==n?this.en.push(new Li(t,n)):"string"==typeof t?this.en.push(new Li(Buffer.from(t,"utf-8"),!1)):this.en.push(new Li(t,!0)),e>0&&0===--e&&this.detach()};this.detach=()=>{},n?.aborted?this.en.close(n.reason):2===t.readyState||3===t.readyState?this.en.close(new Error("connection closed")):(t.on("message",o),t.on("close",r),n?.addEventListener("abort",()=>i("signal aborted")),this.detach=()=>i("WebSocket listener detached"))}next(t){return this.en.shift(t)}[Symbol.asyncIterator](){return this.en[Symbol.asyncIterator]()}}function Wi(t,{timeout:e,signal:n}={}){const i=new zi(t,{limit:1,signal:n});return i.next(e).finally(()=>i.detach())}function Gi(t){const e=at(t);return"GET"===t.method&&(e.D?.has("websocket")??!1)}const Vi=t=>t.headers.origin??lt(t.headers["sec-websocket-origin"]),Zi=(t,e=5e3)=>async n=>{if(!Gi(n))return;const i=await t(n);let r;try{r=await Wi(i,{timeout:e})}catch(t){if((i.readyState??0)>=2)throw St;throw new qi(qi.POLICY_VIOLATION,{statusMessage:"timeout waiting for authentication token",cause:t})}if(r.isBinary)throw new qi(qi.UNSUPPORTED_DATA,{statusMessage:"authentication token must be sent as text"});return r.data.toString("utf-8")};export{G as BlockingQueue,$t as CONTINUE,hn as FileFinder,oe as HTTPError,kt as NEXT_ROUTE,Nt as NEXT_ROUTER,Oe as Property,W as Queue,Kt as Router,St as STOP,Ii as ServerSentEvents,de as WebListener,qi as WebSocketError,Li as WebSocketMessage,zi as WebSocketMessages,pn as acceptBody,Ot as acceptUpgrade,_t as addTeardown,Lt as anyHandler,Cn as checkIfModified,Un as checkIfRange,Ce as clearProperty,Mn as compareETag,rn as compressFileOffline,on as compressFilesInDir,Gt as conditionalErrorHandler,tn as decompressMime,Et as defer,an as emitError,zt as errorHandler,ji as fileServer,V as findCause,qe as generateStrongETag,He as generateWeakETag,Tt as getAbortSignal,jt as getAbsolutePath,Z as getAddressURL,be as getAuthorization,Hn as getBodyJson,Dn as getBodyStream,jn as getBodyText,In as getBodyTextStream,ve as getCharset,yi as getFormData,mi as getFormFields,Ee as getIfRange,nn as getMime,It as getPathParameter,Dt as getPathParameters,Fe as getProperty,ye as getQuery,_e as getRange,bi as getRemainingPathComponents,pe as getSearch,me as getSearchParams,Pn as getTextDecoder,Rn as getTextDecoderStream,Vi as getWebSocketOrigin,Be as hasAuthScope,mt as isSoftClosed,Gi as isWebSocketRequest,fn as jsonErrorHandler,Ji as makeAcceptWebSocket,q as makeAddressTester,gn as makeGetClient,Ae as makeMemo,Ge as makeNegotiator,wn as makeTempFileStorage,Zi as makeWebSocketFallbackTokenFetcher,We as negotiateEncoding,Wi as nextWebSocketMessage,H as parseAddress,mn as proxy,ke as readHTTPDateSeconds,xe as readHTTPInteger,$e as readHTTPKeyValues,Se as readHTTPQualityValues,Te as readHTTPUnquotedCommaSeparated,Qe as readMimeTypes,On as registerCharset,en as registerMime,An as registerUTF32,En as removeForwarded,_n as replaceForwarded,qt as requestHandler,De as requireAuthScope,Me as requireBearerAuth,Ke as resetMime,Ht as restoreAbsolutePath,Tn as sanitiseAndAppendForwarded,Ti as sendCSVStream,Ai as sendFile,Pi as sendJSON,Ri as sendJSONStream,Ni as sendRanges,Hi as setDefaultCacheHeaders,Re as setProperty,wt as setSoftCloseHandler,xn as simpleAppendForwarded,ki as simplifyRange,ae as toListeners,Wt as typedErrorHandler,Jt as upgradeHandler};
|
|
1
|
+
import{isIPv4 as t,isIPv6 as e}from"node:net";import{STATUS_CODES as n,createServer as i,Agent as r,request as o,ServerResponse as s}from"node:http";import{createReadStream as a,constants as c,createWriteStream as f,openAsBlob as u}from"node:fs";import{createHash as h,randomUUID as l}from"node:crypto";import{pipeline as d}from"node:stream/promises";import w from"node:zlib";import{promisify as p}from"node:util";import{extname as m,join as y,dirname as g,basename as b,sep as v,resolve as E}from"node:path";import{readFile as T,writeFile as _,rm as x,stat as S,readdir as $,realpath as k,open as N,mkdtemp as O}from"node:fs/promises";import{tmpdir as A,platform as R}from"node:os";import{Agent as P,request as C}from"node:https";import{TransformStream as F,TextDecoderStream as U,DecompressionStream as M,ReadableStream as B}from"node:stream/web";import{Readable as D,Duplex as I,Writable as j}from"node:stream";function q(n){if(!n||"unknown"===n)return;const i=/^((?:\d{1,3}\.){3}\d{1,3})(?::(\d+))?$/.exec(n);if(i?.[1]&&t(i[1]))return{family:"IPv4",address:i[1],port:i[2]?Number.parseInt(i[2]):void 0};const r=/^\[([\da-fA-F:]+)\](?::(\d+))?$|^([\da-fA-F:]+)$/.exec(n);if(r?.[1]&&e(r[1]))return{family:"IPv6",address:r[1].toLowerCase(),port:r[2]?Number.parseInt(r[2]):void 0};if(r?.[3]&&e(r[3]))return{family:"IPv6",address:r[3].toLowerCase(),port:void 0};const o=/^(.*?):(\d+)$/i.exec(n);return o?.[2]?{family:"alias",address:o[1],port:Number.parseInt(o[2])}:{family:"alias",address:n,port:void 0}}function H(t){const e=new Set,n=[],i=[];for(const r of t){const t=/^((?:\d{1,3}\.){3}\d{1,3})(?:\/(\d+))?$/.exec(r);if(t?.[1]){const e=t[2]?Number.parseInt(t[2]):32,i=e<32?4294967295>>>e:0;n.push([J(t[1])|i,i]);continue}const o=/^\[?([\da-fA-F:]+)\]?(?:\/(\d+))?$/.exec(r);if(o?.[1]){const t=z(o[1]),e=o[2]?L>>BigInt(Number.parseInt(o[2])):0n;i.push([t|e,e]);continue}e.add(r)}return t=>{switch(t?.family){case"alias":return e.has(t.address);case"IPv4":const r=J(t.address);return n.some(([t,e])=>(r|e)===t);case"IPv6":const o=z(t.address);return i.some(([t,e])=>(o|e)===t);default:return!1}}}const L=/*@__PURE__*/BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");function J(t){const e=t.split(".").map(Number);return(e[0]<<24|e[1]<<16|e[2]<<8|e[3])>>>0}function z(t){const e=t.split(":").map(t=>t?Number.parseInt(t,16):-1);let n=0n;for(const t of e)t<0?n<<=16n*BigInt(9-e.length):n=n<<16n|BigInt(t);return n}function W(t,e,n){if(t>=2147483648||Number.isNaN(t)||!n&&t<0)throw new RangeError(`${e} must fit in a 31 bit integer - got ${t}`)}class G{constructor(t){const e={t:null,i:null};this.o=e,this.u=e,void 0!==t&&this.push(t)}isEmpty(){return!this.o.i}clear(){this.o.i=null,this.o.t=null,this.u=this.o}push(t){const e={t,i:null};this.u.i=e,this.u=e}shift(){if(!this.o.i)return null;this.o=this.o.i;const t=this.o.t;return this.o.t=null,t}remove(t){for(let e=this.o;e.i;e=e.i)if(e.i.t===t){e.i=e.i.i;break}}[Symbol.iterator](){return{next:()=>{if(!this.o.i)return{value:null,done:!0};this.o=this.o.i;const t=this.o.t;return this.o.t=null,{value:t,done:!1}}}}}class V{constructor(){this.h=new G,this.l=new G,this.m=0}push(t){if(this.m)return;const e=this.l.shift();e?(e.v&&clearTimeout(e.v),e.T(t)):this.h.push(t)}shift(t){return W(t??0,"timeout"),this.h.isEmpty()?this.m?Promise.reject(this._):new Promise((e,n)=>{const i={T:e,S:n,v:null};this.l.push(i),void 0!==t&&(i.v=setTimeout(()=>{this.l.remove(i),n(new Error(`timeout after ${t}ms`))},t))}):Promise.resolve(this.h.shift())}$(t){this._=t;for(const e of this.l)e.S(t),e.v&&clearTimeout(e.v)}close(t){this.m||(this.m=1,this.$(t))}fail(t){this.m||(this.m=2,this.$(t))}[Symbol.asyncIterator](){return{next:()=>this.shift().then(t=>({value:t,done:!1}),t=>{if(2===this.m)throw t;return{value:null,done:!0}})}}}function Z(t,e){if(t instanceof e)return t;if(t&&"object"==typeof t){if("cause"in t)return Z(t.cause,e);if("error"in t)return Z(t.error,e)}}function X(t,e="http"){if(!t)throw new TypeError("no address");if("string"==typeof t)return t;const n=void 0===t.port?"":`:${t.port}`;if("IPv4"===t.family||"alias"===t.family)return`${e}://${t.address}${n}`;if("IPv6"===t.family)return`${e}://[${t.address}]${n}`;throw new TypeError(`unknown address family: ${t.family}`)}const Y=/*@__PURE__*/Buffer.alloc(0),K=t=>new URL("http://localhost"+(t.url??"/"));class Q extends Error{constructor(t,e,n){super(n??""),this.error=t,this.suppressed=e}}const tt=globalThis.SuppressedError??Q;class et{constructor(){this.k=!1}N(t){this.k?t!==this.O&&(this.O=new tt(t,this.O)):(this.O=t,this.k=!0)}A(){this.k=!1,this.O=void 0}}const nt=new WeakMap;function it(t,e,n){const i=nt.get(t);if(i)return i;const r=K(t),o={R:t,P:r,C:decodeURIComponent(r.pathname),F:new AbortController,U:e,M:[],B:[],D:n?st(t):null};return nt.set(t,o),o}function rt(t,e,n){e||(t.D=null),t.I=n;const i=async()=>{t.F.abort(n.j.writableEnded?"complete":"client abort");const e=new et;await ot(t.M,e,t),await ot(t.B,e,t,()=>{t.H=async e=>{try{await e()}catch(e){t.U(e,"tearing down",t.R)}}}),e.k&&t.U(e.O,"tearing down",t.R)};return n.j.closed?i():n.j.once("close",i),t}async function ot(t,e,n,i){for(;n.L;)await n.L;const r=(async()=>{for(;;){const n=t.pop();if(!n)return void i?.();try{await n()}catch(t){e.N(t)}}})().then(()=>{n.L===r&&(n.L=void 0)});n.L=r,await r}function st(t){return new Set(t.headers.upgrade?.split(",").map(t=>t.trim().toLowerCase())??[])}const at=t=>nt.get(t),ct=t=>nt.delete(t);function ft(t){const e=at(t);if(!e)throw new RangeError("unknown request");return e}function ut(t,e,n=ut){throw t.code=e,Error.captureStackTrace(t,n),t}class ht{constructor(t){this.J=t,this.W=Object.create(null),this.G=!1}get headersSent(){return this.G}writeHead(t,e=n[t]??"-"){return this.G&&ut(new Error("Cannot write headers after they are sent to the client"),"ERR_HTTP_HEADERS_SENT"),this.J.write([`HTTP/1.1 ${t} ${wt(e)}`,...lt(this.W),"",""].join("\r\n"),"ascii"),this.G=!0,this}write(t,e="utf-8",n){return this.J.write(t,e,n)}end(t,e="utf-8",n){return this.J.end(t,e,n),this}setHeader(t,e){const n=t.toLowerCase();return this.W[n]="string"==typeof e||"number"==typeof e?e:[...e],this}setHeaders(t){for(const[e,n]of t)this.setHeader(e,n);return this}}function lt(t){const e=[];for(const[n,i]of Object.entries(t)){const t=dt(i);t&&e.push(`${wt(n)}: ${wt(t)}`)}return e}const dt=t=>"string"==typeof t?t:"number"==typeof t?String(t):t?t.join(", "):"",wt=t=>t.replaceAll(/[^ \t!-~]/g,"");function pt(t,e){const n=at(t);n&&mt(n,e)}function mt(t,e){t.V=e;const n=t.Z;n&&queueMicrotask(()=>Et(e,n,t))}const yt=t=>Boolean(at(t)?.Z);function gt(t,e,n){if(!t.Z){if(t.I&&!t.D){const e=t.I.j;e.headersSent||e.hasHeader("connection")||e.setHeader("connection","close")}t.I?.j.once("close",()=>t.R.socket.destroy()),t.Z={X:e,U:n},Et(t.V,t.Z,t),vt(t)}}function bt(t){if(t.I){if(t.D){if(!t.Y&&t.I.j.writable){const e=new ht(t.I.j);e.setHeader("connection","close"),e.writeHead(503)}}else{const e=t.I.j;e.headersSent||(e.hasHeader("connection")||e.setHeader("connection","close"),e.writeHead(503))}t.I.j.end(()=>t.R.socket.destroy())}else t.R.socket.destroy()}function vt(t){if(clearTimeout(t.K),!t.tt||t.H)return;const e=Date.now();if(e>=t.tt)return void bt(t);let n=t.tt;t.et&&!t.Z&&(e<t.et.nt?n=t.et.nt:(t.Z=t.et,Et(t.V,t.Z,t))),void 0===t.K&&t.B.push(()=>clearTimeout(t.K)),t.K=setTimeout(()=>vt(t),Math.min(n-e,6048e5))}async function Et(t,e,n){try{await(t?.(e.X))}catch(t){e.U(t,"soft closing",n.R),bt(n)}}const Tt=(t,e)=>{const n=ft(t);n.H?n.H(e):n.M.push(e)},_t=(t,e)=>{const n=ft(t);n.H?n.H(e):n.B.push(e)},xt=t=>ft(t).F.signal;class St extends Error{}const $t=new St("STOP"),kt=new St("CONTINUE"),Nt=new St("NEXT_ROUTE"),Ot=new St("NEXT_ROUTER");async function At(t,e){const n=ft(t);if(!n.I)throw new TypeError("cannot call acceptUpgrade from shouldUpgrade");if(!n.D)throw new TypeError("not an upgrade request");if(3===n.Y)throw new TypeError("upgrade already delegated");if(2===n.Y)return n.it;const i=n.I.j;if(!i.readable||!i.writable)throw $t;n.Y=1;const r=await e(t,i,n.I.o);return n.I.o=Y,n.rt=r.onError,r.softCloseHandler&&mt(n,r.softCloseHandler),n.Y=2,n.it=r.return,r.return}function Rt(t){const e=ft(t);if(!e.I)throw new TypeError("cannot call delegateUpgrade from shouldUpgrade");if(!e.D)throw new TypeError("not an upgrade request");if(e.Y)throw new TypeError("upgrade already handled");e.Y=3}const Pt=RegExp.escape??(t=>t.replaceAll(/[^a-zA-Z0-9_ ]/g,t=>"\\u"+t.charCodeAt(0).toString(16).padStart(4,"0"))),Ct=t=>t,Ft=t=>void 0===t?void 0:""===t?[]:t.split("/"),Ut=t=>void 0===t?void 0:""===t?[]:t.split("/").filter(t=>t),Mt=/*@__PURE__*/(t=>e=>{const n=[];let i=0;for(;i<e.length;++i){const r=t.get(e[i]);if(!r)break;n.push([r,!0])}return[Object.fromEntries(n),e.substring(i)]})(
|
|
2
|
+
/*@__PURE__*/new Map([["i","ot"],["!","st"]])),Bt=(t,e)=>{Object.prototype.hasOwnProperty.call(t,e)&&delete t[e]},Dt=Object.freeze({});function It(t,e,n){const i=t.R.url,r=t.C,o=t.ct??Dt;return t.R.url=encodeURIComponent(e).replaceAll(/%2F/g,"/")+t.P.search,t.C=e,n.length>0&&(t.ct=Object.freeze(Object.fromEntries([...Object.entries(o),...n]))),()=>{t.R.url=i,t.C=r,t.ct=o}}function jt(t){return at(t)?.ct??Dt}function qt(t,e){return n=jt(t),i=e,Object.prototype.hasOwnProperty.call(n,i)?n[i]:void 0;var n,i}function Ht(t){const e=at(t);return e?e.P.pathname+e.P.search:t.url??"/"}function Lt(t){const e=at(t);e&&(t.url=e.P.pathname+e.P.search)}const Jt=t=>"function"==typeof t?{handleRequest:t}:t,zt=(t,e)=>"function"==typeof t?{handleUpgrade:t,shouldUpgrade:e}:{shouldUpgrade:e,...t},Wt=(t,e=Kt)=>({handleRequest:t,handleUpgrade:t,shouldUpgrade:e}),Gt=t=>"function"==typeof t?{handleError:t}:t,Vt=(t,e)=>Zt(e=>e instanceof t,e),Zt=(t,e)=>({handleError:(n,i,r)=>{if(r.response&&t(n))return e(n,i,r.response);throw n},shouldHandleError:(e,n,i)=>Boolean(i.response)&&t(e)}),Xt=t=>"function"==typeof t?{handleRequest:t}:t,Yt=t=>"function"==typeof t?{handleUpgrade:t}:t,Kt=()=>!1,Qt=Symbol("http");class te{constructor(){this.ft=[],this.ut=[]}N(t,e,n,i,r){const o=n?((t,e)=>{const n=["^"],i=[],r=/[{}]|\/+|\\(.)|[:*]([a-zA-Z0-9_]*)/g,[{ot:o,st:s},a]=Mt(t);if("/"!==a[0])throw new TypeError("path must begin with '/' or flags");let c=0,f=0;for(const t of a.matchAll(r)){t.index>c&&n.push(Pt(a.substring(c,t.index)));const e=t[0];if("{"===e)n.push("(?:"),++f;else if("}"===e){if(0===f)throw new TypeError(`unbalanced optional braces in path at ${t.index}`);--f,n.push(")?")}else if("/"===e[0])n.push(e),s||n.push("+");else if("\\"===e[0])n.push(Pt(t[1]));else{const r=e[0],o=t[2];if(!o)throw new TypeError(`unnamed parameter or unescaped '${r}' at ${t.index}`);"*"===r?(n.push("(.*?)"),i.push({ht:o,lt:s?Ft:Ut})):(n.push("([^/]+?)"),i.push({ht:o,lt:Ct}))}c=t.index+e.length}if(c<a.length&&n.push(Pt(a.substring(c))),f>0)throw new TypeError("unbalanced optional braces in path");return e&&(n.push("(?:"),s?n.push("(?:(?<=/)|/)"):n.push("(?:/+|(?<=/))"),n.push("(?<rest>.*))?")),n.push("$"),{dt:new RegExp(n.join(""),o?"i":""),wt:i}})(n,i):{dt:null,wt:[]};if(r.some(t=>t instanceof Promise))throw new TypeError("expected handler, got Promise (did you forget to await?)");return this.ft.push({yt:t,gt:"string"==typeof e?e.toLowerCase():e,bt:o.dt,vt:o.wt,Et:r}),this}use(...t){return this.N(null,null,null,!0,t.map(Xt))}mount(t,...e){return this.N(null,null,t,!0,e.map(Xt))}within(t,e){const n=new te;return e(n),this.mount(t,n)}at(t,...e){return this.N(null,null,t,!1,e.map(Xt))}onRequest(t,e,...n){return this.N(ne(t),Qt,e,!1,n.map(Xt))}onUpgrade(t,e,n,...i){return this.N(ne(t),e,n,!1,i.map(Yt))}onError(...t){return this.N(null,null,null,!0,t.map(Gt))}onReturn(...t){return this.ut.push(...t),this}get=(t,...e)=>this.N(ee,Qt,t,!1,e.map(Xt));delete=(...t)=>this.onRequest("DELETE",...t);getOnly=(...t)=>this.onRequest("GET",...t);head=(...t)=>this.onRequest("HEAD",...t);options=(...t)=>this.onRequest("OPTIONS",...t);patch=(...t)=>this.onRequest("PATCH",...t);post=(...t)=>this.onRequest("POST",...t);put=(...t)=>this.onRequest("PUT",...t);ws=(...t)=>this.onUpgrade("GET","websocket",...t);async handleRequest(t){return this.Tt(t,new et)}async handleUpgrade(t){return this.Tt(t,new et)}async handleError(t,e){const n=new et;return n.N(t),this.Tt(e,n)}shouldUpgrade(t){return this._t(ft(t))}_t(t){for(const e of this.ft){const n=ie(t,e);if(!n)continue;let i=()=>{};if(!0!==n)try{i=It(t,n.xt,[])}catch{continue}try{for(const n of e.Et)if(se(n,t))return!0}finally{i()}}return!1}async Tt(t,e){const n=ft(t),i=await this.St(n,e);if(e.k)throw e.O;return i}async St(t,e){for(const n of this.ft){const i=ie(t,n);if(!i)continue;let r=()=>{};if(!0!==i)try{const e=i.$t();r=It(t,i.xt,e)}catch(t){e.N(t);continue}try{const i=await re(t,n.Et,this.ut,e);if(i===Ot)break;if(i===Nt)continue;return i}finally{r()}}return kt}}const ee=new Set(["HEAD","GET"]),ne=t=>t?"string"==typeof t?t:new Set(t):null;function ie(t,e){if("string"==typeof e.yt){if(e.yt!==t.R.method)return!1}else if(null!==e.yt&&!e.yt.has(t.R.method??""))return!1;if(e.gt===Qt){if(t.D)return!1}else if(null!==e.gt&&!t.D?.has(e.gt))return!1;if(null===e.bt)return!0;const n=e.bt.exec(t.C);return!!n&&{xt:"/"+(n.groups?.rest??""),$t:()=>e.vt.map((t,e)=>[t.ht,t.lt(n[e+1])])}}async function re(t,e,n,i){for(const r of e){let e=await oe(r,t,i);if(e!==kt){if(!t.D&&!(e instanceof St)&&n.length)try{const i="object"==typeof e?e:void 0,r=t.R,o=t.I.j;for(const t of n)await t(i,r,o)}catch(t){i.N(t);continue}return e}}return Nt}async function oe(t,e,n){if(t instanceof te)return t.St(e,n);let i=kt;try{if(n.k){if(t.handleError){const r=n.O,o=e.D?{socket:e.I.j,head:e.I.o,hasUpgraded:Boolean(e.Y)}:{response:e.I.j};t.shouldHandleError&&!t.shouldHandleError(r,e.R,o)||(n.A(),i=await t.handleError(r,e.R,o))}}else if(e.D){if(t.handleUpgrade){const n=e.I;i=await t.handleUpgrade(e.R,n.j,n.o)}}else t.handleRequest&&(i=await t.handleRequest(e.R,e.I.j))}catch(t){t instanceof St?i=t:n.N(t)}finally{e.M.length&&await((t,e)=>ot(t.M,e,t))(e,n)}return i===$t?void 0:i}function se(t,e){if(t instanceof te)return t._t(e);if(!t.shouldUpgrade)return Boolean(t.handleUpgrade);try{return t.shouldUpgrade(e.R)}catch(t){return e.U(t,"checking should upgrade",e.R),!1}}class ae extends Error{constructor(t,{message:e,statusMessage:i,headers:r,body:o,...s}={}){super(e??o,s),this.statusCode=0|t,this.statusMessage=i??n[this.statusCode]??"-",this.headers=(t=>{if(!t||t instanceof Headers||Array.isArray(t))return new Headers(t);const e=t instanceof Map?[...t.entries()]:Object.entries(t);return new Headers(e.map(([t,e])=>[t,dt(e)]).filter(([t,e])=>e))})(r),this.body=o??"",this.name=`HTTPError(${this.statusCode} ${this.statusMessage})`}}const ce=(t,e,n)=>{const i=fe(n);if(!i)return;const r=Z(t,ae)??new ae(500);i.setHeader("content-type","text/plain; charset=utf-8"),i.setHeaders(r.headers),i.setHeader("content-length",String(Buffer.byteLength(r.body,"utf-8"))),n.response||i.setHeader("connection","close"),i.writeHead(r.statusCode,r.statusMessage),i.end(r.body,"utf-8")};function fe(t){if(t.response){const e=t.response;return e.headersSent?void e.end():e}const e=t.socket;if(!t.hasUpgraded&&e.writable)return e.addListener("finish",()=>e.destroy()),new ht(e);e.destroy()}function ue(t,{onError:e=he,socketCloseTimeout:n=500}={}){W(n,"socketCloseTimeout");let i=0,r="",o=e;const s=[],a=new Set,c=()=>{const t=[...s];s.length=0;for(const e of t)e()},f=t=>{t&&(a.size?s.push(t):setImmediate(t))},u=t=>{a.add(t),t.B.push(()=>{a.delete(t),!a.size&&s.length&&setImmediate(c)})};return{request:async(n,s)=>{let a;try{a=it(n,e,!1)}catch(t){return e(t,"parsing request",n),void ce(new ae(400),0,{response:s})}if(rt(a,!1,{j:s}),u(a),1===i)gt(a,r,o);else if(2===i)return bt(a),void ct(n);const c=new et,f=await oe(t,a,c);c.k||f!==kt&&f!==Nt&&f!==Ot||c.N(new ae(404)),c.k&&(e(c.O,"handling request",n),ce(c.O,0,{response:s}),ct(n))},upgrade:async(s,a,c)=>{let f;a.once("finish",()=>{const t=setTimeout(()=>a.destroy(),n);a.once("close",()=>clearTimeout(t))});try{f=it(s,e,!0)}catch(t){return e(t,"parsing upgrade",s),void ce(new ae(400),0,{socket:a,hasUpgraded:!1})}if(rt(f,!0,{j:a,o:c}),c=Y,u(f),1===i)gt(f,r,o);else if(2===i)return bt(f),void ct(s);const h=new et,l=await oe(t,f,h);h.k||l!==kt&&l!==Nt&&l!==Ot||(console.warn(`Upgrade ${s.headers.upgrade} request for ${s.url} fell-through. This probably means you need to add shouldUpgrade to one of your upgrade handlers, or if this is intentional, explicitly reject the request (throw new HTTPError(404)) instead of using CONTINUE.`),h.N(new ae(404))),h.k&&(e(h.O,"handling upgrade",s),f.rt?f.rt(h.O):ce(h.O,0,{socket:a,head:f.I?.o??Y,hasUpgraded:Boolean(f.Y)}),ct(s))},shouldUpgrade:n=>{try{const i=it(n,e,!0);return se(t,i)}catch{return!1}},clientError:(t,n)=>{const i=n.kt,r=t.code;n.writable&&!i?.headersSent&&n.end(de.get(r)??we),n.destroy(t),"HPE_INVALID_EOF_STATE"===r||e(t,"initialising request",void 0)},softClose(t,e,n){if(i<1){i=1,r=t,o=e;for(const n of a)gt(n,t,e)}f(n)},hardClose(t){if(i<2){i=2;for(const t of a)bt(t)}f(t)},countConnections:()=>a.size}}const he=(t,e,n)=>{(Z(t,ae)?.statusCode??500)>=500&&console.error("%s",`unhandled error while ${e} ${n?.url??"(no request information)"}:`,t)},le=t=>Buffer.from(`HTTP/1.1 ${t} ${n[t]}\r\nConnection: close\r\n\r\n`),de=/*@__PURE__*/new Map([["HPE_HEADER_OVERFLOW",/*@__PURE__*/le(431)],["HPE_CHUNK_EXTENSIONS_OVERFLOW",/*@__PURE__*/le(413)],["ERR_HTTP_REQUEST_TIMEOUT",/*@__PURE__*/le(408)]]),we=/*@__PURE__*/le(400);class pe extends EventTarget{constructor(t){super(),this.Nt=t}attach(t,e={}){const n=(e,n,i)=>{const r={server:t,error:e,context:n,request:i};this.dispatchEvent(new CustomEvent("error",{detail:r,cancelable:!0}))&&he(e,n,i)},i=ue(this.Nt,{...e,onError:n});!1===e.autoContinue&&t.addListener("checkContinue",i.request),!1===e.rejectNonStandardExpect&&t.addListener("checkExpectation",i.request),t.addListener("request",i.request),t.addListener("upgrade",i.upgrade);const r=t.shouldUpgradeCallback??(()=>!1);!1!==e.overrideShouldUpgradeCallback&&(t.shouldUpgradeCallback=i.shouldUpgrade),t.addListener("clientError",i.clientError);let o=()=>{o=void 0,t.removeListener("checkContinue",i.request),t.removeListener("checkExpectation",i.request),t.removeListener("request",i.request),t.removeListener("upgrade",i.upgrade),t.shouldUpgradeCallback===i.shouldUpgrade&&(t.shouldUpgradeCallback=r),t.removeListener("clientError",i.clientError)};return(t="",e=-1,r=!1,s)=>{if(W(e,"existingConnectionTimeout",!0),r||o?.(),e>0){const r=setTimeout(()=>{o?.(),i.hardClose()},e);i.softClose(t,n,()=>{o?.(),clearTimeout(r),s?.()})}else 0===e?(o?.(),i.hardClose(s)):(o?.(),s&&setImmediate(s));return i}}createServer(t={}){t.shouldUpgradeCallback&&(t={overrideShouldUpgradeCallback:!1,...t});const e=i(t),n=this.attach(e,t),r=Object.assign(e,{closeWithTimeout:(t,i)=>new Promise(r=>n(t,i,!0,()=>{e.close(()=>r()),e.closeAllConnections()}))});return r}listen(t,e,n={}){const i=this.createServer(n);return n.socketTimeout&&i.setTimeout(n.socketTimeout),new Promise((r,o)=>{i.once("error",o),i.listen(t,e,n.backlog??511,()=>{i.off("error",o),r(i)})})}}const me=t=>at(t)?.P??K(t),ye=t=>me(t).search,ge=t=>new URLSearchParams(me(t).searchParams),be=(t,e)=>me(t).searchParams.get(e);function ve(t,e){const n=t.indexOf(e);return-1===n?[t]:[t.substring(0,n),t.substring(n+e.length)]}function Ee(t){const e=t.headers.authorization;if(!e)return;const[n,i]=ve(e," ");return void 0!==i?[n.trim().toLowerCase(),i.trim()]:void 0}function Te(t){const e=/^text\/.*;\s*charset=([^;]+)/i.exec(t.headers["content-type"]??"");return e?.[1]?.trim().toLowerCase()??void 0}function _e(t){const e=t.headers["if-range"];return e&&"string"==typeof e?/^("|W\/")/.test(e)?{etag:[e]}:{modifiedSeconds:Oe(e)}:{}}function xe(t,e,{maxRanges:n=10,maxNonSequential:i=2,maxWithOverlap:r=2}={}){const o=t.headers.range;if(!o||0===e)return;const[s,a]=ve(o,"=");if("bytes"!==s||!a)return;const c=new ae(416,{headers:{"content-range":`bytes */${e}`}}),f=t=>{const e=$e(t);if(void 0===e)throw c;return e},u=[];for(const t of a.split(",")){const[i,r]=ve(t.trim(),"-");if(void 0===r)throw c;let o;if(i)o={start:f(i),end:r?Math.min(f(r),e-1):e-1};else{if(!r)throw c;o={start:Math.max(e-f(r),0),end:e-1}}if(!(o.start>=e)){if(o.end<o.start||u.length>=n)throw c;u.push(o)}}if(!u.length)throw c;if(u.length>i)for(let t=0;t<u.length-1;++t)if(u[t].start>u[t+1].start)throw c;if(u.length>r)for(let t=1;t<u.length;++t){const e=u[t];for(let n=0;n<t;++n){const t=u[n];if(e.end>=t.start&&t.end>=e.start)throw c}}return{ranges:u,totalSize:e}}function Se(t){if(void 0!==t)return"number"==typeof t?[String(t)]:t.length?"string"==typeof t?t.split(",").map(t=>t.trim()):t.flatMap(t=>t.split(",").map(t=>t.trim())):[]}function $e(t){if(t&&/^\s*-?\d+\s*$/.test(t))return Number.parseInt(t,10)}function ke(t){if(t)return t.split(",").map(t=>{const[e,...n]=t.split(";"),i=new Map(n.map(t=>{const[e,n]=ve(t,"=");return[e.trim(),n?.trim()??""]})),r=e.trim(),o="*/*"===r||"*"===r?0:r.endsWith("/*")?1:2,s=Math.max(0,Math.min(1,Number.parseFloat(i.get("q")??"1")));return{name:r,specifiers:i,specificity:o,q:s}})}function Ne(t){const e=new Map,n=/\s*([^=]+)=([^";]*?|"(?:[^\\"]|\\.)*")\s*(?:;|$)/y;for(;n.lastIndex<t.length;){const i=n.exec(t);if(!i)throw new ae(400,{body:"invalid HTTP key values"});const r=i[1].toLowerCase();let o=i[2];'"'===o[0]&&(o=o.substring(1,o.length-1).replaceAll(/\\(.)/g,(t,e)=>e)),e.set(r,o)}return e}function Oe(t){if("string"!=typeof t)return;const e=Date.parse(t);return Number.isNaN(e)?void 0:e/1e3|0}const Ae=t=>"function"==typeof t?t:()=>t;class Re{constructor(t=Ue){this.Ot=Ae(t)}set(t,e){Ce(ft(t)).set(this,e)}get(t){return Fe(t,this,this.Ot)}clear(t){const e=at(t);e?.At?.delete(this)}withValue(t){return Wt(e=>(this.set(e,t),kt))}}const Pe=(t,...e)=>{const n=n=>t(n,...e);return t=>Fe(t,n,n)};function Ce(t){return t.At||(t.At=new Map),t.At}function Fe(t,e,n){const i=at(t);if(!i)return n(t);const r=Ce(i);if(r.has(e))return r.get(e);const o=n(t);return r.set(e,o),o}const Ue=()=>{throw new Error("property has not been set")};function Me({realm:t,extractAndValidateToken:e,fallbackTokenFetcher:n,closeOnExpiry:i=!0,softCloseBufferTime:r=0,onSoftCloseError:o}){const s=Ae(t);return{...Wt(async t=>{const a=Date.now(),c=await s(t),f={"www-authenticate":`Bearer realm="${c}"`},u=Ee(t),h="bearer"===u?.[0]?u[1]:await(n?.(t));if(!h)throw new ae(401,{headers:f,body:"no token provided"});let l;try{l=await e(h,c,t)}catch(t){throw new ae(401,{headers:f,body:"invalid token",cause:t})}if(!l)throw new ae(401,{headers:f,body:"invalid token"});if("object"==typeof l){if("nbf"in l&&"number"==typeof l.nbf&&a<1e3*l.nbf)throw new ae(401,{headers:f,body:"token not valid yet"});if("exp"in l&&"number"==typeof l.exp){const e=1e3*l.exp;if(a>=e-r)throw new ae(401,{headers:f,body:"token expired"});i&&((t,e,n,i=0,r)=>{const o=ft(t),s=n-Math.max(i,0),a=o.tt??Number.POSITIVE_INFINITY,c=o.et?.nt??a;s>=c&&n>=a||(n<a&&(o.tt=n),s<c&&(o.et={nt:s,X:e,U:r??o.U}),vt(o))})(t,"token expired",e,r,o)}}return Ie.set(t,{Rt:c,Pt:!0,Ct:l,Ft:je(l)}),kt}),getTokenData:t=>{const e=Ie.get(t);if(!e.Pt)throw new TypeError("cannot use getTokenData in an unauthenticated endpoint");return e.Ct}}}const Be=(t,e)=>Ie.get(t).Ft.has(e),De=t=>Wt(e=>{const n=Ie.get(e);if(!n.Ft.has(t))throw new ae(403,{headers:{"www-authenticate":`Bearer realm="${n.Rt}", scope="${t}"`},body:`scope required: ${t}`});return kt}),Ie=/*@__PURE__*/new Re({Rt:"",Pt:!1,Ct:null,Ft:new Set});function je(t){if(!t||"object"!=typeof t||!("scopes"in t))return new Set;const{scopes:e}=t;return Array.isArray(e)?new Set(e):"string"==typeof e?new Set([e]):e&&"object"==typeof e?new Set(Object.entries(e).filter(([t,e])=>e).map(([t])=>t)):new Set}function qe(t,e){const n=`${0|e.mtimeMs} ${e.size} ${t??""}`;return`W/"${h("sha256").update(n).digest("base64").substring(0,12)}"`}async function He(t){const e=h("sha256");return"string"==typeof t?await d(a(t),e):await d(t.createReadStream({start:0,autoClose:!1}),e),`"sha256-${e.digest("base64")}"`}const Le=(t,e)=>new RegExp(t,(t.unicodeSets?"v":t.unicode?"u":"")+(t.ignoreCase||e?"i":"")),Je={mime:"accept",language:"accept-language",encoding:"accept-encoding"},ze=/*@__PURE__*/new Map([["zstd","{file}.zst"],["br","{file}.br"],["gzip","{file}.gz"],["deflate","{file}.deflate"],["identity","{file}"]]),We=t=>{return{type:"encoding",options:(e=t,n=ze,Array.isArray(e)?e.map(t=>({match:t,file:n.get(t)})):Object.entries(e).map(([t,e])=>({match:t,file:e})))};var e,n};class Ge{constructor(t,{maxFailedAttempts:e=10}={}){this.Ut=t.map(t=>{if(!Object.prototype.hasOwnProperty.call(Je,t.type))throw new RangeError(`unknown rule type: ${t.type}`);return{Mt:t.type,Bt:t.options.map(t=>({Dt:t.file,It:"string"==typeof t.match?t.match.toLowerCase():Le(t.match,!0),jt:t.as??("string"==typeof t.match?t.match:void 0)}))}}).filter(t=>t.Bt.length>0),this.qt=e,this.vary=[...new Set(this.Ut.map(t=>Je[t.Mt]))].join(" ")}options(t,e){const n={mime:ke(e.accept),language:ke(e["accept-language"]),encoding:ke(e["accept-encoding"])};let i=this.qt;const r=this.Ut,o={};return function*t(e,s){const a=r[s];if(!a)return--i,void(yield{filename:e,info:o});const c=new Set,f=(h=n[a.Mt],h?.length?1===h.length?h:[...h].sort(Ve):[]),u=[];var h;for(const t of a.Bt){const e=f.find(e=>"string"==typeof t.It?e.name.toLowerCase()===t.It:t.It.test(e.name));e&&u.push({...e,Ht:t})}for(const n of u.sort(Ve)){const r=Ze(e,n.Ht.Dt);if(!c.has(r)&&(c.add(r),o[a.Mt]=n.Ht.jt,yield*t(r,s+1),i<=0))return}o[a.Mt]=void 0,!c.has(e)&&i>0&&(yield*t(e,s+1))}(t,0)}}const Ve=(t,e)=>e.q-t.q||e.specificity-t.specificity;function Ze(t,e){return e.replaceAll(/\{(?:file|base|ext)\}/g,e=>"{file}"===e?t:"{base}"===e?t.replace(/\.[^.]*$/,""):m(t))}const Xe=/*@__PURE__*/tn("bin=application/octet-stream;gz(ip),json,ogg,pdf,wasm,xml,y(a)ml,zip,zst(d)=application/{ext};aac,flac,mid(i),wav(e)=audio/{ext};mp3=audio/mpeg;oga,opus=audio/ogg;otf,ttf,woff,woff2=font/{ext};apng,avif,bmp,gif,heic,heif,jp(e)g,png,tif(f),webp=image/{ext};ico,cur=image/x-icon;svg=image/svg+xml;3mf,obj,stl,u3d=model/{ext};wrl=model/vrml;x3d=model/x3d+xml;x3db=model/x3d+binary;x3dv=model/x3d+vrml;css,csv,htm(l),rtf,vcard=text/{ext};(m)js=text/javascript;md=text/markdown;txt=text/plain;3gp(p),3g(pp)2,mp4,mp(e)g,h264=video/{ext};mov=video/quicktime;ogv=video/ogg");let Ye=/*@__PURE__*/new Map(Xe);function Ke(){Ye=new Map(Xe)}function Qe(t){const e=new Map;for(const n of t.split("\n")){const[t,...i]=n.replaceAll(/\s+/g," ").trim().split(" ");if(!t.startsWith("#"))for(const n of i)e.set(n.toLowerCase(),t)}return e}function tn(t){const e=new Map;for(const n of t.split(/[\n;]/g)){const[t,i,r]=/^ *([^=]+)=(.*)$/.exec(n)??[null,null,""];for(const t of i?.split(",")??[]){const[n,i,o="",s=""]=/^([^(]*)(?:\(([^)]*)\)(.*))?$/.exec(t),a=i+o+s,c=r.replace("{ext}",a);e.set(a.toLowerCase(),c),o&&e.set((i+s).toLowerCase(),c)}}return e}function en(t){for(const[e,n]of t)Ye.set(e.toLowerCase(),n)}function nn(t,e="utf-8"){"."===t[0]&&(t=t.substring(1));const n=Ye.get(t)??"application/octet-stream";return n.startsWith("text/")&&!n.includes("charset=")?`${n}; charset=${e}`:n}async function rn(t,e,{minCompression:n=0,deleteObsolete:i=!1}={}){const r=await T(t),o={file:t,mime:nn(m(t)),rawSize:r.byteLength,bestSize:r.byteLength,created:0};if(["image","video","audio","font"].includes(o.mime.split("/")[0]))return o;const s=o.rawSize-n;for(const n of e){const e=an.get(n.match),a=y(g(t),Ze(b(t),n.file));if(!e||a===n.file)continue;const c=s>0?await e(r):void 0;c&&c.byteLength<=s?(await _(a,c),o.bestSize=Math.min(o.bestSize,c.byteLength),++o.created):i&&await x(a).catch(()=>{})}return o}async function on(t,e,n={}){const i=[];await sn(t,i);const r=new Set(i);for(const t of r)for(const n of e){const e=y(g(t),Ze(b(t),n.file));e!==t&&r.delete(e)}return Promise.all([...r].map(t=>rn(t,e,n)))}async function sn(t,e){const n=await S(t);if(n.isDirectory())for(const n of await $(t))await sn(y(t,n),e);else n.isFile()&&e.push(t)}const an=/*@__PURE__*/new Map([["zstd",t=>p(w.zstdCompress)(t)],["br",t=>p(w.brotliCompress)(t,{params:{[w.constants.BROTLI_PARAM_QUALITY]:w.constants.BROTLI_MAX_QUALITY,[w.constants.BROTLI_PARAM_SIZE_HINT]:t.length}})],["gzip",t=>p(w.gzip)(t,{level:w.constants.Z_BEST_COMPRESSION})],["deflate",t=>p(w.deflate)(t)]]),cn=(t,e,n)=>{const i=ft(t);i.U(e,n??(i.D?"handling upgrade":"handling request"),t)},fn=(t,{onlyIfRequested:e=!0,emitError:n=!0,forceStatus:i,contentType:r="application/json"}={})=>({handleError:(o,s,a)=>{if(a.hasUpgraded||e&&!un(s,r))throw o;n&&cn(s,o);const c=fe(a);if(!c)return;const f=Z(o,ae)??new ae(500),u=JSON.stringify(t(f));c.setHeaders(f.headers),c.setHeader("content-type",r),c.setHeader("content-length",String(Buffer.byteLength(u,"utf-8"))),a.response||c.setHeader("connection","close"),i?c.writeHead(i):c.writeHead(f.statusCode,f.statusMessage),c.end(u,"utf-8")},shouldHandleError:(t,n,i)=>!i.hasUpgraded&&(!e||un(n,r))}),un=(t,e)=>ke(t.headers.accept)?.some(t=>t.name===e||"application/json"===t.name)??!1;class hn{constructor(t,{subDirectories:e=!0,caseSensitive:n="exact",allowAllDotfiles:i=!1,allowAllTildefiles:r=!1,allowDirectIndexAccess:o=!1,allow:s=[".well-known"],hide:a=[],indexFiles:c=["index.htm","index.html"],implicitSuffixes:f=[],negotiator:u}){this.Lt=t,this.Jt=!0===e?Number.POSITIVE_INFINITY:e||0,this.zt=n,this.Wt=i,this.Gt=r,this.Vt=o,this.Zt=c,this.Xt=["",...f],this.Yt=new Set(s.map(t=>this.Kt(t))),this.Qt=new Set,this.te=[];for(const t of a)"string"==typeof t?this.Qt.add(this.Kt(t)):this.te.push(Le(t,!n));this.ee=new Set(c.map(t=>this.Kt(t))),this.ne=u,this.vary=u?.vary??""}static async build(t,e={}){return new hn(await k(t,{encoding:"utf-8"})+v,e)}Kt(t){return"exact"===this.zt?t:t.toLowerCase()}ie(t){if(this.Yt.has(t))return!0;const e=t.trim();return!(!("~"!==e[0]&&"~"!==e[e.length-1]||this.Gt)||"."===e[0]&&!this.Wt||this.Qt.has(e)||this.te.some(t=>t.test(e)))}toNormalisedPath(t){const e=t[t.length-1];return e&&this.ee.has(this.Kt(e))?t.slice(0,t.length-1):t}async find(t,e={},n){let i=t.join(v);"force-lowercase"===this.zt&&(i=i.toLowerCase());let r=E(this.Lt,i);if(!r.startsWith(this.Lt)&&r+v!==this.Lt)return n?.push(`${JSON.stringify(r)} is not inside root ${JSON.stringify(this.Lt)}`),null;let o=null,s=null;for(const t of this.Xt){const e=r+t;if(o=e.substring(this.Lt.length).split(v).filter(t=>t),o.length-1>this.Jt)return n?.push(`${JSON.stringify(r)} is nested too deeply (${o.length-1} > ${this.Jt})`),null;if(o.some(t=>!this.ie(this.Kt(t))))return n?.push(`${JSON.stringify(r)} is not permitted`),null;const i=o[o.length-1]??"";if(!this.Vt&&this.ee.has(this.Kt(i))&&!this.Yt.has(this.Kt(i)))return n?.push(`${JSON.stringify(r)} is a hidden index file`),null;if(s=await k(e,{encoding:"utf-8"}).catch(()=>null),s){r=e;break}}if(!s||!o)return n?.push(`file ${JSON.stringify(r)} does not exist`),null;if(this.Kt(s)!==this.Kt(r))return n?.push(`realpath ${JSON.stringify(s)} does not match request ${JSON.stringify(r)}`),null;let a=s,c=await S(s).catch(()=>null);if(!c)return n?.push(`file ${JSON.stringify(s)} does not exist`),null;if(c.isDirectory()){if(o.length>this.Jt)return n?.push(`${JSON.stringify(s)} index file is nested too deeply (${o.length} > ${this.Jt})`),null;for(const t of this.Zt){const e=y(s,t);if(c=await S(e).catch(()=>null),c?.isFile()){a=e;break}}}if(!c?.isFile())return n?.push(`${JSON.stringify(s)} exists but is not a file`),null;if(this.ne){const t=b(a),i=g(a);for(const r of this.ne.options(t,e)){if(!r.filename||r.filename.includes(v))continue;const t=await dn({canonicalPath:a,negotiatedPath:y(i,r.filename),...r.info},n);if(t)return t}}return dn({canonicalPath:a,negotiatedPath:a},n)}async debugAllPaths(){return(await this.precompute()).debugAllPaths()}async precompute(){const t=new Map,e=(e,n)=>{const i=t.get(e);(!i||n.p>i.p)&&t.set(e,n)},n=new G({dir:[this.Lt],depth:0});for(const{dir:t,depth:i}of n){const r=await $(y(...t),{withFileTypes:!0,encoding:"utf-8"}),o=new Set(r.map(t=>this.Kt(t.name)));for(const s of r){const r=this.Kt(s.name);if(!this.ie(r))continue;const a=[...t,s.name];if(s.isDirectory())i<this.Jt&&n.push({dir:a,depth:i+1}),e(this.Kt(a.slice(1).join("/")),ln);else if(s.isFile()){const n={file:y(...a),dir:y(...t),basename:r,siblings:o},i=this.Zt.indexOf(r);if(-1!==i&&(e(this.Kt(t.slice(1).join("/")),{...n,p:this.Zt.length+1-i}),!this.Vt&&!this.Yt.has(r)))continue;const c=this.Kt(a.slice(1).join("/"));for(let t=0;t<this.Xt.length;++t){const i=this.Xt[t];s.name.endsWith(i)&&e(c.substring(0,c.length-i.length),{...n,p:-t})}}}}return{find:async(e,n={},i)=>{const r=t.get(this.Kt(e.join("/")));if(!r?.file)return i?.push(`${JSON.stringify(e.join("/"))} not found in static file paths`),null;if(this.ne)for(const t of this.ne.options(r.basename,n)){if(!r.siblings.has(this.Kt(t.filename)))continue;const e=await dn({canonicalPath:r.file,negotiatedPath:y(r.dir,t.filename),...t.info},i);if(e)return e}return dn({canonicalPath:r.file,negotiatedPath:r.file},i)},debugAllPaths:()=>Promise.resolve(new Set([...t].filter(([t,e])=>e.file).map(([t])=>t))),vary:this.vary}}}const ln={file:"",dir:"",basename:"",siblings:new Set,p:1};async function dn(t,e){const n=await N(t.negotiatedPath,c.O_RDONLY).catch(()=>null);if(!n)return e?.push(`failed to open ${JSON.stringify(t.negotiatedPath)}`),null;const i=()=>(n.close().catch(()=>{}),null),r=await n.stat().catch(i);return r?.isFile()?{handle:n,stats:r,...t}:(e?.push(`${JSON.stringify(t.negotiatedPath)} exists but is not a file`),i())}const wn=/*@__PURE__*/Pe(async t=>{const e=xt(t);if(e.aborted)throw $t;e.throwIfAborted();const n=await O(y(A(),"upload"));_t(t,()=>x(n,{recursive:!0}));let i=0;const r=()=>{if(e.aborted)throw $t;return y(n,(++i).toString(10).padStart(6,"0"))};return{dir:n,nextFile:r,save:async(t,{mode:n=384}={})=>{const i=r(),o=f(i,{mode:n});try{return await d(t,o,{signal:e}),{path:i,size:o.bytesWritten}}finally{o.close()}}}});function pn(t){const e=ft(t);if(!e.I)throw new TypeError("cannot call acceptBody from shouldUpgrade");if(e.F.signal.aborted)throw $t;e.re||e.D||(e.re=!0,"100-continue"===t.headers.expect?.trim().toLowerCase()&&e.I.j.writeContinue())}function mn(t,{blockRequestHeaders:e=["connection","expect","host","keep-alive","proxy-authorization","transfer-encoding","upgrade","via"],requestHeaders:n=[],blockResponseHeaders:i=["connection","keep-alive","transfer-encoding"],responseHeaders:s=[],agent:a,...c}={}){const f=new URL(t);let u;"https:"===f.protocol?(a??=new P({keepAlive:!0,...c}),u=o):(a??=new r({keepAlive:!0,...c}),u=C);const h=f.pathname,l=h+(h.endsWith("/")?"":"/"),w="a://a"+l;return Jt((t,r)=>new Promise((o,c)=>{const p=xt(t),m=t=>c(p.aborted?$t:new ae(502,{cause:t})),y=new URL(w+t.url?.substring(1));if(!y.pathname.startsWith(l)&&y.pathname!==h)return c(new ae(400,{message:"directory traversal blocked"}));pn(t);let g={...t.headers};yn(g,e);for(const e of n)g=e(t,g);const b=u(f,{agent:a,path:y.pathname+y.search,method:t.method,headers:g,signal:p});b.once("error",m),b.once("response",e=>{if(!r.headersSent){let n={...e.headers};yn(n,i);for(const i of s)n=i(t,e,n);r.writeHead(e.statusCode??200,e.statusMessage,n)}d(e,r).then(o,c)}),d(t,b).catch(m)}))}function yn(t,e){for(const e of Se(t.connection)??[])Bt(t,e.toLowerCase());for(const n of e)Bt(t,n)}function gn({trustedProxyCount:t,trustedProxyAddresses:e,trustedHeaders:n}){const i=e?H(e):()=>!0,r=t??(e?Number.POSITIVE_INFINITY:0),o=new Set(n);return Pe(t=>{const e=e=>{if(o.has(e))return Se(t.headers[e])?.reverse()},n=e("forwarded"),s=e("x-forwarded-for"),a=e("x-forwarded-host"),c=e("x-forwarded-proto"),f=e("x-forwarded-protocol"),u=e("x-url-scheme"),h=e("via")?.map(t=>{const e=/^([^/ ]+\/)?([^ ]+) (.+)$/.exec(t);return e?.[3]?q(e[3]):void 0}),l=[bn(t)];if(n)for(const t of n)try{const e=Ne(t);l.push({client:q(e.get("for")),server:q(e.get("by")),host:e.get("host"),proto:e.get("proto")})}catch{l.push({client:void 0,server:void 0,host:void 0,proto:void 0})}else if(s){const t=s.map(q),e=a??[],n=c??f??u??[];let i=l[0].client;for(let r=0;r<t.length;++r){const o=t[r];l.push({client:o,server:h?.[r]??(i?{...i,port:void 0}:void 0),host:e[r],proto:n[r]}),i=o}}else if(h)for(const t of h)l.push({client:void 0,server:t,host:void 0,proto:void 0});let d=Math.min(1+r,l.length);for(let t=0;t<d-1;++t)i(l[t].client)||(d=t+1);return Object.freeze({trusted:l.slice(0,d),untrusted:l.slice(d),outwardChain:l,edge:l[d-1]})})}const bn=t=>({client:{...q(t.socket.remoteAddress)??vn,port:t.socket.remotePort},server:{...q(t.socket.localAddress)??vn,port:t.socket.localPort},host:t.headers.host,proto:void 0}),vn={family:"alias",address:"_disconnected",port:void 0};function En(t,e){return delete e.forwarded,delete e["x-forwarded-for"],delete e["x-forwarded-host"],delete e["x-forwarded-proto"],delete e["x-forwarded-protocol"],delete e["x-url-scheme"],e}function Tn(t,e){const n=En(0,e);return n.forwarded=Sn([bn(t)]),n}const _n=(t,{onlyTrusted:e=!1}={})=>(n,i)=>{const r=En(0,i),o=t(n);return r.forwarded=Sn([...e?o.trusted:o.outwardChain].reverse()),r};function xn(t,e){let n=t.headers.forwarded;const i=Sn([bn(t)]);n?n+=", "+i:n=i;const r=En(0,e);return r.forwarded=n,r}function Sn(t){return t.filter(t=>t.server||t.client).map(t=>Object.entries({for:t.client?.address,by:t.server?.address,host:t.host,proto:t.proto}).filter(([t,e])=>e).map(([t,e])=>e&&/[^a-zA-Z0-9._]/.test(e)?`${t}="${e.replaceAll("\\","\\\\").replaceAll('"','\\"').replaceAll(",","-")}"`:`${t}=${e}`).join("; ")).join(", ")}class $n{constructor(t,{fatal:e=!1}={}){this.oe=t,this.se=e,this.ae=new Uint8Array(4),this.ce=new DataView(this.ae.buffer),this.fe=0}decode(t,{stream:e=!1}={}){const n=t.byteLength,i=[];let r=0;if(this.fe>0){if(r=4-this.fe,n<r)return this.ae.set(t,this.fe),this.fe+=n,"";this.ae.set(t.subarray(0,r),this.fe),i.push(this.ce.getUint32(0,this.oe)),this.fe=0}const o=new DataView(t.buffer,t.byteOffset,t.byteLength);let s=r;for(const t=n-3;s<t;s+=4)i.push(o.getUint32(s,this.oe));if(e?(s<n&&this.ae.set(t.subarray(s)),this.fe=n-s):(this.fe=0,s<n&&(this.se?ut(new TypeError("The encoded data was not valid for encoding utf-32"),"ERR_ENCODING_INVALID_ENCODED_DATA"):i.push(65533))),i.length>0){try{return String.fromCodePoint(...i)}catch{this.se&&ut(new TypeError("The encoded data was not valid for encoding utf-32"),"ERR_ENCODING_INVALID_ENCODED_DATA")}for(let t=0;t<i.length;++t)i[t]>1114111&&(i[t]=65533);return String.fromCodePoint(...i)}return""}}class kn extends F{constructor(t){super({transform(e,n){try{const i=t.decode(e,{stream:!0});i&&n.enqueue(i)}catch(t){n.error(t)}},flush(e){try{const n=t.decode(Y);n&&e.enqueue(n)}catch(t){e.error(t)}}})}}const Nn=new Map;function On(t,e){Nn.set(t.toLowerCase(),e)}function An(){On("utf-32be",{decoder:t=>new $n(!1,t)}),On("utf-32le",{decoder:t=>new $n(!0,t)})}function Rn(t,e={}){const n=Nn.get(t.toLowerCase());if(n)return n.decoder(e);try{return new TextDecoder(t,e)}catch{throw new ae(415,{body:`unsupported charset: ${t}`})}}function Pn(t,e={}){const n=Nn.get(t.toLowerCase());if(n)return n.decoderStream?n.decoderStream(e):new kn(n.decoder(e));try{return new U(t,e)}catch{throw new ae(415,{body:`unsupported charset: ${t}`})}}const Cn=["utf-32be",null,"utf-16be","utf-16be","utf-32le","utf-16le",null,"utf-8"];function Fn(t,e,n){const i=Oe(t.headers["if-modified-since"]),r=Se(t.headers["if-none-match"]);if(r){if(Mn(e,n,r))return!1}else if(i&&(n.mtimeMs/1e3|0)<=i)return!1;return!0}function Un(t,e,n){let i=!0;const r=_e(t);return r.etag&&(i&&=Mn(e,n,r.etag)),r.modifiedSeconds&&(i&&=(n.mtimeMs/1e3|0)===r.modifiedSeconds),i}function Mn(t,e,n){if(n.includes("*"))return!0;const i=t.getHeader("etag");if("string"==typeof i){if(n.includes(i))return!0;if(i.startsWith('W/"'))return!1}return!!n.some(t=>t.startsWith('W/"'))&&n.includes(qe(t.getHeader("content-encoding"),e))}class Bn extends F{constructor(t,e){super({transform(i,r){n+=i.byteLength,n>t?r.error(e):r.enqueue(i)}});let n=0}}function Dn(t,{maxContentBytes:e=Number.POSITIVE_INFINITY,maxNetworkBytes:n=e,maxEncodingSteps:i=1}={}){const r=$e(t.headers["content-length"]);if(void 0!==r&&r>n)throw new ae(413);const o=Se(t.headers["content-encoding"])??[];if(o.length>i)throw new ae(415,{body:"too many content-encoding stages"});pn(t);let s=D.toWeb(t);void 0===r&&Number.isFinite(n)&&(s=s.pipeThrough(new Bn(n,new ae(413))));for(const t of o.reverse())s=s.pipeThrough(Hn(t));return Number.isFinite(e)&&(s=s.pipeThrough(new Bn(e,new ae(413,{body:"decoded content too large"})))),s}function In(t,e={}){const n=Dn(t,e),i=Te(t)??e.defaultCharset??"utf-8";return n.pipeThrough(Pn(i,e))}async function jn(t,e={}){const n=[];for await(const i of In(t,e))n.push(i);return n.join("")}async function qn(t,e={}){const n=await(async(t,e)=>{const n=t.getReader(),i=new Uint8Array(3);let r=0,o=null;for(;;){const t=await n.read(),e=3-r;if(t.done){0===r?(i[0]=1,i[1]=1):1===r&&(i[1]=i[0]),i[2]=i[0],o=null;break}if(o=t.value,o.byteLength>=e){i.set(o.subarray(0,e),r);break}i.set(o,r),r+=o.byteLength}const s=Cn[(i[0]?4:0)|(i[1]?2:0)|(i[2]?1:0)];if(!s)throw n.cancel(),new ae(415,{body:"invalid JSON encoding"});const a=Pn(s,e),c=a.writable.getWriter();return r&&c.write(i.subarray(0,r)),o&&c.write(o),n.releaseLock(),c.releaseLock(),t.pipeThrough(a)})(Dn(t,e),e),i=[];for await(const t of n)i.push(t);return JSON.parse(i.join(""))}function Hn(t){switch(t.toLowerCase()){case"gzip":case"x-gzip":return new M("gzip");case"deflate":return new M("deflate");case"br":try{return new M("brotli")}catch{return I.toWeb(w.createBrotliDecompress())}case"zstd":try{return I.toWeb(w.createZstdDecompress())}catch{throw new ae(415,{body:"unsupported content encoding"})}default:throw new ae(415,{body:"unknown content encoding"})}}function Ln(t){if(!t)return null;const[e,n]=ve(t,";"),i=new Map;if(n){const t=/\s*([!#-'*+\-.0-:>-Z^-z|~]+)=(?:([!#-'*+\-.0-:>-Z^-z|~]+)|"((?:[^\x00-\x08\x0a-\x1f"\\\x7f]|\\.)*)")\s*(;|$)/gy;for(;t.lastIndex!==n.length;){const e=t.exec(n);if(!e)return null;const r=e[1].toLowerCase(),o=e[2]??e[3]?.replaceAll(/\\(.)/g,"$1")??"";i.has(r)||i.set(r,o)}}return{mime:e.trim().toLowerCase(),params:i}}function Jn(t,e,n,i){const r=t.byteLength;for(;e<r;){for(;e<r;++e){const n=t[e];if(32!==n&&9!==n)break}if(e===r)break;if(59!==t[e++])return!1;for(;e<r;++e){const n=t[e];if(32!==n&&9!==n)break}if(e===r)return!1;const o=e;for(;e<r;++e){const n=t[e];if(!Wn[n]){if(61===n)break;return!1}}if(e===r)return!1;const s=t.latin1Slice(o,e).toLowerCase();if("*"===s[s.length-1]){const i=++e;for(;e<r;++e){const n=t[e];if(!Vn[n]){if(39!==n)return!1;break}}if(e===r)return!1;const o=Rn(t.latin1Slice(i,e));for(++e;e<r&&39!==t[e];++e);if(e===r)return!1;if(++e===r)return!1;let a=e;const c=[];for(;e<r;++e){const n=t[e];if(1!==Gn[n]){if(37===n){let n,i;if(e+2<r&&16!==(n=Xn[t[e+1]])&&16!==(i=Xn[t[e+2]])){const r=(n<<4)+i;e>a&&c.push(o.decode(t.subarray(a,e),{stream:!0})),c.push(o.decode(Buffer.from([r]),{stream:!0})),a=(e+=2)+1;continue}return!1}break}}c.push(o.decode(t.subarray(a,e)));const f=c.join("");n.has(s)||n.set(s,f);continue}if(++e===r)return!1;if(34===t[e]){let o=++e,a=!1;const c=[];for(;e<r;++e){const n=t[e];if(92!==n){if(34===n){if(a){o=e,a=!1;continue}c.push(i.decode(t.subarray(o,e)));break}if(a&&(o=e-1,a=!1),!Zn[n])return!1}else a?(o=e,a=!1):(c.push(i.decode(t.subarray(o,e),{stream:!0})),a=!0)}if(e===r)return!1;++e,n.has(s)||n.set(s,c.join(""));continue}let a=e;for(;e<r;++e){const n=t[e];if(!Wn[n]){if(e===a)return!1;break}}n.has(s)||n.set(s,i.decode(t.subarray(a,e)))}return!0}const zn=[1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],Wn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,...zn,0,1,0,1],33),t})(),Gn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,0,1,0,0,0,0,1,0,1,1,0,...zn,0,1,0,1],33),t})(),Vn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.set([1,0,1,1,1,1,0,0,0,0,1,0,1,0,0,...zn,1,0,1,1],33),t})(),Zn=/*@__PURE__*/(()=>{const t=new Uint8Array(256);return t.fill(1,32,256),t[9]=1,t[34]=0,t[92]=0,t[127]=0,t})(),Xn=/*@__PURE__*/(()=>{const t=new Uint8Array(256).fill(16);for(let e=0;e<10;++e)t[48+e]=e;for(let e=0;e<6;++e)t[65+e]=e+10,t[97+e]=e+10;return t})();class Yn{constructor(t,e){const n=t.byteLength;if(!n||n>65535)throw new RangeError("invalid needle");this.ue=t,this.he=e,this.le=null,this.de=0,this.we=null}push(t){let e=0;const n=t.byteLength,i=this.ue,r=i.byteLength-1,o=n-r;let s=-this.de;if(this.de){const a=this.we,c=this.le,f=i[r];if(o>0){const n=t[s+r];n!==f||t.compare(i,-s,r,0,s+r)?s+=a[n]:(this.he(!0,Y,0,0,!0),this.de=0,e=s+=r+1)}const u=o<0?o:0;for(;s<u;){const n=t[s+r];if(n===f&&!c.compare(i,0,-s,this.de+s,this.de)&&!t.compare(i,-s,r,0,s+r)){this.he(!0,c,0,this.de+s,!1),this.de=0,e=s+=r+1;break}s+=a[n]}const h=this.de;if(h>0){const e=i[0];for(;s<0;){const r=c.subarray(0,h).indexOf(e,h+s);if(-1===r){s=0;break}const o=h-r;if(!c.compare(i,1,o,r+1,h)&&!t.compare(i,o,o+n))return r&&(this.he(!1,c,0,r,!1),c.copy(c,0,r,o)),c.set(t,o),void(this.de+=n-r);s=r+1-h}this.he(!1,c,0,h,!1),this.de=0}}for(;s<o;){const n=t.indexOf(i,s);if(-1!==n){if(this.he(!0,t,e,n,!0),n===o+1)return;e=s=n+r+1}else s=o}const a=i[0];for(;s<n;){const o=t.indexOf(a,s);if(-1===o)return void this.he(!1,t,e,n,!0);if(!t.compare(i,1,n-o,o+1)){if(!this.le){this.le=Buffer.allocUnsafe(r),this.we=new Uint16Array(256).fill(r+1);for(let t=0;t<r;++t)this.we[i[t]]=r-t}return t.copy(this.le,0,o),this.de=n-o,void(o>e&&this.he(!1,t,e,o,!0))}s=o+1}n>e&&this.he(!1,t,e,n,!0)}destroy(){const t=this.de;t&&this.le&&this.he(!1,this.le,0,t,!1),this.de=0}}class Kn extends j{constructor({limits:t={},preservePath:e,highWaterMark:n,fileHwm:i,defParamCharset:r="utf-8",defCharset:o="utf-8"},s){super({autoDestroy:!0,emitClose:!0,highWaterMark:n,write:Qn,destroy:ti,final:ei});const a=s.get("boundary");if(!a)throw new ae(400,{body:"multipart boundary not found"});if(a.length>70)throw new ae(400,{body:"multipart boundary too long"});const c=Rn(r),f={autoDestroy:!0,emitClose:!0,highWaterMark:i},u=t.fieldSize??1048576,h=t.fileSize??Number.POSITIVE_INFINITY,l=t.fieldNameSize??100,d=t.files??Number.POSITIVE_INFINITY,w=t.fields??Number.POSITIVE_INFINITY,p=t.parts??Number.POSITIVE_INFINITY;let m,y,g,b,v,E=0,T=0,_=0,x=-1;this.pe=0,this.me=!1;let S=!1;const $=new ni(t=>{this.ye=void 0;const n=t["content-disposition"];if(!n)return void(x=-1);const i=((t,e)=>{if(!t.byteLength)return null;const n=new Map;let i=0;for(;i<t.byteLength;++i)if(!Wn[t[i]]){if(!Jn(t,i,n,e))return null;break}return{type:t.latin1Slice(0,i).toLowerCase(),params:n}})(Buffer.from(n,"latin1"),c);if("form-data"!==i?.type)return void(x=-1);if(v=i.params.get("name"),void 0===v)return this.emit("error",new ae(400,{body:"missing field name"})),void(x=-1);S=v.length>l,S&&(v=v.substring(0,l));let r=i.params.get("filename*")??i.params.get("filename");void 0===r||e||(r=(t=>{for(let e=t.length;e-- >0;)if("/"===t[e]||"\\"===t[e]){t=t.slice(e+1);break}return".."===t||"."===t?"":t})(r));const s=Ln(t["content-type"]);b=s?.mime??"text/plain";const a=s?.params.get("charset")?.toLowerCase()??o;if(y=Rn(a),g=t["content-transfer-encoding"]?.toLowerCase()??"7bit","application/octet-stream"===b||void 0!==r){if(_++===d&&this.emit("filesLimit"),_>d||0===this.listenerCount("file"))return void(x=-1);this.ge=new ii(f,this),++this.pe,this.emit("file",v,this.ge,{nameTruncated:S,filename:r,encoding:g,mimeType:b}),x=h}else{if(T++===w&&this.emit("fieldsLimit"),T>w||0===this.listenerCount("field"))return void(x=-1);m="",x=u}});let k=0;const N=Buffer.from(`\r\n--${a}`,"latin1");this.be=new Yn(N,(t,e,n,i,r)=>{try{if(n===i)return;if(k){if(1===k){if(13===e[n])k=2;else{if(45!==e[n])return void(k=0);k=3}if(++n===i)return}if(2!==k){if(k=0,45!==e[n])return;return this.me=!0,void(this.be=oi)}if(k=0,10!==e[n++])return;if(E++===p&&this.emit("partsLimit"),E>p)return;if(this.ye=$,n===i)return}if(this.ye){const t=this.ye.push(e,n,i);if(-1===t)return this.ye=void 0,$.reset(),void this.emit("error",new ae(400,{body:"malformed part header"}));if(t===i)return;n=t}if(x>=0){const t=Math.min(i,n+x);if(x-=i-n,this.ge){if(t>n){let i;r?i=e.subarray(n,t):(i=Buffer.allocUnsafe(t-n),e.copy(i,0,n,t)),this.ge.push(i)||(this.ge.ve??=this.Ee,this.Ee=void 0)}x<0&&(this.ge.emit("limit"),this.ge.truncated=!0)}else void 0!==m&&(m+=e.latin1Slice(n,t))}}finally{t&&(this.ye?(this.emit("error",new ae(400,{body:"unexpected end of headers"})),this.ye=void 0):this.ge?(this.ge.push(null),this.ge=void 0):void 0!==m&&(this.emit("field",v,y.decode(Buffer.from(m,"latin1")),{nameTruncated:S,valueTruncated:x<0,encoding:g,mimeType:b}),m=void 0),k=1,x=-1)}}),this.write(si)}Te(){if(this.ye)return new ae(400,{body:"malformed part header"});const t=this.ge;return t&&(this.ge=void 0,t.destroy(new ae(400,{body:"unexpected end of file"}))),this.me?null:new ae(400,{body:"unexpected end of form"})}}function Qn(t,e,n){this.Ee=n,this.be.push(t);const i=this.Ee;i&&(this.Ee=void 0,i())}function ti(t,e){this.ye=void 0,this.be=oi,t??=this.Te();const n=this.ge;n&&(this.ge=void 0,n.destroy(t??void 0)),e(t)}function ei(t){if(this.be.destroy(),!this.me)return t(new ae(400,{body:"unexpected end of form"}));this.pe?this._e=()=>t(this.Te()):t(this.Te())}class ni{constructor(t){this.xe=Object.create(null),this.Se=0,this.$e=0,this.m=0,this.ht="",this.ke="",this.Ne=0,this.he=t}reset(){this.xe=Object.create(null),this.Se=0,this.$e=0,this.m=0,this.ht="",this.ke="",this.Ne=0}push(t,e,n){let i=e,r=e;const o=Math.min(n,e+16384-this.$e);for(;r<o;)switch(this.m){case 0:for(;r<o&&Wn[t[r]];++r);if(r>i&&(this.ht+=t.latin1Slice(i,r)),r<o){if(58!==t[r])return-1;if(!this.ht)return-1;++r,this.m=1}break;case 1:for(;r<o;++r){const e=t[r];if(32!==e&&9!==e){i=r,this.m=2;break}}break;case 2:switch(this.Ne){case 0:for(;r<o;++r){const e=t[r];if(e<32||127===e){if(13!==e)return-1;++this.Ne;break}}this.ke+=t.latin1Slice(i,r),++r;break;case 1:if(10!==t[r++])return-1;++this.Ne;break;case 2:{const e=t[r];32===e||9===e?(i=r,this.Ne=0):(++this.Se<2e3&&(this.xe[this.ht.toLowerCase()]??=this.ke),13===e?(++this.Ne,++r):(i=r,this.Ne=0,this.m=0,this.ht="",this.ke=""));break}case 3:{if(10!==t[r++])return-1;const e=this.xe;return this.reset(),this.he(e),r}}}return o<n?-1:(this.$e+=o-e,o)}}class ii extends D{constructor(t,e){super({...t,read:ri}),this.truncated=!1,this.once("end",()=>{if(ri.call(this),0===--e.pe&&e._e){const t=e._e;e._e=void 0,process.nextTick(t)}})}}function ri(t){const e=this.ve;e&&(this.ve=void 0,e())}const oi={push:()=>{},destroy:()=>{}},si=/*@__PURE__*/Buffer.from("\r\n");class ai extends j{constructor({limits:t={},highWaterMark:e,defCharset:n="utf-8"},i){super({autoDestroy:!0,emitClose:!0,highWaterMark:e,write:ci,final:fi}),this.Oe=i.get("charset")??n,this.Ae=t.fieldSize??1048576,this.Re=t.fields??Number.POSITIVE_INFINITY,this.Pe=t.fieldNameSize??100,this.Ce=0,this.Fe=!0,this.Ue="",this.Me=this.Pe,this.Be=0,this.De="",this.Ie=!1,this.je=-2,this.qe=/^utf-?8$/i.test(this.Oe)?1:/^(latin-?1|iso[\-_]?8859-?1|(us-)?ascii)$/i.test(this.Oe)?2:0,this.He=Rn(this.Oe)}}function ci(t,e,n){if(!t.byteLength)return n();if(this.Ce>=this.Re)return this.Ce||t===pi||(++this.Ce,this.emit("fieldsLimit")),n();const i=t.byteLength;let r=0,o=this.je;if(-2!==o){if(-1===o){if(16===(o=Xn[t[r++]]))return n(new ae(400,{body:"malformed urlencoded form"}));if(this.Be|=o,r===i)return this.je=o,n()}const e=Xn[t[r++]];if(16===e)return n(new ae(400,{body:"malformed urlencoded form"}));if(this.Ue+=String.fromCharCode((o<<4)+e),this.je=-2,r===i)return n()}for(wi[ui]=1,wi[hi]=1,wi[li]=1,wi[di]=this.Fe?1:0;;){const e=r;for(;r<i&&!wi[t[r]];++r);if(r>e&&this.Me>=0&&((this.Me-=r-e)<0?this.Ue+=t.latin1Slice(e,r+this.Me):this.Ue+=t.latin1Slice(e,r)),r===i)return n();switch(t[r++]){case ui:for(;;){if(--this.Me<0){wi[ui]=0,wi[li]=0;break}if(r===i)return this.je=-1,n();const e=Xn[t[r++]];if(16===e)return n(new ae(400,{body:"malformed urlencoded form"}));if(this.Be|=e,r===i)return this.je=e,n();const o=Xn[t[r++]];if(16===o)return n(new ae(400,{body:"malformed urlencoded form"}));if(this.Ue+=String.fromCharCode((e<<4)+o),r===i)return n();if(t[r]!==ui)break;r++}break;case hi:const e=!this.qe||1===this.qe&&8&this.Be?this.He.decode(Buffer.from(this.Ue,"latin1")):this.Ue;if(this.Fe?(e||this.Me<0)&&this.emit("field",this.Ue,"",{nameTruncated:this.Me<0,valueTruncated:!1,encoding:this.Oe,mimeType:"text/plain"}):(this.emit("field",this.De,e,{nameTruncated:this.Ie,valueTruncated:this.Me<0,encoding:this.Oe,mimeType:"text/plain"}),this.De="",this.Ie=!1,this.Fe=!0,wi[di]=1),wi[ui]=1,wi[li]=1,this.Ue="",this.Me=this.Pe,this.Be=0,++this.Ce===this.Re&&t!==pi)return this.emit("fieldsLimit"),n();break;case li:--this.Me<0?(wi[ui]=0,wi[li]=0):this.Ue+=" ";break;case di:this.De=!this.qe||1===this.qe&&8&this.Be?this.He.decode(Buffer.from(this.Ue,"latin1")):this.Ue,this.Ie=this.Me<0,this.Fe=!1,wi[di]=0,wi[ui]=1,wi[li]=1,this.Ue="",this.Be=0,this.Me=this.Ae}if(r===i)return n()}}function fi(t){ci.call(this,pi,void 0,t)}const ui=37,hi=38,li=43,di=61,wi=/*@__PURE__*/new Uint8Array(256),pi=/*@__PURE__*/Buffer.from([hi]);function mi(t,{closeAfterErrorDelay:e=500,...n}={}){W(e,"closeAfterErrorDelay",!0);const i=((t,e={})=>{const n=t["content-type"];if(!n)throw new ae(400,{body:"missing content-type"});const i=Ln(n);if(!i)throw new ae(400,{body:"malformed content-type"});const r="application/x-www-form-urlencoded"===i.mime?ai:"multipart/form-data"!==i.mime||e.blockMultipart?null:Kn;if(!r)throw new ae(415);return new r(e,i.params)})(t.headers,n);pn(t);const r=new V,o=(n,o)=>{if(r.fail(new ae(n,o)),i.removeAllListeners(),t.unpipe(i),t.resume(),e>=0){const n=setTimeout(()=>t.socket.destroy(),e);t.once("end",()=>clearTimeout(n))}};i.on("field",(t,e,{nameTruncated:n,valueTruncated:i,encoding:s,mimeType:a})=>t?n?o(400,{body:`field name ${JSON.stringify(t)}... too long`}):i?o(400,{body:`value for ${JSON.stringify(t)} too long`}):void r.push({name:t,encoding:s,mimeType:a,type:"string",value:e}):o(400,{body:"missing field name"})),i.on("file",(t,e,{nameTruncated:n,filename:i,encoding:s,mimeType:a})=>t?n?o(400,{body:`field name ${JSON.stringify(t)}... too long`}):void(i?(e.once("limit",()=>o(400,{body:`uploaded file for ${JSON.stringify(t)}: ${JSON.stringify(i)} too large`})),r.push({name:t,encoding:s,mimeType:a,type:"file",value:e,filename:i})):e.resume()):o(400,{body:"missing field name"})),t.once("error",e=>{t.readableAborted?r.fail($t):o(500,{body:"request error",headers:{connection:"close"},cause:e})}),i.once("error",t=>o(400,{body:"error parsing form data",cause:t})),i.once("partsLimit",()=>o(400,{body:"too many parts"})),i.once("filesLimit",()=>o(400,{body:"too many files"})),i.once("fieldsLimit",()=>o(400,{body:"too many fields"}));const s=()=>r.close("complete");return i.once("close",s),_t(t,s),t.pipe(i),r}async function yi(t,e={}){const n=new FormData,i=new Map;for await(const r of mi(t,e))if("file"===r.type){const o=r.value;let s=await(e.preCheckFile?.({fieldName:r.name,filename:r.filename,encoding:r.encoding,mimeType:r.mimeType,maxBytes:e.limits?.fileSize}));const a=t=>{if("function"==typeof s){const e=s;return s=void 0,e({actualBytes:t})}};_t(t,()=>a(0));const c=await wn(t),f=await c.save(o,{mode:384});await a(f.size);const h=new File([await u(f.path)],r.filename,{type:r.mimeType});i.set(h,f.path),n.append(r.name,h)}else{let t=r.value;e.trimAllValues&&(t=t.trim()),n.append(r.name,t)}return Object.assign(n,{getTempFilePath(t){const e=i.get(t);if(!e)throw new RangeError("unknown file");return e},getBoolean(t){const e=n.get(t);return null===e?null:"true"===e||"on"===e},getString(t){const e=n.get(t);return"string"==typeof e?e:null},getAllStrings:t=>n.getAll(t).filter(t=>"string"==typeof t),getFile(t){const e=n.get(t);return"string"==typeof e?null:e},getAllFiles:t=>n.getAll(t).filter(t=>"string"!=typeof t)})}const gi="win32"===/*@__PURE__*/R();function bi(t,{rejectPotentiallyUnsafe:e=!0}={}){let n=[];const i=at(t);if(i){if("/"===i.C)return[];n=i.C.split("/")}else{const e=K(t).pathname;if("/"===e)return[];n=e.split("/").map(decodeURIComponent)}if(""!==n[0])throw new ae(400,{body:"invalid path"});if(n.shift(),e){const t=gi?Ei:vi;if(n.some(e=>t.test(e)||e.includes(v)))throw new ae(400,{body:"invalid path"});if(n.slice(0,n.length-1).includes(""))throw new ae(400,{body:"invalid path"})}return n}const vi=/[\x00-\x1F\x7F/]|^(\.\.?|~)$/,Ei=/[\x00-\x1F"*/:<>?\\|\x7F]|^[\s.]*$|^(CON|PRN|AUX|NUL|(COM|LPT)[\d\xB9\xB2\xB3])(\.|$)/i,Ti=t=>new Promise(e=>{const n=()=>{t.cork(),e()};t instanceof s?t.write(Y,n):t.once("drain",n),t.uncork()});async function _i(t,e,{delimiter:n=",",newline:i="\n",quote:r='"',encoding:o="utf-8",headerRow:a,end:c=!0}={}){"string"==typeof n&&(n=Buffer.from(n,o)),"string"==typeof i&&(i=Buffer.from(i,o));const f="string"==typeof r?Buffer.from(r,o):r,u=r+r,h=e=>{if(!e)return!0;const n=e.includes(r);return!n&&xi.test(e)?t.write(e,o):(t.write(f),n?t.write(e.replaceAll(r,u),o):t.write(e,o),t.write(f))};t instanceof s&&!t.headersSent&&!t.hasHeader("content-type")&&t.setHeader("content-type","text/csv; charset="+o+(a?"; header=present":!1===a?"; header=absent":"")),t.cork();try{t.write(Y);for await(const r of e){if(t.writableAborted)break;let e=0;if(Symbol.iterator in r)for(const i of r)e&&t.write(n),h(i)||await Ti(t),++e;else for await(const i of r)e&&t.write(n),h(i)||await Ti(t),++e;t.write(i)||await Ti(t)}}finally{t.uncork()}c&&t.end()}const xi=/^[^"':;,\\\r\n\t ]*$/i;function Si(t){if(!t||"object"!=typeof t)return!1;const e=t;return"number"==typeof e.fd&&"function"==typeof e.stat&&"function"==typeof e.createReadStream}class $i{constructor(t){(t=>"Le"in t&&"function"==typeof t.pipe)(t)&&(t=D.toWeb(t)),this.lt=t.getReader(),this.Je=null,this.ze=0,this.m=0}getRange(t,e){if(e<t)throw new RangeError("invalid range");if(t<this.ze)throw new RangeError("non-sequential range");if(this.m)throw new TypeError("previous range still active");let n=e-t+1,i=t-this.ze;this.ze=e+1,this.m=1;const r=this,o=(t,e)=>{const r=t.byteLength;r<=i?i-=r:r>i+n?(this.Je=t.subarray(i+n),e.enqueue(t.subarray(i,i+n)),n=0):i>0?(e.enqueue(t.subarray(i)),n-=r-i,i=0):(e.enqueue(t),n-=r)};return new B({start(t){if(r.Je){const e=r.Je;r.Je=null,o(e,t)}},async pull(t){if(n<=0)return r.m=0,void t.close();const e=await r.lt.read();e.done?t.error(new RangeError("range exceeds content")):"string"==typeof e.value?o(Buffer.from(e.value,"utf-8"),t):e.value instanceof Uint8Array?o(e.value,t):t.error(new TypeError("invalid stream type: must contain bytes or UTF-8 text"))}})}async close(){await this.lt.cancel(),this.lt.releaseLock()}}function ki(t,{forceSequential:e=!1,mergeOverlapDistance:n=100}={}){const i=[];if(n>=0)for(const e of t.ranges){let t=null,r=0;for(let o=0;o<i.length;++o){const s=i[o];e.end>=s.start-n-1&&s.end>=e.start-n-1?t?(++r,t.start=Math.min(t.start,s.start),t.end=Math.max(t.end,s.end)):(t=s,t.start=Math.min(t.start,e.start),t.end=Math.max(t.end,e.end)):r>0&&(i[o-r]=s)}t?i.length-=r:i.push({...e})}else i.push(...t.ranges);if(e)for(let t=0;t<i.length-1;++t)if(i[t].start>i[t+1].start){i.sort((t,e)=>t.start-e.start);break}return{ranges:i,totalSize:t.totalSize}}async function Ni(t,e,n,i){if("string"==typeof n||Si(n)||(i=ki(i,{mergeOverlapDistance:0,forceSequential:!0})),1===i.ranges.length){const r=i.ranges[0];if(e.setHeader("content-length",r.end-r.start+1),e.setHeader("content-range",`bytes ${r.start}-${r.end}/${i.totalSize??"*"}`),e.writeHead(206),"HEAD"===t.method)return void e.end();const o=await Oi(n);return await d(o.We(r.start,r.end),e),void(o.Ge&&await o.Ge())}const r=e.getHeader("content-type"),o=l()+l()+"ABCDEFGHIJKLMNOPQRSTUVWXYZ";e.setHeader("content-type",`multipart/byteranges; boundary=${o}`);const s=i.ranges.map(t=>({o:[`--${o}`,...lt({"content-type":r,"content-range":`bytes ${t.start}-${t.end}/${i.totalSize??"*"}`}),"",""].join("\r\n"),Ve:t})),a=`--${o}--`;let c=a.length;for(const{o:t,Ve:e}of s)c+=t.length+e.end-e.start+1+2;if(e.setHeader("content-length",c),"HEAD"===t.method)return void e.end();let f="";const u=await Oi(n);try{for(const{o:t,Ve:n}of s)e.write(f+t,"ascii"),await d(u.We(n.start,n.end),e,{end:!1}),f="\r\n";e.end(f+a)}finally{u.Ge&&await u.Ge()}}async function Oi(t){if("string"==typeof t){const e=await N(t,"r");return{We:(t,n)=>e.createReadStream({start:t,end:n,autoClose:!1}),Ge:()=>e.close()}}if(Si(t))return{We:(e,n)=>t.createReadStream({start:e,end:n,autoClose:!1})};{const e=new $i(t);return{We:(t,n)=>e.getRange(t,n),Ge:()=>e.close()}}}async function Ai(t,e,n,i=null,r){if(i||("string"==typeof n?i=await S(n):Si(n)&&(i=await n.stat())),i){if("GET"===t.method||"HEAD"===t.method){if(!Fn(t,e,i))return void e.writeHead(304).end();e.setHeader("accept-ranges","bytes");const o=xe(t,i.size,r);if(o&&Un(t,e,i))return Ni(t,e,n,ki(o,r))}e.setHeader("content-length",i.size)}if(e.writeHead(e.statusCode,e.statusMessage),"HEAD"!==t.method)return"string"==typeof n?n=a(n):Si(n)&&(n=n.createReadStream({start:0,autoClose:!1})),d(n,e);e.end()}function Ri(t,e,{replacer:n,space:i,undefinedAsNull:r=!1,encoding:o="utf-8",end:a=!0}={}){const c=JSON.stringify(e,n,i??void 0)??(r?"null":void 0);t instanceof s&&!t.headersSent&&(t.hasHeader("content-type")||t.setHeader("content-type","application/json"),a&&t.setHeader("content-length",Buffer.byteLength(c,o))),a?t.end(c,o):c&&t.write(c,o)}async function Pi(t,e,{replacer:n=null,space:i=null,undefinedAsNull:r=!1,encoding:o="utf-8",end:a=!0}={}){if(Array.isArray(n)){const t=new Set(n.map(t=>String(t)));n=function(e,n){return null===this||Array.isArray(this)||t.has(e)?n:void 0}}"number"==typeof i&&(i=" ".substring(0,i));const c={Ze:e=>t.write(e,o),Xe:()=>Ti(t),Ye:n,Ke:i??""};if(t instanceof s&&!t.headersSent&&!t.hasHeader("content-type")&&t.setHeader("content-type","application/json"),e=Fi(null,"",e,c),Ui(e))r&&c.Ze("null");else{t.cork(),t.write(Y);try{await Ci(c,e,i?"\n":"")}finally{t.uncork()}}a&&t.end()}async function Ci(t,e,n){const i=(i,r,o)=>{t.Ze(i);const s=n+t.Ke,a=t.Ke?": ":":";let c=!0;return{i:async(n,i)=>{const r=Fi(e,n,i,t);o&&Ui(r)||(c?c=!1:t.Ze(","),t.Ze(s),o&&(t.Ze(JSON.stringify(n))||await t.Xe(),t.Ze(a)),await Ci(t,r,s))},Ge:()=>{c||t.Ze(n),t.Ze(r)}}};if(null===e||"object"!=typeof e||e instanceof String||e instanceof Number||e instanceof Boolean||e instanceof Function||e instanceof Symbol||e instanceof BigInt||Mi(e))t.Ze(JSON.stringify(e)??"null")||await t.Xe();else if(e instanceof D){t.Ze('"');for await(const n of e){if("string"!=typeof n)throw new TypeError("Readables must have an encoding");const e=JSON.stringify(n);t.Ze(e.substring(1,e.length-1))||await t.Xe()}t.Ze('"')}else if(e instanceof Map){const t=i("{","}",!0);for(const[n,i]of e)await t.i(n,i);t.Ge()}else if(Bi(e)){let t=0;const n=i("[","]",!1);for(const i of e)await n.i(String(t++),i);n.Ge()}else if(Di(e)){let t=0;const n=i("[","]",!1);for await(const i of e)await n.i(String(t++),i);n.Ge()}else{const t=i("{","}",!0);for(const[n,i]of Object.entries(e))await t.i(n,i);t.Ge()}}function Fi(t,e,n,i){return i.Ye&&(n=i.Ye.call(t,e,n)),n&&"object"==typeof n&&"function"==typeof n.toJSON&&(n=n.toJSON(e)),n}const Ui=t=>void 0===t||"function"==typeof t||"symbol"==typeof t||t instanceof Function||t instanceof Symbol,Mi=t=>JSON.isRawJSON?.(t)??!1,Bi=t=>Symbol.iterator in t,Di=t=>Symbol.asyncIterator in t;class Ii{constructor(t,e,{keepaliveInterval:n=15e3,softCloseReconnectDelay:i=500,softCloseReconnectStagger:r=2e3}={}){W(n,"keepaliveInterval",!0),this.Qe=e,this.tn=n,this.F=new AbortController,e.setHeader("content-type","text/event-stream"),e.setHeader("x-accel-buffering","no"),e.setHeader("cache-control","no-store"),e.writeHead(200),e.flushHeaders(),this.ping=this.ping.bind(this),this.en(),t.once("close",()=>this.close()),pt(t,()=>this.close(i,r))}get signal(){return this.F.signal}get open(){return!this.F.signal.aborted}en(){this.tn>0&&(this.nn=setTimeout(this.ping,this.tn))}ping(){!this.F.signal.aborted&&this.Qe.writable&&(clearTimeout(this.nn),this.Qe.write(":\n\n",()=>this.en()))}send({event:t,id:e,data:n,reconnectDelay:i=-1}){return this.sendFields([["event",t],["id",e],["data",n],["retry",i>=0?String(0|i):void 0]])}async sendFields(t){let e;this.F.signal.throwIfAborted(),this.Qe.cork();try{let n=!1;for(const[e,i]of t){if(void 0===i)continue;const t=i.split(/(?<=\n)|(?<=\r)(?!\n)/g);for(let n of t)this.Qe.write(e)," "===n[0]?this.Qe.write(": "):this.Qe.write(":"),this.Qe.write(n);/[\r\n]$/.test(i)?(this.Qe.write(e),this.Qe.write(":\n")):this.Qe.write("\n"),n=!0}if(!n)return;clearTimeout(this.nn),this.Qe.write("\n",()=>e())}finally{this.Qe.uncork()}await new Promise(t=>{e=t}),this.en()}async close(t=0,e=0){if(this.F.signal.aborted){if(this.Qe.closed)return;return new Promise(t=>this.Qe.once("close",t))}this.tn=0,clearTimeout(this.nn),this.F.abort(new Error("ServerSentEvents closed")),await new Promise(n=>{if(this.Qe.writable&&(t>0||e>0)){const i=t+Math.random()*e;this.Qe.end(`retry:${0|i}\n\n`,n)}else this.Qe.end(n)})}}const ji=async(t,{mode:e="dynamic",fallback:n,verbose:i,callback:r=qi,...o}={})=>{const s=await hn.build(E(process.cwd(),t),o);let a=null;const c=n?.statusCode??200;if(n){let t=n.filePath;t.startsWith("/")&&(t=t.substring(1)),a=s.toNormalisedPath(t.split("/"))}const f="dynamic"===e?{}:{rejectPotentiallyUnsafe:!1},u="dynamic"===e?s:await s.precompute();return{handleRequest:async(t,e)=>{if("GET"!==t.method&&"HEAD"!==t.method)return kt;let n=!1;const o=bi(t,f),s=[];let h=await u.find(o,t.headers,i?s:void 0);if(!h){if(!a)return i&&cn(t,new Error(s.join(", ")),"serving static content"),kt;if(n=!0,h=await u.find(a,t.headers,s),!h)throw new ae(500,{message:`failed to find fallback file: ${s.join(", ")}`})}try{n&&(e.statusCode=c),e.setHeader("content-type",h.mime??nn(m(h.canonicalPath))),h.encoding&&"identity"!==h.encoding&&e.setHeader("content-encoding",h.encoding);const i=u.vary;if(i){const t=e.getHeader("vary")??"";e.setHeader("vary",(t?t+", ":"")+i)}await r(t,e,h,n),await Ai(t,e,h.handle,h.stats)}finally{h.handle.close().catch(()=>{})}}}};function qi(t,e,n){e.setHeader("etag",qe(e.getHeader("content-encoding"),n.stats)),e.setHeader("last-modified",n.stats.mtime.toUTCString())}class Hi extends Error{constructor(t,{message:e,closeReason:n,...i}={}){super(e,i),this.closeCode=0|t,this.closeReason=n??"",this.name=`WebSocketError(${this.closeCode} ${this.closeReason})`}static NORMAL_CLOSURE=1e3;static GOING_AWAY=1001;static UNSUPPORTED_DATA=1003;static POLICY_VIOLATION=1008;static MESSAGE_TOO_BIG=1009;static INTERNAL_SERVER_ERROR=1011;static SERVICE_RESTART=1012;static TRY_AGAIN_LATER=1013;static BAD_GATEWAY=1014}function Li(t,{softCloseStatusCode:e=Hi.GOING_AWAY,...n}={}){const i=(i,r,o)=>new Promise((s,a)=>{const c=new t({...n,noServer:!0,clientTracking:!1});c.once("wsClientError",a),c.handleUpgrade(i,r,o,t=>{c.off("wsClientError",a),o=Y,s({return:t,onError:e=>{const n=Z(e,Hi);if(n)return void t.close(n.closeCode,n.closeReason);const i=Z(e,ae)??new ae(500),r=i.statusCode>=500?Hi.INTERNAL_SERVER_ERROR:4e3+i.statusCode;t.close(r,i.statusMessage)},softCloseHandler:n=>t.close(e,n)})})});return t=>At(t,i)}class Ji{constructor(t,e){this.data=t,this.isBinary=e}get text(){if(this.isBinary)throw new Hi(Hi.UNSUPPORTED_DATA,{closeReason:"expected text"});return this.data.toString("utf-8")}get binary(){if(!this.isBinary)throw new Hi(Hi.UNSUPPORTED_DATA,{closeReason:"expected binary"});return this.data}}class zi{constructor(t,{limit:e=-1,signal:n}={}){this.rn=new V;const i=e=>{t.off("message",o),t.off("close",r),this.rn.close(new Error(e))},r=()=>i("connection closed"),o=(t,n)=>{void 0!==n?this.rn.push(new Ji(t,n)):"string"==typeof t?this.rn.push(new Ji(Buffer.from(t,"utf-8"),!1)):this.rn.push(new Ji(t,!0)),e>0&&0===--e&&this.detach()};this.detach=()=>{},n?.aborted?this.rn.close(n.reason):2===t.readyState||3===t.readyState?this.rn.close(new Error("connection closed")):(t.on("message",o),t.on("close",r),n?.addEventListener("abort",()=>i("signal aborted")),this.detach=()=>i("WebSocket listener detached"))}next(t){return this.rn.shift(t)}[Symbol.asyncIterator](){return this.rn[Symbol.asyncIterator]()}}function Wi(t,{timeout:e,signal:n}={}){const i=new zi(t,{limit:1,signal:n});return i.next(e).finally(()=>i.detach())}function Gi(t){const e=ft(t);return"GET"===t.method&&(e.D?.has("websocket")??!1)}const Vi=t=>t.headers.origin??dt(t.headers["sec-websocket-origin"]),Zi=(t,e=5e3)=>async n=>{if(!Gi(n))return;const i=await t(n);let r;try{r=await Wi(i,{timeout:e})}catch(t){if((i.readyState??0)>=2)throw $t;throw new Hi(Hi.POLICY_VIOLATION,{closeReason:"timeout waiting for authentication token",cause:t})}if(r.isBinary)throw new Hi(Hi.UNSUPPORTED_DATA,{closeReason:"authentication token must be sent as text"});return r.data.toString("utf-8")};export{V as BlockingQueue,kt as CONTINUE,hn as FileFinder,ae as HTTPError,Nt as NEXT_ROUTE,Ot as NEXT_ROUTER,Ge as Negotiator,Re as Property,G as Queue,te as Router,$t as STOP,Ii as ServerSentEvents,pe as WebListener,Hi as WebSocketError,Ji as WebSocketMessage,zi as WebSocketMessages,pn as acceptBody,At as acceptUpgrade,_t as addTeardown,Wt as anyHandler,Fn as checkIfModified,Un as checkIfRange,Mn as compareETag,rn as compressFileOffline,on as compressFilesInDir,Zt as conditionalErrorHandler,tn as decompressMime,Tt as defer,Rt as delegateUpgrade,cn as emitError,Gt as errorHandler,ji as fileServer,Z as findCause,He as generateStrongETag,qe as generateWeakETag,xt as getAbortSignal,Ht as getAbsolutePath,X as getAddressURL,Ee as getAuthorization,qn as getBodyJson,Dn as getBodyStream,jn as getBodyText,In as getBodyTextStream,Te as getCharset,yi as getFormData,mi as getFormFields,_e as getIfRange,nn as getMime,qt as getPathParameter,jt as getPathParameters,be as getQuery,xe as getRange,bi as getRemainingPathComponents,ye as getSearch,ge as getSearchParams,Rn as getTextDecoder,Pn as getTextDecoderStream,Vi as getWebSocketOrigin,Be as hasAuthScope,yt as isSoftClosed,Gi as isWebSocketRequest,fn as jsonErrorHandler,Li as makeAcceptWebSocket,H as makeAddressTester,gn as makeGetClient,Pe as makeMemo,wn as makeTempFileStorage,Zi as makeWebSocketFallbackTokenFetcher,We as negotiateEncoding,Wi as nextWebSocketMessage,q as parseAddress,mn as proxy,Oe as readHTTPDateSeconds,$e as readHTTPInteger,Ne as readHTTPKeyValues,ke as readHTTPQualityValues,Se as readHTTPUnquotedCommaSeparated,Qe as readMimeTypes,On as registerCharset,en as registerMime,An as registerUTF32,En as removeForwarded,Tn as replaceForwarded,Jt as requestHandler,De as requireAuthScope,Me as requireBearerAuth,Ke as resetMime,Lt as restoreAbsolutePath,_n as sanitiseAndAppendForwarded,_i as sendCSVStream,Ai as sendFile,Ri as sendJSON,Pi as sendJSONStream,Ni as sendRanges,qi as setDefaultCacheHeaders,pt as setSoftCloseHandler,xn as simpleAppendForwarded,ki as simplifyRange,ue as toListeners,Vt as typedErrorHandler,zt as upgradeHandler};
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --disable-proto=delete --disallow-code-generation-from-strings --force-node-api-uncaught-exceptions-policy --no-addons
|
|
2
|
-
import{readFile as e}from"node:fs/promises";import{join as t,dirname as o,resolve as r}from"node:path";import{createServer as s}from"node:http";import{Router as i,requestHandler as n,addTeardown as a,CONTINUE as f,proxy as c,fileServer as p,getSearch as l,getQuery as h,getPathParameter as u,WebListener as m,findCause as d,HTTPError as g,compressFilesInDir as w,readMimeTypes as y,decompressMime as b,resetMime as x,registerMime as $}from"./index.js";const v=new Map([["","dir"],["-a","host"],["-b","brotli"],["-c","config-file"],["-C","config-json"],["-d","dir"],["-e","ext"],["-g","gzip"],["-h","help"],["-p","port"],["-P","proxy"],["-v","version"],["br","brotli"],["gz","gzip"],["zst","zstd"]]),S=new Map([["config-file",{type:"string"}],["config-json",{type:"string"}],["dir",{type:"string"}],["ext",{type:"string",multi:!0}],["port",{type:"number"}],["host",{type:"string"}],["zstd",{type:"boolean"}],["brotli",{type:"boolean"}],["gzip",{type:"boolean"}],["deflate",{type:"boolean"}],["proxy",{type:"string"}],["404",{type:"string"}],["spa",{type:"string"}],["mime",{type:"string",multi:!0}],["mime-types",{type:"string",multi:!0}],["write-compressed",{type:"boolean"}],["min-compress",{type:"number"}],["no-serve",{type:"boolean"}],["log",{type:"string"}],["help",{type:"boolean"}],["version",{type:"boolean"}]]),z=new Map([["zstd",{match:"zstd",file:"{file}.zst"}],["brotli",{match:"br",file:"{file}.br"}],["gzip",{match:"gzip",file:"{file}.gz"}],["deflate",{match:"deflate",file:"{file}.deflate"}]]);const k=e=>(t,o)=>{if(t!==e)throw new q(`expected ${JSON.stringify(e)}`,o,8);return e},j=e=>(t,o)=>{if(!e.has(t))throw new q(`expected one of ${JSON.stringify(e)}`,o,7);return t},N=e=>(t,o)=>{const r=[];let s=9;for(const i of e)try{return i(t,o)}catch(e){if(e instanceof q){if(e.p>s)continue;e.p!==s&&(s=e.p,r.length=0)}else s=-1;r.push(e)}throw 1===r.length?r[0]:new AggregateError(r)},E=e=>(t,o)=>{if(!Array.isArray(t))throw new q("expected list, got "+typeof t,o);return t.map((t,r)=>e(t,{...o,path:`${o.path}[${r}]`}))},O=(e,t)=>{if("boolean"!=typeof e)throw new q("expected boolean, got "+typeof e,t);return e},P=(e,t,o)=>(r,s)=>{if("number"!=typeof r)throw new q("expected number, got "+typeof r,s);if(e&&(0|r)!==r)throw new q(`expected integer, got ${r}`,s);if("number"==typeof t&&r<t)throw new q(`value cannot be less than ${t}`,s);if("number"==typeof o&&r>o)throw new q(`value cannot be greater than ${o}`,s);return r},T=(e,t)=>(s,i)=>{if("string"!=typeof s)throw new q("expected string, got "+typeof s,i);if(e&&!e.test(s))throw new q(`expected string matching ${e}`,i);if("uri-reference"===t&&i.file){if(s.startsWith("file://"))return"file://"+r(o(i.file),s.substring(7));if(!s.includes("://"))return r(o(i.file),s)}return s},J=(e,t,o)=>(r,s)=>{if("object"!=typeof r)throw new q("expected object, got "+typeof r,s);if(!r)throw new q("expected object, got null",s);if(Array.isArray(r))throw new q("expected object, got list",s);const i={},n=new Set;for(const[o,a]of Object.entries(r)){n.add(o);const r=(e.get(o)??t)(a,{...s,path:`${s.path}.${o}`});void 0!==r&&(i[o]=r)}for(const e of o)if(void 0===i[e])throw new q(`missing required property ${JSON.stringify(e)}`,s);for(const[t,o]of e)if(!n.has(t)){const e=o(void 0,{...s,path:`${s.path}.${t}`});void 0!==e&&(i[t]=e)}return i},A=e=>e,I=(e,t)=>{throw new q("unknown property",t)};class q extends Error{constructor(e,t,o=0){super(`${e} at ${t.path||"root"}`),this.p=o}}function C(e,t){return t.replaceAll(/\$\{([^${}:]+)(?::-(([^}\\]|\\.)*))?\}/g,(t,o,r)=>{let s;return s="?"===o?l(e):"?"===o[0]?h(e,o.substring(1)):u(e,o),"string"==typeof s?s:Array.isArray(s)?s.join("/"):r??""})}class D{constructor(e,t){this.t=!1,this.o=!1,this.i=!1,this.l=e,this.h=t,this.u=new Map}async set(e){if(!this.o&&!this.i)try{this.o=!0;const t=new Set,o=[];for(let r=0;r<e.length;++r){const s=e[r],i=s.port;i<=0||i>65535?this.l(0,`servers[${r}] must have a specific port from 1 to 65535`):t.has(i)?this.l(0,`skipping servers[${r}] because port ${i} has already been defined`):(t.add(i),o.push(async()=>{const e=await this.m(s,this.u.get(i));e?this.u.set(i,e):this.u.delete(i)}))}this.t||=o.length>0;for(const[e,r]of this.u)t.has(e)||(o.push(r.close),this.u.delete(e));await Promise.all(o.map(e=>e())),this.i?this.$():this.u.size?this.l(1,"all servers ready"):this.l(1,"no servers configured")}finally{this.o=!1}}async m({port:e,host:t,options:o,mount:r},l){const h=this.h("34",`http://${t}:${e}`),u=await(async(e,t=()=>{})=>{const o=new i;o.use(n((e,o)=>{const r=Date.now();return a(e,()=>{const s=Date.now()-r;t({method:e.method??"GET",path:e.url??"/",status:o.statusCode,duration:s})}),f}));for(const t of e)switch(t.type){case"files":"/dev/null"!==t.dir&&o.mount(t.path,await p(t.dir,t.options));break;case"proxy":o.mount(t.path,c(t.target,t.options));break;case"fixture":const e=(e,o)=>{for(const[r,s]of Object.entries(t.headers))"string"==typeof s?o.setHeader(r,C(e,s)):"number"==typeof s?o.setHeader(r,s):o.setHeader(r,s.map(t=>C(e,t)));o.statusCode=t.status,o.end(C(e,t.body))};"GET"===t.method&&o.onRequest("HEAD",t.path,e),o.onRequest(t.method,t.path,e);break;case"redirect":o.at(t.path,n((e,o)=>{o.setHeader("location",C(e,t.target)),o.statusCode=t.status,o.end()}))}return o})(r,o.logRequests?e=>{const t=this.h("1",e.method.replaceAll(/[^a-zA-Z0-9\-_]/g,"?")),o=encodeURI(e.path),r=this.h(M[e.status/100|0]??"",String(e.status)),s=this.h("2",`(${e.duration}ms)`);this.l(0,`${h} ${t} ${o} ${r} ${s}`)}:()=>{}),w=new m(u);let y,b;if(w.addEventListener("error",e=>{e.preventDefault();const{error:t,context:o,request:r}=e.detail;(d(t,g)?.statusCode??500)>=500&&this.l(0,`${h} ${this.h("91","error")}: ${o} ${r?.url} ${t}`)}),l&&t===l.host&&((e,t)=>{for(const o of H)if(e[o]!==t[o])return!1;return!0})(o,l.options))y=l.server,this.l(2,`${h} updated`),l.detach();else{if(l?(this.l(2,`${h} ${this.h("2","restarting (step 1: shutdown)")}`),await l.close(),this.l(2,`${h} ${this.h("2","restarting (step 2: start)")}`)):this.l(2,`${h} ${this.h("2","starting")}`),this.i)return;y=s(o),y.setTimeout(o.socketTimeout),b=G(y,e,t,o.backlog)}const x=w.attach(y,o);return b&&(await b,await new Promise(e=>setTimeout(e,0)),this.l(2,`${h} ready`)),{host:t,options:o,server:y,detach:()=>x("restart",o.restartTimeout),close:()=>new Promise(e=>{const t=x("shutdown",o.shutdownTimeout,!0,()=>{y.close(()=>{this.l(2,`${h} closed`),e()}),y.closeAllConnections()}).countConnections();t>0&&this.l(2,`${h} ${this.h("2",`closing (remaining connections: ${t})`)}`)})}}async $(){this.u.size&&(this.l(2,this.h("2","shutting down")),await Promise.all([...this.u.values()].map(e=>e.close()))),this.t&&this.l(2,"shutdown complete")}shutdown(){this.i||(this.i=!0,this.o||this.$())}}const M=["","37","32","36","31","41;97"],G=async(e,t,o,r=511)=>new Promise((s,i)=>{e.once("error",i),e.listen(t,o,r,()=>{e.off("error",i),s()})}),H=["requestTimeout","keepAliveTimeout","keepAliveTimeoutBuffer","connectionsCheckingInterval","headersTimeout","highWaterMark","maxHeaderSize","noDelay","requireHostHeader","keepAlive","keepAliveInitialDelay","uniqueHeaders","backlog","socketTimeout"];function R(e){return e.reduce((e,t)=>({rawSize:e.rawSize+t.rawSize,bestSize:e.bestSize+t.bestSize,created:e.created+t.created}),{rawSize:0,bestSize:0,created:0})}const B=e=>e<2e3?`${e}B`.padStart(8," "):`${(e/1024).toFixed(1)}kB`.padStart(8," "),U=["none","ready","progress"];process.on("SIGUSR1",()=>{});let L=2;const W=(e,t)=>e<=L&&process.stderr.write(t+"\n");function _(e){process.stdin.destroy(),W(0,e instanceof Error?e.message:String(e))}process.on("unhandledRejection",_),process.on("uncaughtException",_);const F=process.stderr.isTTY&&!process.env.NO_COLOR?(e,t)=>e?`\x1b[${e}m${t}\x1b[0m`:t:(e,t)=>t,Y=(e=>{const t=[];for(let o=0;o<e.length;++o){const r=e[o];if("--"===r)continue;const s=/^--([^ =\-][^ =]*)=(.*)$/.exec(r);if(s){t.push([s[1],s[2]]);continue}const i=/^-([^ =]*)([^ =])=(.*)$/.exec(r);if(i&&"-"!==r[1]){for(const e of i[1])t.push(["-"+e,""]);t.push(["-"+i[2],i[3]]);continue}if("-"!==r[0]||"-"===r){if(0!==o)throw new Error(`value without key: ${r}`);t.push(["",r]);continue}let n=e[o+1];if(n&&"-"===n[0]&&n.length>1&&(n=void 0),void 0!==n&&++o,"-"===r[1])t.push([r.slice(2),n??""]);else{for(const e of r.slice(1,r.length-1))t.push(["-"+e,""]);t.push(["-"+r[r.length-1],n??""])}}const o=new Map;for(const[e,r]of t){const t=(v.get(e)??e).toLowerCase(),s=S.get(t);if(!s)throw new Error(`unknown flag: ${e}`);let i;switch(s.type){case"string":i=r;break;case"number":i=Number.parseFloat(r);break;case"boolean":i=["","on","true","yes","y","1"].includes(r.toLowerCase())}if(s.multi){let e=o.get(t);e||(e=[],o.set(t,e)),e.push(i)}else{if(o.has(t))throw new Error(`multiple values for ${t}`);o.set(t,i)}}return o})(process.argv.slice(2));if(Y.get("version")||Y.get("help")){const r=JSON.parse(await e(t(o(new URL(import.meta.url).pathname),"package.json"),"utf-8"));process.stdout.write(`${r.name} ${r.version}\n`),Y.get("help")&&process.stdout.write((Z=r.name,["","HTTP/1.1 server for Node.js","","Serves the current directory on port 8080 by default.","When running, send SIGINT (Ctrl+C) to stop.","Send SIGHUP or press enter to reload config.","",` npx ${Z} -- [dir] [flags]`,"","Options:"," --config-file=..., -c Path to a JSON configuration file to use (see below)"," --config-json=..., -C Inline JSON configuration to use (see below)",' --port=..., -p The port to bind to. Default "8080"',' --host=..., -a The host address to bind to. Default "localhost"',' --dir=... The directory to serve. Default "."'," --ext=... Implicit file extension to attempt if the requested file"," does not exist (can be specified multiple times)"," --404=... File to use for file-not-found, with status 404"," --spa=... File to use for file-not-found, with status 200"," (e.g. to serve an index file for Single-Page-Apps)"," --zstd, --zst Serve .zst files if zstd compression is requested"," --brotli, --br, -b Serve .br files if brotli compression is requested"," --gzip, --gz, -g Serve .gz files if gzip compression is requested"," --deflate Serve .deflate files if deflate compression is requested"," --proxy=..., -P Proxy requests which match no files to this server"," --mime=... Extra file-extension-to-mime-types to use, in the format",' "ext1=mime1;ext2=mime2" (e.g. "txt=text/plain")'," --mime-types=... Path to an Apache .types file of mime types to register"," --write-compressed Generate and save zstd, brotli, gzip, or deflate files"," for each served file before starting"," --min-compress=... The minimum number of bytes that compression must save,",' otherwise the file is not written. Default "300"'," --no-serve Stop after validating the configuration and optionally"," writing any compressed files",' --log=... "none" / "ready" / "progress" / "full". Set the logging',' level. "ready" prints only the "all servers ready" line,',' "progress" prints server startup and shutdown progress,',' and "full" logs all requests. Default "full"'," --help, -h Print this message and exit"," --version, -v Print the current version and exit","","JSON Configuration:","","JSON offers a more powerful way to configure the server. You can define one or","more servers (one per port), each with its own set of mounted handlers.","Example definition:",""," {",' "servers": ['," {",' "port": 9000,',' "mount": [',' { "type": "files", "dir": "." }',' { "type": "fixture", "method": "GET", "path": "/hello.txt", "body": "Hi!" }',' { "type": "proxy", "target": "https://example.com" }'," ]"," }"," ],",' "mime": ["foo=application/x-foo"],'," }","","All CLI flags are compatible with JSON configuration except --dir and --proxy.","--port is not compatible with JSON configurations with more than one server.","","MIME definitions:","","When defining mime types, some shorthands are available:","- multiple mappings separated by semicolons: foo=text/x-foo;bar=text/x-bar","- multiple file extensions separated by commas: foo,bar=text/plain","- use the file extension in the mime type with {ext}: css,csv=text/{ext}","- optional parts in brackets: jp(e)g,tif(f)=image/{ext}"," ({ext} always maps to the full name, so the example maps .jpg to image/jpeg)","","When using an apache .types file, each line contains a mime type, any amount of","whitespace, then a list of space-separated extensions (without a dot). Lines","starting with # are ignored as comments.","","Example usage:","",` npx ${Z} . --port 3000 --gzip --mime="foo=text/x-foo" --mime="bar=text/x-bar"`,"",` npx ${Z} /dev/null --proxy https://example.com`,"",` npx ${Z} -C '{"servers":[{"port":8080,"mount":[{"type":"files","dir":"."}]}]}'`,"",` npx ${Z} . --write-compressed --min-compress 500 --brotli --gzip`,"",` npx ${Z} . --write-compressed --brotli --no-serve`]).join("\n")+"\n"),process.exit(0)}var Z;(async()=>{const r=new D(W,F);process.on("unhandledRejection",()=>r.shutdown()),process.on("uncaughtException",()=>r.shutdown());const s=function(e){const t=o=>{const r=o.$ref;if(r&&r.startsWith("#/$defs/")){const t=e.$defs[r.substring(8)];if(!t)throw new Error(`unable to find ${r} in schema`);o={...t,...o}}const s=((e,t)=>{if(void 0!==e.const)return k(e.const);if(e.enum)return j(new Set(e.enum));if(e.anyOf)return N(e.anyOf.map(t));switch(e.type){case"array":return E(t(e.items));case"boolean":return O;case"integer":return P(!0,e.minimum,e.maximum);case"number":return P(!1,e.minimum,e.maximum);case"object":const o=e.additionalProperties??!0;return J(new Map(Object.entries(e.properties??{}).map(([e,o])=>[e,t(o)])),"object"==typeof o?t(o):o?A:I,e.required??[]);case"string":let r=null;return e.pattern&&(r=new RegExp(e.pattern)),T(r,e.format??"");default:throw new Error(`unknown part type ${JSON.stringify(e)}`)}})(o,t);if(void 0!==o.default){const e=JSON.stringify(o.default);return(t,o)=>s(void 0===t?JSON.parse(e):t,o)}return(e,t)=>void 0===e?void 0:s(e,t)};return t(e)}(await(async()=>JSON.parse(await e(t(o(new URL(import.meta.url).pathname),"schema.json"),"utf-8")))());function i(){process.stdin.destroy(),r.shutdown()}async function n(){const t=await(async(t,o)=>{const r=e=>o.get(e)??[],s=e=>o.get(e),i=e=>o.get(e),n=s("config-file"),a=s("config-json"),f=i("port"),c=s("host"),p=s("dir")||".",l=r("ext").map(e=>e.startsWith(".")?e:`.${e}`),h=s("404"),u=s("spa"),m=s("proxy"),d=i("min-compress"),g=r("mime"),w=r("mime-types"),y=s("log");if(Number(Boolean(n))+Number(Boolean(a))+Number(Boolean(m))>1)throw new Error("multiple config files are not supported");let b;if(n)b=t(JSON.parse(await e(n,"utf-8")),{file:n,path:""});else if(a)b=t(JSON.parse(a),{file:"",path:""});else{let e;u?e={statusCode:200,filePath:u}:h&&(e={statusCode:404,filePath:h});const o=[{type:"files",dir:p,options:{fallback:e}}];m&&o.push({type:"proxy",target:m}),b=t({servers:[{port:8080,mount:o}]},{file:"",path:""})}const x=1===b.servers.length?b.servers[0]:void 0;if(void 0!==f){if((0|f)!==f)throw new Error("port must be an integer");if(!x)throw new Error("cannot specify port on commandline when defining multiple servers");x.port=f}if(void 0!==c)for(const e of b.servers)e.host=c;const $=(e,t)=>{for(const o of b.servers)for(const r of o.mount)if("files"===r.type){r.options.negotiation??=[];let o=r.options.negotiation.find(t=>t.type===e);o||(o={type:e,options:[]},r.options.negotiation=[...r.options.negotiation,o]),o.options.find(e=>e.match===t.match)||o.options.push(t)}};for(const[e,t]of z)o.get(e)&&$("encoding",t);if(l.length)for(const e of b.servers)for(const t of e.mount)"files"===t.type&&(t.options.implicitSuffixes=l);switch((g.length||w.length)&&(Array.isArray(b.mime)||(b.mime?b.mime=[b.mime]:b.mime=[]),b.mime.push(...g),b.mime.push(...w.map(e=>`file://${e}`))),o.get("write-compressed")&&(b.writeCompressed=!0),void 0!==d&&(b.minCompress=d),o.get("no-serve")&&(b.noServe=!0),y){case"none":case"ready":case"progress":b.log=y;for(const e of b.servers)e.options.logRequests=!1;break;case"full":b.log="progress"}return b})(s,Y);L=U.indexOf(t.log),await(async t=>{const o=[];for(const r of Array.isArray(t)?t:[t])"string"!=typeof r?o.push(new Map(Object.entries(r))):r.startsWith("file://")?o.push(y(await e(r.substring(7),"utf-8"))):o.push(b(r));x();for(const e of o)$(e)})(t.mime),t.writeCompressed&&await(async(e,t,o)=>{let r=0;for(const s of e)for(const e of s.mount)if("files"===e.type){const s=e.options.negotiation?.find(e=>"encoding"===e.type)?.options;if(!s?.length){o(2,`skipping ${e.dir} because no compression is configured`);continue}o(2,`compressing files in ${e.dir} using ${s.map(e=>e.match).join(", ")}`);const i=await w(e.dir,s,t),n=R(i.filter(({mime:e})=>e.startsWith("text/"))),a=R(i.filter(({mime:e})=>!e.startsWith("text/")));o(2,`text: ${B(n.rawSize)} / ${B(n.bestSize)} compressed`),o(2,`other: ${B(a.rawSize)} / ${B(a.bestSize)} compressed`),r+=n.created+a.created}o(2,`${((e,t,o=t+"s")=>1===e?`1 ${t}`:`${e} ${o}`)(r,"compressed file")} written`)})(t.servers,t.minCompress,W),t.noServe?i():r.set(t.servers)}function a(){return W(2,"refreshing config"),n()}n(),process.on("SIGHUP",()=>a()),process.stdin.on("data",e=>{e.includes("\n")&&a()}),process.on("SIGINT",()=>{W(2,""),i()})})();
|
|
2
|
+
import{readFile as e}from"node:fs/promises";import{join as t,dirname as o,resolve as s}from"node:path";import{createServer as r}from"node:http";import{Router as i,requestHandler as n,addTeardown as a,CONTINUE as c,proxy as f,Negotiator as p,fileServer as l,getSearch as h,getQuery as u,getPathParameter as m,WebListener as d,findCause as g,HTTPError as w,compressFilesInDir as y,readMimeTypes as b,decompressMime as x,resetMime as $,registerMime as v}from"./index.js";const S=new Map([["","dir"],["-a","host"],["-b","brotli"],["-c","config-file"],["-C","config-json"],["-d","dir"],["-e","ext"],["-g","gzip"],["-h","help"],["-p","port"],["-P","proxy"],["-v","version"],["br","brotli"],["gz","gzip"],["zst","zstd"]]),z=new Map([["config-file",{type:"string"}],["config-json",{type:"string"}],["dir",{type:"string"}],["ext",{type:"string",multi:!0}],["port",{type:"number"}],["host",{type:"string"}],["zstd",{type:"boolean"}],["brotli",{type:"boolean"}],["gzip",{type:"boolean"}],["deflate",{type:"boolean"}],["proxy",{type:"string"}],["404",{type:"string"}],["spa",{type:"string"}],["mime",{type:"string",multi:!0}],["mime-types",{type:"string",multi:!0}],["write-compressed",{type:"boolean"}],["min-compress",{type:"number"}],["no-serve",{type:"boolean"}],["log",{type:"string"}],["help",{type:"boolean"}],["version",{type:"boolean"}]]),j=new Map([["zstd",{match:"zstd",file:"{file}.zst"}],["brotli",{match:"br",file:"{file}.br"}],["gzip",{match:"gzip",file:"{file}.gz"}],["deflate",{match:"deflate",file:"{file}.deflate"}]]);const k=e=>(t,o)=>{if(t!==e)throw new C(`expected ${JSON.stringify(e)}`,o,8);return e},N=e=>(t,o)=>{if(!e.has(t))throw new C(`expected one of ${JSON.stringify(e)}`,o,7);return t},O=e=>(t,o)=>{const s=[];let r=9;for(const i of e)try{return i(t,o)}catch(e){if(e instanceof C){if(e.p>r)continue;e.p!==r&&(r=e.p,s.length=0)}else r=-1;s.push(e)}throw 1===s.length?s[0]:new AggregateError(s)},E=e=>(t,o)=>{if(!Array.isArray(t))throw new C("expected list, got "+typeof t,o);return t.map((t,s)=>e(t,{...o,path:`${o.path}[${s}]`}))},P=(e,t)=>{if("boolean"!=typeof e)throw new C("expected boolean, got "+typeof e,t);return e},T=(e,t,o)=>(s,r)=>{if("number"!=typeof s)throw new C("expected number, got "+typeof s,r);if(e&&(0|s)!==s)throw new C(`expected integer, got ${s}`,r);if("number"==typeof t&&s<t)throw new C(`value cannot be less than ${t}`,r);if("number"==typeof o&&s>o)throw new C(`value cannot be greater than ${o}`,r);return s},J=(e,t)=>(r,i)=>{if("string"!=typeof r)throw new C("expected string, got "+typeof r,i);if(e&&!e.test(r))throw new C(`expected string matching ${e}`,i);if("uri-reference"===t&&i.file){if(r.startsWith("file://"))return"file://"+s(o(i.file),r.substring(7));if(!r.includes("://"))return s(o(i.file),r)}return r},A=(e,t,o)=>(s,r)=>{if("object"!=typeof s)throw new C("expected object, got "+typeof s,r);if(!s)throw new C("expected object, got null",r);if(Array.isArray(s))throw new C("expected object, got list",r);const i=[],n=new Set;for(const[o,a]of Object.entries(s)){n.add(o);const s=(e.get(o)??t)(a,{...r,path:`${r.path}.${o}`});void 0!==s&&i.push([o,s])}for(const e of o)if(!n.has(e))throw new C(`missing required property ${JSON.stringify(e)}`,r);for(const[t,o]of e)if(!n.has(t)){const e=o(void 0,{...r,path:`${r.path}.${t}`});void 0!==e&&i.push([t,e])}return Object.fromEntries(i)},I=e=>e,q=(e,t)=>{throw new C("unknown property",t)};class C extends Error{constructor(e,t,o=0){super(`${e} at ${t.path||"root"}`),this.p=o}}const D=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0;function M(e,t){return t.replaceAll(/\$\{([^${}:]+)(?::-(([^}\\]|\\.)*))?\}/g,(t,o,s)=>{let r;return r="?"===o?h(e):"?"===o[0]?u(e,o.substring(1)):m(e,o),"string"==typeof r?r:Array.isArray(r)?r.join("/"):s??""})}class G{constructor(e,t){this.t=!1,this.o=!1,this.i=!1,this.l=e,this.h=t,this.u=new Map}async set(e){if(!this.o&&!this.i)try{this.o=!0;const t=new Set,o=[];for(let s=0;s<e.length;++s){const r=e[s],i=r.port;i<=0||i>65535?this.l(0,`servers[${s}] must have a specific port from 1 to 65535`):t.has(i)?this.l(0,`skipping servers[${s}] because port ${i} has already been defined`):(t.add(i),o.push(async()=>{const e=await this.m(r,this.u.get(i));e?this.u.set(i,e):this.u.delete(i)}))}this.t||=o.length>0;for(const[e,s]of this.u)t.has(e)||(o.push(s.close),this.u.delete(e));await Promise.all(o.map(e=>e())),this.i?this.$():this.u.size?this.l(1,"all servers ready"):this.l(1,"no servers configured")}finally{this.o=!1}}async m({port:e,host:t,options:o,mount:s},h){const u=this.h("34",`http://${t}:${e}`),m=await(async(e,t=()=>{})=>{const o=new i;o.use(n((e,o)=>{const s=Date.now();return a(e,()=>{const r=Date.now()-s;t({method:e.method??"GET",path:e.url??"/",status:o.statusCode,duration:r})}),c}));for(const t of e)switch(t.type){case"files":if("/dev/null"!==t.dir){const e=t.options.negotiation&&t.options.negotiation.length>0?new p(t.options.negotiation):void 0;o.mount(t.path,await l(t.dir,{...t.options,negotiator:e}))}break;case"proxy":o.mount(t.path,f(t.target,t.options));break;case"fixture":const e=(e,o)=>{for(const[s,r]of Object.entries(t.headers))"string"==typeof r?o.setHeader(s,M(e,r)):"number"==typeof r?o.setHeader(s,r):o.setHeader(s,r.map(t=>M(e,t)));o.statusCode=t.status,o.end(M(e,t.body))};"GET"===t.method&&o.onRequest("HEAD",t.path,e),o.onRequest(t.method,t.path,e);break;case"redirect":o.at(t.path,n((e,o)=>{o.setHeader("location",M(e,t.target)),o.statusCode=t.status,o.end()}))}return o})(s,o.logRequests?e=>{const t=this.h("1",e.method.replaceAll(/[^a-zA-Z0-9\-_]/g,"?")),o=encodeURI(e.path),s=this.h(H[e.status/100|0]??"",String(e.status)),r=this.h("2",`(${e.duration}ms)`);this.l(0,`${u} ${t} ${o} ${s} ${r}`)}:()=>{}),y=new d(m);let b,x;if(y.addEventListener("error",e=>{e.preventDefault();const{error:t,context:o,request:s}=e.detail;(g(t,w)?.statusCode??500)>=500&&this.l(0,`${u} ${this.h("91","error")}: ${o} ${s?.url} ${t}`)}),h&&t===h.host&&((e,t)=>{for(const o of B)if(e[o]!==t[o])return!1;return!0})(o,h.options))b=h.server,this.l(2,`${u} updated`),h.detach();else{if(h?(this.l(2,`${u} ${this.h("2","restarting (step 1: shutdown)")}`),await h.close(),this.l(2,`${u} ${this.h("2","restarting (step 2: start)")}`)):this.l(2,`${u} ${this.h("2","starting")}`),this.i)return;b=r(o),b.setTimeout(o.socketTimeout),x=R(b,e,t,o.backlog)}const $=y.attach(b,o);return x&&(await x,await new Promise(e=>setTimeout(e,1)),this.l(2,`${u} ready`)),{host:t,options:o,server:b,detach:()=>$("restart",o.restartTimeout),close:()=>new Promise(e=>{const t=$("shutdown",o.shutdownTimeout,!0,()=>{b.close(()=>{this.l(2,`${u} closed`),e()}),b.closeAllConnections()}).countConnections();t>0&&this.l(2,`${u} ${this.h("2",`closing (remaining connections: ${t})`)}`)})}}async $(){this.u.size&&(this.l(2,this.h("2","shutting down")),await Promise.all([...this.u.values()].map(e=>e.close()))),this.t&&this.l(2,"shutdown complete")}shutdown(){this.i||(this.i=!0,this.o||this.$())}}const H=["","37","32","36","31","41;97"],R=async(e,t,o,s=511)=>new Promise((r,i)=>{e.once("error",i),e.listen(t,o,s,()=>{e.off("error",i),r()})}),B=["requestTimeout","keepAliveTimeout","keepAliveTimeoutBuffer","connectionsCheckingInterval","headersTimeout","highWaterMark","maxHeaderSize","noDelay","requireHostHeader","keepAlive","keepAliveInitialDelay","uniqueHeaders","backlog","socketTimeout"];function U(e){return e.reduce((e,t)=>({rawSize:e.rawSize+t.rawSize,bestSize:e.bestSize+t.bestSize,created:e.created+t.created}),{rawSize:0,bestSize:0,created:0})}const L=e=>e<2e3?`${e}B`.padStart(8," "):`${(e/1024).toFixed(1)}kB`.padStart(8," "),W=["none","ready","progress"];process.on("SIGUSR1",()=>{});let _=2;const F=(e,t)=>e<=_&&process.stderr.write(t+"\n");function Y(e){process.stdin.destroy(),F(0,e instanceof Error?e.message:String(e))}process.on("unhandledRejection",Y),process.on("uncaughtException",Y);const Z=process.stderr.isTTY&&!process.env.NO_COLOR?(e,t)=>e?`\x1b[${e}m${t}\x1b[0m`:t:(e,t)=>t,K=(e=>{const t=[];for(let o=0;o<e.length;++o){const s=e[o];if("--"===s)continue;const r=/^--([^ =\-][^ =]*)=(.*)$/.exec(s);if(r){t.push([r[1],r[2]]);continue}const i=/^-([^ =]*)([^ =])=(.*)$/.exec(s);if(i&&"-"!==s[1]){for(const e of i[1])t.push(["-"+e,""]);t.push(["-"+i[2],i[3]]);continue}if("-"!==s[0]||"-"===s){if(0!==o)throw new Error(`value without key: ${s}`);t.push(["",s]);continue}let n=e[o+1];if(n&&"-"===n[0]&&n.length>1&&(n=void 0),void 0!==n&&++o,"-"===s[1])t.push([s.slice(2),n??""]);else{for(const e of s.slice(1,s.length-1))t.push(["-"+e,""]);t.push(["-"+s[s.length-1],n??""])}}const o=new Map;for(const[e,s]of t){const t=(S.get(e)??e).toLowerCase(),r=z.get(t);if(!r)throw new Error(`unknown flag: ${e}`);let i;switch(r.type){case"string":i=s;break;case"number":i=Number.parseFloat(s);break;case"boolean":i=["","on","true","yes","y","1"].includes(s.toLowerCase())}if(r.multi){let e=o.get(t);e||(e=[],o.set(t,e)),e.push(i)}else{if(o.has(t))throw new Error(`multiple values for ${t}`);o.set(t,i)}}return o})(process.argv.slice(2));if(K.get("version")||K.get("help")){const s=JSON.parse(await e(t(o(new URL(import.meta.url).pathname),"package.json"),"utf-8"));process.stdout.write(`${s.name} ${s.version}\n`),K.get("help")&&process.stdout.write((Q=s.name,["","HTTP/1.1 server for Node.js","","Serves the current directory on port 8080 by default.","When running, send SIGINT (Ctrl+C) to stop.","Send SIGHUP or press enter to reload config.","",` npx ${Q} -- [dir] [flags]`,"","Options:"," --config-file=..., -c Path to a JSON configuration file to use (see below)"," --config-json=..., -C Inline JSON configuration to use (see below)",' --port=..., -p The port to bind to. Default "8080"',' --host=..., -a The host address to bind to. Default "localhost"',' --dir=... The directory to serve. Default "."'," --ext=... Implicit file extension to attempt if the requested file"," does not exist (can be specified multiple times)"," --404=... File to use for file-not-found, with status 404"," --spa=... File to use for file-not-found, with status 200"," (e.g. to serve an index file for Single-Page-Apps)"," --zstd, --zst Serve .zst files if zstd compression is requested"," --brotli, --br, -b Serve .br files if brotli compression is requested"," --gzip, --gz, -g Serve .gz files if gzip compression is requested"," --deflate Serve .deflate files if deflate compression is requested"," --proxy=..., -P Proxy requests which match no files to this server"," --mime=... Extra file-extension-to-mime-types to use, in the format",' "ext1=mime1;ext2=mime2" (e.g. "txt=text/plain")'," --mime-types=... Path to an Apache .types file of mime types to register"," --write-compressed Generate and save zstd, brotli, gzip, or deflate files"," for each served file before starting"," --min-compress=... The minimum number of bytes that compression must save,",' otherwise the file is not written. Default "300"'," --no-serve Stop after validating the configuration and optionally"," writing any compressed files",' --log=... "none" / "ready" / "progress" / "full". Set the logging',' level. "ready" prints only the "all servers ready" line,',' "progress" prints server startup and shutdown progress,',' and "full" logs all requests. Default "full"'," --help, -h Print this message and exit"," --version, -v Print the current version and exit","","JSON Configuration:","","JSON offers a more powerful way to configure the server. You can define one or","more servers (one per port), each with its own set of mounted handlers.","Example definition:",""," {",' "servers": ['," {",' "port": 9000,',' "mount": [',' { "type": "files", "dir": "." }',' { "type": "fixture", "method": "GET", "path": "/hello.txt", "body": "Hi!" }',' { "type": "proxy", "target": "https://example.com" }'," ]"," }"," ],",' "mime": ["foo=application/x-foo"],'," }","","All CLI flags are compatible with JSON configuration except --dir and --proxy.","--port is not compatible with JSON configurations with more than one server.","","MIME definitions:","","When defining mime types, some shorthands are available:","- multiple mappings separated by semicolons: foo=text/x-foo;bar=text/x-bar","- multiple file extensions separated by commas: foo,bar=text/plain","- use the file extension in the mime type with {ext}: css,csv=text/{ext}","- optional parts in brackets: jp(e)g,tif(f)=image/{ext}"," ({ext} always maps to the full name, so the example maps .jpg to image/jpeg)","","When using an apache .types file, each line contains a mime type, any amount of","whitespace, then a list of space-separated extensions (without a dot). Lines","starting with # are ignored as comments.","","Example usage:","",` npx ${Q} . --port 3000 --gzip --mime="foo=text/x-foo" --mime="bar=text/x-bar"`,"",` npx ${Q} /dev/null --proxy https://example.com`,"",` npx ${Q} -C '{"servers":[{"port":8080,"mount":[{"type":"files","dir":"."}]}]}'`,"",` npx ${Q} . --write-compressed --min-compress 500 --brotli --gzip`,"",` npx ${Q} . --write-compressed --brotli --no-serve`]).join("\n")+"\n"),process.exit(0)}var Q;(async()=>{const s=new G(F,Z);process.on("unhandledRejection",()=>s.shutdown()),process.on("uncaughtException",()=>s.shutdown());const r=function(e){const t=o=>{const s=o.$ref;if(s&&s.startsWith("#/$defs/")){const t=D(e.$defs,s.substring(8));if(!t)throw new Error(`unable to find ${s} in schema`);o={...t,...o}}const r=((e,t)=>{if(void 0!==e.const)return k(e.const);if(e.enum)return N(new Set(e.enum));if(e.anyOf)return O(e.anyOf.map(t));switch(e.type){case"array":return E(t(e.items));case"boolean":return P;case"integer":return T(!0,e.minimum,e.maximum);case"number":return T(!1,e.minimum,e.maximum);case"object":const o=e.additionalProperties??!0;return A(new Map(Object.entries(e.properties??{}).map(([e,o])=>[e,t(o)])),"object"==typeof o?t(o):o?I:q,e.required??[]);case"string":let s=null;return e.pattern&&(s=new RegExp(e.pattern)),J(s,e.format??"");default:throw new Error(`unknown part type ${JSON.stringify(e)}`)}})(o,t);if(void 0!==o.default){const e=JSON.stringify(o.default);return(t,o)=>r(void 0===t?JSON.parse(e):t,o)}return(e,t)=>void 0===e?void 0:r(e,t)};return t(e)}(await(async()=>JSON.parse(await e(t(o(new URL(import.meta.url).pathname),"schema.json"),"utf-8")))());function i(){process.stdin.destroy(),s.shutdown()}async function n(){const t=await(async(t,o)=>{const s=e=>o.get(e)??[],r=e=>o.get(e),i=e=>o.get(e),n=r("config-file"),a=r("config-json"),c=i("port"),f=r("host"),p=r("dir")||".",l=s("ext").map(e=>e.startsWith(".")?e:`.${e}`),h=r("404"),u=r("spa"),m=r("proxy"),d=i("min-compress"),g=s("mime"),w=s("mime-types"),y=r("log");if(Number(Boolean(n))+Number(Boolean(a))+Number(Boolean(m))>1)throw new Error("multiple config files are not supported");let b;if(n)b=t(JSON.parse(await e(n,"utf-8")),{file:n,path:""});else if(a)b=t(JSON.parse(a),{file:"",path:""});else{let e;u?e={statusCode:200,filePath:u}:h&&(e={statusCode:404,filePath:h});const o=[{type:"files",dir:p,options:{fallback:e}}];m&&o.push({type:"proxy",target:m}),b=t({servers:[{port:8080,mount:o}]},{file:"",path:""})}const x=1===b.servers.length?b.servers[0]:void 0;if(void 0!==c){if((0|c)!==c)throw new Error("port must be an integer");if(!x)throw new Error("cannot specify port on commandline when defining multiple servers");x.port=c}if(void 0!==f)for(const e of b.servers)e.host=f;const $=(e,t)=>{for(const o of b.servers)for(const s of o.mount)if("files"===s.type){s.options.negotiation??=[];let o=s.options.negotiation.find(t=>t.type===e);o||(o={type:e,options:[]},s.options.negotiation=[...s.options.negotiation,o]),o.options.find(e=>e.match===t.match)||o.options.push(t)}};for(const[e,t]of j)o.get(e)&&$("encoding",t);if(l.length)for(const e of b.servers)for(const t of e.mount)"files"===t.type&&(t.options.implicitSuffixes=l);switch((g.length||w.length)&&(Array.isArray(b.mime)||(b.mime?b.mime=[b.mime]:b.mime=[]),b.mime.push(...g),b.mime.push(...w.map(e=>`file://${e}`))),o.get("write-compressed")&&(b.writeCompressed=!0),void 0!==d&&(b.minCompress=d),o.get("no-serve")&&(b.noServe=!0),y){case"none":case"ready":case"progress":b.log=y;for(const e of b.servers)e.options.logRequests=!1;break;case"full":b.log="progress"}return b})(r,K);_=W.indexOf(t.log),await(async t=>{const o=[];for(const s of Array.isArray(t)?t:[t])"string"!=typeof s?o.push(new Map(Object.entries(s))):s.startsWith("file://")?o.push(b(await e(s.substring(7),"utf-8"))):o.push(x(s));$();for(const e of o)v(e)})(t.mime),t.writeCompressed&&await(async(e,t,o)=>{let s=0;for(const r of e)for(const e of r.mount)if("files"===e.type){const r=e.options.negotiation?.find(e=>"encoding"===e.type)?.options;if(!r?.length){o(2,`skipping ${e.dir} because no compression is configured`);continue}o(2,`compressing files in ${e.dir} using ${r.map(e=>e.match).join(", ")}`);const i=await y(e.dir,r,{minCompression:t}),n=U(i.filter(({mime:e})=>e.startsWith("text/"))),a=U(i.filter(({mime:e})=>!e.startsWith("text/")));o(2,`text: ${L(n.rawSize)} / ${L(n.bestSize)} compressed`),o(2,`other: ${L(a.rawSize)} / ${L(a.bestSize)} compressed`),s+=n.created+a.created}o(2,`${((e,t,o=t+"s")=>1===e?`1 ${t}`:`${e} ${o}`)(s,"compressed file")} written`)})(t.servers,t.minCompress,F),t.noServe?i():s.set(t.servers)}function a(){return F(2,"refreshing config"),n()}n(),process.on("SIGHUP",()=>a()),process.stdin.on("data",e=>{e.includes("\n")&&a()}),process.on("SIGINT",()=>{F(2,""),i()})})();
|