feat: init

This commit is contained in:
2026-02-13 22:02:30 +01:00
commit 8f9ff830fb
16711 changed files with 3307340 additions and 0 deletions

56
node_modules/srvx/dist/_chunks/_plugins.mjs generated vendored Normal file
View File

@@ -0,0 +1,56 @@
import { a as green, i as gray, n as bold, s as red } from "./_utils.mjs";
function wrapFetch(server) {
const fetchHandler = server.options.fetch;
const middleware = server.options.middleware || [];
return middleware.length === 0 ? fetchHandler : (request) => callMiddleware(request, fetchHandler, middleware, 0);
}
function callMiddleware(request, fetchHandler, middleware, index) {
if (index === middleware.length) return fetchHandler(request);
return middleware[index](request, () => callMiddleware(request, fetchHandler, middleware, index + 1));
}
const errorPlugin = (server) => {
const errorHandler = server.options.error;
if (!errorHandler) return;
server.options.middleware.unshift((_req, next) => {
try {
const res = next();
return res instanceof Promise ? res.catch((error) => errorHandler(error)) : res;
} catch (error) {
return errorHandler(error);
}
});
};
const gracefulShutdownPlugin = (server) => {
const config = server.options?.gracefulShutdown;
if (!globalThis.process?.on || config === false || config === void 0 && (process.env.CI || process.env.TEST)) return;
const gracefulTimeout = config === true || !config?.gracefulTimeout ? Number.parseInt(process.env.SERVER_SHUTDOWN_TIMEOUT || "") || 5 : config.gracefulTimeout;
let isClosing = false;
let isClosed = false;
const w = server.options.silent ? () => {} : process.stderr.write.bind(process.stderr);
const forceClose = async () => {
if (isClosed) return;
w(red("\x1B[2K\rForcibly closing connections...\n"));
isClosed = true;
await server.close(true);
};
const shutdown = async () => {
if (isClosing || isClosed) return;
setTimeout(() => {
globalThis.process.once("SIGINT", forceClose);
}, 100);
isClosing = true;
const closePromise = server.close();
for (let remaining = gracefulTimeout; remaining > 0; remaining--) {
w(gray(`\rStopping server gracefully (${remaining}s)... Press ${bold("Ctrl+C")} again to force close.`));
if (await Promise.race([closePromise.then(() => true), new Promise((r) => setTimeout(() => r(false), 1e3))])) {
w("\x1B[2K\r" + green("Server closed successfully.\n"));
isClosed = true;
return;
}
}
w("\x1B[2K\rGraceful shutdown timed out.\n");
await forceClose();
};
for (const sig of ["SIGINT", "SIGTERM"]) globalThis.process.on(sig, shutdown);
};
export { gracefulShutdownPlugin as n, wrapFetch as r, errorPlugin as t };

28
node_modules/srvx/dist/_chunks/_url.d.mts generated vendored Normal file
View File

@@ -0,0 +1,28 @@
//#region src/_url.d.ts
type URLInit = {
protocol: string;
host: string;
pathname: string;
search: string;
};
/**
* URL wrapper with fast paths to access to the following props:
*
* - `url.pathname`
* - `url.search`
* - `url.searchParams`
* - `url.protocol`
*
* **NOTES:**
*
* - It is assumed that the input URL is **already encoded** and formatted from an HTTP request and contains no hash.
* - Triggering the setters or getters on other props will deoptimize to full URL parsing.
* - Changes to `searchParams` will be discarded as we don't track them.
*/
declare const FastURL: {
new (url: string | URLInit): URL & {
_url: URL;
};
};
//#endregion
export { FastURL as t };

126
node_modules/srvx/dist/_chunks/_url.mjs generated vendored Normal file
View File

