npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nextnode/validation

v2.1.0

Published

A TypeScript validation library powered by ArkType for comprehensive input validation on both frontend and backend in NextNode projects

Readme

@nextnode/validation

A TypeScript validation library powered by ArkType for comprehensive input validation on both frontend and backend in NextNode projects.

Features

  • ArkType-powered: Full TypeScript type inference with string-based schema definitions
  • Pre-built validators: Email, URL, UUID, credit card, phone, passwords, and 50+ more
  • React Hook Form integration: Ready-to-use resolver
  • Server middleware: Hono, Express, and Fastify adapters
  • Structured errors: Path-based error format with error codes for i18n support
  • Tree-shakeable: Import only what you need
  • Factory functions: Create configurable validators (passwords, API keys, etc.)

Installation

pnpm add @nextnode/validation

Peer dependencies (install as needed):

# React Hook Form integration
pnpm add react-hook-form

# Server middleware
pnpm add hono      # or express / fastify

Quick Start

Basic Validation

import { type } from '@nextnode/validation'

// Define schema using ArkType string syntax
const userSchema = type({
	email: 'string.email',
	age: 'number >= 0',
	role: "'admin' | 'user'",
})

// Validate data
const result = userSchema({ email: '[email protected]', age: 25, role: 'user' })

if (result instanceof type.errors) {
	console.error(result.summary)
} else {
	console.log('Valid user:', result)
}

Using the Validation Engine

import { v } from '@nextnode/validation'

// Create schemas with the validation engine
const schema = v.object<{ name: string; email: string }>({
	name: 'string >= 1',
	email: 'string.email',
})

// Safe parsing (returns result object)
const result = schema.safeParse({ name: 'John', email: '[email protected]' })

if (result.success) {
	console.log(result.data) // Typed as { name: string; email: string }
} else {
	console.log(result.issues) // Array of ValidationIssue
}

// Throws on invalid data
const data = schema.parse(input)

Pre-built Schemas

import {
	schemas, // Common: email, url, uuid, date, json, slug, semver, etc.
	authSchemas, // Auth: strongPassword, username, loginSchema, jwtToken, apiKey
	financialSchemas, // Financial: creditCard, price, iban, bic, currencyCode
	networkSchemas, // Network: ipv4, ipv6, port, hostname, macAddress, domain
	identitySchemas, // Identity: phoneE164, ssnUS, postalCodeFR, age, birthDate
} from '@nextnode/validation'

// Use pre-built validators
const isValidEmail = schemas.email('[email protected]')
const isValidCard = financialSchemas.creditCard('4532015112830366')

// Compose with custom schemas
const paymentSchema = type({
	email: schemas.email,
	amount: financialSchemas.price,
	cardNumber: financialSchemas.creditCard,
})

// Use factory functions for configurable validators
import { createPasswordSchema, createApiKey } from '@nextnode/validation'

const customPassword = createPasswordSchema({
	minLength: 12,
	requireUppercase: true,
	requireSpecialChars: true,
})

const myApiKey = createApiKey('api') // Validates api_XXXXXXXXXX...

React Hook Form Integration

import { useForm } from 'react-hook-form'
import { type } from '@nextnode/validation'
import { arktypeResolver } from '@nextnode/validation/react-hook-form'

const loginSchema = type({
  email: 'string.email',
  password: 'string >= 8'
})

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: arktypeResolver(loginSchema)
  })

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}

      <input {...register('password')} type="password" />
      {errors.password && <span>{errors.password.message}</span>}

      <button type="submit">Login</button>
    </form>
  )
}

TanStack Form Integration

TanStack Form natively supports ArkType via the Standard Schema specification. No adapter needed - use type() directly:

import { useForm } from '@tanstack/react-form'
import { type } from '@nextnode/validation'

const schema = type({
  email: 'string.email',
  password: 'string >= 8'
})

function LoginForm() {
  const form = useForm({
    defaultValues: { email: '', password: '' },
    validators: {
      onChange: schema
    },
    onSubmit: async ({ value }) => {
      console.log(value)
    }
  })

  return (
    <form onSubmit={(e) => { e.preventDefault(); form.handleSubmit() }}>
      <form.Field name="email">
        {(field) => (
          <>
            <input
              value={field.state.value}
              onChange={(e) => field.handleChange(e.target.value)}
            />
            {field.state.meta.errors.map(err => <span key={err}>{err}</span>)}
          </>
        )}
      </form.Field>
      <button type="submit">Submit</button>
    </form>
  )
}

