npm.io
1.0.13 • Published 7 months ago

@visulima/error-handler

Licence
MIT
Version
1.0.13
Deps
7
Size
63 kB
Vulns
0
Weekly
0
Stars
38

visulima error-handler

Error handlers for use in development and production environments.


typescript-image npm-image license-image


Daniel Bannert's open source work is supported by the community on GitHub Sponsors


Install

npm install @visulima/error-handler
yarn add @visulima/error-handler
pnpm add @visulima/error-handler

Features

  • Content Negotiation - Automatically serves HTML, JSON, Problem JSON, or JSON:API based on Accept header
  • Framework Agnostic - Works with Node.js HTTP, Express, Fastify, Koa, Hono, and any Fetch-based runtime
  • Production Ready - Configurable error pages, trace control, and custom handlers
  • TypeScript Support - Full type safety with comprehensive TypeScript definitions
  • Extensible - Custom error handlers via regex matching on Accept headers
  • CSP Support - Built-in Content Security Policy nonce support for inline styles

Quick Start

Node.js HTTP Server
import { createServer } from "node:http";
import httpHandler from "@visulima/error-handler/handler/http/node";

const server = createServer(async (req, res) => {
    try {
        // your app logic...
        throw new Error("Boom!");
    } catch (error) {
        const handler = await httpHandler(error as Error, {
            showTrace: process.env.NODE_ENV !== "production",
        });
        return handler(req, res);
    }
});

server.listen(3000);
Express Setup
import express from "express";
import httpHandler from "@visulima/error-handler/handler/http/node";

const app = express();
app.use(express.json());

app.get("/", async (req, res) => {
    try {
        throw new Error("Example error");
    } catch (error) {
        const handler = await httpHandler(error as Error, {
            showTrace: process.env.NODE_ENV !== "production",
        });
        return handler(req, res);
    }
});

app.listen(3000);
Hono (Fetch Runtime)
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import fetchHandler from "@visulima/error-handler/handler/fetch";

const app = new Hono();

app.get("/", (c) => c.text("OK"));
app.get("/error", () => {
    throw new Error("Boom from Hono");
});

app.onError(async (error, c) => {
    const handler = await fetchHandler(error as Error, {
        showTrace: process.env.NODE_ENV !== "production",
    });
    return handler(c.req.raw);
});

serve({ fetch: app.fetch, port: 3000 });
Fetch-based Runtimes
// Cloudflare Workers
import fetchHandler from "@visulima/error-handler/handler/fetch";

export default {
    async fetch(request: Request): Promise<Response> {
        try {
            throw new Error("Boom");
        } catch (error) {
            const handler = await fetchHandler(error as Error, {
                showTrace: process.env.NODE_ENV !== "production",
            });
            return handler(request);
        }
    },
};
// Deno
import fetchHandler from "@visulima/error-handler/handler/fetch";

Deno.serve(async (request: Request) => {
    try {
        throw new Error("Boom");
    } catch (error) {
        const handler = await fetchHandler(error as Error, {
            showTrace: process.env.NODE_ENV !== "production",
        });
        return handler(request);
    }
});

Content Negotiation

The error handler automatically serves different content types based on the Accept header:

  • text/html → HTML error page
  • application/problem+json → Problem JSON (RFC 7807)
  • application/json → Simple JSON response
  • application/vnd.api+json → JSON:API format
  • text/plain → Plain text
  • application/javascript → JavaScript error throw
Custom Handlers

Add custom handlers for specific content types:

import httpHandler from "@visulima/error-handler/handler/http/node";

const handler = await httpHandler(error, {
    extraHandlers: [
        {
            regex: /application\/yaml/u,
            handler: (error, req, res) => {
                res.setHeader("content-type", "application/yaml");
                res.end(`error: ${error.message}`);
            },
        },
    ],
});

API

httpHandler(error, options?) => Promise<(req, res) => Promise>

Node.js HTTP handler for Express, Connect, Fastify, Koa, and similar frameworks.

Parameters:

  • error: Error - The error to handle
  • options?: HtmlErrorHandlerOptions & { showTrace?: boolean; extraHandlers?: ErrorHandlers }

Options:

  • showTrace?: boolean - Include stack trace in responses (default: true)
  • extraHandlers?: ErrorHandlers - Custom handlers for specific Accept headers
  • errorPage?: string | ((params) => string | Promise<string>) - Custom HTML error page
  • cspNonce?: string - Content Security Policy nonce for inline styles
  • onError?: (error, request, response) => void | Promise<void> - Callback for custom error logging
