diff --git a/README.md b/README.md index e9afd9b..ccdbe0a 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,36 @@ Logs the final object using passed function, Elastic URL or `Debug` library with const error = new ErrorCustom(message, statusCode, errorCode, baseError, logFunction); ``` - * {string} `message` -Error message to set on the Error object + * {string | IConfig} `message` +Error message to set on the Error object, or a config object for all parameters * {number} `statusCode` -HTTP status code +HTTP status code, optional as it can be passed as part of the config * {number} `errorCode` -The specific error code as defined in documentation +The specific error code as defined in documentation, optional as it can be passed as part of the config * {Error} `baseError` Optional base exception to be included as innerException property * {Function|string} `logFunction` Optional function to log the error with. If not supplied, debug library will be used to log to the console with the tag `error-custom`. If a string is provided that is a URL, it will be used to send to that URL with ElasticSearch client in Winston format. + * {object} `context` +Optional context information to provide with the error + +## IConfig definition +An `Iconfig` object can be apssed instead of individual parameters as below, where the definition are the same as the constructor. +``` +export interface IConfig { + message: string; + statusCode: number; + errorCode: number; + baseError?: Error; + logFunction?: string | Function; + context: any; +} +``` + +## toJSON +The object includes a `toJSON()` override to make all parameters iterable. Note that this returns an object, not a JSON string. ## Environment Variables Functionality can be modified with various environment variables: diff --git a/package-lock.json b/package-lock.json index 90b7b3e..a71e9bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@packt/error-custom", - "version": "1.2.0", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -45,9 +45,9 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true } } @@ -242,6 +242,49 @@ } } }, + "@hapi/address": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.0.1.tgz", + "integrity": "sha512-0oEP5UiyV4f3d6cBL8F3Z5S7iWSX39Knnl0lY8i+6gfmmIBj44JCBNtcMgwyS+5v7j3VYavNay0NFHDS+UGQcw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@hapi/formula": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-2.0.0.tgz", + "integrity": "sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A==" + }, + "@hapi/hoek": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz", + "integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw==" + }, + "@hapi/joi": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-17.1.1.tgz", + "integrity": "sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==", + "requires": { + "@hapi/address": "^4.0.1", + "@hapi/formula": "^2.0.0", + "@hapi/hoek": "^9.0.0", + "@hapi/pinpoint": "^2.0.0", + "@hapi/topo": "^5.0.0" + } + }, + "@hapi/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw==" + }, + "@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@sinonjs/commons": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", @@ -296,10 +339,10 @@ "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", "dev": true }, - "@types/joi": { - "version": "14.3.3", - "resolved": "https://registry.npmjs.org/@types/joi/-/joi-14.3.3.tgz", - "integrity": "sha512-6gAT/UkIzYb7zZulAbcof3lFxpiD5EI6xBeTvkL1wYN12pnFQ+y/+xl9BvnVgxkmaIDN89xWhGZLD9CvuOtZ9g==", + "@types/hapi__joi": { + "version": "16.0.12", + "resolved": "https://registry.npmjs.org/@types/hapi__joi/-/hapi__joi-16.0.12.tgz", + "integrity": "sha512-xJYifuz59jXdWY5JMS15uvA3ycS3nQYOGqoIIE0+fwQ0qI3/4CxBc6RHsOTp6wk9M0NWEdpcTl02lOQOKMifbQ==", "dev": true }, "@types/json-schema": { @@ -432,9 +475,9 @@ "dev": true }, "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", "dev": true }, "acorn-jsx": { @@ -1270,6 +1313,17 @@ "lodash": "^4.17.4", "mkdirp": "^0.5.1", "source-map-support": "^0.4.15" + }, + "dependencies": { + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + } } }, "babel-runtime": { @@ -1410,8 +1464,7 @@ "buffer-from": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", - "dev": true + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" }, "builtin-modules": { "version": "1.1.1", @@ -2540,8 +2593,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -2562,14 +2614,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2584,20 +2634,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2714,8 +2761,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2727,7 +2773,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2742,7 +2787,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2750,14 +2794,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2776,7 +2818,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2857,8 +2898,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2870,7 +2910,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2956,8 +2995,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2993,7 +3031,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3013,7 +3050,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3057,14 +3093,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -3130,7 +3164,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, - "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -3216,11 +3249,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "hoek": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz", - "integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q==" - }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -3237,6 +3265,12 @@ "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3406,8 +3440,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true, - "optional": true + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -3456,8 +3489,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-finite": { "version": "1.0.2", @@ -3479,7 +3511,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3540,14 +3571,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - } - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3773,12 +3796,12 @@ } }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", "dev": true, "requires": { - "handlebars": "^4.1.2" + "html-escaper": "^2.0.0" } }, "jmespath": { @@ -3786,16 +3809,6 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, - "joi": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", - "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", - "requires": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -3867,7 +3880,6 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -4558,7 +4570,6 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, - "optional": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -5131,7 +5142,8 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "querystring": { "version": "0.2.0", @@ -5158,9 +5170,9 @@ "optional": true }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "optional": true } @@ -5300,15 +5312,13 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true, - "optional": true + "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true, - "optional": true + "dev": true }, "repeat-string": { "version": "1.6.1", @@ -5527,12 +5537,19 @@ "dev": true }, "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "requires": { - "source-map": "^0.5.6" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } } }, "spawn-wrap": { @@ -5866,14 +5883,6 @@ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, - "topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "requires": { - "hoek": "6.x.x" - } - }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", diff --git a/package.json b/package.json index 34f090c..0292065 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@packt/error-custom", - "version": "1.2.0", + "version": "2.0.0", "description": "Extends the JavaScript Error object with custom properties.", "repository": { "type": "git", @@ -12,7 +12,7 @@ "test": "npm run lint && npm run build && npm run unit && npm run nunit", "lint": "eslint ./src/**/*.*s", "lint:fix": "eslint ./src/**/*.*s ./tests/**/*.*s --fix", - "unit": "mocha --require ts-node/register --require source-map-support/register --recursive 'tests/**/*.spec.*s'", + "unit": "mocha --require ts-node/register --recursive 'tests/**/*.spec.*s'", "nunit": "nyc --check-coverage true mocha --require ts-node/register --recursive 'tests/**/*.spec.*s'", "build": "tsc", "prepublishOnly": "npm run test && npm run build" @@ -44,8 +44,8 @@ "@babel/core": "^7.4.4", "@types/chai": "^4.1.7", "@types/debug": "^4.1.4", - "@types/joi": "^14.3.3", - "@types/mocha": "^5.2.5", + "@types/hapi__joi": "^16.0.12", + "@types/mocha": "^5.2.7", "@types/nock": "^9.3.1", "@types/sinon": "^7.0.13", "@types/uuid": "^3.4.5", @@ -68,9 +68,10 @@ }, "dependencies": { "@elastic/elasticsearch": "^7.4.0", + "@hapi/joi": "^17.1.1", "aws-sdk": "^2.570.0", "debug": "4.1.1", - "joi": "14.3.1", + "source-map-support": "^0.5.16", "uuid": "3.3.2", "winston": "3.2.1", "winston-elasticsearch": "0.8.2" @@ -92,7 +93,7 @@ ], "reporter": [ "lcov", - "html" + "text" ], "all": true } diff --git a/src/lib/IConfig.ts b/src/lib/IConfig.ts new file mode 100644 index 0000000..dfaa519 --- /dev/null +++ b/src/lib/IConfig.ts @@ -0,0 +1,8 @@ +export interface IConfig { + message: string; + statusCode: number; + errorCode: number; + baseError?: Error; + logFunction?: string | Function; + context: any; +} diff --git a/src/lib/error-custom.ts b/src/lib/error-custom.ts index 1769980..48ebd7f 100644 --- a/src/lib/error-custom.ts +++ b/src/lib/error-custom.ts @@ -1,10 +1,15 @@ +/* eslint-disable no-param-reassign */ import debug from 'debug'; -import joi from 'joi'; +import joi from '@hapi/joi'; import v4 from 'uuid/v4'; import url from 'url'; import winston from 'winston'; import Elasticsearch from 'winston-elasticsearch'; import { Client } from '@elastic/elasticsearch'; +// eslint-disable-next-line import/no-extraneous-dependencies +import 'source-map-support/register'; +// eslint-disable-next-line no-unused-vars +import { IConfig } from './IConfig'; /** * Error with enforced error Code and status Code and autogenerated error ID uuid. @@ -15,6 +20,7 @@ class ErrorCustom extends Error { public manuallyThrown: boolean; public id: string; public innerException: any; + public context: any; /** * Error Constructor @@ -24,35 +30,50 @@ class ErrorCustom extends Error { * Logs the final object using passed function or debug library. * * @constructor - * @param {string} message - * Error message to set on the Error object + * @param {string | IConfig} message + * Error message to set on the Error object, or config properties to set all params * * @param {number} statusCode - * HTTP status code + * HTTP status code, optional as it can be passed as part of the config * * @param {number} errorCode - * The specific error code as defined in documentation + * The specific error code as defined in documentation, optional as it can be passed as + * part of the config * - * @param {Error} baseError + * @param {Error?} baseError * Optional base exception to be included as innerException property * * @param {string | Function} logFunction * Optional function to log the error with. If not supplied, debug library will be used * to log to the console with the tag `error-custom` */ - constructor(message: string, statusCode: number, errorCode: number, - baseError?: Error, logFunction?: string | Function) { + constructor(message: string | IConfig, statusCode?: number, errorCode?: number, + baseError?: Error, logFunction?: string | Function, context?: any) { + let messageVal: string; + + // handle the case where we have a config object passed in and remap into params + if (typeof message === 'object') { + messageVal = message.message; + statusCode = message.statusCode; + errorCode = message.errorCode; + baseError = message.baseError; + logFunction = message.logFunction; + context = message.context; + } else { + messageVal = message; + } + // Validation - const messageValidation = joi.validate(message, joi.string().required()); - const statusCodeValidation = joi.validate( - statusCode, - joi.number().integer().min(200).max(600) - .required(), - ); - const errorCodeValidation = joi.validate( - errorCode, - joi.alternatives([joi.string(), joi.number().integer()]).required(), - ); + const messageValidation = joi.string().required().validate(messageVal); + const statusCodeValidation = joi.number().integer().min(200).max(600) + .required() + .validate( + statusCode, + ); + const errorCodeValidation = joi.alternatives([joi.string(), joi.number().integer()]).required() + .validate( + errorCode, + ); const errors = []; if (messageValidation.error) errors.push('Invalid value for message parameter'); if (statusCodeValidation.error) errors.push('Invalid value for statusCode parameter'); @@ -65,34 +86,40 @@ class ErrorCustom extends Error { // Re-enable the original chain for stack traces etc /* istanbul ignore next */ - super(message); + super(messageVal); Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain + this.toJSON = this.toJSON.bind(this); this.statusCode = statusCode; this.errorCode = errorCode; this.manuallyThrown = true; this.id = v4(); this.innerException = baseError; + this.context = context; // Log to chosen location - if (process.env.ELASTIC_LOGGING_URL) { - ErrorCustom.sendToElastic(process.env.ELASTIC_LOGGING_URL, this); - } else { - switch (typeof logFunction) { - case 'function': - logFunction(this.id, this); - break; - case 'string': - if (url.parse(logFunction).host) { - ErrorCustom.sendToElastic(logFunction, this); + try { + if (process.env.ELASTIC_LOGGING_URL) { + ErrorCustom.sendToElastic(process.env.ELASTIC_LOGGING_URL, this); + } else { + switch (typeof logFunction) { + case 'function': + logFunction(this.id, this); break; - } else { + case 'string': + if (url.parse(logFunction).host) { + ErrorCustom.sendToElastic(logFunction, this); + break; + } else { + ErrorCustom.defaultOutput(this.id, this); + break; + } + + default: ErrorCustom.defaultOutput(this.id, this); - break; - } - - default: - ErrorCustom.defaultOutput(this.id, this); + } } + } catch (error) { + console.error('Logging attempts failed', error); } } @@ -114,7 +141,7 @@ class ErrorCustom extends Error { * @param id * @param content */ - private static defaultOutput(id: string, content: ErrorCustom): void { + private static defaultOutput(id: string, content: any): void { return debug('error-custom')(id, content); } @@ -125,7 +152,7 @@ class ErrorCustom extends Error { * @param content */ private static async sendToElastic(node: string, content: ErrorCustom): Promise { - ErrorCustom.defaultOutput(content.id, content); + ErrorCustom.defaultOutput(content.id, content.toJSON()); const date = new Date(); @@ -173,7 +200,7 @@ class ErrorCustom extends Error { esTransport, ], }); - logger.error(content.message, content); + logger.error(content.message, content.toJSON()); } } diff --git a/tests/error-custom-built.spec.js b/tests/error-custom-built.spec.js index 833ecc2..70d2c5b 100644 --- a/tests/error-custom-built.spec.js +++ b/tests/error-custom-built.spec.js @@ -19,6 +19,23 @@ describe('Error Custom (Built)', () => { expect(error.stack).to.be.not.undefined; }); + it('Constructing the instance - object version', () => { + const error = new errorCustom({ + message: 'Error Message', + statusCode: 400, + errorCode: 1000, + context: { productId: '9781234567890' }, + }); + expect(error).to.be.instanceof(errorCustom); + expect(error.message).to.equal('Error Message'); + expect(error.statusCode).to.equal(400); + expect(error.errorCode).to.equal(1000); + expect(error.manuallyThrown).to.be.true; + expect(error.stack).to.be.not.undefined; + expect(error.context).to.be.a('object'); + expect(error.context.productId).to.eql('9781234567890'); + }); + it('undefined message fails', () => { try { new errorCustom(undefined, 200, 1000000); diff --git a/tests/error-custom.spec.ts b/tests/error-custom.spec.ts index 45dc1ac..7914ecf 100644 --- a/tests/error-custom.spec.ts +++ b/tests/error-custom.spec.ts @@ -27,6 +27,23 @@ describe('Error Custom', () => { expect(error.stack).to.be.not.undefined; }); + it('Constructing the instance - object version', () => { + const error = new ErrorCustom({ + message: 'Error Message', + statusCode: 400, + errorCode: 1000, + context: { productId: '9781234567890' }, + }); + expect(error).to.be.instanceof(ErrorCustom); + expect(error.message).to.equal('Error Message'); + expect(error.statusCode).to.equal(400); + expect(error.errorCode).to.equal(1000); + expect(error.manuallyThrown).to.be.true; + expect(error.stack).to.be.not.undefined; + expect(error.context).to.be.a('object'); + expect(error.context.productId).to.eql('9781234567890'); + }); + it('undefined message fails', () => { try { new ErrorCustom(undefined, 200, 1000000); @@ -199,7 +216,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -210,7 +227,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -223,7 +240,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -235,7 +252,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -247,7 +264,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -259,7 +276,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -271,7 +288,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); @@ -283,7 +300,7 @@ describe('Error Custom', () => { const errorFunc = sandbox.stub(winston, 'createLogger').returns({ error: () => { }, } as any); - await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {}); + await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {}); expect(errorFunc.callCount).to.be.gte(1); }); }); diff --git a/tsconfig.json b/tsconfig.json index 48d9a87..c2df81d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "es2017" ], "module": "commonjs", - "target": "es5", + "target": "es2015", "noImplicitAny": false, "sourceMap": true, "emitDecoratorMetadata": true,