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

@dhrupad-sah/exception-catcher

v1.1.1

Published

Automatically catch and report exceptions to Mira Sentinel with rich context and Loki log integration

Readme

@dhrupad-sah/exception-catcher

Automatically catch and report exceptions to Mira Sentinel with rich context and Loki log integration for AI-powered debugging and automatic fix generation.

Features

  • 🚨 Automatic Exception Catching - Monitors uncaught exceptions and unhandled rejections
  • 📊 Rich Context - Collects system info, memory usage, and custom context
  • 🔍 Loki Integration - Correlates exceptions with log data for enhanced debugging
  • 🤖 AI-Powered Fixes - Integrates with Claude Code for automatic issue resolution
  • 📋 GitHub Integration - Automatically creates issues and pull requests
  • 🔄 Retry Logic - Robust error reporting with configurable retries
  • 🎯 Flexible Filtering - Custom error filtering and context enrichment

Installation

npm install @dhrupad-sah/exception-catcher

Quick Start

Fastify Integration (Recommended for APIs)

import Fastify from 'fastify'
import { fastifyMiraSentinel } from '@dhrupad-sah/exception-catcher'

const fastify = Fastify({ logger: true })

// Register the plugin - automatically handles all HTTP route exceptions
await fastify.register(fastifyMiraSentinel, {
  sentinelUrl: process.env.MIRA_SENTINEL_URL!,
  serviceName: 'api-service',
  repo: 'company/api-service',
  
  // Optional: Skip client errors
  skipStatusCodes: [400, 401, 403, 404],
  
  // Optional: Extract custom context
  extractRequestContext: (request) => ({
    userId: request.headers['x-user-id'],
    traceId: request.headers['x-trace-id']
  })
})

// Your routes - exceptions are automatically caught and reported
fastify.get('/users/:id', async (request, reply) => {
  const user = await getUser(request.params.id) // Any error here is caught
  return user
})

await fastify.listen({ port: 3000 })

Basic Usage (Non-Fastify Apps)

import { MiraSentinelExceptionCatcher } from '@dhrupad-sah/exception-catcher'

const catcher = new MiraSentinelExceptionCatcher({
  sentinelUrl: 'https://your-sentinel-instance.com',
  serviceName: 'api-service',
  repo: 'company/api-service'
})

// Initialize and start monitoring
catcher.initialize()

// That's it! All exceptions are now automatically caught and reported

Environment-Based Auto-Initialization

import { autoInitialize } from '@dhrupad-sah/exception-catcher'

// Set environment variables:
// MIRA_SENTINEL_URL=https://your-sentinel-instance.com
// MIRA_SERVICE_NAME=api-service  
// MIRA_REPO=company/api-service

const catcher = autoInitialize()
// Automatically initializes if environment variables are set

Advanced Configuration

import { MiraSentinelExceptionCatcher } from '@dhrupad-sah/exception-catcher'

const catcher = new MiraSentinelExceptionCatcher({
  sentinelUrl: 'https://your-sentinel-instance.com',
  serviceName: 'api-service',
  repo: 'company/api-service',
  apiKey: 'your-api-key', // Optional authentication
  
  // Custom error filtering
  shouldCatchError: (error) => {
    // Skip test errors
    return !error.message.includes('test')
  },
  
  // Enrich context with custom data
  enrichContext: (error, context) => {
    return {
      userId: getCurrentUserId(),
      requestId: getCurrentRequestId(),
      version: process.env.APP_VERSION
    }
  },
  
  // Configure retries
  retry: {
    attempts: 5,
    delay: 2000
  }
})

catcher.initialize()

Manual Exception Reporting

try {
  // Some risky operation
  await processPayment(paymentData)
} catch (error) {
  // Manually report with additional context
  await catcher.reportException(error, {
    context: {
      paymentId: paymentData.id,
      userId: paymentData.userId,
      amount: paymentData.amount
    },
    tags: ['payment', 'critical'],
    severity: 'high'
  })
  
  throw error // Re-throw if needed
}

Event Handling

catcher.on('exception-caught', (error, context) => {
  console.log('Exception caught:', error.message)
})

catcher.on('exception-sent', (context, response) => {
  console.log('Exception reported:', response.jobId)
})

catcher.on('exception-failed', (error, context, reason) => {
  console.error('Failed to report exception:', reason)
})

Integration with Express.js

import express from 'express'
import { MiraSentinelExceptionCatcher } from '@dhrupad-sah/exception-catcher'

const app = express()

const catcher = new MiraSentinelExceptionCatcher({
  sentinelUrl: process.env.MIRA_SENTINEL_URL!,
  serviceName: 'express-api',
  repo: 'company/express-api',
  
  // Enrich with Express context
  enrichContext: (error, context) => {
    const req = (error as any).req
    return req ? {
      method: req.method,
      url: req.url,
      headers: req.headers,
      userAgent: req.get('User-Agent'),
      ip: req.ip
    } : {}
  }
})

catcher.initialize()

// Your routes here
app.get('/api/users', async (req, res) => {
  try {
    const users = await getUsers()
    res.json(users)
  } catch (error) {
    // Attach request context to error
    ;(error as any).req = req
    
    // Report with additional context
    await catcher.reportException(error as Error, {
      context: {
        endpoint: '/api/users',
        method: req.method,
        query: req.query
      },
      tags: ['api', 'users']
    })
    
    res.status(500).json({ error: 'Internal server error' })
  }
})

app.listen(3000)

Integration with Fastify

Option 1: Fastify Plugin (Recommended)

