Cross-field validation
Run cross-field business checks after individual fields have been structurally validated. The public HTTP schema custom predicate receives a field value; do not assume it receives the whole request or performs async work.
import assert from 'node:assert/strict';
import { unprocessableEntity } from '@tagna/udiot/server';
function validateRange(start: number, end: number): void {
if (end < start) {
throw unprocessableEntity('End must be greater than or equal to start');
}
}
validateRange(1, 2);
assert.throws(() => validateRange(2, 1));
This is application-owned validation, not an implicit DTO hook. Perform it before persistence or other side effects. Database invariants still belong in transactions/constraints where applicable.
The legacy CrossFieldValidationEngine root export is type-only; internal
AIDto decorators are not public. See validation ordering.
From the canonical UDIOT public documentation.Try it in the playground ↗