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 🙏

© 2025 – Pkg Stats / Ryan Hefner

betterbe

v3.0.0

Published

**A minimally flexible data validator**

Readme

betterbe

A minimally flexible data validator

github license npm version

Features

  • Props are required by default
  • Strict by default (no type coercion)
  • No unknown properties allowed
  • Lightweight with no dependencies
  • TypeScript-first design

Installation

# npm
npm install betterbe

# yarn
yarn add betterbe

Basic Example

import { boolean, number, object, record, string } from 'betterbe'

const validateUid = string({
  minLength: 10,
  maxLength: 12,
  alphabet: '0123456789',
})

const validateMessage = object({
  from: object({
    uid: validateUid,
  }),
  message: string({ minLength: 1, maxLength: 280 }),
  utcTime: number({ integer: true }),
  urgent: boolean({ required: false }),
  metadata: record(string({ pattern: /^[a-z_]+$/ }), string(), {
    required: false,
  }),
})

// This is not expected to throw (valid input)
validateMessage.validate({
  from: { uid: '1234567890' },
  message: 'Hello, World!',
  utcTime: 1630000000,
  metadata: { user_agent: 'Mozilla/5.0', client_version: '1.0.0' },
})

// This is expected to throw as character `-` is not valid in the uid alphabet
validateMessage.validate({
  from: { uid: '1234567-90' },
  message: 'Hello, World!',
  utcTime: 1630000000,
})

API Reference

String Validator

import { string } from 'betterbe'

// Basic usage
const validateName = string()

// With options
const validateUsername = string({
  minLength: 3,
  maxLength: 20,
  pattern: /^[a-zA-Z0-9_]+$/,
  required: true,
})

// With alphabet restriction
const validateDigitCode = string({
  alphabet: '0123456789',
  minLength: 6,
  maxLength: 6,
})

// With oneOf (enumeration)
const validateColor = string({
  oneOf: ['red', 'green', 'blue'],
})

// With custom test function
const validateEmail = string({
  test: (value) => {
    if (!value.includes('@')) {
      throw new Error('Invalid email format')
    }
  },
})

Options:

  • minLength: Minimum string length
  • maxLength: Maximum string length
  • pattern: RegExp pattern the string must match
  • alphabet: String of allowed characters
  • required: Whether the value is required (default: true)
  • test: Custom validation function
  • oneOf: Array of allowed string values (cannot be used with other string options)

Number Validator

import { number } from 'betterbe'

// Basic usage
const validateAge = number()

// With options
const validatePositiveInteger = number({
  min: 1,
  integer: true,
})

// With range
const validatePercentage = number({
  min: 0,
  max: 100,
})

// Optional number
const validateOptionalCount = number({
  required: false,
})

// Example: NaN validation
try {
  validateAge.validate(NaN)
} catch (error) {
  console.log(error.message) // "is not a number"
}

Note: The number validator automatically rejects NaN values and will throw a validation error with the message "is not a number".

Options:

  • min: Minimum value
  • max: Maximum value
  • integer: Whether the number must be an integer
  • required: Whether the value is required (default: true)

Boolean Validator

import { boolean } from 'betterbe'

// Basic usage
const validateIsActive = boolean()

// Optional boolean
const validateOptionalFlag = boolean({
  required: false,
})

Options:

  • required: Whether the value is required (default: true)

Array Validator

import { array, string, number } from 'betterbe'

// Array of strings
const validateTags = array(string())

// Array of numbers with length constraints
const validateScores = array(number(), {
  minLength: 1,
  maxLength: 10,
})

// Array with unique values
const validateUniqueIds = array(string(), {
  unique: true,
})

// Optional array
const validateOptionalItems = array(string(), {
  required: false,
})

// With custom test function
const validateSortedNumbers = array(number(), {
  test: (values) => {
    for (let i = 1; i < values.length; i++) {
      if (values[i] < values[i - 1]) {
        throw new Error('Array must be sorted in ascending order')
      }
    }
  },
})

Options:

  • minLength: Minimum array length
  • maxLength: Maximum array length
  • required: Whether the value is required (default: true)
  • unique: Whether array values must be unique (default: false)
  • test: Custom validation function