import Fastify from 'fastify'
import { fastifyMiraSentinel } from '@dhrupad-sah/exception-catcher'

const fastify = Fastify({ logger: true })

// Register the plugin - automatically handles all HTTP route exceptions
await fastify.register(fastifyMiraSentinel, {
  sentinelUrl: process.env.MIRA_SENTINEL_URL!,
  serviceName: 'fastify-api',
  repo: 'company/fastify-api',
  
  // Optional configurations
  includeHeaders: true,
  includeBody: false, // Be careful with sensitive data
  skipStatusCodes: [400, 401, 403, 404], // Don't report client errors
  
  // Custom request context extraction
  extractRequestContext: (request) => ({
    userId: request.headers['x-user-id'],
    tenantId: request.headers['x-tenant-id'],
    traceId: request.headers['x-trace-id']
  })
})

// Your routes - exceptions are automatically caught and reported
fastify.get('/users/:id', async (request, reply) => {
  const user = await getUser(request.params.id) // Any error here is caught
  return user
})

// Manual exception reporting is also available
fastify.get('/manual-report', async (request, reply) => {
  try {
    await riskyOperation()
  } catch (error) {
    await fastify.miraSentinel.reportException(error, {
      context: { operation: 'risky' }
    })
    throw error // Re-throw to send HTTP error response
  }
})

await fastify.listen({ port: 3000 })

Option 2: Manual Integration

import Fastify from 'fastify'
import { MiraSentinelExceptionCatcher } from '@dhrupad-sah/exception-catcher'

const fastify = Fastify({ logger: true })

const catcher = new MiraSentinelExceptionCatcher({
  sentinelUrl: process.env.MIRA_SENTINEL_URL!,
  serviceName: 'fastify-api',
  repo: 'company/fastify-api'
})

catcher.initialize()

// Global error handler
fastify.setErrorHandler(async (error, request, reply) => {
  await catcher.reportException(error, {
    context: {
      method: request.method,
      url: request.url,
      params: request.params,
      query: request.query,
      headers: request.headers
    },
    tags: ['fastify', 'api-error']
  })
  
  reply.status(500).send({ error: 'Internal Server Error' })
})

fastify.listen({ port: 3000 })

Environment Variables

| Variable | Description | Required | |----------|-------------|----------| | MIRA_SENTINEL_URL | URL of your Mira Sentinel instance | Yes | | MIRA_SERVICE_NAME | Name of your service | Yes | | MIRA_REPO | GitHub repository (owner/repo) | Yes | | MIRA_API_KEY | API key for authentication | No | | MIRA_ENABLED | Enable/disable (default: true) | No |

Configuration Options

| Option | Type | Description | Default | |--------|------|-------------|---------| | sentinelUrl | string | Mira Sentinel instance URL | Required | | serviceName | string | Service name for Loki correlation | Required | | repo | string | GitHub repository (owner/repo) | Required | | apiKey | string | Optional API key | undefined | | enabled | boolean | Enable/disable catching | true | | timeout | number | HTTP timeout (ms) | 10000 | | shouldCatchError | function | Custom error filter | () => true | | enrichContext | function | Custom context enrichment | () => ({}) | | retry.attempts | number | Retry attempts | 3 | | retry.delay | number | Retry delay (ms) | 1000 |

How It Works

  1. Exception Occurs - Your service throws an exception
  2. Context Collection - Rich context is automatically collected:
    • Error message and stack trace
    • System information (Node.js version, memory, CPU)
    • Timestamp for Loki correlation
    • Custom context from your application
  3. Sent to Mira Sentinel - Exception data is sent to your Sentinel instance
  4. Loki Integration - Sentinel queries Loki logs around the exception time
  5. AI Analysis - Claude Code analyzes the exception + log context
  6. GitHub Integration - Issue and PR are automatically created
  7. Timeline Analysis - Full timeline of events leading to the exception

Best Practices

1. Service Naming

Use consistent service names that match your Loki log labels:

// Good - matches Loki service label
serviceName: 'api-gateway'

// Bad - doesn't match logs
serviceName: 'my-awesome-service'

2. Error Filtering

Filter out noise to focus on actionable exceptions:

shouldCatchError: (error) => {
  // Skip test environments
  if (process.env.NODE_ENV === 'test') return false
  
  // Skip known non-critical errors
  if (error.message.includes('ECONNRESET')) return false
  
  // Skip client errors (4xx)
  if (error.name === 'ValidationError') return false
  
  return true
}

3. Context Enrichment

Add meaningful context for better debugging:

enrichContext: (error, context) => {
  return {
    // Business context
    tenantId: getCurrentTenant(),
    feature: getCurrentFeature(),
    
    // Technical context
    version: process.env.APP_VERSION,
    deployment: process.env.DEPLOYMENT_ID,
    
    // Performance context
    responseTime: getResponseTime(),
    queueSize: getQueueSize()
  }
}

4. Graceful Shutdown

Always clean up on process exit:

const catcher = new MiraSentinelExceptionCatcher(config)
catcher.initialize()

process.on('SIGTERM', () => {
  catcher.shutdown()
  process.exit(0)
})

Testing

Test your integration:

const catcher = new MiraSentinelExceptionCatcher(config)
catcher.initialize()

// Test connection
const isConnected = await catcher.testConnection()
console.log('Connected:', isConnected)

// Test exception reporting
await catcher.reportException(new Error('Test error'), {
  context: { test: true },
  tags: ['test']
})

License

MIT

Support

For support, please create an issue in the GitHub repository.