Note: Use raw ArkType (type()) with TanStack Form. The v.schema() wrapper is designed for React Hook Form integration.

Server Middleware

Hono

import { Hono } from 'hono'
import { type } from '@nextnode/validation'
import { honoValidator } from '@nextnode/validation/middleware/hono'

const app = new Hono()

const userSchema = type({
	email: 'string.email',
	name: 'string >= 1',
})

app.post('/users', honoValidator('body', userSchema), c => {
	const user = c.get('validated')
	return c.json({ user })
})

Express

import express from 'express'
import { type } from '@nextnode/validation'
import { expressValidator } from '@nextnode/validation/middleware/express'

const app = express()
app.use(express.json())

const userSchema = type({
	email: 'string.email',
	name: 'string >= 1',
})

app.post('/users', expressValidator('body', userSchema), (req, res) => {
	const user = req.validated
	res.json({ user })
})

Fastify

import Fastify from 'fastify'
import { type } from '@nextnode/validation'
import { fastifyValidator } from '@nextnode/validation/middleware/fastify'

const fastify = Fastify()

const userSchema = type({
	email: 'string.email',
	name: 'string >= 1',
})

fastify.post(
	'/users',
	{
		preHandler: fastifyValidator('body', userSchema),
	},
	(request, reply) => {
		const user = request.validated
		reply.send({ user })
	},
)

Validation Targets

All middleware adapters support validating different parts of the request:

// Validate request body
honoValidator('body', schema)

// Validate query parameters
honoValidator('query', schema)

// Validate route parameters
honoValidator('params', schema)

// Validate headers
honoValidator('headers', schema)

Error Format

Validation errors follow a structured format for easy i18n:

interface ValidationIssue {
	path: ReadonlyArray<string | number> // ['user', 'email']
	code: string // 'invalid_email'
	message: string // 'must be a valid email'
	expected?: string // 'valid email format'
	actual?: string // 'invalid-email'
}

Custom Validators

import { type } from '@nextnode/validation'

// Regex pattern
const slugSchema = type(/^[a-z0-9-]+$/)

// Custom validation with narrow()
const evenNumber = type('number').narrow(n => n % 2 === 0)

// Complex validation
const passwordSchema = type('string >= 8').narrow((pwd, ctx) => {
	if (!/[A-Z]/.test(pwd)) {
		return ctx.reject({ expected: 'uppercase letter required' })
	}
	if (!/[0-9]/.test(pwd)) {
		return ctx.reject({ expected: 'number required' })
	}
	return true
})

API Reference

Main Exports

| Export | Description | | ------------------------ | --------------------------------------------------------------- | | type | ArkType's type function for schema definitions | | Type | ArkType's Type (for type annotations) | | v | Validation engine instance (v.schema, v.define, v.object) | | createValidationEngine | Factory to create custom engine with config | | ValidationError | Error class thrown by parse() | | Infer | Type utility to infer schema type | | schemas | Common validators (email, url, uuid, slug, semver, etc.) | | authSchemas | Authentication schemas (password, username, JWT, API keys) | | financialSchemas | Financial validators (credit card, IBAN, BIC, price) | | networkSchemas | Network validators (IP, port, hostname, MAC) | | identitySchemas | Identity validators (phone, SSN, postal codes, age) | | ErrorCodes | Error code constants for i18n |

Factory Functions

| Export | Description | | ---------------------- | -------------------------------------------------- | | createPasswordSchema | Create password validator with custom requirements | | createApiKey | Create API key validator with custom prefix | | stringLength | Create string length validator | | numberRange | Create number range validator |

Sub-path Exports

| Path | Description | | ----------------------------------------- | ------------------------ | | @nextnode/validation/react-hook-form | React Hook Form resolver | | @nextnode/validation/middleware | All middleware adapters | | @nextnode/validation/middleware/hono | Hono middleware | | @nextnode/validation/middleware/express | Express middleware | | @nextnode/validation/middleware/fastify | Fastify middleware | | @nextnode/validation/schemas | Pre-built schemas only |

Pre-built Schema Reference