@@ -0,0 +1,126 @@
function lazyInherit(target, source, sourceKey) {
for (const key of [...Object.getOwnPropertyNames(source), ...Object.getOwnPropertySymbols(source)]) {
if (key === "constructor") continue;
const targetDesc = Object.getOwnPropertyDescriptor(target, key);
const desc = Object.getOwnPropertyDescriptor(source, key);
let modified = false;
if (desc.get) {
modified = true;
desc.get = targetDesc?.get || function() {
return this[sourceKey][key];
};
}
if (desc.set) {
modified = true;
desc.set = targetDesc?.set || function(value) {
this[sourceKey][key] = value;
};
}
if (!targetDesc?.value && typeof desc.value === "function") {
modified = true;
desc.value = function(...args) {
return this[sourceKey][key](...args);
};
}
if (modified) Object.defineProperty(target, key, desc);
}
}
const FastURL = /* @__PURE__ */ (() => {
const NativeURL = globalThis.URL;
const FastURL = class URL {
#url;
#href;
#protocol;
#host;
#pathname;
#search;
#searchParams;
#pos;
constructor(url) {
if (typeof url === "string") this.#href = url;
else {
this.#protocol = url.protocol;
this.#host = url.host;
this.#pathname = url.pathname;
this.#search = url.search;
}
}
static [Symbol.hasInstance](val) {
return val instanceof NativeURL;
}
get _url() {
if (this.#url) return this.#url;
this.#url = new NativeURL(this.href);
this.#href = void 0;
this.#protocol = void 0;
this.#host = void 0;
this.#pathname = void 0;
this.#search = void 0;
this.#searchParams = void 0;
this.#pos = void 0;
return this.#url;
}
get href() {
if (this.#url) return this.#url.href;
if (!this.#href) this.#href = `${this.#protocol || "http:"}//${this.#host || "localhost"}${this.#pathname || "/"}${this.#search || ""}`;
return this.#href;
}
#getPos() {
if (!this.#pos) {
const url = this.href;
const protoIndex = url.indexOf("://");
const pathnameIndex = protoIndex === -1 ? -1 : url.indexOf("/", protoIndex + 4);
this.#pos = [
protoIndex,
pathnameIndex,
pathnameIndex === -1 ? -1 : url.indexOf("?", pathnameIndex)
];
}
return this.#pos;
}
get pathname() {
if (this.#url) return this.#url.pathname;
if (this.#pathname === void 0) {
const [, pathnameIndex, queryIndex] = this.#getPos();
if (pathnameIndex === -1) return this._url.pathname;
this.#pathname = this.href.slice(pathnameIndex, queryIndex === -1 ? void 0 : queryIndex);
}
return this.#pathname;
}
get search() {
if (this.#url) return this.#url.search;
if (this.#search === void 0) {
const [, pathnameIndex, queryIndex] = this.#getPos();
if (pathnameIndex === -1) return this._url.search;
const url = this.href;
this.#search = queryIndex === -1 || queryIndex === url.length - 1 ? "" : url.slice(queryIndex);
}
return this.#search;
}
get searchParams() {
if (this.#url) return this.#url.searchParams;
if (!this.#searchParams) this.#searchParams = new URLSearchParams(this.search);
return this.#searchParams;
}
get protocol() {
if (this.#url) return this.#url.protocol;
if (this.#protocol === void 0) {
const [protocolIndex] = this.#getPos();
if (protocolIndex === -1) return this._url.protocol;
this.#protocol = this.href.slice(0, protocolIndex + 1);
}
return this.#protocol;
}
toString() {
return this.href;
}
toJSON() {
return this.href;
}
};
lazyInherit(FastURL.prototype, NativeURL.prototype, "_url");
Object.setPrototypeOf(FastURL.prototype, NativeURL.prototype);
Object.setPrototypeOf(FastURL, NativeURL);
return FastURL;
})();
export { lazyInherit as n, FastURL as t };

15
node_modules/srvx/dist/_chunks/_utils.mjs generated vendored Normal file
View File

@@ -0,0 +1,15 @@
const noColor = /* @__PURE__ */ (() => {
const env = globalThis.process?.env ?? {};
return env.NO_COLOR === "1" || env.TERM === "dumb";
})();
const _c = (c, r = 39) => (t) => noColor ? t : `\u001B[${c}m${t}\u001B[${r}m`;
const bold = /* @__PURE__ */ _c(1, 22);
const red = /* @__PURE__ */ _c(31);
const green = /* @__PURE__ */ _c(32);
const yellow = /* @__PURE__ */ _c(33);
const blue = /* @__PURE__ */ _c(34);
const magenta = /* @__PURE__ */ _c(35);
const cyan = /* @__PURE__ */ _c(36);
const gray = /* @__PURE__ */ _c(90);
const url = (title, url) => noColor ? `[${title}](${url})` : `\u001B]8;;${url}\u001B\\${title}\u001B]8;;\u001B\\`;
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 };

70
node_modules/srvx/dist/_chunks/_utils2.mjs generated vendored Normal file
View File

@@ -0,0 +1,70 @@
function resolvePortAndHost(opts) {
const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
if (port < 0 || port > 65535) throw new RangeError(`Port must be between 0 and 65535 (got "${port}").`);
return {
port,
hostname: opts.hostname ?? globalThis.process?.env.HOST
};
}
function fmtURL(host, port, secure) {
if (!host || !port) return;
if (host.includes(":")) host = `[${host}]`;
return `http${secure ? "s" : ""}://${host}:${port}/`;
}
function printListening(opts, url) {
if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) return;
let additionalInfo = "";
try {
const _url = new URL(url);
if (_url.hostname === "[::]" || _url.hostname === "0.0.0.0") {
_url.hostname = "localhost";
url = _url.href;
additionalInfo = " (all interfaces)";
}
} catch {}
let listeningOn = `➜ Listening on:`;
if (globalThis.process.stdout?.isTTY) {
listeningOn = `\u001B[32m${listeningOn}\u001B[0m`;
url = `\u001B[36m${url}\u001B[0m`;
additionalInfo = `\u001B[2m${additionalInfo}\u001B[0m`;
}
console.log(`${listeningOn} ${url}${additionalInfo}`);
}
function resolveTLSOptions(opts) {
if (!opts.tls || opts.protocol === "http") return;
const cert = resolveCertOrKey(opts.tls.cert);
const key = resolveCertOrKey(opts.tls.key);
if (!cert && !key) {
if (opts.protocol === "https") throw new TypeError("TLS `cert` and `key` must be provided for `https` protocol.");
return;
}
if (!cert || !key) throw new TypeError("TLS `cert` and `key` must be provided together.");
return {
cert,
key,
passphrase: opts.tls.passphrase
};
}
function resolveCertOrKey(value) {
if (!value) return;
if (typeof value !== "string") throw new TypeError("TLS certificate and key must be strings in PEM format or file paths.");
if (value.startsWith("-----BEGIN ")) return value;
const { readFileSync } = process.getBuiltinModule("node:fs");
return readFileSync(value, "utf8");
}
function createWaitUntil() {
const promises = /* @__PURE__ */ new Set();
return {
waitUntil: (promise) => {
if (typeof promise?.then !== "function") return;
promises.add(Promise.resolve(promise).catch(console.error).finally(() => {
promises.delete(promise);
}));
},
wait: () => {
return Promise.all(promises);
}
};
}
export { resolveTLSOptions as a, resolvePortAndHost as i, fmtURL as n, printListening as r, createWaitUntil as t };

19
node_modules/srvx/dist/adapters/aws-lambda.d.mts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
import { FetchHandler, ServerOptions } from "../types.mjs";
import * as AWS from "aws-lambda";
//#region src/adapters/_aws/utils.d.ts
type AWSLambdaResponseStream = NodeJS.WritableStream & {
setContentType(contentType: string): void;
};
//#endregion
//#region src/adapters/aws-lambda.d.ts
type MaybePromise<T> = T | Promise<T>;
type AwsLambdaEvent = AWS.APIGatewayProxyEvent | AWS.APIGatewayProxyEventV2;
type AWSLambdaHandler = (event: AwsLambdaEvent, context: AWS.Context) => MaybePromise<AWS.APIGatewayProxyResult | AWS.APIGatewayProxyResultV2>;
type AWSLambdaStreamingHandler = (event: AwsLambdaEvent, responseStream: AWSLambdaResponseStream, context: AWS.Context) => MaybePromise<void>;
declare function toLambdaHandler(options: ServerOptions): AWSLambdaHandler;
declare function handleLambdaEvent(fetchHandler: FetchHandler, event: AwsLambdaEvent, context: AWS.Context): Promise<AWS.APIGatewayProxyResult | AWS.APIGatewayProxyResultV2>;
declare function handleLambdaEventWithStream(fetchHandler: FetchHandler, event: AwsLambdaEvent, responseStream: AWSLambdaResponseStream, context: AWS.Context): Promise<void>;
declare function invokeLambdaHandler(handler: AWSLambdaHandler, request: Request): Promise<Response>;
//#endregion
export { AWSLambdaHandler, type AWSLambdaResponseStream, AWSLambdaStreamingHandler, AwsLambdaEvent, handleLambdaEvent, handleLambdaEventWithStream, invokeLambdaHandler, toLambdaHandler };

292
node_modules/srvx/dist/adapters/aws-lambda.mjs generated vendored Normal file
View File

@@ -0,0 +1,292 @@
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
function awsRequest(event, context) {
const req = new Request(awsEventURL(event), {
method: awsEventMethod(event),
headers: awsEventHeaders(event),
body: awsEventBody(event)
});
req.runtime = {
name: "aws-lambda",
awsLambda: {
event,
context
}
};
req.ip = awsEventIP(event);
return req;
}
function awsEventMethod(event) {
return event.httpMethod || event.requestContext?.http?.method || "GET";
}
function awsEventIP(event) {
return event.requestContext?.http?.sourceIp || event.requestContext?.identity?.sourceIp;
}
function awsEventURL(event) {
const hostname = event.headers.host || event.headers.Host || event.requestContext?.domainName || ".";
const path = event.path || event.rawPath;
const query = awsEventQuery(event);
const protocol = (event.headers["X-Forwarded-Proto"] || event.headers["x-forwarded-proto"]) === "http" ? "http" : "https";
return new URL(`${path}${query ? `?${query}` : ""}`, `${protocol}://${hostname}`);
}
function awsEventQuery(event) {
if (typeof event.rawQueryString === "string") return event.rawQueryString;
return stringifyQuery({
...event.queryStringParameters,
...event.multiValueQueryStringParameters
});
}
function awsEventHeaders(event) {
const headers = new Headers();
for (const [key, value] of Object.entries(event.headers)) if (value) headers.set(key, value);
if ("cookies" in event && event.cookies) for (const cookie of event.cookies) headers.append("cookie", cookie);
return headers;
}
function awsEventBody(event) {
if (!event.body) return;
if (event.isBase64Encoded) return Buffer.from(event.body || "", "base64");
return event.body;
}
function awsResponseHeaders(response, event) {
const headers = Object.create(null);
for (const [key, value] of response.headers) if (value) headers[key] = Array.isArray(value) ? value.join(",") : String(value);
const cookies = response.headers.getSetCookie();
if (cookies.length === 0) return { headers };
return event?.version === "2.0" || !!event?.requestContext?.http ? {
headers,
cookies
} : {
headers,
cookies,
multiValueHeaders: { "set-cookie": cookies }
};
}
async function awsResponseBody(response) {
if (!response.body) return { body: "" };
const buffer = await toBuffer(response.body);
return isTextType(response.headers.get("content-type") || "") ? { body: buffer.toString("utf8") } : {
body: buffer.toString("base64"),
isBase64Encoded: true
};
}
async function awsStreamResponse(response, responseStream, event) {
const metadata = {
statusCode: response.status,
...awsResponseHeaders(response, event)
};
if (!metadata.headers["transfer-encoding"]) metadata.headers["transfer-encoding"] = "chunked";
const writer = globalThis.awslambda.HttpResponseStream.from(responseStream, metadata);
if (!response.body) {
writer.end();
return;
}
try {
await streamToNodeStream(response.body, writer);
} finally {
writer.end();
}
}
async function streamToNodeStream(body, writer) {
const reader = body.getReader();
try {
let result = await reader.read();
while (!result.done) {
if (!writer.write(result.value)) await new Promise((resolve) => writer.once("drain", resolve));
result = await reader.read();
}
} finally {
reader.releaseLock();
}
}
function isTextType(contentType = "") {
return /^text\/|\/(javascript|json|xml)|utf-?8/i.test(contentType);
}
function toBuffer(data) {
return new Promise((resolve, reject) => {
const chunks = [];
data.pipeTo(new WritableStream({
write(chunk) {
chunks.push(chunk);
},
close() {
resolve(Buffer.concat(chunks));
},
abort(reason) {
reject(reason);
}
})).catch(reject);
});
}
function stringifyQuery(obj) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(obj)) {
if (value == null) continue;
if (Array.isArray(value)) for (const v of value) params.append(key, String(v));
else params.append(key, String(value));
}
return params.toString();
}
async function requestToAwsEvent(request) {
const url = new URL(request.url);
const headers = {};
const cookies = [];
for (const [key, value] of request.headers) {
if (key.toLowerCase() === "cookie") cookies.push(value);
headers[key] = value;
}
let body;
let isBase64Encoded = false;
if (request.body) {
const buffer = await toBuffer(request.body);
if (isTextType(request.headers.get("content-type") || "")) body = buffer.toString("utf8");
else {
body = buffer.toString("base64");
isBase64Encoded = true;
}
}
const now = Date.now();
return {
httpMethod: request.method,
path: url.pathname,
resource: url.pathname,
queryStringParameters: Object.fromEntries(url.searchParams),
multiValueQueryStringParameters: parseMultiValueQuery(url.searchParams),
pathParameters: void 0,
stageVariables: void 0,
multiValueHeaders: Object.fromEntries([...request.headers].map(([k, v]) => [k, [v]])),
version: "2.0",
rawPath: url.pathname,
rawQueryString: url.search.slice(1),
cookies: cookies.length > 0 ? cookies : void 0,
routeKey: `${request.method} ${url.pathname}`,
headers,
body: body ?? null,
isBase64Encoded,
requestContext: {
accountId: "000000000000",
apiId: "local",
resourceId: "local",
stage: "$default",
requestId: crypto.randomUUID(),
identity: {
sourceIp: "127.0.0.1",
userAgent: request.headers.get("user-agent") || "",
accessKey: null,
accountId: null,
apiKey: null,
apiKeyId: null,
caller: null,
clientCert: null,
cognitoAuthenticationProvider: null,
cognitoAuthenticationType: null,
cognitoIdentityId: null,
cognitoIdentityPoolId: null,
principalOrgId: null,
user: null,
userArn: null
},
resourcePath: url.pathname,
httpMethod: request.method,
path: url.pathname,
protocol: "HTTP/1.1",
requestTimeEpoch: now,
authorizer: void 0,
domainName: url.hostname,
http: {
method: request.method,
path: url.pathname,
protocol: "HTTP/1.1",
sourceIp: "127.0.0.1",
userAgent: request.headers.get("user-agent") || ""
},
routeKey: `${request.method} ${url.pathname}`,
time: new Date(now).toISOString(),
timeEpoch: now,
domainPrefix: url.hostname.split(".")[0]
}
};
}
function parseMultiValueQuery(params) {
const result = {};
for (const [key, value] of params) {
if (!result[key]) result[key] = [];
result[key].push(value);
}
return result;
}
function awsResultToResponse(result) {
if (typeof result === "string") return new Response(result, { status: 200 });
const headers = new Headers();
if (result.headers) {
for (const [key, value] of Object.entries(result.headers)) if (value !== void 0) headers.set(key, String(value));
}
if ("multiValueHeaders" in result && result.multiValueHeaders) {
for (const [key, values] of Object.entries(result.multiValueHeaders)) if (values) for (const value of values) headers.append(key, String(value));
}
if ("cookies" in result && result.cookies) for (const cookie of result.cookies) headers.append("set-cookie", cookie);
let body;
if (typeof result.body === "string") if (result.isBase64Encoded) body = Buffer.from(result.body, "base64");
else body = result.body;
const statusCode = typeof result.statusCode === "number" ? result.statusCode : 200;
return new Response(body, {
status: statusCode,
headers
});
}
function createMockContext() {
const id = crypto.randomUUID();
return {
callbackWaitsForEmptyEventLoop: true,
functionName: "local",
functionVersion: "$LATEST",
invokedFunctionArn: `arn:aws:lambda:us-east-1:000000000000:function:local`,
memoryLimitInMB: "128",
awsRequestId: id,
logGroupName: "/aws/lambda/local",
logStreamName: `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}/[$LATEST]${id}`,
getRemainingTimeInMillis: () => 3e4,
done: () => {},
fail: () => {},
succeed: () => {}
};
}
function toLambdaHandler(options) {
const server = new AWSLambdaServer(options);
return (event, context) => server.fetch(event, context);
}
async function handleLambdaEvent(fetchHandler, event, context) {
const response = await fetchHandler(awsRequest(event, context));
return {
statusCode: response.status,
...awsResponseHeaders(response, event),
...await awsResponseBody(response)
};
}
async function handleLambdaEventWithStream(fetchHandler, event, responseStream, context) {
await awsStreamResponse(await fetchHandler(awsRequest(event, context)), responseStream, event);
}
async function invokeLambdaHandler(handler, request) {
return awsResultToResponse(await handler(await requestToAwsEvent(request), createMockContext()));
}
var AWSLambdaServer = class {
runtime = "aws-lambda";
options;
fetch;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
errorPlugin(this);
const fetchHandler = wrapFetch(this);
this.fetch = (event, context) => handleLambdaEvent(fetchHandler, event, context);
}
serve() {}
ready() {
return Promise.resolve().then(() => this);
}
close() {
return Promise.resolve();
}
};
export { handleLambdaEvent, handleLambdaEventWithStream, invokeLambdaHandler, toLambdaHandler };

22
node_modules/srvx/dist/adapters/bun.d.mts generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import { BunFetchHandler, Server, ServerOptions } from "../types.mjs";
import { t as FastURL } from "../_chunks/_url.mjs";
import * as bun from "bun";
//#region src/adapters/bun.d.ts
declare const FastResponse: typeof globalThis.Response;
declare function serve(options: ServerOptions): BunServer;
declare class BunServer implements Server<BunFetchHandler> {
#private;
readonly runtime = "bun";
readonly options: Server["options"];
readonly bun: Server["bun"];
readonly serveOptions: bun.Serve.Options<any> | undefined;
readonly fetch: BunFetchHandler;
constructor(options: ServerOptions);
serve(): Promise<this>;
get url(): string | undefined;
ready(): Promise<this>;
close(closeAll?: boolean): Promise<void>;
}
//#endregion
export { FastResponse, FastURL, serve };

84
node_modules/srvx/dist/adapters/bun.mjs generated vendored Normal file
View File

@@ -0,0 +1,84 @@
import { t as FastURL } from "../_chunks/_url.mjs";
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
const FastResponse = Response;
function serve(options) {
return new BunServer(options);
}
var BunServer = class {
runtime = "bun";
options;
bun = {};
serveOptions;
fetch;
#wait;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
gracefulShutdownPlugin(this);
const fetchHandler = wrapFetch(this);
const loader = globalThis.__srvxLoader__;
if (loader) {
this.fetch = fetchHandler;
loader(fetchHandler);
return;
}
this.#wait = createWaitUntil();
this.fetch = (request, server) => {
Object.defineProperties(request, {
waitUntil: { value: this.#wait?.waitUntil },
runtime: {
enumerable: true,
value: {
name: "bun",
bun: { server }
}
},
ip: {
enumerable: true,
get() {
return server?.requestIP(request)?.address;
}
}
});
return fetchHandler(request);
};
const tls = resolveTLSOptions(this.options);
this.serveOptions = {
...resolvePortAndHost(this.options),
reusePort: this.options.reusePort,
error: this.options.error,
...this.options.bun,
tls: {
cert: tls?.cert,
key: tls?.key,
passphrase: tls?.passphrase,
...this.options.bun?.tls
},
fetch: this.fetch
};
if (!options.manual) this.serve();
}
serve() {
if (!this.bun.server) this.bun.server = Bun.serve(this.serveOptions);
printListening(this.options, this.url);
return Promise.resolve(this);
}
get url() {
const server = this.bun?.server;
if (!server) return;
const address = server.address;
if (address) return fmtURL(address.address, address.port, server.protocol === "https");
return server.url.href;
}
ready() {
return Promise.resolve(this);
}
async close(closeAll) {
await Promise.all([this.#wait?.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
}
};
export { FastResponse, FastURL, serve };

9
node_modules/srvx/dist/adapters/cloudflare.d.mts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import { Server, ServerOptions } from "../types.mjs";
import * as CF from "@cloudflare/workers-types";
//#region src/adapters/cloudflare.d.ts
declare const FastURL: typeof globalThis.URL;
declare const FastResponse: typeof globalThis.Response;
declare function serve(options: ServerOptions): Server<CF.ExportedHandlerFetchHandler>;
//#endregion
export { FastResponse, FastURL, serve };

57
node_modules/srvx/dist/adapters/cloudflare.mjs generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
const FastURL = URL;
const FastResponse = Response;
function serve(options) {
return new CloudflareServer(options);
}
var CloudflareServer = class {
runtime = "cloudflare";
options;
serveOptions;
fetch;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
errorPlugin(this);
const fetchHandler = wrapFetch(this);
this.fetch = (request, env, context) => {
Object.defineProperties(request, {
waitUntil: { value: context.waitUntil.bind(context) },
runtime: {
enumerable: true,
value: {
name: "cloudflare",
cloudflare: {
env,
context
}
}
},
ip: {
enumerable: true,
get() {
return request.headers.get("cf-connecting-ip");
}
}
});
return fetchHandler(request);
};
this.serveOptions = { fetch: this.fetch };
if (!options.manual) this.serve();
}
serve() {
addEventListener("fetch", (event) => {
event.respondWith(this.fetch(event.request, {}, event));
});
}
ready() {
return Promise.resolve().then(() => this);
}
close() {
return Promise.resolve();
}
};
export { FastResponse, FastURL, serve };

21
node_modules/srvx/dist/adapters/deno.d.mts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { DenoFetchHandler, Server, ServerOptions } from "../types.mjs";
import { t as FastURL } from "../_chunks/_url.mjs";
//#region src/adapters/deno.d.ts
declare const FastResponse: typeof globalThis.Response;
declare function serve(options: ServerOptions): DenoServer;
declare class DenoServer implements Server<DenoFetchHandler> {
#private;
readonly runtime = "deno";
readonly options: Server["options"];
readonly deno: Server["deno"];
readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem) | undefined;
readonly fetch: DenoFetchHandler;
constructor(options: ServerOptions);
serve(): Promise<this>;
get url(): string | undefined;
ready(): Promise<Server>;
close(): Promise<void>;
}
//#endregion
export { FastResponse, FastURL, serve };

93
node_modules/srvx/dist/adapters/deno.mjs generated vendored Normal file
View File

@@ -0,0 +1,93 @@
import { t as FastURL } from "../_chunks/_url.mjs";
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
import { n as gracefulShutdownPlugin, r as wrapFetch } from "../_chunks/_plugins.mjs";
const FastResponse = Response;
function serve(options) {
return new DenoServer(options);
}
var DenoServer = class {
runtime = "deno";
options;
deno = {};
serveOptions;
fetch;
#listeningPromise;
#listeningInfo;
#wait;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
gracefulShutdownPlugin(this);
const fetchHandler = wrapFetch(this);
const loader = globalThis.__srvxLoader__;
if (loader) {
this.fetch = fetchHandler;
loader(fetchHandler);
return;
}
this.#wait = createWaitUntil();
this.fetch = (request, info) => {
Object.defineProperties(request, {
waitUntil: { value: this.#wait?.waitUntil },
runtime: {
enumerable: true,
value: {
name: "deno",
deno: {
info,
server: this.deno?.server
}
}
},
ip: {
enumerable: true,
get() {
return (info?.remoteAddr)?.hostname;
}
}
});
return fetchHandler(request);
};
const tls = resolveTLSOptions(this.options);
this.serveOptions = {
...resolvePortAndHost(this.options),
reusePort: this.options.reusePort,
onError: this.options.error,
...tls ? {
key: tls.key,
cert: tls.cert,
passphrase: tls.passphrase
} : {},
...this.options.deno
};
if (!options.manual) this.serve();
}
serve() {
if (this.deno?.server) return Promise.resolve(this.#listeningPromise).then(() => this);
const onListenPromise = Promise.withResolvers();
this.#listeningPromise = onListenPromise.promise;
this.deno.server = Deno.serve({
...this.serveOptions,
onListen: (info) => {
this.#listeningInfo = info;
if (this.options.deno?.onListen) this.options.deno.onListen(info);
printListening(this.options, this.url);
onListenPromise.resolve();
}
}, this.fetch);
return Promise.resolve(this.#listeningPromise).then(() => this);
}
get url() {
return this.#listeningInfo ? fmtURL(this.#listeningInfo.hostname, this.#listeningInfo.port, !!this.serveOptions.cert) : void 0;
}
ready() {
return Promise.resolve(this.#listeningPromise).then(() => this);
}
async close() {
await Promise.all([this.#wait?.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
}
};
export { FastResponse, FastURL, serve };

8
node_modules/srvx/dist/adapters/generic.d.mts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
import { Server, ServerOptions } from "../types.mjs";
//#region src/adapters/generic.d.ts
declare const FastURL: typeof globalThis.URL;
declare const FastResponse: typeof globalThis.Response;
declare function serve(options: ServerOptions): Server;
//#endregion
export { FastResponse, FastURL, serve };

35
node_modules/srvx/dist/adapters/generic.mjs generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import { t as createWaitUntil } from "../_chunks/_utils2.mjs";
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
const FastURL = URL;
const FastResponse = Response;
function serve(options) {
return new GenericServer(options);
}
var GenericServer = class {
runtime = "generic";
options;
fetch;
#wait;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
errorPlugin(this);
this.#wait = createWaitUntil();
const fetchHandler = wrapFetch(this);
this.fetch = (request) => {
Object.defineProperties(request, { waitUntil: { value: this.#wait.waitUntil } });
return Promise.resolve(fetchHandler(request));
};
}
serve() {}
ready() {
return Promise.resolve(this);
}
async close() {
await this.#wait.wait();
}
};
export { FastResponse, FastURL, serve };

78
node_modules/srvx/dist/adapters/node.d.mts generated vendored Normal file
View File

@@ -0,0 +1,78 @@
import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../types.mjs";
import { t as FastURL } from "../_chunks/_url.mjs";
import { Readable } from "node:stream";
//#region src/adapters/_node/request.d.ts
type NodeRequestContext = {
req: NodeServerRequest;
res?: NodeServerResponse;
};
declare const NodeRequest: {
new (nodeCtx: NodeRequestContext): ServerRequest;
};
/**
* Undici uses an incompatible Request constructor depending on private property accessors.
*
* This utility, patches global Request to support `new Request(req)` in Node.js.
*
* Alternatively you can use `new Request(req._request || req)` instead of patching global Request.
*/
declare function patchGlobalRequest(): typeof Request;
//#endregion
//#region src/adapters/_node/response.d.ts
type PreparedNodeResponseBody = string | Buffer | Uint8Array | DataView | ReadableStream | Readable | undefined | null;
interface PreparedNodeResponse {
status: number;
statusText: string;
headers: [string, string][];
body: PreparedNodeResponseBody;
}
/**
* Fast Response for Node.js runtime
*
* It is faster because in most cases it doesn't create a full Response instance.
*/
declare const NodeResponse: {
new (body?: BodyInit | null, init?: ResponseInit): globalThis.Response & {
_toNodeResponse: () => PreparedNodeResponse;
};
};
type NodeResponse = InstanceType<typeof NodeResponse>;
//#endregion
//#region src/adapters/_node/send.d.ts
declare function sendNodeResponse(nodeRes: NodeServerResponse, webRes: Response | NodeResponse): Promise<void>;
//#endregion
//#region src/adapters/_node/web/fetch.d.ts
/**
* Calls a Node.js HTTP Request handler with a Fetch API Request object and returns a Response object.
*
* 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.
*
* 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.
*
* The handler is invoked with these objects, and the response is constructed from the ServerResponse once it is finished.
*
* @experimental Behavior might be unstable.
*/
declare function fetchNodeHandler(handler: NodeHttpHandler, req: ServerRequest): Promise<Response>;
//#endregion
//#region src/adapters/_node/adapter.d.ts
type AdapterMeta = {
__nodeHandler?: NodeHttpHandler;
__fetchHandler?: FetchHandler;
};
/**
* Converts a Fetch API handler to a Node.js HTTP handler.
*/
declare function toNodeHandler(handler: FetchHandler & AdapterMeta): NodeHttpHandler & AdapterMeta;
/**
* Converts a Node.js HTTP handler into a Fetch API handler.
*
* @experimental Behavior might be unstable and won't work in Bun and Deno currently (tracker: https://github.com/h3js/srvx/issues/132)
*/
declare function toFetchHandler(handler: NodeHttpHandler & AdapterMeta): FetchHandler & AdapterMeta;
//#endregion
//#region src/adapters/node.d.ts
declare function serve(options: ServerOptions): Server;
//#endregion
export { type AdapterMeta, NodeResponse as FastResponse, NodeResponse, FastURL, NodeRequest, fetchNodeHandler, patchGlobalRequest, sendNodeResponse, serve, toFetchHandler, toNodeHandler };

744
node_modules/srvx/dist/adapters/node.mjs generated vendored Normal file
View File

@@ -0,0 +1,744 @@
import { n as lazyInherit, t as FastURL } from "../_chunks/_url.mjs";
import { a as resolveTLSOptions, i as resolvePortAndHost, n as fmtURL, r as printListening, t as createWaitUntil } from "../_chunks/_utils2.mjs";
import { n as gracefulShutdownPlugin, r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";
import { Duplex, PassThrough, Readable } from "node:stream";
import nodeHTTPS from "node:https";
import nodeHTTP2 from "node:http2";
async function sendNodeResponse(nodeRes, webRes) {
if (!webRes) {
nodeRes.statusCode = 500;
return endNodeResponse(nodeRes);
}
if (webRes._toNodeResponse) {
const res = webRes._toNodeResponse();
writeHead(nodeRes, res.status, res.statusText, res.headers);
if (res.body) {
if (res.body instanceof ReadableStream) return streamBody(res.body, nodeRes);
else if (typeof res.body?.pipe === "function") {
res.body.pipe(nodeRes);
return new Promise((resolve) => nodeRes.on("close", resolve));
}
nodeRes.write(res.body);
}
return endNodeResponse(nodeRes);
}
const rawHeaders = [...webRes.headers];
writeHead(nodeRes, webRes.status, webRes.statusText, rawHeaders);
return webRes.body ? streamBody(webRes.body, nodeRes) : endNodeResponse(nodeRes);
}
function writeHead(nodeRes, status, statusText, rawHeaders) {
const writeHeaders = globalThis.Deno ? rawHeaders : rawHeaders.flat();
if (!nodeRes.headersSent) if (nodeRes.req?.httpVersion === "2.0") nodeRes.writeHead(status, writeHeaders);
else nodeRes.writeHead(status, statusText, writeHeaders);
}
function endNodeResponse(nodeRes) {
return new Promise((resolve) => nodeRes.end(resolve));
}
function streamBody(stream, nodeRes) {
if (nodeRes.destroyed) {
stream.cancel();
return;
}
const reader = stream.getReader();
function streamCancel(error) {
reader.cancel(error).catch(() => {});
if (error) nodeRes.destroy(error);
}
function streamHandle({ done, value }) {
try {
if (done) nodeRes.end();
else if (nodeRes.write(value)) reader.read().then(streamHandle, streamCancel);
else nodeRes.once("drain", () => reader.read().then(streamHandle, streamCancel));
} catch (error) {
streamCancel(error instanceof Error ? error : void 0);
}
}
nodeRes.on("close", streamCancel);
nodeRes.on("error", streamCancel);
reader.read().then(streamHandle, streamCancel);
return reader.closed.catch(streamCancel).finally(() => {
nodeRes.off("close", streamCancel);
nodeRes.off("error", streamCancel);
});
}
var NodeRequestURL = class extends FastURL {
#req;
constructor({ req }) {
const path = req.url || "/";
if (path[0] === "/") {
const qIndex = path.indexOf("?");
const pathname = qIndex === -1 ? path : path?.slice(0, qIndex) || "/";
const search = qIndex === -1 ? "" : path?.slice(qIndex) || "";
const host = req.headers.host || req.headers[":authority"] || `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
const protocol = req.socket?.encrypted || req.headers["x-forwarded-proto"] === "https" || req.headers[":scheme"] === "https" ? "https:" : "http:";
super({
protocol,
host,
pathname,
search
});
} else super(path);
this.#req = req;
}
get pathname() {
return super.pathname;
}
set pathname(value) {
this._url.pathname = value;
this.#req.url = this._url.pathname + this._url.search;
}
};
const NodeRequestHeaders = /* @__PURE__ */ (() => {
const NativeHeaders = globalThis.Headers;
class Headers {
#req;
#headers;
constructor(req) {
this.#req = req;
}
static [Symbol.hasInstance](val) {
return val instanceof NativeHeaders;
}
get _headers() {
if (!this.#headers) {
const headers = new NativeHeaders();
const rawHeaders = this.#req.rawHeaders;
const len = rawHeaders.length;
for (let i = 0; i < len; i += 2) {
const key = rawHeaders[i];
if (key.charCodeAt(0) === 58) continue;
const value = rawHeaders[i + 1];
headers.append(key, value);
}
this.#headers = headers;
}
return this.#headers;
}
get(name) {
if (this.#headers) return this.#headers.get(name);
const value = this.#req.headers[name.toLowerCase()];
return Array.isArray(value) ? value.join(", ") : value || null;
}
has(name) {
if (this.#headers) return this.#headers.has(name);
return name.toLowerCase() in this.#req.headers;
}
getSetCookie() {
if (this.#headers) return this.#headers.getSetCookie();
const value = this.#req.headers["set-cookie"];
return Array.isArray(value) ? value : value ? [value] : [];
}
*_entries() {
const rawHeaders = this.#req.rawHeaders;
const len = rawHeaders.length;
for (let i = 0; i < len; i += 2) {
const key = rawHeaders[i];
if (key.charCodeAt(0) === 58) continue;
yield [key.toLowerCase(), rawHeaders[i + 1]];
}
}
entries() {
return this.#headers ? this.#headers.entries() : this._entries();
}
[Symbol.iterator]() {
return this.entries();
}
}
lazyInherit(Headers.prototype, NativeHeaders.prototype, "_headers");
Object.setPrototypeOf(Headers, NativeHeaders);
Object.setPrototypeOf(Headers.prototype, NativeHeaders.prototype);
return Headers;
})();
const NodeRequest = /* @__PURE__ */ (() => {
const NativeRequest = globalThis.Request;
class Request {
runtime;
#req;
#url;
#bodyStream;
#request;
#headers;
#abortController;
constructor(ctx) {
this.#req = ctx.req;
this.runtime = {
name: "node",
node: ctx
};
}
static [Symbol.hasInstance](val) {
return val instanceof NativeRequest;
}
get ip() {
return this.#req.socket?.remoteAddress;
}
get method() {
if (this.#request) return this.#request.method;
return this.#req.method || "GET";
}
get _url() {
return this.#url ||= new NodeRequestURL({ req: this.#req });
}
set _url(url) {
this.#url = url;
}
get url() {
if (this.#request) return this.#request.url;
return this._url.href;
}
get headers() {
if (this.#request) return this.#request.headers;
return this.#headers ||= new NodeRequestHeaders(this.#req);
}
get _abortController() {
if (!this.#abortController) {
this.#abortController = new AbortController();
const { req, res } = this.runtime.node;
const abortController = this.#abortController;
const abort = (err) => abortController.abort?.(err);
if (res) res.once("close", () => {
const reqError = req.errored;
if (reqError) abort(reqError);
else if (!res.writableEnded) abort();
});
else req.once("close", () => {
if (!req.complete) abort();
});
}
return this.#abortController;
}
get signal() {
return this.#request ? this.#request.signal : this._abortController.signal;
}
get body() {
if (this.#request) return this.#request.body;
if (this.#bodyStream === void 0) {
const method = this.method;
this.#bodyStream = !(method === "GET" || method === "HEAD") ? Readable.toWeb(this.#req) : null;
}
return this.#bodyStream;
}
text() {
if (this.#request) return this.#request.text();
if (this.#bodyStream !== void 0) return this.#bodyStream ? new Response(this.#bodyStream).text() : Promise.resolve("");
return readBody(this.#req).then((buf) => buf.toString());
}
json() {
if (this.#request) return this.#request.json();
return this.text().then((text) => JSON.parse(text));
}
get _request() {
if (!this.#request) {
const body = this.body;
this.#request = new NativeRequest(this.url, {
method: this.method,
headers: this.headers,
signal: this._abortController.signal,
body,
duplex: body ? "half" : void 0
});
this.#headers = void 0;
this.#bodyStream = void 0;
}
return this.#request;
}
}
lazyInherit(Request.prototype, NativeRequest.prototype, "_request");
Object.setPrototypeOf(Request.prototype, NativeRequest.prototype);
return Request;
})();
function patchGlobalRequest() {
const NativeRequest = globalThis[Symbol.for("srvx.nativeRequest")] ??= globalThis.Request;
const PatchedRequest = class Request extends NativeRequest {
static _srvx = true;
static [Symbol.hasInstance](instance) {
if (this === PatchedRequest) return instance instanceof NativeRequest;
else return Object.prototype.isPrototypeOf.call(this.prototype, instance);
}
constructor(input, options) {
if (typeof input === "object" && "_request" in input) input = input._request;
super(input, options);
}
};
if (!globalThis.Request._srvx) globalThis.Request = PatchedRequest;
return PatchedRequest;
}
function readBody(req) {
if ("rawBody" in req && Buffer.isBuffer(req.rawBody)) return Promise.resolve(req.rawBody);
return new Promise((resolve, reject) => {
const chunks = [];
const onData = (chunk) => {
chunks.push(chunk);
};
const onError = (err) => {
reject(err);
};
const onEnd = () => {
req.off("error", onError);
req.off("data", onData);
resolve(Buffer.concat(chunks));
};
req.on("data", onData).once("end", onEnd).once("error", onError);
});
}
const NodeResponse = /* @__PURE__ */ (() => {
const NativeResponse = globalThis.Response;
const STATUS_CODES = globalThis.process?.getBuiltinModule?.("node:http")?.STATUS_CODES || {};
class NodeResponse {
#body;
#init;
#headers;
#response;
constructor(body, init) {
this.#body = body;
this.#init = init;
}
static [Symbol.hasInstance](val) {
return val instanceof NativeResponse;
}
get status() {
return this.#response?.status || this.#init?.status || 200;
}
get statusText() {
return this.#response?.statusText || this.#init?.statusText || STATUS_CODES[this.status] || "";
}
get headers() {
if (this.#response) return this.#response.headers;
if (this.#headers) return this.#headers;
const initHeaders = this.#init?.headers;
return this.#headers = initHeaders instanceof Headers ? initHeaders : new Headers(initHeaders);
}
get ok() {
if (this.#response) return this.#response.ok;
const status = this.status;
return status >= 200 && status < 300;
}
get _response() {
if (this.#response) return this.#response;
let body = this.#body;
if (body && typeof body.pipe === "function" && !(body instanceof Readable)) {
const stream = new PassThrough();
body.pipe(stream);
const abort = body.abort;
if (abort) stream.once("close", () => abort());
body = stream;
}
this.#response = new NativeResponse(body, this.#headers ? {
...this.#init,
headers: this.#headers
} : this.#init);
this.#init = void 0;
this.#headers = void 0;
this.#body = void 0;
return this.#response;
}
_toNodeResponse() {
const status = this.status;
const statusText = this.statusText;
let body;
let contentType;
let contentLength;
if (this.#response) body = this.#response.body;
else if (this.#body) if (this.#body instanceof ReadableStream) body = this.#body;
else if (typeof this.#body === "string") {
body = this.#body;
contentType = "text/plain; charset=UTF-8";
contentLength = Buffer.byteLength(this.#body);
} else if (this.#body instanceof ArrayBuffer) {
body = Buffer.from(this.#body);
contentLength = this.#body.byteLength;
} else if (this.#body instanceof Uint8Array) {
body = this.#body;
contentLength = this.#body.byteLength;
} else if (this.#body instanceof DataView) {
body = Buffer.from(this.#body.buffer);
contentLength = this.#body.byteLength;
} else if (this.#body instanceof Blob) {
body = this.#body.stream();
contentType = this.#body.type;
contentLength = this.#body.size;
} else if (typeof this.#body.pipe === "function") body = this.#body;
else body = this._response.body;
const headers = [];
const initHeaders = this.#init?.headers;
const headerEntries = this.#response?.headers || this.#headers || (initHeaders ? Array.isArray(initHeaders) ? initHeaders : initHeaders?.entries ? initHeaders.entries() : Object.entries(initHeaders).map(([k, v]) => [k.toLowerCase(), v]) : void 0);
let hasContentTypeHeader;
let hasContentLength;
if (headerEntries) for (const [key, value] of headerEntries) {
if (Array.isArray(value)) for (const v of value) headers.push([key, v]);
else headers.push([key, value]);
if (key === "content-type") hasContentTypeHeader = true;
else if (key === "content-length") hasContentLength = true;
}
if (contentType && !hasContentTypeHeader) headers.push(["content-type", contentType]);
if (contentLength && !hasContentLength) headers.push(["content-length", String(contentLength)]);
this.#init = void 0;
this.#headers = void 0;
this.#response = void 0;
this.#body = void 0;
return {
status,
statusText,
headers,
body
};
}
}
lazyInherit(NodeResponse.prototype, NativeResponse.prototype, "_response");
Object.setPrototypeOf(NodeResponse, NativeResponse);
Object.setPrototypeOf(NodeResponse.prototype, NativeResponse.prototype);
return NodeResponse;
})();
var WebRequestSocket = class extends Duplex {
_httpMessage;
autoSelectFamilyAttemptedAddresses = [];
bufferSize = 0;
bytesRead = 0;
bytesWritten = 0;
connecting = false;
pending = false;
readyState = "open";
remoteAddress = "";
remoteFamily = "";
remotePort = 0;
#request;
#timeoutTimer;
#reqReader;
#headersWritten;
#_writeBody;
_webResBody;
constructor(request) {
super({
signal: request.signal,
allowHalfOpen: true
});
this.#request = request;
this._webResBody = new ReadableStream({ start: (controller) => {
this.#_writeBody = controller.enqueue.bind(controller);
this.once("finish", () => {
this.readyState = "closed";
controller.close();
});
} });
}
setTimeout(ms, cb) {
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return this;
if (cb) this.on("timeout", cb);
if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);
if (ms > 0) this.#timeoutTimer = setTimeout(() => this.emit("timeout"), ms);
return this;
}
setNoDelay() {
return this;
}
setKeepAlive() {
return this;
}
ref() {
return this;
}
unref() {
return this;
}
destroySoon() {
this.destroy();
}
connect() {
return this;
}
resetAndDestroy() {
this.destroy();
return this;
}
address() {
return {
address: "",
family: "",
port: 0
};
}
_read(_size) {
const reader = this.#reqReader ??= this.#request.body?.getReader();
if (!reader) {
this.push(null);
return;
}
reader.read().then((res) => this._onRead(res)).catch((error) => {
this.emit("error", error);
});
}
_onRead(res) {
if (res.done) {
this.push(null);
return;
}
if (res.value) {
this.bytesRead += res.value.byteLength;
this.push(res.value);
}
}
_write(chunk, encoding, callback) {
if (this.#headersWritten) this.#_writeBody(typeof chunk === "string" ? Buffer.from(chunk, encoding) : chunk);
else if (chunk?.length > 0) {
this.#headersWritten = true;
const headerEnd = chunk.lastIndexOf("\r\n\r\n");
if (headerEnd === -1) throw new Error("Invalid HTTP headers chunk!");
if (headerEnd < chunk.length - 4) {
this._write(chunk.slice(headerEnd + 4), encoding, () => {
callback(null);
});
return;
}
}
callback(null);
}
_final(callback) {
callback(null);
}
_destroy(err, cb) {
if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);
if (this.#reqReader) this.#reqReader.cancel().catch((error) => {
console.error(error);
});
this.readyState = "closed";
cb(err ?? void 0);
}
};
var WebIncomingMessage = class extends IncomingMessage {
constructor(req, socket) {
super(socket);
this.method = req.method;
const url = req._url ??= new FastURL(req.url);
this.url = url.pathname + url.search;
for (const [key, value] of req.headers.entries()) this.headers[key.toLowerCase()] = value;
if (req.method !== "GET" && req.method !== "HEAD" && !this.headers["content-length"] && !this.headers["transfer-encoding"]) this.headers["transfer-encoding"] = "chunked";
const onData = (chunk) => {
this.push(chunk);
};
socket.on("data", onData);
socket.once("end", () => {
this.emit("end");
this.off("data", onData);
});
}
};
function callNodeHandler(handler, req) {
const isMiddleware = handler.length > 2;
const nodeCtx = req.runtime?.node;
if (!nodeCtx || !nodeCtx.req || !nodeCtx.res) throw new Error("Node.js runtime context is not available.");
const { req: nodeReq, res: nodeRes } = nodeCtx;
let _headers;
const webRes = new NodeResponse(void 0, {
get status() {
return nodeRes.statusCode;
},
get statusText() {
return nodeRes.statusMessage;
},
get headers() {
if (!_headers) {
const headerEntries = [];
const rawHeaders = nodeRes.getHeaders();
for (const [name, value] of Object.entries(rawHeaders)) if (Array.isArray(value)) for (const v of value) headerEntries.push([name, v]);
else if (value) headerEntries.push([name, String(value)]);
_headers = new Headers(headerEntries);
}
return _headers;
}
});
return new Promise((resolve, reject) => {
nodeRes.once("close", () => resolve(webRes));
nodeRes.once("finish", () => resolve(webRes));
nodeRes.once("error", (error) => reject(error));
let streamPromise;
nodeRes.once("pipe", (stream) => {
streamPromise = new Promise((resolve) => {
stream.once("end", () => resolve(webRes));
stream.once("error", (error) => reject(error));
});
});
try {
if (isMiddleware) Promise.resolve(handler(nodeReq, nodeRes, (error) => error ? reject(error) : streamPromise || resolve(webRes))).catch((error) => reject(error));
else Promise.resolve(handler(nodeReq, nodeRes)).then(() => streamPromise || webRes);
} catch (error) {
reject(error);
}
});
}
var WebServerResponse = class extends ServerResponse {
#socket;
constructor(req, socket) {
super(req);
this.assignSocket(socket);
this.once("finish", () => {
socket.end();
});
this.#socket = socket;
this.waitToFinish = this.waitToFinish.bind(this);
this.toWebResponse = this.toWebResponse.bind(this);
}
waitToFinish() {
if (this.writableEnded) return Promise.resolve();
return new Promise((resolve, reject) => {
this.on("finish", () => resolve());
this.on("error", (err) => reject(err));
});
}
async toWebResponse() {
await this.waitToFinish();
const headers = [];
const httpHeader = this._header?.split("\r\n");
for (let i = 1; httpHeader && i < httpHeader.length; i++) {
const sepIndex = httpHeader[i].indexOf(": ");
if (sepIndex === -1) continue;
const key = httpHeader[i].slice(0, Math.max(0, sepIndex));
const value = httpHeader[i].slice(Math.max(0, sepIndex + 2));
if (!key) continue;
headers.push([key, value]);
}
return new Response(this.#socket._webResBody, {
status: this.statusCode,
statusText: this.statusMessage,
headers
});
}
};
async function fetchNodeHandler(handler, req) {
const nodeRuntime = req.runtime?.node;
if (nodeRuntime && nodeRuntime.req && nodeRuntime.res) return await callNodeHandler(handler, req);
const socket = new WebRequestSocket(req);
const nodeReq = new WebIncomingMessage(req, socket);
const nodeRes = new WebServerResponse(nodeReq, socket);
try {
await handler(nodeReq, nodeRes);
return await nodeRes.toWebResponse();
} catch (error) {
console.error(error, { cause: {
req,
handler
} });
return new Response(null, {
status: 500,
statusText: "Internal Server Error"
});
}
}
function toNodeHandler(handler) {
if (handler.__nodeHandler) return handler.__nodeHandler;
function convertedNodeHandler(nodeReq, nodeRes) {
const res = handler(new NodeRequest({
req: nodeReq,
res: nodeRes
}));
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
}
convertedNodeHandler.__fetchHandler = handler;
assignFnName(convertedNodeHandler, handler, " (converted to Node handler)");
return convertedNodeHandler;
}
function toFetchHandler(handler) {
if (handler.__fetchHandler) return handler.__fetchHandler;
function convertedNodeHandler(req) {
return fetchNodeHandler(handler, req);
}
convertedNodeHandler.__nodeHandler = handler;
assignFnName(convertedNodeHandler, handler, " (converted to Web handler)");
return convertedNodeHandler;
}
function assignFnName(target, source, suffix) {
if (source.name) try {
Object.defineProperty(target, "name", { value: `${source.name}${suffix}` });
} catch {}
}
function serve(options) {
return new NodeServer(options);
}
var NodeServer = class {
runtime = "node";
options;
node;
serveOptions;
fetch;
#isSecure;
#listeningPromise;
#wait;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
errorPlugin(this);
const fetchHandler = this.fetch = wrapFetch(this);
const loader = globalThis.__srvxLoader__;
if (loader) {
loader(fetchHandler);
return;
}
gracefulShutdownPlugin(this);
this.#wait = createWaitUntil();
const handler = (nodeReq, nodeRes) => {
const request = new NodeRequest({
req: nodeReq,
res: nodeRes
});
request.waitUntil = this.#wait?.waitUntil;
const res = fetchHandler(request);
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
};
const tls = resolveTLSOptions(this.options);
const { port, hostname: host } = resolvePortAndHost(this.options);
this.serveOptions = {
port,
host,
exclusive: !this.options.reusePort,
...tls ? {
cert: tls.cert,
key: tls.key,
passphrase: tls.passphrase
} : {},
...this.options.node
};
let server;
this.#isSecure = !!this.serveOptions.cert && this.options.protocol !== "http";
if (this.options.node?.http2 ?? this.#isSecure) if (this.#isSecure) server = nodeHTTP2.createSecureServer({
allowHTTP1: true,
...this.serveOptions
}, handler);
else throw new Error("node.http2 option requires tls certificate!");
else if (this.#isSecure) server = nodeHTTPS.createServer(this.serveOptions, handler);
else server = nodeHTTP.createServer(this.serveOptions, handler);
this.node = {
server,
handler
};
if (!options.manual) this.serve();
}
serve() {
if (this.#listeningPromise) return Promise.resolve(this.#listeningPromise).then(() => this);
this.#listeningPromise = new Promise((resolve) => {
this.node.server.listen(this.serveOptions, () => {
printListening(this.options, this.url);
resolve();
});
});
}
get url() {
const addr = this.node?.server?.address();
if (!addr) return;
return typeof addr === "string" ? addr : fmtURL(addr.address, addr.port, this.#isSecure);
}
ready() {
return Promise.resolve(this.#listeningPromise).then(() => this);
}
async close(closeAll) {
await Promise.all([this.#wait?.wait(), new Promise((resolve, reject) => {
const server = this.node?.server;
if (server && closeAll && "closeAllConnections" in server) server.closeAllConnections();
if (!server || !server.listening) return resolve();
server.close((error) => error ? reject(error) : resolve());
})]);
}
};
export { NodeResponse as FastResponse, NodeResponse, FastURL, NodeRequest, fetchNodeHandler, patchGlobalRequest, sendNodeResponse, serve, toFetchHandler, toNodeHandler };

9
node_modules/srvx/dist/adapters/service-worker.d.mts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import { Server, ServerOptions, ServerRequest } from "../types.mjs";
//#region src/adapters/service-worker.d.ts
declare const FastURL: typeof globalThis.URL;
declare const FastResponse: typeof globalThis.Response;
type ServiceWorkerHandler = (request: ServerRequest, event: FetchEvent) => Response | Promise<Response>;
declare function serve(options: ServerOptions): Server<ServiceWorkerHandler>;
//#endregion
export { FastResponse, FastURL, ServiceWorkerHandler, serve };

76
node_modules/srvx/dist/adapters/service-worker.mjs generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
const FastURL = URL;
const FastResponse = Response;
const isBrowserWindow = typeof window !== "undefined" && typeof navigator !== "undefined";
const isServiceWorker = typeof self !== "undefined" && "skipWaiting" in self;
function serve(options) {
return new ServiceWorkerServer(options);
}
var ServiceWorkerServer = class {
runtime = "service-worker";
options;
fetch;
#fetchListener;
#listeningPromise;
constructor(options) {
this.options = {
...options,
middleware: [...options.middleware || []]
};
for (const plugin of options.plugins || []) plugin(this);
errorPlugin(this);
const fetchHandler = wrapFetch(this);
this.fetch = (request, event) => {
Object.defineProperties(request, { runtime: {
enumerable: true,
value: {
name: "service-worker",
serviceWorker: { event }
}
} });
return Promise.resolve(fetchHandler(request));
};
if (!options.manual) this.serve();
}
serve() {
if (isBrowserWindow) {
if (!navigator.serviceWorker) throw new Error("Service worker is not supported in the current window.");
const swURL = this.options.serviceWorker?.url;
if (!swURL) throw new Error("Service worker URL is not provided. Please set the `serviceWorker.url` serve option or manually register.");
this.#listeningPromise = navigator.serviceWorker.register(swURL, {
type: "module",
scope: this.options.serviceWorker?.scope
}).then((registration) => {
if (registration.active) location.replace(location.href);
else registration.addEventListener("updatefound", () => {
location.replace(location.href);
});
});
} else if (isServiceWorker) {
this.#fetchListener = async (event) => {
if (/\/[^/]*\.[a-zA-Z0-9]+$/.test(new URL(event.request.url).pathname)) return;
Object.defineProperty(event.request, "waitUntil", { value: event.waitUntil.bind(event) });
const response = await this.fetch(event.request, event);
if (response.status !== 404) event.respondWith(response);
};
addEventListener("fetch", this.#fetchListener);
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", () => {
self.clients?.claim?.();
});
}
}
ready() {
return Promise.resolve(this.#listeningPromise).then(() => this);
}
async close() {
if (this.#fetchListener) removeEventListener("fetch", this.#fetchListener);
if (isBrowserWindow) {
const registrations = await navigator.serviceWorker.getRegistrations();
for (const registration of registrations) if (registration.active) await registration.unregister();
} else if (isServiceWorker) await self.registration.unregister();
}
};
export { FastResponse, FastURL, serve };

57
node_modules/srvx/dist/cli.d.mts generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import { LoadOptions } from "./loader.mjs";
import { Server } from "srvx";
//#region src/cli/types.d.ts
declare global {
var __srvx__: Server | undefined;
}
type MainOptions = CLIOptions & {
args?: string[];
meta?: {
name?: string;
version?: string;
description?: string;
};
usage?: {
command?: string;
docs?: string;
issues?: string;
};
};
/**
* CLI options for srvx command
*/
type CLIOptions = {
/** CLI mode: "serve" to start a server, "fetch" to make HTTP requests */mode?: "serve" | "fetch"; /** Show help message */
help?: boolean; /** Show server and runtime versions */
version?: boolean; /** Working directory for resolving entry file */
dir?: string; /** Server entry file to use */
entry?: string; /** Run in production mode (no watch, no debug) */
prod?: boolean; /** Serve static files from the specified directory (default: "public") */
static?: string; /** ES module to preload */
import?: string; /** Host to bind to (default: all interfaces) */
hostname?: string; /** (alias to hostname) */
host?: string; /** Port to listen on (default: "3000") */
port?: string; /** Enable TLS (HTTPS/HTTP2) */
tls?: boolean; /** TLS certificate file */
cert?: string; /** TLS private key file */
key?: string; /** URL or path to fetch */
url?: string; /** HTTP method (default: "GET", or "POST" if body is provided) */
method?: string; /** Request headers (format: "Name: Value", can be used multiple times) */
header?: string[]; /** Show request and response headers */
verbose?: boolean; /** Request body (use "@-" for stdin, "@file" for file) */
data?: string;
};
//#endregion
//#region src/cli/main.d.ts
declare function main(mainOpts: MainOptions): Promise<void>;
//#endregion
//#region src/cli/fetch.d.ts
declare function cliFetch(cliOpts: CLIOptions & LoadOptions & {
loader?: LoadOptions;
stdin?: typeof process.stdin;
stdout?: typeof process.stdout;
stderr?: typeof process.stderr;
}): Promise<Response>;
//#endregion
export { type CLIOptions, type MainOptions, cliFetch, main };

421
node_modules/srvx/dist/cli.mjs generated vendored Normal file
View File

@@ -0,0 +1,421 @@
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";
import { loadServerEntry } from "./loader.mjs";
import { parseArgs } from "node:util";
import { fileURLToPath } from "node:url";
import { fork } from "node:child_process";
import { createReadStream, existsSync, statSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { Readable } from "node:stream";
const NO_ENTRY_ERROR = "No server entry or public directory found";
async function cliServe(cliOpts) {
try {
if (!process.env.NODE_ENV) process.env.NODE_ENV = cliOpts.prod ? "production" : "development";
const loaded = await loadServerEntry({
entry: cliOpts.entry,
dir: cliOpts.dir
});
const { serve: srvxServe } = loaded.nodeCompat ? await import("srvx/node") : await import("srvx");
const { serveStatic } = await import("srvx/static");
const { log } = await import("srvx/log");
const staticDir = resolve(cliOpts.dir || (loaded.url ? dirname(fileURLToPath(loaded.url)) : "."), cliOpts.static || "public");
cliOpts.static = existsSync(staticDir) ? staticDir : "";
if (loaded.notFound && !cliOpts.static) {
process.send?.({ error: "no-entry" });
throw new Error(NO_ENTRY_ERROR, { cause: cliOpts });
}
const serverOptions = {
...loaded.module?.default,
default: void 0,
...loaded.module
};
printInfo(cliOpts, loaded);
await (globalThis.__srvx__ = srvxServe({
...serverOptions,
gracefulShutdown: !!cliOpts.prod,
port: cliOpts.port ?? serverOptions.port,
hostname: cliOpts.hostname ?? cliOpts.host ?? serverOptions.hostname,
tls: cliOpts.tls ? {
cert: cliOpts.cert,
key: cliOpts.key
} : void 0,
error: (error) => {
console.error(error);
return renderError(cliOpts, error);
},
fetch: loaded.fetch || (() => renderError(cliOpts, loaded.notFound ? "Server Entry Not Found" : "No Fetch Handler Exported", 501)),
middleware: [
log(),
cliOpts.static ? serveStatic({ dir: cliOpts.static }) : void 0,
...serverOptions.middleware || []
].filter(Boolean)
})).ready();
} catch (error) {
console.error(error);
process.exit(1);
}
}
function renderError(cliOpts, error, status = 500, title = "Server Error") {
let html = `<!DOCTYPE html><html><head><title>${title}</title></head><body>`;
if (cliOpts.prod) html += `<h1>${title}</h1><p>Something went wrong while processing your request.</p>`;
else html += `
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f8f9fa; color: #333; }
h1 { color: #dc3545; }
pre { background: #fff; padding: 10px; border-radius: 5px; overflow: auto; }
code { font-family: monospace; }
#error { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; }
</style>
<div id="error"><h1>${title}</h1><pre>${error instanceof Error ? error.stack || error.message : String(error)}</pre></div>
`;
return new Response(html, {
status,
headers: { "Content-Type": "text/html; charset=utf-8" }
});
}
function printInfo(cliOpts, loaded) {
let entryInfo;
if (loaded.notFound) entryInfo = gray(`(create ${bold(`server.ts`)})`);
else entryInfo = loaded.fetch ? cyan("./" + relative(".", fileURLToPath(loaded.url))) : red(`No fetch handler exported from ${loaded.url}`);
console.log(gray(`${bold(gray("◆"))} Server handler: ${entryInfo}`));
let staticInfo;
if (cliOpts.static) staticInfo = cyan("./" + relative(".", cliOpts.static) + "/");
else staticInfo = gray(`(create ${bold("public/")} dir)`);
console.log(gray(`${bold(gray("◇"))} Static files: ${staticInfo}`));
console.log("");
}
async function cliFetch(cliOpts) {
const stdin = cliOpts.stdin || process.stdin;
const stdout = cliOpts.stdout || process.stdout;
const stderr = cliOpts.stderr || process.stderr;
let fetchHandler = globalThis.fetch;
let inputURL = cliOpts.url || "/";
if (inputURL[0] === "/") {
const loaded = await loadServerEntry({
dir: cliOpts.dir,
entry: cliOpts.entry,
...cliOpts?.loader
});
if (cliOpts.verbose && loaded.url) {
stderr.write(`* Entry: ${fileURLToPath(loaded.url)}\n`);
if (loaded.nodeCompat) stderr.write(`* Using node compat mode\n`);
}
if (loaded.notFound) throw new Error(`Server entry file not found in ${resolve(cliOpts.dir || ".")}`, { cause: {
dir: cliOpts.dir || process.cwd(),
entry: cliOpts.entry || void 0
} });
else if (!loaded.fetch) throw new Error("No fetch handler exported", { cause: {
dir: cliOpts.dir || process.cwd(),
entry: cliOpts.entry || void 0,
loaded
} });
fetchHandler = loaded.fetch;
} else {
stderr.write(`* Fetching remote URL: ${inputURL}\n`);
if (!URL?.canParse(inputURL)) inputURL = `http${cliOpts.tls ? "s" : ""}://${inputURL}`;
fetchHandler = globalThis.fetch;
}
const headers = new Headers();
if (cliOpts.header) for (const header of cliOpts.header) {
const colonIndex = header.indexOf(":");
if (colonIndex > 0) {
const name = header.slice(0, colonIndex).trim();
const value = header.slice(colonIndex + 1).trim();
headers.append(name, value);
}
}
if (!headers.has("User-Agent")) headers.set("User-Agent", "srvx (curl)");
if (!headers.has("Accept")) headers.set("Accept", "text/markdown, application/json;q=0.9, text/plain;q=0.8, text/html;q=0.7, text/*;q=0.6, */*;q=0.5");
let body;
if (cliOpts.data !== void 0) if (cliOpts.data === "@-") body = new ReadableStream({ async start(controller) {
for await (const chunk of stdin) controller.enqueue(chunk);
controller.close();
} });
else if (cliOpts.data.startsWith("@")) body = Readable.toWeb(createReadStream(cliOpts.data.slice(1)));
else body = cliOpts.data;
const method = cliOpts.method || (body === void 0 ? "GET" : "POST");
const url = new URL(inputURL, `http${cliOpts.tls ? "s" : ""}://${cliOpts.host || cliOpts.hostname || "localhost"}`);
const req = new Request(url, {
method,
headers,
body
});
if (cliOpts.verbose) {
const parsedUrl = new URL(url);
stderr.write(`> ${method} ${parsedUrl.pathname}${parsedUrl.search} HTTP/1.1\n`);
stderr.write(`> Host: ${parsedUrl.host}\n`);
for (const [name, value] of headers) stderr.write(`> ${name}: ${value}\n`);
stderr.write(">\n");
}
const res = await fetchHandler(req);
if (cliOpts.verbose) {
stderr.write(`< HTTP/1.1 ${res.status} ${res.statusText}\n`);
for (const [name, value] of res.headers) stderr.write(`< ${name}: ${value}\n`);
stderr.write("<\n");
}
if (res.body) {
const { isBinary, encoding } = getResponseFormat(res);
if (isBinary) for await (const chunk of res.body) stdout.write(chunk);
else {
const decoder = new TextDecoder(encoding);
for await (const chunk of res.body) stdout.write(decoder.decode(chunk, { stream: true }));
const remaining = decoder.decode();
if (remaining) stdout.write(remaining);
if (stdout.isTTY) stdout.write("\n");
}
}
return res;
}
function getResponseFormat(res) {
const contentType = res.headers.get("content-type") || "";
return {
isBinary: contentType.startsWith("application/octet-stream") || contentType.startsWith("image/") || contentType.startsWith("audio/") || contentType.startsWith("video/") || contentType.startsWith("application/pdf") || contentType.startsWith("application/zip") || contentType.startsWith("application/gzip"),
encoding: contentType.includes("charset=") ? contentType.split("charset=")[1].split(";")[0].trim() : "utf8"
};
}
const srvxMeta = {
name: "srvx",
version: "0.11.3",
description: "Universal Server."
};
function usage(mainOpts) {
const command = mainOpts.usage?.command || "srvx";
const name = mainOpts.meta?.name || srvxMeta.name;
const ver = mainOpts.meta?.version || srvxMeta.version;
const desc = mainOpts.meta?.description || srvxMeta.description;
return `
${cyan(name)}${gray(`${ver ? ` ${ver}` : ""} ${desc ? `- ${desc}` : ""}`)}
${bold("SERVE MODE")}
${bold(green(`# ${command} serve [options]`))}
${gray("$")} ${cyan(command)} serve --entry ${gray("./server.ts")} ${gray("# Start development server")}
${gray("$")} ${cyan(command)} serve --prod ${gray("# Start production server")}
${gray("$")} ${cyan(command)} serve --port=8080 ${gray("# Listen on port 8080")}
${gray("$")} ${cyan(command)} serve --host=localhost ${gray("# Bind to localhost only")}
${gray("$")} ${cyan(command)} serve --import=jiti/register ${gray(`# Enable ${url("jiti", "https://github.com/unjs/jiti")} loader`)}
${gray("$")} ${cyan(command)} serve --tls --cert=cert.pem --key=key.pem ${gray("# Enable TLS (HTTPS/HTTP2)")}
${bold("FETCH MODE")}
${bold(green(`# ${command} fetch|curl [options] [url]`))}
${gray("$")} ${cyan(command)} fetch ${gray("# Fetch from default entry")}
${gray("$")} ${cyan(command)} fetch /api/users ${gray("# Fetch a specific URL/path")}
${gray("$")} ${cyan(command)} fetch --entry ./server.ts /api/users ${gray("# Fetch using a specific entry")}
${gray("$")} ${cyan(command)} fetch -X POST /api/users ${gray("# POST request")}
${gray("$")} ${cyan(command)} fetch -H "Content-Type: application/json" /api ${gray("# With headers")}
${gray("$")} ${cyan(command)} fetch -d '{"name":"foo"}' /api ${gray("# With request body")}
${gray("$")} ${cyan(command)} fetch -v /api/users ${gray("# Verbose output (show headers)")}
${gray("$")} echo '{"name":"foo"}' | ${cyan(command)} fetch -d @- /api ${gray("# Body from stdin")}
${bold("COMMON OPTIONS")}
${green("--entry")} ${yellow("<file>")} Server entry file to use
${green("--dir")} ${yellow("<dir>")} Working directory for resolving entry file
${green("-h, --help")} Show this help message
${green("--version")} Show server and runtime versions
${bold("SERVE OPTIONS")}
${green("-p, --port")} ${yellow("<port>")} Port to listen on (default: ${yellow("3000")})
${green("--host")} ${yellow("<host>")} Host to bind to (default: all interfaces)
${green("-s, --static")} ${yellow("<dir>")} Serve static files from the specified directory (default: ${yellow("public")})
${green("--prod")} Run in production mode (no watch, no debug)
${green("--import")} ${yellow("<loader>")} ES module to preload
${green("--tls")} Enable TLS (HTTPS/HTTP2)
${green("--cert")} ${yellow("<file>")} TLS certificate file
${green("--key")} ${yellow("<file>")} TLS private key file
${bold("FETCH OPTIONS")}
${green("-X, --request")} ${yellow("<method>")} HTTP method (default: ${yellow("GET")}, or ${yellow("POST")} if body is provided)
${green("-H, --header")} ${yellow("<header>")} Add header (format: "Name: Value", can be used multiple times)
${green("-d, --data")} ${yellow("<data>")} Request body (use ${yellow("@-")} for stdin, ${yellow("@file")} for file)
${green("-v, --verbose")} Show request and response headers
${bold("ENVIRONMENT")}
${green("PORT")} Override port
${green("HOST")} Override host
${green("NODE_ENV")} Set to ${yellow("production")} for production mode.
${mainOpts.usage?.docs ? `${url("Documentation", mainOpts.usage.docs)}` : ""}
${mainOpts.usage?.issues ? `${url("Report issues", mainOpts.usage.issues)}` : ""}
`.trim();
}
async function main(mainOpts) {
const args = process.argv.slice(2);
const cliOpts = parseArgs$1(args);
if (cliOpts.version) {
process.stdout.write(versions(mainOpts).join("\n") + "\n");
process.exit(0);
}
if (cliOpts.help) {
console.log(usage(mainOpts));
process.exit(cliOpts.help ? 0 : 1);
}
if (cliOpts.mode === "fetch") try {
const res = await cliFetch(cliOpts);
process.exit(res.ok ? 0 : 22);
} catch (error) {
console.error(error);
process.exit(1);
}
if (process.send) return startServer(cliOpts);
console.log(gray([...versions(mainOpts), cliOpts.prod ? "prod" : "dev"].join(" · ")));
const envFiles = [".env", cliOpts.prod ? ".env.production" : ".env.local"].filter((f) => existsSync(f));
if (envFiles.length > 0) console.log(`${gray(`Loading environment variables from ${magenta(envFiles.join(", "))}`)}`);
if (cliOpts.prod && !cliOpts.import) {
for (const envFile of [...envFiles].reverse()) process.loadEnvFile?.(envFile);
await startServer(cliOpts);
return;
}
const isBun = !!process.versions.bun;
const isDeno = !!process.versions.deno;
const isNode = !isBun && !isDeno;
const runtimeArgs = [];
runtimeArgs.push(...envFiles.map((f) => `--env-file=${f}`));
if (!cliOpts.prod) runtimeArgs.push("--watch");
if (cliOpts.import && (isNode || isBun)) runtimeArgs.push(`--import=${cliOpts.import}`);
await forkCLI(args, runtimeArgs);
}
function parseArgs$1(args) {
const pArg0 = args.find((a) => !a.startsWith("-"));
const mode = pArg0 === "fetch" || pArg0 === "curl" ? "fetch" : "serve";
const commonArgs = {
help: { type: "boolean" },
version: { type: "boolean" },
dir: { type: "string" },
entry: { type: "string" },
host: { type: "string" },
hostname: { type: "string" },
tls: { type: "boolean" }
};
if (mode === "serve") {
const { values, positionals } = parseArgs({
args,
allowPositionals: true,
options: {
...commonArgs,
url: { type: "string" },
prod: { type: "boolean" },
port: {
type: "string",
short: "p"
},
static: {
type: "string",
short: "s"
},
import: { type: "string" },
cert: { type: "string" },
key: { type: "string" }
}
});
if (positionals[0] === "serve") positionals.shift();
const maybeEntryOrDir = positionals[0];
if (maybeEntryOrDir) {
if (values.entry || values.dir) throw new Error("Cannot specify entry or dir as positional argument when --entry or --dir is used!");
if (statSync(maybeEntryOrDir).isDirectory()) values.dir = maybeEntryOrDir;
else values.entry = maybeEntryOrDir;
}
return {
mode,
...values
};
}
const { values, positionals } = parseArgs({
args,
allowPositionals: true,
options: {
...commonArgs,
url: { type: "string" },
method: {
type: "string",
short: "X"
},
request: { type: "string" },
header: {
type: "string",
multiple: true,
short: "H"
},
verbose: {
type: "boolean",
short: "v"
},
data: {
type: "string",
short: "d"
}
}
});
if (positionals[0] === "fetch" || positionals[0] === "curl") positionals.shift();
const method = values.method || values.request;
const url = values.url || positionals[0] || "/";
return {
mode,
...values,
url,
method
};
}
async function startServer(cliOpts) {
setupProcessErrorHandlers();
await cliServe(cliOpts);
}
async function forkCLI(args, runtimeArgs) {
const child = fork(fileURLToPath(globalThis.__SRVX_BIN__ || new URL("../bin/srvx.mjs", import.meta.url)), [...args], { execArgv: [...process.execArgv, ...runtimeArgs].filter(Boolean) });
child.on("error", (error) => {
console.error("Error in child process:", error);
process.exit(1);
});
child.on("exit", (code) => {
if (code !== 0) {
console.error(`Child process exited with code ${code}`);
process.exit(code);
}
});
child.on("message", (msg) => {
if (msg && msg.error === "no-entry") {
console.error("\n" + red(NO_ENTRY_ERROR) + "\n");
process.exit(3);
}
});
let cleanupCalled = false;
const cleanup = (signal, exitCode) => {
if (cleanupCalled) return;
cleanupCalled = true;
try {
child.kill(signal || "SIGTERM");
} catch (error) {
console.error("Error killing child process:", error);
}
if (exitCode !== void 0) process.exit(exitCode);
};
process.on("exit", () => cleanup("SIGTERM"));
process.on("SIGTERM", () => cleanup("SIGTERM", 143));
if (args.includes("--watch")) process.on("SIGINT", () => cleanup("SIGINT", 130));
}
function setupProcessErrorHandlers() {
process.on("uncaughtException", (error) => {
console.error("Uncaught exception:", error);
process.exit(1);
});
process.on("unhandledRejection", (reason) => {
console.error("Unhandled rejection:", reason);
process.exit(1);
});
}
function versions(mainOpts) {
const versions = [];
if (mainOpts.meta?.name) versions.push(`${mainOpts.meta.name} ${mainOpts.meta.version || ""}`.trim());
versions.push(`${srvxMeta.name} ${srvxMeta.version}`);
versions.push(runtime());
return versions;
}
function runtime() {
if (process.versions.bun) return `bun ${process.versions.bun}`;
else if (process.versions.deno) return `deno ${process.versions.deno}`;
else return `node ${process.versions.node}`;
}
export { cliFetch, main };

74
node_modules/srvx/dist/loader.d.mts generated vendored Normal file
View File

@@ -0,0 +1,74 @@
import { ServerHandler } from "srvx";
//#region src/loader.d.ts
declare const defaultExts: string[];
declare const defaultEntries: string[];
/**
* Options for loading a server entry module.
*/
type LoadOptions = {
/**
* Path or URL to the server entry file.
*
* If not provided, common entry points will be searched automatically.
*/
entry?: string;
/**
* Base directory for resolving relative paths.
*
* @default "."
*/
dir?: string;
/**
* Set to `false` to disable interception of `http.Server.listen` to detect legacy handlers.
*
* @default true
*/
interceptHttpListen?: boolean;
/**
* Set to `false` to disable Node.js handler (req, res) compatibility.
*/
nodeCompat?: boolean;
/**
* Hook called after the module is loaded to allow for custom processing.
*
* You can return a modified version of the module if needed.
*/
onLoad?: (module: unknown) => any;
};
/**
* Result of loading a server entry module.
*/
type LoadedServerEntry = {
/**
* The web fetch handler extracted from the loaded module.
*
* This is resolved from `module.fetch`, `module.default.fetch`,
* or upgraded from a legacy Node.js handler.
*/
fetch?: ServerHandler;
/**
* The raw loaded module.
*/
module?: any;
/**
* Whether the handler was upgraded from a legacy Node.js HTTP handler.
*
* When `true`, the original module exported a Node.js-style `(req, res)` handler
* that has been wrapped for web fetch compatibility.
*/
nodeCompat?: boolean;
/**
* The resolved `file://` URL of the loaded entry module.
*/
url?: string;
/**
* Whether the specified entry file was not found.
*
* When `true`, no valid entry point could be located.
*/
notFound?: boolean;
};
declare function loadServerEntry(opts: LoadOptions): Promise<LoadedServerEntry>;
//#endregion
export { LoadOptions, LoadedServerEntry, defaultEntries, defaultExts, loadServerEntry };

116
node_modules/srvx/dist/loader.mjs generated vendored Normal file
View File

@@ -0,0 +1,116 @@
import { pathToFileURL } from "node:url";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
import * as nodeHTTP$1 from "node:http";
const defaultExts = [
".mjs",
".js",
".mts",
".ts"
];
const defaultEntries = [
"server",
"server/index",
"src/server",
"server/server"
];
async function loadServerEntry(opts) {
let entry = opts.entry;
if (entry) {
entry = resolve(opts.dir || ".", entry);
if (!existsSync(entry)) return { notFound: true };
} else {
for (const defEntry of defaultEntries) {
for (const defExt of defaultExts) {
const entryPath = resolve(opts.dir || ".", `${defEntry}${defExt}`);
if (existsSync(entryPath)) {
entry = entryPath;
break;
}
}
if (entry) break;
}
if (!entry) return { notFound: true };
}
const url = entry.startsWith("file://") ? entry : pathToFileURL(resolve(entry)).href;
let mod;
let interceptedNodeHandler;
let interceptedFetchHandler;
try {
if (opts.interceptHttpListen !== false) {
const loaded = await interceptListen(() => import(url));
mod = loaded.res;
interceptedNodeHandler = loaded.listenHandler;
interceptedFetchHandler = loaded.fetchHandler;
} else mod = await import(url);
} catch (error) {
if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
const message = String(error);
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 });
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 });
}
throw error;
}
mod = await opts?.onLoad?.(mod) || mod;
let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch || interceptedFetchHandler;
if (!fetchHandler && typeof mod?.default === "function" && mod.default.length < 2) fetchHandler = mod.default;
let nodeCompat = false;
if (!fetchHandler && opts.nodeCompat !== false) {
const nodeHandler = interceptedNodeHandler || (typeof mod?.default === "function" ? mod.default : void 0);
if (nodeHandler) {
nodeCompat = true;
const { fetchNodeHandler } = await import("srvx/node");
fetchHandler = (webReq) => fetchNodeHandler(nodeHandler, webReq);
}
}
return {
module: mod,
nodeCompat,
url,
fetch: fetchHandler
};
}
let _interceptQueue = Promise.resolve();
async function interceptListen(cb) {
const result = _interceptQueue.then(async () => {
const originalListen = nodeHTTP$1.Server.prototype.listen;
let res;
let listenHandler;
let fetchHandler;
globalThis.__srvxLoader__ = (handler) => {
fetchHandler = handler;
};
try {
nodeHTTP$1.Server.prototype.listen = function(arg1, arg2) {
listenHandler = this._events.request;
if (Array.isArray(listenHandler)) listenHandler = listenHandler[0];
nodeHTTP$1.Server.prototype.listen = originalListen;
const listenCallback = [arg1, arg2].find((arg) => typeof arg === "function");
setImmediate(() => {
listenCallback?.();
});
return new Proxy({}, { get(_, prop) {
const server = globalThis.__srvx__;
if (!server && prop === "address") return () => ({
address: "",
family: "",
port: 0
});
return server?.node?.server?.[prop];
} });
};
res = await cb();
} finally {
nodeHTTP$1.Server.prototype.listen = originalListen;
delete globalThis.__srvxLoader__;
}
return {
res,
listenHandler,
fetchHandler
};
});
_interceptQueue = result.catch(() => {});
return result;
}
export { defaultEntries, defaultExts, loadServerEntry };

7
node_modules/srvx/dist/log.d.mts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { ServerMiddleware } from "./types.mjs";
//#region src/log.d.ts
interface LogOptions {}
declare const log: (_options?: LogOptions) => ServerMiddleware;
//#endregion
export { LogOptions, log };

17
node_modules/srvx/dist/log.mjs generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { a as green, i as gray, l as yellow, n as bold, s as red, t as blue } from "./_chunks/_utils.mjs";
const statusColors = {
1: blue,
2: green,
3: yellow
};
const log = (_options = {}) => {
return async (req, next) => {
const start = performance.now();
const res = await next();
const duration = performance.now() - start;
const statusColor = statusColors[Math.floor(res.status / 100)] || red;
console.log(`${gray(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}]`)} ${bold(req.method)} ${blue(req.url)} [${statusColor(res.status + "")}] ${gray(`(${duration.toFixed(2)}ms)`)}`);
return res;
};
};
export { log };

24
node_modules/srvx/dist/static.d.mts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { ServerMiddleware } from "./types.mjs";
//#region src/static.d.ts
interface ServeStaticOptions {
/**
* The directory to serve static files from.
*/
dir: string;
/**
* The HTTP methods to allow for serving static files.
*/
methods?: string[];
/**
* A function to modify the HTML content before serving it.
*/
renderHTML?: (ctx: {
request: Request;
html: string;
filename: string;
}) => Response | Promise<Response>;
}
declare const serveStatic: (options: ServeStaticOptions) => ServerMiddleware;
//#endregion
export { ServeStaticOptions, serveStatic };

74
node_modules/srvx/dist/static.mjs generated vendored Normal file
View File

@@ -0,0 +1,74 @@
import { t as FastURL } from "./_chunks/_url.mjs";
import { createReadStream } from "node:fs";
import { extname, join, resolve } from "node:path";
import { readFile, stat } from "node:fs/promises";
import { FastResponse } from "srvx";
import { createBrotliCompress, createGzip } from "node:zlib";
const COMMON_MIME_TYPES = {
".html": "text/html",
".htm": "text/html",
".css": "text/css",
".js": "text/javascript",
".mjs": "text/javascript",
".json": "application/json",
".txt": "text/plain",
".xml": "application/xml",
".gif": "image/gif",
".ico": "image/vnd.microsoft.icon",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".png": "image/png",
".svg": "image/svg+xml",
".webp": "image/webp",
".woff": "font/woff",
".woff2": "font/woff2",
".mp4": "video/mp4",
".webm": "video/webm",
".zip": "application/zip",
".pdf": "application/pdf"
};
const serveStatic = (options) => {
const dir = resolve(options.dir) + "/";
const methods = new Set((options.methods || ["GET", "HEAD"]).map((m) => m.toUpperCase()));
return async (req, next) => {
if (!methods.has(req.method)) return next();
const path = (req._url ??= new FastURL(req.url)).pathname.slice(1).replace(/\/$/, "");
let paths;
if (path === "") paths = ["index.html"];
else if (extname(path) === "") paths = [`${path}.html`, `${path}/index.html`];
else paths = [path];
for (const path of paths) {
const filePath = join(dir, path);
if (!filePath.startsWith(dir)) continue;
const fileStat = await stat(filePath).catch(() => null);
if (fileStat?.isFile()) {
const fileExt = extname(filePath);
const headers = {
"Content-Length": fileStat.size.toString(),
"Content-Type": COMMON_MIME_TYPES[fileExt] || "application/octet-stream"
};
if (options.renderHTML && fileExt === ".html") return options.renderHTML({
html: await readFile(filePath, "utf8"),
filename: filePath,
request: req
});
let stream = createReadStream(filePath);
const acceptEncoding = req.headers.get("accept-encoding") || "";
if (acceptEncoding.includes("br")) {
headers["Content-Encoding"] = "br";
delete headers["Content-Length"];
headers["Vary"] = "Accept-Encoding";
stream = stream.pipe(createBrotliCompress());
} else if (acceptEncoding.includes("gzip")) {
headers["Content-Encoding"] = "gzip";
delete headers["Content-Length"];
headers["Vary"] = "Accept-Encoding";
stream = stream.pipe(createGzip());
}
return new FastResponse(stream, { headers });
}
}
return next();
};
};
export { serveStatic };

41
node_modules/srvx/dist/tracing.d.mts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import { Server, ServerMiddleware, ServerPlugin, ServerRequest } from "./types.mjs";
//#region src/tracing.d.ts
/**
* @experimental Channel names, event types and config options may change in future releases.
*/
type RequestEvent = {
server: Server;
request: ServerRequest;
middleware?: {
index: number;
handler: ServerMiddleware;
};
};
/**
*
* @experimental Channel names, event types and config options may change in future releases.
*
* Tracing plugin that adds diagnostics channel tracing to middleware and fetch handlers.
*
* This plugin wraps all middleware and the fetch handler with tracing instrumentation,
* allowing you to subscribe to `srvx.request` and `srvx.middleware` tracing channels.
*
* @example
* ```ts
* import { serve } from "srvx";
* import { tracingPlugin } from "srvx/tracing";
*
* const server = serve({
* fetch: (req) => new Response("OK"),
* middleware: [myMiddleware],
* plugins: [tracingPlugin()],
* });
* ```
*/
declare function tracingPlugin(opts?: {
middleware?: boolean;
fetch?: boolean;
}): ServerPlugin;
//#endregion
export { RequestEvent, tracingPlugin };

34
node_modules/srvx/dist/tracing.mjs generated vendored Normal file
View File

@@ -0,0 +1,34 @@
function tracingPlugin(opts = {}) {
return (server) => {
const { tracingChannel } = globalThis.process?.getBuiltinModule?.("node:diagnostics_channel") || {};
if (!tracingChannel) return;
if (opts.fetch !== false) {
const fetchChannel = tracingChannel("srvx.request");
const originalFetch = server.options.fetch;
server.options.fetch = (request) => {
return fetchChannel.tracePromise(async () => await originalFetch(request), {
request,
server
});
};
}
if (opts.middleware !== false) {
const middlewareChannel = tracingChannel("srvx.middleware");
const wrappedMiddleware = server.options.middleware.map((handler, index) => {
const middleware = Object.freeze({
index,
handler
});
return (request, next) => {
return middlewareChannel.tracePromise(async () => await handler(request, next), {
request,
server,
middleware
});
};
});
server.options.middleware.splice(0, server.options.middleware.length, ...wrappedMiddleware);
}
};
}
export { tracingPlugin };

303
node_modules/srvx/dist/types.d.mts generated vendored Normal file
View File

@@ -0,0 +1,303 @@
import * as NodeHttp from "node:http";
import * as NodeHttps from "node:https";
import * as NodeHttp2 from "node:http2";
import * as AWS from "aws-lambda";
import * as cloudflare_workers0 from "cloudflare:workers";
import * as NodeNet from "node:net";
import * as Bun from "bun";
import * as CF from "@cloudflare/workers-types";
//#region src/types.d.ts
type MaybePromise<T> = T | Promise<T>;
type IsAny<T> = Equal<T, any> extends true ? true : false;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
/**
* Faster URL constructor with lazy access to pathname and search params (For Node, Deno, and Bun).
*/
declare const FastURL: typeof globalThis.URL;
/**
* Faster Response constructor optimized for Node.js (same as Response for other runtimes).
*/
declare const FastResponse: typeof globalThis.Response;
/**
* Create a new server instance.
*/
declare function serve(options: ServerOptions): Server;
/**
* Web fetch compatible request handler
*/
type ServerHandler = (request: ServerRequest) => MaybePromise<Response>;
type ServerMiddleware = (request: ServerRequest, next: () => Response | Promise<Response>) => Response | Promise<Response>;
type ServerPlugin = (server: Server) => void;
/**
* Server options
*/
interface ServerOptions {
/**
* The fetch handler handles incoming requests.
*/
fetch: ServerHandler;
/**
* Handle lifecycle errors.
*
* @note This handler will set built-in Bun and Deno error handler.
*/
error?: ErrorHandler;
/**
* Server middleware handlers to run before the main fetch handler.
*/
middleware?: ServerMiddleware[];
/**
* Server plugins.
*/
plugins?: ServerPlugin[];
/**
* If set to `true`, server will not start listening automatically.
*/
manual?: boolean;
/**
* The port server should be listening to.
*
* Default is read from `PORT` environment variable or will be `3000`.
*
* **Tip:** You can set the port to `0` to use a random port.
*/
port?: string | number;
/**
* The hostname (IP or resolvable host) server listener should bound to.
*
* When not provided, server with listen to all network interfaces by default.
*
* **Important:** If you are running a server that is not expected to be exposed to the network, use `hostname: "localhost"`.
*/
hostname?: string;
/**
* Enabling this option allows multiple processes to bind to the same port, which is useful for load balancing.
*
* **Note:** Despite Node.js built-in behavior that has `exclusive` flag (opposite of `reusePort`) enabled by default, srvx uses non-exclusive mode for consistency.
*/
reusePort?: boolean;
/**
* The protocol to use for the server.
*
* Possible values are `http` and `https`.
*
* If `protocol` is not set, Server will use `http` as the default protocol or `https` if both `tls.cert` and `tls.key` options are provided.
*/
protocol?: "http" | "https";
/**
* If set to `true`, server will not print the listening address.
*/
silent?: boolean;
/**
* Graceful shutdown on SIGINT and SIGTERM signals.
*
* Supported for Node.js, Deno and Bun runtimes.
*
* @default true (disabled in test and ci environments)
*/
gracefulShutdown?: boolean | {
gracefulTimeout?: number;
forceTimeout?: number;
};
/**
* TLS server options.
*/
tls?: {
/**
* File path or inlined TLS certificate in PEM format (required).
*/
cert?: string;
/**
* File path or inlined TLS private key in PEM format (required).
*/
key?: string;
/**
* Passphrase for the private key (optional).
*/
passphrase?: string;
};
/**
* Node.js server options.
*/
node?: (NodeHttp.ServerOptions | NodeHttps.ServerOptions | NodeHttp2.ServerOptions) & NodeNet.ListenOptions & {
http2?: boolean;
};
/**
* Bun server options
*
* @docs https://bun.sh/docs/api/http
*/
bun?: Omit<Bun.Serve.Options<any>, "fetch">;
/**
* Deno server options
*
* @docs https://docs.deno.com/api/deno/~/Deno.serve
*/
deno?: Deno.ServeOptions;
/**
* Service worker options
*/
serviceWorker?: {
/**
* The path to the service worker file to be registered.
*/
url?: string;
/**
* The scope of the service worker.
*
*/
scope?: string;
};
}
interface Server<Handler = ServerHandler> {
/**
* Current runtime name
*/
readonly runtime: "node" | "deno" | "bun" | "cloudflare" | "service-worker" | "aws-lambda" | "generic";
/**
* Server options
*/
readonly options: ServerOptions & {
middleware: ServerMiddleware[];
};
/**
* Server URL address.
*/
readonly url?: string;
/**
* Node.js context.
*/
readonly node?: {
server?: NodeHttp.Server | NodeHttp2.Http2Server;
handler: (req: NodeServerRequest, res: NodeServerResponse) => void | Promise<void>;
};
/**
* Bun context.
*/
readonly bun?: {
server?: Bun.Server<any>;
};
/**
* Deno context.
*/
readonly deno?: {
server?: Deno.HttpServer;
};
/**
* Server fetch handler
*/
readonly fetch: Handler;
/**
* Start listening for incoming requests.
* When `manual` option is enabled, this method needs to be called explicitly to begin accepting connections.
*/
serve(): void | Promise<Server<Handler>>;
/**
* Returns a promise that resolves when the server is ready.
*/
ready(): Promise<Server<Handler>>;
/**
* Stop listening to prevent new connections from being accepted.
*
* By default, it does not cancel in-flight requests or websockets. That means it may take some time before all network activity stops.
*
* @param closeActiveConnections Immediately terminate in-flight requests, websockets, and stop accepting new connections.
* @default false
*/
close(closeActiveConnections?: boolean): Promise<void>;
}
interface ServerRuntimeContext {
name: "node" | "deno" | "bun" | "cloudflare" | "aws-lambda" | (string & {});
/**
* Underlying Node.js server request info.
*/
node?: {
req: NodeServerRequest;
res?: NodeServerResponse;
};
/**
* Underlying Deno server request info.
*/
deno?: {
info: Deno.ServeHandlerInfo<Deno.NetAddr>;
};
/**
* Underlying Bun server request context.
*/
bun?: {
server: Bun.Server<any>;
};
/**
* Underlying Cloudflare request context.
*/
cloudflare?: {
context: CF.ExecutionContext;
env: IsAny<typeof cloudflare_workers0> extends true ? Record<string, unknown> : typeof cloudflare_workers0.env;
};
awsLambda?: {
context: AWS.Context;
event: AWS.APIGatewayProxyEvent | AWS.APIGatewayProxyEventV2;
};
serviceWorker?: {
event: FetchEvent;
};
netlify?: {
context: any;
};
stormkit?: {
event: any;
context: any;
};
vercel?: {
context: {
waitUntil?: (promise: Promise<any>) => void;
};
};
}
interface ServerRequestContext {
[key: string]: unknown;
}
interface ServerRequest extends Request {
/**
* Access to Node.js native instance of request.
*
* See https://srvx.h3.dev/guide/node#noderequest
*/
_request?: Request;
/**
* Access to the parsed URL
*/
_url?: URL;
/**
* Runtime specific request context.
*/
runtime?: ServerRuntimeContext;
/**
* IP address of the client.
*/
ip?: string | undefined;
/**
* Arbitrary context related to the request.
*/
context?: ServerRequestContext;
/**
* Tell the runtime about an ongoing operation that shouldn't close until the promise resolves.
*/
waitUntil?: (promise: Promise<unknown>) => void | Promise<void>;
}
type FetchHandler = (request: Request) => Response | Promise<Response>;
type ErrorHandler = (error: unknown) => Response | Promise<Response>;
type BunFetchHandler = (request: Request, server?: Bun.Server<any>) => Response | Promise<Response>;
type DenoFetchHandler = (request: Request, info?: Deno.ServeHandlerInfo<Deno.NetAddr>) => Response | Promise<Response>;
type NodeServerRequest = NodeHttp.IncomingMessage | NodeHttp2.Http2ServerRequest;
type NodeServerResponse = NodeHttp.ServerResponse | NodeHttp2.Http2ServerResponse;
type NodeHttp1Handler = (req: NodeHttp.IncomingMessage, res: NodeHttp.ServerResponse) => void | Promise<void>;
type NodeHttp2Handler = (req: NodeHttp2.Http2ServerRequest, res: NodeHttp2.Http2ServerResponse) => void | Promise<void>;
type NodeHttpHandler = NodeHttp1Handler | NodeHttp2Handler;
type NodeHTTP1Middleware = (req: NodeHttp.IncomingMessage, res: NodeHttp.ServerResponse, next: (error?: Error) => void) => unknown | Promise<unknown>;
type NodeHTTP2Middleware = (req: NodeHttp2.Http2ServerRequest, res: NodeHttp2.Http2ServerResponse, next: (error?: Error) => void) => unknown | Promise<unknown>;
type NodeHTTPMiddleware = NodeHTTP1Middleware | NodeHTTP2Middleware;
type CloudflareFetchHandler = CF.ExportedHandlerFetchHandler;
//#endregion
export { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHTTP1Middleware, NodeHTTP2Middleware, NodeHTTPMiddleware, NodeHttp1Handler, NodeHttp2Handler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRequestContext, ServerRuntimeContext, serve };