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

pukka

v2.3.1

Published

Delightfully simple TypeScript validation

Downloads

23

Readme

pukka ✅

version(scoped) codecov

🪶 Delightfully simple TypeScript validation

✨ Why pukka?

Because a validation library should check your data, not your patience!

| ✅ Pukka | Power | |:---------|:-------------| | 🪄 Simple | Write schemas as plain objects | | 🎯 Type Safe | Full type inference | | 🧘 Minimal | Just 5 functions, that's it! | | 🔧 Custom Validation | Validations done right, your way | | 📝 Web Standards | FormData and URLSearchParams supported out of the box | | 🛠️ HTML Form Helper | Works great with Remix, react-router and Hono apps | | 🔄 Smart Types | Automatic coercion of strings to numbers, booleans and more | | 🌍 i18n Ready | Strongly typed message keys for localization | | 🛡️ Reliable | 100% code coverage, see index.test.ts | | 🪶 Tiny | Just 2kb minified, zero dependencies |

📦 Installation

npm install pukka

🚀 Basic Usage

Define your schema as a plain object, and add validations

import { object, validator } from 'pukka'

// define your schema
const schema = object({
  name: "string",
  age: "number",
  "email?": "string",         // optional field
  "username:uname": "string", // field with alias
  hobbies: ["string"],        // array
  address: {                  // nested object
    street: "string",
    city: "string",
    state: "string"
  }
})

// create validator
const validate = validator.for(schema, (data, issues) => {
  if (data.age < 18) {
    issues.age.push("Must be 18 or older");
  }
});

// validate 
const { success, data, errors } = validate({
  name: "John",
  age: "25",        // will be coerced to number
  uname: "johndoe", // using alias
  hobbies: ["reading", "coding"],
  address: {
    street: "123 Main St",
    city: "San Francisco",
    state: "CA"
  }
})

if (success) {
  // strongly typed data
  console.log(data.name) // string
  console.log(data.age)  // number
  console.log(data.address.street)
} else {
  console.log(errors)
  console.log(data.address?.street) // street address, if entered
}

⚡ Validation with runtime context

Declare and pass some runtime context to the validator

type MyContext = {
  states: {
    code: string
    cities: string[]
  }[]
}

const validate = validator.for(
  schema,
  usingContext<MyContext>(), // 🌟 validator needs this context
  (data, issues, ctx) => {
    const state = ctx.states.find((code) => code === data.state)
    if(!state?.cities.includes(data.city)) {
      issues.city.push(`Invalid city ${data.city}`)
    }
  }
)

const states = await api.getAllStates()

const { success, data } = validate(input, { states })

📝 FormData validation

Builtin support for FormData and URLSearchParams

const form = new FormData()

form.append("name", "John")
form.append("address.street", "123 Some St") // 🌟 nested object

// hobbies=reading&hobbies=coding
form.append("hobbies", "reading")
form.append("hobbies", "coding")

// 🌟 indexed array
form.append("hobbies[0]", "reading") 
form.append("hobbies[1]", "coding")

const { success, data } = validate(form)

🛠️ Validation options

As with the qs package, an arrayLimit can be set for arrays

This is to prevent someone from sending hobbies[999999999]=cpu-hogging

const { success, data } = validate(form, {
  arrayLimit: 100 // default is 50
})

Strings can be trimmed, and empty strings can be rejected

const { success, data } = validate(form, {
  string: {
    trim: true,
    allowEmpty: false
  };
})

🛠️ Form Helper

Easily lookup the path, errors and also the submitted value for a field

import { form } from 'pukka'

const result = validate(input)

const f = form.helper(result)

<form method="post">
  <input name={f.address.street.path} value={f.address.street.value}>
  <span>{f.address.street.errors[0] ?? ""}</span>
</form>

💬 Customize Error Messages

Default error messages can be customized during validation

const { errors } = validate(input, {
  errorMessage: (key, err) => {
    if (key === "name" && err.code === "required") {
      return "Please enter your full name"
    }
  },
});

🌍 Internationalization

Strongly typed keys for localization

const validate = validator.for(schema, (data, issues) => {
  issues.address.street.push(key => i18n.t(key)) // key is "address.street"
  issues.hobbies[0].push(key => i18n.t(key))     // key is "hobbies"
});