Skip to content

feat(body): update @routup/body for routup v5#761

Merged
tada5hi merged 8 commits intomasterfrom
743-body
Apr 8, 2026
Merged

feat(body): update @routup/body for routup v5#761
tada5hi merged 8 commits intomasterfrom
743-body

Conversation

@tada5hi
Copy link
Copy Markdown
Contributor

@tada5hi tada5hi commented Apr 8, 2026

closes #743

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced async body parsing helpers: readRequestBody(), readRequestBodyText(), readRequestBodyBytes(), readRequestBodyArrayBuffer(), readRequestBodyBlob(), and readRequestBodyStream() for flexible request payload handling.
    • Added new configuration option types: JsonOptions, UrlEncodedOptions, TextOptions, and RawOptions with enhanced customization.
  • Bug Fixes

    • Fixed cookie merging logic in request handling to preserve existing data.
  • Breaking Changes

    • Replaced deprecated useRequestBody() and setRequestBody() with async readRequestBody(event) API.
    • Removed external body-parser dependency; integrated custom parsing.
    • Updated middleware registration from router.install(body()) to router.use(body()).
  • Chores

    • Updated package dependencies to align with latest routup version.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

The @routup/body plugin is updated for routup v5's event-based API, removing body-parser dependencies and req/res-style handlers in favor of event-driven parsing helpers. Handlers now use defineCoreHandler with lazy body caching, and consumers parse bodies via new readRequestBody* helpers instead of the old useRequestBody pattern.

Changes