Common (schemas): email, url, uuid, date, json, base64, alphanumeric, slug, semver, integer, positive, nonNegative, percentage, boolean, nonEmptyString

Auth (authSchemas): username, passwordBasic, strongPassword, authEmail, jwtToken, apiKey, loginSchema, registerSchema, passwordResetSchema, passwordResetRequestSchema

Financial (financialSchemas): creditCard, iban, bic, price, amount, currencyCode, taxIdUS, taxIdFR

Network (networkSchemas): ip, ipv4, ipv6, hostname, domain, port, macAddress, urlSlug, httpMethod, httpStatusCode

Identity (identitySchemas): phoneE164, phoneFlexible, zipCodeUS, postalCodeFR, postalCodeUK, postalCodeCA, ssnUS, ssnFR, age, birthDate, personName, singleName, gender, title, nationalId, passportNumber

Complete Exports Reference

Core Engine

| Export | Type | Description | | ------------------------ | -------- | ---------------------------------- | | type | Function | ArkType type constructor | | Type | Type | ArkType generic type | | v | Object | Default validation engine instance | | createValidationEngine | Function | Factory for custom engine | | ValidationError | Class | Error thrown by parse() | | isWrappedSchema | Function | Type guard for Schema objects | | Infer | Type | Infer TypeScript type from schema |

Types

| Export | Description | | ------------------------ | ---------------------------------------------------- | | Schema<T> | Schema wrapper with safeParse(), parse() methods | | SchemaFactory | Factory function type | | SchemaMetadata | Optional metadata for schemas | | ValidationEngineConfig | Engine configuration options | | ValidationIssue | Single validation error | | ValidationResult<T> | Discriminated union: success or issues | | ErrorFormatter | Interface for custom error formatting | | ErrorFormatterConfig | Formatter configuration | | ErrorCode | Union type of all error codes |

Error Handling

| Export | Type | Description | | ----------------------- | -------- | ----------------------------- | | ErrorCodes | Object | Constants for all error codes | | DefaultErrorFormatter | Class | Default formatter | | createErrorFormatter | Function | Factory for custom formatter |

Factory Functions

| Export | Signature | Description | | ---------------------- | ------------------------------------------------ | ----------------------------- | | createPasswordSchema | (requirements: PasswordRequirements) => Schema | Custom password validator | | createApiKey | (prefix: string) => Schema | API key validator with prefix | | apiKeyWithPrefix | (prefix: string) => Schema | Alias for createApiKey | | stringLength | (min: number, max: number) => Schema | String length range validator | | numberRange | (min: number, max: number) => Schema | Number range validator |

React Hook Form (@nextnode/validation/react-hook-form)

| Export | Type | Description | | ------------------------ | -------- | ---------------------------- | | arktypeResolver | Function | Resolver for React Hook Form | | ArktypeResolver | Type | Resolver function type | | ArktypeResolverOptions | Type | Resolver options | | FieldError | Type | Single field error | | FieldErrors | Type | Map of field errors | | ResolverResult | Type | Resolver return type |

Server Middleware (@nextnode/validation/middleware)

| Export | Type | Description | | ------------------------- | -------- | -------------------------------------------- | | validateData | Function | Core validation function | | createErrorResponse | Function | Error response builder | | honoValidator | Function | Hono middleware | | getValidated | Function | Hono helper to get data | | expressValidator | Function | Express middleware | | fastifyValidator | Function | Fastify preHandler | | ValidationTarget | Type | 'body' \| 'query' \| 'params' \| 'headers' | | MiddlewareConfig | Type | Common middleware config | | ErrorHandler | Type | Custom error handler function | | ErrorHandlerContext | Type | Context passed to error handler | | ValidationErrorResponse | Type | Standard error response format | | HonoValidatorOptions | Type | Hono-specific options | | ExpressValidatorOptions | Type | Express-specific options | | FastifyValidatorOptions | Type | Fastify-specific options |

Error Codes Reference

All error codes are available via ErrorCodes constant for i18n mapping.

Type Errors

| Code | Value | Description | | ---------------- | ---------------- | ---------------------- | | INVALID_TYPE | invalid_type | Wrong type | | REQUIRED | required | Missing required field | | UNEXPECTED_KEY | unexpected_key | Unknown property |

String Errors

