Validation
Validate Niral form actions and RPC inputs with built-in schemas. Coerce form values, validate nested data and return useful field-level error messages.
Built-in coercing schemas — form strings become typed values, errors become field messages. No Zod needed.
export const signup = withSchema(
{
email: v.email(),
age: v.int({ min: 13 }),
tags: v.array(v.string({ min: 1 }), { min: 1, max: 5 }),
bio: v.optional(v.string({ max: 500 })),
},
async ({ email, age, tags, bio }) => {
// values are validated AND coerced ("42" → 42, "on" → true)
return { ok: true }
}
)
- RPC callers get a 400 with
{ errors: { field: message } }— the thrown
client error carries .errors for form UIs
- Ordinary form actions surface it as
form.errors.fieldin props - Reactive form actions expose
saving.errors.fieldon the
formAction("signup") controller without remounting the form
v.file()validates uploads (size, types —image/*wildcards work)
Rules: string, email, int, number, bool, oneOf, array, file, object, optional.
TypeScript infers withSchema handler values and return types, as well as validate(shape, data) results. Check result.ok before using its fully validated value. Nested object errors retain their field structure; array validation errors are a single message for the field.