diff --git a/package-lock.json b/package-lock.json index 59150ae..4d08cfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1303,6 +1303,16 @@ "to-fast-properties": "^2.0.0" } }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.3.tgz", @@ -1481,6 +1491,15 @@ "@types/node": "*" } }, + "@types/bunyan": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz", + "integrity": "sha512-Cblq+Yydg3u+sGiz2mjHjC5MPmdjY+No4qvHrF+BUhblsmSfMvsHLbOG62tPbonsqBj6sbWv1LHcsoe5Jw+/Ow==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -1533,6 +1552,15 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "@types/morgan": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz", + "integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { "version": "16.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.1.tgz", @@ -1833,6 +1861,11 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -1907,6 +1940,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2013,6 +2054,17 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "bunyan": { + "version": "1.8.15", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", + "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.19.3", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -2153,6 +2205,30 @@ "mimic-response": "^1.0.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2165,8 +2241,30 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "commander": { "version": "2.20.3", @@ -2262,6 +2360,11 @@ } } }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2386,6 +2489,15 @@ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -2414,6 +2526,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -2848,6 +2965,11 @@ "reusify": "^1.0.4" } }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2943,6 +3065,11 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3264,6 +3391,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -3419,6 +3551,11 @@ "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -3463,6 +3600,11 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3549,6 +3691,11 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -3595,6 +3742,18 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "requires": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + } + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -3720,11 +3879,83 @@ "moment": ">= 2.9.0" } }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + } + } + } + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true }, "nanocolors": { "version": "0.2.12", @@ -3738,6 +3969,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -3847,6 +4084,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3855,6 +4097,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4118,6 +4368,11 @@ "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -4382,6 +4637,17 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "optional": true + }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4556,6 +4822,14 @@ "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -4599,6 +4873,11 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -4690,6 +4969,11 @@ "has-flag": "^3.0.0" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4741,6 +5025,11 @@ "nopt": "~1.0.10" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5052,6 +5341,55 @@ "string-width": "^4.0.0" } }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "wkx": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", diff --git a/package.json b/package.json index b4660f5..7c572a8 100644 --- a/package.json +++ b/package.json @@ -13,17 +13,20 @@ "dependencies": { "@types/event-stream": "^3.3.34", "@types/node": "^16.10.1", + "bunyan": "^1.8.15", "csvtojson": "^2.0.10", "dotenv": "^10.0.0", "event-stream": "^4.0.1", "express": "^4.17.1", "express-joi-validation": "^5.0.0", "joi": "^17.4.2", + "morgan": "^1.10.0", "pg": "^8.7.1", "pg-hstore": "^2.3.4", "sequelize": "^6.9.0", "tslint": "^6.1.3", - "typescript": "^4.4.3" + "typescript": "^4.4.3", + "winston": "^3.3.3" }, "devDependencies": { "@babel/cli": "^7.15.7", @@ -31,7 +34,9 @@ "@babel/node": "^7.15.4", "@babel/preset-env": "^7.15.6", "@babel/preset-typescript": "^7.15.0", + "@types/bunyan": "^1.8.8", "@types/express": "^4.17.13", + "@types/morgan": "^1.9.3", "@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.1.0", "babel-eslint": "^10.1.0", diff --git a/src/module-3/controllers/groups.ts b/src/module-3/controllers/groups.ts index 29ce3e8..a8e8ea9 100644 --- a/src/module-3/controllers/groups.ts +++ b/src/module-3/controllers/groups.ts @@ -1,5 +1,6 @@ import express from "express"; import { createValidator } from "express-joi-validation"; +import { log, logger } from "../loggers"; import * as GroupsService from "../services/groups"; import { Errors, GroupModel } from "../types"; import { isNull } from "./utils"; @@ -10,25 +11,28 @@ const router = express.Router(); /* Get all groups */ -router.get("/", async (req, res) => { +router.get("/", log(GroupsService.findAll), async (req, res) => { try { const groups = await GroupsService.findAll(); res.status(200).send(groups); } catch (e) { + logger.setError(e.message); res.status(500).send(e.message); } }); /* Find group by id */ -router.get("/:id", async (req, res) => { +router.get("/:id", log(GroupsService.find), async (req, res) => { try { const id = req.params.id; const group = await GroupsService.find(id); if (group) { return res.status(200).send(group); } - res.status(404).send("Group not found"); + const err = "Group not found"; + logger.setError(err); + res.status(404).send(err); } catch (e) { res.status(500).send(e.message); } @@ -36,27 +40,35 @@ router.get("/:id", async (req, res) => { /* Create new group */ -router.post("/", validator.body(groupValidationSchema), async (req, res) => { - try { - const body: GroupModel = req.body; - const isSuccess = await GroupsService.create(body); - if (!isSuccess) { - return res.status(400).send("Group with this name is already exists"); +router.post( + "/", + [log(GroupsService.create), validator.body(groupValidationSchema)], + async (req, res) => { + try { + const body: GroupModel = req.body; + const isSuccess = await GroupsService.create(body); + if (!isSuccess) { + const err = "Group with this name is already exists"; + logger.setError(err); + return res.status(400).send(err); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/groups"); - } catch (e) { - res.status(500).send(e.message); } -}); +); /* Delete group */ -router.delete("/:id", async (req, res) => { +router.delete("/:id", log(GroupsService.remove), async (req, res) => { try { const id = req.params.id; const isSuccess = await GroupsService.remove(id); if (isNull(isSuccess)) { - return res.status(404).send("Something wrong"); + const err = "Something wrong"; + logger.setError(err); + return res.status(404).send(err); } res.redirect("/api/groups"); } catch (e) { @@ -66,17 +78,21 @@ router.delete("/:id", async (req, res) => { /* Update group */ -router.put("/:id", validator.body(groupValidationSchema), async (req, res) => { - try { - const id = req.params.id; - const status = await GroupsService.update(id, req.body); - if ((status as Errors).type === "error") { - return res.status(404).send((status as Errors).message); +router.put( + "/:id", + [log(GroupsService.update), validator.body(groupValidationSchema)], + async ({ params: { id }, body }, res) => { + try { + const status = await GroupsService.update(id, body); + if ((status as Errors).type === "error") { + logger.setError(status); + return res.status(404).send((status as Errors).message); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/groups"); - } catch (e) { - res.status(500).send(e.message); } -}); +); export default router; diff --git a/src/module-3/controllers/user-groups.ts b/src/module-3/controllers/user-groups.ts index e83b280..67ca29b 100644 --- a/src/module-3/controllers/user-groups.ts +++ b/src/module-3/controllers/user-groups.ts @@ -1,5 +1,6 @@ import express from "express"; import { createValidator } from "express-joi-validation"; +import { log, logger } from "../loggers"; import { AddUsersToGroupModel } from "../services/types"; import * as UserGroupsService from "../services/user-groups"; import userGroupValidationSchema from "./validation/user-groups"; @@ -9,11 +10,12 @@ const router = express.Router(); /* Get user-groups list */ -router.get("/", async (req, res) => { +router.get("/", log(UserGroupsService.findAll), async (req, res) => { try { const userGroups = await UserGroupsService.findAll(); res.status(200).send(userGroups); } catch (e) { + logger.setError(e); res.status(500).send(e.message); } }); @@ -22,13 +24,17 @@ router.get("/", async (req, res) => { router.post( "/", - validator.body(userGroupValidationSchema), + [ + log(UserGroupsService.addUsersToGroup), + validator.body(userGroupValidationSchema) + ], async (req, res) => { try { - const body: AddUsersToGroupModel = req.body; - await UserGroupsService.addUsersToGroup(body.groupId, body.userIds); + const { groupId, userIds }: AddUsersToGroupModel = req.body; + await UserGroupsService.addUsersToGroup(groupId, userIds); res.redirect("/api/user-groups"); } catch (e) { + logger.setError(e); res.status(500).send(e.message); } } diff --git a/src/module-3/controllers/users.ts b/src/module-3/controllers/users.ts index f9b8b9c..459d94b 100644 --- a/src/module-3/controllers/users.ts +++ b/src/module-3/controllers/users.ts @@ -1,5 +1,6 @@ import express from "express"; import { createValidator } from "express-joi-validation"; +import { log, logger } from "../loggers"; import * as UsersService from "../services/users"; import { UserModel } from "../types"; import { isNull } from "./utils"; @@ -10,28 +11,35 @@ const router = express.Router(); /* Get users list */ -router.get("/", async (req, res) => { - try { - const users = await UsersService.getAutoSuggestUsers( - req.body.loginSubstring, - req.body.limit - ); - res.status(200).send(users); - } catch (e) { - res.status(500).send(e.message); +router.get( + "/", + log(UsersService.getAutoSuggestUsers), + async ({ body }, res) => { + try { + const users = await UsersService.getAutoSuggestUsers( + body.loginSubstring, + body.limit + ); + res.status(200).send(users); + } catch (e) { + logger.setError(e); + res.status(500).send(e.message); + } } -}); +); /* Find user by id */ -router.get("/:id", async (req, res) => { +router.get("/:id", log(UsersService.find), async (req, res) => { try { const id = req.params.id; const user = await UsersService.find(id); if (user) { return res.status(200).send(user); } - res.status(404).send("User not found"); + const err = "User not found"; + logger.setError(err); + res.status(404).send(err); } catch (e) { res.status(500).send(e.message); } @@ -39,27 +47,35 @@ router.get("/:id", async (req, res) => { /* Create user */ -router.post("/", validator.body(userValidationSchema), async (req, res) => { - try { - const body: UserModel = req.body; - const isSuccess = await UsersService.create(body); - if (!isSuccess) { - return res.status(400).send("User with this login is already exists"); +router.post( + "/", + [log(UsersService.create), validator.body(userValidationSchema)], + async (req, res) => { + try { + const body: UserModel = req.body; + const isSuccess = await UsersService.create(body); + if (!isSuccess) { + const err = "User with this login is already exists"; + logger.setError(err); + return res.status(400).send(err); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/users"); - } catch (e) { - res.status(500).send(e.message); } -}); +); /* Delete user */ -router.delete("/:id", async (req, res) => { +router.delete("/:id", log(UsersService.remove), async (req, res) => { try { const id = req.params.id; const isSuccess = await UsersService.remove(id); if (isNull(isSuccess)) { - return res.status(404).send("User with this id is not found"); + const err = "User with this id is not found"; + logger.setError(err); + return res.status(404).send(err); } res.redirect("/api/users"); } catch (e) { @@ -69,17 +85,23 @@ router.delete("/:id", async (req, res) => { /* Update user */ -router.put("/:id", validator.body(userValidationSchema), async (req, res) => { - try { - const id = req.params.id; - const isSuccess = await UsersService.update(id, req.body); - if (!isSuccess) { - return res.status(404).send("User with this id is not found"); +router.put( + "/:id", + [log(UsersService.update), validator.body(userValidationSchema)], + async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await UsersService.update(id, req.body); + if (!isSuccess) { + const err = "User with this id is not found"; + logger.setError(err); + return res.status(404).send(err); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/users"); - } catch (e) { - res.status(500).send(e.message); } -}); +); export default router; diff --git a/src/module-3/index.ts b/src/module-3/index.ts index c79e912..f769679 100644 --- a/src/module-3/index.ts +++ b/src/module-3/index.ts @@ -3,9 +3,18 @@ import groupsRouter from "./controllers/groups"; import userGroupsRouter from "./controllers/user-groups"; import usersRouter from "./controllers/users"; import db from "./data-access"; +import { + errorLoggerMiddleware, + initHandlers, + mainLoggerMiddleware +} from "./loggers"; const app = express(); +initHandlers(); + +app.use(errorLoggerMiddleware); + app.listen(3000, () => db .authenticate() @@ -16,6 +25,7 @@ app.listen(3000, () => ) .then(() => app.use(express.json())) .then(() => { + app.use(mainLoggerMiddleware); app.use("/api/groups", groupsRouter); app.use("/api/users", usersRouter); app.use("/api/user-groups", userGroupsRouter); diff --git a/src/module-3/loggers.ts b/src/module-3/loggers.ts new file mode 100644 index 0000000..61d4b95 --- /dev/null +++ b/src/module-3/loggers.ts @@ -0,0 +1,88 @@ +import { NextFunction, Request, Response } from "express"; +import morgan from "morgan"; +import winston from "winston"; + +export let logger: LoggerStore = null; + +export class LoggerStore { + private fnName = null; + private fnArgs = null; + private error = null; + + getFnData() { + console.log("\n"); + console.log("============================================"); + console.log("\n"); + console.log("Info of the executed function:"); + console.log({ + ...(this.fnName ? { fnName: this.fnName } : undefined), + ...(this.fnArgs ? { fnArgs: this.fnArgs } : undefined), + ...(this.error ? { error: this.error } : undefined) + }); + } + + setFnData(name: string, { body, params }: Request) { + this.fnName = name; + this.fnArgs = { ...body, ...params }; + } + + setError(message: any) { + this.error = message; + } +} + +const winstonLogger = winston.createLogger({ + transports: [ + new winston.transports.Console({ + level: "error", + handleExceptions: true + }) + ], + format: winston.format.combine( + winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }), + winston.format.colorize({ all: true }), + winston.format.printf( + (info) => `${info.timestamp} ${info.level}: ${info.message}` + ) + ), + exitOnError: false +}); + +export const errorLoggerMiddleware = morgan("tiny", { + stream: { + write: (message) => winstonLogger.error(message) + }, + skip: (req, res) => res.statusCode !== 500 +}); + +export const mainLoggerMiddleware = ( + req: Request, + res: Response, + next: NextFunction +) => { + req.once("close", () => { + logger.getFnData(); + }); + next(); +}; + +export const initHandlers = () => { + logger = new LoggerStore(); + + process.on("uncaughtException", (err) => { + console.log("We found an uncaught exception."); + console.log(err.stack); + }); + + process.on("unhandledRejection", (error) => { + console.log("unhandledRejection", error); + }); +}; + +export const log = (fn: (...params: any) => void) => { + return (req: Request, res: Response, next: NextFunction) => { + logger.setError(null); + logger.setFnData(fn.name, req); + next(); + }; +}; diff --git a/src/module-3/services/groups.ts b/src/module-3/services/groups.ts index 5dd1bdf..a4ed5f5 100644 --- a/src/module-3/services/groups.ts +++ b/src/module-3/services/groups.ts @@ -12,10 +12,11 @@ export const find = async (id: string) => } }); -export const findAll = async () => - Group.findAll({ +export const findAll = async () => { + return Group.findAll({ raw: true }); +}; export const create = async (model: GroupModel) => { const { name } = model;