@zudojs/validation
v1.2.0
Published
Schema validation with Zod integration, constraints, parsers, composers, circular detection, and depth/size checks.
Readme
@zudojs/validation
Schema validation with Zod integration, constraints, parsers, composers, circular detection, and depth/size checks.
Documentation: zudojs.oyinlola.site/docs/packages-validation · For AI agents: Markdown version, llms.txt
Installation
npm install @zudojs/validationQuick Start
import { validate, z } from "@zudojs/validation";
const schema = z.object({
email: z.string().email(),
age: z.number().int().positive(),
});
const result = validate(schema, input);
if (!result.success) {
console.error(result.issues);
}Structural guards for untrusted payloads:
import {
assertDepthWithinLimit,
assertSizeWithinLimit,
assertNoCircularReference,
} from "@zudojs/validation";
// Each aborts as soon as its bound is passed, so the cost is bounded by the
// limit rather than by the size of the input.
assertDepthWithinLimit(body, 32);
assertSizeWithinLimit(body, 1_000_000);
assertNoCircularReference(body);A too-deep payload throws SerializationDepthError with statusCode 400
and expose: true from both assertDepthWithinLimit and
assertNoCircularReference: untrusted input that nests too far is a client
error, and the message names only the observed depth and the limit
(Maximum serialization depth exceeded: 40 > 32), never the payload.
Constructed directly, SerializationDepthError still defaults to an
unexposed 500, which is right for data your own server built.
Safety Notes
- Constraint failures do not carry the rejected value.
ValidationErroris exposed with a 400, so echoing it would return rejected passwords and tokens to the caller and write them to any log that serializes the error. parseRecordandtoFieldErrorsbuild on null-prototype objects, so a__proto__key cannot hijack a validated result.matches()stripsgandyfrom the pattern, which otherwise maketest()stateful and flip the answer on alternate calls.- Constraints carry an optional type guard, so wrong-typed input at a trust
boundary reports as a validation failure rather than a
TypeError. - The size guard counts a shared subtree once per occurrence, the way a
serializer expands it, and measures what
toJSON()returns when a value has one. The cycle and depth guards walk a shared subtree once, so a small graph of shared nodes cannot cost exponential time. All guards walk iteratively, so deeply nested input cannot exhaust the stack inside the check, and handle sparse arrays (a hole counts asundefined). ValidationErrorandValidationResultErrorextend@zudojs/errors'ValidationError, soinstanceofandisValidationError()from either package catch them. TheirtoJSON()keeps the base class's redaction: submitted issue values and sensitivecontextkeys never reach the JSON.not(constraint)fails closed: a wrong-typed value, or one that makes the inner constraint throw, fails.everyItem/someItemread every index, holes included.- A registry rule that declares both
schemaandconstraintsruns the schema, then the constraints on the parsed value.
Features
- Zod schema integration
- Constraint validation
- Composable validators
- Circular reference detection
- Depth and size limits
- Async validation support
Use Cases
- Form validation
- API input validation
- Configuration validation
- Data contract enforcement