Cohort / File(s) Summary
Documentation
README.md
Updated usage examples from coreHandler((req, res) => ...) with useRequestBody(req) to router.post(...defineCoreHandler(async (event) => ...)) with await readRequestBody(event). Replaced Helpers API documentation to document new format-specific readers (readRequestBodyText, readRequestBodyBytes, etc.) and removed old setRequestBody/useRequestBody. Added option type definitions and adjusted default behavior documentation.
Metadata & Dependencies
package.json
Updated repository directory field from packages/cookie to packages/body. Removed direct dependencies on body-parser, @types/body-parser, and smob. Bumped routup peer/dev dependency from ^4.0.1 to ^5.0.0-beta.3.
Core Handler & Module Setup
src/handler.ts, src/module.ts
Added new createHandler(options) that wraps options into a defineCoreHandler returning event.next(). Refactored module.ts to use unified router.use(createHandler(options)) instead of per-format handlers, updated JSDoc, and cleaned up imports.
Options Management
src/helpers/options.ts
Introduced setBodyOptions and getBodyOptions helpers using a symbol-backed event.store pattern to persist and retrieve parsing options across request lifecycle.
Type System
src/types.ts
Replaced body-parser-derived types with plugin-owned BaseOptions, JsonOptions, UrlEncodedOptions, TextOptions, and RawOptions types. Updated Options to accept `
Body Reading Helpers
src/helpers/read*.ts (5 files)
Added readRequestBodyRaw, readRequestBodyStream, readRequestBodyArrayBuffer, readRequestBodyBlob, readRequestBodyBytes, and readRequestBodyText helpers. Raw reading implements size-limit enforcement and caching; stream reading handles decompression; other formats delegate to raw reading and apply format-specific transforms.
Body Parsing Helpers
src/helpers/parse*.ts (2 files)
Added parseJsonBody (with strict-mode validation and reviver support) and parseUrlEncodedBody (with parameter-count enforcement) helpers. Both perform content-type matching and delegate to raw body reading.
Primary Body Reading
src/helpers/read.ts
Added overloaded readRequestBody(event, key?) helper that caches parsed body in event.store, attempts JSON parsing first, falls back to URL-encoded, and optionally returns a specific property.
Helper Utilities
src/utils/*.ts (5 files)
Extracted utilities into separate modules: bool-to-object, decompress (creates DecompressionStream for gzip/deflate/brotli), is-object, match-content-type, and parse-size (converts `number
Public API Exports
src/index.ts, src/helpers/index.ts, src/parser/index.ts
Updated root export to expose new helpers (readRequestBody*) instead of old parser/request exports. Created helpers/index.ts barrel module. Cleared parser/index.ts of re-exports.
Removed Legacy Code
src/request.ts, src/utils.ts, src/parser/*.ts
Removed useRequestBody and setRequestBody request helpers. Removed boolToObject and isObject from main utils file. Removed createJsonHandler, createRawHandler, createTextHandler, createUrlEncodedHandler wrappers around body-parser.
Test Updates
test/unit/module.spec.ts
Replaced supertest/Node dispatcher setup with Routup Fetch-based API (router.fetch(...), defineCoreHandler). Updated handlers to use readRequestBody* helpers. Changed assertions from supertest fields to Fetch Response properties. Added caching and missing-plugin verification tests.
Related Package
packages/cookie/src/request.ts
Modified setRequestCookies to merge updates into existing stored cookies rather than overwriting the entire object.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

  • #743: This PR directly addresses the feature request to update @routup/body for routup v5, covering all required migration steps (peerDependency bump, event-based handler rewrite, new helpers).
  • #742: Related v5 migration issue for another plugin using the same API transition pattern.
  • #745, #746, #747, #749, #750: All track similar routup v5 migrations across other plugins with identical refactoring patterns.

Possibly related PRs

  • #756: Parallels the handler and helper migration from req/res/useRequest* patterns to event-based handlers and new read helpers.

Poem

A rabbit hops through body streams so clear,
No more body-parser chains to sear,
With readRequestBody swift and lean,
V5's event dance, pristine and clean! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(body): update @routup/body for routup v5' accurately describes the main change in this PR - migrating the @routup/body plugin to be compatible with routup v5.
Linked Issues check ✅ Passed The PR successfully implements all coding-related requirements from issue #743: updated peerDependencies to routup v5, converted handlers to event-based API, replaced useRequest* with event-based helpers, added comprehensive tests, and introduced new readRequestBody* helpers for body parsing.
Out of Scope Changes check ✅ Passed All changes are directly related to the v5 migration. The minor change to packages/cookie/src/request.ts is a supporting refactor improving setRequestCookies consistency with the new event-store architecture.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 743-body

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (8)
packages/body/src/utils/bool-to-object.ts (1)

1-7: Clarify behavior for false input.

The function treats both true and false boolean values the same way, returning {} as T. If false is intended to disable a feature (e.g., raw: false to disable raw body parsing), this would incorrectly convert it to an enabled empty options object.

Verify this is the intended behavior. If false should signal "disabled," callers must handle that case before invoking boolToObject.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/utils/bool-to-object.ts` around lines 1 - 7, boolToObject
currently treats any boolean (true or false) the same and returns {} as T, which
incorrectly converts a disabling `false` into an empty options object; change
the boolean handling so only a literal true is converted to an empty options
object: inside boolToObject (function name) replace the typeof check with a
strict comparison (if (input === true) return {} as T;) and otherwise return
input untouched, and ensure callers handle a false value before calling
boolToObject (or adjust the call sites to only call boolToObject when they know
input is true|object).
packages/body/src/module.ts (1)

16-31: Avoid mutating the caller-provided options object.

Derive a local resolved copy before applying defaults to prevent unexpected side effects outside the plugin.

Suggested diff
 export function body(options: Options = {}): Plugin {
+    const resolvedOptions: Options = { ...options };
     if (
-        typeof options.json === 'undefined' &&
-        typeof options.raw === 'undefined' &&
-        typeof options.urlEncoded === 'undefined' &&
-        typeof options.text === 'undefined'
+        typeof resolvedOptions.json === 'undefined' &&
+        typeof resolvedOptions.raw === 'undefined' &&
+        typeof resolvedOptions.urlEncoded === 'undefined' &&
+        typeof resolvedOptions.text === 'undefined'
     ) {
-        options.json = true;
-        options.urlEncoded = true;
+        resolvedOptions.json = true;
+        resolvedOptions.urlEncoded = true;
     }

     return {
         name: 'body',
         install: (router) => {
-            router.use(createHandler(options));
+            router.use(createHandler(resolvedOptions));
         },
     };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/module.ts` around lines 16 - 31, The body function
currently mutates the caller-provided options object when applying defaults;
instead create a local resolvedOptions copy (e.g., shallow clone) and apply the
default settings to that copy before using it. Update the body function to copy
the incoming Options, set resolvedOptions.json and resolvedOptions.urlEncoded
defaults when the various fields are undefined, and pass resolvedOptions into
createHandler(router) so the original options object is not mutated; reference
the body function, Options type, and createHandler/router.use to locate where to
change.
packages/body/src/helpers/blob.ts (1)

21-21: Prefer passing Uint8Array directly to Blob to avoid exposing unintended buffer ranges.

When raw is a Uint8Array view with a non-zero byteOffset (as can happen when readRawBody returns a cached or sliced view), using raw.buffer exposes the entire backing buffer, not just the intended range. Passing raw directly is safer, clearer, and requires no cast.

Suggested diff
-    return new Blob([raw.buffer as ArrayBuffer], { type: contentType });
+    return new Blob([raw], { type: contentType });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/blob.ts` at line 21, The Blob creation currently
uses new Blob([raw.buffer as ArrayBuffer], { type: contentType }) which can
expose the entire backing ArrayBuffer when raw is a Uint8Array view with a
non-zero byteOffset; change the Blob constructor to pass the Uint8Array view
directly (use raw instead of raw.buffer) in the function that returns the Blob
so only the intended slice is included and no cast is needed (refer to the Blob
creation expression and the variables raw and contentType).
packages/body/src/helpers/url-encoded.ts (1)

23-24: Consider specifying encoding from Content-Type header.

The TextDecoder defaults to UTF-8, but the Content-Type header may specify a different charset (e.g., application/x-www-form-urlencoded; charset=iso-8859-1). For robustness, consider parsing the charset from the content-type header.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/url-encoded.ts` around lines 23 - 24, The code
currently decodes the raw body using new TextDecoder() which assumes UTF-8;
update the logic in the handler that calls readRawBody (the code around
readRawBody(event, options) and the subsequent TextDecoder usage) to parse the
charset from the request Content-Type header (e.g., from
event.headers['content-type'] or equivalent), normalize it (fall back to 'utf-8'
if missing or unsupported), and pass that charset into new TextDecoder(charset)
when decoding the raw buffer so non-UTF-8 bodies (e.g., iso-8859-1) are handled
correctly.
packages/body/src/helpers/json.ts (2)

19-53: Return type doesn't reflect that arrays are valid.

The return type Promise<Record<string, any> | undefined> doesn't accurately represent that JSON arrays are valid in strict mode (line 45 allows Array.isArray(parsed)). Consider updating the type to Promise<Record<string, any> | any[] | undefined> for better type safety.

💡 Suggested type update
 export async function parseJsonBody(
     event: IRoutupEvent,
     options: JsonOptions,
-): Promise<Record<string, any> | undefined> {
+): Promise<Record<string, any> | any[] | undefined> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/json.ts` around lines 19 - 53, The return type of
parseJsonBody is too narrow and doesn't account for valid JSON arrays; update
the function signature for parseJsonBody to return Promise<Record<string, any> |
any[] | undefined> (or Promise<object | any[] | undefined> if you prefer) so
callers can safely handle arrays, and update any related type
declarations/imports (e.g., JsonOptions usages) to match the new return type;
ensure the final return cast (return parsed as Record<string, any>) is adjusted
to reflect either Record<string, any> or any[].

30-32: Empty body silently returns {}.

When the request has application/json content-type but an empty body, the function returns {} rather than undefined or throwing. This could mask client bugs where an empty body is sent unintentionally. Consider whether returning undefined (to indicate no parseable content) or throwing a 400 error would be more appropriate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/json.ts` around lines 30 - 32, The helper currently
returns an empty object when the body is empty (the branch "if (!text) { return
{}; }"); change this to return undefined instead of {} to avoid masking
empty-body bugs, update the helper's return type to allow undefined, and update
any callers of the helper (or add a clear error/validation upstream) to handle
undefined cases; alternatively, if you prefer strict validation, replace that
branch with throwing a 400-like error, but be sure to adjust the helper's
signature and call sites accordingly.
packages/body/test/unit/module.spec.ts (2)

136-150: Clarify "accessor-only" behavior in test name or comment.

The test name "should work without plugin (accessor-only)" and comment explain that useRequestBody returns {} without the plugin. This is important behavior to document. Consider adding a brief note explaining that the plugin is required to enable actual parsing, and without it, only an empty object is returned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/test/unit/module.spec.ts` around lines 136 - 150, The test name
and inline comment don't clearly document that useRequestBody returns an empty
object when the body-parsing plugin is not installed; update the test title
and/or add a concise comment to clarify the expected "accessor-only" behavior:
reference the Router, defineCoreHandler, and useRequestBody usage in this test
and state that without the body-parsing plugin the handler only provides an
empty accessor ({}), and that enabling the plugin is required for actual parsing
of JSON payloads sent via createTestRequest.

18-171: Consider adding error scenario tests.

The test suite covers happy paths well but doesn't test error scenarios such as:

  • 413 error when body exceeds size limit
  • 400 error for malformed JSON
  • Strict mode rejection of non-object/array JSON

These would improve confidence in the error handling paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/test/unit/module.spec.ts` around lines 18 - 171, Add unit tests
that exercise error branches: 1) create a Router, use body middleware with a
small size limit via router.use(body({ json: true, /* set limit small */ }))
then POST a payload larger than the limit and assert response.status === 413 and
appropriate error payload; 2) register a route using defineCoreHandler that
returns useRequestBody(event), send a POST with invalid JSON and assert
response.status === 400 and an error body indicating malformed JSON; 3) enable
strict JSON mode in the body middleware (router.use(body({ json: { strict: true
} }))) then POST a non-object/non-array JSON (e.g., a string/number) and assert
the middleware rejects it (status 400 or configured rejection) — locate changes
around router.use(body(...)), defineCoreHandler, and
useRequestBody/readRequestBodyText/readRequestBodyBytes to add these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/body/README.md`:
- Around line 168-176: The README's useRequestBody declarations incorrectly type
the return as Promise<Record<string, any>> which excludes JSON arrays; update
both overloads of useRequestBody to reflect array support by changing their
return type to either Promise<Record<string, any> | unknown[]> or the more
general Promise<unknown> (choose one consistently), so the documented signatures
for useRequestBody(event: IRoutupEvent) and useRequestBody(event: IRoutupEvent,
key: string) accurately represent parser output.
- Around line 205-219: The README's "raw options" description is incorrect: the
`raw` option applies only to readRequestBodyBytes (which accepts RawOptions),
while readRequestBodyArrayBuffer and readRequestBodyBlob accept only
LimitOptions and do not support `raw`; update the `raw` options section to state
that `raw` config is only used by the readRequestBodyBytes helper (mention
RawOptions), and remove or reword the claim that it is used by
readRequestBodyArrayBuffer and readRequestBodyBlob (which take LimitOptions
only) so the docs match the function signatures (readRequestBodyBytes,
readRequestBodyArrayBuffer, readRequestBodyBlob).

In `@packages/body/src/helpers/array-buffer.ts`:
- Around line 16-18: The code returns raw.buffer directly which can expose
pooled bytes when readRawBody/concat() returned a single Uint8Array chunk; fix
by extracting only the chunk's bytes instead of the entire underlying
ArrayBuffer: when returning from array-buffer.ts replace the direct raw.buffer
cast with a sliced view using raw.byteOffset and raw.byteLength (i.e. create a
new ArrayBuffer from raw.buffer.slice(raw.byteOffset, raw.byteOffset +
raw.byteLength)) so the returned ArrayBuffer contains only the chunk's data;
alternatively you can change concat() to always allocate a new Uint8Array for
the single-chunk case (use new Uint8Array(chunks[0])) so downstream code
(readRawBody / the variable raw) never holds a pooled-backed view.

In `@packages/body/src/helpers/url-encoded.ts`:
- Around line 31-40: The loop that assigns parsed URL params (for (const [k, v]
of params) { ... body[k] = v; }) overwrites duplicate keys (last-value-wins);
change it to accumulate repeated keys into arrays: when body[k] is undefined set
body[k]=v, when it's already a value convert to an array [old, v], and when it's
an array push v; preserve the existing limit/count and error behavior
(createError usage) and ensure tests/consumers expecting string vs array are
considered or document this new array-accumulation behavior if intentional.

In `@packages/body/src/index.ts`:
- Around line 8-14: The public API lost setRequestBody; restore backward
compatibility by reintroducing and exporting setRequestBody from the body
package: either add a wrapper function in the helpers module that delegates to
the new API (e.g., call setBodyOptions/useRequestBody appropriately) or, if an
existing implementation exists, simply re-export setRequestBody from './helpers'
alongside useRequestBody and the readRequestBody* exports in
packages/body/src/index.ts so existing consumers (and tests referencing
setRequestBody) continue to work.

In `@packages/body/src/types.ts`:
- Around line 1-8: The documentation claims LimitOptions.limit defaults to
'100kb' but the code never enforces it; update the implementation to inject that
default or change the doc. Fix by ensuring any code path that calls readRawBody
or consumes LimitOptions (e.g., the readRawBody function and the handler/option
helper that builds request parsing options) sets options.limit = options.limit
?? '100kb' before reading the body; alternatively remove the `@default` comment in
the LimitOptions type if you prefer no default. Target the LimitOptions type doc
and the readRawBody function plus the handler/option helper that constructs
parsing options to apply the default.

In `@packages/body/src/utils/match-content-type.ts`:
- Around line 4-10: The helper matchContentType currently accepts only string |
string[] which breaks dynamic per-request matching; change its signature to
accept string | string[] | ((event: IRoutupEvent) => string | string[]) and,
inside matchContentType, if types is a function call it with the event to obtain
the runtime type(s) before normalizing to an array and calling
matchRequestContentType; also update the public option types in JsonOptions,
UrlEncodedOptions, TextOptions, and RawOptions to use the same union so the
plugins can pass dynamic matcher functions.

In `@packages/body/src/utils/parse-size.ts`:
- Around line 13-16: The current parse-size logic silently falls back to
Number.parseInt on malformed inputs which can return NaN and disable size
limits; update the code in the parse-size utility (the branch where
input.match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)$/i) is false) to explicitly reject
invalid size strings by throwing a clear error (e.g., RangeError or TypeError)
instead of calling Number.parseInt, so callers like read-raw-body's limiter
receive a definite failure rather than a falsy NaN. Locate the match check in
the parse-size function and replace the fallback with a thrown error that
includes the original input.

In `@packages/cookie/src/request.ts`:
- Around line 25-34: setRequestCookies currently replaces the entire cookie
store when called with a single key/value (in the branch where key is a string);
change the string-key branch to merge the new { [key]: value } into the existing
cookie map instead of overwriting it: read the current map from
event.store[CookieSymbol] (default to {} if missing), set/override the single
key on that map, and assign the merged map back to event.store[CookieSymbol];
keep the object-overload branch (when isObject(key) is true) unchanged.

---

Nitpick comments:
In `@packages/body/src/helpers/blob.ts`:
- Line 21: The Blob creation currently uses new Blob([raw.buffer as
ArrayBuffer], { type: contentType }) which can expose the entire backing
ArrayBuffer when raw is a Uint8Array view with a non-zero byteOffset; change the
Blob constructor to pass the Uint8Array view directly (use raw instead of
raw.buffer) in the function that returns the Blob so only the intended slice is
included and no cast is needed (refer to the Blob creation expression and the
variables raw and contentType).

In `@packages/body/src/helpers/json.ts`:
- Around line 19-53: The return type of parseJsonBody is too narrow and doesn't
account for valid JSON arrays; update the function signature for parseJsonBody
to return Promise<Record<string, any> | any[] | undefined> (or Promise<object |
any[] | undefined> if you prefer) so callers can safely handle arrays, and
update any related type declarations/imports (e.g., JsonOptions usages) to match
the new return type; ensure the final return cast (return parsed as
Record<string, any>) is adjusted to reflect either Record<string, any> or any[].
- Around line 30-32: The helper currently returns an empty object when the body
is empty (the branch "if (!text) { return {}; }"); change this to return
undefined instead of {} to avoid masking empty-body bugs, update the helper's
return type to allow undefined, and update any callers of the helper (or add a
clear error/validation upstream) to handle undefined cases; alternatively, if
you prefer strict validation, replace that branch with throwing a 400-like
error, but be sure to adjust the helper's signature and call sites accordingly.

In `@packages/body/src/helpers/url-encoded.ts`:
- Around line 23-24: The code currently decodes the raw body using new
TextDecoder() which assumes UTF-8; update the logic in the handler that calls
readRawBody (the code around readRawBody(event, options) and the subsequent
TextDecoder usage) to parse the charset from the request Content-Type header
(e.g., from event.headers['content-type'] or equivalent), normalize it (fall
back to 'utf-8' if missing or unsupported), and pass that charset into new
TextDecoder(charset) when decoding the raw buffer so non-UTF-8 bodies (e.g.,
iso-8859-1) are handled correctly.

In `@packages/body/src/module.ts`:
- Around line 16-31: The body function currently mutates the caller-provided
options object when applying defaults; instead create a local resolvedOptions
copy (e.g., shallow clone) and apply the default settings to that copy before
using it. Update the body function to copy the incoming Options, set
resolvedOptions.json and resolvedOptions.urlEncoded defaults when the various
fields are undefined, and pass resolvedOptions into createHandler(router) so the
original options object is not mutated; reference the body function, Options
type, and createHandler/router.use to locate where to change.

In `@packages/body/src/utils/bool-to-object.ts`:
- Around line 1-7: boolToObject currently treats any boolean (true or false) the
same and returns {} as T, which incorrectly converts a disabling `false` into an
empty options object; change the boolean handling so only a literal true is
converted to an empty options object: inside boolToObject (function name)
replace the typeof check with a strict comparison (if (input === true) return {}
as T;) and otherwise return input untouched, and ensure callers handle a false
value before calling boolToObject (or adjust the call sites to only call
boolToObject when they know input is true|object).

In `@packages/body/test/unit/module.spec.ts`:
- Around line 136-150: The test name and inline comment don't clearly document
that useRequestBody returns an empty object when the body-parsing plugin is not
installed; update the test title and/or add a concise comment to clarify the
expected "accessor-only" behavior: reference the Router, defineCoreHandler, and
useRequestBody usage in this test and state that without the body-parsing plugin
the handler only provides an empty accessor ({}), and that enabling the plugin
is required for actual parsing of JSON payloads sent via createTestRequest.
- Around line 18-171: Add unit tests that exercise error branches: 1) create a
Router, use body middleware with a small size limit via router.use(body({ json:
true, /* set limit small */ })) then POST a payload larger than the limit and
assert response.status === 413 and appropriate error payload; 2) register a
route using defineCoreHandler that returns useRequestBody(event), send a POST
with invalid JSON and assert response.status === 400 and an error body
indicating malformed JSON; 3) enable strict JSON mode in the body middleware
(router.use(body({ json: { strict: true } }))) then POST a non-object/non-array
JSON (e.g., a string/number) and assert the middleware rejects it (status 400 or
configured rejection) — locate changes around router.use(body(...)),
defineCoreHandler, and useRequestBody/readRequestBodyText/readRequestBodyBytes
to add these tests.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6eaa311-1ced-43e4-bac4-6cf93cd83466

📥 Commits

Reviewing files that changed from the base of the PR and between 190178f and edc1a6c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (40)
  • packages/assets/package.json
  • packages/body/README.md
  • packages/body/package.json
  • packages/body/src/handler.ts
  • packages/body/src/helpers/array-buffer.ts
  • packages/body/src/helpers/blob.ts
  • packages/body/src/helpers/body.ts
  • packages/body/src/helpers/bytes.ts
  • packages/body/src/helpers/index.ts
  • packages/body/src/helpers/json.ts
  • packages/body/src/helpers/options.ts
  • packages/body/src/helpers/text.ts
  • packages/body/src/helpers/url-encoded.ts
  • packages/body/src/index.ts
  • packages/body/src/module.ts
  • packages/body/src/parser/index.ts
  • packages/body/src/parser/json.ts
  • packages/body/src/parser/raw.ts
  • packages/body/src/parser/text.ts
  • packages/body/src/parser/url-encoded.ts
  • packages/body/src/request.ts
  • packages/body/src/types.ts
  • packages/body/src/utils.ts
  • packages/body/src/utils/bool-to-object.ts
  • packages/body/src/utils/decompress.ts
  • packages/body/src/utils/index.ts
  • packages/body/src/utils/is-object.ts
  • packages/body/src/utils/match-content-type.ts
  • packages/body/src/utils/parse-size.ts
  • packages/body/src/utils/read-raw-body.ts
  • packages/body/test/unit/module.spec.ts
  • packages/cookie/README.md
  • packages/cookie/package.json
  • packages/cookie/src/handler.ts
  • packages/cookie/src/request.ts
  • packages/cookie/src/response.ts
  • packages/cookie/src/utils.ts
  • packages/cookie/test/unit/module.spec.ts
  • packages/swagger/README.md
  • packages/swagger/package.json
💤 Files with no reviewable changes (7)
  • packages/body/src/parser/json.ts
  • packages/body/src/parser/url-encoded.ts
  • packages/body/src/parser/raw.ts
  • packages/body/src/parser/text.ts
  • packages/body/src/parser/index.ts
  • packages/body/src/utils.ts
  • packages/body/src/request.ts

Comment thread packages/body/README.md Outdated
Comment on lines +168 to +176
declare function useRequestBody(
event: IRoutupEvent,
) : Promise<Record<string, any>>;

declare function useRequestBody(
event: IRoutupEvent,
key: string,
value: unknown
) : void;
) : Promise<any | undefined>;
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify declared/implemented return types for useRequestBody and parser outputs.
rg -n -C4 'function\s+useRequestBody\s*\(|export\s+function\s+useRequestBody\s*\(' packages/body/src
rg -n -C4 'JSON\.parse|urlencoded|parse' packages/body/src/helpers packages/body/src 2>/dev/null

Repository: routup/plugins

Length of output: 18787


🏁 Script executed:

cat -n packages/body/README.md | sed -n '165,180p'

Repository: routup/plugins

Length of output: 552


🏁 Script executed:

sed -n '10,22p' packages/body/src/types.ts

Repository: routup/plugins

Length of output: 376


Update useRequestBody return type in README to reflect array support.

The documented type Promise<Record<string, any>> excludes JSON arrays, which the parser accepts by default in strict mode (the default configuration). The return type should be Promise<Record<string, any> | unknown[]> or Promise<unknown> to accurately reflect parser output and prevent type surprises for consumers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` around lines 168 - 176, The README's useRequestBody
declarations incorrectly type the return as Promise<Record<string, any>> which
excludes JSON arrays; update both overloads of useRequestBody to reflect array
support by changing their return type to either Promise<Record<string, any> |
unknown[]> or the more general Promise<unknown> (choose one consistently), so
the documented signatures for useRequestBody(event: IRoutupEvent) and
useRequestBody(event: IRoutupEvent, key: string) accurately represent parser
output.

