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

@codenhub/validation

v0.0.1

Published

Zero-dependency validation and primitive coercion helpers for TypeScript apps.

Readme

@codenhub/validation

Validation and primitive coercion helpers for TypeScript apps. Validators return a validation-owned result shape, so callers can handle invalid input without exceptions.

Installation

pnpm add @codenhub/validation

Usage

Validate unknown boundary input with val and convert primitive values with coerce when input arrives as strings, environment values, form values, or query params.

import { coerce, val, type ValidationResult } from "@codenhub/validation";

const parsePort = (raw: unknown): ValidationResult<number> => {
  const port = coerce.int(raw, { path: ["port"] });

  if (!port.ok) return port;

  return val.number(port.value, { path: ["port"] }).port();
};

const result = parsePort("3000");

if (result.ok) {
  console.log(result.value);
} else {
  console.error(result.error.message);
}

Reference

@codenhub/validation

Primary entrypoint for validation, coercion, custom validators, and result helpers.

import {
  coerce,
  custom,
  err,
  ok,
  parseResult,
  type ArrayValidators,
  type NumberValidators,
  type ObjectValidators,
  type PlainObject,
  type StringValidators,
  val,
  type ValidationErr,
  type ValidationError,
  type ValidationErrorCode,
  type ValidationErrorInput,
  type ValidationErrorOptions,
  type ValidationIssue,
  type ValidationOk,
  type ValidationOptions,
  type ValidationPathSegment,
  type ValidationResult,
} from "@codenhub/validation";

Supported import paths:

| Path | Description | | ---------------------- | ------------------------------------------- | | @codenhub/validation | Validation, coercion, and result utilities. |

ValidationResult<T>

Represents success or validation failure without throwing.

type ValidationResult<T> = ValidationOk<T> | ValidationErr;

interface ValidationOk<T> {
  ok: true;
  value: T;
}

interface ValidationErr {
  ok: false;
  error: ValidationError;
}

ValidationError

Plain object describing why validation failed.

interface ValidationError {
  code: ValidationErrorCode;
  message: string;
  path: readonly ValidationPathSegment[];
  input?: unknown;
  expected?: string;
  received?: string;
  issues?: readonly ValidationIssue[];
}

type ValidationErrorCode =
  | "invalid_type"
  | "invalid_value"
  | "invalid_format"
  | "too_small"
  | "too_big"
  | "missing_key"
  | "custom";

type ValidationPathSegment = string | number;

interface ValidationIssue {
  code: ValidationErrorCode;
  message: string;
  path: readonly ValidationPathSegment[];
  input?: unknown;
  expected?: string;
  received?: string;
}

path points to the invalid value. input is included only when requested through validation options.

ValidationOptions

Common options accepted by validators and coercers.

interface ValidationOptions {
  path?: readonly ValidationPathSegment[];
  includeInput?: boolean;
}

ok()

Creates a successful validation result.

function ok<T>(value: T): ValidationOk<T>;

err()

Creates a failed validation result.

function err(error: ValidationErrorInput): ValidationErr;

type ValidationErrorInput = string | ValidationIssue | ValidationErrorOptions;

interface ValidationErrorOptions {
  code?: ValidationErrorCode;
  message: string;
  path?: readonly ValidationPathSegment[];
  input?: unknown;
  expected?: string;
  received?: string;
  issues?: readonly ValidationIssue[];
}

String input uses code: "custom" and an empty path.

parseResult()

Normalizes unknown validator output into ValidationResult<T>.

function parseResult<T>(value: unknown): ValidationResult<T>;

Accepted input:

| Input shape | Output | | ------------------------ | -------------------------------------------------- | | { ok: true, value } | Success result. | | { ok: false, error } | Failure with normalized ValidationError. | | ValidationErrorOptions | Failure result. | | Error | Failure with code: "custom" and message. | | string | Failure with code: "custom" and message. | | Anything else | Failure with code: "custom" and generic message. |

