doba

With ArkType

Using doba with ArkType schemas and multi-hop transforms.

Using ArkType for schema validation with multi-hop transforms.

Full example

import { type } from 'arktype'
import { createRegistry } from 'dobajs'

const databaseUser = type({
  id: 'string',
  email: 'string.email',
  passwordHash: 'string',
  createdAt: 'string',
  settings: {
    theme: "'light' | 'dark'",
    notifications: {
      email: 'boolean',
      push: 'boolean',
    },
    internal: {
      lastLoginIp: 'string',
      sessionCount: 'number',
    },
  },
})

const frontendUser = type({
  id: 'string',
  email: 'string.email',
  createdAt: 'string',
  settings: {
    theme: "'light' | 'dark'",
    notifications: {
      email: 'boolean',
      push: 'boolean',
    },
  },
})

const aiUser = type({
  id: 'string',
  email: 'string',
  theme: 'string',
  notificationsEnabled: 'boolean',
})

const legacyUser = type({
  'name?': 'string',
  'darkMode?': 'boolean',
})

const registry = createRegistry({
  schemas: {
    database: databaseUser,
    frontend: frontendUser,
    ai: aiUser,
    legacy: legacyUser,
  },
  migrations: {
    'database->frontend': (user) => ({
      id: user.id,
      email: user.email,
      createdAt: user.createdAt,
      settings: {
        theme: user.settings.theme,
        notifications: user.settings.notifications,
      },
    }),
    'database->ai': (user) => ({
      id: user.id,
      email: user.email,
      theme: user.settings.theme,
      notificationsEnabled: user.settings.notifications.email || user.settings.notifications.push,
    }),
    'frontend->ai': (user) => ({
      id: user.id,
      email: user.email,
      theme: user.settings.theme,
      notificationsEnabled: user.settings.notifications.email || user.settings.notifications.push,
    }),
    'legacy->frontend': (user, ctx) => {
      ctx.defaulted(['id'], 'generated new id')
      ctx.defaulted(['createdAt'], 'set to current timestamp')
      ctx.defaulted(['settings', 'notifications'], 'defaulted to all false')

      let email = 'unknown@example.com'
      if (typeof user.name === 'string' && user.name.length > 0) {
        email = `${user.name.toLowerCase().replace(/\s+/g, '.')}@legacy.example.com`
        ctx.warn(`converted name "${user.name}" to email`)
      }

      return {
        id: `legacy-${Date.now()}`,
        email,
        createdAt: new Date().toISOString(),
        settings: {
          theme: user.darkMode === true ? 'dark' : 'light',
          notifications: { email: false, push: false },
        },
      }
    },
  },
})

Usage

const dbUser: typeof databaseUser.infer = {
  id: 'user-789',
  email: 'charlie@example.com',
  passwordHash: 'hashed_secret123',
  createdAt: '2024-05-10T08:00:00Z',
  settings: {
    theme: 'dark',
    notifications: { email: true, push: true },
    internal: { lastLoginIp: '192.168.0.100', sessionCount: 42 },
  },
}

// Direct
const frontend = await registry.transform(dbUser, 'database', 'frontend')

// Multi-hop: legacy -> frontend -> ai
const legacy: typeof legacyUser.infer = { name: 'Diana Prince', darkMode: true }
const ai = await registry.transform(legacy, 'legacy', 'ai')

if (ai.ok) {
  console.log(ai.value)
  console.log(ai.meta.path) // ["legacy", "frontend", "ai"]
  console.log(ai.meta.steps) // step-by-step breakdown
}

ArkType schemas implement Standard Schema, so they work with doba out of the box. No adapters needed.

On this page