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.