Comment thread packages/body/README.md
Comment on lines +205 to +219
declare function readRequestBodyArrayBuffer(
event: IRoutupEvent,
options?: LimitOptions,
) : Promise<ArrayBuffer>;
```

## Credits
### `readRequestBodyBlob`

This library is currently based on the [body-parser](https://www.npmjs.com/package/body-parser) library,
but this might change in the near future.
Returns the request body as a `Blob`.

```typescript
declare function readRequestBodyBlob(
event: IRoutupEvent,
options?: LimitOptions,
) : Promise<Blob>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify actual function signatures and exported option types for body readers.
rg -n -C3 'export\s+async\s+function\s+readRequestBody(Bytes|ArrayBuffer|Blob)\s*\(' packages/body/src
rg -n -C3 'type\s+(RawOptions|LimitOptions)\b|interface\s+(RawOptions|LimitOptions)\b' packages/body/src
rg -n -C3 'readRequestBodyArrayBuffer|readRequestBodyBlob|readRequestBodyBytes' packages/body/src

Repository: routup/plugins

Length of output: 4013


🏁 Script executed:

sed -n '1,226p' packages/body/README.md | head -150

Repository: routup/plugins

Length of output: 3883


Update the raw options section to exclude arrayBuffer and Blob helpers.

The README's raw options section (line ~165) claims this configuration is used by readRequestBodyBytes, readRequestBodyArrayBuffer, and readRequestBodyBlob, but the actual function signatures only accept RawOptions for readRequestBodyBytes. The readRequestBodyArrayBuffer and readRequestBodyBlob helpers only accept LimitOptions (without the raw config), creating inconsistency between the documented behavior and actual API.

