New:Socket for Asana Is Now Available.Learn more
Get Started

srvx

Package Overview
Dependencies
Maintainers
1
Versions
86
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

srvx - npm Package Compare versions

Comparing version
0.12.5
to
0.12.6
+7
-1
dist/_chunks/types.d.mts

@@ -25,2 +25,8 @@ import * as NodeHttp from "node:http";

/**
* Headers accepted by the runtime `Headers` constructor (`HeadersInit`).
*
* Derived from the ambient `Headers` so that it does not require `lib: ["dom"]`.
*/
type ResponseHeaders = NonNullable<ConstructorParameters<typeof globalThis.Headers>[0]>;
/**
* Options forwarded to `Bun.serve()`.

@@ -60,3 +66,3 @@ *

upgrade(request: Request, options?: {
headers?: HeadersInit;
headers?: ResponseHeaders;
data?: any;

@@ -63,0 +69,0 @@ }): boolean;

+20
-8
import { errorPlugin, wrapFetch } from "../_chunks/_plugins.mjs";
import { forwardedHopValue, resolveClientIP, trustedHops } from "../_chunks/_trust-proxy.mjs";
import { HOST_RE, forwardedHopValue, resolveClientIP, trustedHops } from "../_chunks/_trust-proxy.mjs";
function awsRequest(event, context, trustProxy) {

@@ -32,7 +32,10 @@ const sourceIp = awsEventIP(event);

function awsEventURL(event, hops) {
const path = event.path || event.rawPath;
const rawPath = event.path || event.rawPath || "/";
const path = rawPath[0] === "/" ? rawPath : `/${rawPath}`;
const query = awsEventQuery(event);
const hostname = forwardedHopValue(event.headers["X-Forwarded-Host"] || event.headers["x-forwarded-host"], hops) || event.headers.host || event.headers.Host || event.requestContext?.domainName || ".";
const forwardedHost = forwardedHopValue(event.headers["X-Forwarded-Host"] || event.headers["x-forwarded-host"], hops);
const host = (forwardedHost && HOST_RE.test(forwardedHost) ? forwardedHost : void 0) || event.headers.host || event.headers.Host || event.requestContext?.domainName;
const hostname = host && HOST_RE.test(host) ? host : "_invalid_";
const protocol = forwardedHopValue(event.headers["X-Forwarded-Proto"] || event.headers["x-forwarded-proto"], hops) === "http" ? "http" : "https";
return new URL(`${path}${query ? `?${query}` : ""}`, `${protocol}://${hostname}`);
return new URL(`${protocol}://${hostname}${path}${query ? `?${query}` : ""}`);
}

@@ -49,3 +52,7 @@ function awsEventQuery(event) {

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);
const cookies = "cookies" in event && event.cookies?.length ? event.cookies : void 0;
if (cookies) {
headers.delete("cookie");
for (const cookie of cookies) headers.append("cookie", cookie);
}
return headers;

@@ -142,3 +149,3 @@ }

for (const [key, value] of request.headers) {
if (key.toLowerCase() === "cookie") cookies.push(value);
if (key.toLowerCase() === "cookie") cookies.push(...splitCookieHeader(value));
headers[key] = value;

@@ -218,2 +225,5 @@ }

}
function splitCookieHeader(value) {
return value.split(";").map((c) => c.trim()).filter(Boolean);
}
function parseMultiValueQuery(params) {

@@ -238,4 +248,6 @@ const result = {};

let body;
if (typeof result.body === "string") if (result.isBase64Encoded) body = Buffer.from(result.body, "base64");
else body = result.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;

@@ -242,0 +254,0 @@ return new Response(body, {

@@ -38,2 +38,3 @@ import { FastURL, lazyInherit } from "../_chunks/_url.mjs";

nodeRes.statusCode = 500;
if (nodeRes.req?.httpVersion !== "2.0") nodeRes.statusMessage = "";
nodeRes.end();

@@ -65,5 +66,11 @@ }

function writeHead(nodeRes, status, statusText, rawHeaders) {
if (!nodeRes.headersSent) if (nodeRes.req?.httpVersion === "2.0") nodeRes.writeHead(status, rawHeaders);
else nodeRes.writeHead(status, statusText, rawHeaders);
if (!nodeRes.headersSent) {
if (nodeRes.req?.httpVersion === "2.0") nodeRes.writeHead(status, rawHeaders);
else nodeRes.writeHead(status, safeStatusText(statusText), rawHeaders);
}
}
const INVALID_REASON_PHRASE_RE = /[^\t\u0020-\u007E\u0080-\u00FF]/g;
function safeStatusText(statusText) {
return typeof statusText === "string" && statusText ? statusText.replace(INVALID_REASON_PHRASE_RE, "") : statusText;
}
function endNodeResponse(nodeRes, detached) {

@@ -81,2 +88,8 @@ if (detached) {

}
if (nodeRes.req?.method === "HEAD") {
if (typeof stream.destroy === "function") stream.destroy();
else stream.abort?.();
writeHead(nodeRes, status, statusText, headers);
return endNodeResponse(nodeRes);
}
if (typeof stream.on !== "function" || typeof stream.destroy !== "function") {

@@ -92,4 +105,9 @@ writeHead(nodeRes, status, statusText, headers);

return new Promise((resolve) => {
function cleanup() {
stream.off("error", onEarlyError);
stream.off("readable", onReadable);
nodeRes.off("close", onResClose);
}
function onEarlyError() {
stream.off("readable", onReadable);
cleanup();
stream.destroy();

@@ -100,3 +118,3 @@ writeHead(nodeRes, 500, "Internal Server Error", []);

function onReadable() {
stream.off("error", onEarlyError);
cleanup();
if (nodeRes.destroyed) {

@@ -109,4 +127,10 @@ stream.destroy();

}
function onResClose() {
cleanup();
stream.destroy();
resolve();
}
stream.once("error", onEarlyError);
stream.once("readable", onReadable);
nodeRes.once("close", onResClose);
});

@@ -152,4 +176,6 @@ }

if (host && !HOST_RE.test(host)) host = "_invalid_";
else if (!host) if (req.socket) host = `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
else host = "localhost";
else if (!host) {
if (req.socket) host = `${req.socket.localFamily === "IPv6" ? "[" + req.socket.localAddress + "]" : req.socket.localAddress}:${req.socket?.localPort || "80"}`;
else host = "localhost";
}
const forwardedProto = forwardedHopValue(req.headers["x-forwarded-proto"], hops);

@@ -171,5 +197,27 @@ const protocol = req.socket?.encrypted || forwardedProto === "https" || trusted && req.headers[":scheme"] === "https" ? "https:" : "http:";

});
else super(path);
else {
const target = URL.canParse(path) ? new URL(path) : void 0;
if (target) {
const targetHost = target.host;
const targetPath = target.pathname;
super({
protocol,
host: targetHost ? HOST_RE.test(targetHost) ? targetHost : "_invalid_" : host,
pathname: targetPath ? targetPath[0] === "/" ? targetPath : `/${targetPath}` : "/",
search: target.search
});
} else super({
protocol,
host,
pathname: "/",
search: ""
});
}
}
};
function isValidAbsoluteForm(target) {
if (!URL.canParse(target)) return false;
const url = new URL(target);
return (url.protocol === "http:" || url.protocol === "https:") && url.host !== "";
}
const _nonJoinedHeaders = /* @__PURE__ */ new Set([

@@ -273,2 +321,13 @@ "age",

}
function abortError() {
return new DOMException("The request was aborted.", "AbortError");
}
function erroredStream(error) {
return new ReadableStream({ start(controller) {
controller.error(error);
} });
}
function isClientGone(req) {
return req.aborted || !!req.errored || req.destroyed && !req.complete;
}
const NodeRequest = /* @__PURE__ */ (() => {

@@ -347,10 +406,17 @@ const NativeRequest = getNativeRequest();

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();
});
if (res) {
const onClose = () => {
const reqError = req.errored;
if (reqError) abort(reqError);
else if (!res.writableEnded) abort();
};
res.once("close", onClose);
if (res.destroyed || isClientGone(req)) onClose();
} else {
const onClose = () => {
if (!req.complete || req.aborted) abort();
};
req.once("close", onClose);
if (isClientGone(req)) onClose();
}
}

