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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@byloth/exceptions

v2.3.0

Published

Handle exceptions with ease, create better stacktraces and manage everything in the right place. ❌

Downloads

71

Readme

Exceptions ❌

NPM release GPR release

Handle exceptions with ease, create better stacktraces and manage everything in the right place.

Summary

Installation

npm install --save-dev @byloth/exceptions

Main concepts

Chained exceptions

This library allows you to create a chain of exceptions -just like you can already do with other programming languages- so you can easily know which error caused which exception, where it was thrown and what was the original cause.

At the same time, you can also provide to the user a more friendly error message without losing the original information of the error itself, extremely useful for debugging purposes.

import { Exception } from '@byloth/exceptions';

try {
    // [...]
} catch (error) {
    // [...]

    throw new Exception("I wasn't able to retrieve the current user information. Please, try again later.", error);
}

The above code might throw an exception like this:

Uncaught Exception: I wasn't able to retrieve the current user information. Please, try again later.
    at @example/store/user.ts:37:15
    at @example/main.ts:23:17

Caused by HttpException: HTTP Error 500 (Internal Server Error) for URL 'https://example.com/api/v1/users'
    at @example/services/http.ts:33:9
    at @example/models/user.ts:47:17
    at @example/store/user.ts:12:9
    at @example/main.ts:23:17

Caused by Error: Internal Server Error
    at node_modules/a-random-http-library/_internals/fetch.js:2:354
    at node_modules/a-random-http-library/index.js:1:756
    at @example/services/http.ts:15:11
    at @example/models/user.ts:47:17
    at @example/store/user.ts:12:9
    at @example/main.ts:23:17

So much better, isn't it? 😎

Typed exceptions

JavaScript cannot handle multiple types of exceptions, by design.
Unlike other languages, it doesn't allow you using multiple catch blocks to differentiate your handler logic.

How many times, while developing, have you caught an exception and then checked the error message / type to know what to do next?
Of course, forced to write a lot of if - else statements to handle all the different cases.

Is it boring, right? 😴

This library allows you to build your own exception handlers, so you can easily handle different types of exceptions in a more elegant way.

import { HandlerBuilder } from '@byloth/exceptions';
import { useVuert } from '@byloth/vuert';

import { HttpException, NetworkException, UnauthorizedException } from '@example/exceptions/http';

try {
    // [...]
} catch (error) {
    // Here `error` is of type `unknown`.

    const vuert = useVuert();
    const handler = new HandlerBuilder()
        .on(UnauthorizedException, (exc) => {
            // If `error` is of type `UnauthorizedException`,
            //  then this block will be executed with `exc`
            //  as `error` casted to `UnauthorizedException`.

            vuert.emit({
                type: 'error',
                icon: 'circle-xmark',
                title: "Unauthorized",
                message: "You're not authorized to access this resource. Please, login first.",
                dismissable: true
            });
        })
        .on([HttpException, NetworkException], (exc) => {
            // If `error` is of type `HttpException` or `NetworkException`,
            //  then this block will be executed with `exc` as `error`
            //  casted to `HttpException | NetworkException`.

            vuert.emit({
                type: 'error',
                icon: 'link-slash',
                title: "Communication error",
                message: "There was an error while trying to access the server. Please, try again later.",
                dismissable: true
            });
        })
        .default((exc) => {
            // If `error` is none of the above types,
            //  then this block will be executed with
            //  `exc` as `error` casted to `unknown`.

            vuert.emit({
                type: 'error',
                icon: 'bug',
                title: "Unknown error",
                message: "Something unexpected went wrong. Please, contact our support team.",
                dismissable: true
            });
        });

    handler.handle(error);
}

Handled exceptions

Let's say you are developing your web application and you want to handle errors in a smart way.

The first thing you might think of is to centralize all the error handling logic in a single place, so you can easily maintain it.
To be sure that you're catching all the errors, you place this logic at the outermost level of your application.

Unfortunately, after a while, you start to realize that -in some cases- you can't simply propagate the errors at the top level because you need to handle them in some middle layer of your application to perform some other specific operations before actually propagating them.
To make things worse, you have also to provide some specific output to the user making the default error handling logic redundant and annoying for the user.

At this point, you might think of a solution to handle the errors directly in the middle layer of your application, without propagating them to the top level; but, how can you do that without duplicating the error handling logic?

Here comes the new HandledException class instroduced by this library.
It allows you to handle an exception in whatever place of your application you want, performing every operation you might need and then propagating it to the top level.

For instance, let's say you want to retrieve the current user information from a remote server.
In case of a '401 Unauthorized' error, you want to automatically logout the user, show a snackbar message to the user and redirect him to the login page; any other error should be simply propagated to the top level.

Here's an example of how you can do that:

import { useRouter } from "vue-router";

import { HandlerBuilder } from '@byloth/exceptions';
import { useVuert } from '@byloth/vuert';

import { UnauthorizedException } from '@example/exceptions/http';
import { HttpRequest, HttpResponse } from '@example/services/http';

async function getCurrentUser(): Promise<User>
{
    try {
        const response: HttpResponse = await HttpRequest.Get('/users/me');

        // [...]
    } catch (error) {
        new HandlerBuilder()
            .on(UnauthorizedException, (exc) => {
                logoutUser();
                useRouter().push('/login');

                throw new HandledException(exc);
            })
            .handle(error);
    }
}

function logoutUser(): void
{
    localStorage.removeItem('user:auth_token');

    useVuert().emit({
        type: 'info',
        priority: 'low',
        icon: 'user-secret',
        title: "Logged out",
        message: "You've been logged out successfully.",
        timeout: 5000
    });
}

Assuming also that the top level error handler is defined as follows:

import { HandlerBuilder } from '@byloth/exceptions';
import { useVuert } from '@byloth/vuert';

function errorHandler(error: unknown): void
{
    new HandlerBuilder()
        .default((exc) => useVuert().emit({
            type: 'error',
            icon: 'bug',
            title: "Unknown error",
            message: "Something unexpected went wrong. Please, contact our support team.",
            dismissable: true
        }))
        .handle(error);
}

In a case like this, the user will see a snackbar message, will be redirected to the login page and nothing more.
At the same time, a developer would be able to read in the console a warning message, telling him that an exception was occurred but it was correctly handled by the application and where it was handled exactly.

HandledException: The original exception has already been handled successfully.
    at @example/store/user.ts:37:15
    at @example/main.ts:23:17

Handled UnauthorizedException: You're not authorized to access this resource. Please, login first.
    at @example/services/http.ts:96:23
    at @example/models/user.ts:47:17
    at @example/store/user.ts:12:9
    at @example/main.ts:23:17

Caused by HttpException: HTTP Error 401 (Unauthorized) for URL 'https://example.com/api/v1/users'
    at @example/services/http.ts:33:9
    at @example/models/user.ts:47:17
    at @example/store/user.ts:12:9
    at @example/main.ts:23:17

Caused by Error: Unauthorized
    at node_modules/a-random-http-library/_internals/fetch.js:2:354
    at node_modules/a-random-http-library/index.js:1:756
    at @example/services/http.ts:15:11
    at @example/models/user.ts:47:17
    at @example/store/user.ts:12:9
    at @example/main.ts:23:17