Update the README to clarify that the raw configuration applies only to readRequestBodyBytes:

Suggested README fix
 ### `raw`
 
-Configure options for raw body reading (used by `readRequestBodyBytes`, `readRequestBodyArrayBuffer`, `readRequestBodyBlob`).
+Configure options for raw body reading (used by `readRequestBodyBytes`).
 
 - Type: `RawOptions | boolean`
 - Default: `false`
🧰 Tools
🪛 LanguageTool

[style] ~212-~212: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...uffer>; ### `readRequestBodyBlob` Returns the request body as a `Blob`. types...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` around lines 205 - 219, The README's "raw options"
description is incorrect: the `raw` option applies only to readRequestBodyBytes
(which accepts RawOptions), while readRequestBodyArrayBuffer and
readRequestBodyBlob accept only LimitOptions and do not support `raw`; update
the `raw` options section to state that `raw` config is only used by the
readRequestBodyBytes helper (mention RawOptions), and remove or reword the claim
that it is used by readRequestBodyArrayBuffer and readRequestBodyBlob (which
take LimitOptions only) so the docs match the function signatures
(readRequestBodyBytes, readRequestBodyArrayBuffer, readRequestBodyBlob).

Comment thread packages/body/src/helpers/read-array-buffer.ts
Comment thread packages/body/src/helpers/parse-url-encoded.ts
Comment on lines +8 to +14
export {
useRequestBody,
readRequestBodyArrayBuffer,
readRequestBodyBlob,
readRequestBodyBytes,
readRequestBodyText,
} from './helpers';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find remaining imports of setRequestBody from `@routup/body`.
rg -n -C2 "setRequestBody" packages

