Skip to content

Overview

@xndrjs/domain is the runtime modeling core of xndrjs.

It provides:

  • a validator contract: Validator<Input, Output>
  • modeling kits: domain.primitive, domain.shape, domain.proof
  • behavior attachment: domain.capabilities
  • lightweight validator composition: compose.array, compose.object, compose.optional
  • typed function composition: pipe

Its job is not to be a schema engine. Its job is to turn validation into a stable domain boundary that the rest of your application can trust.

structure describes shape
semantics describes meaning

xndrjs separates:

  • structural validation
  • representation identity
  • semantic guarantees
  • allowed operations
ConceptWhat it answers
ValidatorDoes this unknown input match the expected structure?
PrimitiveIs this scalar value meaningful in my domain?
ShapeIs this object now a trusted representation?
CapabilityWhat transitions are allowed, and are they re-validated?
ProofHas this value earned an additional guarantee?

These concepts are orthogonal and composable.

data does not change, it evolves

Domain values are readonly and replaced, not mutated. Capability methods produce new validated values:

const updated = User.rename(user, "New name");

This removes a class of bugs related to implicit state changes and works naturally with UI frameworks, caching layers, and tests that rely on predictable references.

input is untrusted until a kit creates or proves it

The main trust-boundary operations are:

  • create(input): validate and throw on failure
  • safeCreate(input): validate and return a result union
  • assert(input): validate or prove and throw on failure
  • test(input): check a proof without throwing

After a value leaves the process or becomes JSON, it should re-enter through a boundary again.

NeedUse
Validate an email, id, slug, or currency codedomain.primitive
Materialize a trusted object from external inputdomain.shape
Express an operation such as rename, verify, cancel, approvedomain.capabilities
Require a stronger guarantee for a specific workflowdomain.proof
Build small validators without an adaptercompose
Chain transformations or assertionspipe
import { DomainValidationError, compose, domain, pipe } from "@xndrjs/domain";

Adapter packages re-export this surface for convenience:

import { domain, zodToValidator } from "@xndrjs/domain-zod";