fetchHandler(error, options?) => Promise<(request) => Promise>

Fetch API handler for Cloudflare Workers, Deno, Bun, and other Fetch-based runtimes.

Parameters:

  • error: Error - The error to handle
  • options?: HtmlErrorHandlerOptions & { showTrace?: boolean; extraHandlers?: FetchErrorHandlers }

Options:

  • Same as httpHandler but uses FetchErrorHandlers for custom handlers
  • onError?: (error, request, response) => void | Promise<void> - Callback for custom error logging
Error Handler Types
type ErrorHandlers = {
    handler: ErrorHandler;
    regex: RegExp;
}[];

type FetchErrorHandlers = {
    handler: FetchErrorHandler;
    regex: RegExp;
}[];

type HtmlErrorHandlerOptions = {
    errorPage?:
        | string
        | ((params: {
              error: Error;
              request: IncomingMessage;
              response: ServerResponse;
              reasonPhrase: string;
              statusCode: number;
          }) => string | Promise<string>);
    cspNonce?: string;
    onError?: (error: Error, request: IncomingMessage, response: ServerResponse) => void | Promise<void>;
};

Content Negotiation Examples

Basic Usage
import { createServer } from "node:http";
import httpHandler from "@visulima/error-handler/handler/http/node";

const server = createServer(async (req, res) => {
    try {
        throw new Error("Test error");
    } catch (error) {
        const handler = await httpHandler(error as Error, {
            showTrace: process.env.NODE_ENV !== "production",
        });
        return handler(req, res);
    }
}).listen(3000);
With Custom HTML Error Page
import httpHandler from "@visulima/error-handler/handler/http/node";

const handler = await httpHandler(error, {
    errorPage: ({ error, statusCode }) =>
        `<!DOCTYPE html>
        <html>
        <head><title>Error ${statusCode}</title></head>
        <body>
            <h1>Error ${statusCode}</h1>
            <p>${error.message}</p>
        </body>
        </html>`,
    showTrace: false,
});
With CSP Nonce Support
import httpHandler from "@visulima/error-handler/handler/http/node";

const handler = await httpHandler(error, {
    cspNonce: "nonce-abc123", // Will be added to <style> tags
    showTrace: process.env.NODE_ENV !== "production",
});
With Custom Error Logging
import httpHandler from "@visulima/error-handler/handler/http/node";

const handler = await httpHandler(error, {
    onError: (error, request, response) => {
        // Log to your preferred logging service
        console.error(`[${new Date().toISOString()}] ${request.method} ${request.url} - ${error.message}`);

        // Or send to external logging service
        // logToService({ error: error.message, url: request.url, method: request.method });
    },
    showTrace: process.env.NODE_ENV !== "production",
});

Additional Exports

This package provides additional exports for different use cases:

Runtime-Specific Handlers

For convenience, you can also import runtime-specific handlers:

// Deno
import fetchHandler from "@visulima/error-handler/handler/http/deno";

// Bun
import fetchHandler from "@visulima/error-handler/handler/http/bun";

// Cloudflare Workers
import fetchHandler from "@visulima/error-handler/handler/http/cloudflare";

// Edge Runtime
import fetchHandler from "@visulima/error-handler/handler/http/edge";

// Hono
import fetchHandler from "@visulima/error-handler/handler/http/hono";

// CLI applications
import cliHandler from "@visulima/error-handler/handler/cli";
Individual Error Handlers

You can also import individual error handlers for specific content types:

import { htmlErrorHandler } from "@visulima/error-handler/error-handler/html";
import { problemErrorHandler } from "@visulima/error-handler/error-handler/problem";
import { jsonErrorHandler } from "@visulima/error-handler/error-handler/json";
import { jsonapiErrorHandler } from "@visulima/error-handler/error-handler/jsonapi";
import { textErrorHandler } from "@visulima/error-handler/error-handler/text";
import { jsonpErrorHandler } from "@visulima/error-handler/error-handler/jsonp";
import { xmlErrorHandler } from "@visulima/error-handler/error-handler/xml";
Main Export
import { createNegotiatedErrorHandler } from "@visulima/error-handler";

Supported Node.js Versions

Libraries in this ecosystem make the best effort to track Node.js’ release schedule. Here’s a post on why we think this is important.

Contributing

If you would like to help take a look at the list of issues and check our Contributing guidelines.

Note: please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Credits

License

The visulima error-handler is open-sourced software licensed under the MIT

Keywords