# Confirm whether body package currently exports/defines setRequestBody.
rg -n -C2 "export .*setRequestBody|function setRequestBody|const setRequestBody" packages/body/src

Repository: routup/plugins

Length of output: 787


🏁 Script executed:

# Check if setRequestBody exists anywhere in the body package
rg "setRequestBody" packages/body/ -n

# Check the structure of packages/body
find packages/body -type f -name "*.ts" | head -20

# Check if setRequestBody is in request file
cat packages/body/src/request.ts 2>/dev/null || echo "request.ts not found"

Repository: routup/plugins

Length of output: 790


🏁 Script executed:

# Check handler.ts for setRequestBody definition
cat packages/body/src/handler.ts

# Check module.ts
cat packages/body/src/module.ts

# Check what helpers/index.ts actually exports
cat packages/body/src/helpers/index.ts

Repository: routup/plugins

Length of output: 1531


🏁 Script executed:

# Check body.ts
cat packages/body/src/helpers/body.ts

# Check options.ts  
cat packages/body/src/helpers/options.ts

Repository: routup/plugins

Length of output: 1948


Public API regression: setRequestBody is imported but no longer exported from @routup/body.

The test file packages/decorators/test/unit/body.spec.ts imports setRequestBody on line 2 and uses it on line 20, but this function does not exist in the packages/body codebase. Either re-export setRequestBody for backward compatibility or update all consumers to use the replacement API (e.g., setBodyOptions + useRequestBody).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/index.ts` around lines 8 - 14, The public API lost
setRequestBody; restore backward compatibility by reintroducing and exporting
setRequestBody from the body package: either add a wrapper function in the
helpers module that delegates to the new API (e.g., call
setBodyOptions/useRequestBody appropriately) or, if an existing implementation
exists, simply re-export setRequestBody from './helpers' alongside
useRequestBody and the readRequestBody* exports in packages/body/src/index.ts so
existing consumers (and tests referencing setRequestBody) continue to work.

Comment thread packages/body/src/types.ts Outdated
Comment on lines +4 to +10
export function matchContentType(
event: IRoutupEvent,
types: string | string[],
): boolean {
const typeList = Array.isArray(types) ? types : [types];
return typeList.some((t) => matchRequestContentType(event, t));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep dynamic type matchers supported.

Restricting this helper to string | string[] removes the ability to decide per event whether a parser should run. That is a meaningful regression for the advanced body plugin, and the same restriction propagates into the public type options in packages/body/src/types.ts.

♻️ Proposed fix
 export function matchContentType(
     event: IRoutupEvent,
-    types: string | string[],
+    types: string | string[] | ((event: IRoutupEvent) => boolean),
 ): boolean {
+    if (typeof types === 'function') {
+        return types(event);
+    }
+
     const typeList = Array.isArray(types) ? types : [types];
     return typeList.some((t) => matchRequestContentType(event, t));
 }

Mirror the same union in the JsonOptions, UrlEncodedOptions, TextOptions, and RawOptions type fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/utils/match-content-type.ts` around lines 4 - 10, The
helper matchContentType currently accepts only string | string[] which breaks
dynamic per-request matching; change its signature to accept string | string[] |
((event: IRoutupEvent) => string | string[]) and, inside matchContentType, if
types is a function call it with the event to obtain the runtime type(s) before
normalizing to an array and calling matchRequestContentType; also update the
public option types in JsonOptions, UrlEncodedOptions, TextOptions, and
RawOptions to use the same union so the plugins can pass dynamic matcher
functions.