val

Validation factory for common string, number, object, and array checks.

const val: {
  string(value: unknown, options?: ValidationOptions): StringValidators;
  number(value: unknown, options?: ValidationOptions): NumberValidators;
  object(value: unknown, options?: ValidationOptions): ObjectValidators;
  array<T = unknown>(value: unknown, options?: ValidationOptions): ArrayValidators<T>;
};

Validators return ValidationResult<T> and do not throw for invalid input.

All validator factories accept unknown input. If the input has the wrong base type, every method on the returned validator object returns the same ValidationErr with code: "invalid_type", the provided path, and the original input only when includeInput is enabled.

Validator Types

Validator interfaces describe the method sets returned by val factories. They are exported for callers that need to type reusable validators or function boundaries.

type PlainObject = Record<string, unknown>;

interface StringValidators { ... }
interface NumberValidators { ... }
interface ObjectValidators { ... }
interface ArrayValidators<T> { ... }

| Type | Import path | Purpose | | -------------------- | ---------------------- | ------------------------------------------------- | | StringValidators | @codenhub/validation | Return type for val.string(). | | NumberValidators | @codenhub/validation | Return type for val.number(). | | ObjectValidators | @codenhub/validation | Return type for val.object(). | | ArrayValidators<T> | @codenhub/validation | Return type for val.array<T>(). | | PlainObject | @codenhub/validation | Plain object shape returned by object validators. |

val.string()
val.string(value: unknown, options?: ValidationOptions): StringValidators;

Creates validators for input that must be a string. Non-string input fails with code: "invalid_type".

| Method | Success value | Failure behavior | | --------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | email(options?: { allowPlus?: boolean }) | Trimmed email with the host lowercased. allowPlus defaults to true. | Returns code: "invalid_format" for invalid local parts, public hosts, length limits, or disallowed plus addressing. | | url(options?: { forceHttps?: boolean }) | Normalized public HTTP(S) URL string. Missing protocol defaults to https://. | Returns code: "invalid_format" for invalid URLs, private/non-public host shapes, credentials, or HTTP when forceHttps is true. | | fileType(allowed: string[]) | Lowercase file extension without a leading dot. | Returns code: "invalid_value" when the allow list is empty after normalization, or code: "invalid_format" when the input extension is missing or not allowed. | | minLength(length: number, options?: { trim?: boolean }) | Original string, or trimmed string when trim is true. | Returns code: "invalid_value" for invalid limits, or code: "too_small" when shorter than length. | | maxLength(length: number, options?: { trim?: boolean }) | Original string, or trimmed string when trim is true. | Returns code: "invalid_value" for invalid limits, or code: "too_big" when longer than length. | | notEmpty(options?: { trim?: boolean }) | Original string, or trimmed string. trim defaults to true. | Returns code: "too_small" when the checked string is empty. | | matches(pattern: RegExp, message?: string) | Original string. | Returns code: "invalid_format" with the provided message when the pattern does not match. |

val.number()
val.number(value: unknown, options?: ValidationOptions): NumberValidators;

Creates validators for finite number input. Non-number and NaN input fails with code: "invalid_type"; non-finite numbers fail with code: "invalid_value" before method-specific checks run.

| Method | Success value | Failure behavior | | ------------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | positive() | Original number. | Returns code: "invalid_value" when the number is not greater than zero. | | negative() | Original number. | Returns code: "invalid_value" when the number is not less than zero. | | nonNegative() | Original number. | Returns code: "invalid_value" when the number is less than zero. | | nonPositive() | Original number. | Returns code: "invalid_value" when the number is greater than zero. | | nonZero() | Original number. | Returns code: "invalid_value" when the number is zero. | | int() | Original number. | Returns code: "invalid_value" when the number is not an integer. | | safeInt() | Original number. | Returns code: "invalid_value" when the number is not a safe JavaScript integer. | | range(options: { min?: number; max?: number }) | Original number. | Returns code: "invalid_value" for invalid range configuration, code: "too_small" below min, or code: "too_big" above max. | | finite() | Original number. | Returns success because non-finite values fail before this method runs. | | port() | Original number. | Returns code: "invalid_value" unless the number is an integer from 1 through 65535. |

