diff --git a/package-lock.json b/package-lock.json index c7f8c9ccc..19f62231f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1277,7 +1277,6 @@ "node_modules/@babel/core": { "version": "7.28.5", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2780,9 +2779,9 @@ "license": "MIT" }, "node_modules/@emnapi/runtime": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", - "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", "optional": true, "dependencies": { @@ -2873,8 +2872,6 @@ }, "node_modules/@hapi/address": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^11.0.2" @@ -2885,26 +2882,18 @@ }, "node_modules/@hapi/formula": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", "license": "BSD-3-Clause" }, "node_modules/@hapi/hoek": { "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", "license": "BSD-3-Clause" }, "node_modules/@hapi/pinpoint": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", "license": "BSD-3-Clause" }, "node_modules/@hapi/tlds": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.4.tgz", - "integrity": "sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==", "license": "BSD-3-Clause", "engines": { "node": ">=14.0.0" @@ -2912,8 +2901,6 @@ }, "node_modules/@hapi/topo": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^11.0.2" @@ -2958,8 +2945,6 @@ }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", "cpu": [ "arm64" ], @@ -3002,8 +2987,6 @@ }, "node_modules/@img/sharp-libvips-darwin-arm64": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", "cpu": [ "arm64" ], @@ -3395,6 +3378,8 @@ }, "node_modules/@img/sharp-win32-x64": { "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], @@ -3829,8 +3814,6 @@ }, "node_modules/@mswjs/interceptors": { "version": "0.39.8", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.8.tgz", - "integrity": "sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==", "dev": true, "license": "MIT", "dependencies": { @@ -3903,15 +3886,11 @@ }, "node_modules/@open-draft/deferred-promise": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "dev": true, "license": "MIT" }, "node_modules/@open-draft/logger": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3921,8 +3900,6 @@ }, "node_modules/@open-draft/until": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", "dev": true, "license": "MIT" }, @@ -3936,9 +3913,6 @@ }, "node_modules/@paypal/checkout-server-sdk": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@paypal/checkout-server-sdk/-/checkout-server-sdk-1.0.3.tgz", - "integrity": "sha512-UEdq8akEdMz0Vs4qoQFU2gMp8PpyE/HKyMwiZuK4vIWUKl8jfd1fWKjQN5cDFm9NkFUIp5U7h++rdMOVj9WMNA==", - "deprecated": "Package no longer supported. The author suggests using the @paypal/paypal-server-sdk package instead: https://www.npmjs.com/package/@paypal/paypal-server-sdk. Contact Support at https://www.npmjs.com/support for more info.", "license": "SEE LICENSE IN https://github.com/paypal/Checkout-NodeJS-SDK/blob/master/LICENSE", "dependencies": { "@paypal/paypalhttp": "^1.0.1" @@ -3963,8 +3937,6 @@ }, "node_modules/@paypal/paypalhttp": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@paypal/paypalhttp/-/paypalhttp-1.0.1.tgz", - "integrity": "sha512-DC7AHxTT7drF6dUi3YaFdPVuT15sIkpD5H2eHmdtFgxM4UanS1o1ZDfMhR9mpxd8o+X6pz2r+EZVRRq+n1cssQ==", "license": "MIT", "engines": { "node": ">=4" @@ -3980,7 +3952,6 @@ "node_modules/@redis/client": { "version": "1.6.1", "license": "MIT", - "peer": true, "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -4751,20 +4722,14 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, "node_modules/@streamparser/json": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.6.tgz", - "integrity": "sha512-vL9EVn/v+OhZ+Wcs6O4iKE9EUpwHUqHmCtNUMWjqp+6dr85+XPOSGTEsqYNq1Vn04uk9SWlOVmx9J48ggJVT2Q==", "license": "MIT" }, "node_modules/@swc/helpers": { "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", - "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" @@ -4948,7 +4913,6 @@ "node_modules/@types/node-fetch": { "version": "2.6.13", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "form-data": "^4.0.4" @@ -5083,7 +5047,6 @@ "version": "8.15.0", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5786,8 +5749,6 @@ }, "node_modules/body-parser": { "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -5817,8 +5778,6 @@ }, "node_modules/body-parser/node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -5841,8 +5800,6 @@ }, "node_modules/body-parser/node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5877,8 +5834,6 @@ }, "node_modules/brotli": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", "license": "MIT", "dependencies": { "base64-js": "^1.1.2" @@ -5901,7 +5856,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -6505,8 +6459,6 @@ }, "node_modules/crypto-js": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, "node_modules/css-select": { @@ -6727,8 +6679,6 @@ }, "node_modules/dfa": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", "license": "MIT" }, "node_modules/diff-sequences": { @@ -7134,7 +7084,6 @@ "version": "8.57.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7280,7 +7229,6 @@ "version": "2.32.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7332,7 +7280,6 @@ "version": "6.10.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -7361,7 +7308,6 @@ "version": "7.37.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -7393,7 +7339,6 @@ "version": "4.6.2", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7700,8 +7645,6 @@ }, "node_modules/express": { "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -7982,8 +7925,6 @@ }, "node_modules/fontkit": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", - "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", "license": "MIT", "dependencies": { "@swc/helpers": "^0.5.12", @@ -8067,10 +8008,6 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -9017,8 +8954,6 @@ }, "node_modules/is-node-process": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", "dev": true, "license": "MIT" }, @@ -10196,8 +10131,6 @@ }, "node_modules/joi": { "version": "18.0.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.2.tgz", - "integrity": "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==", "license": "BSD-3-Clause", "dependencies": { "@hapi/address": "^5.1.1", @@ -10214,8 +10147,6 @@ }, "node_modules/jpeg-exif": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", - "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", "license": "MIT" }, "node_modules/js-tokens": { @@ -10277,15 +10208,11 @@ }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true, "license": "ISC" }, "node_modules/json2csv": { "version": "6.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-6.0.0-alpha.2.tgz", - "integrity": "sha512-nJ3oP6QxN8z69IT1HmrJdfVxhU1kLTBVgMfRnNZc37YEY+jZ4nU27rBGxT4vaqM/KUCavLRhntmTuBFqZLBUcA==", "license": "MIT", "dependencies": { "@streamparser/json": "^0.0.6", @@ -10341,8 +10268,6 @@ }, "node_modules/jsonwebtoken/node_modules/jws": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { "jwa": "^1.4.2", @@ -10384,8 +10309,6 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -10471,8 +10394,6 @@ }, "node_modules/linebreak": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", - "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", "license": "MIT", "dependencies": { "base64-js": "0.0.8", @@ -10481,8 +10402,6 @@ }, "node_modules/linebreak/node_modules/base64-js": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10600,9 +10519,6 @@ }, "node_modules/lodash.get": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", "license": "MIT" }, "node_modules/lodash.includes": { @@ -11307,8 +11223,6 @@ }, "node_modules/nock": { "version": "14.0.10", - "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.10.tgz", - "integrity": "sha512-Q7HjkpyPeLa0ZVZC5qpxBt5EyLczFJ91MEewQiIi9taWuA0KB/MDJlUWtON+7dGouVdADTQsf9RA7TZk6D8VMw==", "dev": true, "license": "MIT", "dependencies": { @@ -11386,8 +11300,6 @@ }, "node_modules/node-forge": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", - "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -11404,8 +11316,6 @@ }, "node_modules/nodemailer": { "version": "7.0.11", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.11.tgz", - "integrity": "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==", "license": "MIT-0", "engines": { "node": ">=6.0.0" @@ -11682,8 +11592,6 @@ }, "node_modules/outvariant": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", - "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", "dev": true, "license": "MIT" }, @@ -11750,8 +11658,6 @@ }, "node_modules/pako": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", "license": "MIT" }, "node_modules/parent-module": { @@ -11784,8 +11690,6 @@ }, "node_modules/parse-link-header": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz", - "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==", "license": "MIT", "dependencies": { "xtend": "~4.0.1" @@ -11867,8 +11771,6 @@ }, "node_modules/pdfkit": { "version": "0.17.2", - "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.17.2.tgz", - "integrity": "sha512-UnwF5fXy08f0dnp4jchFYAROKMNTaPqb/xgR8GtCzIcqoTnbOqtp3bwKvO4688oHI6vzEEs8Q6vqqEnC5IUELw==", "license": "MIT", "dependencies": { "crypto-js": "^4.2.0", @@ -12045,9 +11947,7 @@ } }, "node_modules/png-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", - "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + "version": "1.0.0" }, "node_modules/possible-typed-array-names": { "version": "1.1.0", @@ -12174,8 +12074,6 @@ }, "node_modules/propagate": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", "dev": true, "license": "MIT", "engines": { @@ -12227,8 +12125,6 @@ }, "node_modules/qs": { "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -12274,8 +12170,6 @@ }, "node_modules/raw-body": { "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -12289,8 +12183,6 @@ }, "node_modules/raw-body/node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -12309,8 +12201,6 @@ }, "node_modules/raw-body/node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12558,8 +12448,6 @@ }, "node_modules/restructure": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", - "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", "license": "MIT" }, "node_modules/reusify": { @@ -12908,8 +12796,6 @@ }, "node_modules/sharp": { "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -13294,8 +13180,6 @@ }, "node_modules/strict-event-emitter": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true, "license": "MIT" }, @@ -13638,8 +13522,6 @@ }, "node_modules/tiny-inflate": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, "node_modules/tiny-warning": { @@ -13923,8 +13805,6 @@ }, "node_modules/unicode-properties": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", "license": "MIT", "dependencies": { "base64-js": "^1.3.0", @@ -13940,8 +13820,6 @@ }, "node_modules/unicode-trie": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", "license": "MIT", "dependencies": { "pako": "^0.2.5", diff --git a/src/controllers/bmdashboard/__tests__/bmIssueController.test.js b/src/controllers/bmdashboard/__tests__/bmIssueController.test.js index 9525d0b3c..385e8265d 100644 --- a/src/controllers/bmdashboard/__tests__/bmIssueController.test.js +++ b/src/controllers/bmdashboard/__tests__/bmIssueController.test.js @@ -28,31 +28,27 @@ describe('Building Issue Controller', () => { it('should fetch all issues successfully', async () => { const mockIssues = [{ _id: '1', name: 'Issue 1' }]; mockBuildingIssue.find.mockReturnValue({ - populate: jest.fn().mockReturnThis(), - then: jest.fn((resolve) => resolve(mockIssues)), - catch: jest.fn(), + populate: jest.fn().mockResolvedValue(mockIssues), }); await controller.bmGetIssue(req, res); expect(mockBuildingIssue.find).toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(200); - expect(res.send).toHaveBeenCalledWith(mockIssues); + expect(res.json).toHaveBeenCalledWith(mockIssues); }); it('should handle errors when fetching issues', async () => { const error = new Error('Database error'); mockBuildingIssue.find.mockReturnValue({ - populate: jest.fn().mockReturnThis(), - then: jest.fn().mockImplementation(() => Promise.reject(error)), - catch: jest.fn((reject) => reject(error)), + populate: jest.fn().mockRejectedValue(error), }); await controller.bmGetIssue(req, res); expect(mockBuildingIssue.find).toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(500); - expect(res.send).toHaveBeenCalledWith(error); + expect(res.json).toHaveBeenCalledWith(error); }); }); @@ -61,30 +57,24 @@ describe('Building Issue Controller', () => { const mockNewIssue = { _id: '123', name: 'New Issue' }; req.body = mockNewIssue; - mockBuildingIssue.create.mockReturnValue({ - then: jest.fn((resolve) => resolve(mockNewIssue)), - catch: jest.fn(), - }); + mockBuildingIssue.create.mockResolvedValue(mockNewIssue); await controller.bmPostIssue(req, res); expect(mockBuildingIssue.create).toHaveBeenCalledWith(mockNewIssue); expect(res.status).toHaveBeenCalledWith(201); - expect(res.send).toHaveBeenCalledWith(mockNewIssue); + expect(res.json).toHaveBeenCalledWith(mockNewIssue); }); it('should handle errors when creating a new issue', async () => { const error = new Error('Creation error'); - mockBuildingIssue.create.mockReturnValue({ - then: jest.fn().mockImplementation(() => Promise.reject(error)), - catch: jest.fn((reject) => reject(error)), - }); + mockBuildingIssue.create.mockRejectedValue(error); await controller.bmPostIssue(req, res); expect(mockBuildingIssue.create).toHaveBeenCalledWith(req.body); expect(res.status).toHaveBeenCalledWith(500); - expect(res.send).toHaveBeenCalledWith(error); + expect(res.json).toHaveBeenCalledWith(error); }); }); }); diff --git a/src/controllers/bmdashboard/bmIssueController.js b/src/controllers/bmdashboard/bmIssueController.js index 19f362341..7db7ef7e1 100644 --- a/src/controllers/bmdashboard/bmIssueController.js +++ b/src/controllers/bmdashboard/bmIssueController.js @@ -1,40 +1,113 @@ const mongoose = require('mongoose'); -// const BuildingIssue = require('../../models/bmdashboard/buildingIssue'); const BuildingProject = require('../../models/bmdashboard/buildingProject'); +const MS_PER_MINUTE = 60 * 1000; +const MINUTES_PER_HOUR = 60; +const HOURS_PER_DAY = 24; +const AVG_DAYS_PER_MONTH = 30.44; +const MAX_LONGEST_OPEN_ISSUES = 7; + +const getProjectFilterIds = (projectsParam) => + projectsParam ? projectsParam.split(',').map((id) => id.trim()) : []; + +const filterProjectIdsByDates = async (datesParam, currentProjectIds) => { + if (!datesParam) { + return currentProjectIds; + } + + const [start, end] = datesParam.split(',').map((d) => d.trim()); + const matchingProjects = await BuildingProject.find({ + dateCreated: { $gte: new Date(start), $lte: new Date(end) }, + isActive: true, + }) + .select('_id') + .lean(); + + const dateIds = matchingProjects.map((p) => p._id.toString()); + if (currentProjectIds.length === 0) { + return dateIds; + } + + return currentProjectIds.filter((id) => dateIds.includes(id)); +}; + +const getDurationOpenMonths = (issueDate) => + Math.ceil( + (Date.now() - new Date(issueDate)) / + (MS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * AVG_DAYS_PER_MONTH), + ); + +const buildGroupedIssues = (issues) => { + const grouped = {}; + + issues.forEach((issue) => { + if (!issue.issueDate || !issue.projectId) return; + + const issueName = Array.isArray(issue.issueTitle) + ? issue.issueTitle[0] + : issue.issueTitle || 'Unknown Issue'; + + const projectId = issue.projectId._id.toString(); + const projectName = issue.projectId.projectName || issue.projectId.name || 'Unknown Project'; + + const durationOpen = getDurationOpenMonths(issue.issueDate); + + if (!grouped[issueName]) grouped[issueName] = {}; + if (!grouped[issueName][projectId]) { + grouped[issueName][projectId] = { + projectId, + projectName, + durationOpen, + }; + } + }); + + return grouped; +}; + +const buildLongestOpenResponse = (grouped) => + Object.entries(grouped) + .map(([issueName, projectsById]) => ({ + issueName, + projects: Object.values(projectsById), + })) + .slice(0, MAX_LONGEST_OPEN_ISSUES); + const bmIssueController = function (BuildingIssue) { + /* -------------------- GET ALL ISSUES -------------------- */ const bmGetIssue = async (req, res) => { try { - BuildingIssue.find() - .populate() - .then((result) => res.status(200).send(result)) - .catch((error) => res.status(500).send(error)); - } catch (err) { - res.json(err); + const issues = await BuildingIssue.find().populate(); + res.status(200).json(issues); + } catch (error) { + res.status(500).json(error); } }; + /* -------------------- ISSUE CHART (MULTI-YEAR) -------------------- */ const bmGetIssueChart = async (req, res) => { try { const { issueType, year } = req.query; - const matchQuery = {}; // Initialize an empty match query object + const matchQuery = {}; + + if (issueType) matchQuery.issueType = issueType; - // Apply filters if provided - if (issueType) { - matchQuery.issueType = issueType; - } if (year) { - const startDate = new Date(`${year}-01-01T00:00:00Z`); - const endDate = new Date(`${year}-12-31T23:59:59Z`); - matchQuery.issueDate = { $gte: startDate, $lte: endDate }; // Filter based on issueDate + matchQuery.issueDate = { + $gte: new Date(`${year}-01-01T00:00:00Z`), + $lte: new Date(`${year}-12-31T23:59:59Z`), + }; } - const aggregationPipeline = [ - { $match: matchQuery }, // Match the filtered data + const pipeline = [ + { $match: matchQuery }, { $group: { - _id: { issueType: '$issueType', year: { $year: '$issueDate' } }, - count: { $sum: 1 }, // Properly count occurrences + _id: { + issueType: '$issueType', + year: { $year: '$issueDate' }, + }, + count: { $sum: 1 }, }, }, { @@ -48,122 +121,78 @@ const bmIssueController = function (BuildingIssue) { }, }, }, - { $sort: { _id: 1 } }, // Sort by issueType + { $sort: { _id: 1 } }, ]; - const issues = await mongoose.model('buildingIssue').aggregate(aggregationPipeline); // Execute aggregation pipeline + const data = await mongoose.model('buildingIssue').aggregate(pipeline); - // Format the result - const result = issues.reduce((acc, item) => { - const issueTypeKey = item._id; - acc[issueTypeKey] = {}; - item.years.forEach((yearData) => { - acc[issueTypeKey][yearData.year] = yearData.count; + const result = data.reduce((acc, item) => { + acc[item._id] = {}; + item.years.forEach((y) => { + acc[item._id][y.year] = y.count; }); return acc; }, {}); - res.status(200).json(result); // Return the formatted result + res.status(200).json(result); } catch (error) { - console.error('Error fetching issues:', error); res.status(500).json({ message: 'Server error', error }); } }; + /* -------------------- POST ISSUE -------------------- */ const bmPostIssue = async (req, res) => { try { - BuildingIssue.create(req.body) - .then((result) => res.status(201).send(result)) - .catch((error) => res.status(500).send(error)); - } catch (err) { - res.json(err); + const issue = await BuildingIssue.create(req.body); + res.status(201).json(issue); + } catch (error) { + res.status(500).json(error); } }; + /* -------------------- LONGEST OPEN ISSUES (FINAL) -------------------- */ const getLongestOpenIssues = async (req, res) => { try { const { dates, projects } = req.query; - // dates = '2021-10-01,2023-11-03'; - // projects = '654946c8bc5772e8caf7e963'; const query = { status: 'open' }; - let filteredProjectIds = []; + let filteredProjectIds = getProjectFilterIds(projects); - // Parse project filter if provided - if (projects) { - filteredProjectIds = projects.split(',').map((id) => id.trim()); - } - - // Apply date filtering logic - if (dates) { - const [startDateStr, endDateStr] = dates.split(',').map((d) => d.trim()); - const startDate = new Date(startDateStr); - const endDate = new Date(endDateStr); - - const matchingProjects = await BuildingProject.find({ - dateCreated: { $gte: startDate, $lte: endDate }, - isActive: true, - }) - .select('_id') - .lean(); + /* ---- date filter ---- */ + filteredProjectIds = await filterProjectIdsByDates(dates, filteredProjectIds); - const dateFilteredIds = matchingProjects.map((p) => p._id.toString()); - - if (filteredProjectIds.length > 0) { - // Intersection of project filters - filteredProjectIds = filteredProjectIds.filter((id) => dateFilteredIds.includes(id)); - } else { - filteredProjectIds = dateFilteredIds; - } - } - - // If no matching project IDs, return early if (dates && filteredProjectIds.length === 0) { - return res.json([]); // No results to return + return res.json([]); } - if (filteredProjectIds.length > 0) { + if (filteredProjectIds.length) { query.projectId = { $in: filteredProjectIds }; } - let issues = await BuildingIssue.find(query) - .select('issueTitle issueDate') - .populate('projectId') + /* ---- fetch issues ---- */ + const issues = await BuildingIssue.find(query) + .select('issueTitle issueDate projectId') + .populate({ + path: 'projectId', + select: 'projectName name', + }) .lean(); - issues = issues.map((issue) => { - const durationInMonths = Math.ceil( - (new Date() - new Date(issue.issueDate)) / (1000 * 60 * 60 * 24 * 30.44), - ); - const years = Math.floor(durationInMonths / 12); - const months = durationInMonths % 12; - const durationText = - years > 0 - ? `${years} year${years > 1 ? 's' : ''} ${months} month${months > 1 ? 's' : ''}` - : `${months} month${months > 1 ? 's' : ''}`; - - return { - issueName: issue.issueTitle[0], - durationOpen: durationText, - durationInMonths, - }; - }); - - const topIssues = issues - .sort((a, b) => b.durationInMonths - a.durationInMonths) - .slice(0, 7) - .map(({ issueName, durationInMonths }) => ({ - issueName, - durationOpen: durationInMonths, // send number only - })); + /* ---- group by issue + project ---- */ + const grouped = buildGroupedIssues(issues); + const response = buildLongestOpenResponse(grouped); - res.json(topIssues); + res.json(response); } catch (error) { - console.error('Error fetching longest open issues:', error); res.status(500).json({ message: 'Error fetching longest open issues' }); } }; - return { bmGetIssue, bmPostIssue, bmGetIssueChart, getLongestOpenIssues }; + return { + bmGetIssue, + bmPostIssue, + bmGetIssueChart, + getLongestOpenIssues, + }; }; module.exports = bmIssueController; diff --git a/src/startup/db.js b/src/startup/db.js index d8a722398..fd461210f 100644 --- a/src/startup/db.js +++ b/src/startup/db.js @@ -3,16 +3,14 @@ const userProfile = require('../models/userProfile'); const initialPermissions = require('../utilities/createInitialPermissions'); const logger = require('./logger'); require('dotenv').config(); - mongoose.Promise = Promise; - const afterConnect = async () => { try { const user = await userProfile.findOne({ firstName: { $regex: process.env.TIME_ARCHIVE_FIRST_NAME, $options: 'i' }, lastName: { $regex: process.env.TIME_ARCHIVE_LAST_NAME, $options: 'i' }, }); - + console.log('connected to mongodb'); await initialPermissions(); if (!user) { userProfile @@ -32,9 +30,9 @@ const afterConnect = async () => { throw new Error(error); } }; - module.exports = function () { - const uri = `mongodb+srv://${process.env.user}:${encodeURIComponent(process.env.password)}@${process.env.cluster}/${process.env.dbName}?retryWrites=true&w=majority&appName=${process.env.appName}`; + const uri = `mongodb+srv://${process.env.DB_USER}:${encodeURIComponent(process.env.DB_PASSWORD)}@${process.env.DB_CLUSTER}/${process.env.DB_NAME}?retryWrites=true&w=majority&appName=${process.env.DB_APP_NAME}`; + console.log('mongo url' + uri); mongoose .connect(uri, { useNewUrlParser: true, diff --git a/src/startup/routes.js b/src/startup/routes.js index 71526e7a1..5cf404bc1 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -470,6 +470,7 @@ module.exports = function (app) { app.use('/api', toolUtilizationRouter); // lb dashboard + app.use('/api/bm', bmTimeLoggerRouter); app.use('/api', toolAvailabilityRouter); app.use('/api', projectCostTrackingRouter); @@ -494,6 +495,7 @@ module.exports = function (app) { // lb dashboard app.use('/api/lb', lbListingsRouter); + // lb dashboard app.use('/api/bm', bmIssueRouter); app.use('/api', eventRouter); app.use('/api/villages', require('../routes/lbdashboard/villages'));