Comment thread packages/body/src/utils/parse-size.ts
Comment thread packages/cookie/src/request.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (3)
packages/body/src/helpers/read-raw.ts (1)

64-66: ⚠️ Potential issue | 🔴 Critical

Single-chunk fast path can expose bytes outside the logical body.

Returning chunks[0] directly preserves its original backing buffer/view. Downstream uses of .buffer (e.g., array-buffer/blob helpers) may expose bytes beyond the request payload in single-chunk cases. Fix this at the source by forcing a copy here.

🔧 Proposed fix
 function concat(chunks: Uint8Array[], totalSize: number): Uint8Array {
@@
     if (chunks.length === 1) {
-        return chunks[0]!;
+        return new Uint8Array(chunks[0]!);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/read-raw.ts` around lines 64 - 66, The single-chunk
fast path returns chunks[0] directly which can expose its original backing
buffer; change the branch in read-raw where it checks if (chunks.length === 1)
to return a copied view instead (e.g., return chunks[0].slice() or return new
Uint8Array(chunks[0])) so the returned Uint8Array has its own buffer and cannot
expose bytes beyond the logical body.
packages/body/README.md (2)

125-127: ⚠️ Potential issue | 🟡 Minor

raw option scope is still overstated in docs.

Line 125 says raw applies to ArrayBuffer/Blob helpers, but the signatures at Lines 206-220 show those helpers take LimitOptions, not RawOptions.

🛠️ Suggested fix
-Configure options for raw body reading (used by `readRequestBodyBytes`, `readRequestBodyArrayBuffer`, `readRequestBodyBlob`).
+Configure options for raw body reading (used by `readRequestBodyBytes`).

Also applies to: 206-220

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` around lines 125 - 127, The README incorrectly
states that the `raw` option (type RawOptions | boolean) configures the
ArrayBuffer/Blob helpers, but the actual function signatures for
readRequestBodyBytes, readRequestBodyArrayBuffer, and readRequestBodyBlob accept
LimitOptions; update the documentation to accurately reflect the accepted option
type and scope: either change the prose around "Configure options for raw body
reading" to state that `raw` applies only to the raw helpers and that the
ArrayBuffer/Blob helpers accept LimitOptions, or update the function signatures
listed (readRequestBodyBytes, readRequestBodyArrayBuffer, readRequestBodyBlob)
to show RawOptions if that was intended; ensure references to RawOptions and
LimitOptions are consistent and remove the overstated claim that `raw`
configures the ArrayBuffer/Blob helpers.

95-95: ⚠️ Potential issue | 🟡 Minor

useRequestBody return type still narrows JSON array payloads.

Line 95 documents arrays as valid JSON output, but Lines 169-171 type useRequestBody(event) as Promise<Record<string, any>>, which excludes arrays.

🛠️ Suggested fix
 declare function useRequestBody(
     event: IRoutupEvent,
-) : Promise<Record<string, any>>;
+) : Promise<Record<string, any> | unknown[]>;

Also applies to: 169-176

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` at line 95, The docs and type annotation for
useRequestBody are inconsistent: update the documented return to include arrays
and change the type for useRequestBody(event) from Promise<Record<string, any>>
to a type that allows arrays (e.g. Promise<Record<string, any> | any[]>) so JSON
array payloads are accepted; adjust the prose at the earlier table row (the
`strict`/arrays note) and the signature/type examples that reference
useRequestBody to reflect the new union type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/body/README.md`:
- Line 27: The TOC entry for readRequestBodyStream points to the wrong slug
(`#readbodystream`); update the markdown link target to the correct heading slug
(`#readrequestbodystream`) so the [readRequestBodyStream] anchor resolves to the
actual readRequestBodyStream heading; verify any other TOC entries referencing
readRequestBodyStream match the exact heading text.

In `@packages/body/src/helpers/parse-json.ts`:
- Around line 22-23: The function's public return type (currently
Promise<Record<string, any> | undefined>) is wrong when options.strict === false
because primitives are allowed; update the parse JSON helper's signature to
return a broader type (e.g., Promise<any> | undefined or Promise<unknown> |
undefined) and adjust any internal type assertions accordingly so
matchContentType(...) and the strict branch still validate objects but
non-strict can return primitives; apply the same type change to the related
overloads/usages around the other block (lines referenced 45-53) to keep the
public API consistent.

