srvx 0.11.6 → 0.11.8
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/_url.mjs +14 -0
- package/dist/_chunks/loader.d.mts +87 -0
- package/dist/adapters/aws-lambda.mjs +1 -0
- package/dist/adapters/bun.mjs +2 -1
- package/dist/adapters/bunny.mjs +1 -0
- package/dist/adapters/cloudflare.mjs +1 -0
- package/dist/adapters/deno.mjs +2 -1
- package/dist/adapters/generic.mjs +1 -0
- package/dist/adapters/node.mjs +60 -13
- package/dist/adapters/service-worker.mjs +1 -0
- package/dist/cli.d.mts +1 -5
- package/dist/cli.mjs +9 -4
- package/dist/loader.d.mts +1 -73
- package/dist/loader.mjs +41 -19
- package/dist/tracing.mjs +21 -0
- package/package.json +10 -10
package/dist/_chunks/_url.mjs
CHANGED
|
@@ -25,6 +25,20 @@ function lazyInherit(target, source, sourceKey) {
|
|
|
25
25
|
if (modified) Object.defineProperty(target, key, desc);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* URL wrapper with fast paths to access to the following props:
|
|
30
|
+
*
|
|
31
|
+
* - `url.pathname`
|
|
32
|
+
* - `url.search`
|
|
33
|
+
* - `url.searchParams`
|
|
34
|
+
* - `url.protocol`
|
|
35
|
+
*
|
|
36
|
+
* **NOTES:**
|
|
37
|
+
*
|
|
38
|
+
* - It is assumed that the input URL is **already encoded** and formatted from an HTTP request and contains no hash.
|
|
39
|
+
* - Triggering the setters or getters on other props will deoptimize to full URL parsing.
|
|
40
|
+
* - Changes to `searchParams` will be discarded as we don't track them.
|
|
41
|
+
*/
|
|
28
42
|
const FastURL = /* @__PURE__ */ (() => {
|
|
29
43
|
const NativeURL = globalThis.URL;
|
|
30
44
|
const FastURL = class URL {
|
|
@@ -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 };
|
package/dist/adapters/bun.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
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";
|
|
@@ -24,7 +25,7 @@ var BunServer = class {
|
|
|
24
25
|
const loader = globalThis.__srvxLoader__;
|
|
25
26
|
if (loader) {
|
|
26
27
|
this.fetch = fetchHandler;
|
|
27
|
-
loader(
|
|
28
|
+
loader({ server: this });
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
31
|
this.#wait = createWaitUntil();
|
package/dist/adapters/bunny.mjs
CHANGED
package/dist/adapters/deno.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
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";
|
|
@@ -26,7 +27,7 @@ var DenoServer = class {
|
|
|
26
27
|
const loader = globalThis.__srvxLoader__;
|
|
27
28
|
if (loader) {
|
|
28
29
|
this.fetch = fetchHandler;
|
|
29
|
-
loader(
|
|
30
|
+
loader({ server: this });
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
this.#wait = createWaitUntil();
|
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";
|
|
@@ -62,6 +63,11 @@ function streamBody(stream, nodeRes) {
|
|
|
62
63
|
nodeRes.off("error", streamCancel);
|
|
63
64
|
});
|
|
64
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Validates an HTTP Host header value (domain, IPv4, or bracketed IPv6) with optional port.
|
|
68
|
+
* Intended for preliminary filtering invalid values like "localhost:3000/foobar?"
|
|
69
|
+
*/
|
|
70
|
+
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
71
|
var NodeRequestURL = class extends FastURL {
|
|
66
72
|
#req;
|
|
67
73
|
constructor({ req }) {
|
|
@@ -70,7 +76,11 @@ var NodeRequestURL = class extends FastURL {
|
|
|
70
76
|
const qIndex = path.indexOf("?");
|
|
71
77
|
const pathname = qIndex === -1 ? path : path?.slice(0, qIndex) || "/";
|
|
72
78
|
const search = qIndex === -1 ? "" : path?.slice(qIndex) || "";
|
|
73
|
-
|
|
79
|
+
let host = req.headers.host || req.headers[":authority"];
|
|
80
|
+
if (host) {
|
|
81
|
+
if (!HOST_RE.test(host)) throw new TypeError(`Invalid host header: ${host}`);
|
|
82
|
+
} else if (req.socket) host = `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
|
|
83
|
+
else host = "localhost";
|
|
74
84
|
const protocol = req.socket?.encrypted || req.headers["x-forwarded-proto"] === "https" || req.headers[":scheme"] === "https" ? "https:" : "http:";
|
|
75
85
|
super({
|
|
76
86
|
protocol,
|
|
@@ -248,6 +258,13 @@ const NodeRequest = /* @__PURE__ */ (() => {
|
|
|
248
258
|
Object.setPrototypeOf(Request.prototype, NativeRequest.prototype);
|
|
249
259
|
return Request;
|
|
250
260
|
})();
|
|
261
|
+
/**
|
|
262
|
+
* Undici uses an incompatible Request constructor depending on private property accessors.
|
|
263
|
+
*
|
|
264
|
+
* This utility, patches global Request to support `new Request(req)` in Node.js.
|
|
265
|
+
*
|
|
266
|
+
* Alternatively you can use `new Request(req._request || req)` instead of patching global Request.
|
|
267
|
+
*/
|
|
251
268
|
function patchGlobalRequest() {
|
|
252
269
|
const NativeRequest = globalThis[Symbol.for("srvx.nativeRequest")] ??= globalThis.Request;
|
|
253
270
|
const PatchedRequest = class Request extends NativeRequest {
|
|
@@ -282,6 +299,11 @@ function readBody(req) {
|
|
|
282
299
|
req.on("data", onData).once("end", onEnd).once("error", onError);
|
|
283
300
|
});
|
|
284
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Fast Response for Node.js runtime
|
|
304
|
+
*
|
|
305
|
+
* It is faster because in most cases it doesn't create a full Response instance.
|
|
306
|
+
*/
|
|
285
307
|
const NodeResponse = /* @__PURE__ */ (() => {
|
|
286
308
|
const NativeResponse = globalThis.Response;
|
|
287
309
|
const STATUS_CODES = globalThis.process?.getBuiltinModule?.("node:http")?.STATUS_CODES || {};
|
|
@@ -390,6 +412,11 @@ const NodeResponse = /* @__PURE__ */ (() => {
|
|
|
390
412
|
Object.setPrototypeOf(NodeResponse.prototype, NativeResponse.prototype);
|
|
391
413
|
return NodeResponse;
|
|
392
414
|
})();
|
|
415
|
+
/**
|
|
416
|
+
* Events:
|
|
417
|
+
* - Readable (req from client): readable => data => end (push(null)) => error => close
|
|
418
|
+
* - Writable (res to client): pipe => unpipe => drain => finish (end called) => error => close
|
|
419
|
+
*/
|
|
393
420
|
var WebRequestSocket = class extends Duplex {
|
|
394
421
|
_httpMessage;
|
|
395
422
|
autoSelectFamilyAttemptedAddresses = [];
|
|
@@ -604,6 +631,17 @@ var WebServerResponse = class extends ServerResponse {
|
|
|
604
631
|
});
|
|
605
632
|
}
|
|
606
633
|
};
|
|
634
|
+
/**
|
|
635
|
+
* Calls a Node.js HTTP Request handler with a Fetch API Request object and returns a Response object.
|
|
636
|
+
*
|
|
637
|
+
* 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.
|
|
638
|
+
*
|
|
639
|
+
* 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.
|
|
640
|
+
*
|
|
641
|
+
* The handler is invoked with these objects, and the response is constructed from the ServerResponse once it is finished.
|
|
642
|
+
*
|
|
643
|
+
* @experimental Behavior might be unstable.
|
|
644
|
+
*/
|
|
607
645
|
async function fetchNodeHandler(handler, req) {
|
|
608
646
|
const nodeRuntime = req.runtime?.node;
|
|
609
647
|
if (nodeRuntime && nodeRuntime.req && nodeRuntime.res) return await callNodeHandler(handler, req);
|
|
@@ -624,6 +662,9 @@ async function fetchNodeHandler(handler, req) {
|
|
|
624
662
|
});
|
|
625
663
|
}
|
|
626
664
|
}
|
|
665
|
+
/**
|
|
666
|
+
* Converts a Fetch API handler to a Node.js HTTP handler.
|
|
667
|
+
*/
|
|
627
668
|
function toNodeHandler(handler) {
|
|
628
669
|
if (handler.__nodeHandler) return handler.__nodeHandler;
|
|
629
670
|
function convertedNodeHandler(nodeReq, nodeRes) {
|
|
@@ -637,6 +678,11 @@ function toNodeHandler(handler) {
|
|
|
637
678
|
assignFnName(convertedNodeHandler, handler, " (converted to Node handler)");
|
|
638
679
|
return convertedNodeHandler;
|
|
639
680
|
}
|
|
681
|
+
/**
|
|
682
|
+
* Converts a Node.js HTTP handler into a Fetch API handler.
|
|
683
|
+
*
|
|
684
|
+
* @experimental Behavior might be unstable and won't work in Bun and Deno currently (tracker: https://github.com/h3js/srvx/issues/132)
|
|
685
|
+
*/
|
|
640
686
|
function toFetchHandler(handler) {
|
|
641
687
|
if (handler.__fetchHandler) return handler.__fetchHandler;
|
|
642
688
|
function convertedNodeHandler(req) {
|
|
@@ -672,14 +718,6 @@ var NodeServer = class {
|
|
|
672
718
|
for (const plugin of options.plugins || []) plugin(this);
|
|
673
719
|
errorPlugin(this);
|
|
674
720
|
const fetchHandler = this.fetch = wrapFetch(this);
|
|
675
|
-
const loader = globalThis.__srvxLoader__;
|
|
676
|
-
if (loader) {
|
|
677
|
-
loader(fetchHandler);
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
gracefulShutdownPlugin(this);
|
|
681
|
-
this.#wait = createWaitUntil();
|
|
682
|
-
this.waitUntil = this.#wait.waitUntil;
|
|
683
721
|
const handler = (nodeReq, nodeRes) => {
|
|
684
722
|
const request = new NodeRequest({
|
|
685
723
|
req: nodeReq,
|
|
@@ -689,6 +727,18 @@ var NodeServer = class {
|
|
|
689
727
|
const res = fetchHandler(request);
|
|
690
728
|
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
|
|
691
729
|
};
|
|
730
|
+
this.node = {
|
|
731
|
+
handler,
|
|
732
|
+
server: void 0
|
|
733
|
+
};
|
|
734
|
+
const loader = globalThis.__srvxLoader__;
|
|
735
|
+
if (loader) {
|
|
736
|
+
loader({ server: this });
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
gracefulShutdownPlugin(this);
|
|
740
|
+
this.#wait = createWaitUntil();
|
|
741
|
+
this.waitUntil = this.#wait.waitUntil;
|
|
692
742
|
const tls = resolveTLSOptions(this.options);
|
|
693
743
|
const { port, hostname: host } = resolvePortAndHost(this.options);
|
|
694
744
|
this.serveOptions = {
|
|
@@ -711,10 +761,7 @@ var NodeServer = class {
|
|
|
711
761
|
else throw new Error("node.http2 option requires tls certificate!");
|
|
712
762
|
else if (this.#isSecure) server = nodeHTTPS.createServer(this.serveOptions, handler);
|
|
713
763
|
else server = nodeHTTP.createServer(this.serveOptions, handler);
|
|
714
|
-
this.node =
|
|
715
|
-
server,
|
|
716
|
-
handler
|
|
717
|
-
};
|
|
764
|
+
this.node.server = server;
|
|
718
765
|
if (!options.manual) this.serve();
|
|
719
766
|
}
|
|
720
767
|
serve() {
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { LoadOptions } from "./loader.mjs";
|
|
2
|
-
import { Server } from "srvx";
|
|
1
|
+
import { t as LoadOptions } from "./_chunks/loader.mjs";
|
|
3
2
|
|
|
4
3
|
//#region src/cli/types.d.ts
|
|
5
|
-
declare global {
|
|
6
|
-
var __srvx__: Server | undefined;
|
|
7
|
-
}
|
|
8
4
|
type MainOptions = CLIOptions & {
|
|
9
5
|
args?: string[];
|
|
10
6
|
meta?: {
|
package/dist/cli.mjs
CHANGED
|
@@ -10,9 +10,13 @@ const NO_ENTRY_ERROR = "No server entry or public directory found";
|
|
|
10
10
|
async function cliServe(cliOpts) {
|
|
11
11
|
try {
|
|
12
12
|
if (!process.env.NODE_ENV) process.env.NODE_ENV = cliOpts.prod ? "production" : "development";
|
|
13
|
+
let server;
|
|
13
14
|
const loaded = await loadServerEntry({
|
|
14
15
|
entry: cliOpts.entry,
|
|
15
|
-
dir: cliOpts.dir
|
|
16
|
+
dir: cliOpts.dir,
|
|
17
|
+
get srvxServer() {
|
|
18
|
+
return server;
|
|
19
|
+
}
|
|
16
20
|
});
|
|
17
21
|
const { serve: srvxServe } = loaded.nodeCompat ? await import("srvx/node") : await import("srvx");
|
|
18
22
|
const { serveStatic } = await import("srvx/static");
|
|
@@ -29,7 +33,7 @@ async function cliServe(cliOpts) {
|
|
|
29
33
|
...loaded.module
|
|
30
34
|
};
|
|
31
35
|
printInfo(cliOpts, loaded);
|
|
32
|
-
|
|
36
|
+
server = srvxServe({
|
|
33
37
|
...serverOptions,
|
|
34
38
|
gracefulShutdown: !!cliOpts.prod,
|
|
35
39
|
port: cliOpts.port ?? serverOptions.port,
|
|
@@ -48,7 +52,8 @@ async function cliServe(cliOpts) {
|
|
|
48
52
|
cliOpts.static ? serveStatic({ dir: cliOpts.static }) : void 0,
|
|
49
53
|
...serverOptions.middleware || []
|
|
50
54
|
].filter(Boolean)
|
|
51
|
-
})
|
|
55
|
+
});
|
|
56
|
+
await server.ready();
|
|
52
57
|
} catch (error) {
|
|
53
58
|
console.error(error);
|
|
54
59
|
process.exit(1);
|
|
@@ -174,7 +179,7 @@ function getResponseFormat(res) {
|
|
|
174
179
|
}
|
|
175
180
|
const srvxMeta = {
|
|
176
181
|
name: "srvx",
|
|
177
|
-
version: "0.11.
|
|
182
|
+
version: "0.11.8",
|
|
178
183
|
description: "Universal Server."
|
|
179
184
|
};
|
|
180
185
|
function usage(mainOpts) {
|
package/dist/loader.d.mts
CHANGED
|
@@ -1,74 +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
|
-
* Hook called after the module is loaded to allow for custom processing.
|
|
34
|
-
*
|
|
35
|
-
* You can return a modified version of the module if needed.
|
|
36
|
-
*/
|
|
37
|
-
onLoad?: (module: unknown) => any;
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Result of loading a server entry module.
|
|
41
|
-
*/
|
|
42
|
-
type LoadedServerEntry = {
|
|
43
|
-
/**
|
|
44
|
-
* The web fetch handler extracted from the loaded module.
|
|
45
|
-
*
|
|
46
|
-
* This is resolved from `module.fetch`, `module.default.fetch`,
|
|
47
|
-
* or upgraded from a legacy Node.js handler.
|
|
48
|
-
*/
|
|
49
|
-
fetch?: ServerHandler;
|
|
50
|
-
/**
|
|
51
|
-
* The raw loaded module.
|
|
52
|
-
*/
|
|
53
|
-
module?: any;
|
|
54
|
-
/**
|
|
55
|
-
* Whether the handler was upgraded from a legacy Node.js HTTP handler.
|
|
56
|
-
*
|
|
57
|
-
* When `true`, the original module exported a Node.js-style `(req, res)` handler
|
|
58
|
-
* that has been wrapped for web fetch compatibility.
|
|
59
|
-
*/
|
|
60
|
-
nodeCompat?: boolean;
|
|
61
|
-
/**
|
|
62
|
-
* The resolved `file://` URL of the loaded entry module.
|
|
63
|
-
*/
|
|
64
|
-
url?: string;
|
|
65
|
-
/**
|
|
66
|
-
* Whether the specified entry file was not found.
|
|
67
|
-
*
|
|
68
|
-
* When `true`, no valid entry point could be located.
|
|
69
|
-
*/
|
|
70
|
-
notFound?: boolean;
|
|
71
|
-
};
|
|
72
|
-
declare function loadServerEntry(opts: LoadOptions): Promise<LoadedServerEntry>;
|
|
73
|
-
//#endregion
|
|
1
|
+
import { a as loadServerEntry, i as defaultExts, n as LoadedServerEntry, r as defaultEntries, t as LoadOptions } from "./_chunks/loader.mjs";
|
|
74
2
|
export { LoadOptions, LoadedServerEntry, defaultEntries, defaultExts, loadServerEntry };
|
package/dist/loader.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { pathToFileURL } from "node:url";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import * as nodeHTTP$1 from "node:http";
|
|
5
|
+
import { EventEmitter } from "node:events";
|
|
5
6
|
const defaultExts = [
|
|
6
7
|
".mjs",
|
|
7
8
|
".js",
|
|
@@ -35,13 +36,13 @@ async function loadServerEntry(opts) {
|
|
|
35
36
|
const url = entry.startsWith("file://") ? entry : pathToFileURL(resolve(entry)).href;
|
|
36
37
|
let mod;
|
|
37
38
|
let interceptedNodeHandler;
|
|
38
|
-
let
|
|
39
|
+
let interceptedServer;
|
|
39
40
|
try {
|
|
40
41
|
if (opts.interceptHttpListen !== false) {
|
|
41
|
-
const loaded = await interceptListen(() => import(url));
|
|
42
|
+
const loaded = await interceptListen(() => import(url), opts);
|
|
42
43
|
mod = loaded.res;
|
|
43
44
|
interceptedNodeHandler = loaded.listenHandler;
|
|
44
|
-
|
|
45
|
+
interceptedServer = loaded.server;
|
|
45
46
|
} else mod = await import(url);
|
|
46
47
|
} catch (error) {
|
|
47
48
|
if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
@@ -52,7 +53,7 @@ async function loadServerEntry(opts) {
|
|
|
52
53
|
throw error;
|
|
53
54
|
}
|
|
54
55
|
mod = await opts?.onLoad?.(mod) || mod;
|
|
55
|
-
let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch ||
|
|
56
|
+
let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch || interceptedServer?.fetch;
|
|
56
57
|
if (!fetchHandler && typeof mod?.default === "function" && mod.default.length < 2) fetchHandler = mod.default;
|
|
57
58
|
let nodeCompat = false;
|
|
58
59
|
if (!fetchHandler && opts.nodeCompat !== false) {
|
|
@@ -67,18 +68,21 @@ async function loadServerEntry(opts) {
|
|
|
67
68
|
module: mod,
|
|
68
69
|
nodeCompat,
|
|
69
70
|
url,
|
|
70
|
-
fetch: fetchHandler
|
|
71
|
+
fetch: fetchHandler,
|
|
72
|
+
srvxServer: interceptedServer
|
|
71
73
|
};
|
|
72
74
|
}
|
|
73
75
|
let _interceptQueue = Promise.resolve();
|
|
74
|
-
async function interceptListen(cb) {
|
|
76
|
+
async function interceptListen(cb, opts = {}) {
|
|
75
77
|
const result = _interceptQueue.then(async () => {
|
|
76
78
|
const originalListen = nodeHTTP$1.Server.prototype.listen;
|
|
77
79
|
let res;
|
|
78
80
|
let listenHandler;
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
let server;
|
|
82
|
+
const nodeServerStub = opts.nodeServer || opts.srvxServer?.node?.server || new StubNodeServer(() => opts.srvxServer?.node?.server);
|
|
83
|
+
globalThis.__srvxLoader__ = (obj) => {
|
|
84
|
+
server = obj.server;
|
|
85
|
+
if (server && server.node) server.node.server ||= nodeServerStub;
|
|
82
86
|
};
|
|
83
87
|
try {
|
|
84
88
|
nodeHTTP$1.Server.prototype.listen = function(arg1, arg2) {
|
|
@@ -89,15 +93,7 @@ async function interceptListen(cb) {
|
|
|
89
93
|
setImmediate(() => {
|
|
90
94
|
listenCallback?.();
|
|
91
95
|
});
|
|
92
|
-
return
|
|
93
|
-
const server = globalThis.__srvx__;
|
|
94
|
-
if (!server && prop === "address") return () => ({
|
|
95
|
-
address: "",
|
|
96
|
-
family: "",
|
|
97
|
-
port: 0
|
|
98
|
-
});
|
|
99
|
-
return server?.node?.server?.[prop];
|
|
100
|
-
} });
|
|
96
|
+
return nodeServerStub;
|
|
101
97
|
};
|
|
102
98
|
res = await cb();
|
|
103
99
|
} finally {
|
|
@@ -107,10 +103,36 @@ async function interceptListen(cb) {
|
|
|
107
103
|
return {
|
|
108
104
|
res,
|
|
109
105
|
listenHandler,
|
|
110
|
-
|
|
106
|
+
server
|
|
111
107
|
};
|
|
112
108
|
});
|
|
113
109
|
_interceptQueue = result.catch(() => {});
|
|
114
110
|
return result;
|
|
115
111
|
}
|
|
112
|
+
var StubNodeServer = class extends EventEmitter {
|
|
113
|
+
constructor(getServer) {
|
|
114
|
+
super();
|
|
115
|
+
return new Proxy(this, { get(target, prop, receiver) {
|
|
116
|
+
const server = getServer();
|
|
117
|
+
if (!server) return Reflect.get(target, prop, receiver);
|
|
118
|
+
const value = server[prop];
|
|
119
|
+
if (typeof value === "function") return value.bind(server);
|
|
120
|
+
return value;
|
|
121
|
+
} });
|
|
122
|
+
}
|
|
123
|
+
address() {
|
|
124
|
+
return {
|
|
125
|
+
address: "",
|
|
126
|
+
family: "",
|
|
127
|
+
port: 0
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
listen() {
|
|
131
|
+
return this;
|
|
132
|
+
}
|
|
133
|
+
close(callback) {
|
|
134
|
+
callback?.();
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
116
138
|
export { defaultEntries, defaultExts, loadServerEntry };
|
package/dist/tracing.mjs
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @experimental Channel names, event types and config options may change in future releases.
|
|
4
|
+
*
|
|
5
|
+
* Tracing plugin that adds diagnostics channel tracing to middleware and fetch handlers.
|
|
6
|
+
*
|
|
7
|
+
* This plugin wraps all middleware and the fetch handler with tracing instrumentation,
|
|
8
|
+
* allowing you to subscribe to `srvx.request` and `srvx.middleware` tracing channels.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { serve } from "srvx";
|
|
13
|
+
* import { tracingPlugin } from "srvx/tracing";
|
|
14
|
+
*
|
|
15
|
+
* const server = serve({
|
|
16
|
+
* fetch: (req) => new Response("OK"),
|
|
17
|
+
* middleware: [myMiddleware],
|
|
18
|
+
* plugins: [tracingPlugin()],
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
1
22
|
function tracingPlugin(opts = {}) {
|
|
2
23
|
return (server) => {
|
|
3
24
|
const { tracingChannel } = globalThis.process?.getBuiltinModule?.("node:diagnostics_channel") || {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srvx",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
4
4
|
"description": "Universal Server.",
|
|
5
5
|
"homepage": "https://srvx.h3.dev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"vitest": "vitest"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@cloudflare/workers-types": "^4.
|
|
62
|
+
"@cloudflare/workers-types": "^4.20260304.0",
|
|
63
63
|
"@hono/node-server": "^1.19.9",
|
|
64
64
|
"@mitata/counters": "^0.0.8",
|
|
65
65
|
"@mjackson/node-fetch-server": "^0.7.0",
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"@types/bun": "^1.3.9",
|
|
68
68
|
"@types/deno": "^2.5.0",
|
|
69
69
|
"@types/express": "^5.0.6",
|
|
70
|
-
"@types/node": "^25.
|
|
70
|
+
"@types/node": "^25.3.0",
|
|
71
71
|
"@types/node-forge": "^1.3.14",
|
|
72
|
-
"@types/serviceworker": "^0.0.
|
|
73
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
72
|
+
"@types/serviceworker": "^0.0.192",
|
|
73
|
+
"@typescript/native-preview": "^7.0.0-dev.20260225.1",
|
|
74
74
|
"@vitest/coverage-v8": "^4.0.18",
|
|
75
75
|
"@whatwg-node/server": "^0.10.18",
|
|
76
76
|
"automd": "^0.4.3",
|
|
@@ -83,10 +83,10 @@
|
|
|
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.31",
|
|
87
|
+
"oxfmt": "^0.35.0",
|
|
88
|
+
"oxlint": "^1.50.0",
|
|
89
|
+
"srvx-release": "npm:srvx@^0.11.7",
|
|
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
|
}
|