@orveth/validation
Discriminated validation results and a Validator interface that adapters can implement without pulling in a specific schema library. Orveth standardizes the outcome shape; your team chooses the backing implementation.
Result types
| Type | Shape |
|---|---|
ValidationSuccess<T> | { ok: true, value: T } |
ValidationFailure | { ok: false, issues: ValidationIssue[] } |
ValidationResult<T> | Union of success and failure variants. |
ValidationIssue
path— dotted location (for exampleuser.email).message— human-readable explanation.code?— optional stable machine identifier for the issue.
Validator<TInput, TOutput>
Implementations expose validate(input: TInput): ValidationResult<TOutput>. The method must be pure with respect to Orveth: no global mutation, no implicit I/O unless your adapter documents it.
Factory helpers
validationSuccess(value) and validationFailure(issues) keep discriminant fields consistent and reduce boilerplate inside adapters.
Example adapter
import { validationFailure, validationSuccess } from "@orveth/validation";
import type { Validator } from "@orveth/validation";
export const positiveInteger: Validator<string, number> = {
validate(input) {
const trimmed = input.trim();
if (trimmed.length === 0) {
return validationFailure([
{ path: "input", message: "Value is required", code: "REQUIRED" },
]);
}
const parsed = Number.parseInt(trimmed, 10);
if (!Number.isFinite(parsed) || parsed <= 0) {
return validationFailure([
{ path: "input", message: "Must be a positive integer", code: "FORMAT" },
]);
}
return validationSuccess(parsed);
},
};Consuming results
import type { ValidationResult } from "@orveth/validation";
import { HttpError } from "@orveth/errors";
export function ensureSuccess<T>(result: ValidationResult<T>): T {
if (result.ok) {
return result.value;
}
throw new HttpError(422, "ORVETH_VALIDATION_FAILED", "Invalid input", {
details: { issues: result.issues },
});
}