Conversation
📝 WalkthroughWalkthroughThe Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (8)
packages/body/src/utils/bool-to-object.ts (1)
1-7: Clarify behavior forfalseinput.The function treats both
trueandfalseboolean values the same way, returning{} as T. Iffalseis intended to disable a feature (e.g.,raw: falseto disable raw body parsing), this would incorrectly convert it to an enabled empty options object.Verify this is the intended behavior. If
falseshould signal "disabled," callers must handle that case before invokingboolToObject.🤖 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-providedoptionsobject.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 passingUint8Arraydirectly toBlobto avoid exposing unintended buffer ranges.When
rawis a Uint8Array view with a non-zerobyteOffset(as can happen whenreadRawBodyreturns a cached or sliced view), usingraw.bufferexposes the entire backing buffer, not just the intended range. Passingrawdirectly 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
TextDecoderdefaults to UTF-8, but theContent-Typeheader 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 allowsArray.isArray(parsed)). Consider updating the type toPromise<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/jsoncontent-type but an empty body, the function returns{}rather thanundefinedor throwing. This could mask client bugs where an empty body is sent unintentionally. Consider whether returningundefined(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
useRequestBodyreturns{}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
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (40)
packages/assets/package.jsonpackages/body/README.mdpackages/body/package.jsonpackages/body/src/handler.tspackages/body/src/helpers/array-buffer.tspackages/body/src/helpers/blob.tspackages/body/src/helpers/body.tspackages/body/src/helpers/bytes.tspackages/body/src/helpers/index.tspackages/body/src/helpers/json.tspackages/body/src/helpers/options.tspackages/body/src/helpers/text.tspackages/body/src/helpers/url-encoded.tspackages/body/src/index.tspackages/body/src/module.tspackages/body/src/parser/index.tspackages/body/src/parser/json.tspackages/body/src/parser/raw.tspackages/body/src/parser/text.tspackages/body/src/parser/url-encoded.tspackages/body/src/request.tspackages/body/src/types.tspackages/body/src/utils.tspackages/body/src/utils/bool-to-object.tspackages/body/src/utils/decompress.tspackages/body/src/utils/index.tspackages/body/src/utils/is-object.tspackages/body/src/utils/match-content-type.tspackages/body/src/utils/parse-size.tspackages/body/src/utils/read-raw-body.tspackages/body/test/unit/module.spec.tspackages/cookie/README.mdpackages/cookie/package.jsonpackages/cookie/src/handler.tspackages/cookie/src/request.tspackages/cookie/src/response.tspackages/cookie/src/utils.tspackages/cookie/test/unit/module.spec.tspackages/swagger/README.mdpackages/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
| declare function useRequestBody( | ||
| event: IRoutupEvent, | ||
| ) : Promise<Record<string, any>>; | ||
|
|
||
| declare function useRequestBody( | ||
| event: IRoutupEvent, | ||
| key: string, | ||
| value: unknown | ||
| ) : void; | ||
| ) : Promise<any | undefined>; | ||
| ``` |
There was a problem hiding this comment.
🧩 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/nullRepository: 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.tsRepository: 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.
| 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>; |
There was a problem hiding this comment.
🧩 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/srcRepository: routup/plugins
Length of output: 4013
🏁 Script executed:
sed -n '1,226p' packages/body/README.md | head -150Repository: 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).
| export { | ||
| useRequestBody, | ||
| readRequestBodyArrayBuffer, | ||
| readRequestBodyBlob, | ||
| readRequestBodyBytes, | ||
| readRequestBodyText, | ||
| } from './helpers'; |
There was a problem hiding this comment.
🧩 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/srcRepository: 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.tsRepository: 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.tsRepository: 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.
| export function matchContentType( | ||
| event: IRoutupEvent, | ||
| types: string | string[], | ||
| ): boolean { | ||
| const typeList = Array.isArray(types) ? types : [types]; | ||
| return typeList.some((t) => matchRequestContentType(event, t)); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (3)
packages/body/src/helpers/read-raw.ts (1)
64-66:⚠️ Potential issue | 🔴 CriticalSingle-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
rawoption scope is still overstated in docs.Line 125 says
rawapplies to ArrayBuffer/Blob helpers, but the signatures at Lines 206-220 show those helpers takeLimitOptions, notRawOptions.🛠️ 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
useRequestBodyreturn type still narrows JSON array payloads.Line 95 documents arrays as valid JSON output, but Lines 169-171 type
useRequestBody(event)asPromise<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
📒 Files selected for processing (13)
packages/body/README.mdpackages/body/src/helpers/index.tspackages/body/src/helpers/parse-json.tspackages/body/src/helpers/parse-url-encoded.tspackages/body/src/helpers/read-array-buffer.tspackages/body/src/helpers/read-blob.tspackages/body/src/helpers/read-bytes.tspackages/body/src/helpers/read-raw.tspackages/body/src/helpers/read-stream.tspackages/body/src/helpers/read-text.tspackages/body/src/helpers/use-body.tspackages/body/src/index.tspackages/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
| ): Promise<Record<string, any> | undefined> { | ||
| if (!matchContentType(event, options.type ?? 'application/json')) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/body/README.md (2)
125-127:⚠️ Potential issue | 🟡 MinorClarify
rawoption scope to match helper APIs.The docs still state
rawis used byreadRequestBodyBytes,readRequestBodyArrayBuffer, andreadRequestBodyBlob, which does not match the helper option signatures shown below (ArrayBuffer/Blob useBaseOptions).📝 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 | 🟡 MinorWiden documented
readRequestBodyreturn 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
📒 Files selected for processing (11)
packages/body/README.mdpackages/body/src/helpers/parse-url-encoded.tspackages/body/src/helpers/read-bytes.tspackages/body/src/helpers/read-raw.tspackages/body/src/helpers/read-stream.tspackages/body/src/helpers/read-text.tspackages/body/src/module.tspackages/body/src/types.tspackages/body/src/utils/parse-size.tspackages/body/test/unit/module.spec.tspackages/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
| 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); |
There was a problem hiding this comment.
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.
| 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.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
closes #743
Summary by CodeRabbit
Release Notes
New Features
readRequestBody(),readRequestBodyText(),readRequestBodyBytes(),readRequestBodyArrayBuffer(),readRequestBodyBlob(), andreadRequestBodyStream()for flexible request payload handling.JsonOptions,UrlEncodedOptions,TextOptions, andRawOptionswith enhanced customization.Bug Fixes
Breaking Changes
useRequestBody()andsetRequestBody()with asyncreadRequestBody(event)API.body-parserdependency; integrated custom parsing.router.install(body())torouter.use(body()).Chores