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

unified-error-handling

v2.1.0

Published

A lightweight, zero-dependency error handling library with dynamic adapter loading for multiple error tracking services

Readme

Unified Error Handling

npm version License: MIT Bundle Size

A lightweight, zero-dependency error handling library with dynamic adapter loading for multiple error tracking services. Works everywhere - browsers, Node.js, React, and more.

Features

  • 🚀 Zero Dependencies - Core library has no dependencies
  • 🔌 Dynamic Adapter Loading - Only load SDKs when you use them
  • 🎯 Provider-less Architecture - No React Context required, works in any component
  • 📦 Tree-shakeable - Only bundle what you use
  • 🔧 Framework Agnostic - Works with React, Vue, Angular, or vanilla JS
  • 🌐 Universal - Works in browsers, Node.js, React Native
  • 🎨 Customizable - Create your own adapters easily
  • 📊 Rich Context - Automatic breadcrumbs, user context, and device info
  • 🔄 Offline Support - Queue errors when offline, send when back online
  • 🛡️ Type Safe - Full TypeScript support

Installation

npm install unified-error-handling
# or
yarn add unified-error-handling
# or
pnpm add unified-error-handling

Quick Start

Basic Usage (Vanilla JavaScript)

import { initialize, captureError, useAdapter } from 'unified-error-handling';

// Initialize the error store
initialize({
  enableGlobalHandlers: true,
  enableConsoleCapture: true
});

// Use the built-in console adapter
await useAdapter('console');

// Capture errors
try {
  throw new Error('Something went wrong!');
} catch (error) {
  captureError(error);
}

React Usage

import { initialize, useAdapter } from 'unified-error-handling';
import { ErrorBoundary, useErrorHandler } from 'unified-error-handling/react';

// Initialize once in your app
initialize({ enableGlobalHandlers: true });

// In your App component
function App() {
  useEffect(() => {
    useAdapter('sentry', { dsn: 'your-sentry-dsn' });
  }, []);

  return (
    <ErrorBoundary>
      <YourApp />
    </ErrorBoundary>
  );
}

// In any component (no provider needed!)
function MyComponent() {
  const handleError = useErrorHandler();

  const handleClick = () => {
    try {
      // risky operation
    } catch (error) {
      handleError(error);
    }
  };

  return <button onClick={handleClick}>Click me</button>;
}

Supported Adapters

All adapters are loaded dynamically - SDKs are only loaded when you use them. The required SDKs are not bundled with this library.

| Adapter | Package Required | Description | |---------|------------------|-------------| | console | None (built-in) | Logs errors to console (great for development) | | sentry | @sentry/browser | Sentry error tracking | | firebase | firebase | Firebase Crashlytics | | datadog | @datadog/browser-rum + @datadog/browser-logs | DataDog RUM & Logs | | bugsnag | @bugsnag/js | Bugsnag error monitoring | | rollbar | rollbar | Rollbar error tracking | | logrocket | logrocket | LogRocket session replay | | raygun | raygun4js | Raygun crash reporting | | appcenter | appcenter-crashes + appcenter-analytics | Microsoft AppCenter |

Using Adapters

// Console adapter (no SDK needed)
await useAdapter('console');

// Sentry adapter
await useAdapter('sentry', {
  dsn: 'your-sentry-dsn',
  environment: 'production'
});

// Firebase adapter
await useAdapter('firebase', {
  firebaseConfig: { /* your firebase config */ }
});

// DataDog adapter
await useAdapter('datadog', {
  applicationId: 'your-app-id',
  clientToken: 'your-client-token',
  site: 'datadoghq.com'
});

// Bugsnag adapter
await useAdapter('bugsnag', {
  apiKey: 'your-api-key'
});

// Rollbar adapter
await useAdapter('rollbar', {
  accessToken: 'your-access-token'
});

// LogRocket adapter
await useAdapter('logrocket', {
  appId: 'your-app-id'
});

// Raygun adapter
await useAdapter('raygun', {
  apiKey: 'your-api-key'
});

// AppCenter adapter
await useAdapter('appcenter', {
  appSecret: 'your-app-secret'
});

// Switch adapters (last one becomes active)
await useAdapter('console'); // for development
await useAdapter('sentry', config); // switches to Sentry

Creating Custom Adapters

import { createAdapter } from 'unified-error-handling';

createAdapter('my-service', {
  async initialize(config) {
    // Setup your service
  },
  
  async send(error, context) {
    // Send error to your service
    await fetch('https://my-api.com/errors', {
      method: 'POST',
      body: JSON.stringify({ error, context })
    });
  }
});

// Use your custom adapter
await useAdapter('my-service', { apiKey: 'secret' });

API Reference

Core Functions

initialize(config)

Initialize the error store with configuration.

initialize({
  maxBreadcrumbs: 100,        // Maximum breadcrumbs to keep
  enableGlobalHandlers: true,  // Catch unhandled errors
  enableConsoleCapture: true,  // Capture console.error
  enableNetworkCapture: true,  // Capture failed network requests
  beforeSend: (error) => {     // Filter or modify errors
    if (error.message.includes('ignore')) {
      return null; // Don't send
    }
    return error;
  }
});

captureError(error, context?)

Capture an error with optional context.

captureError(new Error('Oops!'), {
  tags: { feature: 'checkout' },
  extra: { orderId: '12345' }
});

captureMessage(message, level?)

Capture a message.

captureMessage('User completed onboarding', 'info');

setUser(user)

Set user context.

setUser({
  id: '12345',
  email: '[email protected]',
  plan: 'premium'
});

addBreadcrumb(breadcrumb)

Add a breadcrumb.

addBreadcrumb({
  message: 'User clicked button',
  category: 'ui',
  level: 'info',
  data: { buttonId: 'submit' }
});

React Hooks

useErrorHandler()

Returns a function to capture errors.

const handleError = useErrorHandler();
handleError(error);

useErrorStore()

Access the full error store.

const { setUser, addBreadcrumb } = useErrorStore();

useAsyncOperation()

Handle async operations with automatic error capture.

const { data, loading, error, execute } = useAsyncOperation(
  async () => fetch('/api/data'),
  [dependency]
);

Advanced Features

Offline Support

Errors are automatically queued when offline and sent when connection is restored.

Error Enrichment

Errors are automatically enriched with:

  • Device information
  • Browser/environment details
  • Stack trace parsing
  • Fingerprinting for grouping
  • Timestamp and context

Console & Network Capture

When enabled, automatically captures:

  • console.error calls
  • Failed network requests (fetch & XHR)
  • Unhandled promise rejections
  • Global errors

TypeScript Support

Full TypeScript support with type definitions included.

import { ErrorContext, NormalizedError } from 'unified-error-handling';

const context: ErrorContext = {
  user: { id: '123' },
  tags: { version: '1.0.0' }
};

Bundle Size

  • Core: ~10KB minified
  • React integration: ~5KB minified
  • Zero dependencies in production

Migration Guide

From Capacitor Plugin

// Before (Capacitor plugin)
import { UnifiedErrorHandling } from 'capacitor-unified-error-handling';
await UnifiedErrorHandling.initialize({ provider: 'sentry' });

// After (New library)
import { initialize, useAdapter } from 'unified-error-handling';
initialize();
await useAdapter('sentry', config);

From React Context

// Before (Context-based)
<ErrorProvider>
  <App />
</ErrorProvider>

// After (No provider needed!)
// Just initialize once
initialize();

// Use anywhere
const handleError = useErrorHandler();

License

MIT © Ahsan Mahmood

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

Support