{"id":25409117,"url":"https://github.com/byloth/exceptions","last_synced_at":"2026-02-18T21:31:27.101Z","repository":{"id":65457370,"uuid":"526662046","full_name":"Byloth/exceptions","owner":"Byloth","description":"❌ Handle exceptions with ease, creating better stacktraces and managing everything in the right place.","archived":false,"fork":false,"pushed_at":"2025-04-20T17:53:27.000Z","size":255,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-05T11:36:54.443Z","etag":null,"topics":["error","exception","handling","javascript","library","stacktrace","traceback","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Byloth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"Byloth"}},"created_at":"2022-08-19T15:37:38.000Z","updated_at":"2025-04-20T17:53:31.000Z","dependencies_parsed_at":"2025-04-20T18:33:38.912Z","dependency_job_id":"41345ed6-3abc-4953-896a-d64119d238ad","html_url":"https://github.com/Byloth/exceptions","commit_stats":{"total_commits":15,"total_committers":1,"mean_commits":15.0,"dds":0.0,"last_synced_commit":"53fea6b02d3b1057aa2107e0a8e82207719b2325"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/Byloth/exceptions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Byloth%2Fexceptions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Byloth%2Fexceptions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Byloth%2Fexceptions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Byloth%2Fexceptions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Byloth","download_url":"https://codeload.github.com/Byloth/exceptions/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Byloth%2Fexceptions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000753,"owners_count":26082921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error","exception","handling","javascript","library","stacktrace","traceback","typescript"],"created_at":"2025-02-16T08:19:14.015Z","updated_at":"2025-10-09T04:06:03.816Z","avatar_url":"https://github.com/Byloth.png","language":"TypeScript","readme":"# Exceptions ❌\n\n[![NPM release](https://github.com/Byloth/exceptions/actions/workflows/release-npm.yml/badge.svg)](https://github.com/Byloth/exceptions/actions/workflows/release-npm.yml)\n[![GPR release](https://github.com/Byloth/exceptions/actions/workflows/release-gpr.yml/badge.svg)](https://github.com/Byloth/exceptions/actions/workflows/release-gpr.yml)\n\nHandle exceptions with ease, create better stacktraces and manage everything in the right place.\n\n## Summary\n\n- [Installation](#installation)\n- [Main concepts](#main-concepts)\n    - [Chained exceptions](#chained-exceptions)\n    - [Typed exceptions](#typed-exceptions)\n    - [Handled exceptions](#handled-exceptions)\n\n## Installation\n\n```sh\nnpm install --save-dev @byloth/exceptions\n```\n\n## Main concepts\n\n### Chained exceptions\n\nThis library allows you to create a chain of exceptions -just like you can already do with other programming languages-\nso you can easily know which error caused which exception, where it was thrown and what was the original cause.\n\nAt the same time, you can also provide to the user a more friendly error message without\nlosing the original information of the error itself, extremely useful for debugging purposes.\n\n```ts\nimport { Exception } from '@byloth/exceptions';\n\ntry {\n    // [...]\n} catch (error) {\n    // [...]\n\n    throw new Exception(\"I wasn't able to retrieve the current user information. Please, try again later.\", error);\n}\n```\n\nThe above code might throw an exception like this:\n\n```\nUncaught Exception: I wasn't able to retrieve the current user information. Please, try again later.\n    at @example/store/user.ts:37:15\n    at @example/main.ts:23:17\n\nCaused by HttpException: HTTP Error 500 (Internal Server Error) for URL 'https://example.com/api/v1/users'\n    at @example/services/http.ts:33:9\n    at @example/models/user.ts:47:17\n    at @example/store/user.ts:12:9\n    at @example/main.ts:23:17\n\nCaused by Error: Internal Server Error\n    at node_modules/a-random-http-library/_internals/fetch.js:2:354\n    at node_modules/a-random-http-library/index.js:1:756\n    at @example/services/http.ts:15:11\n    at @example/models/user.ts:47:17\n    at @example/store/user.ts:12:9\n    at @example/main.ts:23:17\n```\n\n\u003e *So much better, isn't it?* 😎\n\n### Typed exceptions\n\nJavaScript cannot handle multiple types of exceptions, by design.  \nUnlike other languages, it doesn't allow you using multiple\n`catch` blocks to differentiate your handler logic.\n\nHow many times, while developing, have you caught an exception and\nthen checked the error message / type to know what to do next?  \nOf course, forced to write a lot of `if` - `else`\nstatements to handle all the different cases.\n\n\u003e *Is it boring, right?* 😴\n\nThis library allows you to build your own exception handlers, so you\ncan easily handle different types of exceptions in a more elegant way.\n\n```ts\nimport { HandlerBuilder } from '@byloth/exceptions';\nimport { useVuert } from '@byloth/vuert';\n\nimport { HttpException, NetworkException, UnauthorizedException } from '@example/exceptions/http';\n\ntry {\n    // [...]\n} catch (error) {\n    // Here `error` is of type `unknown`.\n\n    const vuert = useVuert();\n    const handler = new HandlerBuilder()\n        .on(UnauthorizedException, (exc) =\u003e {\n            // If `error` is of type `UnauthorizedException`,\n            //  then this block will be executed with `exc`\n            //  as `error` casted to `UnauthorizedException`.\n\n            vuert.emit({\n                type: 'error',\n                icon: 'circle-xmark',\n                title: \"Unauthorized\",\n                message: \"You're not authorized to access this resource. Please, login first.\",\n                dismissable: true\n            });\n        })\n        .on([HttpException, NetworkException], (exc) =\u003e {\n            // If `error` is of type `HttpException` or `NetworkException`,\n            //  then this block will be executed with `exc` as `error`\n            //  casted to `HttpException | NetworkException`.\n\n            vuert.emit({\n                type: 'error',\n                icon: 'link-slash',\n                title: \"Communication error\",\n                message: \"There was an error while trying to access the server. Please, try again later.\",\n                dismissable: true\n            });\n        })\n        .default((exc) =\u003e {\n            // If `error` is none of the above types,\n            //  then this block will be executed with\n            //  `exc` as `error` casted to `unknown`.\n\n            vuert.emit({\n                type: 'error',\n                icon: 'bug',\n                title: \"Unknown error\",\n                message: \"Something unexpected went wrong. Please, contact our support team.\",\n                dismissable: true\n            });\n        });\n\n    handler.handle(error);\n}\n```\n\n### Handled exceptions\n\nLet's say you are developing your web application and you want to handle errors in a smart way.\n\nThe first thing you might think of is to centralize all the error\nhandling logic in a single place, so you can easily maintain it.  \nTo be sure that you're catching all the errors, you place\nthis logic at the outermost level of your application.\n\nUnfortunately, after a while, you start to realize that -in some cases- you\ncan't simply propagate the errors at the top level because you need to\nhandle them in some middle layer of your application to perform some\nother specific operations before actually propagating them.  \nTo make things worse, you have also to provide some specific output to the user\nmaking the default error handling logic redundant and annoying for the user.\n\nAt this point, you might think of a solution to handle the errors directly\nin the middle layer of your application, without propagating them to the top\nlevel; but, how can you do that without duplicating the error handling logic?\n\nHere comes the new `HandledException` class instroduced by this library.  \nIt allows you to handle an exception in whatever place of your application you want,\nperforming every operation you might need and then propagating it to the top level.\n\nFor instance, let's say you want to retrieve the current user information from a remote server.  \nIn case of a '401 Unauthorized' error, you want to automatically logout the user,\nshow a snackbar message to the user and redirect him to the login page;\nany other error should be simply propagated to the top level.\n\nHere's an example of how you can do that:\n\n```ts\nimport { useRouter } from \"vue-router\";\n\nimport { HandlerBuilder } from '@byloth/exceptions';\nimport { useVuert } from '@byloth/vuert';\n\nimport { UnauthorizedException } from '@example/exceptions/http';\nimport { HttpRequest, HttpResponse } from '@example/services/http';\n\nasync function getCurrentUser(): Promise\u003cUser\u003e\n{\n    try {\n        const response: HttpResponse = await HttpRequest.Get('/users/me');\n\n        // [...]\n    } catch (error) {\n        new HandlerBuilder()\n            .on(UnauthorizedException, (exc) =\u003e {\n                logoutUser();\n                useRouter().push('/login');\n\n                throw new HandledException(exc);\n            })\n            .handle(error);\n    }\n}\n\nfunction logoutUser(): void\n{\n    localStorage.removeItem('user:auth_token');\n\n    useVuert().emit({\n        type: 'info',\n        priority: 'low',\n        icon: 'user-secret',\n        title: \"Logged out\",\n        message: \"You've been logged out successfully.\",\n        timeout: 5000\n    });\n}\n```\n\nAssuming also that the top level error handler is defined as follows:\n\n```ts\nimport { HandlerBuilder } from '@byloth/exceptions';\nimport { useVuert } from '@byloth/vuert';\n\nfunction errorHandler(error: unknown): void\n{\n    new HandlerBuilder()\n        .default((exc) =\u003e useVuert().emit({\n            type: 'error',\n            icon: 'bug',\n            title: \"Unknown error\",\n            message: \"Something unexpected went wrong. Please, contact our support team.\",\n            dismissable: true\n        }))\n        .handle(error);\n}\n```\n\nIn a case like this, the user will see a snackbar message,\nwill be redirected to the login page and nothing more.  \nAt the same time, a developer would be able to read in the console\na warning message, telling him that an exception was occurred but it was\ncorrectly handled by the application and where it was handled exactly.\n\n```\nHandledException: The original exception has already been handled successfully.\n    at @example/store/user.ts:37:15\n    at @example/main.ts:23:17\n\nHandled UnauthorizedException: You're not authorized to access this resource. Please, login first.\n    at @example/services/http.ts:96:23\n    at @example/models/user.ts:47:17\n    at @example/store/user.ts:12:9\n    at @example/main.ts:23:17\n\nCaused by HttpException: HTTP Error 401 (Unauthorized) for URL 'https://example.com/api/v1/users'\n    at @example/services/http.ts:33:9\n    at @example/models/user.ts:47:17\n    at @example/store/user.ts:12:9\n    at @example/main.ts:23:17\n\nCaused by Error: Unauthorized\n    at node_modules/a-random-http-library/_internals/fetch.js:2:354\n    at node_modules/a-random-http-library/index.js:1:756\n    at @example/services/http.ts:15:11\n    at @example/models/user.ts:47:17\n    at @example/store/user.ts:12:9\n    at @example/main.ts:23:17\n```\n","funding_links":["https://github.com/sponsors/Byloth"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyloth%2Fexceptions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbyloth%2Fexceptions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyloth%2Fexceptions/lists"}