doba

Registry

The core schema and migration container

The Registry is the central piece of doba. It holds your schemas and migration functions, and provides methods to transform data between them.

createRegistry

Creates a new registry instance. The migration graph is pre-computed at construction time.

import { createRegistry } from 'dobajs'
import { z } from 'zod'

const registry = createRegistry({
  schemas: {
    v1: z.object({ name: z.string() }),
    v2: z.object({ firstName: z.string(), lastName: z.string() }),
  },
  migrations: {
    'v1->v2': (v1) => ({
      firstName: v1.name.split(' ')[0],
      lastName: v1.name.split(' ')[1] || '',
    }),
  },
})

RegistryConfig

OptionTypeDescription
schemasSchemaMapMap of schema names to Standard Schema compliant objects.
migrationsMigrationsFor<Schemas>Migration definitions. Keys use from->to or from<->to syntax.
pathStrategy'shortest' | 'direct'How to find migration paths. Default: 'shortest'.
hooksRegistryHooksLifecycle hooks.
debugbooleanLogs all hook activity to the console. Default: false.

RegistryHooks

type RegistryHooks = {
  onWarning?: (message: string, from: string, to: string) => void
  onTransform?: (info: TransformHookInfo) => void
  onStep?: (info: StepHookInfo) => void
}
HookWhen it fires
onWarningctx.warn(), ctx.defaulted(), deprecated migration usage, migration conflicts
onTransformAfter every transform completes (success or failure). Includes timing and path info.
onStepAfter each migration step completes. Includes step index, label, and timing.

See Debugging for usage examples and type definitions.

Properties

schemas

The registered schemas, exactly as passed to createRegistry.

registry.schemas // { v1: ZodObject<...>, v2: ZodObject<...> }

Methods

transform()

Transforms data from one schema to another.

const result = await registry.transform(data, 'v1', 'v2', options?)

Returns a TransformResult, a discriminated union of success (with value and metadata) or failure (with issues).

TransformOptions

OptionTypeDefaultDescription
validate'none' | 'end' | 'each''end'When to validate against schemas.
pathstring[](auto)Explicit migration path. Overrides automatic path finding.
pathStrategy'shortest' | 'direct'(registry)Override the registry-level path strategy for this transform.
validatePathbooleanfalseCheck that every step has a migration before executing.

TransformMeta

On success, result.meta contains:

type TransformMeta = {
  path: string[] // schema keys traversed
  steps: StepInfo[] // per-step metadata
  warnings: WarningInfo[] // warnings from ctx.warn() and deprecated migrations
  defaults: DefaultedInfo[] // fields filled via ctx.defaulted()
}

type StepInfo = {
  from: string
  to: string
  label?: string // from migration metadata
  deprecated?: string | boolean
}

validate()

Validates a value against a registered schema without transforming.

const result = await registry.validate(data, 'v2')

Returns a ValidateResult with meta.schema set to the schema key.

has()

Type guard to check if a schema name is registered.

if (registry.has(name)) {
  // name is narrowed to a valid schema key
}

hasMigration()

Checks if a direct migration exists between two schemas. Does not consider multi-step paths.

registry.hasMigration('v1', 'v2') // true
registry.hasMigration('v2', 'v1') // false (unless defined)

findPath()

Returns the sequence of schemas needed to migrate from one to another, or null if no path exists.

const path = registry.findPath('v1', 'v3')
// ['v1', 'v2', 'v3'] or null

Uses the registry's pathStrategy to determine the algorithm (BFS or Dijkstra).

explain()

Returns a diagnostic description of the migration path between two schemas without running any migrations. Includes costs, labels, deprecation info, and a human-readable summary.

const info = registry.explain('v1', 'v3')
console.log(info.summary)
// Path: v1 -> v2 -> v3 (2 steps, total cost: 0)
//   1. v1 -> v2 (cost: 0) [v1-to-v2-upgrade]
//   2. v2 -> v3 (cost: 0) [v2-to-v3-upgrade]

When no path exists, the summary includes which schemas are reachable from the source and which schemas can reach the target.

See Debugging for full details.

On this page