Comparing version 0.0.2 to 1.0.2
121
package.json
{ | ||
"name": "new-error", | ||
"version": "0.0.2", | ||
"description": "publish", | ||
"repository": "npm/security-holder" | ||
"version": "1.0.2", | ||
"description": "A production-grade error creation and serialization library designed for Typescript", | ||
"main": "build/index.js", | ||
"types": "build/index.d.ts", | ||
"scripts": { | ||
"build": "npm run build:clean && npm run compile", | ||
"build:clean": "rm -rf build/*", | ||
"compile": "tsc", | ||
"debug": "ts-node-dev --inspect -- src/index.ts", | ||
"debug:break": "ts-node-dev --inspect-brk -- src/index.ts", | ||
"test": "jest", | ||
"test:ci": "jest --ci --coverage", | ||
"test:debug": "node --inspect-brk node_modules/.bin/jest", | ||
"test:watch": "jest --watch", | ||
"test:coverage:watch": "jest --coverage --watch", | ||
"toc": "toc-md README.md README.md", | ||
"add-readme": "git add README.md", | ||
"lint-staged": "lint-staged", | ||
"prepare-publish": "npm run changelog:prepare && version-bump && npm run changelog:release && npm run changelog:stamp", | ||
"version-bump": "version-bump", | ||
"changelog:help": "changelog-version", | ||
"changelog:verify": "changelog-version verify", | ||
"changelog:prepare": "changelog-version prepare", | ||
"changelog:stamp": "git-commit-stamper parse CHANGELOG.md", | ||
"changelog:release": "changelog-version release", | ||
"lint": "prettier-standard src/**/*.ts && standardx src/**/*.ts", | ||
"ts-node-dev": "ts-node-dev" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/theogravity/new-error.git" | ||
}, | ||
"author": "Theo Gravity <theo@suteki.nu>", | ||
"license": "MIT", | ||
"keywords": [ | ||
"error", | ||
"throw", | ||
"custom", | ||
"generate", | ||
"new", | ||
"extends", | ||
"factory", | ||
"subclass", | ||
"inherit", | ||
"extension", | ||
"create", | ||
"typescript", | ||
"serialize", | ||
"collection", | ||
"stack", | ||
"trace", | ||
"err", | ||
"log", | ||
"logging" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/theogravity/new-error/issues" | ||
}, | ||
"homepage": "https://github.com/theogravity/new-error#readme", | ||
"dependencies": { | ||
"es6-error": "^4.1.1", | ||
"sprintf-js": "^1.1.2" | ||
}, | ||
"devDependencies": { | ||
"@theo.gravity/changelog-version": "2.1.10", | ||
"@theo.gravity/version-bump": "2.0.9", | ||
"@types/jest": "25.2.2", | ||
"@types/node": "^14.0.1", | ||
"@typescript-eslint/eslint-plugin": "^2.33.0", | ||
"@typescript-eslint/parser": "^2.33.0", | ||
"eslint": "7.0.0", | ||
"git-commit-stamper": "^1.0.9", | ||
"jest": "^25.5.4", | ||
"jest-cli": "26.0.1", | ||
"jest-junit-reporter": "1.1.0", | ||
"lint-staged": "10.2.2", | ||
"pre-commit": "1.2.2", | ||
"prettier-standard": "16.3.0", | ||
"standardx": "^5.0.0", | ||
"toc-md-alt": "^0.3.2", | ||
"ts-jest": "25.5.1", | ||
"ts-node": "8.10.1", | ||
"ts-node-dev": "1.0.0-pre.44", | ||
"typescript": "3.9.2" | ||
}, | ||
"eslintConfig": { | ||
"parserOptions": { | ||
"ecmaVersion": 6, | ||
"sourceType": "module", | ||
"ecmaFeatures": { | ||
"modules": true | ||
} | ||
}, | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": [ | ||
"@typescript-eslint/eslint-plugin" | ||
], | ||
"rules": { | ||
"@typescript-eslint/no-unused-vars": [ | ||
2, | ||
{ | ||
"args": "none" | ||
} | ||
] | ||
} | ||
}, | ||
"lint-staged": { | ||
"src/**/*.ts": [ | ||
"prettier-standard", | ||
"git add" | ||
] | ||
}, | ||
"pre-commit": [ | ||
"toc", | ||
"lint-staged", | ||
"test:ci", | ||
"build" | ||
] | ||
} |
359
README.md
@@ -1,9 +0,354 @@ | ||
# Security holding package | ||
# new-error | ||
This package name is not currently in use, but was formerly occupied | ||
by another package. To avoid malicious use, npm is hanging on to the | ||
package name, but loosely, and we'll probably give it to you if you | ||
want it. | ||
[![NPM version](http://img.shields.io/npm/v/new-error.svg?style=flat-square)](https://www.npmjs.com/package/new-error) | ||
[![CircleCI](https://circleci.com/gh/theogravity/new-error.svg?style=svg)](https://circleci.com/gh/theogravity/new-error) | ||
![built with typescript](https://camo.githubusercontent.com/92e9f7b1209bab9e3e9cd8cdf62f072a624da461/68747470733a2f2f666c61742e62616467656e2e6e65742f62616467652f4275696c74253230576974682f547970655363726970742f626c7565) | ||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) | ||
You may adopt this package by contacting support@npmjs.com and | ||
requesting the name. | ||
A production-grade error creation library designed for Typescript. Useful for direct printing | ||
of errors to a client or for internal development / logs. | ||
- All created errors extend `Error` with additional methods added on. | ||
- Show errors that are safe for client / user-consumption vs internal only. | ||
- Create your own custom error types with custom messaging, status codes and metadata. | ||
- Attach an error to your error object to get the full error chain. | ||
- Selectively expose error metadata based on internal or external use. | ||
- Built-in auto-completion for Typescript when searching for registered error types. | ||
- 100% test coverage | ||
![Generating an error with autocompletion](/autocomplete.jpg?raw=true "Title") | ||
# Table of Contents | ||
<!-- TOC --> | ||
- [Installation](#installation) | ||
- [Example Usage](#example-usage) | ||
- [Error Registry](#error-registry) | ||
- [Creating errors](#creating-errors) | ||
- [Create a well-defined error](#create-a-well-defined-error) | ||
- [Create an error without a low-level error](#create-an-error-without-a-low-level-error) | ||
- [Instance comparison / `instanceOf` usage](#instance-comparison--instanceof-usage) | ||
- [Error manipulation](#error-manipulation) | ||
- [Attaching errors](#attaching-errors) | ||
- [Format messages](#format-messages) | ||
- [Adding metadata](#adding-metadata) | ||
- [Safe metadata](#safe-metadata) | ||
- [Internal metadata](#internal-metadata) | ||
- [Serializing errors](#serializing-errors) | ||
- [Safe serialization](#safe-serialization) | ||
- [Internal serialization](#internal-serialization) | ||
<!-- TOC END --> | ||
# Installation | ||
`$ npm i new-error --save` | ||
# Example Usage | ||
- Define a set of high level errors | ||
* Common high level error types could be 4xx/5xx HTTP codes | ||
- Define a set of low level errors | ||
* Think of low level errors as a fine-grained sub-code/category to a high level error | ||
- Initialize the error registry with the errors | ||
```typescript | ||
// This is a working example | ||
import { ErrorRegistry } from 'new-error' | ||
// Define high level errors | ||
// Do *not* assign a Typescript type to the object | ||
// or IDE autocompletion will not work! | ||
const errors = { | ||
INTERNAL_SERVER_ERROR: { | ||
/** | ||
* The class name of the generated error | ||
*/ | ||
className: 'InternalServerError', | ||
/** | ||
* A user-friendly code to show to a client. | ||
*/ | ||
code: 'ERR_INT_500', | ||
/** | ||
* (optional) Protocol-specific status code, such as an HTTP status code. Used as the | ||
* default if a Low Level Error status code is not specified or defined. | ||
*/ | ||
statusCode: 500 | ||
} | ||
} | ||
// Define low-level errors | ||
// Do *not* assign a Typescript type to the object | ||
// or IDE autocompletion will not work! | ||
const errorCodes = { | ||
// 'type' of error | ||
DATABASE_FAILURE: { | ||
/** | ||
* Full description of the error. sprintf() flags can be applied | ||
* to customize it. | ||
* @see https://www.npmjs.com/package/sprintf-js | ||
*/ | ||
message: 'There was a database failure, SQL err code %s', | ||
/** | ||
* (optional) A user-friendly code to show to a client. | ||
*/ | ||
subCode: 'DB_0001', | ||
/** | ||
* (optional) Protocol-specific status code, such as an HTTP status code. | ||
*/ | ||
statusCode: 500 | ||
} | ||
} | ||
// Create the error registry by registering your errors and codes | ||
// you will want to memoize this as you will be using the | ||
// reference throughout your application | ||
const errRegistry = new ErrorRegistry(errors, errorCodes) | ||
// Create an instance of InternalServerError | ||
// Typescript autocomplete should show the available definitions as you type the error names | ||
// and type check will ensure that the values are valid | ||
const err = errRegistry.newError('INTERNAL_SERVER_ERROR', 'DATABASE_FAILURE') | ||
console.log(err.toJSON()) | ||
``` | ||
Produces: | ||
(You can omit fields you do not need - see usage section below.) | ||
``` | ||
{ | ||
name: 'InternalServerError', | ||
code: 'ERR_INT_500', | ||
message: 'There was a database failure, SQL err code %s', | ||
type: 'DATABASE_FAILURE', | ||
subCode: 'DB_0001', | ||
statusCode: 500, | ||
meta: {}, | ||
stack: 'InternalServerError: There was a database failure, SQL err code %s\n' + | ||
' at ErrorRegistry.newError (new-error/src/ErrorRegistry.ts:128:12)\n' + | ||
' at Object.<anonymous> (new-error/src/test.ts:55:25)\n' + | ||
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' + | ||
' at Module._compile (new-error/node_modules/source-map-support/source-map-support.js:541:25)\n' + | ||
' at Module.m._compile (/private/var/folders/mx/b54hc2lj3fbfsndkv4xmz8d80000gn/T/ts-node-dev-hook-20649714243977457.js:57:25)\n' + | ||
' at Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' + | ||
' at require.extensions.<computed> (/private/var/folders/mx/b54hc2lj3fbfsndkv4xmz8d80000gn/T/ts-node-dev-hook-20649714243977457.js:59:14)\n' + | ||
' at Object.nodeDevHook [as .ts] (new-error/node_modules/ts-node-dev/lib/hook.js:61:7)\n' + | ||
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' + | ||
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)' | ||
} | ||
``` | ||
# Error Registry | ||
The `ErrorRegistry` is responsible for the registration and creation of errors. | ||
## Creating errors | ||
Errors generated by the registry extends `BaseError`. | ||
### Create a well-defined error | ||
Method: `ErrorRegistry#newError(highLevelErrorName, LowLevelErrorName)` | ||
This is the method you should generally use as you are forced to use your | ||
well-defined high and low level error definitions. This allows for consistency | ||
in how errors are defined and thrown. | ||
```typescript | ||
// Creates an InternalServerError error with a DATABASE_FAILURE code and corresponding | ||
// message and status code | ||
const err = errRegistry.newError('INTERNAL_SERVER_ERROR', 'DATABASE_FAILURE') | ||
``` | ||
### Create an error without a low-level error | ||
Method: `ErrorRegistry#newBareError(highLevelErrorName, message)` | ||
This method does not include a low level error code, and allows direct specification of an | ||
error message. | ||
```typescript | ||
// Creates an InternalServerError error with a custom message | ||
const err = errRegistry.newBareError('INTERNAL_SERVER_ERROR', 'An internal server error has occured.') | ||
``` | ||
## Instance comparison / `instanceOf` usage | ||
Method: `ErrorRegistry#instanceOf(classInstance, highLevelErrorName)` | ||
Performs an `instanceof` operation against a custom error. | ||
```typescript | ||
// creates an InternalServerError error instance | ||
const err = errRegistry.newError('INTERNAL_SERVER_ERROR', 'DATABASE_FAILURE') | ||
if (errRegistry.instanceOf(err, 'INTERNAL_SERVER_ERROR')) { | ||
// resolves to true since err is an InternalServerError instance | ||
} | ||
``` | ||
# Error manipulation | ||
Except for the serialization methods, all methods are chainable. | ||
## Attaching errors | ||
Method: `BaseError#causedBy(err)` | ||
You can attach another error to the error. | ||
```typescript | ||
const externalError = new Error('Some thrown error') | ||
err.causedBy(externalError) | ||
``` | ||
## Format messages | ||
Method: `BaseError#formatMessage(...formatParams)` | ||
See the [`sprintf-js`](https://www.npmjs.com/package/sprintf-js) package for usage. | ||
```typescript | ||
// specify the database specific error code | ||
// Transforms the message to: | ||
// 'There was a database failure, SQL err code %s' -> | ||
// 'There was a database failure, SQL err code SQL_ERR_1234', | ||
err.formatMessage('SQL_ERR_1234') | ||
``` | ||
## Adding metadata | ||
### Safe metadata | ||
Method: `BaseError#withSafeMetadata(data = {})` | ||
Safe metadata would be any kind of data that you would be ok with exposing to a client, like an | ||
HTTP response. | ||
```typescript | ||
err.withSafeMetadata({ | ||
errorId: 'err-12345', | ||
moreData: 1234 | ||
}) | ||
// can be chained to append more data | ||
.withSafeMetadata({ | ||
requestId: 'req-12345' | ||
}) | ||
``` | ||
This can also be written as: | ||
```typescript | ||
err.withSafeMetadata({ | ||
errorId: 'err-12345', | ||
moreData: 1234 | ||
}) | ||
// This will append requestId to the metadata | ||
err.withSafeMetadata({ | ||
requestId: 'req-12345' | ||
}) | ||
``` | ||
### Internal metadata | ||
Method: `BaseError#withMetadata(data = {})` | ||
Internal metadata would be any kind of data that you would *not be* ok with exposing to a client, | ||
but would be useful for internal development / logging purposes. | ||
```typescript | ||
err.withMetadata({ | ||
email: 'test@test.com' | ||
}) | ||
// can be chained to append more data | ||
.withMetadata({ | ||
userId: 'user-abcd' | ||
}) | ||
``` | ||
# Serializing errors | ||
## Safe serialization | ||
Method: `BaseError#toJSONSafe(fieldsToOmit = [])` | ||
Generates output that would be safe for client consumption. | ||
- Omits `name` | ||
- Omits `message` | ||
- Omits `causedBy` | ||
- Omits `type` | ||
- Omits the stack trace | ||
- Omits any data defined via `BaseError#withMetadata()` | ||
```typescript | ||
err.withSafeMetadata({ | ||
errorId: 'err-12345', | ||
requestId: 'req-12345' | ||
}) | ||
// you can remove additional fields by specifying property names in an array | ||
//.toJSONSafe(['code']) removes the code field from output | ||
.toJSONSafe() | ||
``` | ||
Produces: | ||
``` | ||
{ | ||
code: 'ERR_INT_500', | ||
subCode: 'DB_0001', | ||
statusCode: 500, | ||
meta: { errorId: 'err-12345', requestId: 'req-12345' } | ||
} | ||
``` | ||
## Internal serialization | ||
Method: `BaseError#toJSON(fieldsToOmit = [])` | ||
Generates output that would be suitable for internal use. | ||
- Includes `name` | ||
- Includes `type` | ||
- Includes `message` | ||
- Includes `causedBy` | ||
- Includes the stack trace | ||
- All data from `BaseError#withMetadata()` and `BaseError#withJSONMetadata()` is included | ||
```typescript | ||
err.withSafeMetadata({ | ||
errorId: 'err-12345', | ||
}).withMetadata({ | ||
email: 'test@test.com' | ||
}) | ||
// you can remove additional fields by specifying property names in an array | ||
//.toJSON(['code', 'statusCode']) removes the code and statusCode field from output | ||
.toJSON() | ||
``` | ||
Produces: | ||
``` | ||
{ | ||
name: 'InternalServerError', | ||
code: 'ERR_INT_500', | ||
message: 'There was a database failure, SQL err code %s', | ||
type: 'DATABASE_FAILURE', | ||
subCode: 'DB_0001', | ||
statusCode: 500, | ||
meta: { errorId: 'err-12345', requestId: 'req-12345' }, | ||
stack: 'InternalServerError: There was a database failure, SQL err code %s\n' + | ||
' at ErrorRegistry.newError (new-error/src/ErrorRegistry.ts:128:12)\n' + | ||
' at Object.<anonymous> (new-error/src/test.ts:55:25)\n' + | ||
' at Module._compile (internal/modules/cjs/loader.js:1158:30)\n' + | ||
' at Module._compile (new-error/node_modules/source-map-support/source-map-support.js:541:25)\n' + | ||
' at Module.m._compile (/private/var/folders/mx/b54hc2lj3fbfsndkv4xmz8d80000gn/T/ts-node-dev-hook-17091160954051898.js:57:25)\n' + | ||
' at Module._extensions..js (internal/modules/cjs/loader.js:1178:10)\n' + | ||
' at require.extensions.<computed> (/private/var/folders/mx/b54hc2lj3fbfsndkv4xmz8d80000gn/T/ts-node-dev-hook-17091160954051898.js:59:14)\n' + | ||
' at Object.nodeDevHook [as .ts] (new-error/node_modules/ts-node-dev/lib/hook.js:61:7)\n' + | ||
' at Module.load (internal/modules/cjs/loader.js:1002:32)\n' + | ||
' at Function.Module._load (internal/modules/cjs/loader.js:901:14)' | ||
} | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
39079
19
0
542
0
0
355
0
2
20
+ Addedes6-error@^4.1.1
+ Addedsprintf-js@^1.1.2
+ Addedes6-error@4.1.1(transitive)
+ Addedsprintf-js@1.1.3(transitive)