Minimal helper for extracting typed, validated values from Valibot schemas.
valibot.safeParse() works — but it’s not very intuitive.
It leads to very procedural code, where you manually handle control flow and flatten errors — a common task when logging structural data for observability.
It reads like plumbing — not like intent.
...
import { safeParse, flatten } from 'valibot'
const result = safeParse(schema, input)
if (!result.success) {
const issues = flatten(result.issues).nested
logger.warn('validation failed', { issues })
}This boilerplate is everywhere, and it hides your intent behind ceremony.
valext introduces a small shift:
...
import { extract } from '@gambonny/valext'
const result = extract(schema).from(input, issues => {
logger.warn('validation failed', { issues })
})- ✅ Fluent API that reads like intent —
extract(...).from(...) - ✅ Ergonomic structure for validation — no verbose branching or manual flattening
- ✅ Structured error handling — pass a callback to receive flattened issues
pnpm add @gambonny/valextimport { validator } from 'hono/validator'
import { extract } from '@gambonny/valext'
import { credentials } from './schemas'
app.post(
'/signup',
validator('json', async (body, c) => {
const { success, output } = extract(credentials).from(body, issues =>
c.var.logger.warn('validation failed', { issues }),
)
return success ? output : c.text('Invalid input')
}),
)Returns:
{
success: true;
output: T;
issues: undefined;
}or:
{
success: false;
output: undefined;
issues: ValibotFlattenedIssues;
}Exactly like valibot.safeParse(), but lets you pass a callback for flattened errors.
Exactly like valibot.parse(). Will throw if input is invalid.
- ✅
valextusesvalibot.safeParse()under the hood. - ✅ Errors are flattened with
valibot.flatten().nestedfor easy rendering/logging. - ✅ If you need raw nested issues, just use
valibot.safeParse()directly — you’re not locked in.
Reminder:
valextis not an abstraction layer — it’s a tool for making your intent clear at the point of use.