| Code | Value | Description | | ---------------- | ---------------- | ----------------------- | | STRING_MIN | string_min | Below minimum length | | STRING_MAX | string_max | Above maximum length | | STRING_LENGTH | string_length | Exact length mismatch | | STRING_PATTERN | string_pattern | Regex pattern failure | | INVALID_EMAIL | invalid_email | Invalid email format | | INVALID_URL | invalid_url | Invalid URL format | | INVALID_UUID | invalid_uuid | Invalid UUID format | | INVALID_DATE | invalid_date | Invalid date format | | INVALID_JSON | invalid_json | Invalid JSON | | INVALID_BASE64 | invalid_base64 | Invalid base64 encoding | | INVALID_HEX | invalid_hex | Invalid hex string | | INVALID_FORMAT | invalid_format | Generic format error |

Number Errors

| Code | Value | Description | | ----------------- | ----------------- | ------------------------- | | NUMBER_MIN | number_min | Below minimum value | | NUMBER_MAX | number_max | Above maximum value | | NUMBER_RANGE | number_range | Outside allowed range | | NOT_INTEGER | not_integer | Not an integer | | NOT_POSITIVE | not_positive | Not a positive number | | NOT_NEGATIVE | not_negative | Not a negative number | | INVALID_DIVISOR | invalid_divisor | Not divisible by expected |

Array Errors

| Code | Value | Description | | -------------- | -------------- | ----------------------- | | ARRAY_MIN | array_min | Below minimum items | | ARRAY_MAX | array_max | Above maximum items | | ARRAY_LENGTH | array_length | Exact length mismatch | | ARRAY_EMPTY | array_empty | Array must not be empty |

Object Errors

| Code | Value | Description | | -------------- | -------------- | ------------------------ | | OBJECT_EMPTY | object_empty | Object must not be empty |

Auth Errors

| Code | Value | Description | | ----------------------- | ----------------------- | ------------------------- | | INVALID_PASSWORD | invalid_password | Generic password error | | PASSWORD_TOO_SHORT | password_too_short | Below minimum length | | PASSWORD_NO_UPPERCASE | password_no_uppercase | Missing uppercase letter | | PASSWORD_NO_LOWERCASE | password_no_lowercase | Missing lowercase letter | | PASSWORD_NO_NUMBER | password_no_number | Missing number | | PASSWORD_NO_SPECIAL | password_no_special | Missing special character | | PASSWORDS_DONT_MATCH | passwords_dont_match | Passwords don't match |

Financial Errors

| Code | Value | Description | | --------------------- | --------------------- | -------------------------- | | INVALID_CREDIT_CARD | invalid_credit_card | Invalid credit card number | | INVALID_IBAN | invalid_iban | Invalid IBAN | | INVALID_BIC | invalid_bic | Invalid BIC/SWIFT code | | INVALID_CURRENCY | invalid_currency | Invalid currency code | | INVALID_PRICE | invalid_price | Invalid price format |

Network Errors

| Code | Value | Description | | ------------------ | ------------------ | -------------------- | | INVALID_IP | invalid_ip | Invalid IP address | | INVALID_IPV4 | invalid_ipv4 | Invalid IPv4 address | | INVALID_IPV6 | invalid_ipv6 | Invalid IPv6 address | | INVALID_HOSTNAME | invalid_hostname | Invalid hostname | | INVALID_PORT | invalid_port | Invalid port number | | INVALID_MAC | invalid_mac | Invalid MAC address |

Identity Errors

| Code | Value | Description | | --------------------- | --------------------- | ----------------------- | | INVALID_PHONE | invalid_phone | Invalid phone number | | INVALID_SSN | invalid_ssn | Invalid SSN | | INVALID_POSTAL_CODE | invalid_postal_code | Invalid postal/zip code |

Custom Errors

| Code | Value | Description | | ----------- | ----------- | --------------------------- | | CUSTOM | custom | Custom validation error | | PREDICATE | predicate | Predicate validation failed | | NARROW | narrow | Narrow refinement failed |

Development

# Install dependencies
pnpm install

# Run tests (119 tests)
pnpm test

# Watch mode
pnpm test:watch

# Coverage report
pnpm test:coverage

# Type check
pnpm type-check

# Lint and format
pnpm lint
pnpm format

# Build
pnpm build

Requirements

  • Node.js >= 24.0.0
  • pnpm 10+

License

MIT