In `@packages/body/src/helpers/read-raw.ts`:
- Line 27: The current truthy check lets parsed limits of 0 or NaN bypass
enforcement; change the assignment so you explicitly check for presence
(options.limit !== undefined && options.limit !== null), call
parseSize(options.limit) into a temporary (e.g., parsedLimit), then validate
with Number.isFinite(parsedLimit) and accept 0 as a valid limit; if parsedLimit
is not finite (NaN/Infinity) throw a clear error (or handle explicitly) instead
of treating it as undefined; apply the same change where limit is set elsewhere
(the other occurrence using parseSize).

In `@packages/body/src/helpers/read-stream.ts`:
- Line 10: The doc comment contains a typo "no body.shoui"; edit the comment in
packages/body/src/helpers/read-stream.ts to replace the incorrect substring "no
body.shoui" with the correct phrase "no body." (i.e., make the sentence read
"Returns `null` if there is no body.") so the documentation is clear and
accurate.

---

Duplicate comments:
In `@packages/body/README.md`:
- Around line 125-127: The README incorrectly states that the `raw` option (type
RawOptions | boolean) configures the ArrayBuffer/Blob helpers, but the actual
function signatures for readRequestBodyBytes, readRequestBodyArrayBuffer, and
readRequestBodyBlob accept LimitOptions; update the documentation to accurately
reflect the accepted option type and scope: either change the prose around
"Configure options for raw body reading" to state that `raw` applies only to the
raw helpers and that the ArrayBuffer/Blob helpers accept LimitOptions, or update
the function signatures listed (readRequestBodyBytes,
readRequestBodyArrayBuffer, readRequestBodyBlob) to show RawOptions if that was
intended; ensure references to RawOptions and LimitOptions are consistent and
remove the overstated claim that `raw` configures the ArrayBuffer/Blob helpers.
- Line 95: The docs and type annotation for useRequestBody are inconsistent:
update the documented return to include arrays and change the type for
useRequestBody(event) from Promise<Record<string, any>> to a type that allows
arrays (e.g. Promise<Record<string, any> | any[]>) so JSON array payloads are
accepted; adjust the prose at the earlier table row (the `strict`/arrays note)
and the signature/type examples that reference useRequestBody to reflect the new
union type.

In `@packages/body/src/helpers/read-raw.ts`:
- Around line 64-66: The single-chunk fast path returns chunks[0] directly which
can expose its original backing buffer; change the branch in read-raw where it
checks if (chunks.length === 1) to return a copied view instead (e.g., return
chunks[0].slice() or return new Uint8Array(chunks[0])) so the returned
Uint8Array has its own buffer and cannot expose bytes beyond the logical body.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 328f1ab7-79ca-4cdd-b622-463653d815fd

📥 Commits

Reviewing files that changed from the base of the PR and between edc1a6c and 7fa0774.

📒 Files selected for processing (13)
  • packages/body/README.md
  • packages/body/src/helpers/index.ts
  • packages/body/src/helpers/parse-json.ts
  • packages/body/src/helpers/parse-url-encoded.ts
  • packages/body/src/helpers/read-array-buffer.ts
  • packages/body/src/helpers/read-blob.ts
  • packages/body/src/helpers/read-bytes.ts
  • packages/body/src/helpers/read-raw.ts
  • packages/body/src/helpers/read-stream.ts
  • packages/body/src/helpers/read-text.ts
  • packages/body/src/helpers/use-body.ts
  • packages/body/src/index.ts
  • packages/body/src/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/body/src/utils/index.ts
  • packages/body/src/helpers/index.ts
  • packages/body/src/index.ts

Comment thread packages/body/README.md Outdated
Comment on lines +22 to +23
): Promise<Record<string, any> | undefined> {
if (!matchContentType(event, options.type ?? 'application/json')) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Return type is incorrect when strict mode is disabled.

With options.strict === false, primitives are valid outputs, but the function type forces Record<string, any>. This is a public API type mismatch.

🔧 Proposed fix
 export async function parseJsonBody(
     event: IRoutupEvent,
     options: JsonOptions,
-): Promise<Record<string, any> | undefined> {
+): Promise<unknown | undefined> {
@@
-    return parsed as Record<string, any>;
+    return parsed;
 }

Also applies to: 45-53

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/parse-json.ts` around lines 22 - 23, The function's
public return type (currently Promise<Record<string, any> | undefined>) is wrong
when options.strict === false because primitives are allowed; update the parse
JSON helper's signature to return a broader type (e.g., Promise<any> | undefined
or Promise<unknown> | undefined) and adjust any internal type assertions
accordingly so matchContentType(...) and the strict branch still validate
objects but non-strict can return primitives; apply the same type change to the
related overloads/usages around the other block (lines referenced 45-53) to keep
the public API consistent.

Comment thread packages/body/src/helpers/read-raw.ts Outdated
Comment thread packages/body/src/helpers/read-stream.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/body/README.md (2)

125-127: ⚠️ Potential issue | 🟡 Minor

Clarify raw option scope to match helper APIs.

The docs still state raw is used by readRequestBodyBytes, readRequestBodyArrayBuffer, and readRequestBodyBlob, which does not match the helper option signatures shown below (ArrayBuffer/Blob use BaseOptions).

📝 Suggested doc tweak
-Configure options for raw body reading (used by `readRequestBodyBytes`, `readRequestBodyArrayBuffer`, `readRequestBodyBlob`).
+Configure options for raw body reading (used by `readRequestBodyBytes`).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` around lines 125 - 127, Update the README
description to correctly state which helper APIs accept the `raw` option and
which do not: clarify that `readRequestBodyBytes` accepts `RawOptions | boolean`
(uses the `raw` option), while `readRequestBodyArrayBuffer` and
`readRequestBodyBlob` accept `BaseOptions` (do not use `raw`), and adjust the
bullet/type line accordingly; reference the helper names `readRequestBodyBytes`,
`readRequestBodyArrayBuffer`, `readRequestBodyBlob` and the option types
`RawOptions` and `BaseOptions` so the docs match the actual function signatures.

169-176: ⚠️ Potential issue | 🟡 Minor

Widen documented readRequestBody return type.

At Line 171, Promise<Record<string, any>> is too narrow for JSON bodies (arrays are valid too).

📝 Suggested doc tweak
 declare function readRequestBody(
     event: IRoutupEvent,
-) : Promise<Record<string, any>>;
+) : Promise<Record<string, any> | unknown[]>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/README.md` around lines 169 - 176, The documented return type
for readRequestBody is too narrow (Promise<Record<string, any>>) and excludes
valid JSON array bodies; update the first overload of readRequestBody to a wider
type such as Promise<any> or Promise<unknown> so it can represent objects,
arrays, primitives, etc., while leaving the keyed overload
(readRequestBody(event, key): Promise<any | undefined>) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/body/src/helpers/read-raw.ts`:
- Around line 26-31: The cached-return path in read-raw.ts returns
event.store[RawBodySymbol] before applying the configured size limit, letting
callers bypass options.limit; compute the limit (using parseSize(options.limit))
before checking the cache and, when returning the cached Uint8Array from
event.store[RawBodySymbol], validate its byte length against the computed limit
(throw or reject on overflow) so cached reads are subject to the same
enforcement as fresh reads via readRequestBodyStream.

