A lightweight, flexible validation library built with TypeScript. Designed to work seamlessly in browsers, Deno, Node.js, and any JavaScript environment, featuring minimal bundle size and tree-shakable imports.
- Strong TypeScript support with full type inference
- Intuitive, chainable API for building complex validation schemas
- Built-in validators for common data types:
- Strings
- Numbers
- Booleans
- Arrays
- Objects
- URLs
- UUIDs
- Enums
- Literals
- Middleware utilities for Huuma/Route integration
- Clear, helpful validation error messages
- Extremely lightweight bundle size
- Tree-shakable architecture – import only what you need
- Runtime-agnostic – works in browsers, Deno, Node.js, and other JavaScript environments
- Zero dependencies
// Import the entire libraryimport*asvalidatefrom"jsr:@huuma/validate";// Or import specific validators to reduce bundle sizeimport{StringSchema,NumberSchema,ObjectSchema}from"jsr:@huuma/validate";// Import individual validators directly for maximum tree-shakingimport{StringSchema}from"jsr:@huuma/validate/string";import{NumberSchema}from"jsr:@huuma/validate/number";import{ObjectSchema}from"jsr:@huuma/validate/object";import{BooleanSchema}from"jsr:@huuma/validate/boolean";npx jsr add @huuma/validateThen import:
// Import the entire libraryimport*asvalidatefrom"@huuma/validate";// Or import specific validatorsimport{StringSchema,NumberSchema}from"@huuma/validate";import{StringSchema,NumberSchema,ObjectSchema}from"jsr:@huuma/validate";// Define a schemaconstuserSchema=newObjectSchema({username: newStringSchema().notEmpty(),email: newStringSchema().regex(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/),age: newNumberSchema().min(18),});// Validate dataconstresult=userSchema.validate({username: "john_doe",email: "john@example.com",age: 25});// Check if validation passedif(result.errors){console.error("Validation failed:",result.errors);}else{// Use the validated dataconstvalidatedUser=result.value;console.log("Valid user:",validatedUser);}// Alternative: Use parse method (throws error on invalid data)try{constvalidatedUser=userSchema.parse({username: "john_doe",email: "john@example.com",age: 25});console.log("Valid user:",validatedUser);}catch(error){console.error("Validation failed:",error);}import{StringSchema}from"jsr:@huuma/validate";constschema=newStringSchema().notEmpty()// String must not be empty.startsWith("http")// String must start with "http".endsWith(".com")// String must end with ".com".regex(/^[a-z]+$/)// String must match the regex pattern.equals("value")// String must equal "value".notEquals("bad")// String must not equal "bad".optional();// Value can be undefinedimport{NumberSchema}from"jsr:@huuma/validate";constschema=newNumberSchema().positive()// Number must be positive (>= 1).negative()// Number must be negative (< 0).min(10)// Number must be >= 10.max(100)// Number must be <= 100.equals(42)// Number must equal 42.optional();// Value can be undefinedimport{BooleanSchema}from"jsr:@huuma/validate";constschema=newBooleanSchema().true()// Must be true.optional();// Value can be undefined// OrconstfalseSchema=newBooleanSchema().false();// Must be falseimport{ArraySchema,StringSchema}from"jsr:@huuma/validate";// Array of stringsconstschema=newArraySchema(newStringSchema().notEmpty()).optional();// The array itself can be undefinedimport{ObjectSchema,StringSchema,NumberSchema}from"jsr:@huuma/validate";constschema=newObjectSchema({name: newStringSchema().notEmpty(),age: newNumberSchema().min(18),email: newStringSchema().optional(),});import{URLSchema}from"jsr:@huuma/validate";constschema=newURLSchema().http(true)// Must be HTTPS (pass false to allow HTTP or HTTPS).optional();// Or validate specific protocolsconstsshSchema=newURLSchema().protocol("ssh:");import{UUIDSchema}from"jsr:@huuma/validate";// Any UUID versionconstschema=newUUIDSchema();// Specific UUID versionconstuuidV4Schema=newUUIDSchema("4");// Only UUID v4constuuidV1Schema=newUUIDSchema("1");// Only UUID v1import{EnumSchema}from"jsr:@huuma/validate";// String enumconstroleSchema=newEnumSchema(["admin","user","guest"]);// Number enumconststatusSchema=newEnumSchema([200,400,500]);import{LiteralSchema}from"jsr:@huuma/validate";// Must exactly match the literal valueconstschema=newLiteralSchema("active");constnumSchema=newLiteralSchema(42);For applications where bundle size is critical, use direct imports to benefit from tree-shaking:
// Only import what you needimport{StringSchema}from"@huuma/validate/string";import{NumberSchema}from"@huuma/validate/number";// This ensures unused validators aren't included in your bundleEach validator is completely independent, allowing for minimal overhead when only specific validation types are needed. This approach works in all JavaScript environments and is particularly valuable for browser applications.
The library provides middleware for easy integration with Huuma/Route applications:
import{validateBody,validateSearch}from"jsr:@huuma/validate/middleware";import{StringSchema,ObjectSchema}from"jsr:@huuma/validate";import{App}from"@huuma/route";constapp=newApp();// Define schemasconstsearchParamsSchema=newObjectSchema({page: newStringSchema().optional(),limit: newStringSchema().optional(),});constuserSchema=newObjectSchema({username: newStringSchema().notEmpty(),email: newStringSchema().notEmpty(),});// Apply validation middlewareapp.post("/users",validateSearch(searchParamsSchema),// Validates search parametersvalidateBody(userSchema),// Validates request body(ctx)=>{// At this point, both ctx.search and ctx.body are validated// If validation fails, an appropriate HTTP error is returned automaticallyreturnResponse.json({success: true});});You can add custom validators to any schema:
import{StringSchema}from"jsr:@huuma/validate";constschema=newStringSchema().custom((value,key)=>{if(value==="forbidden_value"){return{message: `"${key||'string'}" contains a forbidden value`};}// Return undefined when validation passesreturnundefined;});Validation errors have a consistent format:
// Example validation errors[{message: '"username" is empty'},{message: '"email" is not type "string"'},{message: '"age" is smaller than 18'}]MIT