val.object()
val.object(value: unknown, options?: ValidationOptions): ObjectValidators;

Creates validators for plain objects, including null-prototype objects. Arrays, null, functions, and class instances fail with code: "invalid_type".

| Method | Success value | Failure behavior | | ---------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------- | | plain() | Original plain object. | Returns the base type failure for non-plain objects. | | hasKeys(keys: readonly string[]) | Original plain object. | Returns code: "missing_key" with the missing key appended to path when any required own property is absent. |

val.array()
val.array<T = unknown>(value: unknown, options?: ValidationOptions): ArrayValidators<T>;

Creates validators for array input. Non-array input fails with code: "invalid_type".

| Method | Success value | Failure behavior | | --------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------- | | minLength(length: number) | Original array. | Returns code: "invalid_value" for invalid limits, or code: "too_small" when the array has fewer items. | | maxLength(length: number) | Original array. | Returns code: "invalid_value" for invalid limits, or code: "too_big" when the array has more items. | | notEmpty() | Original array. | Returns code: "too_small" when the array is empty. |

coerce

Converts primitive input before validation.

const coerce: {
  int(value: unknown, options?: ValidationOptions): ValidationResult<number>;
  number(value: unknown, options?: ValidationOptions): ValidationResult<number>;
  bool(value: unknown, options?: ValidationOptions): ValidationResult<boolean>;
  string(value: unknown, options?: ValidationOptions): ValidationResult<string>;
};

Objects and functions are rejected. null and undefined are rejected by coerce.string().

| Method | Success value | Failure behavior | | -------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | coerce.int(value, options?) | Safe integer. | Returns code: "invalid_type" for objects/functions, or code: "invalid_format" for non-decimal or unsafe integer input. | | coerce.number(value, options?) | Finite number. | Returns code: "invalid_type" for objects/functions, or code: "invalid_format" for unsupported number strings such as exponent notation. | | coerce.bool(value, options?) | Boolean. | Accepts booleans and true, false, 1, 0, yes, no, on, and off strings. Other primitive values return code: "invalid_format"; objects/functions return code: "invalid_type". | | coerce.string(value, options?) | Stringified primitive. | Returns code: "invalid_type" for null, undefined, objects, functions, or values that cannot be converted to strings. |

custom()

Runs a custom validator and normalizes returned or thrown failures.

function custom<T>(
  value: unknown,
  validator: (value: unknown) => unknown,
  options?: ValidationOptions,
): ValidationResult<T>;

Thrown strings, Error objects, result-like objects, and validation error options become ValidationErr.

Examples

Validate Object Fields

import { err, val } from "@codenhub/validation";

const input = { email: "[email protected]", port: 3000 };
const email = val.string(input.email, { path: ["email"] }).email();
const port = val.number(input.port, { path: ["port"] }).port();

const issues = [];

for (const result of [email, port]) {
  if (!result.ok) issues.push(result.error);
}

const result = issues.length > 0 ? err({ message: "Invalid config", issues }) : port;

Custom Validator

import { custom, err, ok } from "@codenhub/validation";

const userId = custom("usr_123", (value) => {
  if (typeof value !== "string") return err({ code: "invalid_type", message: "Expected user id" });
  if (!value.startsWith("usr_")) return err({ code: "invalid_format", message: "Invalid user id" });

  return ok(value);
});

Requirements

  • TypeScript strict mode.
  • ESM package.
  • No runtime dependencies.
  • Browser, Node, and SSR safe.

Notes

  • Validators return results instead of throwing for invalid input.
  • Validation errors are plain serializable objects.
  • includeInput should be used only when retaining the original input is safe for the caller.