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

@czap/error

v0.10.0

Published

The one error algebra for LiteShip: build tagged error values that work both as thrown Errors and as Effect failures, and compose your own variants on top with zero dependencies.

Readme

@czap/error

The one LiteShip error algebra — a composable, tagged-error coproduct with zero runtime dependencies. Errors are tagged DATA values, not a class hierarchy: each variant is a _tag-discriminated record that is also a real Error (stack trace + instanceof Error), works with both throw and Effect.fail, and is extended by composing, never editing.

Install

pnpm add @czap/error

Zero runtime deps — it pulls in nothing, not even effect. The Effect interop below works because the records are plain _tag failures; bring your own effect only if you already use it.

30 seconds

import { ValidationError, ParseError, hasTag, matchTag } from '@czap/error';

// A variant is a VALUE and a TYPE. Throw it — it's a real Error:
throw ValidationError('Boundary.make', 'width must be > 0');

// Branch on the tag, not `instanceof`. `hasTag` narrows:
if (hasTag(caught, 'ParseError')) report(caught.source, caught.offset);

// `matchTag` is exhaustive over a closed union — add a variant and every
// match site must handle it or it fails to compile:
function explain(err: ValidationError | ParseError): string {
  return matchTag(err, {
    ValidationError: (e) => `rejected by ${e.module}: ${e.detail}`,
    ParseError: (e) => `could not read ${e.source}: ${e.detail}`,
  });
}

The exact same value is a first-class Effect failure — no effect import inside @czap/error, because Effect.catchTag keys on the _tag these records already carry:

import { Effect } from 'effect';

Effect.fail(ParseError('profile.json', 'expected object', { offset: 12 }))
  .pipe(Effect.catchTag('ParseError', (e) => Effect.succeed(e.detail)));

Where it sits

This is the foundational leaf the rest of the stack adopts — standalone, with zero @czap/* dependencies, so any package can fail with it. The built-in variants form one CLOSED coproduct (LiteShipError = ValidationError | ParseError | IoError | HostCapabilityError | InvariantViolationError | NotFoundError | UnsupportedError | IntegrityError) over the open TaggedError contract every helper (hasTag, matchTag, matchTagOr, raise, assertNever) operates on. See the package surfaces map for the full layout.

When a variant doesn't fit

Do not subclass — there is no base class to extend. You compose: conform a record to TaggedError, build it with the one taggedError composer, and widen the union by |. Editing @czap/error is never the extension path.

import { taggedError, type TaggedError, type LiteShipError } from '@czap/error';

interface RateLimitError extends TaggedError<'RateLimitError'> {
  readonly retryAfter: number;
}
const RateLimitError = (retryAfter: number): RateLimitError =>
  taggedError('RateLimitError', `retry after ${retryAfter}s`, { retryAfter });

type AppError = LiteShipError | RateLimitError; // composition over inheritance

Every helper keeps working on the widened union unchanged — matchTagOr handles the variants you care about and routes the rest through a fallback. Zero rebuild, zero fork.

Docs


Part of LiteShip — powered by the CZAP engine (Content-Zoned Adaptive Projection), distributed as @czap/* packages.