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/error

v0.0.1

Published

Typed error normalization, result helpers, and opt-in registry presets for TypeScript apps.

Readme

@codenhub/error

Typed error normalization and result-style control flow for TypeScript apps. The package starts with an empty error registry by default, so consumers opt into known-error mappings explicitly, including ready-made registries for common platform and library errors.

Installation

pnpm add @codenhub/error

Usage

Configure the app-level AppError.registry during initialization, then normalize thrown or returned unknown values into a predictable error shape.

import { AppError, err, ok, type Result } from "@codenhub/error";

AppError.registry.codes.add("invalid_credentials", {
  message: "Invalid email or password.",
  messageKey: "error.auth.invalidCredentials",
  source: "auth",
});

const signIn = async (): Promise<Result<string>> => {
  try {
    return ok("user-id");
  } catch (error) {
    return err(error);
  }
};

const appError = new AppError({ code: "invalid_credentials" });

console.log(appError.message, appError.messageKey);

Ready registries are opt-in. Merge them into an app-owned registry when the app wants those classifications.

import { AppError } from "@codenhub/error";
import { browserErrorRegistry } from "@codenhub/error/registries/browser";
import { supabaseErrorRegistry } from "@codenhub/error/registries/supabase";

AppError.registry.merge(browserErrorRegistry);
AppError.registry.merge(supabaseErrorRegistry);

Reference

@codenhub/error

Primary entrypoint for app-owned registries, error normalization, and result helpers.

import {
  AppError,
  DEFAULT_APP_ERROR_MESSAGE,
  createErrorRegistry,
  err,
  ok,
  type AppErrorOptions,
  type AppErrorSource,
  type AppErrorType,
  type Err,
  type ErrorFeedback,
  type ErrorPatternDefinition,
  type ErrorPatternRegistryBucket,
  type ErrorPrefixDefinition,
  type ErrorPrefixRegistryBucket,
  type ErrorRegistry,
  type ErrorRegistryBucket,
  type Ok,
  type Result,
} from "@codenhub/error";

Supported import paths:

| Path | Description | | ------------------------------------- | ------------------------------------------------------- | | @codenhub/error | Core error normalization, registry, and result helpers. | | @codenhub/error/registries | Index of opt-in ready registry presets. | | @codenhub/error/registries/browser | Browser and Web API error mappings. | | @codenhub/error/registries/supabase | Supabase error mappings. |

createErrorRegistry()

Creates an empty isolated registry. This is also available as AppError.createRegistry().

function createErrorRegistry(): ErrorRegistry;

Use isolated registries for tests, request scopes, tenant-specific mappings, or integrations where mappings should not use the app-level AppError.registry.

DEFAULT_APP_ERROR_MESSAGE

Default fallback message used when an error has no registry match and no fallbackMessage was provided.

const DEFAULT_APP_ERROR_MESSAGE = "An unexpected error occurred.";

ErrorRegistry

Stores deterministic and heuristic mappings used by AppError.

interface ErrorRegistry {
  codes: ErrorRegistryBucket;
  names: ErrorRegistryBucket;
  messages: ErrorRegistryBucket;
  prefixes: ErrorPrefixRegistryBucket;
  patterns: ErrorPatternRegistryBucket;
  clear(): void;
  merge(registry: ErrorRegistry): void;
}

Code, name, exact message, and prefix matches are deterministic known errors. When multiple prefixes match the same message, the longest normalized prefix wins. Pattern matches are heuristic and should be treated as unexpected errors with better user-facing feedback.

AppError.registry is mutable and starts empty. createErrorRegistry() creates another empty registry with the same bucket API.

Registry buckets support adding one mapping at a time or a tuple list:

interface ErrorRegistryBucket {
  add(identifier: string, feedback: ErrorFeedback): void;
  addList(entries: readonly (readonly [identifier: string, feedback: ErrorFeedback])[]): void;
  clear(): void;
  get(identifier: string): ErrorFeedback | undefined;
  values(): IterableIterator<[string, ErrorFeedback]>;
}

interface ErrorPrefixRegistryBucket {
  add(prefix: string, feedback: ErrorFeedback): void;
  addList(entries: readonly (readonly [prefix: string, feedback: ErrorFeedback])[]): void;
  clear(): void;
  values(): readonly ErrorPrefixDefinition[];
}

interface ErrorPatternRegistryBucket {
  add(pattern: RegExp, feedback: ErrorFeedback): void;
  addList(entries: readonly (readonly [pattern: RegExp, feedback: ErrorFeedback])[]): void;
  clear(): void;
  values(): readonly ErrorPatternDefinition[];
}

values() returns defensive copies. Pattern buckets clone RegExp values so global or sticky regex state does not leak across classifications.

add() and addList() validate entries immediately and throw TypeError for invalid input. Exact and prefix identifiers must be non-empty strings after trimming whitespace and trailing sentence punctuation. Exact identifiers are stored and looked up in that normalized form. Feedback must be an object with a non-empty message; optional messageKey and source values must be strings, and optional retryable must be a boolean. Pattern buckets only accept RegExp patterns.

ErrorFeedback

