feat(router): support Valibot schema validation#43
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR extends the router framework to support Valibot as an alternative schema validation library alongside Zod. A unified validator abstraction layer ( ChangesAdd Valibot Schema Support
🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/types.ts (1)
291-292:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
HasSchemasignores Valibot schemas, breakingClienttype inference for Valibot-based endpoints.type HasSchemas<C> = C extends EndpointConfig<any, infer Schemas> ? (Schemas[keyof Schemas] extends ZodObject<any> ? true : false) : falseWhen
body,searchParams, orparamsis a ValibotObjectSchema,HasSchemasreturnsfalse, so theClienttype falls back to the untyped(path, ctx?) => ...signature and loses the schema-derived request shape. The fix is to also recognize Valibot schemas:-type HasSchemas<C> = - C extends EndpointConfig<any, infer Schemas> ? (Schemas[keyof Schemas] extends ZodObject<any> ? true : false) : false +type HasSchemas<C> = + C extends EndpointConfig<any, infer Schemas> + ? Schemas[keyof Schemas] extends ZodObject<any> | ObjectSchema<any, undefined> + ? true + : false + : false🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/types.ts` around lines 291 - 292, The HasSchemas conditional only checks for ZodObject instances and therefore returns false for Valibot schemas, breaking Client inference; update HasSchemas (the conditional on EndpointConfig and Schemas) to also accept Valibot's ObjectSchema type (e.g., check Schemas[keyof Schemas] extends ZodObject<any> | ObjectSchema<any>) so Valibot-based body/searchParams/params produce true and restore the typed Client signature; ensure you import the Valibot ObjectSchema type and use that union in the conditional where HasSchemas is defined.src/context.ts (1)
45-55:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
formatZodErroris called with ValibotIssue[], producing emptydetails: {}for all Valibot validation failures.When Valibot validation fails,
registry.tssetserror: result.issues— avalibot.Issue[].formatZodErrorreceives that array, checkserror.issues(which isundefinedon an array), immediately returns{}, and every Valibot error response has emptydetails. This is a silent loss of validation detail for Valibot users.The same problem exists in
getSearchParams(Line 97) andgetBody(Line 128).A minimal fix is a dedicated Valibot formatter:
+import type { BaseIssue } from "valibot" + +export const formatValibotError = (issues: BaseIssue<unknown>[]) => { + if (!issues || issues.length === 0) return {} + return issues.reduce((prev, issue) => { + const key = issue.path?.map((p) => p.key).join(".") ?? "" + return { ...prev, [key]: { kind: issue.kind, message: issue.message } } + }, {}) +}Then in each call site, branch on the schema type:
- throw new InvalidZodSchemaError("UNPROCESSABLE_ENTITY", formatZodError(parsed.error)) + throw new InvalidZodSchemaError( + "UNPROCESSABLE_ENTITY", + Array.isArray(parsed.error) ? formatValibotError(parsed.error) : formatZodError(parsed.error) + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/context.ts` around lines 45 - 55, getRouteParams/getSearchParams/getBody call formatZodError with a Valibot Issue[] (set in registry.ts) which makes formatZodError return empty details; add a Valibot-specific formatter (e.g., formatValibotError) that converts valibot.Issue[] into the same details shape expected by InvalidZodSchemaError, then change the error handling in getRouteParams, getSearchParams and getBody to detect the validator/schema type produced by createValidator and branch: when the validation result is a Valibot result call formatValibotError(result.issues) and when it's a Zod result call formatZodError(result.error), and throw InvalidZodSchemaError using the properly formatted details so Valibot failures are surfaced correctly.package.json (1)
85-95:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
valibot(andzod) should be optionalpeerDependencies, notdevDependencies.Both are used in published source files (
src/validator/registry.ts,src/types.ts,src/assert.ts). Withtsup, packages indevDependenciesare bundled into the output, forcing a fixed version on all consumers and preventing them from tree-shaking or supplying their own version. Since support for each library is optional and detected at runtime, both should be declared as optional peer dependencies:+ "peerDependencies": { + "zod": "^4.1.11", + "valibot": "^1.4.0" + }, + "peerDependenciesMeta": { + "zod": { "optional": true }, + "valibot": { "optional": true } + }, "devDependencies": { ... - "zod": "^4.1.11", - "valibot": "^1.4.0" + "zod": "^4.1.11", + "valibot": "^1.4.0" }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@package.json` around lines 85 - 95, Move zod and valibot out of devDependencies and declare them as optional peerDependencies so consumers can provide their own versions and tree-shake properly: remove "zod" and "valibot" from devDependencies in package.json, add them under "peerDependencies" with appropriate semver ranges, and mark them optional via "peerDependenciesMeta" (set each to { "optional": true }). Ensure any runtime detection code in src/validator/registry.ts, src/types.ts, and src/assert.ts continues to handle absence of these libs gracefully (no hard imports), and update packaging/config (tsup) if necessary so these libs are not bundled into the distributed build.
🧹 Nitpick comments (1)
src/assert.ts (1)
3-4: 💤 Low value
BaseSchemashould use a type-only import.
BaseSchemais a TypeScript interface in valibot with no runtime value; importing it as a value forces a side-effectful module evaluation at startup.-import { BaseSchema } from "valibot" -import { ZodObject } from "zod" +import type { BaseSchema } from "valibot" +import type { ZodObject } from "zod"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/assert.ts` around lines 3 - 4, The import of BaseSchema should be type-only to avoid forcing runtime evaluation; update the import in src/assert.ts to use a type import for BaseSchema (e.g., "import type { BaseSchema } from 'valibot'") while leaving ZodObject as a regular import so any runtime value remains available; ensure all usages of BaseSchema in functions/types continue to compile as a type-only import.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/assert.ts`:
- Around line 90-92: isZodSchema currently only checks for "_def" which breaks
for Zod v4; update the predicate in isZodSchema to detect both Zod v3 and v4
internals (e.g., return true if value is a non-null object and contains "_zod"
or "_def", or specifically checks for value["_zod"]?.def) so ZodObject schemas
are recognized across versions and validation in registry.ts works again.
In `@src/validator/registry.ts`:
- Around line 29-32: The thrown "Unsupported schema type" should not be
swallowed and converted into a validation failure: update the code in
registry.ts so the unsupported-schema check either occurs before the try block
or rethrows the error instead of returning { success:false,... } inside the
catch; specifically, ensure the branch that detects an unsupported schema type
(the throw new Error("Unsupported schema type")) is moved out of the try/catch
or that the catch rethrows when e.message === "Unsupported schema type" (or when
the error is not a validation parse result), so callers in context.ts receive an
actual thrown error rather than a 422 result; keep the existing switch to using
result.success for the Valibot SafeParseResult handling.
In `@test/type.test-d.ts`:
- Around line 78-87: Remove or use the dead type alias `Nose`: either delete the
`type Nose = RequestContext<...>` declaration if it's not needed, or replace its
usage where appropriate (e.g., annotate a test helper or parameter with `Nose`)
so the `Nose` alias is referenced; locate the `Nose` declaration and update code
that uses `RequestContext`/`ZodObject`/`ZodString` types to consume this alias
if intended to be kept.
---
Outside diff comments:
In `@package.json`:
- Around line 85-95: Move zod and valibot out of devDependencies and declare
them as optional peerDependencies so consumers can provide their own versions
and tree-shake properly: remove "zod" and "valibot" from devDependencies in
package.json, add them under "peerDependencies" with appropriate semver ranges,
and mark them optional via "peerDependenciesMeta" (set each to { "optional":
true }). Ensure any runtime detection code in src/validator/registry.ts,
src/types.ts, and src/assert.ts continues to handle absence of these libs
gracefully (no hard imports), and update packaging/config (tsup) if necessary so
these libs are not bundled into the distributed build.
In `@src/context.ts`:
- Around line 45-55: getRouteParams/getSearchParams/getBody call formatZodError
with a Valibot Issue[] (set in registry.ts) which makes formatZodError return
empty details; add a Valibot-specific formatter (e.g., formatValibotError) that
converts valibot.Issue[] into the same details shape expected by
InvalidZodSchemaError, then change the error handling in getRouteParams,
getSearchParams and getBody to detect the validator/schema type produced by
createValidator and branch: when the validation result is a Valibot result call
formatValibotError(result.issues) and when it's a Zod result call
formatZodError(result.error), and throw InvalidZodSchemaError using the properly
formatted details so Valibot failures are surfaced correctly.
In `@src/types.ts`:
- Around line 291-292: The HasSchemas conditional only checks for ZodObject
instances and therefore returns false for Valibot schemas, breaking Client
inference; update HasSchemas (the conditional on EndpointConfig and Schemas) to
also accept Valibot's ObjectSchema type (e.g., check Schemas[keyof Schemas]
extends ZodObject<any> | ObjectSchema<any>) so Valibot-based
body/searchParams/params produce true and restore the typed Client signature;
ensure you import the Valibot ObjectSchema type and use that union in the
conditional where HasSchemas is defined.
---
Nitpick comments:
In `@src/assert.ts`:
- Around line 3-4: The import of BaseSchema should be type-only to avoid forcing
runtime evaluation; update the import in src/assert.ts to use a type import for
BaseSchema (e.g., "import type { BaseSchema } from 'valibot'") while leaving
ZodObject as a regular import so any runtime value remains available; ensure all
usages of BaseSchema in functions/types continue to compile as a type-only
import.
🪄 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: 34cd61c6-b17d-47d5-be1e-0fd5e005bc77
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
package.jsonsrc/assert.tssrc/context.tssrc/types.tssrc/validator/registry.tstest/endpoint.test.tstest/type.test-d.ts
| @@ -1,5 +1,6 @@ | |||
| import { describe, test, expect, vi, beforeEach, expectTypeOf } from "vitest" | |||
| import { z } from "zod" | |||
| import { never, z } from "zod" | |||
Description
Adds support for Valibot schema validation alongside the existing Zod integration for route validation.
Validation schemas can now be defined using Valibot for:
This change was introduced as part of the work in aura-stack-ts/auth#160 and expands compatibility with additional schema validation libraries such as Valibot, ArkType, and future adapters.
Key Changes
Usage