@@ -369,3 +435,7 @@ return this.#abortController;

if (this.#bodyStream === void 0) {
let stream = this.#hasBody() && !this.#bodyUsed ? Readable.toWeb(this.#req) : null;
let stream = null;
if (this.#hasBody() && !this.#bodyUsed) {
stream = Readable.toWeb(this.#req);
if (Readable.isDisturbed(stream)) stream = erroredStream(this.#bodyError());
}
if (stream && this.#maxRequestBodySize !== void 0) stream = limitBodyStream(stream, this.#maxRequestBodySize);

@@ -384,3 +454,9 @@ this.#bodyStream = stream;

}
#bodyError() {
const signal = this._abortController.signal;
if (signal.aborted) return signal.reason;
return this.#req.errored || (isClientGone(this.#req) ? abortError() : bodyUnusable());
}
#readBuffered() {
if (isClientGone(this.#req) || this.#req.destroyed || this.#req.readableEnded) return Promise.reject(this.#bodyError());
return readBody(this.#req, this.#maxRequestBodySize);

@@ -481,2 +557,3 @@ }

req.off("error", onError);
req.off("close", onClose);
};

@@ -501,5 +578,13 @@ const onData = (chunk) => {

cleanup();
if (isClientGone(req)) {
reject(req.errored || abortError());
return;
}
resolve(chunks.length === 1 ? chunks[0] : Buffer.concat(chunks));
};
req.on("data", onData).once("end", onEnd).once("error", onError);
const onClose = () => {
cleanup();
reject(req.errored || abortError());
};
req.on("data", onData).once("end", onEnd).once("error", onError).once("close", onClose);
});

@@ -583,22 +668,24 @@ }