Feedback stored in registry buckets.

interface ErrorFeedback {
  message: string;
  messageKey?: string;
  source?: string;
  retryable?: boolean;
}

message should be safe to show to users. messageKey, source, and retryable are optional metadata copied onto matched AppError instances.

ErrorPrefixDefinition and ErrorPatternDefinition

Entries returned by prefixes.values() and patterns.values().

interface ErrorPrefixDefinition extends ErrorFeedback {
  prefix: string;
}

interface ErrorPatternDefinition extends ErrorFeedback {
  pattern: RegExp;
}

Most consumers only need these when inspecting, copying, or testing registry contents.

AppError

Normalizes an unknown value into a predictable error object. By default, it classifies errors with AppError.registry.

class AppError extends Error {
  static readonly registry: ErrorRegistry;

  static createRegistry(): ErrorRegistry;

  readonly type: "known" | "unexpected" | "unknown";
  readonly message: string;
  readonly messageKey: string | null;
  readonly source: string | null;
  readonly originalError: unknown;
  readonly retryable: boolean;

  constructor(error: unknown, options?: AppErrorOptions);
}

AppError does not throw during construction. If no registry mapping matches, it uses DEFAULT_APP_ERROR_MESSAGE or fallbackMessage and classifies the value as "unknown".

AppErrorType and AppErrorSource

Reusable property types for consumers that store or pass around normalized error metadata.

type AppErrorType = "known" | "unexpected" | "unknown";
type AppErrorSource = string | null;

AppErrorOptions

interface AppErrorOptions {
  fallbackMessage?: string;
  registry?: ErrorRegistry;
}

| Option | Type | Default | Description | | ----------------- | --------------- | --------------------------- | --------------------------------------------- | | fallbackMessage | string | DEFAULT_APP_ERROR_MESSAGE | Message used when no mapping matches. | | registry | ErrorRegistry | AppError.registry | Registry used to classify the provided error. |

ok()

Creates a successful result.

function ok<T>(value: T): { ok: true; value: T };

The returned shape is also exported as Ok<T>.

err()

Creates a failed result containing an AppError.

function err(error: unknown, options?: AppErrorOptions): { ok: false; error: AppError };

String errors are also used as the fallback message, so err("Missing user id") produces that message when no registry entry matches.

The returned shape is also exported as Err.

Result<T>

Represents success or failure without exceptions.

type Result<T> = { ok: true; value: T } | { ok: false; error: AppError };

@codenhub/error/registries

Index entrypoint for ready registry presets.

import { browserErrorRegistry, supabaseErrorRegistry } from "@codenhub/error/registries";

Ready registries are plain ErrorRegistry values intended to be merged into AppError.registry or another app-owned registry. Importing a preset does not mutate AppError.registry.

The preset registry objects are mutable like any other ErrorRegistry. Treat imported presets as shared read-only inputs and merge them into an app-owned registry before adding app-specific mappings.

@codenhub/error/registries/browser

Browser and Web API error mappings.

import { browserErrorRegistry } from "@codenhub/error/registries/browser";

Use this preset when normalizing DOMException, fetch, storage, abort, permissions, quota, and other browser API errors.

Importing this preset does not require window, document, DOMException, or other browser globals to exist.

@codenhub/error/registries/supabase

Supabase error mappings.

import { supabaseErrorRegistry } from "@codenhub/error/registries/supabase";

Use this preset when normalizing Supabase Auth, PostgREST, Storage, Realtime, and Edge Functions errors.

Importing this preset only creates static error mappings. It does not contact Supabase services or require Supabase client packages.

Examples

Isolate Tests

import { createErrorRegistry, err } from "@codenhub/error";

const errors = createErrorRegistry();

errors.names.add("AbortError", {
  message: "Request cancelled.",
  source: "browser",
});

const result = err(new DOMException("Aborted", "AbortError"), { registry: errors });

Merge Presets

import { AppError } from "@codenhub/error";
import { browserErrorRegistry, supabaseErrorRegistry } from "@codenhub/error/registries";

AppError.registry.merge(browserErrorRegistry);
AppError.registry.merge(supabaseErrorRegistry);

Add Multiple Mappings

import { AppError } from "@codenhub/error";

AppError.registry.codes.addList([
  ["invalid_credentials", { message: "Invalid email or password.", source: "auth" }],
  ["email_not_confirmed", { message: "Email address is not confirmed.", source: "auth" }],
]);

Requirements

  • TypeScript consumers should use moduleResolution: "bundler" or another resolver that understands package exports.
  • The core API is intended to run in browsers, Node, SSR, workers, and edge runtimes.
  • Browser-specific registry presets may reference browser error names and messages, but importing them must not require browser globals to exist.
  • The package has no runtime dependencies.

Notes

  • Registries are opt-in by design. Consumers start from a blank registry to avoid hidden global classifications.
  • Registries, including AppError.registry and ready registry presets, are currently mutable. Configure shared registries during app initialization and avoid mutating imported presets at runtime. A future version is expected to provide stronger mutation safeguards.
  • Preset registries should prefer stable error codes or names over message matching when a library provides them.