diff --git a/package-lock.json b/package-lock.json index 1f230c56..5c58e9d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,6 +82,15 @@ "regenerator-runtime": "^0.13.4" } }, + "@babel/runtime-corejs3": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.6.tgz", + "integrity": "sha512-Xl8SPYtdjcMoCsIM4teyVRg7jIcgl8F2kRtoCcXuHzXswt9UxZCS6BzRo8fcnCuP6u2XtPgvyonmEPF57Kxo9Q==", + "requires": { + "core-js-pure": "^3.14.0", + "regenerator-runtime": "^0.13.4" + } + }, "@commitlint/cli": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-11.0.0.tgz", @@ -823,6 +832,47 @@ "uri-js": "^4.2.2" } }, + "amqplib": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.8.0.tgz", + "integrity": "sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA==", + "requires": { + "bitsyntax": "~0.1.0", + "bluebird": "^3.7.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "~5.2.1", + "url-parse": "~1.5.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -1181,8 +1231,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { "version": "1.0.0", @@ -1269,11 +1318,35 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, + "bitsyntax": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz", + "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", + "requires": { + "buffer-more-ints": "~1.0.0", + "debug": "~2.6.9", + "safe-buffer": "~5.1.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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "body-parser": { "version": "1.19.0", @@ -1376,6 +1449,11 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, "buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -1435,7 +1513,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -1725,7 +1802,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -1858,8 +1934,7 @@ "cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" }, "copy-descriptor": { "version": "0.1.1", @@ -1872,11 +1947,15 @@ "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==", "dev": true }, + "core-js-pure": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.15.0.tgz", + "integrity": "sha512-RO+LFAso8DB6OeBX9BAcEGvyth36QtxYon1OyVsITNVtSKr/Hos0BXZwnsOJ7o+O6KHtK+O+cJIEj9NGg6VwFA==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { "version": "7.0.0", @@ -2247,6 +2326,11 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, + "deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=" + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -2307,8 +2391,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "depd": { "version": "1.1.2", @@ -3128,6 +3211,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -3296,8 +3384,12 @@ "formidable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", - "dev": true + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" + }, + "forward-emitter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/forward-emitter/-/forward-emitter-0.1.1.tgz", + "integrity": "sha1-Vu3QwIIlDtujNOC5Iv/SwBk53uE=" }, "forwarded": { "version": "0.1.2", @@ -3344,8 +3436,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -3359,6 +3450,11 @@ "integrity": "sha512-YUJTQkApkLT/fru0QdYWP0lVZdPKhF5kXCP24sgI4gR/vFMJFopCj5t1+9FAKIYcML/nxzx2PMkA1ymO1FC+tQ==", "dev": true }, + "generic-pool": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.8.tgz", + "integrity": "sha512-Pz93INFSbhjEROVbM91rurD05G+Kx8833rG+lVU57mznEBpzkc1f5/g+d511a1Yf8dbAEsm7DDA3QLytMFbiGA==" + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3369,7 +3465,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -3513,7 +3608,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -3532,8 +3626,7 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "has-value": { "version": "1.0.0", @@ -3868,6 +3961,11 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "individual": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", + "integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c=" + }, "inflection": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", @@ -4638,8 +4736,7 @@ "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" }, "lodash.get": { "version": "4.4.2", @@ -4682,6 +4779,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -4736,7 +4838,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -6204,6 +6305,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -6224,6 +6330,96 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "rascal": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/rascal/-/rascal-13.0.3.tgz", + "integrity": "sha512-zj+roDwfUZcXvzacyT9lGVh5vp1aivFdY5/9AXfaLJcHB7ZmGw2kkzKdRZOjLkJ5VPIVjFIWBffxelp0xMQ5xw==", + "requires": { + "async": "^3.2.0", + "debug": "^4.1.1", + "deep-freeze": "0.0.1", + "forward-emitter": "^0.1.1", + "generic-pool": "^3.7.1", + "lodash": "^4.17.21", + "lru-cache": "^6.0.0", + "safe-json-parse": "^4.0.0", + "stashback": "^1.1.2", + "superagent": "^6.1.0", + "uuid": "^8.3.2", + "xregexp": "^5.0.1" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", @@ -6383,8 +6579,7 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regex-not": { "version": "1.0.2", @@ -6439,6 +6634,11 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -6521,11 +6721,27 @@ "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", "dev": true }, + "rust-result": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz", + "integrity": "sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I=", + "requires": { + "individual": "^2.0.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz", + "integrity": "sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw=", + "requires": { + "rust-result": "^1.0.0" + } + }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", @@ -6681,6 +6897,23 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "dependencies": { + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + } + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -7005,6 +7238,16 @@ } } }, + "stashback": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/stashback/-/stashback-1.1.3.tgz", + "integrity": "sha512-MS4X5BV7JJG8GE6IR1X3Y2HEZH3L407KlevQlnadmCLL32ORBvK6Ojm/MtB12MF/XngYgHHSucaNG+tcLmK8jg==", + "requires": { + "debug": "^4.1.1", + "lodash.defaults": "^4.2.0", + "lodash.reduce": "^4.6.0" + } + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -7094,7 +7337,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -7566,6 +7808,15 @@ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -7599,8 +7850,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utile": { "version": "0.3.0", @@ -7857,6 +8107,14 @@ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" }, + "xregexp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.0.2.tgz", + "integrity": "sha512-JPNfN40YMNSDxZrahMrmtNH1QqPJp0/qNeEJM2nnOlhcBdfCCjekPYFV2OnwKxwvpEYglH1RBotbpRRaEuCG8Q==", + "requires": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7871,8 +8129,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { "version": "1.10.0", diff --git a/package.json b/package.json index 939ec445..7a69bc9e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "test-watch": "NODE_ENV=test NODE_LOG_LEVEL=info mocha -r dotenv/config dotenv_config_path=.env.test --timeout 10000 --require co-mocha -w -b --ignore './server/repositories/**/*.spec.js' './server/setup.js' './server/**/*.spec.js' './__tests__/seed.spec.js' './__tests__/supertest.js'", "test-watch-debug": "NODE_ENV=test NODE_LOG_LEVEL=debug DOTENV_CONFIG_PATH=.env.test mocha -r dotenv/config --timeout 10000 --require co-mocha -w -b --ignore './server/repositories/**/*.spec.js' './server/setup.js' './server/**/*.spec.js' './__tests__/seed.spec.js' './__tests__/**/*.spec.js'", "test-e2e": "NODE_TLS_REJECT_UNAUTHORIZED='0' mocha --config ./__tests__/e2e/.mocharc.js", - "test-e2e-locally": "RUN_E2E_LOCALLY=true DB_SSL=false NODE_ENV=test NODE_LOG_LEVEL=debug NODE_TLS_REJECT_UNAUTHORIZED='0' mocha --config ./__tests__/e2e/.mocharc.js ./server/setup.js", + "test-e2e-locally": "RUN_E2E_LOCALLY=true DB_SSL=false NODE_LOG_LEVEL=debug NODE_TLS_REJECT_UNAUTHORIZED='0' mocha --config ./__tests__/e2e/.mocharc.js ./server/setup.js", "prettier-fix": "prettier ./ --write", "db-migrate-ci": "cd database; db-migrate up", "start-db": "docker-compose up" @@ -34,6 +34,7 @@ "license": "GPL-3.0-or-later", "dependencies": { "@sentry/node": "^5.1.0", + "amqplib": "^0.8.0", "bcryptjs": "^2.4.3", "body-parser": "^1.18.2", "chai-uuid": "^1.0.6", @@ -51,6 +52,7 @@ "morgan": "^1.9.1", "nodemon": "^2.0.4", "pg": "^8.5.1", + "rascal": "^13.0.3", "uuid": "^8.2.0" }, "devDependencies": { diff --git a/server/models/Wallet.js b/server/models/Wallet.js index 96ac5d52..c165900b 100644 --- a/server/models/Wallet.js +++ b/server/models/Wallet.js @@ -21,7 +21,7 @@ class Wallet{ this._id = idOrJSON.id; this._JSON = idOrJSON; }else{ - throw new HttpError(500); + throw new HttpError(500, "Wrong constructor arg for wallet"); } const WalletService = require("../services/WalletService"); this.walletRepository = new WalletRepository(session); diff --git a/server/repositories/TransferRepository.js b/server/repositories/TransferRepository.js index a4a89f30..2fbf7c25 100644 --- a/server/repositories/TransferRepository.js +++ b/server/repositories/TransferRepository.js @@ -28,6 +28,18 @@ class TransferRepository extends BaseRepository{ state: Transfer.STATE.pending, }); } + + async getTokenAndCaptureIds(id){ + return await this._session.getDB().raw( + ` + SELECT token_id, capture_id FROM "transaction" tr + LEFT JOIN "token" t + ON tr.token_id = t.id + WHERE transfer_id = ? + `, + [id], + ); + } } module.exports = TransferRepository; diff --git a/server/repositories/TransferRepository.spec.js b/server/repositories/TransferRepository.spec.js index b3cc4b24..03d4e683 100644 --- a/server/repositories/TransferRepository.spec.js +++ b/server/repositories/TransferRepository.spec.js @@ -6,6 +6,7 @@ const knex = require("../database/knex"); const tracker = mockKnex.getTracker(); const Session = require("../models/Session"); const uuid = require('uuid'); +const sinon = require('sinon'); describe("TransferRepository", () => { let transferRepository; @@ -74,5 +75,24 @@ describe("TransferRepository", () => { expect(result).lengthOf(1); }); + it("getTokensById", async () => { + const data = [{ + capture_id: "c", + token_id: "t", + }]; + tracker.uninstall(); + tracker.install(); + tracker.on('query', function sendResult(query, step) { + [ + function firstQuery() { + expect(query.sql).match(/capture_id/); + query.response(data); + }, + ][step - 1](); + }); + const result = await transferRepository.getTokenAndCaptureIds(1); + sinon.assert.match(result, data); + }); + }); diff --git a/server/routes/transferRouter.js b/server/routes/transferRouter.js index 365eacfe..08b5e02d 100644 --- a/server/routes/transferRouter.js +++ b/server/routes/transferRouter.js @@ -57,6 +57,7 @@ transferRouter.post( const walletLogin = await walletService.getById(res.locals.wallet_id); const walletSender = await walletService.getByIdOrName(req.body.sender_wallet); const walletReceiver = await walletService.getByIdOrName(req.body.receiver_wallet); + const transferService = new TransferService(session); // check if this transfer is a claim (claim == not transferrrable tokens) const claim = req.body.claim; @@ -76,7 +77,18 @@ transferRouter.post( // TODO: get only transferrable tokens result = await walletLogin.transferBundle(walletSender, walletReceiver, req.body.bundle.bundle_size, claim); } - const transferService = new TransferService(session); + + // send message + if (result.state === Transfer.STATE.completed) { + // just send message in production + if(process.env.NODE_ENV !== "test"){ + await transferService.sendMessage(result.id); + } + } + + await session.commitTransaction(); + + // response result = await transferService.convertToResponse(result); if (result.state === Transfer.STATE.completed) { res.status(201).json(result); @@ -88,7 +100,6 @@ transferRouter.post( } else { throw new Error(`Unexpected state ${result.state}`); } - await session.commitTransaction(); }catch(e){ if(e instanceof HttpError && !e.shouldRollback()){ // if the error type is HttpError, means the exception has been handled @@ -127,8 +138,12 @@ transferRouter.post( const transferJson2 = await transferService.convertToResponse( transferJson, ); - res.status(200).json(transferJson2); + // just send message in production + if(process.env.NODE_ENV !== "test"){ + await transferService.sendMessage(transferJson.id); + } await session.commitTransaction(); + res.status(200).json(transferJson2); } catch (e) { if (e instanceof HttpError && !e.shouldRollback()) { // if the error type is HttpError, means the exception has been handled @@ -167,8 +182,8 @@ transferRouter.post( const transferJson2 = await transferService.convertToResponse( transferJson, ); - res.status(200).json(transferJson2); await session.commitTransaction(); + res.status(200).json(transferJson2); } catch (e) { if (e instanceof HttpError && !e.shouldRollback()) { // if the error type is HttpError, means the exception has been handled @@ -207,8 +222,8 @@ transferRouter.delete( const transferJson2 = await transferService.convertToResponse( transferJson, ); - res.status(200).json(transferJson2); await session.commitTransaction(); + res.status(200).json(transferJson2); } catch (e) { if (e instanceof HttpError && !e.shouldRollback()) { // if the error type is HttpError, means the exception has been handled @@ -280,8 +295,12 @@ transferRouter.post( const transferJson2 = await transferService.convertToResponse( transferJson, ); - res.status(200).json(transferJson2); + // just send message in production + if(process.env.NODE_ENV !== "test"){ + await transferService.sendMessage(transferJson.id); + } await session.commitTransaction(); + res.status(200).json(transferJson2); } catch (e) { if (e instanceof HttpError && !e.shouldRollback()) { // if the error type is HttpError, means the exception has been handled diff --git a/server/routes/transferRouter.spec.js b/server/routes/transferRouter.spec.js index 5f7437f1..329e76c7 100644 --- a/server/routes/transferRouter.spec.js +++ b/server/routes/transferRouter.spec.js @@ -148,6 +148,7 @@ describe("transferRouter", () => { id: tokenId, state: Transfer.STATE.completed, }); + sinon.stub(TransferService.prototype, "sendMessage"); const res = await request(app) .post('/') .send({ @@ -188,6 +189,7 @@ describe("transferRouter", () => { id: transferId, state: Transfer.STATE.completed, }); + const sendMessage = sinon.stub(TransferService.prototype, "sendMessage"); const res = await request(app) .post('/') .send({ @@ -196,6 +198,9 @@ describe("transferRouter", () => { receiver_wallet: wallet2Id, }); expect(res).property('statusCode').eq(201); + + // should not send message to queue because ENV = test + sinon.assert.notCalled(sendMessage); }); // //TODO: test for case 1: with trust relationship, tokens specified diff --git a/server/services/MQConfig.js b/server/services/MQConfig.js new file mode 100644 index 00000000..16756057 --- /dev/null +++ b/server/services/MQConfig.js @@ -0,0 +1,26 @@ +module.exports = { + config: { + "vhosts": { + "test": { + "connection": { + "url": process.env.RABBIT_MQ_URL, + "socketOptions": { + "timeout": 1000 + } + }, + "exchanges": ["wallet-service-ex"], + "queues": ["token-transfer:events"], + "bindings": [ + "wallet-service-ex[token.transfer] -> token-transfer:events" + ], + "publications": { + "token-assigned": { + "exchange": "wallet-service-ex", + "routingKey": "token.transfer" + } + }, + } + } + } +} + diff --git a/server/services/MQService.js b/server/services/MQService.js new file mode 100644 index 00000000..442c136c --- /dev/null +++ b/server/services/MQService.js @@ -0,0 +1,44 @@ +const Broker = require('rascal').BrokerAsPromised; +const config = require("./MQConfig").config; +const HttpError = require("../utils/HttpError"); +const log = require("loglevel"); + +class MQService{ + + constructor(session){ + this._settsion = session; + } + + sendMessage(payload){ + log.warn("to send message"); + return new Promise((resolve, reject) => { + Broker.create(config) + .then(broker => { + broker.publish("token-assigned", payload) + .then(publication => { + log.warn("publication is on"); + publication + .on("success", () => { + log.warn("message sent!"); + resolve(true); + }) + .on("error", (err, messageId)=> { + const error = `Error with id ${messageId} ${err.message}`; + log.error(error); + reject(new HttpError(500, error)); + }); + }) + .catch(err => { + log.error(err); + reject(new HttpError(500, `Error publishing message ${err}`)); + }) + }) + .catch(err => { + log.error(err); + reject(new HttpError(500, `Error create broker ${err}`)); + }) + }); + } +} + +module.exports = MQService; diff --git a/server/services/MQService.spec.js b/server/services/MQService.spec.js new file mode 100644 index 00000000..bba52fc0 --- /dev/null +++ b/server/services/MQService.spec.js @@ -0,0 +1,103 @@ +const MQService = require("./MQService"); +const Broker = require('rascal').BrokerAsPromised; +const sinon = require("sinon"); +const {expect} = require("chai"); +const jestExpect = require("expect"); +const log = require("loglevel"); + +describe("MQService", () => { + + afterEach(() => { + sinon.restore(); + }); + + it("send message successfully", async () => { + const broker = { + publish: async () => { + console.log("publish"); + return { + on(event, handler){ + // mock the success event + if(event === "success"){ + setImmediate(handler); + } + return this; + } + } + } + }; + sinon.spy(broker, "publish"); + sinon.stub(Broker, "create").resolves(broker); + const mqService = new MQService(); + + const payload = {a:1}; + const result = await mqService.sendMessage(payload); + expect(result).eq(true); + sinon.assert.calledWith(broker.publish, "raw-capture-created", payload, "field-data.capture.creation"); + + }); + + it("send message with problem", async () => { + sinon.stub(Broker, "create").resolves({ + publish: async () => { + console.log("publish"); + return { + on(event, handler){ + // mock the error event + if(event === "error"){ + setImmediate(() => handler(new Error("Message sending wrong"), "No.1")); + } + return this; + } + } + } + }); + const mqService = new MQService(); + + await jestExpect(async () => { + await mqService.sendMessage({a:1}); + }).rejects.toThrow(/Message sending wrong/); + + }); + +}); + +describe("Real operation, just for dev", () => { + + it("Send and receive message", async function(){ + try{ + + const mqService = new MQService(); + const payload = {a:1}; + const result = await mqService.sendMessage(payload); + log.warn("result:", result); + + +// await new Promise((resolve, reject) => { +// // check the message +// // Consume a message +// const config = require("./MQConfig").config; +// Broker.create(config) +// .then(broker => { +// log.info("connected to broker"); +// broker.subscribeAll() +// .then(subscriptions => { +// subscriptions.forEach( subscription => { +// subscription.on('message', (message, content, ackOrNack) => { +// log.warn("message:", message, content); +// log.warn("message content received:", message.content && message.content.toString()); +// ackOrNack(); +// resolve(); +// }).on('error', console.error); +// }); +// }); +// }); +// const mqService = new MQService(); +// const payload = {a:1}; +// mqService.sendMessage(payload); +// }); + }catch(e){ + log.error("e:",e ); + }; + }); +}); diff --git a/server/services/TransferService.js b/server/services/TransferService.js index 1097f923..96726f84 100644 --- a/server/services/TransferService.js +++ b/server/services/TransferService.js @@ -1,9 +1,14 @@ const WalletService = require('./WalletService'); +const MQService = require("./MQService"); +const log = require("loglevel"); +const TransferRepository = require('../repositories/TransferRepository'); class TransferService { constructor(session) { this._session = session; - this.walletService = new WalletService(session); + this._walletService = new WalletService(session); + this._mqService = new MQService(); + this._transferRepository = new TransferRepository(session); } async convertToResponse(transferObject) { @@ -14,25 +19,56 @@ class TransferService { } = transferObject; const result = { ...transferObject }; { - const wallet = await this.walletService.getById(originator_wallet_id); + const wallet = await this._walletService.getById(originator_wallet_id); const json = await wallet.toJSON(); result.originating_wallet = json.name; delete result.originator_wallet_id; } { - const wallet = await this.walletService.getById(source_wallet_id); + const wallet = await this._walletService.getById(source_wallet_id); const json = await wallet.toJSON(); result.source_wallet = await json.name; delete result.source_wallet_id; } { - const wallet = await this.walletService.getById(destination_wallet_id); + const wallet = await this._walletService.getById(destination_wallet_id); const json = await wallet.toJSON(); result.destination_wallet = await json.name; delete result.destination_wallet_id; } return result; } + + /* + * Send message to queue, inform about the transfer detail, token, and + * associated tree/capture + * + { + "type": "TokensAssigned", + "wallet_name": "joeswallet", + "entries": [ + { "capture_id": "63e00bca-8eb0-11eb-8dcd-0242ac130003", "token_id": "9d7abad8-8eb0-11eb-8dcd-0242ac130003" }, + { "capture_id": "8533b704-8eb0-11eb-8dcd-0242ac130003", "token_id":"a5799d94-8eb0-11eb-8dcd-0242ac130003" } ] + } + */ + async sendMessage(transferId){ + log.debug("send message"); + const transfer = await this._transferRepository.getById(transferId); + const walletReceiver = await this._walletService.getById(transfer.destination_wallet_id); + const walletReceiverObj = await walletReceiver.toJSON(); + const walletSender = await this._walletService.getById(transfer.source_wallet_id); + const walletSenderObj = await walletSender.toJSON(); + const tokenData = await this._transferRepository.getTokenAndCaptureIds(transferId); + const message = { + transfer_id: transferId, + type: "TokensAssigned", + wallet_name : walletReceiverObj.name, + wallet_name_sender : walletSenderObj.name, + entries: tokenData, + }; + await this._mqService.sendMessage(message); + } + } module.exports = TransferService; diff --git a/server/services/TransferService.spec.js b/server/services/TransferService.spec.js index 53412797..334627db 100644 --- a/server/services/TransferService.spec.js +++ b/server/services/TransferService.spec.js @@ -10,6 +10,8 @@ chai.use(sinonChai); const { expect } = chai; const Session = require('../models/Session'); const Wallet = require('../models/Wallet'); +const MQService = require("./MQService"); +const TransferRepository = require("../repositories/TransferRepository"); describe('TransferService', () => { let transferService; @@ -43,4 +45,49 @@ describe('TransferService', () => { expect(result).property('originating_wallet').eq('testName'); expect(result).property('destination_wallet').eq('testName'); }); + + describe("sendMessage", () => { + + it("Successfully", async () => { + const transferId = "x"; + const transfer = { + id: transferId, + destination_wallet_id: 1, + source_wallet_id: 2, + } + const walletA = new Wallet({ + id: uuid.v1(), + name: "walletA", + }); + const walletB = new Wallet({ + id: uuid.v1(), + name: "walletB", + }); + const sendMessage = sinon.stub(MQService.prototype, "sendMessage"); + sinon.stub(TransferRepository.prototype, "getById").resolves(transfer); + sinon.stub(TransferRepository.prototype, "getTokenAndCaptureIds").resolves([{ + token_id: "t", + capture_id: "c", + }]); + sinon.stub(WalletService.prototype, "getById") + .onFirstCall() + .resolves(walletA) + .onSecondCall() + .resolves(walletB); + await transferService.sendMessage(transferId); + sinon.assert.calledWith(sendMessage, sinon.match({ + // TODO can not match type, why? + // type: "TokenAssigned", + wallet_name: "walletA", + wallet_name_sender: "walletB", + transfer_id: transferId, + entries: [{ + capture_id: "c", + token_id: "t", + }], + })); + + }); + + }); });