Skip to content

feat: export body size limit helpers via srvx/body-limit#280

Merged
pi0 merged 3 commits into
mainfrom
feat/size-limit-utils
Jul 22, 2026
Merged

feat: export body size limit helpers via srvx/body-limit#280
pi0 merged 3 commits into
mainfrom
feat/size-limit-utils

Conversation

@pi0x

@pi0x pi0x commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Closes #279.

Exposes srvx's runtime-agnostic body-size-limit utilities as a public srvx/body-limit subpath so downstream layers (e.g. h3 per-handler limits) can enforce the same streaming semantics and error shape instead of re-implementing them.

Changes

  • Rename src/_body-limit.tssrc/body-limit.ts (public); add the ./body-limit export + build input. Internal Node/Deno adapter imports updated.
  • ReadableStream<Uint8Array> typing on limitBodyStream.
  • Early Content-Length rejection in limitRequestBody — rejects without reading a byte when the declared size already exceeds the limit.
  • Expanded JSDoc on pull-based/backpressure semantics and upstream cancellation.
  • Documented canonical error shape { code: "ERR_BODY_TOO_LARGE", statusCode: 413, status: 413 }.
  • New srvx/body-limit guide page + cross-link from the maxRequestBodySize option doc.
  • New unit tests (test/body-limit.test.ts).

Design note: early rejection

The naive "throw synchronously from limitRequestBody" would regress the Deno adapter — the throw escapes the fetch wrapper before the handler's try/catch and turns a clean 413 into an uncaught 500. Instead the returned request's body stream is pre-errored (and the original body cancelled unread). This still avoids reading any bytes off the socket, but the error surfaces on consumption — identical to the streaming path — so every existing caller works unchanged.

Content-Length is treated strictly as a fast path; the streaming limit remains the source of truth (absent/understated headers under chunked encoding are still caught).

Verification

pnpm lint, pnpm typecheck, and full vitest run (1262 passed / 35 skipped) — including the real-runtime Deno end-to-end body-limit test, which exercises the new early-reject path.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added reusable request and stream body-size limiting utilities.
    • Exposed them via a new srvx/body-limit subpath export.
    • Enforced limits now return a consistent ERR_BODY_TOO_LARGE HTTP 413-style error.
  • Documentation
    • Added a new guide with usage examples and the standardized 413 error shape.
    • Updated request options docs to reference the shared helpers.
  • Tests
    • Added coverage for enforcement, upstream cancellation, early rejection via Content-Length, and malformed Content-Length handling.

Make the runtime-agnostic body-size-limit utilities public so downstream
layers (e.g. h3 per-handler limits) can reuse the same streaming semantics
and error shape. Closes #279.

- Rename `_body-limit.ts` -> `body-limit.ts` and add `./body-limit` export
- Type body streams as `ReadableStream<Uint8Array>`
- Reject early (without reading the body) when `Content-Length` already
  exceeds the limit, keeping the streaming limit as the source of truth
- Document pull/backpressure semantics and the canonical 413 error shape
- Add `srvx/body-limit` guide page and unit tests

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0x
pi0x requested a review from pi0 as a code owner July 22, 2026 11:06
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c49cc10d-6895-4ab7-ab5f-6ff47ecad628

📥 Commits

Reviewing files that changed from the base of the PR and between 60d71b6 and 9da7ba8.

📒 Files selected for processing (3)
  • docs/1.guide/11.body-limit.md
  • src/body-limit.ts
  • test/body-limit.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/body-limit.test.ts
  • docs/1.guide/11.body-limit.md
  • src/body-limit.ts

📝 Walkthrough

Walkthrough

The change exposes runtime-agnostic body-size limiting helpers through srvx/body-limit, updates build and adapter wiring, adds comprehensive stream and request tests, and documents the API and error semantics.

Changes

Body-limit helper export

Layer / File(s) Summary
Body-limit implementation and validation
src/body-limit.ts, test/body-limit.test.ts
Adds canonical 413 errors, pull-based stream limiting, request wrapping, early Content-Length rejection, cancellation behavior, and tests for these paths.
Public module and runtime wiring
package.json, build.config.mjs, src/adapters/...
Publishes srvx/body-limit, includes it in the bundle, and updates Node and Deno imports.
Public API documentation
docs/1.guide/11.body-limit.md, docs/1.guide/5.options.md
Documents helper semantics, error fields, and custom body-size enforcement.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • h3js/h3 issue 1498: Addresses overlapping streaming request-body size enforcement and early Content-Length rejection.

Possibly related PRs

  • h3js/srvx#216: Touches Node request body-size enforcement and shared 413 error behavior.
  • h3js/srvx#253: Touches Node adapter integration and limitBodyStream consumption semantics.

Poem

A bunny found streams in a burrow so bright,
With limits that pull every byte just right.
Too large? “413!” the error will say,
Then upstream is cancelled and hops away.
Public helpers now bloom in the bundle today.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: publicly exporting body-size limit helpers via the srvx/body-limit subpath.
Linked Issues check ✅ Passed The PR satisfies #279 by exporting the helpers, preserving the canonical error contract, adding the type improvement, and documenting behavior.
Out of Scope Changes check ✅ Passed All changes support the body-limit export work, including adapter updates, build config, docs, and tests; no unrelated scope is evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/size-limit-utils

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/srvx@280

commit: 60d71b6

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/body-limit.ts`:
- Around line 93-99: The fast-path check in the body-size enforcement flow must
only use a syntactically valid, all-digit Content-Length value. Update the
contentLength parsing around request.headers.get("content-length") to validate
the raw header before numeric conversion, treating malformed, decimal,
hexadecimal, Infinity, empty, or absent values as unavailable so they fall
through to streaming enforcement; retain early rejection only for valid values
exceeding maxRequestBodySize.
- Around line 20-24: Define and export a BodyTooLargeError type containing the
documented code, statusCode, and status fields, then update
createBodyTooLargeError to return that type instead of the generic Error.
Preserve the existing error message and field values while exposing the complete
shape to TypeScript consumers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6e3df18-25e8-4118-b09c-753d0c68298d

📥 Commits

Reviewing files that changed from the base of the PR and between 4cf9c63 and 9a5a61d.

📒 Files selected for processing (9)
  • build.config.mjs
  • docs/1.guide/11.body-limit.md
  • docs/1.guide/5.options.md
  • package.json
  • src/_body-limit.ts
  • src/adapters/_node/request.ts
  • src/adapters/deno.ts
  • src/body-limit.ts
  • test/body-limit.test.ts
💤 Files with no reviewable changes (1)
  • src/_body-limit.ts

Comment thread src/body-limit.ts Outdated
Comment thread src/body-limit.ts
pi0 and others added 2 commits July 22, 2026 11:16
- Export a typed `BodyTooLargeError` interface so consumers get the
  `code`/`statusCode`/`status` fields without casting
- Only fast-reject on an all-digit `Content-Length` (HTTP `1*DIGIT`);
  treat decimal/hex/`Infinity`/malformed values as absent and fall
  through to the authoritative streaming limit

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0
pi0 merged commit 851bf2e into main Jul 22, 2026
13 of 15 checks passed
@pi0
pi0 deleted the feat/size-limit-utils branch July 22, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export body-size-limit helpers (limitBodyStream / limitRequestBody) for downstream reuse

2 participants