srvx 0.11.7 → 0.11.9
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/dist/_chunks/_plugins.mjs +4 -0
- package/dist/_chunks/_url.mjs +20 -0
- package/dist/_chunks/_utils.mjs +2 -0
- package/dist/_chunks/_utils2.mjs +2 -0
- package/dist/_chunks/loader.d.mts +87 -0
- package/dist/adapters/aws-lambda.mjs +5 -0
- package/dist/adapters/bun.mjs +3 -0
- package/dist/adapters/bunny.mjs +3 -0
- package/dist/adapters/cloudflare.mjs +3 -0
- package/dist/adapters/deno.mjs +3 -0
- package/dist/adapters/generic.mjs +3 -0
- package/dist/adapters/node.mjs +71 -1
- package/dist/adapters/service-worker.mjs +3 -0
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +11 -1
- package/dist/loader.d.mts +1 -86
- package/dist/loader.mjs +2 -0
- package/dist/log.mjs +2 -0
- package/dist/static.mjs +4 -2
- package/dist/tracing.mjs +23 -0
- package/package.json +14 -14
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as green, i as gray, n as bold, s as red } from "./_utils.mjs";
|
|
2
|
+
//#region src/_middleware.ts
|
|
2
3
|
function wrapFetch(server) {
|
|
3
4
|
const fetchHandler = server.options.fetch;
|
|
4
5
|
const middleware = server.options.middleware || [];
|
|
@@ -8,6 +9,8 @@ function callMiddleware(request, fetchHandler, middleware, index) {
|
|
|
8
9
|
if (index === middleware.length) return fetchHandler(request);
|
|
9
10
|
return middleware[index](request, () => callMiddleware(request, fetchHandler, middleware, index + 1));
|
|
10
11
|
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/_plugins.ts
|
|
11
14
|
const errorPlugin = (server) => {
|
|
12
15
|
const errorHandler = server.options.error;
|
|
13
16
|
if (!errorHandler) return;
|
|
@@ -53,4 +56,5 @@ const gracefulShutdownPlugin = (server) => {
|
|
|
53
56
|
};
|
|
54
57
|
for (const sig of ["SIGINT", "SIGTERM"]) globalThis.process.on(sig, shutdown);
|
|
55
58
|
};
|
|
59
|
+
//#endregion
|
|
56
60
|
export { gracefulShutdownPlugin as n, wrapFetch as r, errorPlugin as t };
|
package/dist/_chunks/_url.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/_inherit.ts
|
|
1
2
|
function lazyInherit(target, source, sourceKey) {
|
|
2
3
|
for (const key of [...Object.getOwnPropertyNames(source), ...Object.getOwnPropertySymbols(source)]) {
|
|
3
4
|
if (key === "constructor") continue;
|
|
@@ -25,6 +26,23 @@ function lazyInherit(target, source, sourceKey) {
|
|
|
25
26
|
if (modified) Object.defineProperty(target, key, desc);
|
|
26
27
|
}
|
|
27
28
|
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/_url.ts
|
|
31
|
+
const _needsNormRE = /(?:(?:^|\/)(?:\.|\.\.|%2e|%2e\.|\.%2e|%2e%2e)(?:\/|$))|[\\^\x80-\uffff]/i;
|
|
32
|
+
/**
|
|
33
|
+
* URL wrapper with fast paths to access to the following props:
|
|
34
|
+
*
|
|
35
|
+
* - `url.pathname`
|
|
36
|
+
* - `url.search`
|
|
37
|
+
* - `url.searchParams`
|
|
38
|
+
* - `url.protocol`
|
|
39
|
+
*
|
|
40
|
+
* **NOTES:**
|
|
41
|
+
*
|
|
42
|
+
* - It is assumed that the input URL is **already encoded** and formatted from an HTTP request and contains no hash.
|
|
43
|
+
* - Triggering the setters or getters on other props will deoptimize to full URL parsing.
|
|
44
|
+
* - Changes to `searchParams` will be discarded as we don't track them.
|
|
45
|
+
*/
|
|
28
46
|
const FastURL = /* @__PURE__ */ (() => {
|
|
29
47
|
const NativeURL = globalThis.URL;
|
|
30
48
|
const FastURL = class URL {
|
|
@@ -38,6 +56,7 @@ const FastURL = /* @__PURE__ */ (() => {
|
|
|
38
56
|
#pos;
|
|
39
57
|
constructor(url) {
|
|
40
58
|
if (typeof url === "string") this.#href = url;
|
|
59
|
+
else if (_needsNormRE.test(url.pathname)) this.#url = new NativeURL(`${url.protocol || "http:"}//${url.host || "localhost"}${url.pathname}${url.search || ""}`);
|
|
41
60
|
else {
|
|
42
61
|
this.#protocol = url.protocol;
|
|
43
62
|
this.#host = url.host;
|
|
@@ -123,4 +142,5 @@ const FastURL = /* @__PURE__ */ (() => {
|
|
|
123
142
|
Object.setPrototypeOf(FastURL, NativeURL);
|
|
124
143
|
return FastURL;
|
|
125
144
|
})();
|
|
145
|
+
//#endregion
|
|
126
146
|
export { lazyInherit as n, FastURL as t };
|
package/dist/_chunks/_utils.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/cli/_utils.ts
|
|
1
2
|
const noColor = /* @__PURE__ */ (() => {
|
|
2
3
|
const env = globalThis.process?.env ?? {};
|
|
3
4
|
return env.NO_COLOR === "1" || env.TERM === "dumb";
|
|
@@ -12,4 +13,5 @@ const magenta = /* @__PURE__ */ _c(35);
|
|
|
12
13
|
const cyan = /* @__PURE__ */ _c(36);
|
|
13
14
|
const gray = /* @__PURE__ */ _c(90);
|
|
14
15
|
const url = (title, url) => noColor ? `[${title}](${url})` : `\u001B]8;;${url}\u001B\\${title}\u001B]8;;\u001B\\`;
|
|
16
|
+
//#endregion
|
|
15
17
|
export { green as a, url as c, gray as i, yellow as l, bold as n, magenta as o, cyan as r, red as s, blue as t };
|
package/dist/_chunks/_utils2.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/_utils.ts
|
|
1
2
|
function resolvePortAndHost(opts) {
|
|
2
3
|
const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
|
|
3
4
|
const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
|
|
@@ -67,4 +68,5 @@ function createWaitUntil() {
|
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
}
|
|
71
|
+
//#endregion
|
|
70
72
|
export { resolveTLSOptions as a, resolvePortAndHost as i, fmtURL as n, printListening as r, createWaitUntil as t };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Server, ServerHandler } from "srvx";
|
|
2
|
+
|
|
3
|
+
//#region src/loader.d.ts
|
|
4
|
+
declare const defaultExts: string[];
|
|
5
|
+
declare const defaultEntries: string[];
|
|
6
|
+
/**
|
|
7
|
+
* Options for loading a server entry module.
|
|
8
|
+
*/
|
|
9
|
+
type LoadOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* Path or URL to the server entry file.
|
|
12
|
+
*
|
|
13
|
+
* If not provided, common entry points will be searched automatically.
|
|
14
|
+
*/
|
|
15
|
+
entry?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Base directory for resolving relative paths.
|
|
18
|
+
*
|
|
19
|
+
* @default "."
|
|
20
|
+
*/
|
|
21
|
+
dir?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Set to `false` to disable interception of `http.Server.listen` to detect legacy handlers.
|
|
24
|
+
*
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
interceptHttpListen?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Set to `false` to disable Node.js handler (req, res) compatibility.
|
|
30
|
+
*/
|
|
31
|
+
nodeCompat?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Node.js server instance to return when intercepting `http.Server.listen`.
|
|
34
|
+
*/
|
|
35
|
+
nodeServer?: NodeServer;
|
|
36
|
+
/**
|
|
37
|
+
* srvx server instance to return when intercepting `http.Server.listen`.
|
|
38
|
+
*/
|
|
39
|
+
srvxServer?: Server;
|
|
40
|
+
/**
|
|
41
|
+
* Hook called after the module is loaded to allow for custom processing.
|
|
42
|
+
*
|
|
43
|
+
* You can return a modified version of the module if needed.
|
|
44
|
+
*/
|
|
45
|
+
onLoad?: (module: unknown) => any;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Result of loading a server entry module.
|
|
49
|
+
*/
|
|
50
|
+
type LoadedServerEntry = {
|
|
51
|
+
/**
|
|
52
|
+
* The web fetch handler extracted from the loaded module.
|
|
53
|
+
*
|
|
54
|
+
* This is resolved from `module.fetch`, `module.default.fetch`,
|
|
55
|
+
* or upgraded from a legacy Node.js handler.
|
|
56
|
+
*/
|
|
57
|
+
fetch?: ServerHandler;
|
|
58
|
+
/**
|
|
59
|
+
* The raw loaded module.
|
|
60
|
+
*/
|
|
61
|
+
module?: any;
|
|
62
|
+
/**
|
|
63
|
+
* Whether the handler was upgraded from a legacy Node.js HTTP handler.
|
|
64
|
+
*
|
|
65
|
+
* When `true`, the original module exported a Node.js-style `(req, res)` handler
|
|
66
|
+
* that has been wrapped for web fetch compatibility.
|
|
67
|
+
*/
|
|
68
|
+
nodeCompat?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The resolved `file://` URL of the loaded entry module.
|
|
71
|
+
*/
|
|
72
|
+
url?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the specified entry file was not found.
|
|
75
|
+
*
|
|
76
|
+
* When `true`, no valid entry point could be located.
|
|
77
|
+
*/
|
|
78
|
+
notFound?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* The original srvx server instance if the module used the loader API to export a server directly.
|
|
81
|
+
*/
|
|
82
|
+
srvxServer?: Server;
|
|
83
|
+
};
|
|
84
|
+
declare function loadServerEntry(opts: LoadOptions): Promise<LoadedServerEntry>;
|
|
85
|
+
type NodeServer = NonNullable<Server["node"]>["server"];
|
|
86
|
+
//#endregion
|
|
87
|
+
export { loadServerEntry as a, defaultExts as i, LoadedServerEntry as n, defaultEntries as r, LoadOptions as t };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
3
|
+
//#region src/adapters/_aws/utils.ts
|
|
2
4
|
function awsRequest(event, context) {
|
|
3
5
|
const req = new Request(awsEventURL(event), {
|
|
4
6
|
method: awsEventMethod(event),
|
|
@@ -249,6 +251,8 @@ function createMockContext() {
|
|
|
249
251
|
succeed: () => {}
|
|
250
252
|
};
|
|
251
253
|
}
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/adapters/aws-lambda.ts
|
|
252
256
|
function toLambdaHandler(options) {
|
|
253
257
|
const server = new AWSLambdaServer(options);
|
|
254
258
|
return (event, context) => server.fetch(event, context);
|
|
@@ -289,4 +293,5 @@ var AWSLambdaServer = class {
|
|
|
289
293
|
return Promise.resolve();
|
|
290
294
|
}
|
|
291
295
|
};
|
|
296
|
+
//#endregion
|
|
292
297
|
export { handleLambdaEvent, handleLambdaEventWithStream, invokeLambdaHandler, toLambdaHandler };
|
package/dist/adapters/bun.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { t as FastURL } from "../_chunks/_url.mjs";
|
|
2
3
|
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
|
3
4
|
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
|
|
5
|
+
//#region src/adapters/bun.ts
|
|
4
6
|
const FastResponse = Response;
|
|
5
7
|
function serve(options) {
|
|
6
8
|
return new BunServer(options);
|
|
@@ -83,4 +85,5 @@ var BunServer = class {
|
|
|
83
85
|
await Promise.all([this.#wait?.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
|
|
84
86
|
}
|
|
85
87
|
};
|
|
88
|
+
//#endregion
|
|
86
89
|
export { FastResponse, FastURL, serve };
|
package/dist/adapters/bunny.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
3
|
+
//#region src/adapters/bunny.ts
|
|
2
4
|
const FastURL = URL;
|
|
3
5
|
const FastResponse = Response;
|
|
4
6
|
function serve(options) {
|
|
@@ -51,4 +53,5 @@ var BunnyServer = class {
|
|
|
51
53
|
return Promise.resolve();
|
|
52
54
|
}
|
|
53
55
|
};
|
|
56
|
+
//#endregion
|
|
54
57
|
export { FastResponse, FastURL, serve };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
3
|
+
//#region src/adapters/cloudflare.ts
|
|
2
4
|
const FastURL = URL;
|
|
3
5
|
const FastResponse = Response;
|
|
4
6
|
function serve(options) {
|
|
@@ -54,4 +56,5 @@ var CloudflareServer = class {
|
|
|
54
56
|
return Promise.resolve();
|
|
55
57
|
}
|
|
56
58
|
};
|
|
59
|
+
//#endregion
|
|
57
60
|
export { FastResponse, FastURL, serve };
|
package/dist/adapters/deno.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { t as FastURL } from "../_chunks/_url.mjs";
|
|
2
3
|
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
|
3
4
|
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
|
|
5
|
+
//#region src/adapters/deno.ts
|
|
4
6
|
const FastResponse = Response;
|
|
5
7
|
function serve(options) {
|
|
6
8
|
return new DenoServer(options);
|
|
@@ -92,4 +94,5 @@ var DenoServer = class {
|
|
|
92
94
|
await Promise.all([this.#wait?.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
|
|
93
95
|
}
|
|
94
96
|
};
|
|
97
|
+
//#endregion
|
|
95
98
|
export { FastResponse, FastURL, serve };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
|
2
3
|
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
4
|
+
//#region src/adapters/generic.ts
|
|
3
5
|
const FastURL = URL;
|
|
4
6
|
const FastResponse = Response;
|
|
5
7
|
function serve(options) {
|
|
@@ -34,4 +36,5 @@ var GenericServer = class {
|
|
|
34
36
|
await this.#wait.wait();
|
|
35
37
|
}
|
|
36
38
|
};
|
|
39
|
+
//#endregion
|
|
37
40
|
export { FastResponse, FastURL, serve };
|
package/dist/adapters/node.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { n as lazyInherit, t as FastURL } from "../_chunks/_url.mjs";
|
|
2
3
|
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
|
3
4
|
import { n as gracefulShutdownPlugin, r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
@@ -5,6 +6,7 @@ import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";
|
|
|
5
6
|
import { Duplex, PassThrough, Readable } from "node:stream";
|
|
6
7
|
import nodeHTTPS from "node:https";
|
|
7
8
|
import nodeHTTP2 from "node:http2";
|
|
9
|
+
//#region src/adapters/_node/send.ts
|
|
8
10
|
async function sendNodeResponse(nodeRes, webRes) {
|
|
9
11
|
if (!webRes) {
|
|
10
12
|
nodeRes.statusCode = 500;
|
|
@@ -62,6 +64,13 @@ function streamBody(stream, nodeRes) {
|
|
|
62
64
|
nodeRes.off("error", streamCancel);
|
|
63
65
|
});
|
|
64
66
|
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/adapters/_node/url.ts
|
|
69
|
+
/**
|
|
70
|
+
* Validates an HTTP Host header value (domain, IPv4, or bracketed IPv6) with optional port.
|
|
71
|
+
* Intended for preliminary filtering invalid values like "localhost:3000/foobar?"
|
|
72
|
+
*/
|
|
73
|
+
const HOST_RE = /^(\[(?:[A-Fa-f0-9:.]+)\]|(?:[A-Za-z0-9_-]+\.)*[A-Za-z0-9_-]+|(?:\d{1,3}\.){3}\d{1,3})(:\d{1,5})?$/;
|
|
65
74
|
var NodeRequestURL = class extends FastURL {
|
|
66
75
|
#req;
|
|
67
76
|
constructor({ req }) {
|
|
@@ -70,7 +79,11 @@ var NodeRequestURL = class extends FastURL {
|
|
|
70
79
|
const qIndex = path.indexOf("?");
|
|
71
80
|
const pathname = qIndex === -1 ? path : path?.slice(0, qIndex) || "/";
|
|
72
81
|
const search = qIndex === -1 ? "" : path?.slice(qIndex) || "";
|
|
73
|
-
|
|
82
|
+
let host = req.headers.host || req.headers[":authority"];
|
|
83
|
+
if (host) {
|
|
84
|
+
if (!HOST_RE.test(host)) throw new TypeError(`Invalid host header: ${host}`);
|
|
85
|
+
} else if (req.socket) host = `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
|
|
86
|
+
else host = "localhost";
|
|
74
87
|
const protocol = req.socket?.encrypted || req.headers["x-forwarded-proto"] === "https" || req.headers[":scheme"] === "https" ? "https:" : "http:";
|
|
75
88
|
super({
|
|
76
89
|
protocol,
|
|
@@ -89,6 +102,8 @@ var NodeRequestURL = class extends FastURL {
|
|
|
89
102
|
this.#req.url = this._url.pathname + this._url.search;
|
|
90
103
|
}
|
|
91
104
|
};
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/adapters/_node/headers.ts
|
|
92
107
|
const NodeRequestHeaders = /* @__PURE__ */ (() => {
|
|
93
108
|
const NativeHeaders = globalThis.Headers;
|
|
94
109
|
class Headers {
|
|
@@ -150,6 +165,8 @@ const NodeRequestHeaders = /* @__PURE__ */ (() => {
|
|
|
150
165
|
Object.setPrototypeOf(Headers.prototype, NativeHeaders.prototype);
|
|
151
166
|
return Headers;
|
|
152
167
|
})();
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/adapters/_node/request.ts
|
|
153
170
|
const NodeRequest = /* @__PURE__ */ (() => {
|
|
154
171
|
const NativeRequest = globalThis.Request;
|
|
155
172
|
class Request {
|
|
@@ -248,6 +265,13 @@ const NodeRequest = /* @__PURE__ */ (() => {
|
|
|
248
265
|
Object.setPrototypeOf(Request.prototype, NativeRequest.prototype);
|
|
249
266
|
return Request;
|
|
250
267
|
})();
|
|
268
|
+
/**
|
|
269
|
+
* Undici uses an incompatible Request constructor depending on private property accessors.
|
|
270
|
+
*
|
|
271
|
+
* This utility, patches global Request to support `new Request(req)` in Node.js.
|
|
272
|
+
*
|
|
273
|
+
* Alternatively you can use `new Request(req._request || req)` instead of patching global Request.
|
|
274
|
+
*/
|
|
251
275
|
function patchGlobalRequest() {
|
|
252
276
|
const NativeRequest = globalThis[Symbol.for("srvx.nativeRequest")] ??= globalThis.Request;
|
|
253
277
|
const PatchedRequest = class Request extends NativeRequest {
|
|
@@ -282,6 +306,13 @@ function readBody(req) {
|
|
|
282
306
|
req.on("data", onData).once("end", onEnd).once("error", onError);
|
|
283
307
|
});
|
|
284
308
|
}
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/adapters/_node/response.ts
|
|
311
|
+
/**
|
|
312
|
+
* Fast Response for Node.js runtime
|
|
313
|
+
*
|
|
314
|
+
* It is faster because in most cases it doesn't create a full Response instance.
|
|
315
|
+
*/
|
|
285
316
|
const NodeResponse = /* @__PURE__ */ (() => {
|
|
286
317
|
const NativeResponse = globalThis.Response;
|
|
287
318
|
const STATUS_CODES = globalThis.process?.getBuiltinModule?.("node:http")?.STATUS_CODES || {};
|
|
@@ -390,6 +421,13 @@ const NodeResponse = /* @__PURE__ */ (() => {
|
|
|
390
421
|
Object.setPrototypeOf(NodeResponse.prototype, NativeResponse.prototype);
|
|
391
422
|
return NodeResponse;
|
|
392
423
|
})();
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/adapters/_node/web/socket.ts
|
|
426
|
+
/**
|
|
427
|
+
* Events:
|
|
428
|
+
* - Readable (req from client): readable => data => end (push(null)) => error => close
|
|
429
|
+
* - Writable (res to client): pipe => unpipe => drain => finish (end called) => error => close
|
|
430
|
+
*/
|
|
393
431
|
var WebRequestSocket = class extends Duplex {
|
|
394
432
|
_httpMessage;
|
|
395
433
|
autoSelectFamilyAttemptedAddresses = [];
|
|
@@ -505,6 +543,8 @@ var WebRequestSocket = class extends Duplex {
|
|
|
505
543
|
cb(err ?? void 0);
|
|
506
544
|
}
|
|
507
545
|
};
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/adapters/_node/web/incoming.ts
|
|
508
548
|
var WebIncomingMessage = class extends IncomingMessage {
|
|
509
549
|
constructor(req, socket) {
|
|
510
550
|
super(socket);
|
|
@@ -523,6 +563,8 @@ var WebIncomingMessage = class extends IncomingMessage {
|
|
|
523
563
|
});
|
|
524
564
|
}
|
|
525
565
|
};
|
|
566
|
+
//#endregion
|
|
567
|
+
//#region src/adapters/_node/call.ts
|
|
526
568
|
function callNodeHandler(handler, req) {
|
|
527
569
|
const isMiddleware = handler.length > 2;
|
|
528
570
|
const nodeCtx = req.runtime?.node;
|
|
@@ -566,6 +608,8 @@ function callNodeHandler(handler, req) {
|
|
|
566
608
|
}
|
|
567
609
|
});
|
|
568
610
|
}
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/adapters/_node/web/response.ts
|
|
569
613
|
var WebServerResponse = class extends ServerResponse {
|
|
570
614
|
#socket;
|
|
571
615
|
constructor(req, socket) {
|
|
@@ -604,6 +648,19 @@ var WebServerResponse = class extends ServerResponse {
|
|
|
604
648
|
});
|
|
605
649
|
}
|
|
606
650
|
};
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/adapters/_node/web/fetch.ts
|
|
653
|
+
/**
|
|
654
|
+
* Calls a Node.js HTTP Request handler with a Fetch API Request object and returns a Response object.
|
|
655
|
+
*
|
|
656
|
+
* If the web Request contains an existing Node.js req/res pair (indicating it originated from a Node.js server from srvx/node), it will be called directly.
|
|
657
|
+
*
|
|
658
|
+
* Otherwise, new Node.js IncomingMessage and ServerResponse objects are created and linked to a custom Duplex stream that bridges the Fetch API streams with Node.js streams.
|
|
659
|
+
*
|
|
660
|
+
* The handler is invoked with these objects, and the response is constructed from the ServerResponse once it is finished.
|
|
661
|
+
*
|
|
662
|
+
* @experimental Behavior might be unstable.
|
|
663
|
+
*/
|
|
607
664
|
async function fetchNodeHandler(handler, req) {
|
|
608
665
|
const nodeRuntime = req.runtime?.node;
|
|
609
666
|
if (nodeRuntime && nodeRuntime.req && nodeRuntime.res) return await callNodeHandler(handler, req);
|
|
@@ -624,6 +681,11 @@ async function fetchNodeHandler(handler, req) {
|
|
|
624
681
|
});
|
|
625
682
|
}
|
|
626
683
|
}
|
|
684
|
+
//#endregion
|
|
685
|
+
//#region src/adapters/_node/adapter.ts
|
|
686
|
+
/**
|
|
687
|
+
* Converts a Fetch API handler to a Node.js HTTP handler.
|
|
688
|
+
*/
|
|
627
689
|
function toNodeHandler(handler) {
|
|
628
690
|
if (handler.__nodeHandler) return handler.__nodeHandler;
|
|
629
691
|
function convertedNodeHandler(nodeReq, nodeRes) {
|
|
@@ -637,6 +699,11 @@ function toNodeHandler(handler) {
|
|
|
637
699
|
assignFnName(convertedNodeHandler, handler, " (converted to Node handler)");
|
|
638
700
|
return convertedNodeHandler;
|
|
639
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Converts a Node.js HTTP handler into a Fetch API handler.
|
|
704
|
+
*
|
|
705
|
+
* @experimental Behavior might be unstable and won't work in Bun and Deno currently (tracker: https://github.com/h3js/srvx/issues/132)
|
|
706
|
+
*/
|
|
640
707
|
function toFetchHandler(handler) {
|
|
641
708
|
if (handler.__fetchHandler) return handler.__fetchHandler;
|
|
642
709
|
function convertedNodeHandler(req) {
|
|
@@ -651,6 +718,8 @@ function assignFnName(target, source, suffix) {
|
|
|
651
718
|
Object.defineProperty(target, "name", { value: `${source.name}${suffix}` });
|
|
652
719
|
} catch {}
|
|
653
720
|
}
|
|
721
|
+
//#endregion
|
|
722
|
+
//#region src/adapters/node.ts
|
|
654
723
|
function serve(options) {
|
|
655
724
|
return new NodeServer(options);
|
|
656
725
|
}
|
|
@@ -744,4 +813,5 @@ var NodeServer = class {
|
|
|
744
813
|
})]);
|
|
745
814
|
}
|
|
746
815
|
};
|
|
816
|
+
//#endregion
|
|
747
817
|
export { NodeResponse as FastResponse, NodeResponse, FastURL, NodeRequest, fetchNodeHandler, patchGlobalRequest, sendNodeResponse, serve, toFetchHandler, toNodeHandler };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import "../_chunks/_utils.mjs";
|
|
1
2
|
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
3
|
+
//#region src/adapters/service-worker.ts
|
|
2
4
|
const FastURL = URL;
|
|
3
5
|
const FastResponse = Response;
|
|
4
6
|
const isBrowserWindow = typeof window !== "undefined" && typeof navigator !== "undefined";
|
|
@@ -73,4 +75,5 @@ var ServiceWorkerServer = class {
|
|
|
73
75
|
} else if (isServiceWorker) await self.registration.unregister();
|
|
74
76
|
}
|
|
75
77
|
};
|
|
78
|
+
//#endregion
|
|
76
79
|
export { FastResponse, FastURL, serve };
|
package/dist/cli.d.mts
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { fork } from "node:child_process";
|
|
|
6
6
|
import { createReadStream, existsSync, statSync } from "node:fs";
|
|
7
7
|
import { dirname, relative, resolve } from "node:path";
|
|
8
8
|
import { Readable } from "node:stream";
|
|
9
|
+
//#region src/cli/serve.ts
|
|
9
10
|
const NO_ENTRY_ERROR = "No server entry or public directory found";
|
|
10
11
|
async function cliServe(cliOpts) {
|
|
11
12
|
try {
|
|
@@ -88,6 +89,8 @@ function printInfo(cliOpts, loaded) {
|
|
|
88
89
|
console.log(gray(`${bold(gray("◇"))} Static files: ${staticInfo}`));
|
|
89
90
|
console.log("");
|
|
90
91
|
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/cli/fetch.ts
|
|
91
94
|
async function cliFetch(cliOpts) {
|
|
92
95
|
const stdin = cliOpts.stdin || process.stdin;
|
|
93
96
|
const stdout = cliOpts.stdout || process.stdout;
|
|
@@ -177,11 +180,15 @@ function getResponseFormat(res) {
|
|
|
177
180
|
encoding: contentType.includes("charset=") ? contentType.split("charset=")[1].split(";")[0].trim() : "utf8"
|
|
178
181
|
};
|
|
179
182
|
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/cli/_meta.ts
|
|
180
185
|
const srvxMeta = {
|
|
181
186
|
name: "srvx",
|
|
182
|
-
version: "0.11.
|
|
187
|
+
version: "0.11.9",
|
|
183
188
|
description: "Universal Server."
|
|
184
189
|
};
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/cli/usage.ts
|
|
185
192
|
function usage(mainOpts) {
|
|
186
193
|
const command = mainOpts.usage?.command || "srvx";
|
|
187
194
|
const name = mainOpts.meta?.name || srvxMeta.name;
|
|
@@ -247,6 +254,8 @@ ${mainOpts.usage?.docs ? `➤ ${url("Documentation", mainOpts.usage.docs)}` : ""
|
|
|
247
254
|
${mainOpts.usage?.issues ? `➤ ${url("Report issues", mainOpts.usage.issues)}` : ""}
|
|
248
255
|
`.trim();
|
|
249
256
|
}
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region src/cli/main.ts
|
|
250
259
|
async function main(mainOpts) {
|
|
251
260
|
const args = process.argv.slice(2);
|
|
252
261
|
const cliOpts = parseArgs$1(args);
|
|
@@ -423,4 +432,5 @@ function runtime() {
|
|
|
423
432
|
else if (process.versions.deno) return `deno ${process.versions.deno}`;
|
|
424
433
|
else return `node ${process.versions.node}`;
|
|
425
434
|
}
|
|
435
|
+
//#endregion
|
|
426
436
|
export { cliFetch, main };
|
package/dist/loader.d.mts
CHANGED
|
@@ -1,87 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/loader.d.ts
|
|
4
|
-
declare const defaultExts: string[];
|
|
5
|
-
declare const defaultEntries: string[];
|
|
6
|
-
/**
|
|
7
|
-
* Options for loading a server entry module.
|
|
8
|
-
*/
|
|
9
|
-
type LoadOptions = {
|
|
10
|
-
/**
|
|
11
|
-
* Path or URL to the server entry file.
|
|
12
|
-
*
|
|
13
|
-
* If not provided, common entry points will be searched automatically.
|
|
14
|
-
*/
|
|
15
|
-
entry?: string;
|
|
16
|
-
/**
|
|
17
|
-
* Base directory for resolving relative paths.
|
|
18
|
-
*
|
|
19
|
-
* @default "."
|
|
20
|
-
*/
|
|
21
|
-
dir?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Set to `false` to disable interception of `http.Server.listen` to detect legacy handlers.
|
|
24
|
-
*
|
|
25
|
-
* @default true
|
|
26
|
-
*/
|
|
27
|
-
interceptHttpListen?: boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Set to `false` to disable Node.js handler (req, res) compatibility.
|
|
30
|
-
*/
|
|
31
|
-
nodeCompat?: boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Node.js server instance to return when intercepting `http.Server.listen`.
|
|
34
|
-
*/
|
|
35
|
-
nodeServer?: NodeServer;
|
|
36
|
-
/**
|
|
37
|
-
* srvx server instance to return when intercepting `http.Server.listen`.
|
|
38
|
-
*/
|
|
39
|
-
srvxServer?: Server;
|
|
40
|
-
/**
|
|
41
|
-
* Hook called after the module is loaded to allow for custom processing.
|
|
42
|
-
*
|
|
43
|
-
* You can return a modified version of the module if needed.
|
|
44
|
-
*/
|
|
45
|
-
onLoad?: (module: unknown) => any;
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Result of loading a server entry module.
|
|
49
|
-
*/
|
|
50
|
-
type LoadedServerEntry = {
|
|
51
|
-
/**
|
|
52
|
-
* The web fetch handler extracted from the loaded module.
|
|
53
|
-
*
|
|
54
|
-
* This is resolved from `module.fetch`, `module.default.fetch`,
|
|
55
|
-
* or upgraded from a legacy Node.js handler.
|
|
56
|
-
*/
|
|
57
|
-
fetch?: ServerHandler;
|
|
58
|
-
/**
|
|
59
|
-
* The raw loaded module.
|
|
60
|
-
*/
|
|
61
|
-
module?: any;
|
|
62
|
-
/**
|
|
63
|
-
* Whether the handler was upgraded from a legacy Node.js HTTP handler.
|
|
64
|
-
*
|
|
65
|
-
* When `true`, the original module exported a Node.js-style `(req, res)` handler
|
|
66
|
-
* that has been wrapped for web fetch compatibility.
|
|
67
|
-
*/
|
|
68
|
-
nodeCompat?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* The resolved `file://` URL of the loaded entry module.
|
|
71
|
-
*/
|
|
72
|
-
url?: string;
|
|
73
|
-
/**
|
|
74
|
-
* Whether the specified entry file was not found.
|
|
75
|
-
*
|
|
76
|
-
* When `true`, no valid entry point could be located.
|
|
77
|
-
*/
|
|
78
|
-
notFound?: boolean;
|
|
79
|
-
/**
|
|
80
|
-
* The original srvx server instance if the module used the loader API to export a server directly.
|
|
81
|
-
*/
|
|
82
|
-
srvxServer?: Server;
|
|
83
|
-
};
|
|
84
|
-
declare function loadServerEntry(opts: LoadOptions): Promise<LoadedServerEntry>;
|
|
85
|
-
type NodeServer = NonNullable<Server["node"]>["server"];
|
|
86
|
-
//#endregion
|
|
1
|
+
import { a as loadServerEntry, i as defaultExts, n as LoadedServerEntry, r as defaultEntries, t as LoadOptions } from "./_chunks/loader.mjs";
|
|
87
2
|
export { LoadOptions, LoadedServerEntry, defaultEntries, defaultExts, loadServerEntry };
|
package/dist/loader.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import * as nodeHTTP$1 from "node:http";
|
|
5
5
|
import { EventEmitter } from "node:events";
|
|
6
|
+
//#region src/loader.ts
|
|
6
7
|
const defaultExts = [
|
|
7
8
|
".mjs",
|
|
8
9
|
".js",
|
|
@@ -135,4 +136,5 @@ var StubNodeServer = class extends EventEmitter {
|
|
|
135
136
|
return this;
|
|
136
137
|
}
|
|
137
138
|
};
|
|
139
|
+
//#endregion
|
|
138
140
|
export { defaultEntries, defaultExts, loadServerEntry };
|
package/dist/log.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as green, i as gray, l as yellow, n as bold, s as red, t as blue } from "./_chunks/_utils.mjs";
|
|
2
|
+
//#region src/log.ts
|
|
2
3
|
const statusColors = {
|
|
3
4
|
1: blue,
|
|
4
5
|
2: green,
|
|
@@ -14,4 +15,5 @@ const log = (_options = {}) => {
|
|
|
14
15
|
return res;
|
|
15
16
|
};
|
|
16
17
|
};
|
|
18
|
+
//#endregion
|
|
17
19
|
export { log };
|
package/dist/static.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { t as FastURL } from "./_chunks/_url.mjs";
|
|
2
2
|
import { createReadStream } from "node:fs";
|
|
3
|
-
import { extname, join, resolve } from "node:path";
|
|
3
|
+
import { extname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { readFile, stat } from "node:fs/promises";
|
|
5
5
|
import { FastResponse } from "srvx";
|
|
6
6
|
import { createBrotliCompress, createGzip } from "node:zlib";
|
|
7
|
+
//#region src/static.ts
|
|
7
8
|
const COMMON_MIME_TYPES = {
|
|
8
9
|
".html": "text/html",
|
|
9
10
|
".htm": "text/html",
|
|
@@ -28,7 +29,7 @@ const COMMON_MIME_TYPES = {
|
|
|
28
29
|
".pdf": "application/pdf"
|
|
29
30
|
};
|
|
30
31
|
const serveStatic = (options) => {
|
|
31
|
-
const dir = resolve(options.dir) +
|
|
32
|
+
const dir = resolve(options.dir) + sep;
|
|
32
33
|
const methods = new Set((options.methods || ["GET", "HEAD"]).map((m) => m.toUpperCase()));
|
|
33
34
|
return async (req, next) => {
|
|
34
35
|
if (!methods.has(req.method)) return next();
|
|
@@ -71,4 +72,5 @@ const serveStatic = (options) => {
|
|
|
71
72
|
return next();
|
|
72
73
|
};
|
|
73
74
|
};
|
|
75
|
+
//#endregion
|
|
74
76
|
export { serveStatic };
|
package/dist/tracing.mjs
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
//#region src/tracing.ts
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @experimental Channel names, event types and config options may change in future releases.
|
|
5
|
+
*
|
|
6
|
+
* Tracing plugin that adds diagnostics channel tracing to middleware and fetch handlers.
|
|
7
|
+
*
|
|
8
|
+
* This plugin wraps all middleware and the fetch handler with tracing instrumentation,
|
|
9
|
+
* allowing you to subscribe to `srvx.request` and `srvx.middleware` tracing channels.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { serve } from "srvx";
|
|
14
|
+
* import { tracingPlugin } from "srvx/tracing";
|
|
15
|
+
*
|
|
16
|
+
* const server = serve({
|
|
17
|
+
* fetch: (req) => new Response("OK"),
|
|
18
|
+
* middleware: [myMiddleware],
|
|
19
|
+
* plugins: [tracingPlugin()],
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
1
23
|
function tracingPlugin(opts = {}) {
|
|
2
24
|
return (server) => {
|
|
3
25
|
const { tracingChannel } = globalThis.process?.getBuiltinModule?.("node:diagnostics_channel") || {};
|
|
@@ -31,4 +53,5 @@ function tracingPlugin(opts = {}) {
|
|
|
31
53
|
}
|
|
32
54
|
};
|
|
33
55
|
}
|
|
56
|
+
//#endregion
|
|
34
57
|
export { tracingPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srvx",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.9",
|
|
4
4
|
"description": "Universal Server.",
|
|
5
5
|
"homepage": "https://srvx.h3.dev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,18 +59,18 @@
|
|
|
59
59
|
"vitest": "vitest"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@cloudflare/workers-types": "^4.
|
|
63
|
-
"@hono/node-server": "^1.19.
|
|
62
|
+
"@cloudflare/workers-types": "^4.20260307.1",
|
|
63
|
+
"@hono/node-server": "^1.19.11",
|
|
64
64
|
"@mitata/counters": "^0.0.8",
|
|
65
65
|
"@mjackson/node-fetch-server": "^0.7.0",
|
|
66
|
-
"@types/aws-lambda": "^8.10.
|
|
67
|
-
"@types/bun": "^1.3.
|
|
66
|
+
"@types/aws-lambda": "^8.10.161",
|
|
67
|
+
"@types/bun": "^1.3.10",
|
|
68
68
|
"@types/deno": "^2.5.0",
|
|
69
69
|
"@types/express": "^5.0.6",
|
|
70
|
-
"@types/node": "^25.
|
|
70
|
+
"@types/node": "^25.3.5",
|
|
71
71
|
"@types/node-forge": "^1.3.14",
|
|
72
|
-
"@types/serviceworker": "^0.0.
|
|
73
|
-
"@typescript/native-preview": "
|
|
72
|
+
"@types/serviceworker": "^0.0.193",
|
|
73
|
+
"@typescript/native-preview": "7.0.0-dev.20260309.1",
|
|
74
74
|
"@vitest/coverage-v8": "^4.0.18",
|
|
75
75
|
"@whatwg-node/server": "^0.10.18",
|
|
76
76
|
"automd": "^0.4.3",
|
|
@@ -78,15 +78,15 @@
|
|
|
78
78
|
"eslint-config-unjs": "^0.6.2",
|
|
79
79
|
"execa": "^9.6.1",
|
|
80
80
|
"express": "^5.2.1",
|
|
81
|
-
"fastify": "^5.
|
|
81
|
+
"fastify": "^5.8.2",
|
|
82
82
|
"get-port-please": "^3.2.0",
|
|
83
83
|
"mdbox": "^0.1.1",
|
|
84
84
|
"mitata": "^1.0.34",
|
|
85
85
|
"node-forge": "^1.3.3",
|
|
86
|
-
"obuild": "^0.4.
|
|
87
|
-
"oxfmt": "^0.
|
|
88
|
-
"oxlint": "^1.
|
|
89
|
-
"srvx-release": "npm:srvx@^0.11.
|
|
86
|
+
"obuild": "^0.4.32",
|
|
87
|
+
"oxfmt": "^0.36.0",
|
|
88
|
+
"oxlint": "^1.51.0",
|
|
89
|
+
"srvx-release": "npm:srvx@^0.11.8",
|
|
90
90
|
"tslib": "^2.8.1",
|
|
91
91
|
"typescript": "^5.9.3",
|
|
92
92
|
"undici": "^7.22.0",
|
|
@@ -98,5 +98,5 @@
|
|
|
98
98
|
"engines": {
|
|
99
99
|
"node": ">=20.16.0"
|
|
100
100
|
},
|
|
101
|
-
"packageManager": "pnpm@10.
|
|
101
|
+
"packageManager": "pnpm@10.30.2"
|
|
102
102
|
}
|