srvx 0.11.2 → 0.11.4
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 +12 -7
- package/dist/adapters/bun.d.mts +1 -1
- package/dist/adapters/bun.mjs +8 -2
- package/dist/adapters/deno.d.mts +1 -1
- package/dist/adapters/deno.mjs +8 -2
- package/dist/adapters/node.mjs +19 -6
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/loader.d.mts +73 -1
- package/dist/loader.mjs +115 -1
- package/package.json +8 -8
- package/dist/_chunks/loader.d.mts +0 -74
- package/dist/_chunks/loader.mjs +0 -108
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as green, i as gray,
|
|
1
|
+
import { a as green, i as gray, n as bold, s as red } from "./_utils.mjs";
|
|
2
2
|
function wrapFetch(server) {
|
|
3
3
|
const fetchHandler = server.options.fetch;
|
|
4
4
|
const middleware = server.options.middleware || [];
|
|
@@ -24,23 +24,28 @@ const gracefulShutdownPlugin = (server) => {
|
|
|
24
24
|
const config = server.options?.gracefulShutdown;
|
|
25
25
|
if (!globalThis.process?.on || config === false || config === void 0 && (process.env.CI || process.env.TEST)) return;
|
|
26
26
|
const gracefulTimeout = config === true || !config?.gracefulTimeout ? Number.parseInt(process.env.SERVER_SHUTDOWN_TIMEOUT || "") || 5 : config.gracefulTimeout;
|
|
27
|
-
let
|
|
27
|
+
let isClosing = false;
|
|
28
|
+
let isClosed = false;
|
|
28
29
|
const w = server.options.silent ? () => {} : process.stderr.write.bind(process.stderr);
|
|
29
30
|
const forceClose = async () => {
|
|
31
|
+
if (isClosed) return;
|
|
30
32
|
w(red("\x1B[2K\rForcibly closing connections...\n"));
|
|
33
|
+
isClosed = true;
|
|
31
34
|
await server.close(true);
|
|
32
|
-
w(yellow("Server closed.\n"));
|
|
33
|
-
globalThis.process.exit(0);
|
|
34
35
|
};
|
|
35
36
|
const shutdown = async () => {
|
|
36
|
-
if (
|
|
37
|
-
|
|
37
|
+
if (isClosing || isClosed) return;
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
globalThis.process.once("SIGINT", forceClose);
|
|
40
|
+
}, 100);
|
|
41
|
+
isClosing = true;
|
|
38
42
|
const closePromise = server.close();
|
|
39
43
|
for (let remaining = gracefulTimeout; remaining > 0; remaining--) {
|
|
40
44
|
w(gray(`\rStopping server gracefully (${remaining}s)... Press ${bold("Ctrl+C")} again to force close.`));
|
|
41
45
|
if (await Promise.race([closePromise.then(() => true), new Promise((r) => setTimeout(() => r(false), 1e3))])) {
|
|
42
46
|
w("\x1B[2K\r" + green("Server closed successfully.\n"));
|
|
43
|
-
|
|
47
|
+
isClosed = true;
|
|
48
|
+
return;
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
w("\x1B[2K\rGraceful shutdown timed out.\n");
|
package/dist/adapters/bun.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ declare class BunServer implements Server<BunFetchHandler> {
|
|
|
10
10
|
readonly runtime = "bun";
|
|
11
11
|
readonly options: Server["options"];
|
|
12
12
|
readonly bun: Server["bun"];
|
|
13
|
-
readonly serveOptions: bun.Serve.Options<any
|
|
13
|
+
readonly serveOptions: bun.Serve.Options<any> | undefined;
|
|
14
14
|
readonly fetch: BunFetchHandler;
|
|
15
15
|
constructor(options: ServerOptions);
|
|
16
16
|
serve(): Promise<this>;
|
package/dist/adapters/bun.mjs
CHANGED
|
@@ -20,10 +20,16 @@ var BunServer = class {
|
|
|
20
20
|
for (const plugin of options.plugins || []) plugin(this);
|
|
21
21
|
gracefulShutdownPlugin(this);
|
|
22
22
|
const fetchHandler = wrapFetch(this);
|
|
23
|
+
const loader = globalThis.__srvxLoader__;
|
|
24
|
+
if (loader) {
|
|
25
|
+
this.fetch = fetchHandler;
|
|
26
|
+
loader(fetchHandler);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
23
29
|
this.#wait = createWaitUntil();
|
|
24
30
|
this.fetch = (request, server) => {
|
|
25
31
|
Object.defineProperties(request, {
|
|
26
|
-
waitUntil: { value: this.#wait
|
|
32
|
+
waitUntil: { value: this.#wait?.waitUntil },
|
|
27
33
|
runtime: {
|
|
28
34
|
enumerable: true,
|
|
29
35
|
value: {
|
|
@@ -72,7 +78,7 @@ var BunServer = class {
|
|
|
72
78
|
return Promise.resolve(this);
|
|
73
79
|
}
|
|
74
80
|
async close(closeAll) {
|
|
75
|
-
await Promise.all([this.#wait
|
|
81
|
+
await Promise.all([this.#wait?.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
|
|
76
82
|
}
|
|
77
83
|
};
|
|
78
84
|
export { FastResponse, FastURL, serve };
|
package/dist/adapters/deno.d.mts
CHANGED
|
@@ -9,7 +9,7 @@ declare class DenoServer implements Server<DenoFetchHandler> {
|
|
|
9
9
|
readonly runtime = "deno";
|
|
10
10
|
readonly options: Server["options"];
|
|
11
11
|
readonly deno: Server["deno"];
|
|
12
|
-
readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem);
|
|
12
|
+
readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem) | undefined;
|
|
13
13
|
readonly fetch: DenoFetchHandler;
|
|
14
14
|
constructor(options: ServerOptions);
|
|
15
15
|
serve(): Promise<this>;
|
package/dist/adapters/deno.mjs
CHANGED
|
@@ -22,10 +22,16 @@ var DenoServer = class {
|
|
|
22
22
|
for (const plugin of options.plugins || []) plugin(this);
|
|
23
23
|
gracefulShutdownPlugin(this);
|
|
24
24
|
const fetchHandler = wrapFetch(this);
|
|
25
|
+
const loader = globalThis.__srvxLoader__;
|
|
26
|
+
if (loader) {
|
|
27
|
+
this.fetch = fetchHandler;
|
|
28
|
+
loader(fetchHandler);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
25
31
|
this.#wait = createWaitUntil();
|
|
26
32
|
this.fetch = (request, info) => {
|
|
27
33
|
Object.defineProperties(request, {
|
|
28
|
-
waitUntil: { value: this.#wait
|
|
34
|
+
waitUntil: { value: this.#wait?.waitUntil },
|
|
29
35
|
runtime: {
|
|
30
36
|
enumerable: true,
|
|
31
37
|
value: {
|
|
@@ -81,7 +87,7 @@ var DenoServer = class {
|
|
|
81
87
|
return Promise.resolve(this.#listeningPromise).then(() => this);
|
|
82
88
|
}
|
|
83
89
|
async close() {
|
|
84
|
-
await Promise.all([this.#wait
|
|
90
|
+
await Promise.all([this.#wait?.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
|
|
85
91
|
}
|
|
86
92
|
};
|
|
87
93
|
export { FastResponse, FastURL, serve };
|
package/dist/adapters/node.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { n as lazyInherit, t as FastURL } from "../_chunks/_url.mjs";
|
|
|
2
2
|
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
|
|
3
3
|
import { n as gracefulShutdownPlugin, r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
|
|
4
4
|
import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";
|
|
5
|
-
import { Duplex, Readable } from "node:stream";
|
|
5
|
+
import { Duplex, PassThrough, Readable } from "node:stream";
|
|
6
6
|
import nodeHTTPS from "node:https";
|
|
7
7
|
import nodeHTTP2 from "node:http2";
|
|
8
8
|
async function sendNodeResponse(nodeRes, webRes) {
|
|
@@ -316,7 +316,15 @@ const NodeResponse = /* @__PURE__ */ (() => {
|
|
|
316
316
|
}
|
|
317
317
|
get _response() {
|
|
318
318
|
if (this.#response) return this.#response;
|
|
319
|
-
|
|
319
|
+
let body = this.#body;
|
|
320
|
+
if (body && typeof body.pipe === "function" && !(body instanceof Readable)) {
|
|
321
|
+
const stream = new PassThrough();
|
|
322
|
+
body.pipe(stream);
|
|
323
|
+
const abort = body.abort;
|
|
324
|
+
if (abort) stream.once("close", () => abort());
|
|
325
|
+
body = stream;
|
|
326
|
+
}
|
|
327
|
+
this.#response = new NativeResponse(body, this.#headers ? {
|
|
320
328
|
...this.#init,
|
|
321
329
|
headers: this.#headers
|
|
322
330
|
} : this.#init);
|
|
@@ -662,15 +670,20 @@ var NodeServer = class {
|
|
|
662
670
|
};
|
|
663
671
|
for (const plugin of options.plugins || []) plugin(this);
|
|
664
672
|
errorPlugin(this);
|
|
665
|
-
gracefulShutdownPlugin(this);
|
|
666
673
|
const fetchHandler = this.fetch = wrapFetch(this);
|
|
674
|
+
const loader = globalThis.__srvxLoader__;
|
|
675
|
+
if (loader) {
|
|
676
|
+
loader(fetchHandler);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
gracefulShutdownPlugin(this);
|
|
667
680
|
this.#wait = createWaitUntil();
|
|
668
681
|
const handler = (nodeReq, nodeRes) => {
|
|
669
682
|
const request = new NodeRequest({
|
|
670
683
|
req: nodeReq,
|
|
671
684
|
res: nodeRes
|
|
672
685
|
});
|
|
673
|
-
request.waitUntil = this.#wait
|
|
686
|
+
request.waitUntil = this.#wait?.waitUntil;
|
|
674
687
|
const res = fetchHandler(request);
|
|
675
688
|
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
|
|
676
689
|
};
|
|
@@ -720,10 +733,10 @@ var NodeServer = class {
|
|
|
720
733
|
return Promise.resolve(this.#listeningPromise).then(() => this);
|
|
721
734
|
}
|
|
722
735
|
async close(closeAll) {
|
|
723
|
-
await Promise.all([this.#wait
|
|
736
|
+
await Promise.all([this.#wait?.wait(), new Promise((resolve, reject) => {
|
|
724
737
|
const server = this.node?.server;
|
|
738
|
+
if (server && closeAll && "closeAllConnections" in server) server.closeAllConnections();
|
|
725
739
|
if (!server || !server.listening) return resolve();
|
|
726
|
-
if (closeAll && "closeAllConnections" in server) server.closeAllConnections();
|
|
727
740
|
server.close((error) => error ? reject(error) : resolve());
|
|
728
741
|
})]);
|
|
729
742
|
}
|
package/dist/cli.d.mts
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as green, c as url, i as gray, l as yellow, n as bold, o as magenta, r as cyan, s as red } from "./_chunks/_utils.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { loadServerEntry } from "./loader.mjs";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { fork } from "node:child_process";
|
|
@@ -174,7 +174,7 @@ function getResponseFormat(res) {
|
|
|
174
174
|
}
|
|
175
175
|
const srvxMeta = {
|
|
176
176
|
name: "srvx",
|
|
177
|
-
version: "0.11.
|
|
177
|
+
version: "0.11.3",
|
|
178
178
|
description: "Universal Server."
|
|
179
179
|
};
|
|
180
180
|
function usage(mainOpts) {
|
package/dist/loader.d.mts
CHANGED
|
@@ -1,2 +1,74 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { 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
|
+
* 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
|
|
2
74
|
export { LoadOptions, LoadedServerEntry, defaultEntries, defaultExts, loadServerEntry };
|
package/dist/loader.mjs
CHANGED
|
@@ -1,2 +1,116 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import * as nodeHTTP$1 from "node:http";
|
|
5
|
+
const defaultExts = [
|
|
6
|
+
".mjs",
|
|
7
|
+
".js",
|
|
8
|
+
".mts",
|
|
9
|
+
".ts"
|
|
10
|
+
];
|
|
11
|
+
const defaultEntries = [
|
|
12
|
+
"server",
|
|
13
|
+
"server/index",
|
|
14
|
+
"src/server",
|
|
15
|
+
"server/server"
|
|
16
|
+
];
|
|
17
|
+
async function loadServerEntry(opts) {
|
|
18
|
+
let entry = opts.entry;
|
|
19
|
+
if (entry) {
|
|
20
|
+
entry = resolve(opts.dir || ".", entry);
|
|
21
|
+
if (!existsSync(entry)) return { notFound: true };
|
|
22
|
+
} else {
|
|
23
|
+
for (const defEntry of defaultEntries) {
|
|
24
|
+
for (const defExt of defaultExts) {
|
|
25
|
+
const entryPath = resolve(opts.dir || ".", `${defEntry}${defExt}`);
|
|
26
|
+
if (existsSync(entryPath)) {
|
|
27
|
+
entry = entryPath;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (entry) break;
|
|
32
|
+
}
|
|
33
|
+
if (!entry) return { notFound: true };
|
|
34
|
+
}
|
|
35
|
+
const url = entry.startsWith("file://") ? entry : pathToFileURL(resolve(entry)).href;
|
|
36
|
+
let mod;
|
|
37
|
+
let interceptedNodeHandler;
|
|
38
|
+
let interceptedFetchHandler;
|
|
39
|
+
try {
|
|
40
|
+
if (opts.interceptHttpListen !== false) {
|
|
41
|
+
const loaded = await interceptListen(() => import(url));
|
|
42
|
+
mod = loaded.res;
|
|
43
|
+
interceptedNodeHandler = loaded.listenHandler;
|
|
44
|
+
interceptedFetchHandler = loaded.fetchHandler;
|
|
45
|
+
} else mod = await import(url);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
48
|
+
const message = String(error);
|
|
49
|
+
if (/"\.(m|c)?ts"/g.test(message)) throw new Error(`Make sure you're using Node.js v22.18+ or v24+ for TypeScript support (current version: ${process.versions.node})`, { cause: error });
|
|
50
|
+
else if (/"\.(m|c)?tsx"/g.test(message)) throw new Error(`You need a compatible loader for JSX support (Deno, Bun or srvx --register jiti/register)`, { cause: error });
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
mod = await opts?.onLoad?.(mod) || mod;
|
|
55
|
+
let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch || interceptedFetchHandler;
|
|
56
|
+
if (!fetchHandler && typeof mod?.default === "function" && mod.default.length < 2) fetchHandler = mod.default;
|
|
57
|
+
let nodeCompat = false;
|
|
58
|
+
if (!fetchHandler && opts.nodeCompat !== false) {
|
|
59
|
+
const nodeHandler = interceptedNodeHandler || (typeof mod?.default === "function" ? mod.default : void 0);
|
|
60
|
+
if (nodeHandler) {
|
|
61
|
+
nodeCompat = true;
|
|
62
|
+
const { fetchNodeHandler } = await import("srvx/node");
|
|
63
|
+
fetchHandler = (webReq) => fetchNodeHandler(nodeHandler, webReq);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
module: mod,
|
|
68
|
+
nodeCompat,
|
|
69
|
+
url,
|
|
70
|
+
fetch: fetchHandler
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
let _interceptQueue = Promise.resolve();
|
|
74
|
+
async function interceptListen(cb) {
|
|
75
|
+
const result = _interceptQueue.then(async () => {
|
|
76
|
+
const originalListen = nodeHTTP$1.Server.prototype.listen;
|
|
77
|
+
let res;
|
|
78
|
+
let listenHandler;
|
|
79
|
+
let fetchHandler;
|
|
80
|
+
globalThis.__srvxLoader__ = (handler) => {
|
|
81
|
+
fetchHandler = handler;
|
|
82
|
+
};
|
|
83
|
+
try {
|
|
84
|
+
nodeHTTP$1.Server.prototype.listen = function(arg1, arg2) {
|
|
85
|
+
listenHandler = this._events.request;
|
|
86
|
+
if (Array.isArray(listenHandler)) listenHandler = listenHandler[0];
|
|
87
|
+
nodeHTTP$1.Server.prototype.listen = originalListen;
|
|
88
|
+
const listenCallback = [arg1, arg2].find((arg) => typeof arg === "function");
|
|
89
|
+
setImmediate(() => {
|
|
90
|
+
listenCallback?.();
|
|
91
|
+
});
|
|
92
|
+
return new Proxy({}, { get(_, prop) {
|
|
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
|
+
} });
|
|
101
|
+
};
|
|
102
|
+
res = await cb();
|
|
103
|
+
} finally {
|
|
104
|
+
nodeHTTP$1.Server.prototype.listen = originalListen;
|
|
105
|
+
delete globalThis.__srvxLoader__;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
res,
|
|
109
|
+
listenHandler,
|
|
110
|
+
fetchHandler
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
_interceptQueue = result.catch(() => {});
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
2
116
|
export { defaultEntries, defaultExts, loadServerEntry };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srvx",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "Universal Server.",
|
|
5
5
|
"homepage": "https://srvx.h3.dev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"vitest": "vitest"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@cloudflare/workers-types": "^4.
|
|
61
|
+
"@cloudflare/workers-types": "^4.20260210.0",
|
|
62
62
|
"@hono/node-server": "^1.19.9",
|
|
63
63
|
"@mitata/counters": "^0.0.8",
|
|
64
64
|
"@mjackson/node-fetch-server": "^0.7.0",
|
|
@@ -66,10 +66,10 @@
|
|
|
66
66
|
"@types/bun": "^1.3.8",
|
|
67
67
|
"@types/deno": "^2.5.0",
|
|
68
68
|
"@types/express": "^5.0.6",
|
|
69
|
-
"@types/node": "^25.2.
|
|
69
|
+
"@types/node": "^25.2.3",
|
|
70
70
|
"@types/node-forge": "^1.3.14",
|
|
71
|
-
"@types/serviceworker": "^0.0.
|
|
72
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
71
|
+
"@types/serviceworker": "^0.0.186",
|
|
72
|
+
"@typescript/native-preview": "^7.0.0-dev.20260210.1",
|
|
73
73
|
"@vitest/coverage-v8": "^4.0.18",
|
|
74
74
|
"@whatwg-node/server": "^0.10.18",
|
|
75
75
|
"automd": "^0.4.3",
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
"mdbox": "^0.1.1",
|
|
83
83
|
"mitata": "^1.0.34",
|
|
84
84
|
"node-forge": "^1.3.3",
|
|
85
|
-
"obuild": "^0.4.
|
|
85
|
+
"obuild": "^0.4.27",
|
|
86
86
|
"oxfmt": "^0.28.0",
|
|
87
87
|
"oxlint": "^1.43.0",
|
|
88
88
|
"srvx-release": "npm:srvx@^0.10.1",
|
|
89
89
|
"tslib": "^2.8.1",
|
|
90
90
|
"typescript": "^5.9.3",
|
|
91
|
-
"undici": "^7.
|
|
91
|
+
"undici": "^7.21.0",
|
|
92
92
|
"vitest": "^4.0.18"
|
|
93
93
|
},
|
|
94
94
|
"resolutions": {
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"engines": {
|
|
98
98
|
"node": ">=20.16.0"
|
|
99
99
|
},
|
|
100
|
-
"packageManager": "pnpm@10.
|
|
100
|
+
"packageManager": "pnpm@10.29.2"
|
|
101
101
|
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { 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
|
-
* 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
|
|
74
|
-
export { loadServerEntry as a, defaultExts as i, LoadedServerEntry as n, defaultEntries as r, LoadOptions as t };
|
package/dist/_chunks/loader.mjs
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { pathToFileURL } from "node:url";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import * as nodeHTTP$1 from "node:http";
|
|
5
|
-
const defaultExts = [
|
|
6
|
-
".mjs",
|
|
7
|
-
".js",
|
|
8
|
-
".mts",
|
|
9
|
-
".ts"
|
|
10
|
-
];
|
|
11
|
-
const defaultEntries = [
|
|
12
|
-
"server",
|
|
13
|
-
"server/index",
|
|
14
|
-
"src/server",
|
|
15
|
-
"server/server"
|
|
16
|
-
];
|
|
17
|
-
async function loadServerEntry(opts) {
|
|
18
|
-
let entry = opts.entry;
|
|
19
|
-
if (entry) {
|
|
20
|
-
entry = resolve(opts.dir || ".", entry);
|
|
21
|
-
if (!existsSync(entry)) return { notFound: true };
|
|
22
|
-
} else {
|
|
23
|
-
for (const defEntry of defaultEntries) {
|
|
24
|
-
for (const defExt of defaultExts) {
|
|
25
|
-
const entryPath = resolve(opts.dir || ".", `${defEntry}${defExt}`);
|
|
26
|
-
if (existsSync(entryPath)) {
|
|
27
|
-
entry = entryPath;
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (entry) break;
|
|
32
|
-
}
|
|
33
|
-
if (!entry) return { notFound: true };
|
|
34
|
-
}
|
|
35
|
-
const url = entry.startsWith("file://") ? entry : pathToFileURL(resolve(entry)).href;
|
|
36
|
-
let mod;
|
|
37
|
-
let listenHandler;
|
|
38
|
-
try {
|
|
39
|
-
if (opts.interceptHttpListen !== false) {
|
|
40
|
-
const loaded = await interceptListen(() => import(url));
|
|
41
|
-
mod = loaded.res;
|
|
42
|
-
listenHandler = loaded.listenHandler;
|
|
43
|
-
} else mod = await import(url);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
46
|
-
const message = String(error);
|
|
47
|
-
if (/"\.(m|c)?ts"/g.test(message)) throw new Error(`Make sure you're using Node.js v22.18+ or v24+ for TypeScript support (current version: ${process.versions.node})`, { cause: error });
|
|
48
|
-
else if (/"\.(m|c)?tsx"/g.test(message)) throw new Error(`You need a compatible loader for JSX support (Deno, Bun or srvx --register jiti/register)`, { cause: error });
|
|
49
|
-
}
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
mod = await opts?.onLoad?.(mod) || mod;
|
|
53
|
-
let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch;
|
|
54
|
-
if (!fetchHandler && typeof mod?.default === "function" && mod.default.length < 2) fetchHandler = mod.default;
|
|
55
|
-
let nodeCompat = false;
|
|
56
|
-
if (!fetchHandler && opts.nodeCompat !== false) {
|
|
57
|
-
const nodeHandler = listenHandler || (typeof mod?.default === "function" ? mod.default : void 0);
|
|
58
|
-
if (nodeHandler) {
|
|
59
|
-
nodeCompat = true;
|
|
60
|
-
const { fetchNodeHandler } = await import("srvx/node");
|
|
61
|
-
fetchHandler = (webReq) => fetchNodeHandler(nodeHandler, webReq);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
module: mod,
|
|
66
|
-
nodeCompat,
|
|
67
|
-
url,
|
|
68
|
-
fetch: fetchHandler
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
let _interceptQueue = Promise.resolve();
|
|
72
|
-
async function interceptListen(cb) {
|
|
73
|
-
const result = _interceptQueue.then(async () => {
|
|
74
|
-
const originalListen = nodeHTTP$1.Server.prototype.listen;
|
|
75
|
-
let res;
|
|
76
|
-
let listenHandler;
|
|
77
|
-
try {
|
|
78
|
-
nodeHTTP$1.Server.prototype.listen = function(arg1, arg2) {
|
|
79
|
-
listenHandler = this._events.request;
|
|
80
|
-
if (Array.isArray(listenHandler)) listenHandler = listenHandler[0];
|
|
81
|
-
nodeHTTP$1.Server.prototype.listen = originalListen;
|
|
82
|
-
const listenCallback = [arg1, arg2].find((arg) => typeof arg === "function");
|
|
83
|
-
setImmediate(() => {
|
|
84
|
-
listenCallback?.();
|
|
85
|
-
});
|
|
86
|
-
return new Proxy({}, { get(_, prop) {
|
|
87
|
-
const server = globalThis.__srvx__;
|
|
88
|
-
if (!server && prop === "address") return () => ({
|
|
89
|
-
address: "",
|
|
90
|
-
family: "",
|
|
91
|
-
port: 0
|
|
92
|
-
});
|
|
93
|
-
return server?.node?.server?.[prop];
|
|
94
|
-
} });
|
|
95
|
-
};
|
|
96
|
-
res = await cb();
|
|
97
|
-
} finally {
|
|
98
|
-
nodeHTTP$1.Server.prototype.listen = originalListen;
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
res,
|
|
102
|
-
listenHandler
|
|
103
|
-
};
|
|
104
|
-
});
|
|
105
|
-
_interceptQueue = result.catch(() => {});
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
export { defaultExts as n, loadServerEntry as r, defaultEntries as t };
|