if (this.#response) body = this.#response.body;
else if (this.#body != null) 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, this.#body.byteOffset, this.#body.byteLength);
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;
else if (this.#body != null) {
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, this.#body.byteOffset, this.#body.byteLength);
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 = [];

@@ -787,2 +874,3 @@ const initHeaders = this.#init?.headers;

this.httpVersion = "1.1";
const headers = {};
const rawHeaders = this.rawHeaders;

@@ -792,3 +880,3 @@ for (const [key, value] of req.headers.entries()) {

if (lowerKey === "set-cookie") continue;
this.headers[lowerKey] = value;
headers[lowerKey] = value;
rawHeaders.push(key, value);

@@ -798,6 +886,7 @@ }

if (setCookie.length > 0) {
this.headers["set-cookie"] = setCookie;
headers["set-cookie"] = setCookie;
for (const cookie of setCookie) rawHeaders.push("set-cookie", cookie);
}
if (req.method !== "GET" && req.method !== "HEAD" && !this.headers["content-length"] && !this.headers["transfer-encoding"]) this.headers["transfer-encoding"] = "chunked";
if (req.method !== "GET" && req.method !== "HEAD" && !headers["content-length"] && !headers["transfer-encoding"]) headers["transfer-encoding"] = "chunked";
this.headers = headers;
const onData = (chunk) => {

@@ -911,3 +1000,3 @@ if (!this.push(chunk)) socket.pause();

writeHead(statusCode, statusMessage, headers) {
const result = typeof statusMessage === "string" ? super.writeHead(statusCode, statusMessage, stripTransferEncoding(headers)) : super.writeHead(statusCode, stripTransferEncoding(statusMessage));
const result = typeof statusMessage === "string" ? super.writeHead(statusCode, statusMessage, stripTransferEncoding(headers)) : super.writeHead(statusCode, stripTransferEncoding(headers ?? statusMessage));
this.#onHeadersSent?.();

@@ -1068,3 +1157,3 @@ return result;

}));
return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
return res instanceof Promise ? res.then((resolvedRes) => send(nodeRes, resolvedRes)) : send(nodeRes, res);
}

@@ -1075,2 +1164,5 @@ convertedNodeHandler.__fetchHandler = handler;

}
function send(nodeRes, webRes) {
return sendNodeResponse(nodeRes, webRes).catch((error) => handleSendError(nodeRes, error));
}
function toFetchHandler(handler) {

@@ -1114,3 +1206,3 @@ if (handler.__fetchHandler) return handler.__fetchHandler;

const reqUrl = nodeReq.url;
if (reqUrl && reqUrl[0] !== "/" && reqUrl !== "*" && !URL.canParse(reqUrl)) {
if (reqUrl && reqUrl[0] !== "/" && reqUrl !== "*" && !isValidAbsoluteForm(reqUrl)) {
nodeRes.statusCode = 400;

@@ -1159,8 +1251,9 @@ nodeRes.end();

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);
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);

@@ -1167,0 +1260,0 @@ this.node.server = server;

@@ -11,2 +11,7 @@ /**

*
* srvx's `ServerRequest._request` escape hatch is served over the same limited
* stream, so unwrapping the request (`req._request`, or `new Request(req)` under
* `patchGlobalRequest()`, which rewrites the input to `_request`) cannot reach
* the raw body and bypass the limit.
*
* Proxy-wrapping (rather than rebuilding via `new Request(request, …)`) is

@@ -13,0 +18,0 @@ * deliberate: it preserves the exact object handed in — including srvx's

@@ -10,2 +10,3 @@ function limitRequestBody(request, maxRequestBodySize, options) {

let limited;
let nativeRequest;
const limitedBody = () => limited ??= new Response(overLimit ? erroredStream(createError(maxRequestBodySize)) : limitBodyStream(request.body, maxRequestBodySize, options));

@@ -16,2 +17,9 @@ return new Proxy(request, { get(target, prop) {

if (typeof prop === "string" && bodyReadMethods.has(prop)) return () => limitedBody()[prop]();
if (prop === "_request" && "_request" in target) return nativeRequest ??= new Request(target.url, {
method: target.method,
headers: target.headers,
signal: target.signal,
body: limitedBody().body,
duplex: "half"
});
if (prop === "clone") return () => limitRequestBody(target.clone(), maxRequestBodySize, options);

@@ -18,0 +26,0 @@ const value = Reflect.get(target, prop, target);

@@ -21,3 +21,7 @@ import { bold, cyan, gray, green, magenta, red, url, yellow } from "./_chunks/_utils.mjs";

});
const { serve: srvxServe } = loaded.nodeCompat ? await import("srvx/node") : await import("srvx");
const nested = loaded.srvxServer?.options;
const nestedNode = nested?.node;
const nestedMTLS = !!nestedNode && ("requestCert" in nestedNode || "ca" in nestedNode);
if (nestedMTLS && loaded.srvxServer?.runtime !== "node") throw new Error(`[srvx] The server entry configures mutual TLS, which requires srvx's Node.js adapter (import { serve } from "srvx/node").`);
const { serve: srvxServe } = loaded.nodeCompat || nestedMTLS ? await import("srvx/node") : await import("srvx");
const { staticMiddleware } = await import("srvx/static");

@@ -39,3 +43,4 @@ const { loggerMiddleware } = await import("srvx/log");

};
let tls = serverOptions.tls;
let tls = serverOptions.tls ?? nested?.tls;
let protocol = serverOptions.protocol ?? nested?.protocol;
if (cliOpts.tls) {

@@ -47,3 +52,8 @@ if (!cliOpts.cert || !cliOpts.key) throw new Error("--tls requires both --cert and --key.");

};
protocol = void 0;
}
const nodeOptions = nested?.node || serverOptions.node ? {
...nested?.node,
...serverOptions.node
} : void 0;
printInfo(cliOpts, loaded);

@@ -56,2 +66,4 @@ server = srvxServe({

tls,
protocol,
node: nodeOptions,
error: (error) => {

@@ -77,3 +89,3 @@ console.error(error);

let html = `<!DOCTYPE html><html><head><title>${safeTitle}</title></head><body>`;
if (cliOpts.prod) html += `<h1>${safeTitle}</h1><p>Something went wrong while processing your request.</p>`;
if (cliOpts.prod || process.env.NODE_ENV === "production") html += `<h1>${safeTitle}</h1><p>Something went wrong while processing your request.</p>`;
else html += `

@@ -159,12 +171,14 @@ <style>

let isStream = false;
if (cliOpts.data !== void 0) if (cliOpts.data === "@-") {
isStream = true;
body = new ReadableStream({ async start(controller) {
for await (const chunk of stdin) controller.enqueue(chunk);
controller.close();
} });
} else if (cliOpts.data.startsWith("@")) {
isStream = true;
body = Readable.toWeb(createReadStream(cliOpts.data.slice(1)));
} else body = cliOpts.data;
if (cliOpts.data !== void 0) {
if (cliOpts.data === "@-") {
isStream = true;
body = new ReadableStream({ async start(controller) {
for await (const chunk of stdin) controller.enqueue(chunk);
controller.close();
} });
} else if (cliOpts.data.startsWith("@")) {
isStream = true;
body = Readable.toWeb(createReadStream(cliOpts.data.slice(1)));
} else body = cliOpts.data;
}
const method = cliOpts.method || (body === void 0 ? "GET" : "POST");

@@ -214,3 +228,3 @@ const url = new URL(inputURL, `http${cliOpts.tls ? "s" : ""}://${cliOpts.host || cliOpts.hostname || "localhost"}`);

name: "srvx",
version: "0.12.4",
version: "0.12.5",
description: "Universal Server."

@@ -389,2 +403,3 @@ };

} else if (sub === "serve") positionals.shift();
const prod = values.prod ?? process.env.NODE_ENV === "production";
if (mode === "fetch") {

@@ -396,2 +411,3 @@ const method = values.method || values.request;

...values,
prod,
url,

@@ -410,3 +426,4 @@ method

mode,
...values
...values,
prod
};

@@ -419,3 +436,4 @@ }

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) });
const srvxBin = fileURLToPath(globalThis.__SRVX_BIN__ || new URL("../bin/srvx.mjs", import.meta.url));
const child = fork(srvxBin, [...args], { execArgv: [...process.execArgv, ...runtimeArgs].filter(Boolean) });
child.on("error", (error) => {

@@ -422,0 +440,0 @@ console.error("Error in child process:", error);

@@ -20,9 +20,10 @@ import { fileURLToPath, pathToFileURL } from "node:url";

let entry = opts.entry;
if (entry) if (entry.startsWith("file://")) {
if (!existsSync(fileURLToPath(entry))) return { notFound: true };
if (entry) {
if (entry.startsWith("file://")) {
if (!existsSync(fileURLToPath(entry))) return { notFound: true };
} else {
entry = resolve(opts.dir || ".", entry);
if (!existsSync(entry)) return { notFound: true };
}
} else {
entry = resolve(opts.dir || ".", entry);
if (!existsSync(entry)) return { notFound: true };
}
else {
for (const defEntry of defaultEntries) {

@@ -29,0 +30,0 @@ for (const defExt of defaultExts) {

@@ -89,3 +89,4 @@ import { ServerPlugin } from "./_chunks/types.mjs";

* TLS (`tls.cert` / `tls.key`) and throws otherwise, since mutual TLS cannot run over
* plain HTTP.
* plain HTTP. A request that still reaches the plugin over a plain socket (TLS dropped
* after construction by an outer host) is answered with `496` rather than run.
*

@@ -92,0 +93,0 @@ * With the default `rejectUnauthorized: true`, unauthenticated clients are rejected

@@ -24,3 +24,7 @@ import { resolveCertOrKey } from "./_chunks/_utils2.mjs";

const socket = request.runtime?.node?.req?.socket;
if (socket && typeof socket.getPeerCertificate === "function") request.tls = {
if (!socket || typeof socket.getPeerCertificate !== "function") return new Response("Client certificate required", {
status: 496,
headers: { "content-type": "text/plain; charset=UTF-8" }
});
request.tls = {
peerCertificate: socket.getPeerCertificate(),

@@ -27,0 +31,0 @@ authorized: socket.authorized,

@@ -42,3 +42,3 @@ import { FastURL } from "./_chunks/_url.mjs";

const COMPRESS_MIN_SIZE = 1024;
const COMPRESS_MAX_SIZE = 10 * 1024 * 1024;
const COMPRESS_MAX_SIZE = 10485760;
const COMPRESSORS = {

@@ -233,13 +233,16 @@ br: (sizeHint) => createBrotliCompress({ params: {

}
if (parsed) return new FastResponse(file.handle.createReadStream({
start: parsed.start,
end: parsed.end
}), {
status: 206,
headers: {
...headers,
"Content-Range": `bytes ${parsed.start}-${parsed.end}/${file.size}`,
"Content-Length": (parsed.end - parsed.start + 1).toString()
}
});
if (parsed) {
const stream = file.handle.createReadStream({
start: parsed.start,
end: parsed.end
});
return new FastResponse(stream, {
status: 206,
headers: {
...headers,
"Content-Range": `bytes ${parsed.start}-${parsed.end}/${file.size}`,
"Content-Length": (parsed.end - parsed.start + 1).toString()
}
});
}
}

@@ -246,0 +249,0 @@ }

{
"name": "srvx",
"version": "0.12.5",
"version": "0.12.6",
"description": "Universal Server.",

@@ -59,5 +59,5 @@ "homepage": "https://srvx.h3.dev",

"test:node-compat:deno": "deno run vitest test/node.test",
"test:node-compat:bun": "bun vitest test/node.test.ts",
"test:node-compat:bun": "bun --bun run vitest run test/node.test.ts",
"test:node-adapters:deno": "deno run vitest test/node-adapters.test",
"test:node-adapters:bun": "bun vitest test/node-adapters.test.ts",
"test:node-adapters:bun": "bun --bun run vitest run test/node-adapters.test.ts",
"typecheck": "tsc --noEmit --skipLibCheck",

@@ -67,4 +67,4 @@ "vitest": "vitest"

"devDependencies": {
"@cloudflare/workers-types": "^5",
"@hono/node-server": "^2.0.10",
"@cloudflare/workers-types": "^5.20260818.1",
"@hono/node-server": "^2.1.1",
"@mitata/counters": "^0.0.8",

@@ -76,6 +76,6 @@ "@mjackson/node-fetch-server": "^0.7.0",

"@types/express": "^5.0.6",
"@types/node": "^26.1.1",
"@types/node": "^26.2.0",
"@types/node-forge": "^1.3.14",
"@types/serviceworker": "^0.0.199",
"@vitest/coverage-v8": "^4.1.10",
"@types/serviceworker": "^0.0.200",
"@vitest/coverage-v8": "^4.1.11",
"@whatwg-node/server": "^0.11.0",

@@ -85,5 +85,5 @@ "automd": "^0.4.3",

"eslint-config-unjs": "^0.6.2",
"execa": "^9.6.1",
"execa": "^10.0.1",
"express": "^5.2.1",
"fastify": "^5.10.0",
"fastify": "^5.12.1",
"get-port-please": "^3.2.0",

@@ -94,9 +94,9 @@ "mdbox": "^0.1.1",

"obuild": "^0.4.38",
"oxfmt": ">=0.58.0",
"oxlint": "^1.73.0",
"srvx-release": "npm:srvx@^0.11.21",
"oxfmt": "^0.64.0",
"oxlint": "^1.79.0",
"srvx-release": "npm:srvx@^0.12.5",
"tslib": "^2.8.1",
"typescript": "^7.0.2",
"undici": "8.4.0",
"vitest": "^4.1.10"
"undici": "^8.10.0",
"vitest": "^4.1.11"
},

@@ -103,0 +103,0 @@ "resolutions": {