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

spekvet

v2026.10.8

Published

A runtime validation and assertion library for server-side invariants.

Readme

spekvet

spekvet is a JavaScript library for runtime validation and invariant checking. Define reusable specs from types, shapes, and predicates, then check the contracts your functions rely on.

npm install spekvet

Require a valid booking

A function relies on assumptions about its inputs. Checking those assumptions at its boundary stops invalid state before it produces misleading results or fails farther from the cause.

import { spec } from 'spekvet';

const booking = spec({
  name: spec.string.min(1),
  seats: spec.number.and(Number.isSafeInteger).min(1).max(100),
});

function reserve(input) {
  const { name, seats } = booking.assert(input, 'Invalid booking');
  return `${name}: ${seats} seats`;
}

reserve({ name: 'Ada', seats: 2 });
'Ada: 2 seats'

spec({ ... }) describes the required fields. Here, name must be a nonempty string and seats a safe integer from 1 to 100. .and() adds a predicate after the number check. Object specs allow extra properties, so a function can check the fields it needs in a richer record.

.assert() returns the original input on success, making it useful in destructuring, assignments, and return statements. If the contract fails, it throws an Error with the mismatch in cause and the complete input in input:

reserve({ name: 'Ada', seats: 0 });
Error: Invalid booking

Use .diff() to inspect a failure instead: it returns undefined on success or a mismatch on failure.

booking.diff({ name: 'Ada', seats: 0 });
{ kind: 'min', expected: 1, input: 0, path: ['seats'] }

The mismatch identifies the failed check, its requirement, and the failing value. Its path locates that value inside the original input. The optional second arguments have different meanings: .assert(input, message) sets the error message; .diff(input, tag) supplies a fallback diagnostic tag.

Check a monitoring station

import { spec } from 'spekvet';

const reading = spec({
  unit: spec.any('C', 'F'),
  value: spec.number,
});

const latitude = spec.number.min(-90).max(90);
const longitude = spec.number.min(-180).max(180);

const station = spec({
  location: [latitude, longitude],
  readings: [reading],
  attachments: [],
  note: spec.optional(spec.string),
});

station.diff({
  location: [51.5, -0.12],
  readings: [{ unit: 'C', value: 18 }],
  attachments: ['photo.jpg', { source: 'manual' }],
});
undefined

Array schemas have three forms:

  • [] accepts any array.
  • [reading] checks every element against a spec.
  • [latitude, longitude] describes an exact-length tuple with a check for each position.

Lists may be empty; use spec([reading]).min(1) to require at least one reading.

spec.any('C', 'F') accepts either literal value.

spec.optional() allows omission or undefined, so the station needs no note.

station.diff({
  location: [51.5, -0.12],
  readings: [{ unit: 'C', value: '18' }],
  attachments: [],
});
{ kind: 'type', expected: 'finite number', input: '18', path: ['readings', 0, 'value'] }

Specs only check values. Parsing and transformation belong in your domain models or explicit caller functions, where input assumptions and conversion order remain visible. Spekvet does not adopt “parse, don't validate” as its API: it checks contracts without silently repairing values that violate them.

Checks stop at the first mismatch; a failed union contains the mismatch from each alternative. Predicates must return synchronously; async predicates and Promise-returning functions are unsupported. Promises are not awaited and are truthy, so they would incorrectly pass validation. Exceptions from synchronous predicates propagate unchanged. Chaining returns new specs, leaving the originals unchanged.

More ways to compose checks

Require an exact measurement or bound an object’s key count:

import { spec } from 'spekvet';

spec.string.size(2).diff('Ada'); // { kind: 'size', expected: 2, input: 'Ada' }
spec.object.max(1).diff({ a: 1, b: 2 }); // { kind: 'max', expected: 1, input: { a: 1, b: 2 } }

Require a defined value, allow null, or match a value by identity:

spec.defined.diff(null); // undefined (only undefined is rejected)
spec.nullable(spec.string).diff(null); // undefined

const token = {};
spec.literal(token).diff(token); // undefined

Label a failure with application metadata:

spec.string.min(1).tag('name-required').diff('');
{ kind: 'min', expected: 1, input: '', tag: 'name-required' }

Check relationships between fields, then assert a result before returning it:

const interval = spec({ start: spec.number, end: spec.number })
  .and(({ start, end }) => start <= end);
const duration = spec.number.min(0);

function elapsed(input) {
  const { start, end } = interval.assert(input, 'Invalid interval');
  return duration.assert(end - start, 'Invalid duration');
}

elapsed({ start: 3, end: 8 }); // 5

Defer a schema to allow recursive references:

const tree = spec.lazy(() => ({
  value: spec.string,
  children: [tree],
}));

tree.diff({ value: 'root', children: [{ value: 'leaf', children: [] }] }); // undefined

Next steps

  • Tour — Learn the full API, composition, and diagnostics.
  • Recipes — Reuse domain rules, check field relationships, and transform validated values.
  • Security — Handle sensitive values and bound validation work.

Inspired by Clojure Spec and TigerStyle.