Object Validator

import { object, string, number, boolean } from 'betterbe'

// Basic usage
const validateUser = object({
  name: string(),
  age: number(),
  isActive: boolean(),
})

// Nested objects
const validatePost = object({
  title: string(),
  content: string(),
  author: object({
    id: string(),
    name: string(),
  }),
  published: boolean(),
})

// Optional object
const validateOptionalMetadata = object(
  {
    tags: array(string()),
  },
  {
    required: false,
  },
)

// With custom test function
const validateCredentials = object(
  {
    username: string(),
    password: string(),
  },
  {
    test: (value) => {
      if (value.username === value.password) {
        throw new Error('Username and password cannot be the same')
      }
    },
  },
)

Options:

  • required: Whether the value is required (default: true)
  • test: Custom validation function

Record Validator

import { record, string, number, boolean } from 'betterbe'

// Basic usage - validates objects with dynamic keys
const validateScores = record(
  string(), // all keys must be strings
  number(), // all values must be numbers
)

// With key validation - only specific keys allowed
const validatePermissions = record(
  string({ oneOf: ['read', 'write', 'admin'] }),
  boolean(),
)

// With key pattern validation
const validateUserData = record(
  string({ pattern: /^user_[0-9]+$/ }), // keys like "user_123"
  object({
    name: string(),
    age: number(),
  }),
)

// Nested records
const validateConfiguration = record(
  string({ pattern: /^[a-z]+$/ }), // lowercase keys only
  record(string({ oneOf: ['value', 'enabled', 'config'] }), string()),
)

// Optional record
const validateOptionalSettings = record(string(), string(), { required: false })

// With custom test function
const validateApiKeys = record(
  string({ pattern: /^api_/ }),
  string({ minLength: 32 }),
  {
    test: (value) => {
      if (Object.keys(value).length === 0) {
        throw new Error('At least one API key is required')
      }
    },
  },
)

Options:

  • required: Whether the value is required (default: true)
  • test: Custom validation function

Error Handling

The library throws ValidationError instances when validation fails. These errors contain:

  • type: The type of validation that failed (e.g., 'required', 'minLength', 'pattern')
  • message: A human-readable error message
  • meta: Additional metadata about the validation that failed

Error Metadata

The meta object includes context information:

  • context: 'key' or 'value' - indicates whether the error is for key or value validation
  • originalKey: The key that failed validation (in record validators)
  • propertyName: The property name that failed validation (in object validators)
  • arrayIndex: The array index where validation failed (in array validators)

Examples

import { string, record, array, object } from 'betterbe'

// Basic validation error
const validateUsername = string({ minLength: 3 })

try {
  validateUsername.validate('ab')
} catch (error) {
  console.log(error.type) // 'minLength'
  console.log(error.message) // "is shorter than expected length 3"
  console.log(error.meta) // { minLength: 3, context: 'value' }
}

// Record key validation error
const validateScores = record(string({ pattern: /^[a-z]+$/ }), number())

try {
  validateScores.validate({ 'Invalid-Key': 100 })
} catch (error) {
  console.log(error.type) // 'pattern'
  console.log(error.message) // "key 'Invalid-Key' does not match pattern"
  console.log(error.meta) // { pattern: /^[a-z]+$/, context: 'key', originalKey: 'Invalid-Key' }
}

// Array item validation error
const validateNumbers = array(number({ min: 0 }))

try {
  validateNumbers.validate([1, -5, 3])
} catch (error) {
  console.log(error.type) // 'min'
  console.log(error.message) // "'[1]' is less than minimum 0"
  console.log(error.meta) // { min: 0, context: 'value', arrayIndex: 1 }
}

// Object property validation error
const validateUser = object({
  name: string({ maxLength: 10 }),
  age: number(),
})

try {
  validateUser.validate({ name: 'ThisNameIsTooLong', age: 25 })
} catch (error) {
  console.log(error.type) // 'maxLength'
  console.log(error.message) // "'name' is longer than expected length 10"
  console.log(error.meta) // { maxLength: 10, context: 'value', propertyName: 'name' }
}

License

MIT