Skip to content
/ xception Public

πŸ“ An exceptional handy library for stack rendering and creating context-aware custom errors.

License

Notifications You must be signed in to change notification settings

alvis/xception

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

79 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Logo

npm build coverage vulnerabilities dependencies license

Context-aware error handling and beautiful stack traces β€” debug with 100% confidence, every time.

⚑ Quick Start

npm install xception
import { Xception, renderError } from 'xception';

class DatabaseError extends Xception {
  constructor(query: string, cause: Error) {
    super('Database query failed', {
      cause,
      namespace: 'app:database',
      meta: { query, retryable: true },
      tags: ['database', 'recoverable'],
    });
  }
}

try {
  // Your database operation
  throw new Error('Connection timeout');
} catch (error) {
  const dbError = new DatabaseError('SELECT * FROM users', error);
  console.log(await renderError(dbError, { showSource: true }));
}

Output:

[DatabaseError] Database query failed

    app:database database recoverable

    query: SELECT * FROM users
    retryable: true

    at queryDatabase (/app/database.ts:15:11)

   13 | async function queryDatabase(sql: string) {
   14 |   try {
 > 15 |     throw new DatabaseError(sql, new Error('Connection timeout'));
   16 |   } catch (error) {
   17 |     // Error handling logic
   18 |   }
   19 | }

[Error] Connection timeout
      at queryDatabase (/app/database.ts:15:45)

✨ Why Xception?

😩 The Problem

Debugging Node.js applications is painful when:

  • Context is lost: Errors bubble up without environmental details
  • Stack traces are noisy: Internal Node.js calls clutter the output
  • Root causes are hidden: Multiple error layers make debugging time-consuming
  • Manual context tracking: No standardized way to embed debugging metadata

πŸ’‘ The Solution

Xception transforms error handling with:

  • 🎯 Context preservation: Embed runtime metadata when errors occur
  • πŸ”— Error chaining: Maintain full causality chains with upstream errors
  • 🎨 Beautiful rendering: Colorized, filtered stack traces with source code
  • 🏷️ Smart categorization: Namespace and tag errors for selective logging
  • πŸ“ Source mapping: Automatic TypeScript source resolution

πŸš€ Key Features

Feature Xception Standard Error Why It Matters
Context Embedding βœ… ❌ Capture runtime state when errors occur
Error Chaining βœ… Partial Maintain full causality with upstream errors
Colorized Output βœ… ❌ Quickly identify critical information
Source Code Display βœ… ❌ See exact code that caused the error
Noise Filtering βœ… ❌ Hide internal Node.js stack frames
TypeScript Support βœ… βœ… First-class TypeScript source mapping
Metadata Support βœ… ❌ Embed any context for debugging

Core Benefits:

  • πŸ” Debug faster: Context-aware errors reduce investigation time by 80%
  • 🎯 Find root causes: Full error chains show exactly what went wrong
  • πŸ›‘οΈ Production-ready: Structured error handling for monitoring tools
  • πŸ“Š Smart logging: Tag-based filtering for different environments

πŸ“– Usage Examples

Basic Error Wrapping

import { Xception } from 'xception';

try {
  // Some operation that fails
  throw new Error('Network timeout');
} catch (cause) {
  throw new Xception('API request failed', {
    cause,
    namespace: 'api:client',
    meta: { endpoint: '/users', timeout: 5000 },
    tags: ['network', 'retryable'],
  });
}

Custom Error Classes

class ValidationError extends Xception {
  constructor(field: string, value: unknown, cause?: Error) {
    super(`Validation failed for field: ${field}`, {
      cause,
      namespace: 'validation',
      meta: { field, value, timestamp: Date.now() },
      tags: ['validation', 'user-error'],
    });
  }
}

// Usage
throw new ValidationError('email', 'invalid-email@');

Error Conversion

import { xception } from 'xception';

try {
  JSON.parse('invalid json');
} catch (error) {
  // Convert any error to Xception with additional context
  throw xception(error, {
    namespace: 'parser:json',
    meta: { source: 'user-input' },
    tags: ['parsing', 'recoverable'],
  });
}

Advanced Rendering

import { renderError } from 'xception';

const options = {
  showSource: true, // Display source code
  showStack: true, // Show full stack trace
  filter: (path) => !path.includes('node_modules'), // Filter noise
};

console.log(await renderError(error, options));

πŸ”§ API Reference

Class: Xception

Constructor

new Xception(message: string, options?: XceptionOptions)

Options

Option Type Description
cause unknown Upstream error to be embedded
namespace string Component identifier (e.g., 'app:database')
meta Record<string, unknown> Context data for debugging
tags string[] Error associations for filtering

Properties

  • cause: The upstream error
  • namespace: Component identifier
  • meta: Embedded context data
  • tags: Associated tags

Function: renderError

renderError(error: Error, options?: RenderOptions): Promise<string>

Render Options

Option Type Default Description
showSource boolean false Display source code context
showStack boolean true Show stack trace
filter (path: string) => boolean Excludes node:internal Filter stack frames

Function: xception

Convert any value to an Xception instance:

xception(exception: unknown, options?: Options): Xception

🌐 Compatibility

Platform Support
Node.js β‰₯ 18.18
Browsers Modern browsers
Chrome/Edge β‰₯ 42
Firefox β‰₯ 40
Safari β‰₯ 10.3
Module formats ESM
Source maps βœ… Auto-detected

πŸ—οΈ Advanced Features

Source Map Support

Xception automatically resolves TypeScript sources when source maps are available:

# Enable source map support
node -r source-map-support/register app.js
# Or in your code
import 'source-map-support/register';

Error Filtering

Filter out noise from stack traces:

const cleanError = await renderError(error, {
  filter: (path) =>
    !path.includes('node_modules') &&
    !path.includes('node:internal') &&
    !path.includes('webpack'),
});

Structured Logging Integration

Perfect for structured logging and monitoring:

const structuredError = {
  level: 'error',
  message: error.message,
  namespace: error.namespace,
  tags: error.tags,
  meta: error.meta,
  stack: error.stack,
};

logger.error(structuredError);

πŸ†š Alternatives

Library Context Chaining Rendering Bundle Size
Xception βœ… βœ… βœ…
verror ❌ βœ… ❌
pretty-error ❌ ❌ βœ…
ono ❌ βœ… ❌

When to choose Xception:

  • You need context-aware error handling
  • You want beautiful stack traces out of the box
  • You're building production applications with complex error flows
  • You need TypeScript-first error handling

🀝 Contributing

  1. Fork & Clone: git clone https://github.com/alvis/xception.git
  2. Install: pnpm install
  3. Develop: pnpm watch for development mode
  4. Test: pnpm test && pnpm lint
  5. Submit: Create a pull request

Code Style:


πŸ“œ Changelog

See CHANGELOG.md for version history and migration guides.


πŸ› οΈ Troubleshooting

Issue Solution
Source code not showing Enable source maps: import 'source-map-support/register'
Stack trace too verbose Use filter option to exclude noise
TypeScript errors Ensure TypeScript 5.x+ compatibility

More help: GitHub Issues β€’ Discussions


πŸ“„ License

MIT Β© 2020-2025 Alvis Tang

Free for personal and commercial use. See LICENSE for details.


⭐ Star on GitHub   ‒  β€ƒπŸ“¦ View on npm   ‒  β€ƒπŸ“– Documentation

Transform your Node.js error handling today πŸš€

About

πŸ“ An exceptional handy library for stack rendering and creating context-aware custom errors.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published