---

Duplicate comments:
In `@packages/body/README.md`:
- Around line 125-127: Update the README description to correctly state which
helper APIs accept the `raw` option and which do not: clarify that
`readRequestBodyBytes` accepts `RawOptions | boolean` (uses the `raw` option),
while `readRequestBodyArrayBuffer` and `readRequestBodyBlob` accept
`BaseOptions` (do not use `raw`), and adjust the bullet/type line accordingly;
reference the helper names `readRequestBodyBytes`, `readRequestBodyArrayBuffer`,
`readRequestBodyBlob` and the option types `RawOptions` and `BaseOptions` so the
docs match the actual function signatures.
- Around line 169-176: The documented return type for readRequestBody is too
narrow (Promise<Record<string, any>>) and excludes valid JSON array bodies;
update the first overload of readRequestBody to a wider type such as
Promise<any> or Promise<unknown> so it can represent objects, arrays,
primitives, etc., while leaving the keyed overload (readRequestBody(event, key):
Promise<any | undefined>) as-is.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b151e851-5eca-49f4-b8c1-90b26f728a53

📥 Commits

Reviewing files that changed from the base of the PR and between 81408fd and 2583498.

📒 Files selected for processing (11)
  • packages/body/README.md
  • packages/body/src/helpers/parse-url-encoded.ts
  • packages/body/src/helpers/read-bytes.ts
  • packages/body/src/helpers/read-raw.ts
  • packages/body/src/helpers/read-stream.ts
  • packages/body/src/helpers/read-text.ts
  • packages/body/src/module.ts
  • packages/body/src/types.ts
  • packages/body/src/utils/parse-size.ts
  • packages/body/test/unit/module.spec.ts
  • packages/cookie/src/request.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/body/src/helpers/read-bytes.ts
  • packages/body/test/unit/module.spec.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/body/src/utils/parse-size.ts
  • packages/body/src/helpers/read-text.ts
  • packages/body/src/helpers/read-stream.ts
  • packages/body/src/helpers/parse-url-encoded.ts
  • packages/body/src/module.ts
  • packages/body/src/types.ts

Comment on lines +26 to +31
if (options.cache && RawBodySymbol in event.store) {
return event.store[RawBodySymbol] as Uint8Array;
}

const limit = options.limit !== undefined ? parseSize(options.limit) : undefined;
const stream = readRequestBodyStream(event, options);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Enforce limit on cached reads too.

At Line 26, cached data returns before Line 30 computes/applies limit, so a stricter later call can bypass size enforcement.

🔧 Suggested fix
 export async function readRequestBodyRaw(
     event: IRoutupEvent,
     options: BaseOptions = {},
 ): Promise<Uint8Array> {
+    const limit = options.limit !== undefined ? parseSize(options.limit) : undefined;
+
     if (options.cache && RawBodySymbol in event.store) {
-        return event.store[RawBodySymbol] as Uint8Array;
+        const cached = event.store[RawBodySymbol] as Uint8Array;
+        if (limit !== undefined && cached.length > limit) {
+            throw createError({
+                statusCode: 413,
+                statusMessage: 'request entity too large',
+            });
+        }
+        return cached;
     }
 
-    const limit = options.limit !== undefined ? parseSize(options.limit) : undefined;
     const stream = readRequestBodyStream(event, options);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (options.cache && RawBodySymbol in event.store) {
return event.store[RawBodySymbol] as Uint8Array;
}
const limit = options.limit !== undefined ? parseSize(options.limit) : undefined;
const stream = readRequestBodyStream(event, options);
const limit = options.limit !== undefined ? parseSize(options.limit) : undefined;
if (options.cache && RawBodySymbol in event.store) {
const cached = event.store[RawBodySymbol] as Uint8Array;
if (limit !== undefined && cached.length > limit) {
throw createError({
statusCode: 413,
statusMessage: 'request entity too large',
});
}
return cached;
}
const stream = readRequestBodyStream(event, options);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/body/src/helpers/read-raw.ts` around lines 26 - 31, The
cached-return path in read-raw.ts returns event.store[RawBodySymbol] before
applying the configured size limit, letting callers bypass options.limit;
compute the limit (using parseSize(options.limit)) before checking the cache
and, when returning the cached Uint8Array from event.store[RawBodySymbol],
validate its byte length against the computed limit (throw or reject on
overflow) so cached reads are subject to the same enforcement as fresh reads via
readRequestBodyStream.

@tada5hi
Copy link
Copy Markdown
Contributor Author

tada5hi commented Apr 8, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

feat: update @routup/body for routup v5

1 participant