🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

srvx

Package Overview
Dependencies
Maintainers
1
Versions
77
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.11.18
to
0.11.19
+39
dist/_chunks/_body-limit.mjs
function createBodyTooLargeError(maxRequestBodySize) {
return Object.assign(/* @__PURE__ */ new Error(`Request body exceeds the maximum allowed size of ${maxRequestBodySize} bytes.`), {
code: "ERR_BODY_TOO_LARGE",
statusCode: 413,
status: 413
});
}
function limitBodyStream(stream, maxRequestBodySize) {
const reader = stream.getReader();
let size = 0;
return new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read();
if (done) {
controller.close();
return;
}
size += value.byteLength;
if (size > maxRequestBodySize) {
const error = createBodyTooLargeError(maxRequestBodySize);
reader.cancel(error).catch(() => {});
controller.error(error);
return;
}
controller.enqueue(value);
},
cancel(reason) {
return reader.cancel(reason);
}
});
}
function limitRequestBody(request, maxRequestBodySize) {
if (!request.body) return request;
return new Request(request, {
body: limitBodyStream(request.body, maxRequestBodySize),
duplex: "half"
});
}
export { createBodyTooLargeError, limitBodyStream, limitRequestBody };
+3
-2

@@ -29,2 +29,3 @@ function lazyInherit(target, source, sourceKey) {

const _needsNormRE = /(?:(?:^|\/)(?:\.|\.\.|%2e|%2e\.|\.%2e|%2e%2e)(?:\/|$))|[\\^#"<>{}`\x80-\uffff]/i;
const _searchNeedsNormRE = /[#"'<>]/;
const FastURL = /* @__PURE__ */ (() => {

@@ -44,5 +45,5 @@ const NativeURL = globalThis.URL;

const isOriginForm = url[0] === "/";
if (isOriginForm && !url.includes("#")) this.#href = url;
if (isOriginForm && !_searchNeedsNormRE.test(url)) this.#href = url;
else this.#url = new NativeURL(isOriginForm ? `http://localhost${url}` : url);
} else if (_needsNormRE.test(url.pathname) || url.search?.includes("#")) this.#url = new NativeURL(`${url.protocol || "http:"}//${url.host || "localhost"}${url.pathname}${url.search || ""}`);
} else if (_needsNormRE.test(url.pathname) || url.search && _searchNeedsNormRE.test(url.search)) this.#url = new NativeURL(`${url.protocol || "http:"}//${url.host || "localhost"}${url.pathname}${url.search || ""}`);
else {

@@ -49,0 +50,0 @@ this.#protocol = url.protocol;

+1
-0

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

error: this.options.error,
...this.options.maxRequestBodySize !== void 0 ? { maxRequestBodySize: this.options.maxRequestBodySize } : {},
...this.options.bun,

@@ -58,0 +59,0 @@ tls: {

import { FastURL } from "../_chunks/_url.mjs";
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions, toNativeResponse } from "../_chunks/_utils2.mjs";
import { gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins.mjs";
import { limitRequestBody } from "../_chunks/_body-limit.mjs";
const FastResponse = Response;

@@ -34,3 +35,5 @@ function serve(options) {

this.waitUntil = this.#wait.waitUntil;
const maxRequestBodySize = this.options.maxRequestBodySize;
this.fetch = (request, info) => {
if (maxRequestBodySize !== void 0) request = limitRequestBody(request, maxRequestBodySize);
Object.defineProperties(request, {

@@ -37,0 +40,0 @@ waitUntil: { value: this.#wait?.waitUntil },

@@ -7,2 +7,7 @@ import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../types.mjs";

res?: NodeServerResponse;
/**
* Maximum allowed size (in bytes) for the request body, enforced for both the
* buffered reads and the streamed body. See `ServerOptions.maxRequestBodySize`.
*/
maxRequestBodySize?: number;
};

@@ -58,3 +63,5 @@ declare const NodeRequest: {

*/
declare function toNodeHandler(handler: FetchHandler & AdapterMeta): NodeHttpHandler & AdapterMeta;
declare function toNodeHandler(handler: FetchHandler & AdapterMeta, options?: {
maxRequestBodySize?: number;
}): NodeHttpHandler & AdapterMeta;
/**

@@ -61,0 +68,0 @@ * Converts a Node.js HTTP handler into a Fetch API handler.

import { FastURL, lazyInherit } from "../_chunks/_url.mjs";
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils2.mjs";
import { errorPlugin, gracefulShutdownPlugin, wrapFetch } from "../_chunks/_plugins.mjs";
import { createBodyTooLargeError, limitBodyStream } from "../_chunks/_body-limit.mjs";
import nodeHTTP, { IncomingMessage, ServerResponse } from "node:http";

@@ -161,14 +162,9 @@ import { Duplex, PassThrough, Readable, addAbortSignal } from "node:stream";

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;
return this._headers.get(name);
}
has(name) {
if (this.#headers) return this.#headers.has(name);
return name.toLowerCase() in this.#req.headers;
return this._headers.has(name);
}
getSetCookie() {
if (this.#headers) return this.#headers.getSetCookie();
const value = this.#req.headers["set-cookie"];
return Array.isArray(value) ? value : value ? [value] : [];
return this._headers.getSetCookie();
}

@@ -198,4 +194,6 @@ entries() {

#abortController;
#maxRequestBodySize;
constructor(ctx) {
this.#req = ctx.req;
this.#maxRequestBodySize = ctx.maxRequestBodySize;
this.runtime = {

@@ -254,4 +252,5 @@ name: "node",

const method = this.method;
const hasBody = !(method === "GET" || method === "HEAD");
this.#bodyStream = hasBody ? Readable.toWeb(this.#req) : null;
let stream = !(method === "GET" || method === "HEAD") ? Readable.toWeb(this.#req) : null;
if (stream && this.#maxRequestBodySize !== void 0) stream = limitBodyStream(stream, this.#maxRequestBodySize);
this.#bodyStream = stream;
}

@@ -263,3 +262,3 @@ return this.#bodyStream;

if (this.#bodyStream !== void 0) return this.#bodyStream ? new Response(this.#bodyStream).text() : Promise.resolve("");
return readBody(this.#req).then((buf) => buf.toString());
return readBody(this.#req, this.#maxRequestBodySize).then((buf) => buf.toString());
}

@@ -306,15 +305,33 @@ json() {

}
function readBody(req) {
if ("rawBody" in req && Buffer.isBuffer(req.rawBody)) return Promise.resolve(req.rawBody);
function readBody(req, maxRequestBodySize) {
if ("rawBody" in req && Buffer.isBuffer(req.rawBody)) {
if (maxRequestBodySize !== void 0 && req.rawBody.length > maxRequestBodySize) return Promise.reject(createBodyTooLargeError(maxRequestBodySize));
return Promise.resolve(req.rawBody);
}
return new Promise((resolve, reject) => {
const chunks = [];
let size = 0;
const cleanup = () => {
req.off("data", onData);
req.off("end", onEnd);
req.off("error", onError);
};
const onData = (chunk) => {
if (maxRequestBodySize !== void 0) {
size += chunk.length;
if (size > maxRequestBodySize) {
cleanup();
req.pause?.();
reject(createBodyTooLargeError(maxRequestBodySize));
return;
}
}
chunks.push(chunk);
};
const onError = (err) => {
cleanup();
reject(err);
};
const onEnd = () => {
req.off("error", onError);
req.off("data", onData);
cleanup();
resolve(Buffer.concat(chunks));

@@ -416,4 +433,5 @@ };

else headers.push([key, value]);
if (key === "content-type") hasContentTypeHeader = true;
else if (key === "content-length") hasContentLength = true;
const lowerKey = typeof key === "string" ? key.toLowerCase() : key;
if (lowerKey === "content-type") hasContentTypeHeader = true;
else if (lowerKey === "content-length") hasContentLength = true;
}

@@ -733,3 +751,3 @@ if (contentType && !hasContentTypeHeader) headers.push(["content-type", contentType]);

}
function toNodeHandler(handler) {
function toNodeHandler(handler, options) {
if (handler.__nodeHandler) return handler.__nodeHandler;

@@ -739,3 +757,4 @@ function convertedNodeHandler(nodeReq, nodeRes) {

req: nodeReq,
res: nodeRes
res: nodeRes,
maxRequestBodySize: options?.maxRequestBodySize
}));

@@ -793,3 +812,4 @@ return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);

req: nodeReq,
res: nodeRes
res: nodeRes,
maxRequestBodySize: this.options.maxRequestBodySize
});

@@ -796,0 +816,0 @@ request.waitUntil = this.#wait?.waitUntil;

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

name: "srvx",
version: "0.11.17",
version: "0.11.18",
description: "Universal Server."

@@ -185,0 +185,0 @@ };

@@ -101,2 +101,22 @@ import * as NodeHttp from "node:http";

/**
* Maximum allowed size (in bytes) for the request body.
*
* As the body is read, its accumulated length is tracked and, once it exceeds
* this limit, reading is aborted and rejects with a `413`-style error (the error
* has `statusCode: 413`, `status: 413` and `code: "ERR_BODY_TOO_LARGE"`) so a
* handler can map it to an HTTP 413 (Payload Too Large) response.
*
* The limit covers the buffered reads (`request.text()` / `request.json()`) as
* well as the streamed body (`request.body`, and therefore `arrayBuffer()` /
* `blob()` / `bytes()` / `formData()`).
*
* Runtime support:
* - **Node**: enforced by srvx (body stream is size-limited).
* - **Bun**: mapped to Bun's native `maxRequestBodySize` (413 before the handler).
* - **Deno**: enforced by srvx (request body stream is size-limited).
*
* @default undefined (no limit)
*/
maxRequestBodySize?: number;
/**
* TLS server options.

@@ -103,0 +123,0 @@ */

{
"name": "srvx",
"version": "0.11.18",
"version": "0.11.19",
"description": "Universal Server.",

@@ -62,4 +62,4 @@ "homepage": "https://srvx.h3.dev",

"devDependencies": {
"@cloudflare/workers-types": "^4.20260617.1",
"@hono/node-server": "^2.0.5",
"@cloudflare/workers-types": "^4.20260701.1",
"@hono/node-server": "^2.0.6",
"@mitata/counters": "^0.0.8",

@@ -71,5 +71,5 @@ "@mjackson/node-fetch-server": "^0.7.0",

"@types/express": "^5.0.6",
"@types/node": "^25.9.3",
"@types/node": "^26.1.0",
"@types/node-forge": "^1.3.14",
"@types/serviceworker": "^0.0.197",
"@types/serviceworker": "^0.0.199",
"@typescript/native-preview": "latest",

@@ -83,3 +83,3 @@ "@vitest/coverage-v8": "^4.1.9",

"express": "^5.2.1",
"fastify": "^5.8.5",
"fastify": "^5.9.0",
"get-port-please": "^3.2.0",

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

"node-forge": "^1.4.0",
"obuild": "^0.4.36",
"oxfmt": "^0.55.0",
"oxlint": "^1.70.0",
"srvx-release": "npm:srvx@^0.11.16",
"obuild": "^0.4.37",
"oxfmt": "^0.57.0",
"oxlint": "^1.72.0",
"srvx-release": "npm:srvx@^0.11.18",
"tslib": "^2.8.1",
"typescript": "^6.0.3",
"undici": "~8.3",
"undici": "~8.3.0",
"vitest": "^4.1.9"

@@ -98,0 +98,0 @@ },