diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..902e474 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,15 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + +export default [ + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + pluginJs.configs.recommended, +]; diff --git a/package-lock.json b/package-lock.json index 93eead2..c61f639 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6530 +1,8614 @@ { "name": "api", - "version": "1.0.0", - "lockfileVersion": 1, + "version": "2.0.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@samverschueren/stream-to-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", - "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "packages": { + "": { + "name": "api", + "version": "2.0.0", + "dependencies": { + "apple-signin-auth": "^2.0.0", + "aws-sdk": "2.1660.0", + "axios": "1.7.2", + "bcrypt-nodejs": "0.0.3", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", + "mongodb-uri": "0.9.7", + "mongoose": "8.5.1", + "morgan": "1.10.0", + "multer": "1.3.0", + "nodemailer": "6.9.14", + "now": "11.4.6", + "openai": "^4.103.0", + "randomstring": "1.3.0", + "raven": "2.6.0", + "speakingurl": "14.0.1", + "validator": "13.12.0" + }, + "devDependencies": { + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, - "requires": { - "any-observable": "^0.3.0" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6.9.0" } }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "node_modules/@commitlint/config-validator": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.0.0.tgz", + "integrity": "sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg==", "dev": true, - "requires": { - "acorn": "^3.0.4" - }, + "license": "MIT", + "optional": true, "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } + "@commitlint/types": "^20.0.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" } }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node_modules/@commitlint/execute-rule": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=v18" } }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true + "node_modules/@commitlint/load": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.1.0.tgz", + "integrity": "sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.1.0", + "@commitlint/types": "^20.0.0", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, - "requires": { - "string-width": "^2.0.0" + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true + "node_modules/@commitlint/resolve-extends": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.1.0.tgz", + "integrity": "sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/types": "^20.0.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "node_modules/@commitlint/types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.0.0.tgz", + "integrity": "sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA==", "dev": true, - "requires": { - "ansi-wrap": "0.1.0" + "license": "MIT", + "optional": true, + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "append-field": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", - "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true + "node_modules/@eslint/config-array/node_modules/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, + "license": "MIT" }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, - "requires": { - "arr-flatten": "^1.0.1" + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, - "array-uniq": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz", - "integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=" - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sdk": { - "version": "2.94.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.94.0.tgz", - "integrity": "sha1-cEPePvjCTLarS/I18I2H2EFz4XQ=", - "requires": { - "buffer": "4.9.1", - "crypto-browserify": "1.0.9", - "events": "^1.1.1", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.0.1", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" + "node_modules/@eslint/eslintrc/node_modules/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, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "axios": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", - "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", - "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "node_modules/@gulpjs/messages": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", + "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "node_modules/@gulpjs/to-absolute-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz", + "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==", "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "license": "MIT", + "dependencies": { + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "babel-polyfill": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", - "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "core-js": "^2.4.0", - "regenerator-runtime": "^0.10.0" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, + "license": "Apache-2.0", "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + "node_modules/@jimp/bmp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", + "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "node_modules/@jimp/core": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", + "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } }, - "bcrypt-nodejs": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", - "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=" + "node_modules/@jimp/core/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" + "node_modules/@jimp/custom": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "license": "MIT", + "dependencies": { + "@jimp/core": "^0.22.12" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true + "node_modules/@jimp/gif": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", + "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "gifwrap": "^0.10.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bignumber.js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", - "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" + "node_modules/@jimp/jpeg": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", + "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "node_modules/@jimp/plugin-blit": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", + "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "node_modules/@jimp/plugin-blur": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", + "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "bmp-js": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz", - "integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo=" - }, - "body-parser": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", - "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", - "requires": { - "bytes": "2.4.0", - "content-type": "~1.0.2", - "debug": "2.6.7", - "depd": "~1.1.0", - "http-errors": "~1.6.1", - "iconv-lite": "0.4.15", - "on-finished": "~2.3.0", - "qs": "6.4.0", - "raw-body": "~2.2.0", - "type-is": "~1.6.15" + "node_modules/@jimp/plugin-circle": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", + "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", + "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "@jimp/utils": "^0.22.12", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/@jimp/plugin-contain": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", + "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/@jimp/plugin-displace": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", + "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "node_modules/@jimp/plugin-dither": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", + "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "bson": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", - "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", + "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "node_modules/@jimp/plugin-flip": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", + "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", + "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" + "node_modules/@jimp/plugin-invert": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + "node_modules/@jimp/plugin-mask": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", + "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", + "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", + "license": "MIT", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "@jimp/utils": "^0.22.12", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" } }, - "cachedir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz", - "integrity": "sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg==", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" + "node_modules/@jimp/plugin-resize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", + "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", + "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", + "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", + "license": "MIT", "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" } }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" - }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", + "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "node_modules/@jimp/plugins": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "license": "MIT", + "dependencies": { + "@jimp/plugin-blit": "^0.22.12", + "@jimp/plugin-blur": "^0.22.12", + "@jimp/plugin-circle": "^0.22.12", + "@jimp/plugin-color": "^0.22.12", + "@jimp/plugin-contain": "^0.22.12", + "@jimp/plugin-cover": "^0.22.12", + "@jimp/plugin-crop": "^0.22.12", + "@jimp/plugin-displace": "^0.22.12", + "@jimp/plugin-dither": "^0.22.12", + "@jimp/plugin-fisheye": "^0.22.12", + "@jimp/plugin-flip": "^0.22.12", + "@jimp/plugin-gaussian": "^0.22.12", + "@jimp/plugin-invert": "^0.22.12", + "@jimp/plugin-mask": "^0.22.12", + "@jimp/plugin-normalize": "^0.22.12", + "@jimp/plugin-print": "^0.22.12", + "@jimp/plugin-resize": "^0.22.12", + "@jimp/plugin-rotate": "^0.22.12", + "@jimp/plugin-scale": "^0.22.12", + "@jimp/plugin-shadow": "^0.22.12", + "@jimp/plugin-threshold": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" } }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true + "node_modules/@jimp/png": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", + "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + "node_modules/@jimp/tiff": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", + "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "license": "MIT", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "node_modules/@jimp/types": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "license": "MIT", + "dependencies": { + "@jimp/bmp": "^0.22.12", + "@jimp/gif": "^0.22.12", + "@jimp/jpeg": "^0.22.12", + "@jimp/png": "^0.22.12", + "@jimp/tiff": "^0.22.12", + "timm": "^1.6.1" }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", + "license": "MIT", "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } + "regenerator-runtime": "^0.13.3" } }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.1.tgz", + "integrity": "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", + "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, + "license": "MIT", + "optional": true, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "@types/node": "*" } }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "requires": { - "restore-cursor": "^1.0.1" + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.2.tgz", + "integrity": "sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.13.0" } }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "license": "MIT", "dependencies": { - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - } + "@types/node": "*", + "form-data": "^4.0.4" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, - "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==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "requires": { - "color-name": "1.1.3" + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "commitizen": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-2.10.1.tgz", - "integrity": "sha1-jDld7zSolfTpSVLC78PJ60w2g70=", - "dev": true, - "requires": { - "cachedir": "^1.1.0", - "chalk": "1.1.3", - "cz-conventional-changelog": "2.0.0", - "dedent": "0.6.0", - "detect-indent": "4.0.0", - "find-node-modules": "1.0.4", - "find-root": "1.0.0", - "fs-extra": "^1.0.0", - "glob": "7.1.1", - "inquirer": "1.2.3", - "lodash": "4.17.5", - "minimist": "1.2.0", - "opencollective": "1.0.3", - "path-exists": "2.1.0", - "shelljs": "0.7.6", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "cz-conventional-changelog": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.0.0.tgz", - "integrity": "sha1-Val5r9/pXnAkh50qD1kkYwFwtTM=", - "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "pad-right": "^0.2.2", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dev": true, + "license": "MIT", "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "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" - } - }, - "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==" - }, - "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" - } - } + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "connect": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.2.tgz", - "integrity": "sha1-aU6NIGgb/kkCgsiriGvpjwn0L+c=", - "requires": { - "debug": "2.6.7", - "finalhandler": "1.0.3", - "parseurl": "~1.3.1", - "utils-merge": "1.0.0" - }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "finalhandler": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz", - "integrity": "sha1-70fneVDpmXgOhgIqVg4yF+DQzIk=", - "requires": { - "debug": "2.6.7", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "contains-path": { + "node_modules/ansi-wrap": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "content-security-policy-builder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz", - "integrity": "sha1-2R8bB2I2wRmFDH3umSS/VeBXcrM=", - "requires": { - "dashify": "^0.2.0" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "conventional-commit-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.3.0.tgz", - "integrity": "sha512-6iB39PrcGYdz0n3z31kj6/Km6mK9hm9oMRhwcLnKxE7WNoeRKZbTAobliKrbYZ5jqyCvtcVEfjCiaEzhL3AVmQ==", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", - "dev": true - }, - "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=" - }, - "cors": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", - "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", - "requires": { - "object-assign": "^4", - "vary": "^1" + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - } - } + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", + "license": "MIT" }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "cross-env": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.0.5.tgz", - "integrity": "sha1-Q4PTZNlmCHPdGFs5ivO/717//vM=", + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", "dev": true, - "requires": { - "cross-spawn": "^5.1.0", - "is-windows": "^1.0.0" - }, + "license": "MIT", "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "node_modules/append-buffer/node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "node_modules/append-field": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", + "integrity": "sha512-8BgHoIwbQZaAQgDZLBu2vQoXHgUpSx4vQK1qv7e6R8YfbiSf4fCaBPJRtM1BaxVn1rIHc5ftv0cklsJ78BkouQ==", + "license": "MIT" }, - "crypto-browserify": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz", - "integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA=" + "node_modules/apple-signin-auth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/apple-signin-auth/-/apple-signin-auth-2.0.0.tgz", + "integrity": "sha512-/O5gvAby7OU2K7baYQCzY0e0tCiHzhFkzt9L2v3bMd2I2w0ckCZ/4hdVUOrbolRGMppME+Zo8TAKPVru8aYnzg==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "node-rsa": "^1.1.1" + }, + "engines": { + "node": ">=18.0.0" + } }, - "crypto-random-string": { + "node_modules/archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" }, - "cz-conventional-changelog": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz", - "integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "requires": { - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^1.0.1", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - } + "license": "Python-2.0" }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "dasherize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" - }, - "dashify": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz", - "integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4=" - }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "dedent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz", - "integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, - "requires": { - "clone": "^1.0.2" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "define-property": { + "node_modules/arr-map": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, - "detect-file": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0" + "license": "MIT", + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "detect-indent": { + "node_modules/array-initial/node_modules/is-number": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true, - "requires": { - "repeating": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "dns-prefetch-control": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz", - "integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI=" - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true, - "requires": { - "esutils": "^2.0.2" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "dom-walk": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", - "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "dont-sniff-mimetype": { + "node_modules/array-sort": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz", - "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=" - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", "dev": true, - "requires": { - "is-obj": "^1.0.0" + "license": "MIT", + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "dotenv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", - "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true, - "requires": { - "readable-stream": "~1.1.9" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, - "requires": { - "iconv-lite": "~0.4.13" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "node_modules/async-done": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz", + "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==", "dev": true, - "requires": { - "once": "~1.3.0" - }, + "license": "MIT", "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "requires": { - "wrappy": "1" - } - } + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "stream-exhaust": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" } + ], + "license": "MIT" + }, + "node_modules/async-settle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", + "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "eslint-config-semistandard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-12.0.1.tgz", - "integrity": "sha512-4zaPW5uRFasf2uRZkE19Y+W84KBV3q+oyWYOsgUN+5DQXE5HCsh7ZxeWDXxozk7NPycGm0kXcsJzLe5GZ1jCeg==", - "dev": true + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", - "dev": true + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" + "node_modules/aws-sdk": { + "version": "2.1660.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1660.0.tgz", + "integrity": "sha512-nyCEm6J4exq4gxeK5/LB5Q9unQTzFy6fbFHnrrmJZvp1KnRbJ10W2UtwQmeibPAz9b4w+RTKJMe6QEZ38eXeqA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "eslint-plugin-import": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz", - "integrity": "sha1-+gkIPVp1KI35xsfQn+EiVZhWVec=", + "node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", "dev": true, - "requires": { - "builtin-modules": "^1.1.1", - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0" + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true } } }, - "eslint-plugin-node": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", - "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "node_modules/bach": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz", + "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==", "dev": true, - "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "^5.4.1" + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0", + "async-settle": "^2.0.0", + "now-and-later": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "eslint-plugin-promise": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", - "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", - "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", - "dev": true - }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true + "license": "MIT" }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "node_modules/bare-events": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.7.0.tgz", + "integrity": "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==", "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } + "license": "Apache-2.0" }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "requires": { - "estraverse": "^4.0.0" + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, - "requires": { - "estraverse": "^4.1.0" + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "node_modules/basic-auth/node_modules/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==", + "license": "MIT" }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "node_modules/bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha512-NmTbLm867btBHCBZ222FQXkQKzecB0KG6pTXFa6NeTVZaSnLfCsx7EK2PL3J+kX8xJThUquEBbhimRCKKZX9zA==", + "deprecated": "bcrypt-nodejs is no longer actively maintained. Please use bcrypt or bcryptjs. See https://github.com/kelektiv/node.bcrypt.js/wiki/bcrypt-vs-brypt.js to learn more about these two options" }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } }, - "event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "license": "MIT", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" } }, - "exif-parser": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", - "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=" - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "requires": { - "fill-range": "^2.1.0" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "os-homedir": "^1.0.1" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "expect-ct": { + "node_modules/bmp-js": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.1.0.tgz", - "integrity": "sha1-UnNWeN4YUwiQ2Ne5XwrGNkCVgJQ=" - }, - "express": { - "version": "4.15.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", - "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=", - "requires": { - "accepts": "~1.3.3", - "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "~1.0.2", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.7", - "depd": "~1.1.0", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "etag": "~1.8.0", - "finalhandler": "~1.0.3", - "fresh": "0.5.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.1", - "path-to-regexp": "0.1.7", - "proxy-addr": "~1.1.4", - "qs": "6.4.0", - "range-parser": "~1.2.0", - "send": "0.15.3", - "serve-static": "1.12.3", - "setprototypeof": "1.0.3", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.0", - "vary": "~1.1.1" - }, + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, + "license": "MIT", "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "external-editor": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", - "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "requires": { - "extend": "^3.0.0", - "spawn-sync": "^1.0.15", - "tmp": "^0.0.29" + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" } }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "node_modules/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" } }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "license": "MIT", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "finalhandler": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", - "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", "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=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "find-node-modules": { + "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-1.0.4.tgz", - "integrity": "sha1-tt6zzMtpnIcDdne87eLF9YYrJVA=", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "requires": { - "findup-sync": "0.4.2", - "merge": "^1.2.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", - "dev": true + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "find-root": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz", - "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=", - "dev": true + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6" + } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "requires": { - "locate-path": "^2.0.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "findup-sync": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz", - "integrity": "sha1-qBF9D3MST1pFRoOVef5S1xKfteU=", + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true, - "requires": { - "detect-file": "^0.1.0", - "is-glob": "^2.0.1", - "micromatch": "^2.3.7", - "resolve-dir": "^0.1.0" + "license": "MIT" + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" } }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, + "license": "MIT", "dependencies": { - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - } + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", - "requires": { - "debug": "^3.0.0" + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, - "requires": { - "for-in": "^1.0.1" + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "requires": { - "map-cache": "^0.2.2" + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "frameguard": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.0.0.tgz", - "integrity": "sha1-e8rUae57lukdEs6zlZx4I1qScuk=" + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } + }, + "node_modules/cloneable-readable/node_modules/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "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" + } + }, + "node_modules/concat-stream/node_modules/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==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "dev": true, + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz", + "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "each-props": "^3.0.0", + "is-plain-object": "^5.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/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==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", + "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "jiti": "^2.4.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/each-props": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz", + "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.36.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/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, + "license": "MIT" + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/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, + "license": "MIT" + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "license": "MIT", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/fancy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz", + "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-support": "^1.1.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "license": "MIT", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fined": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz", + "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^5.0.0", + "object.defaults": "^1.1.0", + "object.pick": "^1.3.0", + "parse-filepath": "^1.0.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/flagged-respawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz", + "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } + }, + "node_modules/flush-write-stream/node_modules/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fork-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==", + "dev": true, + "license": "BSD" + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/freemail": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.7.0.tgz", + "integrity": "sha512-XzEdol9AxxwDN5ISi+J560MgQRKTiGOTRFakRQLUQDEjr48hBMzU5Eo7c2U13zzz3IwcaD+54jWHJrg6/wqRNA==", + "license": "ISC", + "dependencies": { + "tldjs": "^1.5.2" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz", + "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.8", + "streamx": "^2.12.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gifwrap": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", + "integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==", + "license": "MIT", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.3.tgz", + "integrity": "sha512-fqZVj22LtFJkHODT+M4N1RJQ3TjnnQhfE9GwZI8qXscYarnhpip70poMldRnP8ipQ/w0B621kOhfc53/J9bd/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gulpjs/to-absolute-glob": "^4.0.0", + "anymatch": "^3.1.3", + "fastq": "^1.13.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "is-negated-glob": "^1.0.0", + "normalize-path": "^3.0.0", + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-watcher": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz", + "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^2.0.0", + "chokidar": "^3.5.3" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glogg": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", + "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==", + "dev": true, + "license": "MIT", + "dependencies": { + "sparkles": "^2.1.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/google-auth-library": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.11.0.tgz", + "integrity": "sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gulp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz", + "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-watcher": "^6.0.0", + "gulp-cli": "^3.0.0", + "undertaker": "^2.0.0", + "vinyl-fs": "^4.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.1.0.tgz", + "integrity": "sha512-zZzwlmEsTfXcxRKiCHsdyjZZnFvXWM4v1NqBJSYbuApkvVKivjcmOS2qruAJ+PkEHLFavcDKH40DPc1+t12a9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@gulpjs/messages": "^1.1.0", + "chalk": "^4.1.2", + "copy-props": "^4.0.0", + "gulplog": "^2.2.0", + "interpret": "^3.1.1", + "liftoff": "^5.0.1", + "mute-stdout": "^2.0.0", + "replace-homedir": "^2.0.0", + "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "v8flags": "^4.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gulp-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/gulp-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/gulp-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/gulp-cli/node_modules/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, + "license": "MIT" + }, + "node_modules/gulp-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-eslint-new": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/gulp-eslint-new/-/gulp-eslint-new-2.5.0.tgz", + "integrity": "sha512-sEF9dnihZ04oUybO4grpPO0zomJwiAeCKcVyYZouzfArkJut/cVcjN3KA0g9iaX1g05pZhhYTBH6pnrqGTiVOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint": "8 || 9", + "fancy-log": "^2.0.0", + "plugin-error": "^2.0.1", + "semver": "^7.7.2", + "ternary-stream": "^3.0.0", + "vinyl-fs": "^4.0.2" + }, + "engines": { + "node": "^12.20 || ^14.13 || >=16" + }, + "optionalDependencies": { + "@types/node": ">=12" + } + }, + "node_modules/gulp-nodemon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.5.0.tgz", + "integrity": "sha512-vXfaP72xo2C6XOaXrNcLEM3QqDJ1x21S3x97U4YtzN2Rl2kH57++aFkAVxe6BafGRSTxs/xVfE/jNNlCv5Ym2Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "colors": "^1.2.1", + "gulp": "^4.0.0", + "nodemon": "^2.0.2" + } + }, + "node_modules/gulp-nodemon/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "license": "ISC", + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/gulp-nodemon/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/gulp-nodemon/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-nodemon/node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-nodemon/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/gulp-nodemon/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-nodemon/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dev": true, + "license": "MIT", + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/gulp-nodemon/node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } + }, + "node_modules/gulp-nodemon/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-nodemon/node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/gulp-nodemon/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-nodemon/node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-nodemon/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-nodemon/node_modules/yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/gulp-nodemon/node_modules/yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "node_modules/gulplog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", + "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "glogg": "^2.2.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/husky": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.1.tgz", + "integrity": "sha512-fCqlqLXcBnXa/TJXmT93/A36tJsjdJkibQ1MuIiFyCCYUlpYpIaj2mv1w+3KR6Rzu1IC3slFTje5f6DUp2A2rg==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "license": "MIT", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/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, + "license": "MIT" + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "license": "MIT" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } }, - "freemail": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/freemail/-/freemail-1.5.0.tgz", - "integrity": "sha1-k7sPZ8SYcUO0eLQH6Y4ybq2O1OA=", - "requires": { - "tldjs": "^1.5.2" + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } }, - "fs-exists-sync": { + "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", - "dev": true + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" }, - "fs-extra": { + "node_modules/is-valid-glob": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "fs.realpath": { + "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/jimp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", + "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", + "license": "MIT", + "dependencies": { + "@jimp/custom": "^0.22.12", + "@jimp/plugins": "^0.22.12", + "@jimp/types": "^0.22.12", + "regenerator-runtime": "^0.13.3" + } }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, + "license": "MIT", "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "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" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } + "bignumber.js": "^9.0.0" } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "optional": true }, - "functional-red-black-tree": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, - "requires": { - "globule": "~0.1.0" + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", - "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", - "dev": true + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" } }, - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "glob-parent": { + "node_modules/last-run": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" - }, - "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } + "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", + "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" } }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, - "requires": { - "gaze": "^0.5.1" + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" } }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "find-index": "^0.1.1" + "license": "MIT", + "dependencies": { + "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" } }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - } + "node_modules/lazystream/node_modules/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==", + "dev": true, + "license": "MIT" }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "node_modules/lazystream/node_modules/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==", "dev": true, - "requires": { - "ini": "^1.3.4" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" + "license": "MIT", + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", + "node_modules/lead": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", + "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" + "license": "MIT", + "engines": { + "node": ">=10.13.0" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "node_modules/liftoff": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.1.tgz", + "integrity": "sha512-wwLXMbuxSF8gMvubFcFRp56lkFV69twvbU5vDPbaw+Q+/rF8j0HKjGbIdlSi+LuJm9jf7k9PB+nTxnsLMPcv2Q==", "dev": true, - "requires": { - "sparkles": "^1.0.0" + "license": "MIT", + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^5.0.0", + "fined": "^2.0.0", + "flagged-respawn": "^2.0.0", + "is-plain-object": "^5.0.0", + "rechoir": "^0.8.0", + "resolve": "^1.20.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "google-auth-library": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz", - "integrity": "sha1-bhW6vuhf0d0U2NEoopW2g41SE24=", - "requires": { - "gtoken": "^1.2.1", - "jws": "^3.1.4", - "lodash.noop": "^3.0.1", - "request": "^2.74.0" + "node_modules/liftoff/node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" } }, - "google-p12-pem": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.2.tgz", - "integrity": "sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=", - "requires": { - "node-forge": "^0.7.1" + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "gtoken": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", - "integrity": "sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w==", - "requires": { - "google-p12-pem": "^0.1.0", - "jws": "^3.0.0", - "mime": "^1.4.1", - "request": "^2.72.0" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - } - } + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT", + "optional": true }, - "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "node_modules/lint-staged": { + "version": "15.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", + "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", "dev": true, - "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" - }, + "license": "MIT", "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - } + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.4", + "execa": "~8.0.1", + "lilconfig": "~3.1.1", + "listr2": "~8.2.1", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.4.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, - "gulp-eslint": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", - "integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==", + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "requires": { - "eslint": "^4.0.0", - "gulp-util": "^3.0.8" + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "gulp-nodemon": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/gulp-nodemon/-/gulp-nodemon-2.2.1.tgz", - "integrity": "sha1-2b8Zn1WFRYFZ09KZFT5gtGhotvQ=", - "dev": true, - "requires": { - "colors": "^1.0.3", - "event-stream": "^3.2.1", - "gulp": "^3.9.1", - "nodemon": "^1.10.2" - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, + "node_modules/lint-staged/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "node_modules/lint-staged/node_modules/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, - "requires": { - "glogg": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "license": "MIT" }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "node_modules/listr2": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, - "requires": { - "function-bind": "^1.1.1" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", "dev": true, - "requires": { - "sparkles": "^1.0.0" - } + "license": "MIT" }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "helmet": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.8.1.tgz", - "integrity": "sha512-HzcpQ74kE1gNFvTd8fI/Nz2N0b0Aa/38dSiSVt/ijkwjc50tUp5siXTE9lTBibQ4JlRzp/35Qf+j2bZgHYwg1g==", - "requires": { - "connect": "3.6.2", - "dns-prefetch-control": "0.1.0", - "dont-sniff-mimetype": "1.0.0", - "expect-ct": "0.1.0", - "frameguard": "3.0.0", - "helmet-csp": "2.5.1", - "hide-powered-by": "1.0.0", - "hpkp": "2.0.0", - "hsts": "2.1.0", - "ienoopen": "1.0.0", - "nocache": "2.0.0", - "referrer-policy": "1.1.0", - "x-xss-protection": "1.0.0" - } - }, - "helmet-csp": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.5.1.tgz", - "integrity": "sha512-PLLch8wVcVF2+ViTtSGHIvXqQVjcwGRtBwrNPggC+j28J7eSoPHxbJBr9SvLgh9V3HZa0C1zZFZ6gYVLIrPD0Q==", - "requires": { - "camelize": "1.0.0", - "content-security-policy-builder": "1.1.0", - "dasherize": "2.0.0", - "lodash.reduce": "4.6.0", - "platform": "1.3.4" - } - }, - "hide-powered-by": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.0.0.tgz", - "integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=" - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, - "requires": { - "parse-passwd": "^1.0.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "hpkp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" - }, - "hsts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.1.0.tgz", - "integrity": "sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA==" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "license": "MIT", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.0.0-rc.13.tgz", - "integrity": "sha512-ZNNoaBgfOHRA05UHS/etBoWFDu65mjPoohPYQwOqb5155KOovBp8LMkMoNK0kn3VYdsm+HWdtuHbD4XjfzlfpQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.2", - "execa": "^0.9.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", - "is-ci": "^1.1.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", - "run-node": "^1.0.0", - "slash": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - } - } + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ienoopen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.0.0.tgz", - "integrity": "sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms=" - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "import-fresh": { + "node_modules/load-json-file/node_modules/strip-bom": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "dependencies": { - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" }, - "inquirer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", - "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "external-editor": "^1.1.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "mute-stream": "0.0.6", - "pinkie-promise": "^2.0.0", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" }, - "ip-regex": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", - "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=" + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" }, - "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "dependencies": { - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - } - } + "license": "MIT" }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "license": "MIT" }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "license": "MIT", + "optional": true }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true, - "requires": { - "kind-of": "^3.0.2" - } + "license": "MIT", + "optional": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" - }, - "is-glob": { + "node_modules/log-symbols/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { - "is-extglob": "^1.0.0" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "node_modules/log-symbols/node_modules/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, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } + "license": "MIT" }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "symbol-observable": "^1.1.0" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "requires": { - "path-is-inside": "^1.0.1" + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", + "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", "dev": true, - "requires": { - "isobject": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, - "requires": { - "is-unc-path": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "requires": { - "unc-path-regex": "^0.1.2" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isemail": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", - "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "dev": true, - "requires": { - "isarray": "1.0.0" + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", - "dev": true - }, - "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "jimp": { - "version": "0.2.28", - "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz", - "integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=", - "requires": { - "bignumber.js": "^2.1.0", - "bmp-js": "0.0.3", - "es6-promise": "^3.0.2", - "exif-parser": "^0.1.9", - "file-type": "^3.1.0", - "jpeg-js": "^0.2.0", - "load-bmfont": "^1.2.3", - "mime": "^1.3.4", - "mkdirp": "0.5.1", - "pixelmatch": "^4.0.0", - "pngjs": "^3.0.0", - "read-chunk": "^1.0.1", - "request": "^2.65.0", - "stream-to-buffer": "^0.1.0", - "tinycolor2": "^1.1.2", - "url-regex": "^3.0.0" - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, - "joi": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", - "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", - "requires": { - "hoek": "2.x.x", - "isemail": "1.x.x", - "moment": "2.x.x", - "topo": "1.x.x" - } - }, - "jpeg-js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", - "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, - "requires": { - "graceful-fs": "^4.1.6" + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "jsonwebtoken": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz", - "integrity": "sha1-fKMk9SFfi+A5zTWmxFu4y3SkSPs=", - "requires": { - "joi": "^6.10.1", - "jws": "^3.1.4", - "lodash.once": "^4.0.0", - "ms": "^2.0.0", - "xtend": "^4.0.1" + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "kareem": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", - "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, - "requires": { - "is-buffer": "^1.1.5" + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "requires": { - "graceful-fs": "^4.1.9" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, - "requires": { - "package-json": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "license": "MIT", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", "dev": true, - "requires": { - "extend": "^3.0.0", + "license": "MIT", + "dependencies": { "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.3" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - } - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.3", - "ini": "1.3.5", - "is-windows": "1.0.2", - "which": "1.3.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" - } - } + "engines": { + "node": ">= 0.10.0" } }, - "lint-staged": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-7.2.2.tgz", - "integrity": "sha512-BWT3kx242hq5oaKJ8QiazPeHwJnEXImvjmgZfjljMI5HX6RrTxI3cTJXywre6GNafMONCD/suFnEiFmC69Gscg==", + "node_modules/matchdep/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, - "requires": { - "chalk": "^2.3.1", - "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", - "debug": "^3.1.0", - "dedent": "^0.7.0", - "execa": "^0.9.0", - "find-parent-dir": "^0.3.0", - "is-glob": "^4.0.0", - "is-windows": "^1.0.2", - "jest-validate": "^23.5.0", - "listr": "^0.14.1", - "lodash": "^4.17.5", - "log-symbols": "^2.2.0", - "micromatch": "^3.1.8", - "npm-which": "^3.0.1", - "p-map": "^1.1.1", - "path-is-inside": "^1.0.2", - "pify": "^3.0.0", - "please-upgrade-node": "^3.0.2", - "staged-git-files": "1.1.1", - "string-argv": "^0.0.2", - "stringify-object": "^3.2.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, - "dependencies": { - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "node_modules/matchdep/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "load-bmfont": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz", - "integrity": "sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==", - "requires": { - "buffer-equal": "0.0.1", - "mime": "^1.3.4", - "parse-bmfont-ascii": "^1.0.3", - "parse-bmfont-binary": "^1.0.5", - "parse-bmfont-xml": "^1.1.4", - "phin": "^2.9.1", - "xhr": "^2.0.1", - "xtend": "^4.0.0" + "node_modules/matchdep/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "load-json-file": { + "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/matchdep/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "node_modules/matchdep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, - "requires": { - "lodash._root": "^3.0.0" + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" } }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.isarguments": { + "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "lodash.noop": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", - "integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=" - }, - "lodash.once": { - "version": "4.1.1", - "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.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "node_modules/matchdep/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "node_modules/matchdep/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "requires": { - "chalk": "^2.0.1" - }, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "node_modules/matchdep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - } + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "node_modules/matchdep/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "node_modules/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, - "requires": { - "pify": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "node_modules/matchdep/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/matchdep/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, - "requires": { - "object-visit": "^1.0.0" + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" } }, - "media-typer": { + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "memory-pager": { + "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "license": "MIT" }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", - "dev": true + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true, + "license": "MIT" }, - "merge-descriptors": { + "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" }, - "methods": { + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "min-document": { + "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { "dom-walk": "^0.1.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "mixin-deep": { + "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.45", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz", + "integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/mongodb-uri": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz", + "integrity": "sha512-s6BdnqNoEYfViPJgkH85X5Nw5NpzxN8hoflKLweNa7vBxt2V7kaS06d74pAtqDxde8fn4r9h4dNdLiFGoNV0KA==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" } }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" + "node_modules/mongoose": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", + "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", + "license": "MIT", + "dependencies": { + "bson": "^6.7.0", + "kareem": "2.6.3", + "mongodb": "6.7.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mongoose/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" - }, - "moment-timezone": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.21.tgz", - "integrity": "sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==", - "requires": { - "moment": ">= 2.9.0" + "node_modules/mongoose/node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=12" } }, - "mongodb": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.6.tgz", - "integrity": "sha512-E5QJuXQoMlT7KyCYqNNMfAkhfQD79AT4F8Xd+6x37OX+8BL17GyXyWvfm6wuyx4wnzCCPoCSLeMeUN2S7dU9yw==", - "requires": { - "mongodb-core": "3.1.5", - "safe-buffer": "^5.1.2" + "node_modules/mongoose/node_modules/gcp-metadata": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" } }, - "mongodb-core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.5.tgz", - "integrity": "sha512-emT/tM4ZBinqd6RZok+EzDdtN4LjYJIckv71qQVOEFmvXgT5cperZegVmTgox/1cx4XQu6LJ5ZuIwipP/eKdQg==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - }, + "node_modules/mongoose/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "bson": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.3.tgz", - "integrity": "sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==" - } + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "mongodb-uri": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz", - "integrity": "sha1-D3ca0W9IOuZfQoeWlCjp+8SqYYE=" - }, - "mongoose": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.3.2.tgz", - "integrity": "sha512-07fpCMqvCiSdKXIygt3aAeNFJYjQPjDXILbwBEmF0e8gy2hSKMNuP5QG4J6L8m9BhjVxcvoLiPzaGKN7I/7lLg==", - "requires": { - "async": "2.6.1", - "bson": "~1.0.5", - "kareem": "2.3.0", - "lodash.get": "4.4.2", - "mongodb": "3.1.6", - "mongodb-core": "3.1.5", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.5.1", - "mquery": "3.2.0", - "ms": "2.0.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", + "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true }, - "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==" + "socks": { + "optional": true } } }, - "mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" - }, - "morgan": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz", - "integrity": "sha1-eErHc05KRTqcbm6GgKkyknXItoc=", - "requires": { - "basic-auth": "~1.1.0", - "debug": "2.6.8", - "depd": "~1.1.0", + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "on-headers": "~1.0.2" }, - "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "engines": { + "node": ">= 0.8.0" } }, - "mpath": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.5.1.tgz", - "integrity": "sha512-H8OVQ+QEz82sch4wbODFOz+3YQ61FYz/z3eJ5pIdbMEaUzDqA268Wd+Vt4Paw9TJfvDgVKaayC0gBzMIw2jhsg==" + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, - "mquery": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz", - "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==", - "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", + "dependencies": { + "debug": "4.x" }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "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==" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/mquery/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "multer": { + "node_modules/multer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz", - "integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=", - "requires": { + "integrity": "sha512-wbAkTsh0QXkvqvHCU2qSLEXLuRN7IKMEe80+JrXfJzANniPNgrNcDOMKfGgR1EhL7y7MHIbODVwT7uaVY20ggw==", + "deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.", + "license": "MIT", + "dependencies": { "append-field": "^0.1.0", "busboy": "^0.2.11", "concat-stream": "^1.5.0", @@ -6534,42 +8618,51 @@ "type-is": "^1.6.4", "xtend": "^4.0.0" }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - } + "engines": { + "node": ">= 0.10.0" } }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "node_modules/multer/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mute-stdout": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz", + "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==", "dev": true, - "requires": { - "duplexer2": "0.0.2" + "license": "MIT", + "engines": { + "node": ">= 10.13.0" } }, - "mute-stream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", - "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", - "dev": true + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "node_modules/nan": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", "dev": true, + "license": "MIT", "optional": true }, - "nanomatch": { + "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", @@ -6582,1904 +8675,2347 @@ "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" }, - "nocache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz", - "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=" + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "node-fetch": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", - "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "license": "ISC" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node-forge": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", - "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" + "node_modules/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", + "license": "MIT", + "dependencies": { + "asn1": "^0.2.4" + } }, - "nodemailer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.0.1.tgz", - "integrity": "sha1-uVhksH+s7oKH6CMu/9bx1W7HWrI=" + "node_modules/nodemailer": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } }, - "nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, - "requires": { - "chokidar": "^2.1.8", - "debug": "^3.2.6", + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.5.0" + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "ms": "^2.1.1" } }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "node_modules/nodemon/node_modules/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, + "license": "MIT" + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "requires": { - "abbrev": "1" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "now": { + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now": { "version": "11.4.6", "resolved": "https://registry.npmjs.org/now/-/now-11.4.6.tgz", - "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==" + "integrity": "sha512-5SMS8lVuCzqD55CPQlGcjvOJJJPuDSLoqKIIGR4uEooCbDhHl//dHZmBpT1uLSwT1MYvhYUMf9OpFQRwXG4KEg==", + "deprecated": "\"now\" is deprecated and will stop receiving updates on December 31, 2020. Please use \"vercel\" instead.", + "hasInstallScript": true, + "license": "Apache-2.0", + "bin": { + "now": "download/dist/now" + } }, - "npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "node_modules/now-and-later": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", + "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==", "dev": true, - "requires": { - "which": "^1.2.10" + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "requires": { - "path-key": "^2.0.0" + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "requires": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "number-is-nan": { + "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "object-copy": { + "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "requires": { - "isobject": "^3.0.0" - }, + "license": "ISC", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "wrappy": "1" } }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.104.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", + "integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==", + "license": "Apache-2.0", "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "zod": { + "optional": true } } }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.129", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.129.tgz", + "integrity": "sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A==", + "license": "MIT", "dependencies": { - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - } + "undici-types": "~5.26.4" } }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, - "requires": { - "isobject": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=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==" + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { - "wrappy": "1" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true + "node_modules/ora/node_modules/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, + "license": "MIT" }, - "opencollective": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", - "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", - "dev": true, - "requires": { - "babel-polyfill": "6.23.0", - "chalk": "1.1.3", - "inquirer": "3.0.6", - "minimist": "1.2.0", - "node-fetch": "1.6.3", - "opn": "4.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inquirer": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", - "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "chalk": "^1.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.1", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx": "^4.1.0", - "string-width": "^2.0.0", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "opn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.1" } }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "node_modules/ordered-read-streams/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "license": "MIT", + "dependencies": { + "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" } }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true + "node_modules/ordered-read-streams/node_modules/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==", + "dev": true, + "license": "MIT" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "node_modules/ordered-read-streams/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", - "dev": true + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "os-tmpdir": { + "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, - "requires": { - "p-try": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { - "p-limit": "^1.1.0" + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { - "repeat-string": "^1.5.2" + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-bmfont-ascii": { + "node_modules/parse-bmfont-ascii": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", - "integrity": "sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=" + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==", + "license": "MIT" }, - "parse-bmfont-binary": { + "node_modules/parse-bmfont-binary": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", - "integrity": "sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=" + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==", + "license": "MIT" }, - "parse-bmfont-xml": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", - "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", - "requires": { + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "license": "MIT", + "dependencies": { "xml-parse-from-string": "^1.0.0", - "xml2js": "^0.4.5" + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-bmfont-xml/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "parse-filepath": { + "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-headers": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", - "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" + "node_modules/parse-headers": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", + "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", + "license": "MIT" }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "requires": { - "error-ex": "^1.2.0" + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "parse-node-version": { + "node_modules/parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "parse-passwd": { + "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "pascalcase": { + "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "path-dirname": { + "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true, + "license": "MIT" }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" }, - "path-root": { + "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "path-root-regex": { + "node_modules/path-root-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "path-to-regexp": { + "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, - "requires": { - "pify": "^2.0.0" + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "license": "MIT", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "phin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", - "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==" + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } }, - "pify": { + "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "pinkie": { + "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "pinkie-promise": { + "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pixelmatch": { + "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", - "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=", - "requires": { + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "license": "ISC", + "dependencies": { "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" } }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/plugin-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz", + "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==", "dev": true, - "requires": { - "find-up": "^2.1.0" + "license": "MIT", + "dependencies": { + "ansi-colors": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "platform": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz", - "integrity": "sha1-bw+xftqqSPIUQrOpdcBjEw8cPr0=" + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "license": "MIT", + "engines": { + "node": ">=12.13.0" + } }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, - "requires": { - "semver-compare": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "prettier": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.2.tgz", - "integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==", - "dev": true - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } + "node_modules/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==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" }, - "process-nextick-args": { + "node_modules/pump": { "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", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, - "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", - "requires": { - "forwarded": "~0.1.0", - "ipaddr.js": "1.4.0" + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } }, - "psl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.5.0.tgz", - "integrity": "sha512-4vqUjKi2huMu1OJiLhi3jN6jeeKvMZdI1tYgi/njW5zV52jNLgSAZSdN16m9bJFe61/cT8ulmw4qFitV9QRsEA==" + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } }, - "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", - "dev": true + "node_modules/pumpify/node_modules/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==", + "dev": true, + "license": "MIT" }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "node_modules/pumpify/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "querystring": { + "node_modules/querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" } }, - "randomstring": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz", - "integrity": "sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=", - "requires": { - "array-uniq": "1.0.2" + "node_modules/randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==", + "license": "MIT" + }, + "node_modules/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "license": "MIT", + "dependencies": { + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" + }, + "engines": { + "node": "*" } }, - "range-parser": { + "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "raven": { + "node_modules/raven": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.0.tgz", - "integrity": "sha1-OAaoLJ7ozT51w7fqe7GTWq0JLQw=", - "requires": { + "integrity": "sha512-9s2rMxaV03VUqj+rlK5uJZg0iz1EKFdihdXqz5I4DTpOrBZ/z22Od7/2mzE5+Q7tUrpk+mhIIuoaAt/SduIeTg==", + "deprecated": "Please upgrade to @sentry/node. See the migration guide https://bit.ly/3ybOlo7", + "license": "BSD-2-Clause", + "dependencies": { "cookie": "0.3.1", "md5": "^2.2.1", "stack-trace": "0.0.10", "timed-out": "4.0.1", "uuid": "3.0.0" }, - "dependencies": { - "uuid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", - "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" - } + "bin": { + "raven": "bin/raven" + }, + "engines": { + "node": ">= 4.0.0" } }, - "raw-body": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", - "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", - "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.15", + "node_modules/raven/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raven/node_modules/uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha512-rqE1LoOVLv3QrZMjb4NkF5UWlkurCfPyItVnFPNKDDGkHw4dQUdE4zMcLqx28+0Kcf3+bnUk4PisaiRJT4aiaQ==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, + "license": "MIT", "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "read-chunk": { + "node_modules/read-pkg-up": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz", - "integrity": "sha1-X2jKswfmY/GZk1J9m1icrORmEZQ=" + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "license": "MIT", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "license": "MIT", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "readable-stream": { + "node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "license": "MIT", + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" - }, + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz", + "integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==", + "license": "MIT", "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "readable-stream": "^4.7.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "node_modules/readable-web-to-node-stream/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "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" - } - }, - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "safe-buffer": "~5.2.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { - "resolve": "^1.1.6" + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "referrer-policy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz", - "integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk=" - }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "regex-not": { + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "regexp-clone": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", - "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } + }, + "node_modules/remove-bom-stream/node_modules/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-bom-stream/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { - "rc": "^1.0.1" + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "remove-trailing-separator": { + "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "repeat-string": { + "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", "dev": true, - "requires": { - "is-finite": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">= 10" } }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - } + "node_modules/replace-homedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz", + "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "require_optional": { + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" } }, - "resolve-from": { + "node_modules/resolve-options": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz", + "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "value-or-function": "^4.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "resolve-url": { + "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true, + "license": "MIT" }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "ret": { + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "right-pad": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", - "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, - "requires": { - "is-promise": "^2.1.0" + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", - "dev": true - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, - "requires": { - "rx-lite": "*" + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, - "requires": { - "tslib": "^1.9.0" + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "safe-regex": { + "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ret": "~0.1.10" } }, - "safer-buffer": { + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "sax": { + "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", + "license": "ISC" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true + "node_modules/semver-greatest-satisfied-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz", + "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "sver": "^1.8.3" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - } - }, - "send": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz", - "integrity": "sha1-UBP5+ZAj31DRvZiSwZ4979HVMwk=", - "requires": { - "debug": "2.6.7", - "depd": "~1.1.0", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "etag": "~1.8.0", - "fresh": "0.5.0", - "http-errors": "~1.6.1", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, - "dependencies": { - "debug": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", - "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - } + "engines": { + "node": ">= 0.8.0" } }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", - "dev": true + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, - "serve-static": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz", - "integrity": "sha1-n0uhni8wMMVH+K+ZEHg47DjVseI=", - "requires": { - "encodeurl": "~1.0.1", + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.1", - "send": "0.15.3" + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "set-value": { + "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "shebang-command": { + "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { - "shebang-regex": "^1.0.0" + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shelljs": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz", - "integrity": "sha1-N5zM+1a5HIYB5HkzVutTgpJN6a0=", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "sigmund": { + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" + "license": "ISC", + "engines": { + "node": ">=14" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "license": "MIT", "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" } }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "snapdragon": { + "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", @@ -8489,1269 +11025,1700 @@ "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "snapdragon-node": { + "node_modules/snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "snapdragon-util": { + "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "source-map": { + "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true, + "license": "MIT" + }, + "node_modules/sparkles": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", + "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "node_modules/stream-composer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", + "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==", "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "license": "MIT", + "dependencies": { + "streamx": "^2.13.2" } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true, + "license": "MIT" }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true, + "license": "MIT" }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { - "memory-pager": "^1.0.2" + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", + "engines": { + "node": ">=0.8.0" } }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "dev": true, - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" } }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=0.6.19" } }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, - "spdx-expression-parse": { + "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "speakingurl": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.0.tgz", - "integrity": "sha512-70UD8Mm2cMkufkiUJ6tt7DLdLytYxTc1OwzXYJ9LVutfIoNx/Dmuj6vj/x0qAbUEFdyYKaHza1K/B1sI4hEk1A==" - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { - "through": "2" + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "requires": { - "extend-shallow": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "staged-git-files": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.1.tgz", - "integrity": "sha512-H89UNKr1rQJvI1c/PIR3kiAMBV23yvR7LItZiV74HWZwzt7f3YHuujJ9nJZlt58WlFox7XQsOahexwk7nTe69A==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", - "dev": true - }, - "stream-to": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-to/-/stream-to-0.2.2.tgz", - "integrity": "sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0=" - }, - "stream-to-buffer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz", - "integrity": "sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=", - "requires": { - "stream-to": "~0.2.0" + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "string-argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", - "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", - "dev": true + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "node_modules/sver": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz", + "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==", "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "license": "MIT", + "optionalDependencies": { + "semver": "^6.3.0" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "node_modules/sver/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" } }, - "strip-bom": { + "node_modules/ternary-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz", + "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^4.1.1", + "fork-stream": "^0.0.4", + "merge-stream": "^2.0.0", + "through2": "^3.0.1" + } }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" } }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "node_modules/through2-filter/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "requires": { - "execa": "^0.7.0" + "license": "MIT", + "dependencies": { + "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" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "node_modules/through2-filter/node_modules/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==", + "dev": true, + "license": "MIT" }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "node_modules/through2-filter/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } }, - "through2": { + "node_modules/through2-filter/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" - }, + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "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" - } - }, - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "node_modules/through2/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "os-homedir": "^1.0.0" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "time-stamp": { + "node_modules/time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "timed-out": { + "node_modules/timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==", + "license": "MIT" }, - "tldjs": { + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tldjs": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/tldjs/-/tldjs-1.8.0.tgz", - "integrity": "sha1-ucFr1t41e1X/y+fVvkH2s8p24/o=", - "requires": { + "integrity": "sha512-oJHVrNdgPYlU7vszbSBMYDykdnJ8DmjaGML5KysOn2MIYtnpl1Yn+bCSF/vNo8vZkd0U+eRGg1qkQjHDLD/Teg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { "punycode": "^1.4.1" }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" } }, - "tmp": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", - "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-object-path": { + "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex": { + "node_modules/to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "topo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", - "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", - "requires": { - "hoek": "2.x.x" + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, - "requires": { - "nopt": "~1.0.10" + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz", + "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "license": "MIT", "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "BSD-3-Clause" + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true, + "license": "ISC" }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { + "license": "MIT", + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, - "unc-path-regex": { + "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "undefsafe": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", - "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undertaker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz", + "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==", "dev": true, - "requires": { - "debug": "^2.2.0" + "license": "MIT", + "dependencies": { + "bach": "^2.0.1", + "fast-levenshtein": "^3.0.0", + "last-run": "^2.0.0", + "undertaker-registry": "^2.0.0" }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/undertaker-registry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz", + "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "fastest-levenshtein": "^1.0.7" } }, - "union-value": { + "node_modules/undici-types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz", + "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", + "license": "MIT" + }, + "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">= 10.0.0" } }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "unset-value": { + "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "license": "MIT", "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "upath": { + "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "urix": { + "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true, + "license": "MIT" }, - "url": { + "node_modules/url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "license": "MIT", + "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "url-regex": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", - "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", - "requires": { - "ip-regex": "^1.0.1" - } + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "license": "MIT" }, - "use": { + "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true + "node_modules/utif2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", + "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.11" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", - "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + "node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", "dev": true, - "requires": { - "user-home": "^1.1.1" + "license": "MIT", + "engines": { + "node": ">= 10.13.0" } }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", - "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/value-or-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", + "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "node_modules/vinyl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.1.tgz", + "integrity": "sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.2", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" } }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^5.0.0", + "vinyl": "^3.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-contents/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/vinyl-contents/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/vinyl-contents/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "BSD-3-Clause" + }, + "node_modules/vinyl-contents/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/vinyl-contents/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "node_modules/vinyl-fs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.2.tgz", + "integrity": "sha512-XRFwBLLTl8lRAOYiBqxY279wY46tVxLaRhSwo3GzKEuLz1giffsOquWWboD/haGf5lx+JyTigCFfe7DWHoARIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-mkdirp-stream": "^2.0.1", + "glob-stream": "^8.0.3", + "graceful-fs": "^4.2.11", + "iconv-lite": "^0.6.3", + "is-valid-glob": "^1.0.0", + "lead": "^4.0.0", + "normalize-path": "3.0.0", + "resolve-options": "^2.0.0", + "stream-composer": "^1.0.2", + "streamx": "^2.14.0", + "to-through": "^3.0.0", + "value-or-function": "^4.0.0", + "vinyl": "^3.0.1", + "vinyl-sourcemap": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/vinyl-fs/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "requires": { - "string-width": "^2.1.1" + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-2.0.0.tgz", + "integrity": "sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.10", + "now-and-later": "^3.0.0", + "streamx": "^2.12.5", + "vinyl": "^3.0.0", + "vinyl-contents": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } }, - "wrap-ansi": { + "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "x-xss-protection": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.0.0.tgz", - "integrity": "sha1-iYr7k4abJGYc+cUvnujbjtB2Tdk=" + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", - "dev": true + "node_modules/wrap-ansi/node_modules/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, + "license": "MIT" }, - "xhr": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", - "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", - "requires": { - "global": "~4.3.0", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "license": "MIT", + "dependencies": { + "global": "~4.4.0", "is-function": "^1.0.1", "parse-headers": "^2.0.0", "xtend": "^4.0.0" } }, - "xml-parse-from-string": { + "node_modules/xml-parse-from-string": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", - "integrity": "sha1-qQKekp09vN7RafPG4oI42VpdWig=" + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==", + "license": "MIT" }, - "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "requires": { + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "license": "MIT", + "dependencies": { "sax": ">=0.6.0", - "xmlbuilder": "^4.1.0" + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "^4.0.0" + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" } }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 392caf0..017b542 100644 --- a/package.json +++ b/package.json @@ -10,54 +10,53 @@ "cmt": "git-cz", "deploy": "now && now alias", "serve": "cross-env NODE_ENV=development gulp", - "start": "node src/index.js" + "start": "node src/index.js", + "format": "prettier --single-quote --trailing-comma none --tab-width=2 --write \"src/**/*.js\"" }, "devDependencies": { - "commitizen": "2.10.1", - "cross-env": "5.0.5", - "cz-conventional-changelog": "2.1.0", - "eslint": "4.19.1", - "eslint-config-semistandard": "12.0.1", - "eslint-config-standard": "10.2.1", - "eslint-plugin-import": "2.10.0", - "eslint-plugin-node": "6.0.1", - "eslint-plugin-promise": "3.7.0", - "eslint-plugin-standard": "3.1.0", - "gulp": "3.9.1", - "gulp-eslint": "4.0.0", - "gulp-nodemon": "2.2.1", - "husky": "1.0.0-rc.13", - "lint-staged": "7.2.2", - "prettier": "1.14.2" + "@eslint/js": "^9.7.0", + "commitizen": "4.3.0", + "cross-env": "7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^9.7.0", + "globals": "^15.8.0", + "gulp": "5.0.0", + "gulp-eslint-new": "^2.2.0", + "gulp-nodemon": "^2.2.1", + "husky": "9.1.1", + "lint-staged": "15.2.7", + "prettier": "3.3.3" }, "dependencies": { - "aws-sdk": "2.94.0", - "axios": "0.18.0", + "apple-signin-auth": "^2.0.0", + "aws-sdk": "2.1660.0", + "axios": "1.7.2", "bcrypt-nodejs": "0.0.3", - "body-parser": "1.17.2", - "cors": "2.8.4", - "dotenv": "4.0.0", - "express": "4.15.3", - "form-data": "2.3.2", - "freemail": "1.5.0", - "google-auth-library": "0.10.0", - "helmet": "3.8.1", - "ip": "1.1.5", - "jimp": "0.2.28", - "jsonwebtoken": "7.4.1", - "lodash": "4.17.4", - "moment": "2.18.1", - "moment-timezone": "0.5.21", + "body-parser": "1.20.2", + "cors": "2.8.5", + "dotenv": "16.4.5", + "express": "4.19.2", + "form-data": "4.0.0", + "freemail": "1.7.0", + "google-auth-library": "9.11.0", + "helmet": "7.1.0", + "ip": "2.0.1", + "jimp": "0.22.12", + "jsonwebtoken": "9.0.2", + "lodash": "4.17.21", + "moment": "2.30.1", + "moment-timezone": "0.5.45", "mongodb-uri": "0.9.7", - "mongoose": "5.3.2", - "morgan": "1.8.2", + "mongoose": "8.5.1", + "morgan": "1.10.0", "multer": "1.3.0", - "nodemailer": "4.0.1", + "nodemailer": "6.9.14", "now": "11.4.6", - "randomstring": "1.1.5", + "openai": "^4.103.0", + "randomstring": "1.3.0", "raven": "2.6.0", - "speakingurl": "14.0.0", - "validator": "9.4.1" + "speakingurl": "14.0.1", + "validator": "13.12.0" }, "lint-staged": { "src/**/*.{js}": [ @@ -78,5 +77,8 @@ "hooks": { "pre-commit": "lint-staged" } + }, + "overrides": { + "graceful-fs": "^4.2.11" } } diff --git a/src/helpers/Error.js b/src/helpers/Error.js new file mode 100644 index 0000000..dc2e6e7 --- /dev/null +++ b/src/helpers/Error.js @@ -0,0 +1,13 @@ +function sendError(errors) { + let message = ""; + if (typeof errors === "object") { + let error = Object.entries(errors)[0]; + message = `${error[0]} ${error[1]}`; + } + if (typeof errors === "string") { + message = errors; + } + return { error: true, message, status: false }; +} + +module.exports = { sendError }; diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 53eeef5..3fd5a1f 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -1,129 +1,156 @@ -module.exports = { - languages: ['en', 'es'], - placesTypes: [ - 'accounting', - 'airport', - 'amusement_park', - 'aquarium', - 'art_gallery', - 'atm', - 'bakery', - 'bank', - 'bar', - 'beauty_salon', - 'bicycle_store', - 'book_store', - 'bowling_alley', - 'bus_station', - 'cafe', - 'campground', - 'car_dealer', - 'car_rental', - 'car_repair', - 'car_wash', - 'casino', - 'cemetery', - 'church', - 'city_hall', - 'clothing_store', - 'convenience_store', - 'courthouse', - 'dentist', - 'department_store', - 'doctor', - 'electrician', - 'electronics_store', - 'embassy', - 'establishment', - 'fire_station', - 'florist', - 'funeral_home', - 'furniture_store', - 'gas_station', - 'gym', - 'hair_care', - 'hardware_store', - 'hindu_temple', - 'home_goods_store', - 'hospital', - 'insurance_agency', - 'jewelry_store', - 'laundry', - 'lawyer', - 'library', - 'liquor_store', - 'local_government_office', - 'locksmith', - 'lodging', - 'meal_delivery', - 'meal_takeaway', - 'mosque', - 'movie_rental', - 'movie_theater', - 'moving_company', - 'museum', - 'night_club', - 'painter', - 'park', - 'parking', - 'pet_store', - 'pharmacy', - 'physiotherapist', - 'plumber', - 'police', - 'post_office', - 'real_estate_agency', - 'restaurant', - 'roofing_contractor', - 'rv_park', - 'school', - 'shoe_store', - 'shopping_mall', - 'spa', - 'stadium', - 'storage', - 'store', - 'subway_station', - 'synagogue', - 'taxi_stand', - 'train_station', - 'transit_station', - 'travel_agency', - 'university', - 'veterinary_care', - 'zoo' - ], - directionsTypes: [ - 'administrative_area_level_1', - 'administrative_area_level_2', - 'administrative_area_level_3', - 'administrative_area_level_4', - 'administrative_area_level_5', - 'colloquial_area', - 'country', - 'finance', - 'floor', - 'geocode', - 'intersection', - 'locality', - 'natural_feature', - 'neighborhood', - 'place_of_worship', - 'political', - 'postal_code', - 'postal_code_prefix', - 'postal_code_suffix', - 'postal_town', - 'premise', - 'route', - 'street_address', - 'street_number', - 'sublocality', - 'sublocality_level_5', - 'sublocality_level_4', - 'sublocality_level_3', - 'sublocality_level_2', - 'sublocality_level_1', - 'subpremise' - ] -}; +module.exports = { + languages: ["en", "es"], + placesTypes: [ + "accounting", + "airport", + "amusement_park", + "aquarium", + "art_gallery", + "atm", + "bakery", + "bank", + "bar", + "beauty_salon", + "bicycle_store", + "book_store", + "bowling_alley", + "bus_station", + "cafe", + "campground", + "car_dealer", + "car_rental", + "car_repair", + "car_wash", + "casino", + "cemetery", + "church", + "city_hall", + "clothing_store", + "convenience_store", + "courthouse", + "dentist", + "department_store", + "doctor", + "electrician", + "electronics_store", + "embassy", + "establishment", + "fire_station", + "florist", + "funeral_home", + "furniture_store", + "gas_station", + "gym", + "hair_care", + "hardware_store", + "hindu_temple", + "home_goods_store", + "hospital", + "insurance_agency", + "jewelry_store", + "laundry", + "lawyer", + "library", + "liquor_store", + "local_government_office", + "locksmith", + "lodging", + "meal_delivery", + "meal_takeaway", + "mosque", + "movie_rental", + "movie_theater", + "moving_company", + "museum", + "night_club", + "painter", + "park", + "parking", + "pet_store", + "pharmacy", + "physiotherapist", + "plumber", + "police", + "post_office", + "real_estate_agency", + "restaurant", + "roofing_contractor", + "rv_park", + "school", + "shoe_store", + "shopping_mall", + "spa", + "stadium", + "storage", + "store", + "subway_station", + "synagogue", + "taxi_stand", + "train_station", + "transit_station", + "travel_agency", + "university", + "veterinary_care", + "zoo", + ], + directionsTypes: [ + "administrative_area_level_1", + "administrative_area_level_2", + "administrative_area_level_3", + "administrative_area_level_4", + "administrative_area_level_5", + "colloquial_area", + "country", + "finance", + "floor", + "geocode", + "intersection", + "locality", + "natural_feature", + "neighborhood", + "place_of_worship", + "political", + "postal_code", + "postal_code_prefix", + "postal_code_suffix", + "postal_town", + "premise", + "route", + "street_address", + "street_number", + "sublocality", + "sublocality_level_5", + "sublocality_level_4", + "sublocality_level_3", + "sublocality_level_2", + "sublocality_level_1", + "subpremise", + ], + disability: [ + "yes", "no", "not-to-say", "" + ], + genders: [ + "female", + "male", + "other", + "private", + "transgender", + "non-binary", + "gender-fluid", + "agender", + "not-to-say", + ], + race: [ + "black/african american", + "caucasian", + "indigenous/first nation/native american", + "latino/hispanic", + "middle eastern/north african", + "native hawaiian/pacific islander", + "biracial/multiracial", + "asian", + "non-naucasian", + "not-to-disclose", + "", + ], +}; diff --git a/src/helpers/db-connector.js b/src/helpers/db-connector.js index 9ee3db3..183145d 100644 --- a/src/helpers/db-connector.js +++ b/src/helpers/db-connector.js @@ -1,106 +1,97 @@ -const mongoose = require('mongoose'); -const mongoUri = require('mongodb-uri'); - -mongoose.Promise = global.Promise; - -const delayToReconnect = 1000; -let disconnecting; -let initialized = false; -const mongodbURI = process.env.MONGODB_URI; -const dbName = mongoUri.parse(mongodbURI).database; -const options = { - connectTimeoutMS: 30000, - keepAlive: 120, - useCreateIndex: true, - useNewUrlParser: true -}; - -function logging(db) { - db.on('connected', () => - console.log(`Database connection to ${dbName} established`) - ); - db.on('open', () => console.log(`Database connection to ${dbName} opened`)); - db.on('disconnected', () => { - if (disconnecting !== true) { - console.log(`Database connection to ${dbName} lost`); - } - }); - db.on('error', err => { - console.log(`Database connection to ${dbName} error`); - throw err; - }); -} - -function open() { - console.log(`Opening database connection to ${dbName}...`); - mongoose.connect( - mongodbURI, - options - ); -} - -function reconnection(db) { - let timer; - - function reconnect() { - timer = false; - open(db); - } - - function clear() { - if (timer) { - clearTimeout(timer); - } - timer = false; - } - - function schedule() { - if (disconnecting) { - console.log(`Database connection to ${dbName} explicitly shut down`); - return; - } - - if (timer) { - clearTimeout(timer); - } - timer = setTimeout(reconnect, delayToReconnect); - } - - db.on('disconnected', schedule); - db.on('connected', clear); -} - -function connect(done) { - const db = mongoose.connection; - - if (initialized === false) { - initialized = true; - logging(db); - reconnection(db); - } - - open(); - - db.once('connected', done); -} - -function disconnect(done) { - const db = mongoose.connection; - - function disconnected() { - disconnecting = false; - if (done) { - done(); - } - } - - if (db.readyState !== 0) { - disconnecting = true; - db.once('disconnected', disconnected); - db.close(); - } -} - -connect.disconnect = disconnect; - -module.exports = connect; +const mongoose = require('mongoose'); +const mongoUri = require('mongodb-uri'); + +mongoose.Promise = global.Promise; + +const delayToReconnect = 1000; +let disconnecting; +let initialized = false; +const mongodbURI = process.env.MONGODB_URI; +const dbName = mongoUri.parse(mongodbURI).database; + +function logging(db) { + db.on('connected', () => + console.log(`Database connection to ${dbName} established`) + ); + db.on('open', () => console.log(`Database connection to ${dbName} opened`)); + db.on('disconnected', () => { + if (disconnecting !== true) { + console.log(`Database connection to ${dbName} lost`); + } + }); + db.on('error', (err) => { + console.log(`Database connection to ${dbName} error`); + throw err; + }); +} + +function open() { + console.log(`Opening database connection to ${dbName}...`); + mongoose.connect(mongodbURI); +} + +function reconnection(db) { + let timer; + + function reconnect() { + timer = false; + open(db); + } + + function clear() { + if (timer) { + clearTimeout(timer); + } + timer = false; + } + + function schedule() { + if (disconnecting) { + console.log(`Database connection to ${dbName} explicitly shut down`); + return; + } + + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(reconnect, delayToReconnect); + } + + db.on('disconnected', schedule); + db.on('connected', clear); +} + +function connect(done) { + const db = mongoose.connection; + + if (initialized === false) { + initialized = true; + logging(db); + reconnection(db); + } + + open(); + + db.once('connected', done); +} + +function disconnect(done) { + const db = mongoose.connection; + + function disconnected() { + disconnecting = false; + if (done) { + done(); + } + } + + if (db.readyState !== 0) { + disconnecting = true; + db.once('disconnected', disconnected); + db.close(); + } +} + +connect.disconnect = disconnect; + +module.exports = connect; diff --git a/src/helpers/index.js b/src/helpers/index.js index 3445d7f..e27326c 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,106 +1,129 @@ -const aws = require('aws-sdk'); -const { camelCase } = require('lodash'); -const jwt = require('jsonwebtoken'); -const { mapKeys, pickBy } = require('lodash'); -const nodemailer = require('nodemailer'); -const { snakeCase } = require('lodash'); - -const { User } = require('../models/user'); - -module.exports = { - cleanSpaces(string) { - return string.replace(/\s+/g, ' ').trim(); - }, - deleteUnusedProperties(obj) { - return pickBy(obj, prop => prop); - }, - isAuthenticated: ({ isOptional }) => async (req, res, next) => { - const authorizationHeader = req.headers.authorization; - let token; - - if (authorizationHeader) { - token = authorizationHeader.split(' ')[1]; - } - - if (token) { - let decoded; - try { - decoded = await jwt.verify(token, process.env.JWT_SECRET); - } catch (err) { - return res.status(401).json({ general: 'Failed to authenticate' }); - } - - let user; - try { - user = await User.findOne({ - _id: decoded.userId, - isArchived: false - }).select( - '-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt' - ); - } catch (err) { - console.log( - `User ${decoded.userId} failed to be found at authenticate` - ); - return next(err); - } - - if (user) { - req.user = user; - - if ( - (isOptional && req.user && req.user.isBlocked) || - (!isOptional && req.user.isBlocked) - ) { - return res.status(423).json({ general: 'You are blocked' }); - } - - return next(); - } - - return res.status(404).json({ general: 'User not found' }); - } - - if (isOptional) { - return next(); - } - - return res.status(401).json({ general: 'No token provided' }); - }, - isNumber(number) { - return !isNaN(parseFloat(number)) && isFinite(number); - }, - mapCamelCaseKeys(obj) { - return mapKeys(obj, (value, key) => camelCase(key)); - }, - mapSnakeCaseKeys(obj) { - return mapKeys(obj, (value, key) => snakeCase(key)); - }, - removeSpaces(string) { - return string.replace(/\s/g, ''); - }, - sendEmail({ - senderEmail = process.env.SENDER_EMAIL, - receiversEmails, - subject, - htmlContent, - textContent - }) { - const transporter = nodemailer.createTransport({ - SES: new aws.SES({ - apiVersion: '2010-12-01' - }) - }); - - return transporter.sendMail({ - from: `"AXS Map" <${senderEmail}>`, - to: receiversEmails.join(', '), - subject, - text: textContent, - html: htmlContent - }); - }, - toJSON(obj) { - return JSON.parse(JSON.stringify(obj)); - } -}; +const aws = require("aws-sdk"); +const { camelCase } = require("lodash"); +const jwt = require("jsonwebtoken"); +const { mapKeys, pickBy } = require("lodash"); +const nodemailer = require("nodemailer"); +const { snakeCase } = require("lodash"); + +const { User } = require("../models/user"); + +module.exports = { + cleanSpaces(string) { + return string.replace(/\s+/g, " ").trim(); + }, + deleteUnusedProperties(obj) { + return pickBy(obj, (prop) => prop); + }, + isAuthenticated: + ({ isOptional }) => + async (req, res, next) => { + const authorizationHeader = req.headers.authorization; + const deviceType = req.headers["x-device-type"]; + const userAgent = req.headers["user-agent"]; + + let token; + + if (authorizationHeader) { + token = authorizationHeader.split(" ")[1]; + } + + if (token) { + let decoded; + try { + decoded = await jwt.verify(token, process.env.JWT_SECRET); + } catch (err) { + console.log(err); + return res.status(401).json({ general: "Failed to authenticate" }); + } + + let user; + try { + user = await User.findOne({ + _id: decoded.userId, + isArchived: false, + }).select( + "-__v -createdAt -isAdmin -isArchived -isBlocked -hashedPassword -updatedAt" + ); + if (req.originalUrl.startsWith("/venues?") && req.method === "GET") { + const location = req?.query?.location; + if (location) { + const [lat, lng] = location + .split(",") + .map((coord) => coord?.trim()); + if (lat && lng) { + user.lastLocation = { + lat, + lng, + }; + } + } + } + user.lastActivityTime = new Date().toISOString(); + user.device = deviceType || userAgent || ""; + user.save(); + } catch (err) { + console.log( + `User ${decoded.userId} failed to be found at authenticate` + ); + return next(err); + } + + if (user) { + req.user = user; + + if ( + (isOptional && req.user && req.user.isBlocked) || + (!isOptional && req.user.isBlocked) + ) { + return res.status(423).json({ general: "You are blocked" }); + } + + return next(); + } + + return res.status(404).json({ general: "User not found" }); + } + + if (isOptional) { + return next(); + } + + return res.status(401).json({ general: "No token provided" }); + }, + isNumber(number) { + return !isNaN(parseFloat(number)) && isFinite(number); + }, + mapCamelCaseKeys(obj) { + return mapKeys(obj, (value, key) => camelCase(key)); + }, + mapSnakeCaseKeys(obj) { + return mapKeys(obj, (value, key) => snakeCase(key)); + }, + removeSpaces(string) { + return string.replace(/\s/g, ""); + }, + sendEmail({ + senderEmail = process.env.SENDER_EMAIL, + receiversEmails, + subject, + htmlContent, + textContent, + }) { + const transporter = nodemailer.createTransport({ + SES: new aws.SES({ + apiVersion: "2010-12-01", + }), + }); + + return transporter.sendMail({ + from: `"AXS Map" <${senderEmail}>`, + to: receiversEmails.join(", "), + subject, + text: textContent, + html: htmlContent, + }); + }, + toJSON(obj) { + return JSON.parse(JSON.stringify(obj)); + }, +}; diff --git a/src/helpers/mail-template.js b/src/helpers/mail-template.js new file mode 100644 index 0000000..bbb4960 --- /dev/null +++ b/src/helpers/mail-template.js @@ -0,0 +1,234 @@ +const activationEmailTemplate = (link, name) => { + return ` + + + + + + + +
+ + + + + + + + + + + +
+

Welcome to AXS MAP 🎉

+

You're just one step away from getting started!

+
+

+ Hi ${name}, +

+

+ Thanks for signing up! Please confirm your email address by clicking the button below. +

+ + + +

+ If you didn’t sign up for AXS Map, no worries — you can safely ignore this email. +

+
+

+ Need help? Contact Support +

+

© 2025 AXS MAP. All rights reserved.

+
+
+ + +`; +}; + +const submitServeyUserMailTemplate = (userName) => { + return ` + + + + + + + +
+ + + + + + + + + + + +
+

Thank You for Sharing Your Voice! 🙌

+

Your recent AXS Map survey has been submitted.

+
+

+ Hi ${userName}, +

+

+ We truly appreciate your input! Your recent survey submission helps us make AXS Map more accessible and impactful for everyone. +

+ + + +

+ Want to contribute more? You can always submit another review or share your experience with friends to help grow the community. +

+
+

+ Questions? Contact Support +

+

© 2025 AXS MAP. All rights reserved.

+
+
+ + +`; +}; + +const adminServeyMailTemplate = (name, email, answers) => { + return ` + + + + + + + +
+ + + + + + + + + + +
+

New Survey Submitted on AXS Map 📝

+

A new survey response has just been submitted by a user.

+
+

+ User Name: ${name}
+ Email: ${email} +

+ +
+ +

Survey Responses:

+ + ${answers.map((item, index) => { + return `

+ Q${index + 1}: ${item?.question}
+ A: ${item?.answer} +

`; + })} +
+

+ For any issues, reach out to Support +

+

© 2025 AXS MAP. Admin Notification Email

+
+
+ + +`; +}; + +const donationMailTemplate = (name) => { + return ` + + + + + + + +
+ + + + + + + + + + + + + + + + +
+

Thank You for Supporting AXS Map 🙏

+

Here’s your exclusive content

+
+

+ Hi ${name}, +

+ +

+ Thank you so much for supporting AXS Map. Your generosity helps us continue making accessibility more visible and empowering communities everywhere. +

+ +

+ As a token of our appreciation, we’re sharing exclusive content just for our donors. You can access it through this private playlist: +

+ + + +

+ Please keep this link private, as it’s reserved for supporters like you. +

+ +

+ We’re grateful to have you with us on this journey toward a more accessible world. Enjoy the content, and thank you again for being part of the AXS Map community. +

+ +

+ With gratitude,
The AXS Map Team +

+
+

+ Need help? Contact Support +

+

© 2025 AXS MAP. All rights reserved.

+
+
+ + +`; +}; + +module.exports = { + activationEmailTemplate, + submitServeyUserMailTemplate, + adminServeyMailTemplate, + donationMailTemplate, +}; diff --git a/src/helpers/venue-review-summary.js b/src/helpers/venue-review-summary.js index e752584..3e98162 100644 --- a/src/helpers/venue-review-summary.js +++ b/src/helpers/venue-review-summary.js @@ -1,5 +1,5 @@ //const { ReviewLogic } = require('review-icon-logic-2.json'); -const reviewLogic = require('./review-icon-logic-2.json'); +const reviewLogic = require("./review-icon-logic-2.json"); function assignFromYesNo(venueField) { //field may not exist for old data @@ -8,8 +8,8 @@ function assignFromYesNo(venueField) { // Mongoose hasOwnProperty test issues if ( venueField && - venueField.hasOwnProperty('yes') && - venueField.hasOwnProperty('no') && + "yes" in venueField && + "no" in venueField && !(venueField.yes === 0 && venueField.no === 0) ) { if (venueField.yes >= venueField.no) { @@ -23,12 +23,10 @@ function assignFromYesNo(venueField) { } function assignFromSteps(stepField) { - let moreThanTwo = stepField.hasOwnProperty('moreThanTwo') - ? stepField.moreThanTwo - : 0; - let two = stepField.hasOwnProperty('two') ? stepField.two : 0; - let one = stepField.hasOwnProperty('one') ? stepField.one : 0; - let zero = stepField.hasOwnProperty('zero') ? stepField.zero : 0; + let moreThanTwo = "moreThanTwo" in stepField ? stepField.moreThanTwo : 0; + let two = "two" in stepField ? stepField.two : 0; + let one = "one" in stepField ? stepField.one : 0; + let zero = "zero" in stepField ? stepField.zero : 0; if (moreThanTwo === 0 && two === 0 && one === 0 && zero === 0) { return null; @@ -95,50 +93,50 @@ module.exports = { //console.log('in calculateRatingLevel, select venue data: ', venueData); let sectionLogic, ratingDefinition; - if (reviewSummaryLogic.hasOwnProperty(sectionName)) { + if (sectionName in reviewSummaryLogic) { //valid values: entrance, restroom, interior sectionLogic = reviewSummaryLogic[sectionName]; } else { - console.log('Error: Logic not found for sectionLogic: ' + sectionName); + console.log("Error: Logic not found for sectionLogic: " + sectionName); return { - errors: 'Logic not found for sectionLogic: ' + sectionName + errors: "Logic not found for sectionLogic: " + sectionName, }; } let ratingLevel, ratingGlyphs; - const ratingLevels = ['alert', 'caution', 'accessible']; + const ratingLevels = ["alert", "caution", "accessible"]; - for (rl = 0; rl < ratingLevels.length; rl++) { + for (let rl = 0; rl < ratingLevels.length; rl++) { if ( - sectionLogic.hasOwnProperty(ratingLevels[rl]) && + ratingLevels[rl] in sectionLogic && sectionLogic[ratingLevels[rl]].length > 0 ) { //level loop - for (idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { + for (let idx = 0; idx < sectionLogic[ratingLevels[rl]].length; idx++) { ratingDefinition = sectionLogic[ratingLevels[rl]][idx]; let ratingDefinitionMatch = false; if ( - ratingDefinition.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.field) + "field" in ratingDefinition && + ratingDefinition.field in venueData ) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ("matchValue" in ratingDefinition && venueData[ratingDefinition.field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ("notMatchValue" in ratingDefinition && venueData[ratingDefinition.field] !== ratingDefinition.notMatchValue) ) { ratingDefinitionMatch = true; } - } else if (ratingDefinition.hasOwnProperty('fields')) { + } else if ("fields" in ratingDefinition) { let fieldMatchCount = 0; - for (field of ratingDefinition.fields) { + for (let field of ratingDefinition.fields) { if ( - (ratingDefinition.hasOwnProperty('matchValue') && + ("matchValue" in ratingDefinition && venueData[field] === ratingDefinition.matchValue) || - (ratingDefinition.hasOwnProperty('notMatchValue') && + ("notMatchValue" in ratingDefinition && venueData[field] !== ratingDefinition.notMatchValue) ) { fieldMatchCount++; @@ -150,21 +148,18 @@ module.exports = { } } - if ( - ratingDefinitionMatch === true && - ratingDefinition.hasOwnProperty('and') - ) { + if (ratingDefinitionMatch === true && "and" in ratingDefinition) { //console.log('Evaluate AND condition in ' + sectionName); if ( - ratingDefinition.and.hasOwnProperty('field') && - venueData.hasOwnProperty(ratingDefinition.and.field) + "field" in ratingDefinition.and && + ratingDefinition.and.field in venueData ) { //evaluate 'and' condition depending on match or noMatch value - if (ratingDefinition.and.hasOwnProperty('matchValue')) { + if ("matchValue" in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] == ratingDefinition.and.matchValue; - } else if (ratingDefinition.and.hasOwnProperty('notMatchValue')) { + } else if ("notMatchValue" in ratingDefinition.and) { ratingDefinitionMatch = venueData[ratingDefinition.and.field] !== ratingDefinition.and.notMatchValue; @@ -178,11 +173,11 @@ module.exports = { if (ratingDefinitionMatch === true) { //console.log('Found rule match for ' + sectionName); - if (ratingLevels[rl] == 'alert') { + if (ratingLevels[rl] == "alert") { ratingLevel = 1; - } else if (ratingLevels[rl] == 'caution') { + } else if (ratingLevels[rl] == "caution") { ratingLevel = 3; - } else if (ratingLevels[rl] == 'accessible') { + } else if (ratingLevels[rl] == "accessible") { ratingLevel = 5; } @@ -202,16 +197,91 @@ module.exports = { //console.log('ratingLevel not set: ', sectionLogic); ratingLevel = 0; ratingGlyphs = - sectionLogic.hasOwnProperty('default') && + "default" in sectionLogic && sectionLogic.default.length > 0 && - sectionLogic.default[0].hasOwnProperty('showGlyph') + "showGlyph" in sectionLogic.default[0] ? sectionLogic.default[0].showGlyph - : ''; + : ""; } return { ratingLevel: ratingLevel, - ratingGlyphs: ratingGlyphs + ratingGlyphs: ratingGlyphs, }; - } + }, + calculateInteriorScore(venue) { + const multipleFloors = venue.multipleFloors?.yes === 1; + const hasAccessibleElevator = venue.hasAccessibleElevator?.yes === 1; + const hasInteriorRamp = venue.hasInteriorRamp?.yes === 1; + const hasFlashingLights = venue.brightLightTitle?.yes === 1; + + const hasAnyGreen = + venue.multipleFloors?.no === 1 || + hasAccessibleElevator || + hasInteriorRamp; + + const isYellow = venue.hasWellLit?.no === 1 && hasFlashingLights; + + const isRed = + multipleFloors && + venue.hasAccessibleElevator?.no === 1 && + venue.hasInteriorRamp?.no === 1; + + if (isRed) return 1; + if (isYellow) return 3; + if (hasAnyGreen) return 5; + + return 3; + }, + calculateEntranceScore(venue) { + const hasStep = venue.steps?.zero === 1; + const hasPermanentRamp = venue.hasPermanentRamp?.yes === 1; + const hasSecondEntry = venue.hasSecondEntry?.yes === 1; + const hasWideEntrance = venue.hasWideEntrance?.yes === 1; + + const hasAnyGreenCondition = + hasStep || hasWideEntrance || hasPermanentRamp || hasSecondEntry; + + const isYellowCondition = + hasStep && venue.hasPermanentRamp.no === 1 && hasSecondEntry; + + const isRedCondition = + hasStep && + venue.hasPermanentRamp.no === 1 && + venue.hasSecondEntry?.no === 1; + + if (isRedCondition) return 1; + if (isYellowCondition) return 3; + if (hasAnyGreenCondition) return 5; + + return 3; + }, + calculateBathroomScore(venue) { + const hasWashroom = venue.hasWashroom?.yes === 1; + const hasSupportAroundToilet = venue.hasSupportAroundToilet?.yes === 1; + + if (venue.hasWashroom?.no === 1) { + return 1; + } + if ( + venue.hasSupportAroundToilet?.no === 1 && + venue.hasLoweredSinks?.no === 1 + ) { + return 3; + } + + if (hasWashroom || hasSupportAroundToilet) return 5; + + return 3; + }, + calculateMapIconScore() { + const total = entranceScore + interiorScore + restroomScore; + const avg = total / 3; + + // Maximum possible total is 15 (5 points each for entrance, interior, restroom) + // Scale the average to account for max possible score + if (avg > 3) return 5; + if (avg > 1) return 3; + return 1; + }, }; diff --git a/src/index.js b/src/index.js index f75263b..e3eee62 100644 --- a/src/index.js +++ b/src/index.js @@ -1,81 +1,84 @@ -const fs = require('fs'); -const https = require('https'); - -const bodyParser = require('body-parser'); -const cors = require('cors'); -const express = require('express'); -const helmet = require('helmet'); -const ip = require('ip'); -const morgan = require('morgan'); -const raven = require('raven'); - -// Fill process.env with environment variables -require('dotenv').config(); -//console.log(process.env) - -const port = process.env.PORT || 8000; - -const connectToDB = require('./helpers/db-connector'); -const routes = require('./routes'); - -function connectedToDB() { - const app = express(); - - raven - .config(process.env.SENTRY_URL, { - captureUnhandledRejections: true - }) - .install(); - - // Middlewares - app.use(raven.requestHandler()); - app.use(cors()); - app.use(morgan('dev')); - app.use(bodyParser.json()); - app.use(helmet()); - - // Routes - app.set('strict routing', true); - app.use('/', routes); - - // Error handling - app.use(raven.errorHandler()); - app.use((req, res, _next) => res.status(404).json({ general: 'Not found' })); - app.use((err, req, res, _next) => { - if (err instanceof SyntaxError) { - return res.status(400).json({ general: 'Invalid JSON format' }); - } - - console.error(err.stack); - return res.status(500).json({ general: 'Something went wrong' }); - }); - - process.on('uncaughtException', err => { - console.error(err); - raven.captureException(err); - }); - process.on('unhandledRejection', err => { - console.error(err); - raven.captureException(err); - }); - - // App Initialization - if (process.env.NODE_ENV === 'production') { - console.log(`Listening on http://${ip.address()}:${port}`); - app.listen(port); - } else { - https - .createServer( - { - key: fs.readFileSync('./certificates/server.key'), - cert: fs.readFileSync('./certificates/server.crt') - }, - app - ) - .listen(port, () => - console.log(`Listening on https://${ip.address()}:${port}`) - ); - } -} - -connectToDB(connectedToDB); +const bodyParser = require("body-parser"); +const cors = require("cors"); +const express = require("express"); +const helmet = require("helmet"); +const ip = require("ip"); +const morgan = require("morgan"); +const raven = require("raven"); + +// Fill process.env with environment variables +require("dotenv").config(); +//console.log(process.env) + +const port = process.env.PORT || 8000; +const connectToDB = require("./helpers/db-connector"); +const routes = require("./routes"); + +function connectedToDB() { + const app = express(); + + raven + .config(process.env.SENTRY_URL, { + captureUnhandledRejections: true, + }) + .install(); + + // Middlewares + app.use(raven.requestHandler()); + app.use(cors()); + app.use(morgan("dev")); + app.use(bodyParser.json()); + app.use(helmet()); + + // Routes + app.set("strict routing", true); + app.get("/", (req, res) => { + console.log("calling / route"); + res.send("server is up"); + }); + app.use("/", routes); + + // Error handling + app.use(raven.errorHandler()); + app.use((req, res) => res.status(404).json({ general: "Not found" })); + app.use((err, req, res) => { + if (err instanceof SyntaxError) { + return res.status(400).json({ general: "Invalid JSON format" }); + } + + console.error(err.stack); + return res.status(500).json({ general: "Something went wrong" }); + }); + + process.on("uncaughtException", (err) => { + console.error(err); + raven.captureException(err); + }); + process.on("unhandledRejection", (err) => { + console.error(err); + raven.captureException(err); + }); + app.listen(port, () => { + console.log(`Listening on http://${ip.address()}:${port}`); + }); + // App Initialization + // if (process.env.NODE_ENV === "production") { + // app.listen(port, () => { + // console.log(`Listening on http://${ip.address()}:${port}`); + // }); + // } else { + // https + // .createServer( + // { + // key: fs.readFileSync("./certificates/server.key"), + // cert: fs.readFileSync("./certificates/server.crt"), + // }, + // app + // ) + // .listen(port, () => + // console.log(`Listening on https://${ip.address()}:${port}`) + // ); + // } +} + +connectToDB(connectedToDB); diff --git a/src/models/activation-ticket.js b/src/models/activation-ticket.js index 621d2c0..9e6112c 100644 --- a/src/models/activation-ticket.js +++ b/src/models/activation-ticket.js @@ -1,48 +1,73 @@ -const mongoose = require('mongoose'); - -const activationTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - }, - userData: { - firstName: { - type: String, - maxlength: [24, 'Should have less than 25 characters'] - }, - isSubscribed: { - type: Boolean - }, - lastName: { - type: String, - maxlength: [36, 'Should have less than 37 characters'] - }, - password: { - type: String, - maxlength: [30, 'Should have less than 31 characters'], - minlength: [8, 'Should have more than 7 characters'] - }, - username: { - type: String, - maxlength: [67, 'Should have less than 68 characters'] - } - } - }, - { timestamps: true } -); - -module.exports = { - ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), - activationTicketSchema -}; +const mongoose = require('mongoose'); + +const activationTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + }, + userData: { + firstName: { + type: String, + maxlength: [24, 'Should have less than 25 characters'] + }, + isSubscribed: { + type: Boolean + }, + lastName: { + type: String, + maxlength: [36, 'Should have less than 37 characters'] + }, + password: { + type: String, + maxlength: [30, 'Should have less than 31 characters'], + minlength: [8, 'Should have more than 7 characters'] + }, + username: { + type: String, + maxlength: [67, 'Should have less than 68 characters'] + }, + aboutMe: { + type: String, + default:null, + maxlength: [67, 'Should have less than 68 characters'] + }, + dateOfBirth: { + type: String, + default:null, + maxlength: [67, 'Should have less than 68 characters'] + }, + disability: { + type: String, + default:null, + maxlength: [67, 'Should have less than 68 characters'] + }, + gender: { + type: String, + default:null, + maxlength: [67, 'Should have less than 68 characters'] + }, + race: { + type: String, + default:null, + maxlength: [67, 'Should have less than 68 characters'] + }, + } + }, + { timestamps: true } +); + +module.exports = { + ActivationTicket: mongoose.model('ActivationTicket', activationTicketSchema), + activationTicketSchema +}; diff --git a/src/models/donations.js b/src/models/donations.js new file mode 100644 index 0000000..fa4cb67 --- /dev/null +++ b/src/models/donations.js @@ -0,0 +1,24 @@ +const mongoose = require("mongoose"); + +const donation = new mongoose.Schema({ + userId: { type: String, required: true }, + type: { type: String, enum: ["one_time", "monthly"], required: true }, + productId: String, // e.g. "monthlysupporter" or "donation_small" + transactionId: String, // Apple transaction ID + originalTransactionId: String, // same for subscription renewals + amount: Number, // optional, from Apple response + currency: String, // optional + country: String, // optional + status: { + type: String, + enum: ["purchased", "renewed", "canceled", "refunded"], + }, + platform: String, + purchasedAt: { type: Date, default: Date.now }, + expiresAt: Date, // only for subscriptions +}); + +module.exports = { + Donations: mongoose.model("Donations", donation), + donation, +}; diff --git a/src/models/event.js b/src/models/event.js index a767260..8c4b586 100644 --- a/src/models/event.js +++ b/src/models/event.js @@ -1,141 +1,141 @@ -const mongoose = require('mongoose'); - -const eventSchema = new mongoose.Schema( - { - address: { - type: String, - maxlength: [200, 'Should be less than 201 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - donationAmounts: { - type: [ - { - value: { - type: Number, - default: 5, - max: [10000, 'Should be less than 10001'], - min: [5, 'Should be greater than 4'] - } - } - ] - }, - donationEnabled: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - donationGoal: { - type: Number, - default: 10, - max: [100000, 'Should be less than 100001'], - min: [10, 'Should be greater than 9'] - }, - donationId: { - type: String, - default: '' - }, - endDate: { - type: Date, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isOpen: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - name: { - type: String, - maxlength: [100, 'Should be less than 101 characters'], - required: [true, 'Is required'] - }, - participants: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - participantsGoal: { - type: Number, - max: [1000, 'Should be less than 1001'], - min: [1, 'Should be greater than 0'], - required: [true, 'Is required'] - }, - poster: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsGoal: { - type: Number, - max: [10000, 'Should be less than 10001'], - min: [1, 'Should be greater than 0'] - }, - startDate: { - type: Date, - required: [true, 'Is required'] - }, - teamManager: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue' - } - }, - { timestamps: true } -); - -eventSchema.index({ - address: 'text', - name: 'text', - endDate: 1, - reviewsAmount: 1, - startDate: 1 -}); - -module.exports = { - Event: mongoose.model('Event', eventSchema), - eventSchema -}; +const mongoose = require('mongoose'); + +const eventSchema = new mongoose.Schema( + { + address: { + type: String, + maxlength: [200, 'Should be less than 201 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + donationAmounts: { + type: [ + { + value: { + type: Number, + default: 5, + max: [10000, 'Should be less than 10001'], + min: [5, 'Should be greater than 4'] + } + } + ] + }, + donationEnabled: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + donationGoal: { + type: Number, + default: 10, + max: [100000, 'Should be less than 100001'], + min: [10, 'Should be greater than 9'] + }, + donationId: { + type: String, + default: '' + }, + endDate: { + type: Date, + required: [true, 'Is required'] + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isOpen: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + name: { + type: String, + maxlength: [100, 'Should be less than 101 characters'], + required: [true, 'Is required'] + }, + participants: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ] + }, + participantsGoal: { + type: Number, + max: [1000, 'Should be less than 1001'], + min: [1, 'Should be greater than 0'], + required: [true, 'Is required'] + }, + poster: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + }, + reviewsGoal: { + type: Number, + max: [10000, 'Should be less than 10001'], + min: [1, 'Should be greater than 0'] + }, + startDate: { + type: Date, + required: [true, 'Is required'] + }, + teamManager: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + } + ], + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Venue' + } + }, + { timestamps: true } +); + +eventSchema.index({ + address: 'text', + name: 'text', + endDate: 1, + reviewsAmount: 1, + startDate: 1 +}); + +module.exports = { + Event: mongoose.model('Event', eventSchema), + eventSchema +}; diff --git a/src/models/password-ticket.js b/src/models/password-ticket.js index 00a4ced..ca98254 100644 --- a/src/models/password-ticket.js +++ b/src/models/password-ticket.js @@ -1,26 +1,26 @@ -const mongoose = require('mongoose'); - -const passwordTicketSchema = new mongoose.Schema( - { - email: { - type: String, - maxlength: [254, 'Should have less than 255 characters'], - required: [true, 'Is required'] - }, - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [75, 'Should have less than 76 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), - passwordTicketSchema -}; +const mongoose = require('mongoose'); + +const passwordTicketSchema = new mongoose.Schema( + { + email: { + type: String, + maxlength: [254, 'Should have less than 255 characters'], + required: [true, 'Is required'] + }, + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [75, 'Should have less than 76 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + PasswordTicket: mongoose.model('PasswordTicket', passwordTicketSchema), + passwordTicketSchema +}; diff --git a/src/models/petition.js b/src/models/petition.js index af49041..01f3423 100644 --- a/src/models/petition.js +++ b/src/models/petition.js @@ -1,59 +1,59 @@ -const mongoose = require('mongoose'); - -const petitionSchema = new mongoose.Schema( - { - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - message: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - sender: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - state: { - type: String, - default: 'pending', - enum: { - values: ['accepted', 'canceled', 'pending', 'rejected'], - message: 'Should be a valid state' - }, - required: [true, 'Is required'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - type: { - type: String, - enum: { - values: [ - 'invite-team-event', - 'invite-user-event', - 'invite-user-team', - 'request-team-event', - 'request-user-event', - 'request-user-team' - ], - message: 'Should be a valid type' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - }, - { timestamps: true } -); - -petitionSchema.index({ createdAt: -1 }); - -module.exports = { - Petition: mongoose.model('Petition', petitionSchema), - petitionSchema -}; +const mongoose = require('mongoose'); + +const petitionSchema = new mongoose.Schema( + { + event: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + }, + message: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + sender: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + }, + state: { + type: String, + default: 'pending', + enum: { + values: ['accepted', 'canceled', 'pending', 'rejected'], + message: 'Should be a valid state' + }, + required: [true, 'Is required'] + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Team' + }, + type: { + type: String, + enum: { + values: [ + 'invite-team-event', + 'invite-user-event', + 'invite-user-team', + 'request-team-event', + 'request-user-event', + 'request-user-team' + ], + message: 'Should be a valid type' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + }, + { timestamps: true } +); + +petitionSchema.index({ createdAt: -1 }); + +module.exports = { + Petition: mongoose.model('Petition', petitionSchema), + petitionSchema +}; diff --git a/src/models/photo.js b/src/models/photo.js index 6a277a8..37d7049 100644 --- a/src/models/photo.js +++ b/src/models/photo.js @@ -1,66 +1,66 @@ -const mongoose = require('mongoose'); - -const photoSchema = new mongoose.Schema( - { - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - fileName: { - type: String, - maxlength: [25, 'Should be less than 26 characters'], - required: [true, 'Is required'] - }, - isAllowed: { - type: Boolean, - default: true, - required: [true, 'Is required'] - }, - url: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - Photo: mongoose.model('Photo', photoSchema), - photoSchema -}; +const mongoose = require('mongoose'); + +const photoSchema = new mongoose.Schema( + { + complaints: [ + { + comments: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, 'Is required'] + }, + type: { + type: String, + enum: { + values: [ + 'biased', + 'copyright', + 'inconsistent', + 'offensive', + 'offtopic', + 'other', + 'spam' + ], + general: 'Invalid type of complaint' + }, + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + } + ], + fileName: { + type: String, + maxlength: [25, 'Should be less than 26 characters'], + required: [true, 'Is required'] + }, + isAllowed: { + type: Boolean, + default: true, + required: [true, 'Is required'] + }, + url: { + type: String, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + Photo: mongoose.model('Photo', photoSchema), + photoSchema +}; diff --git a/src/models/refresh-token.js b/src/models/refresh-token.js index ac74a06..3ddeffe 100644 --- a/src/models/refresh-token.js +++ b/src/models/refresh-token.js @@ -1,27 +1,27 @@ -const mongoose = require('mongoose'); - -const refreshTokenSchema = new mongoose.Schema( - { - expiresAt: { - type: Date, - required: [true, 'Is required'] - }, - key: { - type: String, - maxlength: [80, 'Should have less than 81 characters'], - required: [true, 'Is required'], - unique: true - }, - userId: { - type: String, - maxlength: [24, 'Should have less than 25 characters'], - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -module.exports = { - RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), - refreshTokenSchema -}; +const mongoose = require('mongoose'); + +const refreshTokenSchema = new mongoose.Schema( + { + expiresAt: { + type: Date, + required: [true, 'Is required'] + }, + key: { + type: String, + maxlength: [80, 'Should have less than 81 characters'], + required: [true, 'Is required'], + unique: true + }, + userId: { + type: String, + maxlength: [24, 'Should have less than 25 characters'], + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +module.exports = { + RefreshToken: mongoose.model('RefreshToken', refreshTokenSchema), + refreshTokenSchema +}; diff --git a/src/models/review.js b/src/models/review.js index 7ed9617..5ac2679 100644 --- a/src/models/review.js +++ b/src/models/review.js @@ -1,122 +1,125 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: Boolean, - hasPortableRamp: Boolean, - hasWideEntrance: Boolean, - hasAccessibleTableHeight: Boolean, - hasAccessibleElevator: Boolean, - hasInteriorRamp: Boolean, - hasSwingOutDoor: Boolean, - hasLargeStall: Boolean, - hasSupportAroundToilet: Boolean, - hasLoweredSinks: Boolean, - - //original fields - allowsGuideDog: Boolean, - comments: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - complaints: [ - { - comments: { - type: String, - maxlength: [300, 'Should be less than 30 characters'] - }, - createdAt: { - type: Date, - default: Date.now, - required: [true, 'Is required'] - }, - type: { - type: String, - enum: { - values: [ - 'biased', - 'copyright', - 'inconsistent', - 'offensive', - 'offtopic', - 'other', - 'spam' - ], - general: 'Invalid type of complaint' - }, - required: [true, 'Is required'] - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - } - } - ], - - /* - * deprecated 5-star scoring - */ - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - event: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - }, - hasParking: Boolean, - hasSecondEntry: Boolean, - hasWellLit: Boolean, - isBanned: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: Boolean, - isSpacious: Boolean, - steps: { - type: Number, - max: [3, 'Should be less than 4'], - min: [0, 'Should be more than -1'] - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - }, - user: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: [true, 'Is required'] - }, - venue: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Venue', - required: [true, 'Is required'] - }, - voters: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ] - }, - { timestamps: true } -); - -module.exports = { - Review: mongoose.model('Review', reviewSchema), - reviewSchema -}; +const mongoose = require("mongoose"); + +const reviewSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: Boolean, + hasPortableRamp: Boolean, + hasWideEntrance: Boolean, + hasAccessibleTableHeight: Boolean, + hasAccessibleElevator: Boolean, + hasInteriorRamp: Boolean, + hasSwingOutDoor: Boolean, + hasLargeStall: Boolean, + hasSupportAroundToilet: Boolean, + hasLoweredSinks: Boolean, + has1Step: Boolean, + has2Step: Boolean, + multipleFloors: Boolean, + hasWashroom: Boolean, + brightLightTitle: Boolean, + + //original fields + allowsGuideDog: Boolean, + comments: { + type: String, + }, + complaints: [ + { + comments: { + type: String, + }, + createdAt: { + type: Date, + default: Date.now, + required: [true, "Is required"], + }, + type: { + type: String, + enum: { + values: [ + "biased", + "copyright", + "inconsistent", + "offensive", + "offtopic", + "other", + "spam", + ], + general: "Invalid type of complaint", + }, + required: [true, "Is required"], + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: [true, "Is required"], + }, + }, + ], + + /* + * deprecated 5-star scoring + */ + _entryScore: { + type: Number, + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _bathroomScore: { + type: Number, + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false, + }, + + event: { + type: mongoose.Schema.Types.ObjectId, + ref: "Event", + }, + hasParking: Boolean, + hasSecondEntry: Boolean, + hasWellLit: Boolean, + isBanned: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + isQuiet: Boolean, + isSpacious: Boolean, + steps: { + type: Number, + max: [3, "Should be less than 4"], + min: [0, "Should be more than -1"], + }, + team: { + type: mongoose.Schema.Types.ObjectId, + ref: "Team", + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: [true, "Is required"], + }, + venue: { + type: mongoose.Schema.Types.ObjectId, + ref: "Venue", + required: [true, "Is required"], + }, + voters: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + }, + ], + }, + { timestamps: true } +); + +module.exports = { + Review: mongoose.model("Review", reviewSchema), + reviewSchema, +}; diff --git a/src/models/survey.js b/src/models/survey.js new file mode 100644 index 0000000..44d0c0e --- /dev/null +++ b/src/models/survey.js @@ -0,0 +1,53 @@ +const mongoose = require("mongoose"); + +const surveySchema = new mongoose.Schema( + { + features: { + type: String, + required: [true, "Is required"], + }, + navigationEase: { + type: String, + required: [true, "Is required"], + }, + motivation: { + type: String, + required: [true, "Is required"], + }, + accessibility: { + type: String, + required: [true, "Is required"], + }, + additionalFeatures: { + type: String, + required: true, + }, + satisfaction: { + type: String, + required: false, + }, + challenges: { + type: String, + required: false, + }, + recommend: { + type: String, + required: false, + }, + frequency: { + type: String, + required: false, + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: [true, "Is required"], + }, + }, + { timestamps: true } +); + +module.exports = { + Survey: mongoose.model("Survey", surveySchema), + surveySchema, +}; diff --git a/src/models/team.js b/src/models/team.js index 0d61217..9d96722 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -1,62 +1,62 @@ -const mongoose = require('mongoose'); - -const teamSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [300, 'Should be less than 301 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - managers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - required: [true, 'Is required'] - }, - members: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'User' - } - ], - name: { - type: String, - maxlength: [35, 'Should be less than 36 characters'], - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - } - }, - { timestamps: true } -); - -teamSchema.index({ name: 'text', reviewsAmount: 1 }); - -module.exports = { - Team: mongoose.model('Team', teamSchema), - teamSchema -}; +const mongoose = require('mongoose'); + +const teamSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`, + maxlength: [2000, 'Should be less than 2001 characters'], + required: [true, 'Is required'] + }, + description: { + type: String, + maxlength: [300, 'Should be less than 301 characters'] + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Event' + } + ], + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + managers: { + type: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + required: [true, 'Is required'] + }, + members: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User' + } + ], + name: { + type: String, + maxlength: [35, 'Should be less than 36 characters'], + required: [true, 'Is required'] + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, 'Is required'] + } + }, + { timestamps: true } +); + +teamSchema.index({ name: 'text', reviewsAmount: 1 }); + +module.exports = { + Team: mongoose.model('Team', teamSchema), + teamSchema +}; diff --git a/src/models/user.js b/src/models/user.js index e0c9cb9..6dd097a 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -1,193 +1,269 @@ -const bcrypt = require('bcrypt-nodejs'); -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema( - { - avatar: { - type: String, - default: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`, - maxlength: [2000, 'Should be less than 2001 characters'], - required: [true, 'Is required'] - }, - description: { - type: String, - maxlength: [2000, 'Should be less than 2001 characters'] - }, - disabilities: { - type: [String], - default: ['none'], - enum: { - values: [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ], - general: 'Invalid type of disability' - }, - required: [true, 'Is required'] - }, - email: { - type: String, - maxlength: [254, 'Should be less than 255 characters'] - }, - events: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Event' - } - ], - facebookId: String, - firstName: { - type: String, - maxlength: [24, 'Should be less than 25 characters'], - required: [true, 'Is required'] - }, - gender: { - type: String, - default: 'private', - enum: { - values: ['female', 'male', 'other', 'private', 'transgender'], - general: 'Invalid type of gender' - }, - required: [true, 'Is required'] - }, - googleId: String, - hashedPassword: { - type: String, - maxlength: [256, 'Should be less than 255 characters'] - }, - isAdmin: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isBlocked: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isSubscribed: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - lastName: { - type: String, - maxlength: [36, 'Should be less than 37 characters'], - required: [true, 'Is required'] - }, - language: { - type: String, - default: 'en', - enum: { - values: ['en', 'es'], - general: 'Invalid type of language' - }, - required: [true, 'Is required'] - }, - phone: { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - }, - reviewFieldsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - reviewsAmount: { - type: Number, - default: 0, - required: [true, 'Is required'] - }, - showDisabilities: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showEmail: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - showPhone: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - teams: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: 'Team' - } - ], - username: { - type: String, - maxlength: [67, 'Should be less than 68 characters'] - }, - zip: { - type: String, - maxlength: [32, 'Should be less than 33 characters'] - } - }, - { timestamps: true } -); - -userSchema.index( - { - email: 'text', - firstName: 'text', - lastName: 'text', - username: 'text', - reviewsAmount: 1 - }, - { weights: { email: 5, username: 5 } } -); - -function hashPassword(password) { - bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { - if (errorOnSaltGeneration) { - return false; - } - - bcrypt.hash( - password, - salt, - null, - (errorOnHashingPassword, hashedPassword) => { - if (errorOnHashingPassword) { - return false; - } - - this.hashedPassword = hashedPassword; - return true; - } - ); - }); -} - -function comparePassword(password) { - return bcrypt.compareSync(password, this.hashedPassword); -} - -userSchema.virtual('password').set(hashPassword); -userSchema.methods.comparePassword = comparePassword; - -module.exports = { - User: mongoose.model('User', userSchema), - userSchema -}; +const bcrypt = require("bcrypt-nodejs"); +const mongoose = require("mongoose"); + +const userSchema = new mongoose.Schema( + { + avatar: { + type: String, + default: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`, + maxlength: [2000, "Should be less than 2001 characters"], + required: [true, "Is required"], + }, + description: { + type: String, + maxlength: [2000, "Should be less than 2001 characters"], + }, + disabilities: { + type: [String], + default: ["none"], + enum: { + values: [ + "brain", + "cognitive", + "hearing", + "invisible", + "none", + "other", + "physical", + "private", + "psychological", + "spinal-cord", + "vision", + ], + general: "Invalid type of disability", + }, + required: [true, "Is required"], + }, + email: { + type: String, + maxlength: [254, "Should be less than 255 characters"], + }, + events: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "Event", + }, + ], + facebookId: String, + firstName: { + type: String, + maxlength: [24, "Should be less than 25 characters"], + }, + gender: { + type: String, + default: "not-to-say", + enum: { + values: [ + "female", + "male", + "other", + "private", + "transgender", + "non-binary", + "gender-fluid", + "agender", + "not-to-say", + ], + general: "Invalid type of gender", + }, + required: [true, "Is required"], + }, + googleId: String, + appleId: String, + hashedPassword: { + type: String, + maxlength: [256, "Should be less than 255 characters"], + }, + isAdmin: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + isArchived: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + lastLogin: { + type: Date, + default: null, + }, + inactivityEmailSent: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + inactivityEmailSentAt: { + type: Date, + default: null, + }, + isBlocked: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + isSubscribed: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + lastName: { + type: String, + maxlength: [36, "Should be less than 37 characters"], + }, + language: { + type: String, + default: "en", + enum: { + values: ["en", "es"], + general: "Invalid type of language", + }, + required: [true, "Is required"], + }, + phone: { + type: String, + maxlength: [50, "Should be less than 51 characters"], + }, + reviewFieldsAmount: { + type: Number, + default: 0, + required: [true, "Is required"], + }, + reviewsAmount: { + type: Number, + default: 0, + required: [true, "Is required"], + }, + showDisabilities: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + lastActivityTime: { + type: Date, + default: null, + }, + lastLocation: { + type: { + lat: { + type: Number, + }, + lng: { + type: Number, + }, + }, + default: { + lat: null, + lng: null, + }, + }, + device: { + type: String, + default: "", + }, + showEmail: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + showPhone: { + type: Boolean, + default: false, + required: [true, "Is required"], + }, + teams: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "Team", + }, + ], + username: { + type: String, + maxlength: [67, "Should be less than 68 characters"], + }, + zip: { + type: String, + maxlength: [32, "Should be less than 33 characters"], + }, + aboutMe: { + type: String, + }, + birthday: { + type: Date, + default: null, + required: false, + }, + race: { + type: String, + default: "", + enum: [ + "black/african american", + "caucasian", + "indigenous/first nation/native american", + "latino/hispanic", + "middle eastern/north african", + "native hawaiian/pacific islander", + "biracial/multiracial", + "asian", + "non-naucasian", + "not-to-disclose", + "", + ], + required: false, + }, + disability: { + type: String, + default: "", + enum: ["yes", "No", "not-to-say", ""], + required: false, + }, + }, + { timestamps: true } +); + +userSchema.index( + { + email: "text", + firstName: "text", + lastName: "text", + username: "text", + reviewsAmount: 1, + }, + { weights: { email: 5, username: 5 } } +); + +function hashPassword(password) { + bcrypt.genSalt(10, (errorOnSaltGeneration, salt) => { + if (errorOnSaltGeneration) { + return false; + } + + bcrypt.hash( + password, + salt, + null, + (errorOnHashingPassword, hashedPassword) => { + if (errorOnHashingPassword) { + return false; + } + + this.hashedPassword = hashedPassword; + return true; + } + ); + }); +} + +function comparePassword(password) { + return bcrypt.compareSync(password, this.hashedPassword ?? ''); +} + +userSchema.virtual("password").set(hashPassword); +userSchema.methods.comparePassword = comparePassword; + +module.exports = { + User: mongoose.model("User", userSchema), + userSchema, +}; diff --git a/src/models/venue.js b/src/models/venue.js index 9c473f4..c629761 100644 --- a/src/models/venue.js +++ b/src/models/venue.js @@ -1,315 +1,355 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema( - { - //new expanded fields - hasPermanentRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasPortableRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWideEntrance: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleTableHeight: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasAccessibleElevator: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasInteriorRamp: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSwingOutDoor: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLargeStall: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSupportAroundToilet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasLoweredSinks: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - entranceScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - entranceGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - interiorScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //description: 'can only be one of the enum values and is required', - //: 'default' - type: Number, - default: 0 - }, - interiorGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - restroomScore: { - //enum: ['alert', 'caution', 'accessible', 'default'], - //: 'can only be one of the enum values and is required', - //default: 'default' - type: Number, - default: 0 - }, - restroomGlyphs: { - type: String, - maxlength: [32, 'Should be less than 256 characters'] - }, - mapMarkerScore: { - type: Number, - default: 0 - }, - - //original fields - address: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - allowsGuideDog: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - - /* - * deprecated 5-star scoring - */ - _bathroomReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than 1'] - }, - _bathroomScore: { - type: Number - //max: [4, 'Should be less than 5'], - //min: [1, 'Should be more than 0'] - }, - _entryReviews: { - type: Number, - default: 0 - //min: [0, 'Should be more than -1'] - }, - _entryScore: { - type: Number - //max: [9, 'Should be less than 10'], - //min: [1, 'Should be more than 0'] - }, - _isScoreConverted: { - type: Boolean, - default: false - }, - - hasParking: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasSecondEntry: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - hasWellLit: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isArchived: { - type: Boolean, - default: false, - required: [true, 'Is required'] - }, - isQuiet: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - isSpacious: { - yes: { - type: Number, - default: 0 - }, - no: { - type: Number, - default: 0 - } - }, - location: { - type: { - type: String, - default: 'Point' - }, - coordinates: [Number] - }, - name: { - type: String, - maxlength: [255, 'Should be less than 256 characters'] - }, - photos: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Photo' - } - ], - placeId: { - type: String, - maxlength: [255, 'Should be less than 256 characters'], - required: [true, 'Is required'] - }, - reviews: [ - { - type: mongoose.Schema.ObjectId, - ref: 'Review' - } - ], - steps: { - zero: { - type: Number, - default: 0 - }, - one: { - type: Number, - default: 0 - }, - two: { - type: Number, - default: 0 - }, - moreThanTwo: { - type: Number, - default: 0 - } - }, - types: [ - { - type: String, - maxlength: [50, 'Should be less than 51 characters'] - } - ] - }, - { timestamps: true } -); - -venueSchema.index({ location: '2dsphere', placeId: 1 }); - -venueSchema.virtual('coordinates').get(function() { - return { - lat: this.location.coordinates[1], - lng: this.location.coordinates[0] - }; -}); - -venueSchema.virtual('photo').get(function() { - return undefined; -}); - -module.exports = { - Venue: mongoose.model('Venue', venueSchema), - venueSchema -}; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema( + { + //new expanded fields + hasPermanentRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWheelchairParking: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + brightLightTitle: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWashroom: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + multipleFloors: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasPortableRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWideEntrance: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleTableHeight: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasAccessibleElevator: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasInteriorRamp: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSwingOutDoor: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLargeStall: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSupportAroundToilet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasLoweredSinks: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + entranceScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + entranceGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + interiorScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //description: 'can only be one of the enum values and is required', + //: 'default' + type: Number, + default: 0 + }, + interiorGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + restroomScore: { + //enum: ['alert', 'caution', 'accessible', 'default'], + //: 'can only be one of the enum values and is required', + //default: 'default' + type: Number, + default: 0 + }, + restroomGlyphs: { + type: String, + maxlength: [32, 'Should be less than 256 characters'] + }, + mapMarkerScore: { + type: Number, + default: 0 + }, + + //original fields + address: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + allowsGuideDog: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + + /* + * deprecated 5-star scoring + */ + _bathroomReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than 1'] + }, + _bathroomScore: { + type: Number + //max: [4, 'Should be less than 5'], + //min: [1, 'Should be more than 0'] + }, + _entryReviews: { + type: Number, + default: 0 + //min: [0, 'Should be more than -1'] + }, + _entryScore: { + type: Number + //max: [9, 'Should be less than 10'], + //min: [1, 'Should be more than 0'] + }, + _isScoreConverted: { + type: Boolean, + default: false + }, + + hasParking: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasSecondEntry: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + hasWellLit: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isArchived: { + type: Boolean, + default: false, + required: [true, 'Is required'] + }, + isQuiet: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + isSpacious: { + yes: { + type: Number, + default: 0 + }, + no: { + type: Number, + default: 0 + } + }, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number] + }, + name: { + type: String, + maxlength: [255, 'Should be less than 256 characters'] + }, + photos: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Photo' + } + ], + placeId: { + type: String, + maxlength: [255, 'Should be less than 256 characters'], + required: [true, 'Is required'] + }, + reviews: [ + { + type: mongoose.Schema.ObjectId, + ref: 'Review' + } + ], + steps: { + zero: { + type: Number, + default: 0 + }, + one: { + type: Number, + default: 0 + }, + two: { + type: Number, + default: 0 + }, + moreThanTwo: { + type: Number, + default: 0 + } + }, + types: [ + { + type: String, + maxlength: [50, 'Should be less than 51 characters'] + } + ] + }, + { timestamps: true } +); + +venueSchema.index({ location: '2dsphere', placeId: 1 }); + +venueSchema.virtual('coordinates').get(function () { + return { + lat: this.location.coordinates[1], + lng: this.location.coordinates[0] + }; +}); + +venueSchema.virtual('photo').get(function () { + return undefined; +}); + +module.exports = { + Venue: mongoose.model('Venue', venueSchema), + venueSchema +}; diff --git a/src/routes/auth/activate-account.js b/src/routes/auth/activate-account.js index b78caf7..4ad8407 100644 --- a/src/routes/auth/activate-account.js +++ b/src/routes/auth/activate-account.js @@ -1,139 +1,142 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const key = req.params.key; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ key }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - console.log( - `Activation ticket with key ${key} failed to be found at activate-account.` - ); - return next(err); - } - - if (!activationTicket) { - return res.status(404).json({ general: 'Activation ticket not found' }); - } - - let expiresAt = moment(activationTicket.expiresAt).utc(); - const now = moment.utc(); - if (expiresAt.isBefore(now)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Activation ticket expired' }); - } - - const userData = Object.assign({}, activationTicket.userData, { - email: activationTicket.email - }); - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at activate-account.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at activate-account.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at activate-account.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with key ${ - activationTicket.key - } failed to be deleted at activate-account.` - ); - return next(err); - } - - return res.redirect(`${process.env.APP_URL}/sign-in`); -}; +const crypto = require("crypto"); + +const moment = require("moment"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); + +const { ActivationTicket } = require("../../models/activation-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + const key = req.params.key; + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ key }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Activation ticket not found" }); + } + return next(err); + } + + if (!activationTicket) { + return res.status(404).json({ general: "Activation ticket not found" }); + } + + let expiresAt = moment(activationTicket.expiresAt).utc(); + const now = moment.utc(); + if (expiresAt.isBefore(now)) { + try { + await ActivationTicket.deleteOne({ key }); + } catch (err) { + return next(err); + } + + return res.status(400).json({ general: "Activation ticket expired" }); + } + + const userData = { + firstName: activationTicket?.userData?.firstName, + isSubscribed: activationTicket?.userData?.isSubscribed, + lastName: activationTicket?.userData?.lastName, + password: activationTicket?.userData?.password, + username: activationTicket?.userData?.username, + aboutMe: activationTicket?.userData?.aboutMe || '', + dateOfBirth: activationTicket?.userData?.dateOfBirth || null, + disability: activationTicket?.userData?.disability || '', + gender: activationTicket?.userData?.gender || 'not-to-say', + race: activationTicket?.userData?.race || '', + email: activationTicket?.email, + }; + + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false, + }); + } catch (err) { + console.log("Users failed to be found at activate-account."); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: "Is already taken" }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: "lowercase", + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false, + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at activate-account.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + console.log( + `User failed to be created at activate-account.\nData: ${JSON.stringify( + userData + )}` + ); + return next(err); + } + + const today = moment.utc(); + expiresAt = today.add(30, "days").toDate(); + const refreshTokenData = { + expiresAt, + key: `${user.id}${crypto.randomBytes(28).toString("hex")}`, + userId: user.id, + }; + + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token failed to be created at activate-account.\nData: ${JSON.stringify( + refreshTokenData + )}` + ); + return next(err); + } + + try { + await ActivationTicket.deleteOne({ key }); + } catch (err) { + console.log( + `Activation ticket with key ${ + activationTicket.key + } failed to be deleted at activate-account.` + ); + return next(err); + } + // TODO change base URL + + return res.redirect(`https://axsmap.com/sign-in`); +}; diff --git a/src/routes/auth/apple-sign-in.js b/src/routes/auth/apple-sign-in.js new file mode 100644 index 0000000..9bbdc1f --- /dev/null +++ b/src/routes/auth/apple-sign-in.js @@ -0,0 +1,74 @@ +const crypto = require("crypto"); + +const axios = require("axios"); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateAppleSignIn } = require("./validations"); + +const appleSignin = require("apple-signin-auth"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateAppleSignIn(req.body); + const { identityToken } = req.body; + if (!isValid) { + return res.status(400).json(errors); + } + + try { + const appleResponse = await appleSignin.verifyIdToken(identityToken, { + audience: process?.env?.APPLE_APP_IDENTIFIER, // Your app's Bundle ID or Service ID + ignoreExpiration: false, // Set true only for testing (not recommended in production) + }); + console.log(appleResponse); + let user = await User.findOne({ + email: appleResponse?.email, + }); + if (!user) { + user = new User({ + email: appleResponse?.email, + firstName:appleResponse?.fullName?.givenName ?? "", + lastName:appleResponse?.fullName?.familyName ?? "", + appleId: appleResponse?.sub, + lastLogin: new Date(), + }); + + await user.save(); + } else { + // Check if user is archived + if (user.isArchived) { + return res.status(403).json({ + error: "Account archived", + isArchived: true, + userId: user._id.toString() + }); + } + + // Update lastLogin for existing users + await User.findByIdAndUpdate(user._id, { lastLogin: new Date() }); + } + + const userId = user._id; + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + let refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { + expiresIn: "30d", + }); + res.json({ + refreshToken: refreshToken.key, + token, + }); + } catch (err) { + console.log(err) + res.status(401).json({ success: false, error: "Invalid Apple token" }); + } +}; diff --git a/src/routes/auth/facebook-sign-in.js b/src/routes/auth/facebook-sign-in.js index bc68c5e..42c44a8 100644 --- a/src/routes/auth/facebook-sign-in.js +++ b/src/routes/auth/facebook-sign-in.js @@ -1,200 +1,105 @@ -const crypto = require('crypto'); - -const axios = require('axios'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateFacebookSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateFacebookSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://graph.facebook.com/v2.10/oauth/access_token'; - const getTokenParams = { - code, - client_id: process.env.FACEBOOK_CLIENT_ID, - client_secret: process.env.FACEBOOK_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/facebook` - }; - let getTokenResponse; - try { - getTokenResponse = await axios.get(getTokenUrl, { params: getTokenParams }); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const facebookToken = getTokenResponse.data.access_token; - - const getProfileUrl = - 'https://graph.facebook.com/v2.10/me?fields=id,email,first_name,last_name,locale'; - const getProfileOptions = { - params: { - access_token: facebookToken - } - }; - let getProfileResponse; - try { - getProfileResponse = await axios.get(getProfileUrl, getProfileOptions); - } catch (err) { - console.log('Profile data failed to be found at facebook-sign-in.'); - return next(err); - } - - const email = getProfileResponse.data.email - ? getProfileResponse.data.email - : ''; - const facebookId = getProfileResponse.data.id; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { facebookId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with facebookId ${facebookId} and email ${email} failed to be found at facebook-sign-in.` - ); - return next(err); - } - - let accessToken; - let refreshToken; - - if (!user) { - console.log(getProfileResponse.data); - const userData = { - email: getProfileResponse.data.email ? getProfileResponse.data.email : '', - facebookId: getProfileResponse.data.id, - firstName: getProfileResponse.data.first_name, - lastName: getProfileResponse.data.last_name - }; - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at facebook-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at facebook-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - const getPictureUrl = `https://graph.facebook.com/v2.10/${ - userData.facebookId - }/picture`; - const getPictureOptions = { - params: { - access_token: accessToken, - redirect: false, - type: 'large' - } - }; - let getPictureResponse; - try { - getPictureResponse = await axios.get(getPictureUrl, getPictureOptions); - } catch (err) { - console.log('User picture failed to be found at facebook-sign-in.'); - return next(err); - } - - const isSilhouette = getPictureResponse.data.data.is_silhouette; - if (!isSilhouette) { - userData.avatar = getPictureResponse.data.data.url; - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at facebook-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at facebook-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); -}; +const crypto = require("crypto"); + +const axios = require("axios"); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateFacebookSignIn } = require("./validations"); + +module.exports = async (req, res, next) => { + // const { errors, isValid } = validateFacebookSignIn(req.body); + // if (!isValid) { + // return res.status(400).json(errors); + // } + + let token = req?.body?.code; + try { + if (req.body.web) { + const tokenResponse = await axios.get( + "https://graph.facebook.com/v17.0/oauth/access_token", + { + params: { + client_id: process.env.FACEBOOK_CLIENT_ID, + client_secret: process.env.FACEBOOK_CLIENT_SECRET, + redirect_uri: req.body.redirectUri, // must match exactly + code: req.body.code, + }, + } + ); + + token = tokenResponse.data.access_token; + } + + let fbUser = req.body?.profile || {}; + if (!req.body?.profile) { + const fbUserResponse = await axios.get(`https://graph.facebook.com/me`, { + params: { + access_token: token, + fields: "id,name,email,picture", + }, + }); + + fbUser = fbUserResponse.data; + } + if (fbUser?.email) { + const email = fbUser.email; + + let user = await User.findOne({ email: fbUser.email }); + + if (!user) { + const [firstName, lastName] = fbUser.name.split(" "); + user = new User({ + fbId: fbUser.id, + email, + firstName: firstName || "", + lastName: lastName || "", + avatar: fbUser.picture.data.url, + lastLogin: new Date(), + }); + + await user.save(); + } else { + // Check if user is archived + if (user.isArchived) { + return res.status(403).json({ + error: "Account archived", + isArchived: true, + userId: user._id.toString() + }); + } + + // Update lastLogin for existing users + await User.findByIdAndUpdate(user._id, { lastLogin: new Date() }); + } + + const userId = user._id; + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { + expiresIn: "30d", + }); + + res.json({ + refreshToken: refreshToken.key, + token, + }); + } else { + res.status(400).json({ + success: false, + error: "Email is not linked with this account", + }); + } + } catch (err) { + res.status(401).json({ success: false, error: "Invalid Facebook token" }); + } +}; diff --git a/src/routes/auth/forgotten-password.js b/src/routes/auth/forgotten-password.js index ed3039f..7e4c61b 100644 --- a/src/routes/auth/forgotten-password.js +++ b/src/routes/auth/forgotten-password.js @@ -1,88 +1,83 @@ -const crypto = require('crypto'); - -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateForgottenPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateForgottenPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log( - `User with email ${email} failed to be found at forgotten-password.` - ); - return next(err); - } - - if (!user) { - return res.status(200).json({ general: 'Success' }); - } - - try { - await PasswordTicket.remove({ email }); - } catch (err) { - console.log( - `Password ticket with email ${email} failed to be removed at forgotten-password.` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); - } catch (err) { - console.log( - `Password ticket failed to be created at forgotten-password.\nData: ${JSON.stringify( - { email, expiresAt, key } - )}` - ); - return next(err); - } - - const htmlContent = ` -

Hi from AXS Map!

-

To reset your password use the link below:

-
- - ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} - -

-

Stay awesome.

- `; - const receiversEmails = [passwordTicket.email]; - const subject = 'Reset Password'; - const textContent = ` - Hi from AXS Map! - To reset your password use the link below: - ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} - Stay awesome. - `; - - sendEmail({ - receiversEmails, - subject, - htmlContent, - textContent - }); - - return res.status(200).json({ general: 'Success' }); -}; +const crypto = require("crypto"); + +const moment = require("moment"); + +const { PasswordTicket } = require("../../models/password-ticket"); +const { sendEmail } = require("../../helpers"); +const { User } = require("../../models/user"); + +const { validateForgottenPassword } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateForgottenPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + } catch (err) { + console.log( + `User with email ${email} failed to be found at forgotten-password.` + ); + return next(err); + } + + if (!user) { + return res.status(200).json({ general: "Success" }); + } + + try { + await PasswordTicket.deleteOne({ email }); + } catch (err) { + console.log( + `Password ticket with email ${email} failed to be removed at forgotten-password.` + ); + return next(err); + } + + const today = moment.utc(); + const expiresAt = today.add(1, "days").toDate(); + const key = `${crypto + .randomBytes(31) + .toString("hex")}${new Date().getTime().toString()}`; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.create({ email, expiresAt, key }); + } catch (err) { + return next(err); + } + + const htmlContent = ` +

Hi from AXS Map!

+

To reset your password use the link below:

+
+ + https://axsmap.com/reset-password?key=${passwordTicket.key} + +

+

Stay awesome.

+ `; + const receiversEmails = [passwordTicket.email]; + const subject = "Reset Password"; + const textContent = ` + Hi from AXS Map! + To reset your password use the link below: + ${process.env.APP_URL}/reset-password?key=${passwordTicket.key} + Stay awesome. + `; + + sendEmail({ + receiversEmails, + subject, + htmlContent, + textContent, + }); + + return res.status(200).json({ general: "Success" }); +}; diff --git a/src/routes/auth/generate-token.js b/src/routes/auth/generate-token.js index ba1016f..b6ff3e7 100644 --- a/src/routes/auth/generate-token.js +++ b/src/routes/auth/generate-token.js @@ -1,55 +1,55 @@ -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateGenerateToken } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGenerateToken(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ key }); - } catch (err) { - console.log( - `Refresh Token with key ${key} failed to be found at generate-token.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(404).json({ general: 'Refresh Token not found' }); - } - - const expiresAt = moment(refreshToken.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at generate-token.` - ); - return next(err); - } - - return res.status(401).json({ general: 'Refresh Token expired' }); - } - - const token = jwt.sign( - { userId: refreshToken.userId }, - process.env.JWT_SECRET, - { - expiresIn: 3600 - } - ); - return res.status(200).json({ token }); -}; +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); + +const { validateGenerateToken } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateGenerateToken(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ key }); + } catch (err) { + console.log( + `Refresh Token with key ${key} failed to be found at generate-token.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(404).json({ general: "Refresh Token not found" }); + } + + const expiresAt = moment(refreshToken.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await RefreshToken.deleteOne({ key }); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at generate-token.` + ); + return next(err); + } + + return res.status(401).json({ general: "Refresh Token expired" }); + } + + const token = jwt.sign( + { userId: refreshToken.userId }, + process.env.JWT_SECRET, + { + expiresIn: '30d', + } + ); + return res.status(200).json({ token }); +}; diff --git a/src/routes/auth/google-sign-in.js b/src/routes/auth/google-sign-in.js index 6031188..216a02a 100644 --- a/src/routes/auth/google-sign-in.js +++ b/src/routes/auth/google-sign-in.js @@ -1,188 +1,102 @@ -const crypto = require('crypto'); -const querystring = require('querystring'); - -const axios = require('axios'); -const GoogleAuth = require('google-auth-library'); -const jwt = require('jsonwebtoken'); -const moment = require('moment'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateGoogleSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateGoogleSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const code = req.body.code; - - const getTokenUrl = 'https://www.googleapis.com/oauth2/v4/token'; - const getTokenParams = { - code, - client_id: process.env.GOOGLE_CLIENT_ID, - client_secret: process.env.GOOGLE_CLIENT_SECRET, - redirect_uri: `${process.env.APP_URL}/auth/google`, - grant_type: 'authorization_code' - }; - let getTokenResponse; - try { - getTokenResponse = await axios.post( - getTokenUrl, - querystring.stringify(getTokenParams) - ); - } catch (err) { - return res.status(400).json({ general: 'Invalid code' }); - } - - const auth = new GoogleAuth(); - const client = new auth.OAuth2(process.env.GOOGLE_CLIENT_ID, '', ''); - const idToken = getTokenResponse.data.id_token; - client.verifyIdToken( - idToken, - process.env.GOOGLE_CLIENT_ID, - async (err, login) => { - if (err) { - return res.status(400).json({ general: 'Invalid token id' }); - } - - const payload = login.getPayload(); - - const email = payload.email; - const googleId = payload.sub; - let user; - try { - user = await User.findOne({ - $or: [{ email }, { googleId }], - isArchived: false - }); - } catch (err) { - console.log( - `User with googleId ${googleId} and email ${email} failed to be found at google-sign-in.` - ); - return next(err); - } - - let refreshToken; - - if (!user) { - const userData = { - email: payload.email, - googleId: payload.sub, - firstName: payload.given_name, - lastName: payload.family_name - }; - - if (payload.locale === 'en') { - userData.language = 'en'; - } else if (payload.locale === 'es') { - userData.language = 'es'; - } - - if (payload.picture) { - userData.avatar = payload.picture; - } - - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at google-sign-in.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at google-sign-in.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - - try { - user = await User.create(userData); - } catch (err) { - console.log( - `User failed to be created at google-sign-in.\nData: ${JSON.stringify( - userData - )}` - ); - return next(err); - } - - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const refreshTokenData = { - expiresAt, - key: `${user.id}${crypto.randomBytes(28).toString('hex')}`, - userId: user.id - }; - - try { - refreshToken = await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token failed to be created at google-sign-in.\nData: ${JSON.stringify( - refreshTokenData - )}` - ); - return next(err); - } - } else { - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at google-sign-in.` - ); - return next(err); - } - } - - const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { - expiresIn: 3600 - }); - refreshToken = refreshToken.key; - - return res.status(200).json({ token, refreshToken }); - } - ); -}; +const crypto = require("crypto"); +const querystring = require("querystring"); + +const axios = require("axios"); +const { OAuth2Client } = require("google-auth-library"); +const jwt = require("jsonwebtoken"); +const moment = require("moment"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateGoogleSignIn } = require("./validations"); + +const CLIENT_ID = process.env.GOOGLE_CLIENT_ID; + +module.exports = async (req, res) => { + const { errors, isValid } = validateGoogleSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + let code = req.body.code; + const oauth2Client = new OAuth2Client(CLIENT_ID); + try { + const deviceType = req.headers["x-device-type"]; + if (deviceType === "web") { + const tokenRes = await fetch("https://oauth2.googleapis.com/token", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ + code, + client_id: process.env.GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET, + redirect_uri: process.env.GOOGLE_REDIRECT_URI, + grant_type: "authorization_code", + }), + }); + const googleToken = await tokenRes.json(); + code =googleToken?.id_token + } + + const ticket = await oauth2Client.verifyIdToken({ + idToken: code, + audience: CLIENT_ID, + }); + + const payload = ticket.getPayload(); + const { email, name, picture } = payload; + + const [firstName, lastName] = name.split(" "); + + let user = await User.findOne({ email }); + if (!user) { + user = new User({ + email: email, + firstName: firstName || name, + lastName: lastName || "", + createdAt: new Date(), + avatar: picture, + lastLogin: new Date(), + }); + await user.save(); + } else { + // Check if user is archived + if (user.isArchived) { + return res.status(403).json({ + error: "Account archived", + isArchived: true, + userId: user._id.toString() + }); + } + + // Update lastLogin for existing users + await User.findByIdAndUpdate(user._id, { lastLogin: new Date() }); + } + + const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { + expiresIn: "30d", + }); + + const userId = user._id; + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + + return res.json({ + token, + refreshToken: refreshToken.key, + }); + } catch (err) { + console.log(err); + return res.status(500).json({ error: "Something went wrong" }); + } +}; diff --git a/src/routes/auth/index.js b/src/routes/auth/index.js index d1cb782..7ed6889 100644 --- a/src/routes/auth/index.js +++ b/src/routes/auth/index.js @@ -1,27 +1,31 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const activateAccount = require('./activate-account'); -const facebookSignIn = require('./facebook-sign-in'); -const forgottenPassword = require('./forgotten-password'); -const generateToken = require('./generate-token'); -const googleSignIn = require('./google-sign-in'); -const resetPassword = require('./reset-password'); -const signIn = require('./sign-in'); -const signOut = require('./sign-out'); -const signUp = require('./sign-up'); - -const router = new express.Router(); - -router.get('/activate-account/:key', activateAccount); -router.post('/facebook', facebookSignIn); -router.post('/forgotten-password', forgottenPassword); -router.post('/google', googleSignIn); -router.put('/reset-password', resetPassword); -router.post('/sign-in', signIn); -router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); -router.post('/sign-up', signUp); -router.post('/token', generateToken); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const activateAccount = require('./activate-account'); +const facebookSignIn = require('./facebook-sign-in'); +const appleSignin = require('./apple-sign-in'); +const forgottenPassword = require('./forgotten-password'); +const generateToken = require('./generate-token'); +const googleSignIn = require('./google-sign-in'); +const reactivateAccount = require('./reactivate-account'); +const resetPassword = require('./reset-password'); +const signIn = require('./sign-in'); +const signOut = require('./sign-out'); +const signUp = require('./sign-up'); + +const router = new express.Router(); + +router.get('/activate-account/:key', activateAccount); +router.post('/facebook', facebookSignIn); +router.post('/apple', appleSignin); +router.post('/forgotten-password', forgottenPassword); +router.post('/google', googleSignIn); +router.post('/reactivate-account', reactivateAccount); +router.put('/reset-password', resetPassword); +router.post('/sign-in', signIn); +router.delete('/sign-out', isAuthenticated({ isOptional: false }), signOut); +router.post('/sign-up', signUp); +router.post('/token', generateToken); + +module.exports = router; diff --git a/src/routes/auth/reactivate-account.js b/src/routes/auth/reactivate-account.js new file mode 100644 index 0000000..85dd55d --- /dev/null +++ b/src/routes/auth/reactivate-account.js @@ -0,0 +1,152 @@ +const bcrypt = require("bcrypt-nodejs"); +const crypto = require("crypto"); + +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +/** + * Reactivate an archived user account + * Requires: userId, new password, and updated profile information + * Sets isArchived to false and updates lastLogin + */ +module.exports = async (req, res, next) => { + const { + userId, + password, + firstName, + lastName, + email, + disabilities, + gender, + zip, + phone, + showDisabilities, + showEmail, + showPhone, + aboutMe, + birthday, + race, + disability, + } = req.body; + + // Validation + if (!userId) { + return res.status(400).json({ general: "User ID is required" }); + } + + if (!password || password.length < 6) { + return res.status(400).json({ + password: "Password must be at least 6 characters" + }); + } + + if (!firstName || !lastName) { + return res.status(400).json({ + general: "First name and last name are required" + }); + } + + if (!email) { + return res.status(400).json({ email: "Email is required" }); + } + + // Find user + let user; + try { + user = await User.findById(userId); + } catch (err) { + console.log(`User with ID ${userId} failed to be found at reactivation.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: "User not found" }); + } + + if (!user.isArchived) { + return res.status(400).json({ + general: "Account is not archived" + }); + } + + // Hash new password + let hashedPassword; + try { + hashedPassword = await new Promise((resolve, reject) => { + bcrypt.genSalt(10, (saltErr, salt) => { + if (saltErr) return reject(saltErr); + + bcrypt.hash(password, salt, null, (hashErr, hash) => { + if (hashErr) return reject(hashErr); + resolve(hash); + }); + }); + }); + } catch (err) { + console.log("Failed to hash password during reactivation"); + return next(err); + } + + // Prepare update data + const updateData = { + hashedPassword, + firstName, + lastName, + email, + isArchived: false, + lastLogin: new Date(), + inactivityEmailSent: false, + inactivityEmailSentAt: null, + }; + + // Add optional fields if provided + if (disabilities !== undefined) updateData.disabilities = disabilities; + if (gender !== undefined) updateData.gender = gender; + if (zip !== undefined) updateData.zip = zip; + if (phone !== undefined) updateData.phone = phone; + if (showDisabilities !== undefined) updateData.showDisabilities = showDisabilities; + if (showEmail !== undefined) updateData.showEmail = showEmail; + if (showPhone !== undefined) updateData.showPhone = showPhone; + if (aboutMe !== undefined) updateData.aboutMe = aboutMe; + if (birthday !== undefined) updateData.birthday = birthday; + if (race !== undefined) updateData.race = race; + if (disability !== undefined) updateData.disability = disability; + + // Update user + try { + user = await User.findByIdAndUpdate(userId, updateData, { new: true }); + } catch (err) { + console.log(`Failed to reactivate user ${userId}`); + return next(err); + } + + // Generate tokens + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log(`Refresh Token for userId ${userId} failed to be created at reactivation.`); + return next(err); + } + + const token = jwt.sign({ userId }, process.env.JWT_SECRET, { + expiresIn: '30d', + }); + + return res.status(200).json({ + refreshToken: refreshToken.key, + token, + message: "Account reactivated successfully" + }); +}; diff --git a/src/routes/auth/reset-password.js b/src/routes/auth/reset-password.js index 5e69206..c1250b4 100644 --- a/src/routes/auth/reset-password.js +++ b/src/routes/auth/reset-password.js @@ -1,133 +1,132 @@ -const moment = require('moment'); - -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateResetPassword } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateResetPassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const key = req.body.key; - const password = req.body.password; - - let passwordTicket; - try { - passwordTicket = await PasswordTicket.findOne({ key }); - } catch (err) { - console.log( - `Password ticket with key ${key} failed to be found at reset-password.` - ); - return next(err); - } - - if (!passwordTicket) { - return res.status(404).json({ general: 'Password Ticket not found' }); - } - - const expiresAt = moment(passwordTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'Password Ticket expired' }); - } - - let user; - try { - user = await User.findOne({ - email: passwordTicket.email, - isArchived: false - }); - } catch (err) { - console.log( - `User with email ${ - passwordTicket.email - } failed to be found at reset-password.` - ); - return next(err); - } - - if (!user) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(400).json({ general: 'User not found' }); - } - - const passwordMatches = user.comparePassword(password); - if (passwordMatches) { - return res.status(400).json({ password: 'Is already used' }); - } - - user.password = password; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at reset-password.` - ); - return next(err); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${ - user.id - } failed to be found at reset-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with userId ${ - refreshToken.userId - } failed to be removed at reset-password.` - ); - return next(err); - } - } - - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password Ticket with key ${ - passwordTicket.key - } failed to be removed at reset-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require("moment"); + +const { PasswordTicket } = require("../../models/password-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateResetPassword } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateResetPassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const key = req.body.key; + const password = req.body.password; + + let passwordTicket; + try { + passwordTicket = await PasswordTicket.findOne({ key }); + } catch (err) { + console.log( + `Password ticket with key ${key} failed to be found at reset-password.` + ); + return next(err); + } + + if (!passwordTicket) { + return res.status(404).json({ general: "Password Ticket not found" }); + } + const expiresAt = moment(passwordTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await PasswordTicket.deleteOne({ key }); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: "Password Ticket expired" }); + } + let user; + try { + user = await User.findOne({ + email: passwordTicket.email, + isArchived: false, + }); + } catch (err) { + console.log( + `User with email ${ + passwordTicket.email + } failed to be found at reset-password.` + ); + return next(err); + } + + if (!user) { + try { + await PasswordTicket.deleteOne({ key }); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(400).json({ general: "User not found" }); + } + if (user?.hashedPassword) { + const passwordMatches = user.comparePassword(password); + if (passwordMatches) { + return res.status(400).json({ password: "Is already used" }); + } + } + + user.password = password; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at reset-password.` + ); + return next(err); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${ + user.id + } failed to be found at reset-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await RefreshToken.deleteOne({ userId: user.id }); + } catch (err) { + console.log( + `Refresh Token with userId ${ + refreshToken.userId + } failed to be removed at reset-password.` + ); + return next(err); + } + } + + try { + await PasswordTicket.deleteOne({ key }); + } catch (err) { + console.log( + `Password Ticket with key ${ + passwordTicket.key + } failed to be removed at reset-password.` + ); + return next(err); + } + + return res.status(200).json({ general: "Success" }); +}; diff --git a/src/routes/auth/sign-in.js b/src/routes/auth/sign-in.js index f0ac99d..3290057 100644 --- a/src/routes/auth/sign-in.js +++ b/src/routes/auth/sign-in.js @@ -1,69 +1,79 @@ -const crypto = require('crypto'); - -const jwt = require('jsonwebtoken'); -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateSignIn } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignIn(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const email = req.body.email; - const password = req.body.password; - - let user; - try { - user = await User.findOne({ email, isArchived: false }); - } catch (err) { - console.log(`User with email ${email} failed to be found at sign-in.`); - return next(err); - } - - if (!user) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - if (user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - if (!user.hashedPassword) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const passwordMatches = user.comparePassword(password); - - if (!passwordMatches) { - return res.status(400).json({ general: 'Email or password incorrect' }); - } - - const userId = user.id; - const today = moment.utc(); - const expiresAt = today.add(14, 'days').toDate(); - const key = `${userId}${crypto.randomBytes(28).toString('hex')}`; - - let refreshToken; - try { - refreshToken = await RefreshToken.findOneAndUpdate( - { userId }, - { expiresAt, key, userId }, - { new: true, setDefaultsOnInsert: true, upsert: true } - ); - } catch (err) { - console.log( - `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` - ); - return next(err); - } - - const token = jwt.sign({ userId }, process.env.JWT_SECRET, { - expiresIn: 36000 - }); - return res.status(200).json({ refreshToken: refreshToken.key, token }); -}; +const crypto = require("crypto"); + +const jwt = require("jsonwebtoken"); +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateSignIn } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateSignIn(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const email = req.body.email; + const password = req.body.password; + + let user; + try { + user = await User.findOne({ email, isArchived: false }); + console.log("User", user); + } catch (err) { + console.log(`User with email ${email} failed to be found at sign-in.`); + return next(err); + } + + if (!user) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + if (user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + if (!user.hashedPassword) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const passwordMatches = user.comparePassword(password); + + if (!passwordMatches) { + return res.status(400).json({ general: "Email or password incorrect" }); + } + + const userId = user.id; + + // Update lastLogin timestamp + try { + await User.findByIdAndUpdate(userId, { lastLogin: new Date() }); + } catch (updateErr) { + console.log(`Failed to update lastLogin for userId ${userId}: ${updateErr.message}`); + // Continue with login even if lastLogin update fails + } + + const today = moment.utc(); + const expiresAt = today.add(30, "days").toDate(); + const key = `${userId}${crypto.randomBytes(28).toString("hex")}`; + + let refreshToken; + try { + refreshToken = await RefreshToken.findOneAndUpdate( + { userId }, + { expiresAt, key, userId }, + { new: true, setDefaultsOnInsert: true, upsert: true } + ); + } catch (err) { + console.log( + `Refresh Token for userId ${userId} failed to be created or updated at sign-in.` + ); + return next(err); + } +console.log(process.env.JWT_SECRET) + const token = jwt.sign({ userId }, process.env.JWT_SECRET, { + expiresIn: '30d', + }); + return res.status(200).json({ refreshToken: refreshToken.key, token }); +}; diff --git a/src/routes/auth/sign-out.js b/src/routes/auth/sign-out.js index 075ef8d..57ada88 100644 --- a/src/routes/auth/sign-out.js +++ b/src/routes/auth/sign-out.js @@ -1,34 +1,34 @@ -const { RefreshToken } = require('../../models/refresh-token'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh token with userId ${req.user.id} failed to be found at sign-out.` - ); - return next(err); - } - - if (!refreshToken) { - return res.status(204).json({ general: 'Success' }); - } - - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with userId ${ - req.user.id - } failed to be deleted at sign-out.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { RefreshToken } = require("../../models/refresh-token"); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${req.user.id} failed to be found at sign-out.` + ); + return next(err); + } + + if (!refreshToken) { + return res.status(204).json({ general: "Success" }); + } + + try { + await RefreshToken.deleteOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh token with userId ${ + req.user.id + } failed to be deleted at sign-out.` + ); + return next(err); + } + + return res.status(204).json({ general: "Success" }); +}; diff --git a/src/routes/auth/sign-up.js b/src/routes/auth/sign-up.js index 8819b94..9845a13 100644 --- a/src/routes/auth/sign-up.js +++ b/src/routes/auth/sign-up.js @@ -1,158 +1,165 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { cleanSpaces, sendEmail } = require('../../helpers'); -const { User } = require('../../models/user'); - -const { validateSignUp } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateSignUp(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const data = pick(req.body, [ - 'email', - 'firstName', - 'isSubscribed', - 'lastName', - 'password' - ]); - data.firstName = cleanSpaces(data.firstName); - data.lastName = cleanSpaces(data.lastName); - data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; - - let activationTicket; - try { - activationTicket = await ActivationTicket.findOne({ email: data.email }); - } catch (err) { - console.log( - `Activation ticket with email ${ - data.email - } failed to be found at sign-up.` - ); - return next(err); - } - - if (activationTicket) { - const expiresAt = moment(activationTicket.expiresAt).utc(); - const today = moment.utc(); - if (expiresAt.isBefore(today)) { - try { - await activationTicket.remove(); - } catch (err) { - console.log( - `Activation ticket with email ${ - activationTicket.email - } failed to be removed at sign-up.` - ); - return next(err); - } - } - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: data.email }, { username: data.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at sign-up.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === data.email) { - return res.status(400).json({ email: 'Is already taken' }); - } - - let repeatedUser; - do { - data.username = `${slugify(data.firstName)}-${slugify( - data.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at sign-up.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === data.username); - } - } - - const today = moment.utc(); - const expiresAt = today.add(1, 'days').toDate(); - const key = `${crypto - .randomBytes(31) - .toString('hex')}${new Date().getTime().toString()}`; - - const activationTicketData = { - email: data.email, - expiresAt, - key, - userData: { - firstName: data.firstName, - isSubscribed: data.isSubscribed, - lastName: data.lastName, - password: data.password, - username: data.username - } - }; - try { - activationTicket = await ActivationTicket.create(activationTicketData); - } catch (err) { - console.log( - `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( - activationTicketData - )}` - ); - return next(err); - } - - const subject = 'Activate Account'; - const htmlContent = ` -

Welcome to AXS Map!

-

To activate your account use the link below:

-
- - ${process.env.API_URL}/auth/activate-account/${activationTicket.key} - -

-

Stay awesome.

- `; - const textContent = ` - Welcome to AXS Map! - To activate your account use the link below: - ${process.env.API_URL}/auth/activate-account/${activationTicket.key} - Stay awesome. - `; - const receiversEmails = [activationTicket.email]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(201).json({ general: 'Success' }); -}; +const crypto = require("crypto"); + +const moment = require("moment"); +const { pick } = require("lodash"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); + +const { ActivationTicket } = require("../../models/activation-ticket"); +const { cleanSpaces, sendEmail } = require("../../helpers"); +const { User } = require("../../models/user"); + +const { validateSignUp } = require("./validations"); +const { activationEmailTemplate } = require("../../helpers/mail-template"); + +module.exports = async (req, res, next) => { + + const { errors, isValid } = validateSignUp(req.body); + console.log(errors) + if (!isValid) { + return res.status(400).json({message:Object.entries(errors)[0][1]}); + } + + const data = pick(req.body, [ + "email", + "firstName", + "isSubscribed", + "lastName", + "password", + "aboutMe", + "dateOfBirth", + "disability", + "gender", + "race", + ]); + data.aboutMe = cleanSpaces(data.aboutMe ?? ""); + data.firstName = cleanSpaces(data.firstName); + data.lastName = cleanSpaces(data.lastName); + data.username = `${slugify(data.firstName)}-${slugify(data.lastName)}`; + + + let activationTicket; + try { + activationTicket = await ActivationTicket.findOne({ email: data.email }); + } catch (err) { + console.log( + `Activation ticket with email ${ + data.email + } failed to be found at sign-up.` + ); + return next(err); + } + + if (activationTicket) { + const expiresAt = moment(activationTicket.expiresAt).utc(); + const today = moment.utc(); + if (expiresAt.isBefore(today)) { + try { + await ActivationTicket.deleteOne({ _id: activationTicket._id }); + } catch (err) { + console.log( + `Activation ticket with email ${ + activationTicket.email + } failed to be removed at sign-up.` + ); + return next(err); + } + } + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: data.email }, { username: data.username }], + isArchived: false, + }); + } catch (err) { + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === data.email) { + return res.status(400).json({ message: "This email address is already in use. Please use forgot password to login." }); + } + + let repeatedUser; + do { + data.username = `${slugify(data?.firstName)}-${slugify( + data?.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: "lowercase", + })}`; + + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false, + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at sign-up.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === data.username); + } + } + + const today = moment.utc(); + const expiresAt = today.add(1, "days").toDate(); + const key = `${crypto + .randomBytes(31) + .toString("hex")}${new Date().getTime().toString()}`; + + const activationTicketData = { + email: data.email, + expiresAt, + key, + userData: { + firstName: data.firstName, + isSubscribed: data.isSubscribed, + lastName: data.lastName, + password: data.password, + username: data.username, + aboutMe: data.aboutMe || null, + dateOfBirth: data.dateOfBirth || null, + disability: data.disability || null, + gender: data.gender || null, + race: data?.race || '', + }, + }; + console.log(activationTicketData) + try { + activationTicket = await ActivationTicket.create(activationTicketData); + } catch (err) { + console.log( + `Activation ticket failed to be created at sign-up.\nData: ${JSON.stringify( + activationTicketData + )}` + ); + return next(err); + } + + const subject = "Activate Account"; + // TODO change base URL for ACTIVATION + const textContent = ` + Welcome to AXS Map! + To activate your account use the link below: + ${process.env.API_URL}/auth/activate-account/${activationTicket.key} + Stay awesome. + `; + const receiversEmails = [activationTicket.email]; + const activationLink = `https://axsmap.com/auth/activate-account/${activationTicket.key}`; + const name = `${activationTicket?.userData?.firstName ?? ""} ${activationTicket?.userData?.lastName ?? ""}`; + + sendEmail({ + subject, + htmlContent: activationEmailTemplate(activationLink, name), + textContent, + receiversEmails, + }); + + return res.status(201).json({ general: "Success" }); +}; diff --git a/src/routes/auth/validations.js b/src/routes/auth/validations.js index f8bb8f4..70ae01c 100644 --- a/src/routes/auth/validations.js +++ b/src/routes/auth/validations.js @@ -1,155 +1,178 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -const { cleanSpaces } = require('../../helpers'); - -module.exports = { - validateFacebookSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateForgottenPassword(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (!isEmail(data.email)) { - errors.email = 'Should be a valid email'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGenerateToken(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateGoogleSignIn(data) { - const errors = {}; - - if (!data.code) { - errors.code = 'Is required'; - } else if (typeof data.code !== 'string') { - errors.code = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateResetPassword(data) { - const errors = {}; - - if (!data.key) { - errors.key = 'Is required'; - } else if (typeof data.key !== 'string') { - errors.key = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignIn(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateSignUp(data) { - const errors = {}; - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (typeof data.isSubscribed === 'undefined') { - errors.isSubscribed = 'Is required'; - } else if (typeof data.isSubscribed !== 'boolean') { - errors.isSubscribed = 'Should be a boolean'; - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one surname'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require("freemail"); +const { isEmail } = require("validator"); +const { isEmpty } = require("lodash"); + +const { cleanSpaces } = require("../../helpers"); + +const { disability, race, genders } = require("../../helpers/constants"); + +module.exports = { + validateFacebookSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = "Is required"; + } else if (typeof data.code !== "string") { + errors.code = "Should be a string"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateAppleSignIn(data) { + const errors = {}; + + if (!data.identityToken) { + errors.identityToken = "Is required"; + } else if (typeof data.identityToken !== "string") { + errors.identityToken = "Should be a string"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateForgottenPassword(data) { + const errors = {}; + + if (!data.email) { + errors.email = "Is required"; + } else if (typeof data.email !== "string") { + errors.email = "Should be a string"; + } else if (!isEmail(data.email)) { + errors.email = "Should be a valid email"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGenerateToken(data) { + const errors = {}; + + if (!data.key) { + errors.key = "Is required"; + } else if (typeof data.key !== "string") { + errors.key = "Should be a string"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateGoogleSignIn(data) { + const errors = {}; + + if (!data.code) { + errors.code = "Is required"; + } else if (typeof data.code !== "string") { + errors.code = "Should be a string"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateResetPassword(data) { + const errors = {}; + + if (!data.key) { + errors.key = "Is required"; + } else if (typeof data.key !== "string") { + errors.key = "Should be a string"; + } + + if (!data.password) { + errors.password = "Is required"; + } else if (typeof data.password !== "string") { + errors.password = "Should be a string"; + } else if (data.password.length < 8) { + errors.password = "Should have more than 7 characters"; + } else if (data.password.length > 30) { + errors.password = "Should have less than 31 characters"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignIn(data) { + const errors = {}; + + if (!data.email) { + errors.email = "Is required"; + } else if (typeof data.email !== "string") { + errors.email = "Should be a string"; + } + + if (!data.password) { + errors.password = "Is required"; + } else if (typeof data.password !== "string") { + errors.password = "Should be a string"; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateSignUp(data) { + const errors = {}; + + if (!data.email) { + errors.email = "Is required"; + } else if (typeof data.email !== "string") { + errors.email = "Should be a string"; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = "Should have less than 255 characters"; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = "Should be a valid email"; + } + + if (!data.firstName) { + errors.firstName = "Is required"; + } else if (typeof data.firstName !== "string") { + errors.firstName = "Should be a string"; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = "Should only have letters"; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = "Should have less than 25 characters"; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(" ").length > 1) { + errors.firstName = "Should only be one name"; + } + } + + if (typeof data.isSubscribed === "undefined") { + errors.isSubscribed = "Is required"; + } else if (typeof data.isSubscribed !== "boolean") { + errors.isSubscribed = "Should be a boolean"; + } + + if (!data.lastName) { + errors.lastName = "Is required"; + } else if (typeof data.lastName !== "string") { + errors.lastName = "Should be a string"; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = "Should only have letters"; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = "Should have less than 37 characters"; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(" ").length > 1) { + errors.lastName = "Should only be one surname"; + } + } + + if (!data.password) { + errors.password = "Is required"; + } else if (typeof data.password !== "string") { + errors.password = "Should be a string"; + } else if (data.password.length < 8) { + errors.password = "Should have more than 7 characters"; + } else if (data.password.length > 30) { + errors.password = "Should have less than 31 characters"; + } + + // if (data.disability && !disability.includes(data.disability)) { + // errors.disability = "Please select a valid disability option"; + // } + // if (data.gender && !genders.includes(data.gender)) { + // errors.gender = "Please select a valid gender option"; + // } + // if (data.race && !race.includes(data.race)) { + // errors.race = "Please select a valid race option"; + // } + + return { errors, isValid: isEmpty(errors) }; + }, +}; diff --git a/src/routes/donatins/apple.webhook.js b/src/routes/donatins/apple.webhook.js new file mode 100644 index 0000000..0efbbc7 --- /dev/null +++ b/src/routes/donatins/apple.webhook.js @@ -0,0 +1,63 @@ +// services/apple.js +const axios = require("axios"); + +const APPLE_PROD = "https://buy.itunes.apple.com/verifyReceipt"; +const APPLE_SANDBOX = "https://sandbox.itunes.apple.com/verifyReceipt"; + +async function verifyAppleReceipt(base64Receipt) { + const body = { + "receipt-data": base64Receipt, + password: process.env.APPLE_SHARED_SECRET, + "exclude-old-transactions": true, + }; + + // Try production then fallback to sandbox on 21007 + + const tryVerify = async (url) => + (await axios.post(url, body, { timeout: 10000 })).data; + + let data = await tryVerify(APPLE_PROD); + if (data.status === 21007) data = await tryVerify(APPLE_SANDBOX); + + if (data.status !== 0) { + const err = new Error(`Apple verify failed: status ${data.status}`); + err.apple = data; + throw err; + } + return data; +} + +// Extract latest transaction for a given product (auto-renewing sub) +function pickLatestForProduct(receipt, productId) { + const items = (receipt.latest_receipt_info || []).filter( + (i) => i.product_id === productId + ); + if (!items.length) return null; + + // newest by expires date if present, else by purchase date + const sorted = items.sort((a, b) => { + const aExp = Number(a.expires_date_ms || 0); + const bExp = Number(b.expires_date_ms || 0); + return bExp - aExp; + }); + + const latest = sorted[0]; + const pending = (receipt.pending_renewal_info || []).find( + (p) => p.product_id === productId + ); + return { + transactionId: latest.transaction_id, + originalTransactionId: latest.original_transaction_id, + purchasedAt: new Date(Number(latest.purchase_date_ms)), + expiresAt: latest.expires_date_ms + ? new Date(Number(latest.expires_date_ms)) + : undefined, + willRenew: pending + ? pending.auto_renew_status === "1" + : Boolean(latest.expires_date_ms), + environment: receipt.environment?.toLowerCase() || "production", + raw: { latest, pending }, + }; +} + +module.exports = { verifyAppleReceipt, pickLatestForProduct }; diff --git a/src/routes/donatins/donation.js b/src/routes/donatins/donation.js new file mode 100644 index 0000000..ad16601 --- /dev/null +++ b/src/routes/donatins/donation.js @@ -0,0 +1,126 @@ +// services/apple.js +const axios = require("axios"); +const { Donations } = require("../../models/donations"); +const { sendEmail } = require("../../helpers"); +const { donationMailTemplate } = require("../../helpers/mail-template"); + +const APPLE_PROD = "https://buy.itunes.apple.com/verifyReceipt"; +const APPLE_SANDBOX = "https://sandbox.itunes.apple.com/verifyReceipt"; + +async function verifyAppleReceipt(receipt) { + const payload = { + "receipt-data": receipt, + password: process.env.APP_SHARED_SECRET, // only needed for subscriptions + "exclude-old-transactions": true, + }; + + try { + // let response = await axios.post("https://buy.itunes.apple.com/verifyReceipt", payload, { + // headers: { "Content-Type": "application/json" } + // }); + + response = await axios.post(APPLE_SANDBOX, payload, { + headers: { "Content-Type": "application/json" }, + }); + + return response.data; + } catch (err) { + console.error("Apple verification failed", err); + throw err; + } +} + +async function purchaseProduct(req, res) { + try { + const receipt = await verifyAppleReceipt(req.body.transactionReceipt); + if (receipt.status === 0 || receipt?.environment === "Sandbox") { + const alreadyExists = await Donations.findOne({ + userId: req.user.id, + transactionId: req.body.transactionId, + }); + if (alreadyExists) { + return res.status(400).json({ message: "Already purchased" }); + } + sendEmail({ + receiversEmails: [req.user?.email], + subject: + "Thank You for Supporting AXS Map – Here’s Your Exclusive Content", + htmlContent: donationMailTemplate({ + name: req.user?.firstName + " " + req.user?.lastName, + }), + }); + // if (receipt?.environment === "Sandbox") + // return res.status(400).json({ message: "Apple verification failed" }); + + const result = await Donations.create({ + userId: req.user.id, + amount: req.body.amount, + type: "one_time", + currency: req.body.currency, + productId: req.body.productId, + transactionId: req.body.transactionId, + receipt: req.body.transactionReceipt, + status: "purchased", + purchasedAt: req?.body?.transactionDate, + country: req?.body?.country, + platform: req?.body?.platform, + }); + return res.status(200).json({ result }); + } else { + return res.status(400).json({ message: "verification failed" }); + } + } catch (error) { + console.log(error); + res.status(400).json({ message: "Apple verification failed" }); + } +} + +async function purchaseSubscription(req, res) { + try { + const receipt = + req.body.platform === "ios" + ? await verifyAppleReceipt(req.body.transactionReceipt) + : { receipt: { status: 0 } }; + // if (receipt.status !== 0 || receipt?.environment !== "Sandbox") { + // return res.status(400).json({ message: "verification failed" }); + // } + const alreadyExists = await Donations.findOne({ + userId: req.user.id, + transactionId: req.body.transactionId, + }); + if (alreadyExists) { + return res.status(400).json({ message: "Already purchased" }); + } + sendEmail({ + receiversEmails: [req.user?.email], + subject: + "Thank You for Supporting AXS Map – Here’s Your Exclusive Content", + htmlContent: donationMailTemplate({ + name: req.user?.firstName + " " + req.user?.lastName, + }), + }); + // if (receipt?.environment === "Sandbox") + // return res.status(400).json({ message: "Apple verification failed" }); + + const result = await Donations.create({ + userId: req.user.id, + amount: req.body.amount, + type: "monthly", + currency: req.body.currency, + productId: req.body.productId, + transactionId: req.body.transactionId, + originalTransactionId: req.body?.originalTransactionIdentifierIOS, + receipt: req.body.transactionReceipt, + status: "purchased", + purchasedAt: req?.body?.transactionDate, + country: req?.body?.country, + platform: req?.body?.platform, + }); + return res.status(200).json({ result }); + } catch (error) { + console.log(error); + res.status(400).json({ message: "Apple verification failed" }); + } +} + +module.exports = { purchaseProduct, purchaseSubscription }; diff --git a/src/routes/donatins/google.webhook.js b/src/routes/donatins/google.webhook.js new file mode 100644 index 0000000..b0e7f62 --- /dev/null +++ b/src/routes/donatins/google.webhook.js @@ -0,0 +1,41 @@ +// services/google.js +const { google } = require('googleapis'); + +async function androidPublisher() { + const auth = new google.auth.GoogleAuth({ + scopes: ['https://www.googleapis.com/auth/androidpublisher'], + keyFile: process.env.GOOGLE_SERVICE_ACCOUNT_JSON, + }); + const client = await auth.getClient(); + return google.androidpublisher({ version: 'v3', auth: client }); +} + +async function verifyAndroidProduct(productId, purchaseToken) { + const api = await androidPublisher(); + const res = await api.purchases.products.get({ + packageName: process.env.GOOGLE_PACKAGE_NAME, + productId, + token: purchaseToken, + }); + return res.data; // purchaseState, consumptionState, orderId... +} + +async function verifyAndroidSubscription(productId, purchaseToken) { + const api = await androidPublisher(); + const res = await api.purchases.subscriptions.get({ + packageName: process.env.GOOGLE_PACKAGE_NAME, + subscriptionId: productId, + token: purchaseToken, + }); + return res.data; // expiryTimeMillis, autoRenewing, paymentState, cancelReason... +} + +function mapAndroidStatus(d) { + // subscriptions + const expiresAt = d.expiryTimeMillis ? new Date(Number(d.expiryTimeMillis)) : undefined; + const willRenew = Boolean(d.autoRenewing); + // purchaseState: 0 purchased, 1 canceled, 2 pending (for INAPP) + return { expiresAt, willRenew }; +} + +module.exports = { verifyAndroidProduct, verifyAndroidSubscription, mapAndroidStatus }; diff --git a/src/routes/donatins/index.js b/src/routes/donatins/index.js new file mode 100644 index 0000000..693721a --- /dev/null +++ b/src/routes/donatins/index.js @@ -0,0 +1,16 @@ +const express = require("express"); +const { purchaseProduct, purchaseSubscription } = require("./donation"); +const { isAuthenticated } = require("../../helpers"); + +const router = new express.Router(); + +router.post("/product", isAuthenticated({ isOptional: false }), purchaseProduct); +router.post( + "/subscription", + isAuthenticated({ isOptional: false }), + purchaseSubscription +); +// router.post("/apple-webhook", appleSignin); +// router.post("/google-webhook", appleSignin); + +module.exports = router; diff --git a/src/routes/events/create-event.js b/src/routes/events/create-event.js index 7b35bda..6712dc2 100644 --- a/src/routes/events/create-event.js +++ b/src/routes/events/create-event.js @@ -1,190 +1,173 @@ -const axios = require('axios'); -const FormData = require('form-data'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - address: req.body.address, - description: req.body.description, - donationAmounts: req.body.donationAmounts, - donationEnabled: req.body.donationEnabled, - donationGoal: req.body.donationGoal, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - name: req.body.name, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager - }; - - const { errors, isValid } = validateCreateEvent(data); - if (!isValid) return res.status(400).json(errors); - - data.address = cleanSpaces(data.address); - - data.endDate = moment(data.endDate) - .endOf('day') - .utc() - .toDate(); - - data.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]] - }; - delete data.locationCoordinates; - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Event ${data.name} failed to be found at create-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - if (data.poster) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at create-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - } - - data.startDate = moment(data.startDate) - .startOf('day') - .utc() - .toDate(); - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log( - `Team ${data.teamManager} failed to be found at create-event` - ); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - data.teamManager = undefined; - } - - if (data.donationEnabled) { - const campaignData = new FormData(); - campaignData.append('title', data.name); - campaignData.append('goal_in_cents', data.donationGoal * 100); - - let options = { - method: 'POST', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns`, - headers: { - 'Content-Type': `multipart/form-data; boundary=${ - campaignData._boundary - }` - }, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - }, - data: campaignData - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be created at create-event.'); - return next(err); - } - - data.donationId = response.data.campaign.id; - } - - let event; - try { - event = await Event.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Event failed to be created at create-event.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - id: event.id, - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(201).json(dataResponse); -}; +const axios = require("axios"); +const FormData = require("form-data"); +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { cleanSpaces } = require("../../helpers"); +const { Photo } = require("../../models/photo"); +const { Team } = require("../../models/team"); + +const { validateCreateEvent } = require("./validations"); +const { sendError } = require("../../helpers/Error"); + +module.exports = async (req, res, next) => { + const data = { + address: req.body.address, + description: req.body.description, + donationAmounts: req.body.donationAmounts, + donationEnabled: req.body.donationEnabled, + donationGoal: req.body.donationGoal, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + name: req.body.name, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager, + }; + + const { errors, isValid } = validateCreateEvent(data); + if (!isValid) return res.status(400).json(sendError(errors)); + + data.address = cleanSpaces(data.address); + + data.endDate = moment(data.endDate).endOf("day").toDate(); + data.startDate = moment(data.startDate).startOf("day").toDate(); + + data.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], + }; + delete data.locationCoordinates; + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + + if (data.poster) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at create-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json(sendError({ poster: "Not found" })); + } + } + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log( + `Team ${data.teamManager} failed to be found at create-event` + ); + return next(err); + } + + if (!team) { + return res.status(404).json(sendError({ teamManager: "Not found" })); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json(sendError({ general: "Forbidden action" })); + } + } else { + data.teamManager = undefined; + } + + if (data.donationEnabled) { + const campaignData = new FormData(); + campaignData.append("title", data.name); + campaignData.append("goal_in_cents", data.donationGoal * 100); + + let options = { + method: "POST", + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns`, + headers: { + "Content-Type": `multipart/form-data; boundary=${ + campaignData._boundary + }`, + }, + auth: { + username: process.env.DONATELY_TOKEN, + password: "", + }, + data: campaignData, + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log("Donation campaign failed to be created at create-event."); + return next(err); + } + + data.donationId = response.data.campaign.id; + } + + let event; + try { + event = await Event.create(data); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Event failed to be created at create-event.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0], + }; + } + const dataResponse = { + id: event.id, + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager, + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/events/delete-event.js b/src/routes/events/delete-event.js index 17842f1..ec69388 100644 --- a/src/routes/events/delete-event.js +++ b/src/routes/events/delete-event.js @@ -1,130 +1,130 @@ -const aws = require('aws-sdk'); -const { last } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const s3 = new aws.S3(); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - console.log(`Event ${eventId} failed to be found at delete-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if ( - !event.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today) && event.reviews > 0) { - return res.status(423).json({ - general: - 'It cannot be removed because it already ended and has one or more reviews' - }); - } - - const participantsPromises = event.participants.map(p => - User.findOne({ _id: p.toString() }) - ); - - let participants; - try { - participants = await Promise.all(participantsPromises); - } catch (err) { - console.log('A participant failed to be found at delete-event'); - return next(err); - } - - for (const participant of participants) { - participant.events = participant.events.filter( - e => e.toString() !== event.id - ); - participant.updatedAt = moment.utc().toDate(); - - try { - await participant.save(); - } catch (err) { - console.log( - `Participant ${participant.id} failed to be updated at delete-event` - ); - return next(err); - } - } - - if (event.photos && event.photos.length > 0) { - for (const photo of event.photos) { - const photoParams = { - Bucket: process.env.AWS_S3_BUCKET, - Key: `events/photos/${last(photo.url.split('/'))}` - }; - - try { - await s3.deleteObject(photoParams).promise(); - } catch (err) { - console.log( - `Photo ${photoParams.Key} failed to be deleted at delete-event` - ); - return next(err); - } - } - } - - if (event.teams && event.teams.length > 0) { - const teamsPromises = event.teams.map(t => - Team.findOne({ _id: t.toString() }) - ); - - let teams; - try { - teams = await Promise.all(teamsPromises); - } catch (err) { - console.log('A team failed to be found at delete-event'); - return next(err); - } - - for (const team of teams) { - team.events = team.events.filter(e => e.toString() !== event.id); - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-event`); - return next(err); - } - } - } - - try { - await event.remove(); - } catch (err) { - console.log(`Event ${event.id} failed to be removed at delete-event`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require("aws-sdk"); +const { last } = require("lodash"); +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); + +const s3 = new aws.S3(); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Event not found" }); + } + console.log(`Event ${eventId} failed to be found at delete-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: "Event not found" }); + } + + if ( + !event.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: "Forbidden action" }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today) && event.reviews > 0) { + return res.status(423).json({ + general: + "It cannot be removed because it already ended and has one or more reviews", + }); + } + + const participantsPromises = event.participants.map((p) => + User.findOne({ _id: p.toString() }) + ); + + let participants; + try { + participants = await Promise.all(participantsPromises); + } catch (err) { + console.log("A participant failed to be found at delete-event"); + return next(err); + } + + for (const participant of participants) { + participant.events = participant.events.filter( + (e) => e.toString() !== event.id + ); + participant.updatedAt = moment.utc().toDate(); + + try { + await participant.save(); + } catch (err) { + console.log( + `Participant ${participant.id} failed to be updated at delete-event` + ); + return next(err); + } + } + + if (event.photos && event.photos.length > 0) { + for (const photo of event.photos) { + const photoParams = { + Bucket: process.env.AWS_S3_BUCKET, + Key: `events/photos/${last(photo.url.split("/"))}`, + }; + + try { + await s3.deleteObject(photoParams).promise(); + } catch (err) { + console.log( + `Photo ${photoParams.Key} failed to be deleted at delete-event` + ); + return next(err); + } + } + } + + if (event.teams && event.teams.length > 0) { + const teamsPromises = event.teams.map((t) => + Team.findOne({ _id: t.toString() }) + ); + + let teams; + try { + teams = await Promise.all(teamsPromises); + } catch (err) { + console.log("A team failed to be found at delete-event"); + return next(err); + } + + for (const team of teams) { + team.events = team.events.filter((e) => e.toString() !== event.id); + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-event`); + return next(err); + } + } + } + + try { + await Event.deleteOne({ _id: eventId }); + } catch (err) { + console.log(`Event ${event.id} failed to be removed at delete-event`); + return next(err); + } + + return res.status(204).json({ general: "Success" }); +}; diff --git a/src/routes/events/edit-event.js b/src/routes/events/edit-event.js index 29368ab..96aa7e2 100644 --- a/src/routes/events/edit-event.js +++ b/src/routes/events/edit-event.js @@ -1,387 +1,377 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditEvent } = require('./validations'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at edit-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - address: req.body.address, - description: req.body.description, - endDate: req.body.endDate, - isOpen: req.body.isOpen, - locationCoordinates: req.body.locationCoordinates, - managers: req.body.managers, - name: req.body.name, - participants: req.body.participants, - participantsGoal: req.body.participantsGoal, - poster: req.body.poster, - reviewsGoal: req.body.reviewsGoal, - startDate: req.body.startDate, - teamManager: req.body.teamManager, - teams: req.body.teams - }; - - const { errors, isValid } = validateEditEvent(data); - if (!isValid) return res.status(400).json(errors); - - event.address = data.address ? cleanSpaces(data.address) : event.address; - event.description = data.description || event.description; - - if (data.endDate) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(event.startDate) - .startOf('day') - .utc(); - - if (!data.startDate) { - if (endDate.isBefore(startDate)) { - return res.status(400).json({ - endDate: 'Should be equal to or greater than startDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - endDate: 'Should last less than 365 days from startDate' - }); - } - } - - event.endDate = endDate.toDate(); - } - - event.isOpen = - typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; - - if (data.locationCoordinates && data.locationCoordinates.length > 0) { - event.location = { - coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], - type: 'Point' - }; - } - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const eventManagers = event.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; - if (managersToAdd.length > 0) { - const eventParticipants = event.participants.map(p => p.toString()); - const notParticipant = managersToAdd.find( - m => !eventParticipants.includes(m) - ); - - if (notParticipant) { - return res.status(400).json({ - managers: `User ${notParticipant} is not a participant of this event` - }); - } - - event.managers = [...eventManagers, ...managersToAdd]; - event.participants = event.participants.filter( - p => !managersToAdd.includes(p.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, eventManagers)) - ]; - if (managersToRemove.length === event.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - event.managers = event.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const eventParticipants = event.participants.map(p => p.toString()); - event.participants = [...eventParticipants, ...managersToRemove]; - } - - if (data.name) { - const eventName = cleanSpaces(data.name); - - if (eventName !== event.name) { - let repeatedEvent; - try { - repeatedEvent = await Event.findOne({ - name: eventName, - isArchived: false - }); - } catch (err) { - console.log(`Event ${eventName} failed to be found at edit-event`); - return next(err); - } - - if (repeatedEvent) { - return res.status(400).json({ name: 'Is already taken' }); - } - - event.name = eventName; - } - } - - if (data.participants) { - const eventParticipants = event.participants.map(p => p.toString()); - let participantsToRemove = data.participants.map(p => p.substring(1)); - participantsToRemove = [ - ...new Set(intersection(participantsToRemove, eventParticipants)) - ]; - - const getParticipants = participantsToRemove.map(p => - User.find({ _id: p, isArchived: false }) - ); - let participants; - try { - participants = await Promise.all(getParticipants); - } catch (err) { - console.log('Participants failed to be found at edit-event'); - return next(err); - } - - const updateParticipants = participants.map((p, i) => { - p[i].events = p[i].events.filter(e => e.toString() !== event.id); - return p[i].save(); - }); - - try { - await Promise.all(updateParticipants); - } catch (err) { - console.log('Participants failed to be updated at edit-event'); - return next(err); - } - - event.participants = event.participants.filter( - p => !participantsToRemove.includes(p.toString()) - ); - } - - event.participantsGoal = data.participantsGoal || event.participantsGoal; - - if ( - data.poster && - !data.poster.includes('default') && - data.poster !== event.poster - ) { - let poster; - try { - poster = await Photo.findOne({ url: data.poster }); - } catch (err) { - console.log(`Poster ${data.poster} failed to be found at edit-event`); - return next(err); - } - - if (!poster) { - return res.status(404).json({ poster: 'Not found' }); - } - - event.poster = data.poster; - } else if (data.poster === '') { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - - event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; - - if (data.startDate) { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const endDate = moment(event.endDate) - .endOf('day') - .utc(); - - if (!data.endDate) { - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - return res.status(400).json({ - startDate: 'Should be equal to or greater than the current time' - }); - } else if (startDate.isAfter(endDate)) { - return res.status(400).json({ - startDate: 'Should be equal to or less than endDate' - }); - } else if (endDate.diff(startDate, 'days') > 365) { - return res.status(400).json({ - startDate: 'Should last less than 365 days to endDate' - }); - } - } - - event.startDate = startDate.toDate(); - } - - if (data.teamManager) { - let team; - try { - team = await Team.findOne({ _id: data.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${data.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = data.teamManager; - - team.events = [...new Set([...team.events, event.id])]; - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } else if (data.teamManager === '' && event.teamManager) { - let team; - try { - team = await Team.findOne({ _id: event.teamManager, isArchived: false }); - } catch (err) { - console.log(`Team ${event.teamManager} failed to be found at edit-event`); - return next(err); - } - - if (!team) { - return res.status(404).json({ teamManager: 'Not found' }); - } - - const teamManagers = team.managers.map(m => m.toString()); - if (!teamManagers.includes(req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - event.teamManager = null; - - team.events = team.events.filter(e => e.toString() !== event.id); - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at edit-event`); - return next(err); - } - } - - if (data.teams) { - const eventTeams = event.teams.map(t => t.toString()); - let teamsToRemove = data.teams.map(t => t.substring(1)); - teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; - - const getTeams = teamsToRemove.map(t => - Team.find({ _id: t, isArchived: false }) - ); - let teams; - try { - teams = await Promise.all(getTeams); - } catch (err) { - console.log('Teams failed to be found at edit-event'); - return next(err); - } - - const updateTeams = teams.map((t, i) => { - t[i].events = t[i].events.filter(e => e.toString() !== event.id); - return t[i].save(); - }); - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log('Teams failed to be updated at edit-event'); - return next(err); - } - - event.teams = event.teams.filter( - t => !teamsToRemove.includes(t.toString()) - ); - } - - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Event ${event.id} failed to be updated at edit-event`); - return next(err); - } - - let eventLocation; - if (event.location.coordinates) { - eventLocation = { - lat: event.location.coordinates[1], - lng: event.location.coordinates[0] - }; - } - const dataResponse = { - address: event.address, - description: event.description, - endDate: event.description, - isOpen: event.isOpen, - location: eventLocation, - managers: event.managers, - name: event.name, - participantsGoal: event.participantsGoal, - poster: event.poster, - reviewsGoal: event.reviewsGoal, - teamManager: event.teamManager - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { Event } = require('../../models/event'); +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditEvent } = require('./validations'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at edit-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + address: req.body.address, + description: req.body.description, + endDate: req.body.endDate, + isOpen: req.body.isOpen, + locationCoordinates: req.body.locationCoordinates, + managers: req.body.managers, + name: req.body.name, + participants: req.body.participants, + participantsGoal: req.body.participantsGoal, + poster: req.body.poster, + reviewsGoal: req.body.reviewsGoal, + startDate: req.body.startDate, + teamManager: req.body.teamManager, + teams: req.body.teams + }; + + const { errors, isValid } = validateEditEvent(data); + if (!isValid) return res.status(400).json(errors); + + event.address = data.address ? cleanSpaces(data.address) : event.address; + event.description = data.description || event.description; + + if (data.endDate) { + const endDate = moment(data.endDate).endOf('day').utc(); + const startDate = moment(event.startDate).startOf('day').utc(); + + if (!data.startDate) { + if (endDate.isBefore(startDate)) { + return res.status(400).json({ + endDate: 'Should be equal to or greater than startDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + endDate: 'Should last less than 365 days from startDate' + }); + } + } + + event.endDate = endDate.toDate(); + } + + event.isOpen = + typeof data.isOpen !== 'undefined' ? data.isOpen : event.isOpen; + + if (data.locationCoordinates && data.locationCoordinates.length > 0) { + event.location = { + coordinates: [data.locationCoordinates[1], data.locationCoordinates[0]], + type: 'Point' + }; + } + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const eventManagers = event.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, eventManagers))]; + if (managersToAdd.length > 0) { + const eventParticipants = event.participants.map((p) => p.toString()); + const notParticipant = managersToAdd.find( + (m) => !eventParticipants.includes(m) + ); + + if (notParticipant) { + return res.status(400).json({ + managers: `User ${notParticipant} is not a participant of this event` + }); + } + + event.managers = [...eventManagers, ...managersToAdd]; + event.participants = event.participants.filter( + (p) => !managersToAdd.includes(p.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, eventManagers)) + ]; + if (managersToRemove.length === event.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + event.managers = event.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const eventParticipants = event.participants.map((p) => p.toString()); + event.participants = [...eventParticipants, ...managersToRemove]; + } + + if (data.name) { + const eventName = cleanSpaces(data.name); + + if (eventName !== event.name) { + let repeatedEvent; + try { + repeatedEvent = await Event.findOne({ + name: eventName, + isArchived: false + }); + } catch (err) { + console.log(`Event ${eventName} failed to be found at edit-event`); + return next(err); + } + + if (repeatedEvent) { + return res.status(400).json({ name: 'Is already taken' }); + } + + event.name = eventName; + } + } + + if (data.participants) { + const eventParticipants = event.participants.map((p) => p.toString()); + let participantsToRemove = data.participants.map((p) => p.substring(1)); + participantsToRemove = [ + ...new Set(intersection(participantsToRemove, eventParticipants)) + ]; + + const getParticipants = participantsToRemove.map((p) => + User.find({ _id: p, isArchived: false }) + ); + let participants; + try { + participants = await Promise.all(getParticipants); + } catch (err) { + console.log('Participants failed to be found at edit-event'); + return next(err); + } + + const updateParticipants = participants.map((p, i) => { + p[i].events = p[i].events.filter((e) => e.toString() !== event.id); + return p[i].save(); + }); + + try { + await Promise.all(updateParticipants); + } catch (err) { + console.log('Participants failed to be updated at edit-event'); + return next(err); + } + + event.participants = event.participants.filter( + (p) => !participantsToRemove.includes(p.toString()) + ); + } + + event.participantsGoal = data.participantsGoal || event.participantsGoal; + + if ( + data.poster && + !data.poster.includes('default') && + data.poster !== event.poster + ) { + let poster; + try { + poster = await Photo.findOne({ url: data.poster }); + } catch (err) { + console.log(`Poster ${data.poster} failed to be found at edit-event`); + return next(err); + } + + if (!poster) { + return res.status(404).json({ poster: 'Not found' }); + } + + event.poster = data.poster; + } else if (data.poster === '') { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + + event.reviewsGoal = data.reviewsGoal || event.reviewsGoal; + + if (data.startDate) { + const startDate = moment(data.startDate).startOf('day').utc(); + const endDate = moment(event.endDate).endOf('day').utc(); + + if (!data.endDate) { + const today = moment().startOf('day').utc(); + + if (startDate.isBefore(today)) { + return res.status(400).json({ + startDate: 'Should be equal to or greater than the current time' + }); + } else if (startDate.isAfter(endDate)) { + return res.status(400).json({ + startDate: 'Should be equal to or less than endDate' + }); + } else if (endDate.diff(startDate, 'days') > 365) { + return res.status(400).json({ + startDate: 'Should last less than 365 days to endDate' + }); + } + } + + event.startDate = startDate.toDate(); + } + + if (data.teamManager) { + let team; + try { + team = await Team.findOne({ _id: data.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${data.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = data.teamManager; + + team.events = [...new Set([...team.events, event.id])]; + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } else if (data.teamManager === '' && event.teamManager) { + let team; + try { + team = await Team.findOne({ _id: event.teamManager, isArchived: false }); + } catch (err) { + console.log(`Team ${event.teamManager} failed to be found at edit-event`); + return next(err); + } + + if (!team) { + return res.status(404).json({ teamManager: 'Not found' }); + } + + const teamManagers = team.managers.map((m) => m.toString()); + if (!teamManagers.includes(req.user.id)) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + event.teamManager = null; + + team.events = team.events.filter((e) => e.toString() !== event.id); + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at edit-event`); + return next(err); + } + } + + if (data.teams) { + const eventTeams = event.teams.map((t) => t.toString()); + let teamsToRemove = data.teams.map((t) => t.substring(1)); + teamsToRemove = [...new Set(intersection(teamsToRemove, eventTeams))]; + + const getTeams = teamsToRemove.map((t) => + Team.find({ _id: t, isArchived: false }) + ); + let teams; + try { + teams = await Promise.all(getTeams); + } catch (err) { + console.log('Teams failed to be found at edit-event'); + return next(err); + } + + const updateTeams = teams.map((t, i) => { + t[i].events = t[i].events.filter((e) => e.toString() !== event.id); + return t[i].save(); + }); + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log('Teams failed to be updated at edit-event'); + return next(err); + } + + event.teams = event.teams.filter( + (t) => !teamsToRemove.includes(t.toString()) + ); + } + + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Event ${event.id} failed to be updated at edit-event`); + return next(err); + } + + let eventLocation; + if (event.location.coordinates) { + eventLocation = { + lat: event.location.coordinates[1], + lng: event.location.coordinates[0] + }; + } + const dataResponse = { + address: event.address, + description: event.description, + endDate: event.description, + isOpen: event.isOpen, + location: eventLocation, + managers: event.managers, + name: event.name, + participantsGoal: event.participantsGoal, + poster: event.poster, + reviewsGoal: event.reviewsGoal, + teamManager: event.teamManager + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/get-event.js b/src/routes/events/get-event.js index eb8bd3a..c07a89d 100644 --- a/src/routes/events/get-event.js +++ b/src/routes/events/get-event.js @@ -1,207 +1,207 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); -const { isMongoId } = require('validator'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - let eventId = req.params.eventId; - if (!isMongoId(eventId)) { - return res.status(400).json({ general: 'Event not found' }); - } - eventId = mongoose.Types.ObjectId(eventId); - - let event; - try { - event = await Event.aggregate([ - { - $match: { _id: eventId } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'users', - let: { participants: '$participants' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$participants'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'participants' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'teams', - let: { teamManager: '$teamManager' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$teamManager'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teamManager' - } - }, - { - $unwind: { - path: '$teamManager', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'events', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - donationAmounts: 1, - donationId: 1, - endDate: 1, - isOpen: 1, - location: 1, - managers: 1, - name: 1, - participants: 1, - participantsGoal: 1, - poster: 1, - ranking: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1, - teamManager: 1, - teams: 1 - } - } - ]); - } catch (err) { - console.log(`Event ${eventId} failed to be found at get-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const dataResponse = Object.assign({}, event[0], { - ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 - }); - - if (dataResponse.donationId) { - let options = { - method: 'GET', - url: `https://${ - process.env.DONATELY_SUBDOMAIN - }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, - auth: { - username: process.env.DONATELY_TOKEN, - password: '' - } - }; - - let response; - try { - response = await axios(options); - } catch (err) { - console.log('Donation campaign failed to be found at get-event.'); - return next(err); - } - - dataResponse.donationAmountRaised = response.data.campaign.amount_raised; - dataResponse.donationDonorsCount = response.data.campaign.donors_count; - dataResponse.donationGoal = response.data.campaign.campaign_goal; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const mongoose = require('mongoose'); +const { isMongoId } = require('validator'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + let eventId = req.params.eventId; + if (!isMongoId(eventId)) { + return res.status(400).json({ general: 'Event not found' }); + } + eventId = new mongoose.Types.ObjectId(eventId); + + let event; + try { + event = await Event.aggregate([ + { + $match: { _id: eventId } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'users', + let: { participants: '$participants' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$participants'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'participants' + } + }, + { + $lookup: { + from: 'teams', + let: { teams: '$teams' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$teams'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teams' + } + }, + { + $lookup: { + from: 'teams', + let: { teamManager: '$teamManager' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$teamManager'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'teamManager' + } + }, + { + $unwind: { + path: '$teamManager', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'events', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + donationAmounts: 1, + donationId: 1, + endDate: 1, + isOpen: 1, + location: 1, + managers: 1, + name: 1, + participants: 1, + participantsGoal: 1, + poster: 1, + ranking: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + teamManager: 1, + teams: 1 + } + } + ]); + } catch (err) { + console.log(`Event ${eventId} failed to be found at get-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const dataResponse = Object.assign({}, event[0], { + ranking: event[0].ranking.length ? event[0].ranking[0].ranking + 1 : 1 + }); + + if (dataResponse.donationId) { + let options = { + method: 'GET', + url: `https://${ + process.env.DONATELY_SUBDOMAIN + }.dntly.com/api/v1/admin/campaigns/${dataResponse.donationId}`, + auth: { + username: process.env.DONATELY_TOKEN, + password: '' + } + }; + + let response; + try { + response = await axios(options); + } catch (err) { + console.log('Donation campaign failed to be found at get-event.'); + return next(err); + } + + dataResponse.donationAmountRaised = response.data.campaign.amount_raised; + dataResponse.donationDonorsCount = response.data.campaign.donors_count; + dataResponse.donationGoal = response.data.campaign.campaign_goal; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/events/index.js b/src/routes/events/index.js index fbbe43d..600d8f6 100644 --- a/src/routes/events/index.js +++ b/src/routes/events/index.js @@ -1,31 +1,37 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createEvent = require('./create-event'); -const deleteEvent = require('./delete-event'); -const editEvent = require('./edit-event'); -const getEvent = require('./get-event'); -const leaveEvent = require('./leave-event'); -const listEvents = require('./list-events'); -const joinEvent = require('./join-event'); - -const router = new express.Router(); - -router.get('', listEvents); -router.post('', isAuthenticated({ isOptional: false }), createEvent); -router.get('/:eventId', getEvent); -router.put('/:eventId', isAuthenticated({ isOptional: false }), editEvent); -router.delete('/:eventId', isAuthenticated({ isOptional: false }), deleteEvent); -router.post( - '/:eventId/join', - isAuthenticated({ isOptional: false }), - joinEvent -); -router.put( - '/:eventId/leave', - isAuthenticated({ isOptional: false }), - leaveEvent -); - -module.exports = router; +const express = require("express"); + +const { isAuthenticated } = require("../../helpers"); + +const createEvent = require("./create-event"); +const deleteEvent = require("./delete-event"); +const editEvent = require("./edit-event"); +const getEvent = require("./get-event"); +const leaveEvent = require("./leave-event"); +const listEvents = require("./list-events"); +const listOldEvents = require("./list-old-events"); +const joinEvent = require("./join-event"); +const listUpcoimgEvents = require("./list-upcoimg-events"); +const JoinedEvents = require("./joined-events"); + +const router = new express.Router(); + +router.get("", listEvents); +router.get("/joinedEvents", JoinedEvents); +router.get("/old", isAuthenticated({ isOptional: false }), listOldEvents); +router.get("/upComing", listUpcoimgEvents); +router.post("", isAuthenticated({ isOptional: false }), createEvent); +router.get("/:eventId", getEvent); +router.put("/:eventId", isAuthenticated({ isOptional: false }), editEvent); +router.delete("/:eventId", isAuthenticated({ isOptional: false }), deleteEvent); +router.post( + "/:eventId/join", + isAuthenticated({ isOptional: false }), + joinEvent +); +router.put( + "/:eventId/leave", + isAuthenticated({ isOptional: false }), + leaveEvent +); + +module.exports = router; diff --git a/src/routes/events/join-event.js b/src/routes/events/join-event.js index 91b4f1e..6251641 100644 --- a/src/routes/events/join-event.js +++ b/src/routes/events/join-event.js @@ -1,134 +1,153 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at join-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const eventParticipants = event.participants.map(p => p.toString()); - if (eventParticipants.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - const eventManagers = event.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a participant in this event' }); - } - - if (event.isOpen) { - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at join-event`); - return next(err); - } - - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at join-event`); - return next(err); - } - - return res.status(200).json({ general: 'Joined' }); - } else { - let petition; - try { - petition = await Petition.findOne({ - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to event ${ - event.id - } failed to be found at join-event` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at join-event` - ); - return next(err); - } - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (endDate.isBefore(today)) { - return res - .status(423) - .json({ general: 'This event has already finished' }); - } - - const petitionData = { - event: event.id, - sender: req.user.id, - type: 'request-user-event' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-event.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); - } -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Event not found" }); + } + return next(err); + } + + if (!event) { + return res.status(404).json({ general: "Event not found" }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today)) { + return res + .status(423) + .json({ general: "This event has already finished" }); + } + + const eventParticipants = event.participants.map((p) => p.toString()); + if (eventParticipants.includes(req.user.id)) { + return res + .status(400) + .json({ general: "You already are a participant in this event" }); + } + + const eventManagers = event.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: "You already are a participant in this event" }); + } + + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at join-event`); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at join-event`); + return next(err); + } + + + return res.status(200).json({ general: "Joined" }); + + if (true || event.isOpen) { + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + + + return res.status(200).json({ general: "Joined" }); + } else { + let petition; + try { + petition = await Petition.findOne({ + event: event.id, + sender: req.user.id, + type: "request-user-event", + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to event ${ + event.id + } failed to be found at join-event` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "You already have a pending petition with this event", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + event: event.id, + sender: req.user.id, + type: "request-user-event", + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at join-event` + ); + return next(err); + } + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (endDate.isBefore(today)) { + return res + .status(423) + .json({ general: "This event has already finished" }); + } + + const petitionData = { + event: event.id, + sender: req.user.id, + type: "request-user-event", + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-event.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: "Requested" }); + } +}; diff --git a/src/routes/events/joined-events.js b/src/routes/events/joined-events.js new file mode 100644 index 0000000..346f70b --- /dev/null +++ b/src/routes/events/joined-events.js @@ -0,0 +1,58 @@ +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const jwt = require("jsonwebtoken"); + +module.exports = async (req, res) => { + const authHeader = req.headers.authorization; + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return res + .status(401) + .json({ message: "Authorization token missing or invalid" }); + } + + const token = authHeader.split(" ")[1]; + + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const userId = decoded.userId; + + const eventsQuery = {}; + const currentDate = moment().startOf("day").utc().toDate(); + + eventsQuery.startDate = { $lte: currentDate }; + eventsQuery.endDate = { $gte: currentDate }; + eventsQuery.$or = [{ managers: userId }, { participants: userId }]; + + const queryParams = req.query; + const isTest = + typeof queryParams.isTest === "boolean" + ? queryParams.isTest + : queryParams.isTest?.toLowerCase?.() === "true"; + + if (!isTest) { + eventsQuery.name = { + $not: /t[\W_0-9]*e[\W_0-9]*s[\W_0-9]*t/i, + }; + } + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate().match(eventsQuery).project({ + _id: 0, + id: "$_id", + name: 1, + description: 1, + }), + Event.countDocuments(eventsQuery), + ]); + + return res.status(200).json({ + total, + results: events, + }); + } catch (err) { + return res.status(400).json({ err }); + } +}; diff --git a/src/routes/events/leave-event.js b/src/routes/events/leave-event.js index 5b4e0fd..17dc445 100644 --- a/src/routes/events/leave-event.js +++ b/src/routes/events/leave-event.js @@ -1,69 +1,69 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const eventId = req.params.eventId; - - let event; - try { - event = await Event.findOne({ _id: eventId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Event not found' }); - } - - console.log(`Event ${eventId} failed to be found at leave-event`); - return next(err); - } - - if (!event) { - return res.status(404).json({ general: 'Event not found' }); - } - - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - - if (endDate.isBefore(today)) { - return res.status(400).json({ - general: 'You cannot leave because it already ended' - }); - } - - if (event.managers.find(m => m.toString() === req.user.id)) { - event.managers = event.managers.filter(m => m.toString() !== req.user.id); - - if (event.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (event.participants.find(p => p.toString() === req.user.id)) { - event.participants = event.participants.filter( - p => p.toString() !== req.user.id - ); - } else { - return res.status(400).json({ general: 'You are not a participant' }); - } - - event.updatedAt = today.toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at leave-event`); - return next(err); - } - - req.user.events = req.user.events.filter(e => e.toString() !== event.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-event`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const eventId = req.params.eventId; + + let event; + try { + event = await Event.findOne({ _id: eventId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Event not found' }); + } + + console.log(`Event ${eventId} failed to be found at leave-event`); + return next(err); + } + + if (!event) { + return res.status(404).json({ general: 'Event not found' }); + } + + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + + if (endDate.isBefore(today)) { + return res.status(400).json({ + general: 'You cannot leave because it already ended' + }); + } + + if (event.managers.find((m) => m.toString() === req.user.id)) { + event.managers = event.managers.filter((m) => m.toString() !== req.user.id); + + if (event.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (event.participants.find((p) => p.toString() === req.user.id)) { + event.participants = event.participants.filter( + (p) => p.toString() !== req.user.id + ); + } else { + return res.status(400).json({ general: 'You are not a participant' }); + } + + event.updatedAt = today.toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at leave-event`); + return next(err); + } + + req.user.events = req.user.events.filter((e) => e.toString() !== event.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-event`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/events/list-events.js b/src/routes/events/list-events.js index 9521d85..faafab5 100644 --- a/src/routes/events/list-events.js +++ b/src/routes/events/list-events.js @@ -1,95 +1,90 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); - -const { validateListEvents } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListEvents(queryParams); - if (!isValid) return res.status(400).json(errors); - - const eventsQuery = {}; - - if (queryParams.keywords) { - eventsQuery.$text = { $search: queryParams.keywords }; - } - - eventsQuery.isArchived = false; - - let afterDate; - let beforeDate; - if (queryParams.afterDate && queryParams.beforeDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - - eventsQuery.startDate = { $gte: afterDate, $lte: beforeDate }; - } else if (queryParams.afterDate) { - afterDate = moment(queryParams.afterDate) - .utc() - .toDate(); - eventsQuery.startDate = { $gte: afterDate }; - } else if (queryParams.beforeDate) { - beforeDate = moment(queryParams.beforeDate) - .utc() - .toDate(); - eventsQuery.startDate = { $lte: beforeDate }; - } - - let sortBy = queryParams.sortBy || '-startDate'; - let page = queryParams.page ? queryParams.page - 1 : 0; - const pageLimit = queryParams.pageLimit || 12; - - let events; - let total; - try { - [events, total] = await Promise.all([ - Event.aggregate() - .match(eventsQuery) - .project({ - _id: 0, - id: '$_id', - address: 1, - endDate: 1, - name: 1, - poster: 1, - reviewsAmount: 1, - reviewsGoal: 1, - startDate: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Event.find(eventsQuery).count() - ]); - } catch (err) { - console.log('Events failed to be found or count at list-events'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: events - }); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) { + return res.status(400).json(errors); + } + + const eventsQuery = {}; + + if (queryParams.keywords && queryParams.keywords !== "") { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + eventsQuery.isArchived = false; + + let sortBy = "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + const currentDate = moment().startOf("day").utc().toDate(); + + eventsQuery.startDate = { $lte: currentDate }; + eventsQuery.endDate = { $gte: currentDate }; + + const isTest = + typeof queryParams.isTest === "boolean" + ? queryParams.isTest + : queryParams.isTest?.toLowerCase?.() === "true"; + + if (!isTest) { + eventsQuery.name = { + $not: /t[\W_0-9]*e[\W_0-9]*s[\W_0-9]*t/i, + }; + } + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + location: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/events/list-old-events.js b/src/routes/events/list-old-events.js new file mode 100644 index 0000000..1101e00 --- /dev/null +++ b/src/routes/events/list-old-events.js @@ -0,0 +1,89 @@ +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords && queryParams.keywords !== "") { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + let sortBy = "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + + const currentDate = moment().utc().toDate(); + eventsQuery.endDate = { $lt: currentDate }; + eventsQuery.$or = [ + { managers: req?.user?.id }, + { participants: req?.user?.id }, + ]; + + const isTest = + typeof queryParams.isTest === "boolean" + ? queryParams.isTest + : queryParams.isTest?.toLowerCase?.() === "true"; + + if (!isTest) { + eventsQuery.name = { + $not: /t[\W_0-9]*e[\W_0-9]*s[\W_0-9]*t/i, + }; + } + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + location: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/events/list-upcoimg-events.js b/src/routes/events/list-upcoimg-events.js new file mode 100644 index 0000000..d0c3886 --- /dev/null +++ b/src/routes/events/list-upcoimg-events.js @@ -0,0 +1,87 @@ +const moment = require("moment"); + +const { Event } = require("../../models/event"); + +const { validateListEvents } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListEvents(queryParams); + if (!isValid) return res.status(400).json(errors); + + const eventsQuery = {}; + + if (queryParams.keywords && queryParams.keywords !== "") { + eventsQuery.$text = { $search: queryParams.keywords }; + } + + eventsQuery.isArchived = false; + + let sortBy = "-startDate"; + let page = queryParams.page ? queryParams.page - 1 : 0; + const pageLimit = queryParams.pageLimit || 12; + const currentDate = moment().startOf("day").utc().toDate(); + + eventsQuery.startDate = { $gte: currentDate }; + + const isTest = + typeof queryParams.isTest === "boolean" + ? queryParams.isTest + : queryParams.isTest?.toLowerCase?.() === "true"; + + if (!isTest) { + eventsQuery.name = { + $not: /t[\W_0-9]*e[\W_0-9]*s[\W_0-9]*t/i, + }; + } + + let events; + let total; + try { + [events, total] = await Promise.all([ + Event.aggregate() + .match(eventsQuery) + .project({ + _id: 0, + id: "$_id", + address: 1, + endDate: 1, + name: 1, + poster: 1, + reviewsAmount: 1, + reviewsGoal: 1, + startDate: 1, + location: 1, + description: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Event.countDocuments(eventsQuery), + ]); + } catch (err) { + console.log("Events failed to be found or count at list-events"); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: events, + }); +}; diff --git a/src/routes/events/validations.js b/src/routes/events/validations.js index 2b15620..c468b50 100644 --- a/src/routes/events/validations.js +++ b/src/routes/events/validations.js @@ -1,490 +1,474 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); -const moment = require('moment'); - -const { isNumber } = require('../../helpers'); - -module.exports = { - validateCreateEvent(data) { - const errors = {}; - - if (typeof data.address === 'undefined' || data.address === '') { - errors.address = 'Is required'; - } else if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (data.donationEnabled === true) { - if (typeof data.donationAmounts === 'undefined') { - errors.donationAmounts = 'Is required'; - } - if (typeof data.donationGoal === 'undefined') { - errors.donationGoal = 'Is required'; - } - } - - if (typeof data.donationAmounts !== 'undefined') { - if (!Array.isArray(data.donationAmounts)) { - errors.donationAmounts = 'Should be an array'; - } else { - data.donationAmounts.some(d => { - if (typeof d.value === 'undefined') { - errors.donationAmounts = - 'All elements should have a value property'; - return true; - } else if (typeof d.value !== 'number') { - errors.donationAmounts = 'All value properties should be numbers'; - return true; - } else if (d < 5 || d > 10000) { - errors.donationAmounts = - 'All value properties should be between 5 and 10000'; - return true; - } - }); - } - } - - if ( - typeof data.donationEnabled !== 'undefined' && - typeof data.donationEnabled !== 'boolean' - ) { - errors.donationEnabled = 'Should be a boolean'; - } - - if (typeof data.donationGoal !== 'undefined') { - if (typeof data.donationGoal !== 'number') { - errors.donationGoal = 'Should be a number'; - } else if (!isInt(data.donationGoal.toString())) { - errors.donationGoal = 'Should be a integer'; - } - } - - let endDateIsValid = false; - if (typeof data.endDate === 'undefined' || data.endDate === '') { - errors.endDate = 'Is required'; - } else if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates === 'undefined') { - errors.locationCoordinates = 'Is required'; - } else if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - if (typeof data.participantsGoal === 'undefined') { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal === 'undefined') { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - - let startDateIsValid = false; - if (typeof data.startDate === 'undefined' || data.startDate === '') { - errors.startDate = 'Is required'; - } else if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditEvent(data) { - const errors = {}; - - if (typeof data.address !== 'undefined') { - if (typeof data.address !== 'string') { - errors.address = 'Should be a string'; - } else if (data.address === '') { - errors.address = 'Is required'; - } - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - let endDateIsValid = false; - if (typeof data.endDate !== 'undefined') { - if (typeof data.endDate !== 'string') { - errors.endDate = 'Should be a string'; - } else if (data.endDate === '') { - errors.endDate = 'Is required'; - } else if (!moment(data.endDate).isValid()) { - errors.endDate = 'Should have a ISO-8601 format'; - } else { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (endDate.isBefore(today)) { - errors.endDate = 'Should be greater than or equal to today'; - } else { - endDateIsValid = true; - } - } - } - - if ( - typeof data.isOpen !== 'undefined' && - typeof data.isOpen !== 'boolean' - ) { - errors.isOpen = 'Should be a boolean'; - } - - if (typeof data.locationCoordinates !== 'undefined') { - if (!Array.isArray(data.locationCoordinates)) { - errors.locationCoordinates = 'Should be an array'; - } else if (typeof data.locationCoordinates[0] === 'undefined') { - errors.locationCoordinates = 'Latitude is required'; - } else if (!isNumber(data.locationCoordinates[0])) { - errors.locationCoordinates = 'Latitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[0]) < -90 || - parseFloat(data.locationCoordinates[0]) > 90 - ) { - errors.locationCoordinates = 'Latitude value is not valid'; - } else if (typeof data.locationCoordinates[1] === 'undefined') { - errors.locationCoordinates = 'Longitude is required'; - } else if (!isNumber(data.locationCoordinates[1])) { - errors.locationCoordinates = 'Longitude should be a number'; - } else if ( - parseFloat(data.locationCoordinates[1]) < -180 || - parseFloat(data.locationCoordinates[1]) > 180 - ) { - errors.locationCoordinates = 'Longitude value is not valid'; - } else if (data.locationCoordinates.length > 2) { - errors.locationCoordinates = 'Should only have latitude and longitude'; - } - } - - if (typeof data.managers !== 'undefined') { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (typeof data.participants !== 'undefined') { - if (!Array.isArray(data.participants)) { - errors.participants = 'Should be an array'; - } else { - data.participants.some(p => { - if (typeof p !== 'string') { - errors.participants = 'Should only have string values'; - return true; - } else if (!p) { - errors.participants = 'Should not have empty values'; - return true; - } else if (!p.startsWith('-')) { - errors.participants = `${p} should start with -`; - return true; - } else if (!isMongoId(p.substring(1))) { - errors.participants = `${p} should be an id`; - return true; - } - }); - } - } - - if (typeof data.participantsGoal !== 'undefined') { - if (data.participantsGoal === null) { - errors.participantsGoal = 'Is required'; - } else if (typeof data.participantsGoal !== 'number') { - errors.participantsGoal = 'Should be a number'; - } else if (!isInt(data.participantsGoal.toString())) { - errors.participantsGoal = 'Should be a integer'; - } - } - - if (typeof data.poster !== 'undefined' && typeof data.poster !== 'string') { - errors.poster = 'Should be a string'; - } - - if (typeof data.reviewsGoal !== 'undefined') { - if (data.reviewsGoal === null) { - errors.reviewsGoal = 'Is required'; - } else if (typeof data.reviewsGoal !== 'number') { - errors.reviewsGoal = 'Should be a number'; - } else if (!isInt(data.reviewsGoal.toString())) { - errors.reviewsGoal = 'Should be a integer'; - } - } - - let startDateIsValid = false; - if (typeof data.startDate !== 'undefined') { - if (typeof data.startDate !== 'string') { - errors.startDate = 'Should be a string'; - } else if (data.startDate === '') { - errors.startDate = 'Is required'; - } else if (!moment(data.startDate).isValid()) { - errors.startDate = 'Should have a ISO-8601 format'; - } else { - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - const today = moment() - .startOf('day') - .utc(); - - if (startDate.isBefore(today)) { - errors.startDate = 'Should be greater than or equal to today'; - } else { - startDateIsValid = true; - } - } - } - - if ( - typeof data.teamManager !== 'undefined' && - typeof data.teamManager !== 'string' - ) { - errors.teamManager = 'Should be a string'; - } else if (data.teamManager && !isMongoId(data.teamManager)) { - errors.teamManager = 'Should be a valid id'; - } - - if (typeof data.teams !== 'undefined') { - if (!Array.isArray(data.teams)) { - errors.teams = 'Should be an array'; - } else { - data.teams.some(t => { - if (typeof t !== 'string') { - errors.teams = 'Should only have string values'; - return true; - } else if (!t) { - errors.teams = 'Should not have empty values'; - return true; - } else if (!t.startsWith('-')) { - errors.teams = `${t} should start with -`; - return true; - } else if (!isMongoId(t.substring(1))) { - errors.teams = `${t} should be an id`; - return true; - } - }); - } - } - - if (endDateIsValid && startDateIsValid) { - const endDate = moment(data.endDate) - .endOf('day') - .utc(); - const startDate = moment(data.startDate) - .startOf('day') - .utc(); - - if (startDate.isAfter(endDate)) { - errors.endDate = 'Should be greater than or equal to startDate'; - errors.startDate = 'Should be less than or equal to endDate'; - } else if (endDate.diff(startDate, 'days') > 365) { - errors.endDate = 'Should last less than 365 days'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListEvents(queryParams) { - const errors = {}; - - let isAfterDateValid = false; - if ( - queryParams.afterDate && - !moment(queryParams.afterDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.afterDate = 'Should have YYYY-MM-DD format'; - } else { - isAfterDateValid = true; - } - - let isBeforeDateValid = false; - if ( - queryParams.beforeDate && - !moment(queryParams.beforeDate, 'YYYY-MM-DD', true).isValid() - ) { - errors.beforeDate = 'Should have YYYY-MM-DD format'; - } else { - isBeforeDateValid = true; - } - - if (isAfterDateValid && isBeforeDateValid) { - const afterDate = moment(queryParams.afterDate, 'YYYY-MM-DD').utc(); - const beforeDate = moment(queryParams.beforeDate, 'YYYY-MM-DD').utc(); - if (afterDate.isAfter(beforeDate)) { - errors.afterDate = 'Should be less than beforeDate'; - errors.beforeDate = 'Should be greater than afterDate'; - } - } - - const sortOptions = [ - 'name', - '-name', - 'reviewsAmount', - '-reviewsAmount', - 'startDate', - '-startDate' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require("lodash"); +const { isInt, isMongoId } = require("validator"); +const moment = require("moment"); + +const { isNumber } = require("../../helpers"); + +module.exports = { + validateCreateEvent(data) { + const errors = {}; + + if (typeof data.address === "undefined" || data.address === "") { + errors.address = "Is required"; + } else if (typeof data.address !== "string") { + errors.address = "Should be a string"; + } + + if ( + typeof data.description !== "undefined" && + typeof data.description !== "string" + ) { + errors.description = "Should be a string"; + } + + if (data.donationEnabled === true) { + if (typeof data.donationAmounts === "undefined") { + errors.donationAmounts = "Is required"; + } + if (typeof data.donationGoal === "undefined") { + errors.donationGoal = "Is required"; + } + } + + if (typeof data.donationAmounts !== "undefined") { + if (!Array.isArray(data.donationAmounts)) { + errors.donationAmounts = "Should be an array"; + } else { + data.donationAmounts.some((d) => { + if (typeof d.value === "undefined") { + errors.donationAmounts = + "All elements should have a value property"; + return true; + } else if (typeof d.value !== "number") { + errors.donationAmounts = "All value properties should be numbers"; + return true; + } else if (d < 5 || d > 10000) { + errors.donationAmounts = + "All value properties should be between 5 and 10000"; + return true; + } + }); + } + } + + if ( + typeof data.donationEnabled !== "undefined" && + typeof data.donationEnabled !== "boolean" + ) { + errors.donationEnabled = "Should be a boolean"; + } + + if (typeof data.donationGoal !== "undefined") { + if (typeof data.donationGoal !== "number") { + errors.donationGoal = "Should be a number"; + } else if (!isInt(data.donationGoal.toString())) { + errors.donationGoal = "Should be a integer"; + } + } + + let endDateIsValid = false; + if (typeof data.endDate === "undefined" || data.endDate === "") { + errors.endDate = "Is required"; + } else if (typeof data.endDate !== "string") { + errors.endDate = "Should be a string"; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = "Should have a ISO-8601 format"; + } else { + endDateIsValid = true; + } + + if ( + typeof data.isOpen !== "undefined" && + typeof data.isOpen !== "boolean" + ) { + errors.isOpen = "Should be a boolean"; + } + + if (typeof data.locationCoordinates === "undefined") { + errors.locationCoordinates = "Is required"; + } else if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = "Should be an array"; + } else if (typeof data.locationCoordinates[0] === "undefined") { + errors.locationCoordinates = "Latitude is required"; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = "Latitude should be a number"; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = "Latitude value is not valid"; + } else if (typeof data.locationCoordinates[1] === "undefined") { + errors.locationCoordinates = "Longitude is required"; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = "Longitude should be a number"; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = "Longitude value is not valid"; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = "Should only have latitude and longitude"; + } + if (typeof data.name === "undefined" || data.name === "") { + errors.name = "Is required"; + } else if (typeof data.name !== "string") { + errors.name = "Should be a string"; + } + + if (typeof data.participantsGoal === "undefined") { + errors.participantsGoal = "Is required"; + } else if (typeof data.participantsGoal !== "number") { + errors.participantsGoal = "Should be a number"; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = "Should be a integer"; + } + + if (typeof data.poster !== "undefined" && typeof data.poster !== "string") { + errors.poster = "Should be a string"; + } + + if (typeof data.reviewsGoal === "undefined") { + errors.reviewsGoal = "Is required"; + } else if (typeof data.reviewsGoal !== "number") { + errors.reviewsGoal = "Should be a number"; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = "Should be a integer"; + } + + let startDateIsValid = false; + if (typeof data.startDate === "undefined" || data.startDate === "") { + errors.startDate = "Is required"; + } else if (typeof data.startDate !== "string") { + errors.startDate = "Should be a string"; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = "Should have a ISO-8601 format"; + } else { + startDateIsValid = true; + } + + if ( + typeof data.teamManager !== "undefined" && + typeof data.teamManager !== "string" + ) { + errors.teamManager = "Should be a string"; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = "Should be a valid id"; + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf("day").utc(); + const startDate = moment(data.startDate).startOf("day").utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = "Should be greater than or equal to startDate"; + errors.startDate = "Should be less than or equal to endDate"; + } else if (endDate.diff(startDate, "days") > 365) { + errors.endDate = "Should last less than 365 days"; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditEvent(data) { + const errors = {}; + + if (typeof data.address !== "undefined") { + if (typeof data.address !== "string") { + errors.address = "Should be a string"; + } else if (data.address === "") { + errors.address = "Is required"; + } + } + + if ( + typeof data.description !== "undefined" && + typeof data.description !== "string" + ) { + errors.description = "Should be a string"; + } + + let endDateIsValid = false; + if (typeof data.endDate !== "undefined") { + if (typeof data.endDate !== "string") { + errors.endDate = "Should be a string"; + } else if (data.endDate === "") { + errors.endDate = "Is required"; + } else if (!moment(data.endDate).isValid()) { + errors.endDate = "Should have a ISO-8601 format"; + } else { + const endDate = moment(data.endDate).endOf("day").utc(); + const today = moment().startOf("day").utc(); + + if (endDate.isBefore(today)) { + errors.endDate = "Should be greater than or equal to today"; + } else { + endDateIsValid = true; + } + } + } + + if ( + typeof data.isOpen !== "undefined" && + typeof data.isOpen !== "boolean" + ) { + errors.isOpen = "Should be a boolean"; + } + + if (typeof data.locationCoordinates !== "undefined") { + if (!Array.isArray(data.locationCoordinates)) { + errors.locationCoordinates = "Should be an array"; + } else if (typeof data.locationCoordinates[0] === "undefined") { + errors.locationCoordinates = "Latitude is required"; + } else if (!isNumber(data.locationCoordinates[0])) { + errors.locationCoordinates = "Latitude should be a number"; + } else if ( + parseFloat(data.locationCoordinates[0]) < -90 || + parseFloat(data.locationCoordinates[0]) > 90 + ) { + errors.locationCoordinates = "Latitude value is not valid"; + } else if (typeof data.locationCoordinates[1] === "undefined") { + errors.locationCoordinates = "Longitude is required"; + } else if (!isNumber(data.locationCoordinates[1])) { + errors.locationCoordinates = "Longitude should be a number"; + } else if ( + parseFloat(data.locationCoordinates[1]) < -180 || + parseFloat(data.locationCoordinates[1]) > 180 + ) { + errors.locationCoordinates = "Longitude value is not valid"; + } else if (data.locationCoordinates.length > 2) { + errors.locationCoordinates = "Should only have latitude and longitude"; + } + } + + if (typeof data.managers !== "undefined") { + if (!Array.isArray(data.managers)) { + errors.managers = "Should be an array"; + } else { + data.managers.some((m) => { + if (typeof m !== "string") { + errors.managers = "Should only have string values"; + return true; + } else if (!m) { + errors.managers = "Should not have empty values"; + return true; + } else { + if (m.startsWith("-")) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (typeof data.name !== "undefined") { + if (typeof data.name !== "string") { + errors.name = "Should be a string"; + } else if (data.name === "") { + errors.name = "Is required"; + } + } + + if (typeof data.participants !== "undefined") { + if (!Array.isArray(data.participants)) { + errors.participants = "Should be an array"; + } else { + data.participants.some((p) => { + if (typeof p !== "string") { + errors.participants = "Should only have string values"; + return true; + } else if (!p) { + errors.participants = "Should not have empty values"; + return true; + } else if (!p.startsWith("-")) { + errors.participants = `${p} should start with -`; + return true; + } else if (!isMongoId(p.substring(1))) { + errors.participants = `${p} should be an id`; + return true; + } + }); + } + } + + if (typeof data.participantsGoal !== "undefined") { + if (data.participantsGoal === null) { + errors.participantsGoal = "Is required"; + } else if (typeof data.participantsGoal !== "number") { + errors.participantsGoal = "Should be a number"; + } else if (!isInt(data.participantsGoal.toString())) { + errors.participantsGoal = "Should be a integer"; + } + } + + if (typeof data.poster !== "undefined" && typeof data.poster !== "string") { + errors.poster = "Should be a string"; + } + + if (typeof data.reviewsGoal !== "undefined") { + if (data.reviewsGoal === null) { + errors.reviewsGoal = "Is required"; + } else if (typeof data.reviewsGoal !== "number") { + errors.reviewsGoal = "Should be a number"; + } else if (!isInt(data.reviewsGoal.toString())) { + errors.reviewsGoal = "Should be a integer"; + } + } + + let startDateIsValid = false; + if (typeof data.startDate !== "undefined") { + if (typeof data.startDate !== "string") { + errors.startDate = "Should be a string"; + } else if (data.startDate === "") { + errors.startDate = "Is required"; + } else if (!moment(data.startDate).isValid()) { + errors.startDate = "Should have a ISO-8601 format"; + } else { + const startDate = moment(data.startDate).startOf("day").utc(); + const today = moment().startOf("day").utc(); + + if (startDate.isBefore(today)) { + errors.startDate = "Should be greater than or equal to today"; + } else { + startDateIsValid = true; + } + } + } + + if ( + typeof data.teamManager !== "undefined" && + typeof data.teamManager !== "string" + ) { + errors.teamManager = "Should be a string"; + } else if (data.teamManager && !isMongoId(data.teamManager)) { + errors.teamManager = "Should be a valid id"; + } + + if (typeof data.teams !== "undefined") { + if (!Array.isArray(data.teams)) { + errors.teams = "Should be an array"; + } else { + data.teams.some((t) => { + if (typeof t !== "string") { + errors.teams = "Should only have string values"; + return true; + } else if (!t) { + errors.teams = "Should not have empty values"; + return true; + } else if (!t.startsWith("-")) { + errors.teams = `${t} should start with -`; + return true; + } else if (!isMongoId(t.substring(1))) { + errors.teams = `${t} should be an id`; + return true; + } + }); + } + } + + if (endDateIsValid && startDateIsValid) { + const endDate = moment(data.endDate).endOf("day").utc(); + const startDate = moment(data.startDate).startOf("day").utc(); + + if (startDate.isAfter(endDate)) { + errors.endDate = "Should be greater than or equal to startDate"; + errors.startDate = "Should be less than or equal to endDate"; + } else if (endDate.diff(startDate, "days") > 365) { + errors.endDate = "Should last less than 365 days"; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListEvents(queryParams) { + const errors = {}; + + // --- afterDate validation --- + let isAfterDateValid = false; + if ( + queryParams.afterDate && + !moment(queryParams.afterDate, "YYYY-MM-DD", true).isValid() + ) { + errors.afterDate = "Should have YYYY-MM-DD format"; + } else { + isAfterDateValid = true; + } + + // --- beforeDate validation --- + let isBeforeDateValid = false; + if ( + queryParams.beforeDate && + !moment(queryParams.beforeDate, "YYYY-MM-DD", true).isValid() + ) { + errors.beforeDate = "Should have YYYY-MM-DD format"; + } else { + isBeforeDateValid = true; + } + + // --- afterDate and beforeDate validation --- + if (isAfterDateValid && isBeforeDateValid) { + const afterDate = moment(queryParams.afterDate, "YYYY-MM-DD").utc(); + const beforeDate = moment(queryParams.beforeDate, "YYYY-MM-DD").utc(); + if (afterDate.isAfter(beforeDate)) { + errors.afterDate = "Should be less than beforeDate"; + errors.beforeDate = "Should be greater than afterDate"; + } + } + + // --- sortBy validation --- + const sortOptions = [ + "name", + "-name", + "reviewsAmount", + "-reviewsAmount", + "startDate", + "-startDate", + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = "Should be a valid sort"; + } + + // --- page validation --- + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = "Should be a integer"; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = "Should be a positive integer"; + } + } + + // --- pageLimit validation --- + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = "Should be a integer"; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = "Should be a positive integer"; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = "Should be less than 13"; + } + } + + // --- isTest validation --- + if (queryParams.isTest !== undefined) { + const value = + typeof queryParams.isTest === "boolean" + ? queryParams.isTest + : queryParams.isTest.toLowerCase?.(); + + if ( + value !== true && + value !== false && + value !== "true" && + value !== "false" + ) { + errors.isTest = "Should be a boolean (true or false)"; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, +}; diff --git a/src/routes/index.js b/src/routes/index.js index 702f72e..c8ace7c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,25 +1,27 @@ -const express = require('express'); - -const auth = require('./auth'); -const events = require('./events'); -const others = require('./others'); -const petitions = require('./petitions'); -const photos = require('./photos'); -const reviews = require('./reviews'); -const teams = require('./teams'); -const users = require('./users'); -const venues = require('./venues'); - -const router = new express.Router(); - -router.use('', others); -router.use('/auth', auth); -router.use('/events', events); -router.use('/petitions', petitions); -router.use('/photos', photos); -router.use('/reviews', reviews); -router.use('/teams', teams); -router.use('/users', users); -router.use('/venues', venues); - -module.exports = router; +const express = require("express"); + +const auth = require("./auth"); +const events = require("./events"); +const others = require("./others"); +const petitions = require("./petitions"); +const photos = require("./photos"); +const reviews = require("./reviews"); +const teams = require("./teams"); +const users = require("./users"); +const venues = require("./venues"); +const donations = require("./donatins"); + +const router = new express.Router(); + +router.use("", others); +router.use("/auth", auth); +router.use("/events", events); +router.use("/petitions", petitions); +router.use("/photos", photos); +router.use("/reviews", reviews); +router.use("/teams", teams); +router.use("/users", users); +router.use("/venues", venues); +router.use("/donations", donations); + +module.exports = router; diff --git a/src/routes/others/contact.js b/src/routes/others/contact.js index 73033b7..b0b689e 100644 --- a/src/routes/others/contact.js +++ b/src/routes/others/contact.js @@ -1,37 +1,37 @@ -const { sendEmail } = require('../../helpers'); - -const { validateContact } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - email: req.body.email, - message: req.body.message, - name: req.body.name - }; - - const { errors, isValid } = validateContact(data); - if (!isValid) return res.status(400).json(errors); - - const subject = 'Message from Contact Page'; - const htmlContent = ` -

${data.message}

-

-

Name: ${data.name}

-

Email: ${data.email}

- `; - const textContent = ` - ${data.message}\n\n - Name: ${data.name}\n - Email: ${data.email} - `; - const receiversEmails = [process.env.AXSLAB_EMAIL]; - - sendEmail({ - subject, - htmlContent, - textContent, - receiversEmails - }); - - return res.status(200).json({ message: 'Success' }); -}; +const { sendEmail } = require('../../helpers'); + +const { validateContact } = require('./validations'); + +module.exports = async (req, res) => { + const data = { + email: req.body.email, + message: req.body.message, + name: req.body.name + }; + + const { errors, isValid } = validateContact(data); + if (!isValid) return res.status(400).json(errors); + + const subject = 'Message from Contact Page'; + const htmlContent = ` +

${data.message}

+

+

Name: ${data.name}

+

Email: ${data.email}

+ `; + const textContent = ` + ${data.message}\n\n + Name: ${data.name}\n + Email: ${data.email} + `; + const receiversEmails = [process.env.AXSLAB_EMAIL]; + + sendEmail({ + subject, + htmlContent, + textContent, + receiversEmails + }); + + return res.status(200).json({ message: 'Success' }); +}; diff --git a/src/routes/others/index.js b/src/routes/others/index.js index 09034dc..0ba2a70 100644 --- a/src/routes/others/index.js +++ b/src/routes/others/index.js @@ -1,11 +1,14 @@ -const express = require('express'); - -const contact = require('./contact'); -const migrateScores = require('./migrate-scores'); - -const router = new express.Router(); - -router.post('/contact', contact); -router.get('/migrate-scores', migrateScores); - -module.exports = router; +const express = require("express"); + +const contact = require("./contact"); +const migrateScores = require("./migrate-scores"); +const survey = require("./survey"); +const { isAuthenticated } = require("../../helpers"); + +const router = new express.Router(); + +router.post("/contact", contact); +router.post("/survey", isAuthenticated({ isOptional: false }), survey); +router.get("/migrate-scores", migrateScores); + +module.exports = router; diff --git a/src/routes/others/migrate-scores.js b/src/routes/others/migrate-scores.js index 06820bb..f311206 100644 --- a/src/routes/others/migrate-scores.js +++ b/src/routes/others/migrate-scores.js @@ -2,7 +2,7 @@ const { Venue } = require('../../models/venue'); const { Review } = require('../../models/review'); const { User } = require('../../models/user'); -module.exports = async (req, res, next) => { +module.exports = async (req, res) => { const saveChanges = req.query.save && req.query.save === 'true'; console.log('IN MIGRATE SCORES, SAVING CHANGES: ' + saveChanges); @@ -28,7 +28,7 @@ module.exports = async (req, res, next) => { let venuesProcessed = 0; let pages = 0; while (venuesProcessed < venuesTotalCount) { - timeBlockStart = new Date(); + let timeBlockStart = new Date(); let venueChunk; try { venueChunk = await Venue.find({ @@ -52,8 +52,8 @@ module.exports = async (req, res, next) => { console.log('UNEXPECTED AMOUNT OF VENUES UNCONVERTED FOUND'); } - for (venue of venueChunk) { - for (review of venue.reviews) { + for (const venue of venueChunk) { + for (const review of venue.reviews) { //console.log("reviewID: ", review); let dbReview; @@ -88,6 +88,7 @@ module.exports = async (req, res, next) => { case 4: dbReview.hasWideEntrance = true; venue.hasWideEntrance.yes += 1; + break; case 3: dbReview.hasPortableRamp = true; venue.hasPortableRamp.yes += 1; @@ -111,6 +112,7 @@ module.exports = async (req, res, next) => { venue.hasLoweredSinks.yes += 1; dbReview.hasSupportAroundToilet = true; venue.hasSupportAroundToilet.yes += 1; + break; case 3: dbReview.hasSwingOutDoor = true; venue.hasSwingOutDoor.yes += 1; @@ -201,40 +203,47 @@ module.exports = async (req, res, next) => { } //end venues while-loop try { - reviewsTotalCount = await Review.countDocuments({ + // Count the total number of unconverted reviews + const reviewsTotalCount = await Review.countDocuments({ _isScoreConverted: { $ne: true } }); - } catch (err) { - console.log('Reviews unconverted failed to be counted, error: ', err); - return res.status(404).json(err); - } - console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - - if (reviewsTotalCount > 0) { - let unconvertedReviews; + console.log('THERE ARE ' + reviewsTotalCount + ' UNCONVERTED REVIEWS'); - try { - unconvertedReviews = await Review.find({ - _isScoreConverted: { $ne: true } - }); - } catch (err) { - console.log('Reviews unconverted failed to be found, error: ', err); - return res.status(404).json(err); - } + if (reviewsTotalCount > 0) { + let unconvertedReviews; - for (unconvertedReview of unconvertedReviews) { try { - matchingVenue = await Venue.find({ - reviews: unconvertedReview.id + // Find all unconverted reviews + unconvertedReviews = await Review.find({ + _isScoreConverted: { $ne: true } }); } catch (err) { console.log('Reviews unconverted failed to be found, error: ', err); return res.status(404).json(err); } - console.log('Review ID: ' + unconvertedReview.id); - console.log("Review's venue: " + matchingVenue.id); + for (const unconvertedReview of unconvertedReviews) { + let matchingVenue; + + try { + // Find the venue for each unconverted review + matchingVenue = await Venue.findOne({ + reviews: unconvertedReview.id + }); + } catch (err) { + console.log('Venue search failed, error: ', err); + return res.status(404).json(err); + } + + console.log('Review ID: ' + unconvertedReview.id); + console.log( + "Review's venue: " + (matchingVenue ? matchingVenue.id : 'Not found') + ); + } } + } catch (err) { + console.log('Reviews unconverted count failed, error: ', err); + return res.status(404).json(err); } console.log('FINISHED PROCESSING ALL RECORDS'); diff --git a/src/routes/others/survey.js b/src/routes/others/survey.js new file mode 100644 index 0000000..d7102b3 --- /dev/null +++ b/src/routes/others/survey.js @@ -0,0 +1,82 @@ +const { Survey } = require("../../models/survey"); +const { + adminServeyMailTemplate, + submitServeyUserMailTemplate, +} = require("../../helpers/mail-template"); +const { sendEmail } = require("../../helpers"); + +const questions = { + features: "What features do you use most on AXS Map?", + navigationEase: "How easy is it to navigate the app?", + motivation: "What motivates you to participate in Mapathons?", + accessibility: "How can we improve accessibility ratings?", + additionalFeatures: "Any additional features you'd like to see?", + satisfaction: "How satisfied are you with the app?", + challenges: "What challenges have you faced using AXS Map?", + recommend: "Would you recommend it to others?", + frequency: "What would make you use it more often?", +}; + +module.exports = async (req, res) => { + const { + features, + navigationEase, + motivation, + accessibility, + additionalFeatures, + satisfaction, + challenges, + recommend, + frequency, + } = req.body; + try { + const surveyForm = new Survey({ + features, + navigationEase, + motivation, + accessibility, + additionalFeatures, + satisfaction, + challenges, + recommend, + frequency, + user: req?.user?.id, + }); + + await surveyForm.save(); + sendEmail({ + subject: "Survey Submission Confirmation", + htmlContent: submitServeyUserMailTemplate( + `${req?.user?.firstName ?? ""} ${req?.user?.lastName ?? ""}` + ), + textContent: "", + receiversEmails: [req?.user?.email], + }); + const aswers = [ + { question: questions.features, answer: features }, + { question: questions.navigationEase, answer: navigationEase }, + { question: questions.motivation, answer: motivation }, + { question: questions.accessibility, answer: accessibility }, + { question: questions.additionalFeatures, answer: additionalFeatures }, + { question: questions.satisfaction, answer: satisfaction }, + { question: questions.challenges, answer: challenges }, + { question: questions.recommend, answer: recommend }, + { question: questions.frequency, answer: frequency }, + ]; + sendEmail({ + subject: "Survey Submission Confirmation", + htmlContent: adminServeyMailTemplate( + `${req?.user?.firstName ?? ""} ${req?.user?.lastName ?? ""}`, + req?.user?.email, + aswers + ), + textContent: "", + receiversEmails: [`${process?.env?.SERVEY_SUBMISSION_MAIL}`], + }); + + res.status(201).json({ message: "Survey saved successfully." }); + } catch (error) { + console.log(error) + res.status(500).json({ error: "Something went wrong." }); + } +}; diff --git a/src/routes/others/validations.js b/src/routes/others/validations.js index b1a8c92..3663493 100644 --- a/src/routes/others/validations.js +++ b/src/routes/others/validations.js @@ -1,37 +1,37 @@ -const freemail = require('freemail'); -const { isEmail } = require('validator'); -const { isEmpty } = require('lodash'); - -module.exports = { - validateContact(data) { - const errors = {}; - - if (typeof data.email === 'undefined' || data.email === '') { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (data.email.length > 254) { - errors.email = 'Should be less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Should be a valid email'; - } - - if (typeof data.message === 'undefined' || data.message === '') { - errors.message = 'Is required'; - } else if (typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } else if (data.message.length > 300) { - errors.message = 'Should be less than 301 characters'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name.length > 60) { - errors.name = 'Should be less than 61 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail } = require('validator'); +const { isEmpty } = require('lodash'); + +module.exports = { + validateContact(data) { + const errors = {}; + + if (typeof data.email === 'undefined' || data.email === '') { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (data.email.length > 254) { + errors.email = 'Should be less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Should be a valid email'; + } + + if (typeof data.message === 'undefined' || data.message === '') { + errors.message = 'Is required'; + } else if (typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } else if (data.message.length > 300) { + errors.message = 'Should be less than 301 characters'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name.length > 60) { + errors.name = 'Should be less than 61 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/petitions/create-petition.js b/src/routes/petitions/create-petition.js index 82ba6b7..69a8474 100644 --- a/src/routes/petitions/create-petition.js +++ b/src/routes/petitions/create-petition.js @@ -1,474 +1,498 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateCreatePetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateCreatePetition(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = Object.assign( - {}, - { - event: req.body.event, - message: req.body.message, - team: req.body.team, - type: req.body.type, - user: req.body.user - } - ); - data.sender = req.user.id.toString(); - const today = moment.utc(); - - if (data.type === 'invite-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ event: 'Not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.teams.find(t => t.toString() === data.team)) { - return res.status(400).json({ - general: 'Team is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - } else if (data.type === 'invite-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from event ${data.event} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (data.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (!event.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (event.participants.find(p => p.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'invite-user-team') { - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - type: data.type, - user: data.user - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to user ${ - data.user - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already has a pending invitation to team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - if (req.sender === data.user) { - return res.status(400).json({ general: 'User should not be you' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (team.members.find(m => m.toString() === data.user)) { - return res.status(400).json({ - general: 'User is already member of team' - }); - } - - let user; - try { - user = await User.findOne({ _id: data.user }); - } catch (err) { - console.log(`User ${data.user} failed to be found at create-petition`); - return next(err); - } - - if (!user) return res.status(404).json({ general: 'User not found' }); - } else if (data.type === 'request-team-event') { - delete data.user; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - team: data.team, - type: data.type - }); - } catch (err) { - console.log( - `Petition from team ${data.team} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'Team already has a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.teams.find(t => t.toString() === data.sender)) { - return res.status(400).json({ - general: 'Team is already participant of event ' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (!team.managers.find(m => m.toString() === data.sender)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else if (data.type === 'request-user-event') { - delete data.team; - - let petition; - try { - petition = await Petition.findOne({ - event: data.event, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to event ${ - data.event - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with event' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-petition`); - return next(err); - } - - if (!event) return res.status(404).json({ general: 'Event not found' }); - - if (event.participants.find(p => p.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is participant of event' - }); - } - - const endDate = moment(event.endDate).utc(); - if (endDate.isBefore(today)) { - return res.status(400).json({ general: 'Event has already finished' }); - } - } else { - // data.type === request-user-team - delete data.event; - - let petition; - try { - petition = await Petition.findOne({ - team: data.team, - sender: data.sender, - type: data.type - }); - } catch (err) { - console.log( - `Petition from user ${data.sender} to team ${ - data.team - } failed to be found at create-petition` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'User already have a pending request with team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at create-petition` - ); - return next(err); - } - } - - let team; - try { - team = await Team.findOne({ _id: data.team }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-petition`); - return next(err); - } - - if (!team) return res.status(404).json({ general: 'Team not found' }); - - if (team.members.find(m => m.toString() === data.sender)) { - return res.status(400).json({ - general: 'User already is member of team' - }); - } - } - - let petition; - try { - petition = await Petition.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at create-petition.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - const dataResponse = Object.assign( - {}, - { - createdAt: petition.createdAt, - event: petition.event, - message: petition.message, - sender: petition.sender, - state: petition.state, - team: petition.team, - type: petition.type, - user: petition.user - } - ); - return res.status(201).json(dataResponse); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); + +const { validateCreatePetition } = require("./validations"); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateCreatePetition(req.body); + if (!isValid) return res.status(400).json(errors); + + const data = Object.assign( + {}, + { + event: req.body.event, + message: req.body.message, + team: req.body.team, + type: req.body.type, + user: req.body.user, + } + ); + data.sender = req.user.id.toString(); + const today = moment.utc(); + + if (data.type === "invite-team-event") { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type, + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "Team already has a pending invitation to event", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + event: data.event, + team: data.team, + type: data.type, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ event: "Not found" }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (event.teams.find((t) => t.toString() === data.team)) { + return res.status(400).json({ + general: "Team is already participant of event", + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: "Event has already finished" }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: "Team not found" }); + } else if (data.type === "invite-user-event") { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + type: data.type, + user: data.user, + }); + } catch (err) { + console.log( + `Petition from event ${data.event} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "User already has a pending invitation to event", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + event: data.event, + type: data.type, + user: data.user, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (data.sender === data.user) { + return res.status(400).json({ general: "User should not be you" }); + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: "Event not found" }); + + if (!event.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (event.participants.find((p) => p.toString() === data.user)) { + return res.status(400).json({ + general: "User is already participant of event", + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: "Event has already finished" }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: "User not found" }); + } else if (data.type === "invite-user-team") { + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + type: data.type, + user: data.user, + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to user ${ + data.user + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "User already has a pending invitation to team", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + team: data.team, + type: data.type, + user: data.user, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + if (req.sender === data.user) { + return res.status(400).json({ general: "User should not be you" }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: "Team not found" }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (team.members.find((m) => m.toString() === data.user)) { + return res.status(400).json({ + general: "User is already member of team", + }); + } + + let user; + try { + user = await User.findOne({ _id: data.user }); + } catch (err) { + console.log(`User ${data.user} failed to be found at create-petition`); + return next(err); + } + + if (!user) return res.status(404).json({ general: "User not found" }); + } else if (data.type === "request-team-event") { + delete data.user; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + team: data.team, + type: data.type, + }); + } catch (err) { + console.log( + `Petition from team ${data.team} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "Team already has a pending request with event", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + event: data.event, + team: data.team, + type: data.type, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: "Event not found" }); + + if (event.teams.find((t) => t.toString() === data.sender)) { + return res.status(400).json({ + general: "Team is already participant of event ", + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: "Event has already finished" }); + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: "Team not found" }); + + if (!team.managers.find((m) => m.toString() === data.sender)) { + return res.status(403).json({ general: "Forbidden action" }); + } + } else if (data.type === "request-user-event") { + delete data.team; + + let petition; + try { + petition = await Petition.findOne({ + event: data.event, + sender: data.sender, + type: data.type, + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to event ${ + data.event + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "User already have a pending request with event", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + event: data.event, + sender: data.sender, + type: data.type, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-petition`); + return next(err); + } + + if (!event) return res.status(404).json({ general: "Event not found" }); + + if (event.participants.find((p) => p.toString() === data.sender)) { + return res.status(400).json({ + general: "User already is participant of event", + }); + } + + const endDate = moment(event.endDate).utc(); + if (endDate.isBefore(today)) { + return res.status(400).json({ general: "Event has already finished" }); + } + } else { + // data.type === request-user-team + delete data.event; + + let petition; + try { + petition = await Petition.findOne({ + team: data.team, + sender: data.sender, + type: data.type, + }); + } catch (err) { + console.log( + `Petition from user ${data.sender} to team ${ + data.team + } failed to be found at create-petition` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "User already have a pending request with team", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + team: data.team, + sender: data.sender, + type: data.type, + }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at create-petition` + ); + return next(err); + } + } + + let team; + try { + team = await Team.findOne({ _id: data.team }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-petition`); + return next(err); + } + + if (!team) return res.status(404).json({ general: "Team not found" }); + + if (team.members.find((m) => m.toString() === data.sender)) { + return res.status(400).json({ + general: "User already is member of team", + }); + } + } + + let petition; + try { + petition = await Petition.create(data); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at create-petition.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + const dataResponse = Object.assign( + {}, + { + createdAt: petition.createdAt, + event: petition.event, + message: petition.message, + sender: petition.sender, + state: petition.state, + team: petition.team, + type: petition.type, + user: petition.user, + } + ); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/petitions/edit-petition.js b/src/routes/petitions/edit-petition.js index 5537b38..f837db2 100644 --- a/src/routes/petitions/edit-petition.js +++ b/src/routes/petitions/edit-petition.js @@ -1,555 +1,557 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditPetition } = require('./validations'); - -module.exports = async (req, res, next) => { - const petitionId = req.params.petitionId; - - let petition; - try { - petition = await Petition.findOne({ _id: petitionId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Petition not found' }); - } - - console.log(`Petition ${petitionId} failed to be found at edit-petition`); - return next(err); - } - - if (!petition) { - return res.status(404).json({ general: 'Petition not found' }); - } - - if (petition.state === 'accepted') { - return res.status(400).json({ general: 'Is already accepted' }); - } - - if (petition.state === 'canceled') { - return res.status(400).json({ general: 'Is already canceled' }); - } - - if (petition.state === 'rejected') { - return res.status(400).json({ general: 'Is already rejected' }); - } - - const { errors, isValid } = validateEditPetition(req.body); - if (!isValid) return res.status(400).json(errors); - - let isSender = false; - - if (petition.sender.toString() === req.user.id) { - isSender = true; - if (req.body.state === 'canceled') { - petition.state = 'canceled'; - } else { - return res.status(400).json({ state: 'Should only be canceled' }); - } - } - - if (petition.type.endsWith('event')) { - let event; - try { - event = await Event.findOne({ _id: petition.event }); - } catch (err) { - console.log( - `Event ${petition.event} failed to be found at edit-petition` - ); - return next(err); - } - - if (!event) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Event is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'invite-user-event') { - if ( - event.participants.find(p => p.toString() === petition.user.toString()) - ) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, req.user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.events = [...req.user.events, event.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else if (petition.type === 'request-team-event') { - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.team} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (event.teams.find(t => t.toString() === team.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'Team is already a participant of event. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.teams = [...event.teams, team.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - team.events = [...team.events, event.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-event' - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.user} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (event.participants.find(p => p.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: - 'User is already a participant of event. Petition was removed' - }); - } - - if (!isSender) { - if (!event.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - event.participants = [...event.participants, user.id]; - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.events = [...user.events, event.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } else { - // petition.type.endsWith('team') - let team; - try { - team = await Team.findOne({ _id: petition.team }); - } catch (err) { - console.log( - `Team ${petition.entityId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!team) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'Team is already removed. Petition was removed' - }); - } - - if (petition.type === 'invite-user-team') { - if (team.members.find(m => m.toString() === petition.user.toString())) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - } else { - if (petition.user.toString() !== req.user.id) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, req.user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${req.user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } else { - // petition.type === 'request-user-team' - - let user; - try { - user = await User.findOne({ _id: petition.sender }); - } catch (err) { - console.log( - `User ${petition.senderId} failed to be found at edit-petition` - ); - return next(err); - } - - if (!user) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already removed. Petition was removed' - }); - } - - if (team.members.find(m => m.toString() === user.id)) { - try { - await petition.remove(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be removed at edit-petition` - ); - return next(err); - } - - return res.status(400).json({ - general: 'User is already a member of team. Petition was removed' - }); - } - - if (!isSender) { - if (!team.managers.find(m => m.toString() === req.user.id)) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - if (req.body.state === 'accepted') { - team.members = [...team.members, user.id]; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at edit-petition` - ); - return next(err); - } - - user.teams = [...user.teams, team.id]; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User ${user.id} failed to be updated at edit-petition` - ); - return next(err); - } - - petition.state = 'accepted'; - } else { - petition.state = 'rejected'; - } - } - } - } - - petition.updatedAt = moment.utc().toDate(); - - try { - await petition.save(); - } catch (err) { - console.log( - `Petition ${petition.id} failed to be updated at edit-petition` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); + +const { validateEditPetition } = require("./validations"); + +module.exports = async (req, res, next) => { + const petitionId = req.params.petitionId; + + let petition; + try { + petition = await Petition.findOne({ _id: petitionId }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Petition not found" }); + } + + console.log(`Petition ${petitionId} failed to be found at edit-petition`); + return next(err); + } + + if (!petition) { + return res.status(404).json({ general: "Petition not found" }); + } + + if (petition.state === "accepted") { + return res.status(400).json({ general: "Is already accepted" }); + } + + if (petition.state === "canceled") { + return res.status(400).json({ general: "Is already canceled" }); + } + + if (petition.state === "rejected") { + return res.status(400).json({ general: "Is already rejected" }); + } + + const { errors, isValid } = validateEditPetition(req.body); + if (!isValid) return res.status(400).json(errors); + + let isSender = false; + + if (petition.sender.toString() === req.user.id) { + isSender = true; + if (req.body.state === "canceled") { + petition.state = "canceled"; + } else { + return res.status(400).json({ state: "Should only be canceled" }); + } + } + + if (petition.type.endsWith("event")) { + let event; + try { + event = await Event.findOne({ _id: petition.event }); + } catch (err) { + console.log( + `Event ${petition.event} failed to be found at edit-petition` + ); + return next(err); + } + + if (!event) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "Event is already removed. Petition was removed", + }); + } + + if (petition.type === "invite-team-event") { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "Team is already removed. Petition was removed", + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + "Team is already a participant of event. Petition was removed", + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + } else { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } else if (petition.type === "invite-user-event") { + if ( + event.participants.find( + (p) => p.toString() === petition.user.toString() + ) + ) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + "User is already a participant of event. Petition was removed", + }); + } + + if (isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + event.participants = [...event.participants, req.user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.events = [...req.user.events, event.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } else if (petition.type === "request-team-event") { + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.team} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "Team is already removed. Petition was removed", + }); + } + + if (event.teams.find((t) => t.toString() === team.id)) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + "Team is already a participant of event. Petition was removed", + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + } else { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + event.teams = [...event.teams, team.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + team.events = [...team.events, event.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } else { + // petition.type === 'request-user-event' + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.user} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "User is already removed. Petition was removed", + }); + } + + if (event.participants.find((p) => p.toString() === user.id)) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: + "User is already a participant of event. Petition was removed", + }); + } + + if (!isSender) { + if (!event.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + event.participants = [...event.participants, user.id]; + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.events = [...user.events, event.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } + } else { + // petition.type.endsWith('team') + let team; + try { + team = await Team.findOne({ _id: petition.team }); + } catch (err) { + console.log( + `Team ${petition.entityId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!team) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "Team is already removed. Petition was removed", + }); + } + + if (petition.type === "invite-user-team") { + if (team.members.find((m) => m.toString() === petition.user.toString())) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "User is already a member of team. Petition was removed", + }); + } + + if (isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + } else { + if (petition.user.toString() !== req.user.id) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + team.members = [...team.members, req.user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${req.user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } else { + // petition.type === 'request-user-team' + + let user; + try { + user = await User.findOne({ _id: petition.sender }); + } catch (err) { + console.log( + `User ${petition.senderId} failed to be found at edit-petition` + ); + return next(err); + } + + if (!user) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "User is already removed. Petition was removed", + }); + } + + if (team.members.find((m) => m.toString() === user.id)) { + try { + await Petition.deleteOne({ _id: petitionId }); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be removed at edit-petition` + ); + return next(err); + } + + return res.status(400).json({ + general: "User is already a member of team. Petition was removed", + }); + } + + if (!isSender) { + if (!team.managers.find((m) => m.toString() === req.user.id)) { + return res.status(403).json({ general: "Forbidden action" }); + } + + if (req.body.state === "accepted") { + team.members = [...team.members, user.id]; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at edit-petition` + ); + return next(err); + } + + user.teams = [...user.teams, team.id]; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User ${user.id} failed to be updated at edit-petition` + ); + return next(err); + } + + petition.state = "accepted"; + } else { + petition.state = "rejected"; + } + } + } + } + + petition.updatedAt = moment.utc().toDate(); + + try { + await petition.save(); + } catch (err) { + console.log( + `Petition ${petition.id} failed to be updated at edit-petition` + ); + return next(err); + } + + return res.status(200).json({ general: "Success" }); +}; diff --git a/src/routes/petitions/index.js b/src/routes/petitions/index.js index c2de682..fb87cfe 100644 --- a/src/routes/petitions/index.js +++ b/src/routes/petitions/index.js @@ -1,19 +1,19 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPetition = require('./create-petition'); -const editPetition = require('./edit-petition'); -const listPetitions = require('./list-petitions'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listPetitions); -router.post('', isAuthenticated({ isOptional: false }), createPetition); -router.put( - '/:petitionId', - isAuthenticated({ isOptional: false }), - editPetition -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createPetition = require('./create-petition'); +const editPetition = require('./edit-petition'); +const listPetitions = require('./list-petitions'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listPetitions); +router.post('', isAuthenticated({ isOptional: false }), createPetition); +router.put( + '/:petitionId', + isAuthenticated({ isOptional: false }), + editPetition +); + +module.exports = router; diff --git a/src/routes/petitions/list-petitions.js b/src/routes/petitions/list-petitions.js index 838d0cb..5188a62 100644 --- a/src/routes/petitions/list-petitions.js +++ b/src/routes/petitions/list-petitions.js @@ -1,277 +1,277 @@ -const mongoose = require('mongoose'); - -const { compact } = require('lodash'); -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); -const { Event } = require('../../models/event'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - const userId = mongoose.Types.ObjectId(req.user.id); - - const petitionsQuery = { - state: { $in: ['accepted', 'pending', 'rejected'] } - }; - - if (queryParams.filter === 'sent') { - petitionsQuery.sender = userId; - } else { - // get the user's events - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - // get the user's teams - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - - let userEvents = []; - let userTeams = []; - try { - userEvents = await Promise.all(getUserEvents); - // remove null values from array - userEvents = compact(userEvents); - userTeams = await Promise.all(getUserTeams); - // remove null values from array - userTeams = compact(userTeams); - } catch (err) { - console.log('Events/Teams failed to be found at list-petitions'); - return next(err); - } - - const managedEvents = []; - userEvents.map(e => { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push(mongoose.Types.ObjectId(e.id)); - } - }); - - const managedTeams = []; - userTeams.map(t => { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push(mongoose.Types.ObjectId(t.id)); - } - }); - - petitionsQuery.$or = [ - { - $and: [ - { user: userId }, - { type: { $in: ['invite-user-event', 'invite-user-team'] } } - ] - }, - { - $and: [ - { event: { $in: managedEvents } }, - { type: { $in: ['request-team-event', 'request-user-event'] } } - ] - }, - { - $and: [ - { team: { $in: managedTeams } }, - { type: { $in: ['invite-team-event', 'request-user-team'] } } - ] - } - ]; - } - - const sortBy = '-createdAt'; - - let page = queryParams.page || 1; - const pageLimit = 12; - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - // Fetch data - const aggregateQuery = [ - { - $match: petitionsQuery - }, - { - $sort: { createdAt: -1 } - }, - { - $lookup: { - from: 'events', - let: { event: '$event' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$event'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - name: 1, - poster: 1 - } - } - ], - as: 'event' - } - }, - { - $unwind: { - path: '$event', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { sender: '$sender' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$sender'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'sender' - } - }, - { - $unwind: { - path: '$sender', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'teams', - let: { team: '$team' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$team'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'team' - } - }, - { - $unwind: { - path: '$team', - preserveNullAndEmptyArrays: true - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $unwind: { - path: '$user', - preserveNullAndEmptyArrays: true - } - }, - { - $project: { - _id: 0, - id: '$_id', - createdAt: 1, - event: 1, - message: 1, - sender: 1, - state: 1, - team: 1, - type: 1, - user: 1 - } - } - ]; - - // paginate - aggregateQuery.push( - { - $skip: page * pageLimit - }, - { - $limit: pageLimit - } - ); - - let petitions; - let total; - try { - [petitions, total] = await Promise.all([ - Petition.aggregate(aggregateQuery), - Petition.find(petitionsQuery).count() - ]); - } catch (err) { - console.log('Petitions failed to be found or count at list-petitions'); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page, - lastPage, - pageLimit, - total, - sortBy, - results: petitions - }); -}; +const mongoose = require('mongoose'); + +const { compact } = require('lodash'); +const { Petition } = require('../../models/petition'); +const { Team } = require('../../models/team'); +const { Event } = require('../../models/event'); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + const userId = new mongoose.Types.ObjectId(req.user.id); + + const petitionsQuery = { + state: { $in: ['accepted', 'pending', 'rejected'] } + }; + + if (queryParams.filter === 'sent') { + petitionsQuery.sender = userId; + } else { + // get the user's events + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + // get the user's teams + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + + let userEvents = []; + let userTeams = []; + try { + userEvents = await Promise.all(getUserEvents); + // remove null values from array + userEvents = compact(userEvents); + userTeams = await Promise.all(getUserTeams); + // remove null values from array + userTeams = compact(userTeams); + } catch (err) { + console.log('Events/Teams failed to be found at list-petitions'); + return next(err); + } + + const managedEvents = []; + userEvents.map((e) => { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push(new mongoose.Types.ObjectId(e.id)); + } + }); + + const managedTeams = []; + userTeams.map((t) => { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push(new mongoose.Types.ObjectId(t.id)); + } + }); + + petitionsQuery.$or = [ + { + $and: [ + { user: userId }, + { type: { $in: ['invite-user-event', 'invite-user-team'] } } + ] + }, + { + $and: [ + { event: { $in: managedEvents } }, + { type: { $in: ['request-team-event', 'request-user-event'] } } + ] + }, + { + $and: [ + { team: { $in: managedTeams } }, + { type: { $in: ['invite-team-event', 'request-user-team'] } } + ] + } + ]; + } + + const sortBy = '-createdAt'; + + let page = queryParams.page || 1; + const pageLimit = 12; + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + // Fetch data + const aggregateQuery = [ + { + $match: petitionsQuery + }, + { + $sort: { createdAt: -1 } + }, + { + $lookup: { + from: 'events', + let: { event: '$event' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$event'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + name: 1, + poster: 1 + } + } + ], + as: 'event' + } + }, + { + $unwind: { + path: '$event', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { sender: '$sender' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$sender'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'sender' + } + }, + { + $unwind: { + path: '$sender', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'teams', + let: { team: '$team' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$team'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + name: 1 + } + } + ], + as: 'team' + } + }, + { + $unwind: { + path: '$team', + preserveNullAndEmptyArrays: true + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $unwind: { + path: '$user', + preserveNullAndEmptyArrays: true + } + }, + { + $project: { + _id: 0, + id: '$_id', + createdAt: 1, + event: 1, + message: 1, + sender: 1, + state: 1, + team: 1, + type: 1, + user: 1 + } + } + ]; + + // paginate + aggregateQuery.push( + { + $skip: page * pageLimit + }, + { + $limit: pageLimit + } + ); + + let petitions; + let total; + try { + [petitions, total] = await Promise.all([ + Petition.aggregate(aggregateQuery), + Petition.countDocuments(petitionsQuery) + ]); + } catch (err) { + console.log('Petitions failed to be found or count at list-petitions'); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page, + lastPage, + pageLimit, + total, + sortBy, + results: petitions + }); +}; diff --git a/src/routes/petitions/validations.js b/src/routes/petitions/validations.js index fe683d3..03d0f2b 100644 --- a/src/routes/petitions/validations.js +++ b/src/routes/petitions/validations.js @@ -1,79 +1,79 @@ -const { isEmpty } = require('lodash'); -const { isMongoId } = require('validator'); - -const { Petition } = require('../../models/petition'); - -module.exports = { - validateCreatePetition(data) { - const errors = {}; - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if (data.message && typeof data.message !== 'string') { - errors.message = 'Should be a string'; - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - const petitionTypes = Petition.schema.path('type').enumValues; - if (!data.type) { - errors.type = 'Is required'; - } else if (typeof data.type !== 'string') { - errors.type = 'Should be a string'; - } else if (!petitionTypes.includes(data.type)) { - errors.type = 'Should be a valid type'; - } else if ( - data.type === 'invite-team-event' || - data.type === 'request-team-event' - ) { - if (!data.event) errors.event = 'Is required'; - if (!data.team) errors.team = 'Is required'; - } else if (data.type === 'invite-user-event') { - if (!data.event) errors.event = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-event' && !data.event) { - errors.event = 'Is required'; - } else if (data.type === 'invite-user-team') { - if (!data.team) errors.team = 'Is required'; - if (!data.user) errors.user = 'Is required'; - } else if (data.type === 'request-user-team' && !data.team) { - errors.team = 'Is required'; - } - - if (data.user) { - if (typeof data.user !== 'string') { - errors.user = 'Should be a string'; - } else if (!isMongoId(data.user)) { - errors.user = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditPetition(data) { - const errors = {}; - - const petitionStates = Petition.schema.path('state').enumValues; - if (!data.state) { - errors.state = 'Is required'; - } else if (!petitionStates.includes(data.state)) { - errors.state = 'Should be a valid state'; - } else if (data.state === 'pending') { - errors.state = 'Should be a different state'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isMongoId } = require('validator'); + +const { Petition } = require('../../models/petition'); + +module.exports = { + validateCreatePetition(data) { + const errors = {}; + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if (data.message && typeof data.message !== 'string') { + errors.message = 'Should be a string'; + } + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + const petitionTypes = Petition.schema.path('type').enumValues; + if (!data.type) { + errors.type = 'Is required'; + } else if (typeof data.type !== 'string') { + errors.type = 'Should be a string'; + } else if (!petitionTypes.includes(data.type)) { + errors.type = 'Should be a valid type'; + } else if ( + data.type === 'invite-team-event' || + data.type === 'request-team-event' + ) { + if (!data.event) errors.event = 'Is required'; + if (!data.team) errors.team = 'Is required'; + } else if (data.type === 'invite-user-event') { + if (!data.event) errors.event = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-event' && !data.event) { + errors.event = 'Is required'; + } else if (data.type === 'invite-user-team') { + if (!data.team) errors.team = 'Is required'; + if (!data.user) errors.user = 'Is required'; + } else if (data.type === 'request-user-team' && !data.team) { + errors.team = 'Is required'; + } + + if (data.user) { + if (typeof data.user !== 'string') { + errors.user = 'Should be a string'; + } else if (!isMongoId(data.user)) { + errors.user = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditPetition(data) { + const errors = {}; + + const petitionStates = Petition.schema.path('state').enumValues; + if (!data.state) { + errors.state = 'Is required'; + } else if (!petitionStates.includes(data.state)) { + errors.state = 'Should be a valid state'; + } else if (data.state === 'pending') { + errors.state = 'Should be a different state'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/photos/create-photo.js b/src/routes/photos/create-photo.js index 43fd66d..8db09f7 100644 --- a/src/routes/photos/create-photo.js +++ b/src/routes/photos/create-photo.js @@ -1,115 +1,115 @@ -const fs = require('fs'); -const util = require('util'); - -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const multer = require('multer'); -const randomstring = require('randomstring'); - -const { Photo } = require('../../models/photo'); - -jimp.prototype.getBufferAsync = util.promisify(jimp.prototype.getBuffer); - -module.exports = async (req, res, next) => { - const uploadPhoto = util.promisify( - multer({ - dest: '/tmp', - limits: { fileSize: 8388608 }, - fileFilter: (req, file, cb) => { - if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { - cb(null, true); - } else { - cb(new Error('Should have .jpeg or .png extension')); - } - } - }).single('photo') - ); - try { - await uploadPhoto(req, res); - } catch (err) { - return res.status(400).json({ photo: err.message }); - } - - if (!req.file) { - return res.status(400).json({ photo: 'Is required' }); - } - - let photoFile; - try { - photoFile = await jimp.read(req.file.path); - } catch (err) { - console.log('Photo failed to be read at create-photo'); - return next(err); - } - - if (req.body.isWide === 'true') { - photoFile.cover(640, 480).quality(85); - } else { - photoFile.cover(400, 400).quality(85); - } - - let photoBuffer; - try { - photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); - } catch (err) { - return next(err); - } - - const photoExtension = photoFile.getExtension(); - const photoFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${photoExtension}`; - - const s3 = new aws.S3(); - try { - await s3 - .putObject({ - ACL: 'public-read', - Body: photoBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: photoFile.getMIME(), - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be uploaded at create-photo'); - return next(err); - } - - fs.unlink(req.file.path); - - const photoData = { - fileName: photoFileName, - url: `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/photos/${photoFileName}`, - user: req.user.id - }; - - let photo; - try { - photo = await Photo.create(photoData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log('Photo failed to be created at create-photo'); - return next(err); - } - - const dataResponse = { - id: photo.id, - fileName: photo.fileName, - url: photo.url, - user: photo.user - }; - return res.status(201).json(dataResponse); -}; +const fs = require('fs'); + +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const multer = require('multer'); +const randomstring = require('randomstring'); + +const { Photo } = require('../../models/photo'); + +const upload = multer({ + dest: '/tmp', + limits: { fileSize: 8388608 }, + fileFilter: (req, file, cb) => { + if (/^image\/(jpe?g|png)$/i.test(file.mimetype)) { + cb(null, true); + } else { + cb(new Error('Should have .jpeg or .png extension')); + } + } +}).single('photo'); + +module.exports = async (req, res, next) => { + upload(req, res, async (err) => { + if (err) { + return res.status(400).json({ photo: err.message }); + } + + if (!req.file) { + return res.status(400).json({ photo: 'Is required' }); + } + + let photoFile; + try { + photoFile = await jimp.read(req.file.path); + } catch (err) { + console.log('Photo failed to be read at create-photo'); + return next(err); + } + + if (req.body.isWide === 'true') { + photoFile.cover(640, 480).quality(85); + } else { + photoFile.cover(400, 400).quality(85); + } + + let photoBuffer; + try { + photoBuffer = await photoFile.getBufferAsync(photoFile.getMIME()); + } catch (err) { + return next(err); + } + + const photoExtension = photoFile.getExtension(); + const photoFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${photoExtension}`; + + const s3 = new aws.S3(); + try { + await s3 + .putObject({ + ACL: 'public-read', + Body: photoBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: photoFile.getMIME(), + Key: `photos/${photoFileName}` + }) + .promise(); + } catch (err) { + console.log('Photo failed to be uploaded at create-photo'); + return next(err); + } + + fs.unlink(req.file.path, (err) => { + if (err) { + console.log('Failed to delete temporary file', err); + } + }); + + const photoData = { + fileName: photoFileName, + url: `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/photos/${photoFileName}`, + user: req.user.id + }; + + let photo; + try { + photo = await Photo.create(photoData); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log('Photo failed to be created at create-photo'); + return next(err); + } + + const dataResponse = { + id: photo.id, + fileName: photo.fileName, + url: photo.url, + user: photo.user + }; + return res.status(201).json(dataResponse); + }); +}; diff --git a/src/routes/photos/delete-photo.js b/src/routes/photos/delete-photo.js index fa78064..03152f1 100644 --- a/src/routes/photos/delete-photo.js +++ b/src/routes/photos/delete-photo.js @@ -1,47 +1,47 @@ -const aws = require('aws-sdk'); - -const { Photo } = require('../../models/photo'); - -module.exports = async (req, res, next) => { - const photoFileName = req.params.photoFileName; - - let photo; - try { - photo = await Photo.findOne({ fileName: photoFileName }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Photo not found' }); - } - - console.log(`Photo ${photoFileName} failed to be found at delete-photo`); - return next(err); - } - - if (photo) { - try { - await photo.remove(); - } catch (err) { - console.log( - `Photo ${photoFileName} failed to be deleted at delete-photo` - ); - return next(err); - } - } - - if (!photoFileName.includes('default')) { - const s3 = new aws.S3(); - try { - await s3 - .deleteObject({ - Bucket: process.env.AWS_S3_BUCKET, - Key: `photos/${photoFileName}` - }) - .promise(); - } catch (err) { - console.log('Photo failed to be deleted at delete-photo'); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const aws = require("aws-sdk"); + +const { Photo } = require("../../models/photo"); + +module.exports = async (req, res, next) => { + const photoFileName = req.params.photoFileName; + + let photo; + try { + photo = await Photo.findOne({ fileName: photoFileName }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Photo not found" }); + } + + console.log(`Photo ${photoFileName} failed to be found at delete-photo`); + return next(err); + } + + if (photo) { + try { + await photo.deleteOne({ fileName: photoFileName }); + } catch (err) { + console.log( + `Photo ${photoFileName} failed to be deleted at delete-photo` + ); + return next(err); + } + } + + if (!photoFileName.includes("default")) { + const s3 = new aws.S3(); + try { + await s3 + .deleteObject({ + Bucket: process.env.AWS_S3_BUCKET, + Key: `photos/${photoFileName}`, + }) + .promise(); + } catch (err) { + console.log("Photo failed to be deleted at delete-photo"); + return next(err); + } + } + + return res.status(204).json({ general: "Success" }); +}; diff --git a/src/routes/photos/index.js b/src/routes/photos/index.js index bd00f27..d5640d2 100644 --- a/src/routes/photos/index.js +++ b/src/routes/photos/index.js @@ -1,17 +1,17 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createPhoto = require('./create-photo'); -const deletePhoto = require('./delete-photo'); - -const router = new express.Router(); - -router.post('', isAuthenticated({ isOptional: false }), createPhoto); -router.delete( - '/:photoFileName', - isAuthenticated({ isOptional: false }), - deletePhoto -); - -module.exports = router; +const express = require("express"); + +const { isAuthenticated } = require("../../helpers"); + +const createPhoto = require("./create-photo"); +const deletePhoto = require("./delete-photo"); + +const router = new express.Router(); + +router.post("", isAuthenticated({ isOptional: false }), createPhoto); +router.delete( + "/:photoFileName", + isAuthenticated({ isOptional: false }), + deletePhoto +); + +module.exports = router; diff --git a/src/routes/reviews/ban-review.js b/src/routes/reviews/ban-review.js index 6e97ee9..227507e 100644 --- a/src/routes/reviews/ban-review.js +++ b/src/routes/reviews/ban-review.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at ban-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - review.isBanned = true; - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at ban-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at ban-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + review.isBanned = true; + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at ban-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/create-ai-review.js b/src/routes/reviews/create-ai-review.js new file mode 100644 index 0000000..2131120 --- /dev/null +++ b/src/routes/reviews/create-ai-review.js @@ -0,0 +1,58 @@ +const OPENAI = require("openai"); +const sytemInstruction = `You are an assistant that writes a concise, natural, and helpful accessibility review summary for a location based on the answers given. The answers are boolean or null values representing accessibility features of the location. Use the information below to generate a short review that a person might write as a review comment. Mention only the positive and negative aspects explicitly answered true or false. Ignore any null or unknown fields. +the comment shouldn't be greater than 70 words. comment should only mention the features that are answered true. + +Use these guidelines to form your comment: +- If "hasWideEntrance" is false, but "hasSecondEntry" is true, mention that the main entrance was not wide enough, but there was a second entrance that was accessible. +- If "hasWashroom" is true, mention that the location has accessible restrooms that were comfortable to use. +- If "hasPermanentRamp" is true, mention the presence of a permanent ramp. +- If "multipleFloors" is true and "hasAccessibleElevator" is true, mention that accessible elevators are available to access multiple floors. +- Mention parking accessibility if "hasParking" or "hasWheelchairParking" is true. +- Include other features if answered true or false, focusing on accessibility and ease of use. + +Answer in a friendly and informative tone, as if a person is giving a brief review summary.`; + +module.exports = async (req, res,) => { + try { + const openai = new OPENAI({ + apiKey:process.env.OPENAI_API_KEY, + }); + const response = await openai.chat.completions.create({ + model: "gpt-4", + messages: [ + { + role: "system", + content: sytemInstruction, + }, + { + role: "user", + content: ` + Here are the answers: + steps: ${req?.body?.steps} + has1Step: ${req?.body?.has1Step} + has2Step: ${req?.body?.has2Step} + hasWideEntrance: ${req?.body?.hasWideEntrance} + hasParking: ${req?.body?.hasParking} + hasSecondEntry: ${req?.body?.hasSecondEntry} + hasPermanentRamp: ${req?.body?.hasPermanentRamp} + multipleFloors: ${req.body?.multipleFloors} + hasAccessibleElevator: ${req.body?.hasAccessibleElevator} + hasWellLit: ${req.body?.hasWellLit} + brightLightTitle: ${req.body?.brightLightTitle} + hasPortableRamp: ${req.body?.hasPortableRamp} + hasSupportAroundToilet: ${req?.body?.hasSupportAroundToilet} + hasWashroom: ${req?.body?.hasWashroom} + hasWheelchairParking: ${req?.body?.hasWheelchairParking}`, + }, + ], + temperature: 0, + max_tokens: 1000, + top_p: 1, + }); + return res + .status(200) + .json({ general: "Success", data: response.choices[0].message.content }); + } catch (error) { + throw String(error); + } +}; diff --git a/src/routes/reviews/create-review.js b/src/routes/reviews/create-review.js index ff61b71..56619e3 100644 --- a/src/routes/reviews/create-review.js +++ b/src/routes/reviews/create-review.js @@ -1,557 +1,606 @@ -const axios = require('axios'); -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Photo } = require('../../models/photo'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - console.log('body: ', req.body); - const { errors, isValid } = validateCreateEditReview(req.body); - if (!isValid) return res.status(400).json(errors); - - const data = { - //new expanded fields - hasPermanentRamp: req.body.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: req.body.hasWideEntrance, - hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, - hasAccessibleElevator: req.body.hasAccessibleElevator, - hasInteriorRamp: req.body.hasInteriorRamp, - hasSwingOutDoor: req.body.hasSwingOutDoor, - hasLargeStall: req.body.hasLargeStall, - hasSupportAroundToilet: req.body.hasSupportAroundToilet, - hasLoweredSinks: req.body.hasLoweredSinks, - interiorScore: req.body.interiorScore, - _isScoreConverted: true, - - //original fields - allowsGuideDog: req.body.allowsGuideDog, - //bathroomScore: req.body.bathroomScore, - comments: req.body.comments, - //entryScore: req.body.entryScore, - event: req.body.event, - hasParking: req.body.hasParking, - hasSecondEntry: req.body.hasSecondEntry, - hasWellLit: req.body.hasWellLit, - isQuiet: req.body.isQuiet, - isSpacious: req.body.isSpacious, - steps: req.body.steps, - team: req.body.team, - user: req.user.id - }; - - let event; - if (data.event) { - try { - event = await Event.findOne({ _id: data.event, isArchived: false }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at create-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if ( - !event.participants.find(p => p.toString() === data.user) && - !event.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment() - .startOf('day') - .utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - } - - let team; - if (data.team) { - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at create-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if ( - !team.members.find(m => m.toString() === data.user) && - !team.managers.find(m => m.toString() === data.user) - ) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - } - - const placeId = req.body.place; - let venue; - try { - venue = await Venue.findOne({ placeId }); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at create-review` - ); - return next(err); - } - - if (!venue) { - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log( - `Place ${placeId} failed to be found at create-review, after Google search` - ); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const venueData = { - address: placeData.formatted_address, - location: { - coordinates: [ - placeData.geometry.location.lng, - placeData.geometry.location.lat - ] - }, - name: placeData.name, - placeId, - types: placeData.types - }; - - try { - venue = await Venue.create(venueData); - } catch (err) { - console.log( - `Venue failed to be created at create-review.\nData: ${JSON.stringify( - venueData - )}` - ); - return next(err); - } - } - data.venue = venue.id; - - let review; - try { - review = await Review.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Review failed to be created at create-review.\nData: ${JSON.stringify( - data - )}` - ); - return next(err); - } - - // Sample review Obj - /* - _isScoreConverted: false, - isBanned: false, - voters: [], - _id: 5e853db2587b2740c501f12e, - hasAccessibleElevator: true, - hasInteriorRamp: true, - hasSwingOutDoor: false, - hasLargeStall: false, - user: 5e14e8584701fb22ade354e9, - venue: 5e3da8d56d958200424ffdfe, - complaints: [], - createdAt: 2020-04-02T01:19:46.508Z, - updatedAt: 2020-04-02T01:19:46.508Z, - __v: 0 - */ - - //subtracts out the 10 standard fields to determine - var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; - req.user.reviewFieldsAmount = - req.user.reviewFieldsAmount + reviewedFieldsCount; - req.user.reviewsAmount = req.user.reviewsAmount + 1; - req.user.updatedAt = moment.utc().toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log( - `User ${ - req.user.id - } failed to be updated at create-review, after updated review count` - ); - return next(err); - } - - if (event) { - event.reviewsAmount = event.reviewsAmount + 1; - event.updatedAt = moment.utc().toDate(); - try { - await event.save(); - } catch (err) { - console.log( - `Event ${event.id} failed to be updated at create-review, after event` - ); - return next(err); - } - } - - if (req.body.photo) { - let photo; - try { - photo = await Photo.findOne({ url: req.body.photo }); - } catch (err) { - console.log( - `Photo ${req.body.photo} failed to be found at create-review` - ); - return next(err); - } - - if (!photo) { - return res.status(404).json({ photo: 'Not found' }); - } - - venue.photos = [...venue.photos, photo.id]; - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, after photos` - ); - return next(err); - } - } - - if (team) { - team.reviewsAmount = team.reviewsAmount + 1; - team.updatedAt = moment.utc().toDate(); - try { - await team.save(); - } catch (err) { - console.log( - `Team ${team.id} failed to be updated at create-review, after team` - ); - return next(err); - } - } - - // - //new expanded fields - // - if (typeof review.hasPermanentRamp !== 'undefined') { - venue.hasPermanentRamp = { - yes: review.hasPermanentRamp - ? venue.hasPermanentRamp.yes + 1 - : venue.hasPermanentRamp.yes, - no: review.hasPermanentRamp - ? venue.hasPermanentRamp.no - : venue.hasPermanentRamp.no + 1 - }; - } - - if (typeof review.hasPortableRamp !== 'undefined') { - venue.hasPortableRamp = { - yes: review.hasPortableRamp - ? venue.hasPortableRamp.yes + 1 - : venue.hasPortableRamp.yes, - no: review.hasPortableRamp - ? venue.hasPortableRamp.no - : venue.hasPortableRamp.no + 1 - }; - } - - if (typeof review.hasWideEntrance !== 'undefined') { - venue.hasWideEntrance = { - yes: review.hasWideEntrance - ? venue.hasWideEntrance.yes + 1 - : venue.hasWideEntrance.yes, - no: review.hasWideEntrance - ? venue.hasWideEntrance.no - : venue.hasWideEntrance.no + 1 - }; - } - - if (typeof review.hasAccessibleTableHeight !== 'undefined') { - venue.hasAccessibleTableHeight = { - yes: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.yes + 1 - : venue.hasAccessibleTableHeight.yes, - no: review.hasAccessibleTableHeight - ? venue.hasAccessibleTableHeight.no - : venue.hasAccessibleTableHeight.no + 1 - }; - } - - if (typeof review.hasAccessibleElevator !== 'undefined') { - venue.hasAccessibleElevator = { - yes: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.yes + 1 - : venue.hasAccessibleElevator.yes, - no: review.hasAccessibleElevator - ? venue.hasAccessibleElevator.no - : venue.hasAccessibleElevator.no + 1 - }; - } - - if (typeof review.hasInteriorRamp !== 'undefined') { - venue.hasInteriorRamp = { - yes: review.hasInteriorRamp - ? venue.hasInteriorRamp.yes + 1 - : venue.hasInteriorRamp.yes, - no: review.hasInteriorRamp - ? venue.hasInteriorRamp.no - : venue.hasInteriorRamp.no + 1 - }; - } - - if (typeof review.hasSwingOutDoor !== 'undefined') { - venue.hasSwingOutDoor = { - yes: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.yes + 1 - : venue.hasSwingOutDoor.yes, - no: review.hasSwingOutDoor - ? venue.hasSwingOutDoor.no - : venue.hasSwingOutDoor.no + 1 - }; - } - - if (typeof review.hasLargeStall !== 'undefined') { - venue.hasLargeStall = { - yes: review.hasLargeStall - ? venue.hasLargeStall.yes + 1 - : venue.hasLargeStall.yes, - no: review.hasLargeStall - ? venue.hasLargeStall.no - : venue.hasLargeStall.no + 1 - }; - } - - if (typeof review.hasSupportAroundToilet !== 'undefined') { - venue.hasSupportAroundToilet = { - yes: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.yes + 1 - : venue.hasSupportAroundToilet.yes, - no: review.hasSupportAroundToilet - ? venue.hasSupportAroundToilet.no - : venue.hasSupportAroundToilet.no + 1 - }; - } - - if (typeof review.hasLoweredSinks !== 'undefined') { - venue.hasLoweredSinks = { - yes: review.hasLoweredSinks - ? venue.hasLoweredSinks.yes + 1 - : venue.hasLoweredSinks.yes, - no: review.hasLoweredSinks - ? venue.hasLoweredSinks.no - : venue.hasLoweredSinks.no + 1 - }; - } - - // - //original fields - // - if (typeof review.allowsGuideDog !== 'undefined') { - venue.allowsGuideDog = { - yes: review.allowsGuideDog - ? venue.allowsGuideDog.yes + 1 - : venue.allowsGuideDog.yes, - no: review.allowsGuideDog - ? venue.allowsGuideDog.no - : venue.allowsGuideDog.no + 1 - }; - } - - /* - if (typeof review.bathroomScore !== 'undefined') { - if (venue.bathroomReviews > 0) { - venue.bathroomScore = - (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / - (venue.bathroomReviews + 1); - venue.bathroomReviews += 1; - } else { - venue.bathroomScore = review.bathroomScore; - venue.bathroomReviews = 1; - } - } - - if (venue.entryReviews > 0) { - venue.entryScore = - (venue.entryScore * venue.entryReviews + review.entryScore) / - (venue.entryReviews + 1); - venue.entryReviews += 1; - } else { - venue.entryScore = review.entryScore; - venue.entryReviews = 1; - } - */ - - if (typeof review.hasParking !== 'undefined') { - venue.hasParking = { - yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, - no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1 - }; - } - - if (typeof review.hasSecondEntry !== 'undefined') { - venue.hasSecondEntry = { - yes: review.hasSecondEntry - ? venue.hasSecondEntry.yes + 1 - : venue.hasSecondEntry.yes, - no: review.hasSecondEntry - ? venue.hasSecondEntry.no - : venue.hasSecondEntry.no + 1 - }; - } - - if (typeof review.hasWellLit !== 'undefined') { - venue.hasWellLit = { - yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, - no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1 - }; - } - - if (typeof review.isQuiet !== 'undefined') { - venue.isQuiet = { - yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, - no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1 - }; - } - - if (typeof review.isSpacious !== 'undefined') { - venue.isSpacious = { - yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, - no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1 - }; - } - - venue.reviews = [...venue.reviews, review.id]; - - if (typeof review.steps !== 'undefined') { - venue.steps = { - zero: review.steps === 0 ? venue.steps.zero + 1 : venue.steps.zero, - one: review.steps === 1 ? venue.steps.one + 1 : venue.steps.one, - two: review.steps === 2 ? venue.steps.two + 1 : venue.steps.two, - moreThanTwo: - review.steps === 3 - ? venue.steps.moreThanTwo + 1 - : venue.steps.moreThanTwo - }; - } - - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - //console.log('entrance score: ', scoring); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - //console.log('interior score: ', scoring); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - //console.log('restroom score: ', scoring); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - //console.log('venue: ', venue); - - try { - await venue.save(); - } catch (err) { - console.log( - `Venue ${venue.id} failed to be updated at create-review, at final step` - ); - return next(err); - } - - const dataResponse = { - //new expanded fields - hasPermanentRamp: review.hasPermanentRamp, - hasPortableRamp: req.body.hasPortableRamp, - hasWideEntrance: review.hasWideEntrance, - hasAccessibleTableHeight: review.hasAccessibleTableHeight, - hasAccessibleElevator: review.hasAccessibleElevator, - hasInteriorRamp: review.hasInteriorRamp, - hasSwingOutDoor: review.hasSwingOutDoor, - hasLargeStall: review.hasLargeStall, - hasSupportAroundToilet: review.hasSupportAroundToilet, - hasLoweredSinks: review.hasLoweredSinks, - - /* - entranceScore: review.entranceScore, - entranceGlyph: review.entryGlyph, - interiorScore: review.interiorScore, - interiorGlyph: review.interiorGlyph, - restroomScore: review.restroomScore, - restroomGlyph: review.restroomGlyph, - */ - - //original fields - id: review.id, - allowsGuideDog: review.allowsGuideDog, - //bathroomScore: review.bathroomScore, - comments: review.comments, - //entryScore: review.entryScore, - event: review.event, - hasParking: review.hasParking, - hasSecondEntry: review.hasSecondEntry, - hasWellLit: review.hasWellLit, - isQuiet: review.isQuiet, - isSpacious: review.isSpacious, - steps: review.steps, - team: review.team, - user: review.user, - userReviewFieldsAmount: req.user.reviewFieldsAmount, - userReviewsAmount: req.user.reviewsAmount, - venue: review.venue - }; - return res.status(201).json(dataResponse); -}; +const axios = require("axios"); +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Photo } = require("../../models/photo"); +const { Review } = require("../../models/review"); +const { Team } = require("../../models/team"); +const { Venue } = require("../../models/venue"); + +const { validateCreateEditReview } = require("./validations"); +const venueReviewSummary = require("../../helpers/venue-review-summary.js"); + +module.exports = async (req, res, next) => { + // const { errors, isValid } = validateCreateEditReview(req.body); + // if (!isValid) return res.status(400).json(errors); + + const data = { + // existing fields + hasParking: req.body.hasParking, + hasWellLit: req.body.hasWellLit, + steps: req.body.steps, + hasWideEntrance: req.body.hasWideEntrance, + hasAccessibleElevator: req.body.hasAccessibleElevator, + hasSupportAroundToilet: req.body.hasSupportAroundToilet, + // new added fields + has2Step: req.body.has2Step, + has1Step: req.body.has1Step, + multipleFloors: req.body.multipleFloors, + hasWashroom: req.body.hasWashroom, + brightLightTitle: req.body.brightLightTitle, + hasSecondEntry: req.body.hasSecondEntry, + hasPermanentRamp: req.body.hasPermanentRamp, + hasLoweredSinks: req.body.hasLoweredSinks, + hasPortableRamp: req.body.hasPortableRamp, + hasWheelchairParking:req.body.hasWheelchairParking, + + // hasAccessibleTableHeight: req.body.hasAccessibleTableHeight, + // hasInteriorRamp: req.body.hasInteriorRamp, + // hasSwingOutDoor: req.body.hasSwingOutDoor, + // hasLargeStall: req.body.hasLargeStall, + // interiorScore: req.body.interiorScore, + // _isScoreConverted: true, + // allowsGuideDog: req.body.allowsGuideDog, + // isQuiet: req.body.isQuiet, + // isSpacious: req.body.isSpacious, + // extra fields + event: req.body.event, + team: req.body.team, + user: req.user.id, + comments: req.body.comments, + }; + + + let event; + if (data.event) { + try { + event = await Event.findOne({ _id: data.event, isArchived: false }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at create-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: "Event not found" }); + } + + if ( + !event.participants.find((p) => p.toString() === data.user) && + !event.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ event: "You are not a participant of this event" }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment().startOf("day").utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: "Event has not started yet" }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: "Event has already finished" }); + } + } + + let team; + if (data.team) { + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at create-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: "Team not found" }); + } + + if ( + !team.members.find((m) => m.toString() === data.user) && + !team.managers.find((m) => m.toString() === data.user) + ) { + return res + .status(400) + .json({ team: "You are not a member of this team" }); + } + } + + const placeId = req.body.place; + let venue; + try { + venue = await Venue.findOne({ placeId }); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at create-review` + ); + return next(err); + } + + if (!venue) { + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log( + `Place ${placeId} failed to be found at create-review, after Google search` + ); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== "OK") { + return res.status(404).json({ general: "Place not found" }); + } + + const placeData = response.data.result; + const venueData = { + address: placeData.formatted_address, + location: { + coordinates: [ + placeData.geometry.location.lng, + placeData.geometry.location.lat, + ], + }, + name: placeData.name, + placeId, + types: placeData.types, + }; + + try { + venue = await Venue.create(venueData); + } catch (err) { + console.log( + `Venue failed to be created at create-review.\nData: ${JSON.stringify( + venueData + )}` + ); + return next(err); + } + } + data.venue = venue.id; + + let review; + try { + review = await Review.create(data); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Review failed to be created at create-review.\nData: ${JSON.stringify( + data + )}` + ); + return next(err); + } + + // Sample review Obj + /* + _isScoreConverted: false, + isBanned: false, + voters: [], + _id: 5e853db2587b2740c501f12e, + hasAccessibleElevator: true, + hasInteriorRamp: true, + hasSwingOutDoor: false, + hasLargeStall: false, + user: 5e14e8584701fb22ade354e9, + venue: 5e3da8d56d958200424ffdfe, + complaints: [], + createdAt: 2020-04-02T01:19:46.508Z, + updatedAt: 2020-04-02T01:19:46.508Z, + __v: 0 + */ + + //subtracts out the 10 standard fields to determine + var reviewedFieldsCount = Object.keys(review.toObject()).length - 10; + req.user.reviewFieldsAmount = + req.user.reviewFieldsAmount + reviewedFieldsCount; + req.user.reviewsAmount = req.user.reviewsAmount + 1; + req.user.updatedAt = moment.utc().toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log( + `User ${ + req.user.id + } failed to be updated at create-review, after updated review count` + ); + return next(err); + } + + if (event) { + event.reviewsAmount = event.reviewsAmount + 1; + event.updatedAt = moment.utc().toDate(); + try { + await event.save(); + } catch (err) { + console.log( + `Event ${event.id} failed to be updated at create-review, after event` + ); + return next(err); + } + } + + if (req.body.photo) { + let photo; + try { + photo = await Photo.findOne({ url: req.body.photo }); + } catch (err) { + console.log( + `Photo ${req.body.photo} failed to be found at create-review` + ); + return next(err); + } + + if (!photo) { + return res.status(404).json({ photo: "Not found" }); + } + + venue.photos = [...venue.photos, photo.id]; + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, after photos` + ); + return next(err); + } + } + + if (team) { + team.reviewsAmount = team.reviewsAmount + 1; + team.updatedAt = moment.utc().toDate(); + try { + await team.save(); + } catch (err) { + console.log( + `Team ${team.id} failed to be updated at create-review, after team` + ); + return next(err); + } + } + + // + //new expanded fields + // + // hasParking: req.body.hasParking, + // hasWellLit: req.body.hasWellLit, + // steps: req.body.steps, + // hasWideEntrance: req.body.hasWideEntrance, + // hasAccessibleElevator: req.body.hasAccessibleElevator, + // hasSupportAroundToilet: req.body.hasSupportAroundToilet, + // // new added fields + // has2Step:req.body.has2Step , + // multipleFloors: req.body.multipleFloors, + // hasWashroom: req.body.hasWashroom, + // brightLightTitle: req.body.brightLightTitle, + // has1Step: req.body.has1Step, + + const keys = [ + "hasParking", + "hasWellLit", + "hasWideEntrance", + "hasAccessibleElevator", + "hasSupportAroundToilet", + "multipleFloors", + "hasWashroom", + "brightLightTitle", + "hasSecondEntry", + "hasPermanentRamp", + "hasLoweredSinks", + "hasWheelchairParking", + "hasPortableRamp", + ]; + + keys.forEach((key) => { + if (typeof review[key] !== "undefined") { + venue[key] = { + yes: venue[key].yes + (review[key] ? 1 : 0), + no: venue[key].no + (review[key] ? 0 : 1), + }; + } + }); + + // if (typeof review.hasPermanentRamp !== "undefined") { + // venue.hasPermanentRamp = { + // yes: review.hasPermanentRamp + // ? venue.hasPermanentRamp.yes + 1 + // : venue.hasPermanentRamp.yes, + // no: review.hasPermanentRamp + // ? venue.hasPermanentRamp.no + // : venue.hasPermanentRamp.no + 1, + // }; + // } + + // if (typeof review.hasPermanentRamp !== "undefined") { + // venue.hasPermanentRamp = { + // yes: review.hasPermanentRamp + // ? venue.hasPermanentRamp.yes + 1 + // : venue.hasPermanentRamp.yes, + // no: review.hasPermanentRamp + // ? venue.hasPermanentRamp.no + // : venue.hasPermanentRamp.no + 1, + // }; + // } + + // if (typeof review.hasPortableRamp !== "undefined") { + // venue.hasPortableRamp = { + // yes: review.hasPortableRamp + // ? venue.hasPortableRamp.yes + 1 + // : venue.hasPortableRamp.yes, + // no: review.hasPortableRamp + // ? venue.hasPortableRamp.no + // : venue.hasPortableRamp.no + 1, + // }; + // } + + // if (typeof review.hasWideEntrance !== "undefined") { + // venue.hasWideEntrance = { + // yes: review.hasWideEntrance + // ? venue.hasWideEntrance.yes + 1 + // : venue.hasWideEntrance.yes, + // no: review.hasWideEntrance + // ? venue.hasWideEntrance.no + // : venue.hasWideEntrance.no + 1, + // }; + // } + + // if (typeof review.hasAccessibleTableHeight !== "undefined") { + // venue.hasAccessibleTableHeight = { + // yes: review.hasAccessibleTableHeight + // ? venue.hasAccessibleTableHeight.yes + 1 + // : venue.hasAccessibleTableHeight.yes, + // no: review.hasAccessibleTableHeight + // ? venue.hasAccessibleTableHeight.no + // : venue.hasAccessibleTableHeight.no + 1, + // }; + // } + + // if (typeof review.hasAccessibleElevator !== "undefined") { + // venue.hasAccessibleElevator = { + // yes: review.hasAccessibleElevator + // ? venue.hasAccessibleElevator.yes + 1 + // : venue.hasAccessibleElevator.yes, + // no: review.hasAccessibleElevator + // ? venue.hasAccessibleElevator.no + // : venue.hasAccessibleElevator.no + 1, + // }; + // } + + // if (typeof review.hasInteriorRamp !== "undefined") { + // venue.hasInteriorRamp = { + // yes: review.hasInteriorRamp + // ? venue.hasInteriorRamp.yes + 1 + // : venue.hasInteriorRamp.yes, + // no: review.hasInteriorRamp + // ? venue.hasInteriorRamp.no + // : venue.hasInteriorRamp.no + 1, + // }; + // } + + // if (typeof review.hasSwingOutDoor !== "undefined") { + // venue.hasSwingOutDoor = { + // yes: review.hasSwingOutDoor + // ? venue.hasSwingOutDoor.yes + 1 + // : venue.hasSwingOutDoor.yes, + // no: review.hasSwingOutDoor + // ? venue.hasSwingOutDoor.no + // : venue.hasSwingOutDoor.no + 1, + // }; + // } + + // if (typeof review.hasLargeStall !== "undefined") { + // venue.hasLargeStall = { + // yes: review.hasLargeStall + // ? venue.hasLargeStall.yes + 1 + // : venue.hasLargeStall.yes, + // no: review.hasLargeStall + // ? venue.hasLargeStall.no + // : venue.hasLargeStall.no + 1, + // }; + // } + + // if (typeof review.hasSupportAroundToilet !== "undefined") { + // venue.hasSupportAroundToilet = { + // yes: review.hasSupportAroundToilet + // ? venue.hasSupportAroundToilet.yes + 1 + // : venue.hasSupportAroundToilet.yes, + // no: review.hasSupportAroundToilet + // ? venue.hasSupportAroundToilet.no + // : venue.hasSupportAroundToilet.no + 1, + // }; + // } + + // if (typeof review.hasLoweredSinks !== "undefined") { + // venue.hasLoweredSinks = { + // yes: review.hasLoweredSinks + // ? venue.hasLoweredSinks.yes + 1 + // : venue.hasLoweredSinks.yes, + // no: review.hasLoweredSinks + // ? venue.hasLoweredSinks.no + // : venue.hasLoweredSinks.no + 1, + // }; + // } + + // + //original fields + // + // if (typeof review.allowsGuideDog !== "undefined") { + // venue.allowsGuideDog = { + // yes: review.allowsGuideDog + // ? venue.allowsGuideDog.yes + 1 + // : venue.allowsGuideDog.yes, + // no: review.allowsGuideDog + // ? venue.allowsGuideDog.no + // : venue.allowsGuideDog.no + 1, + // }; + // } + + /* + if (typeof review.bathroomScore !== 'undefined') { + if (venue.bathroomReviews > 0) { + venue.bathroomScore = + (venue.bathroomScore * venue.bathroomReviews + review.bathroomScore) / + (venue.bathroomReviews + 1); + venue.bathroomReviews += 1; + } else { + venue.bathroomScore = review.bathroomScore; + venue.bathroomReviews = 1; + } + } + + if (venue.entryReviews > 0) { + venue.entryScore = + (venue.entryScore * venue.entryReviews + review.entryScore) / + (venue.entryReviews + 1); + venue.entryReviews += 1; + } else { + venue.entryScore = review.entryScore; + venue.entryReviews = 1; + } + */ + + // if (typeof review.hasParking !== "undefined") { + // venue.hasParking = { + // yes: review.hasParking ? venue.hasParking.yes + 1 : venue.hasParking.yes, + // no: review.hasParking ? venue.hasParking.no : venue.hasParking.no + 1, + // }; + // } + + // if (typeof review.hasSecondEntry !== "undefined") { + // venue.hasSecondEntry = { + // yes: review.hasSecondEntry + // ? venue.hasSecondEntry.yes + 1 + // : venue.hasSecondEntry.yes, + // no: review.hasSecondEntry + // ? venue.hasSecondEntry.no + // : venue.hasSecondEntry.no + 1, + // }; + // } + + // if (typeof review.hasWellLit !== "undefined") { + // venue.hasWellLit = { + // yes: review.hasWellLit ? venue.hasWellLit.yes + 1 : venue.hasWellLit.yes, + // no: review.hasWellLit ? venue.hasWellLit.no : venue.hasWellLit.no + 1, + // }; + // } + + // if (typeof review.isQuiet !== "undefined") { + // venue.isQuiet = { + // yes: review.isQuiet ? venue.isQuiet.yes + 1 : venue.isQuiet.yes, + // no: review.isQuiet ? venue.isQuiet.no : venue.isQuiet.no + 1, + // }; + // } + + // if (typeof review.isSpacious !== "undefined") { + // venue.isSpacious = { + // yes: review.isSpacious ? venue.isSpacious.yes + 1 : venue.isSpacious.yes, + // no: review.isSpacious ? venue.isSpacious.no : venue.isSpacious.no + 1, + // }; + // } + + venue.reviews = [...venue.reviews, review.id]; + + if (typeof review.steps !== "undefined") { + venue.steps = { + zero: review.steps ? 1 : 0, + one: review.has1Step ? 1 : 0, + two: review.has2Step ? 1 : 0, + moreThanTwo: review.has2Step ? 1 : 0, + }; + } + + // let scoring; + // //calculate entranceScore, glyphs + // scoring = venueReviewSummary.calculateRatingLevel("entrance", venue); + // //console.log('entrance score: ', scoring); + // venue.entranceScore = scoring.ratingLevel; + // venue.entranceGlyphs = scoring.ratingGlyphs; + + // //calculate interiorScore, glyphs + // scoring = venueReviewSummary.calculateRatingLevel("interior", venue); + // //console.log('interior score: ', scoring); + // venue.interiorScore = scoring.ratingLevel; + // venue.interiorGlyphs = scoring.ratingGlyphs; + + // //calculate restroomScore, glyphs + // scoring = venueReviewSummary.calculateRatingLevel("restroom", venue); + // //console.log('restroom score: ', scoring); + // venue.restroomScore = scoring.ratingLevel; + // venue.restroomGlyphs = scoring.ratingGlyphs; + + // venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + // venue.entranceScore, + // venue.interiorScore, + // venue.restroomScore + // ); + + //console.log('venue: ', venue); + + try { + await venue.save(); + } catch (err) { + console.log( + `Venue ${venue.id} failed to be updated at create-review, at final step` + ); + return next(err); + } + + const dataResponse = { + //new expanded fields + hasPermanentRamp: review.hasPermanentRamp, + hasPortableRamp: req.body.hasPortableRamp, + hasWideEntrance: review.hasWideEntrance, + hasAccessibleTableHeight: review.hasAccessibleTableHeight, + hasAccessibleElevator: review.hasAccessibleElevator, + hasInteriorRamp: review.hasInteriorRamp, + hasSwingOutDoor: review.hasSwingOutDoor, + hasLargeStall: review.hasLargeStall, + hasSupportAroundToilet: review.hasSupportAroundToilet, + hasLoweredSinks: review.hasLoweredSinks, + + /* + entranceScore: review.entranceScore, + entranceGlyph: review.entryGlyph, + interiorScore: review.interiorScore, + interiorGlyph: review.interiorGlyph, + restroomScore: review.restroomScore, + restroomGlyph: review.restroomGlyph, + */ + + //original fields + id: review.id, + allowsGuideDog: review.allowsGuideDog, + //bathroomScore: review.bathroomScore, + comments: review.comments, + //entryScore: review.entryScore, + event: review.event, + hasParking: review.hasParking, + hasSecondEntry: review.hasSecondEntry, + hasWellLit: review.hasWellLit, + isQuiet: review.isQuiet, + isSpacious: review.isSpacious, + steps: review.steps, + team: review.team, + user: review.user, + userReviewFieldsAmount: req.user.reviewFieldsAmount, + userReviewsAmount: req.user.reviewsAmount, + venue: review.venue, + }; + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/reviews/edit-review.js b/src/routes/reviews/edit-review.js index dd59ebf..251c2d5 100644 --- a/src/routes/reviews/edit-review.js +++ b/src/routes/reviews/edit-review.js @@ -1,217 +1,217 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Event } = require('../../models/event'); -const { Review } = require('../../models/review'); -const { Team } = require('../../models/team'); -const { Venue } = require('../../models/venue'); - -const { validateCreateEditReview } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }).select( - '-__v -createdAt -updatedAt' - ); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at edit-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - if (review.user.toString() !== req.user.id) { - return res - .status(423) - .json({ general: 'You cannot edit someone else review' }); - } - - let venue; - try { - venue = await Venue.findOne({ - _id: review.venue.toString(), - isArchived: false - }); - } catch (err) { - console.log( - `Venue ${review.venue.toString()} failed to be found at edit-review` - ); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Review venue not found' }); - } - - const data = pick(req.body, [ - //new expanded fields - 'hasPermanentRamp', - 'hasPortableRamp', - 'hasWideEntrance', - 'hasAccessibleTableHeight', - 'hasAccessibleElevator', - 'hasInteriorRamp', - 'hasSwingOutDoor', - 'hasLargeStall', - 'hasSupportAroundToilet', - 'hasLoweredSinks', - - //original fields - //'bathroomScore', - 'comments', - //'entryScore', - 'event', - 'guideDog', - 'parking', - 'quiet', - 'ramp', - 'secondEntry', - 'spacious', - 'steps', - 'team', - 'wellLit' - ]); - const { errors, isValid } = validateCreateEditReview(data); - - if (!isValid) { - return res.status(400).json(errors); - } - - //review.bathroomScore = data.bathroomScore || review.bathroomScore; - review.comments = data.comments || review.comments; - //review.entryScore = data.entryScore || review.entryScore; - - if (data.event) { - let event; - try { - event = await Event.findOne({ _id: data.event }); - } catch (err) { - console.log(`Event ${data.event} failed to be found at edit-review`); - return next(err); - } - - if (!event) { - return res.status(404).json({ event: 'Event not found' }); - } - - if (!event.participants.find(p => p.toString() === req.user.id)) { - return res - .status(400) - .json({ event: 'You are not a participant of this event' }); - } - - const startDate = moment(event.startDate).utc(); - const endDate = moment(event.endDate).utc(); - const today = moment.utc(); - if (startDate.isAfter(today)) { - return res.status(400).json({ event: 'Event has not started yet' }); - } else if (endDate.isBefore(today)) { - return res.status(400).json({ event: 'Event has already finished' }); - } - - review.event = data.event; - } - - review.guideDog = data.guideDog || review.guideDog; - review.parking = data.parking || review.parking; - review.quiet = data.quiet || review.quiet; - review.ramp = data.ramp || review.ramp; - review.secondEntry = data.secondEntry || review.secondEntry; - review.spacious = data.spacious || review.spacious; - - //new expanded fields - review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; - review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; - review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; - review.hasAccessibleTableHeight = - data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; - review.hasAccessibleElevator = - data.hasAccessibleElevator || review.hasAccessibleElevator; - review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; - review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; - review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; - review.hasSupportAroundToilet = - data.hasSupportAroundToilet || review.hasSupportAroundToilet; - review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; - - if (data.steps) { - venue.stepsReviews[review.steps] -= 1; - venue.stepsReviews[data.steps] += 1; - review.steps = data.steps; - } - - if (data.team) { - let team; - try { - team = await Team.findOne({ _id: data.team, isArchived: false }); - } catch (err) { - console.log(`Team ${data.team} failed to be found at edit-review`); - return next(err); - } - - if (!team) { - return res.status(404).json({ team: 'Team not found' }); - } - - if (!team.members.find(m => m.toString() === req.user.id)) { - return res - .status(400) - .json({ team: 'You are not a member of this team' }); - } - - review.team = data.team; - } - - review.wellLit = data.wellLit || review.wellLit; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Review ${review.id} failed to be updated at edit-review`); - return next(err); - } - - try { - await venue.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Venue ${venue.id} failed to be updated at edit-review`); - return next(err); - } - - return res.status(200).json(review); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Event } = require('../../models/event'); +const { Review } = require('../../models/review'); +const { Team } = require('../../models/team'); +const { Venue } = require('../../models/venue'); + +const { validateCreateEditReview } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }).select( + '-__v -createdAt -updatedAt' + ); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at edit-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + if (review.user.toString() !== req.user.id) { + return res + .status(423) + .json({ general: 'You cannot edit someone else review' }); + } + + let venue; + try { + venue = await Venue.findOne({ + _id: review.venue.toString(), + isArchived: false + }); + } catch (err) { + console.log( + `Venue ${review.venue.toString()} failed to be found at edit-review` + ); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Review venue not found' }); + } + + const data = pick(req.body, [ + //new expanded fields + 'hasPermanentRamp', + 'hasPortableRamp', + 'hasWideEntrance', + 'hasAccessibleTableHeight', + 'hasAccessibleElevator', + 'hasInteriorRamp', + 'hasSwingOutDoor', + 'hasLargeStall', + 'hasSupportAroundToilet', + 'hasLoweredSinks', + + //original fields + //'bathroomScore', + 'comments', + //'entryScore', + 'event', + 'guideDog', + 'parking', + 'quiet', + 'ramp', + 'secondEntry', + 'spacious', + 'steps', + 'team', + 'wellLit' + ]); + const { errors, isValid } = validateCreateEditReview(data); + + if (!isValid) { + return res.status(400).json(errors); + } + + //review.bathroomScore = data.bathroomScore || review.bathroomScore; + review.comments = data.comments || review.comments; + //review.entryScore = data.entryScore || review.entryScore; + + if (data.event) { + let event; + try { + event = await Event.findOne({ _id: data.event }); + } catch (err) { + console.log(`Event ${data.event} failed to be found at edit-review`); + return next(err); + } + + if (!event) { + return res.status(404).json({ event: 'Event not found' }); + } + + if (!event.participants.find((p) => p.toString() === req.user.id)) { + return res + .status(400) + .json({ event: 'You are not a participant of this event' }); + } + + const startDate = moment(event.startDate).utc(); + const endDate = moment(event.endDate).utc(); + const today = moment.utc(); + if (startDate.isAfter(today)) { + return res.status(400).json({ event: 'Event has not started yet' }); + } else if (endDate.isBefore(today)) { + return res.status(400).json({ event: 'Event has already finished' }); + } + + review.event = data.event; + } + + review.guideDog = data.guideDog || review.guideDog; + review.parking = data.parking || review.parking; + review.quiet = data.quiet || review.quiet; + review.ramp = data.ramp || review.ramp; + review.secondEntry = data.secondEntry || review.secondEntry; + review.spacious = data.spacious || review.spacious; + + //new expanded fields + review.hasPermanentRamp = data.hasPermanentRamp || review.hasPermanentRamp; + review.hasPortableRamp = data.hasPortableRamp || review.hasPortableRamp; + review.hasWideEntrance = data.hasWideEntrance || review.hasWideEntrance; + review.hasAccessibleTableHeight = + data.hasAccessibleTableHeight || review.hasAccessibleTableHeight; + review.hasAccessibleElevator = + data.hasAccessibleElevator || review.hasAccessibleElevator; + review.hasInteriorRamp = data.hasInteriorRamp || review.hasInteriorRamp; + review.hasSwingOutDoor = data.hasSwingOutDoor || review.hasSwingOutDoor; + review.hasLargeStall = data.hasLargeStall || review.hasLargeStall; + review.hasSupportAroundToilet = + data.hasSupportAroundToilet || review.hasSupportAroundToilet; + review.hasLoweredSinks = data.hasLoweredSinks || review.hasLoweredSinks; + + if (data.steps) { + venue.stepsReviews[review.steps] -= 1; + venue.stepsReviews[data.steps] += 1; + review.steps = data.steps; + } + + if (data.team) { + let team; + try { + team = await Team.findOne({ _id: data.team, isArchived: false }); + } catch (err) { + console.log(`Team ${data.team} failed to be found at edit-review`); + return next(err); + } + + if (!team) { + return res.status(404).json({ team: 'Team not found' }); + } + + if (!team.members.find((m) => m.toString() === req.user.id)) { + return res + .status(400) + .json({ team: 'You are not a member of this team' }); + } + + review.team = data.team; + } + + review.wellLit = data.wellLit || review.wellLit; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Review ${review.id} failed to be updated at edit-review`); + return next(err); + } + + try { + await venue.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Venue ${venue.id} failed to be updated at edit-review`); + return next(err); + } + + return res.status(200).json(review); +}; diff --git a/src/routes/reviews/flag-review.js b/src/routes/reviews/flag-review.js index a92319d..9de8ce9 100644 --- a/src/routes/reviews/flag-review.js +++ b/src/routes/reviews/flag-review.js @@ -1,50 +1,50 @@ -const moment = require('moment'); -const { pick } = require('lodash'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at flag-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - const data = pick(req.body, ['comments', 'type']); - - review.complaints = [ - ...review.complaints, - { - comments: data.comments, - type: data.type, - user: req.user.id - } - ]; - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at flag-review`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); +const { pick } = require('lodash'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at flag-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + const data = pick(req.body, ['comments', 'type']); + + review.complaints = [ + ...review.complaints, + { + comments: data.comments, + type: data.type, + user: req.user.id + } + ]; + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at flag-review`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/reviews/index.js b/src/routes/reviews/index.js index 8031f89..9cc7488 100644 --- a/src/routes/reviews/index.js +++ b/src/routes/reviews/index.js @@ -1,29 +1,31 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const banReview = require('./ban-review'); -const createReview = require('./create-review'); -const editReview = require('./edit-review'); -const flagReview = require('./flag-review'); -const listReviews = require('./list-reviews'); -const voteReview = require('./vote-review'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: false }), listReviews); -router.post('', isAuthenticated({ isOptional: false }), createReview); -router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); -router.put( - '/:reviewId/vote', - isAuthenticated({ isOptional: false }), - voteReview -); -router.post( - '/:reviewId/flag', - isAuthenticated({ isOptional: false }), - flagReview -); -router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const banReview = require('./ban-review'); +const createReview = require('./create-review'); +const createAiReview = require('./create-ai-review'); +const editReview = require('./edit-review'); +const flagReview = require('./flag-review'); +const listReviews = require('./list-reviews'); +const voteReview = require('./vote-review'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: false }), listReviews); +router.post('', isAuthenticated({ isOptional: false }), createReview); +router.put('/:reviewId', isAuthenticated({ isOptional: false }), editReview); +router.post('/create', isAuthenticated({ isOptional: false }), createAiReview); +router.put( + '/:reviewId/vote', + isAuthenticated({ isOptional: false }), + voteReview +); +router.post( + '/:reviewId/flag', + isAuthenticated({ isOptional: false }), + flagReview +); +router.put('/:reviewId/ban', isAuthenticated({ isOptional: false }), banReview); + +module.exports = router; diff --git a/src/routes/reviews/list-reviews.js b/src/routes/reviews/list-reviews.js index 9050b45..280601c 100644 --- a/src/routes/reviews/list-reviews.js +++ b/src/routes/reviews/list-reviews.js @@ -1,184 +1,184 @@ -const { toBoolean, toInt } = require('validator'); - -const { Review } = require('../../models/review'); - -const { validateListReviews } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const queryParams = req.query; - const { errors, isValid } = validateListReviews(queryParams); - - if (!isValid) { - return res.status(400).json(errors); - } - - const reviewsQuery = {}; - - if (queryParams.restroomScore) { - //const limits = queryParams.bathroomScore.split(','); - reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; - } - - if (queryParams.entranceScore) { - //const limits = queryParams.entryScore.split(','); - reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; - } - - if (queryParams.event) { - reviewsQuery.event = queryParams.event; - } - - if (queryParams.guideDog) { - reviewsQuery.guideDog = toBoolean(queryParams.guideDog); - } - - if (queryParams.parking) { - reviewsQuery.parking = toBoolean(queryParams.parking); - } - - if (queryParams.quiet) { - reviewsQuery.quiet = toBoolean(queryParams.quiet); - } - - if (queryParams.ramp) { - reviewsQuery.ramp = toBoolean(queryParams.ramp); - } - - if (queryParams.secondEntry) { - reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); - } - - if (queryParams.spacious) { - reviewsQuery.spacious = toBoolean(queryParams.spacious); - } - - if (queryParams.steps) { - reviewsQuery.steps = toInt(queryParams.steps); - } - - if (queryParams.team) { - reviewsQuery.team = queryParams.team; - } - - if (queryParams.user) { - reviewsQuery.user = queryParams.user; - } - - if (queryParams.venue) { - reviewsQuery.venue = queryParams.venue; - } - - if (queryParams.wellLit) { - reviewsQuery.wellLit = toBoolean(queryParams.wellLit); - } - - // - // new expanded fields - // - if (queryParams.hasPermanentRamp) { - reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); - } - - if (queryParams.hasPortableRamp) { - reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); - } - - if (queryParams.hasWideEntrance) { - reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); - } - - if (queryParams.hasAccessibleTableHeight) { - reviewsQuery.hasAccessibleTableHeight = toBoolean( - queryParams.hasAccessibleTableHeight - ); - } - - if (queryParams.hasAccessibleElevator) { - reviewsQuery.hasAccessibleElevator = toBoolean( - queryParams.hasAccessibleElevator - ); - } - - if (queryParams.hasInteriorRamp) { - reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); - } - - if (queryParams.hasSwingOutDoor) { - reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); - } - - if (queryParams.hasLargeStall) { - reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); - } - - if (queryParams.hasSupportAroundToilet) { - reviewsQuery.hasSupportAroundToilet = toBoolean( - queryParams.hasSupportAroundToilet - ); - } - - if (queryParams.hasLoweredSinks) { - reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); - } - - if (queryParams.interiorScore) { - reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; - } - - let page = queryParams.page || 1; - const pageLimit = 18; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let reviews; - let total; - try { - [reviews, total] = await Promise.all([ - Review.find(reviewsQuery) - .select('-__v -updatedAt -createdAt') - .sort('createdAt') - .skip(page * pageLimit) - .limit(pageLimit), - Review.find(reviewsQuery).count() - ]); - } catch (err) { - console.log('Reviews failed to be found or count at list-reviews'); - return next(err); - } - - let first = `${process.env.API_URL}/reviews?page=1`; - const lastPage = Math.ceil(total / pageLimit); - let last = `${process.env.API_URL}/reviews?page=${lastPage}`; - - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - first = null; - last = null; - page = null; - } - - return res.status(200).json({ - first, - last, - page, - pageLimit, - results: reviews, - total - }); -}; +const { toBoolean, toInt } = require('validator'); + +const { Review } = require('../../models/review'); + +const { validateListReviews } = require('./validations'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const queryParams = req.query; + const { errors, isValid } = validateListReviews(queryParams); + + if (!isValid) { + return res.status(400).json(errors); + } + + const reviewsQuery = {}; + + if (queryParams.restroomScore) { + //const limits = queryParams.bathroomScore.split(','); + reviewsQuery.bathroomScore = { $gte: toInt(queryParams.bathroomScore) }; + } + + if (queryParams.entranceScore) { + //const limits = queryParams.entryScore.split(','); + reviewsQuery.entranceScore = { $gte: toInt(queryParams.entranceScore) }; + } + + if (queryParams.event) { + reviewsQuery.event = queryParams.event; + } + + if (queryParams.guideDog) { + reviewsQuery.guideDog = toBoolean(queryParams.guideDog); + } + + if (queryParams.parking) { + reviewsQuery.parking = toBoolean(queryParams.parking); + } + + if (queryParams.quiet) { + reviewsQuery.quiet = toBoolean(queryParams.quiet); + } + + if (queryParams.ramp) { + reviewsQuery.ramp = toBoolean(queryParams.ramp); + } + + if (queryParams.secondEntry) { + reviewsQuery.secondEntry = toBoolean(queryParams.secondEntry); + } + + if (queryParams.spacious) { + reviewsQuery.spacious = toBoolean(queryParams.spacious); + } + + if (queryParams.steps) { + reviewsQuery.steps = toInt(queryParams.steps); + } + + if (queryParams.team) { + reviewsQuery.team = queryParams.team; + } + + if (queryParams.user) { + reviewsQuery.user = queryParams.user; + } + + if (queryParams.venue) { + reviewsQuery.venue = queryParams.venue; + } + + if (queryParams.wellLit) { + reviewsQuery.wellLit = toBoolean(queryParams.wellLit); + } + + // + // new expanded fields + // + if (queryParams.hasPermanentRamp) { + reviewsQuery.hasPermanentRamp = toBoolean(queryParams.hasPermanentRamp); + } + + if (queryParams.hasPortableRamp) { + reviewsQuery.hasPortableRamp = toBoolean(queryParams.hasPortableRamp); + } + + if (queryParams.hasWideEntrance) { + reviewsQuery.hasWideEntrance = toBoolean(queryParams.hasWideEntrance); + } + + if (queryParams.hasAccessibleTableHeight) { + reviewsQuery.hasAccessibleTableHeight = toBoolean( + queryParams.hasAccessibleTableHeight + ); + } + + if (queryParams.hasAccessibleElevator) { + reviewsQuery.hasAccessibleElevator = toBoolean( + queryParams.hasAccessibleElevator + ); + } + + if (queryParams.hasInteriorRamp) { + reviewsQuery.hasInteriorRamp = toBoolean(queryParams.hasInteriorRamp); + } + + if (queryParams.hasSwingOutDoor) { + reviewsQuery.hasSwingOutDoor = toBoolean(queryParams.hasSwingOutDoor); + } + + if (queryParams.hasLargeStall) { + reviewsQuery.hasLargeStall = toBoolean(queryParams.hasLargeStall); + } + + if (queryParams.hasSupportAroundToilet) { + reviewsQuery.hasSupportAroundToilet = toBoolean( + queryParams.hasSupportAroundToilet + ); + } + + if (queryParams.hasLoweredSinks) { + reviewsQuery.hasLoweredSinks = toBoolean(queryParams.hasLoweredSinks); + } + + if (queryParams.interiorScore) { + reviewsQuery.interiorScore = { $gte: toInt(queryParams.interiorScore) }; + } + + let page = queryParams.page || 1; + const pageLimit = 18; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: 'Should be equal to or greater than 1' }); + } + + let reviews; + let total; + try { + [reviews, total] = await Promise.all([ + Review.find(reviewsQuery) + .select('-__v -updatedAt -createdAt') + .sort('createdAt') + .skip(page * pageLimit) + .limit(pageLimit), + Review.find(reviewsQuery).count() + ]); + } catch (err) { + console.log('Reviews failed to be found or count at list-reviews'); + return next(err); + } + + let first = `${process.env.API_URL}/reviews?page=1`; + const lastPage = Math.ceil(total / pageLimit); + let last = `${process.env.API_URL}/reviews?page=${lastPage}`; + + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + first = null; + last = null; + page = null; + } + + return res.status(200).json({ + first, + last, + page, + pageLimit, + results: reviews, + total + }); +}; diff --git a/src/routes/reviews/validations.js b/src/routes/reviews/validations.js index 70ea8cb..7993a41 100644 --- a/src/routes/reviews/validations.js +++ b/src/routes/reviews/validations.js @@ -1,376 +1,369 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateEditReview(data) { - const errors = {}; - - // - // new expanded fields - // - if ( - typeof data.hasPermanentRamp !== 'undefined' && - typeof data.hasPermanentRamp !== 'boolean' - ) { - errors.hasPermanentRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasPortableRamp !== 'undefined' && - typeof data.hasPortableRamp !== 'boolean' - ) { - errors.hasPortableRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasWideEntrance !== 'undefined' && - typeof data.hasWideEntrance !== 'boolean' - ) { - errors.hasWideEntrance = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleTableHeight !== 'undefined' && - typeof data.hasAccessibleTableHeight !== 'boolean' - ) { - errors.hasAccessibleTableHeight = 'Should be a boolean'; - } - - if ( - typeof data.hasAccessibleElevator !== 'undefined' && - typeof data.hasAccessibleElevator !== 'boolean' - ) { - errors.hasAccessibleElevator = 'Should be a boolean'; - } - - if ( - typeof data.hasInteriorRamp !== 'undefined' && - typeof data.hasInteriorRamp !== 'boolean' - ) { - errors.hasInteriorRamp = 'Should be a boolean'; - } - - if ( - typeof data.hasSwingOutDoor !== 'undefined' && - typeof data.hasSwingOutDoor !== 'boolean' - ) { - errors.hasSwingOutDoor = 'Should be a boolean'; - } - - if ( - typeof data.hasLargeStall !== 'undefined' && - typeof data.hasLargeStall !== 'boolean' - ) { - errors.hasLargeStall = 'Should be a boolean'; - } - - if ( - typeof data.hasSupportAroundToilet !== 'undefined' && - typeof data.hasSupportAroundToilet !== 'boolean' - ) { - errors.hasSupportAroundToilet = 'Should be a boolean'; - } - - if ( - typeof data.hasLoweredSinks !== 'undefined' && - typeof data.hasLoweredSinks !== 'boolean' - ) { - errors.hasLoweredSinks = 'Should be a boolean'; - } - - /* - *interiorScore - if (typeof data.interiorScore !== 'undefined') { - if (typeof data.interiorScore !== 'number') { - errors.interiorScore = 'Should be a number'; - } else if (data.interiorScore < 1 || data.interiorScore > 7) { - //Remove required interiorScore - //errors.interiorScore = 'Should be between 1 and 7'; - } - } - */ - - // - //original fields - // - if ( - typeof data.allowsGuideDog !== 'undefined' && - typeof data.allowsGuideDog !== 'boolean' - ) { - errors.allowsGuideDog = 'Should be a boolean'; - } - - /* - * bathroomScore - if (typeof data.bathroomScore !== 'undefined') { - if (typeof data.bathroomScore !== 'number') { - errors.bathroomScore = 'Should be a number'; - } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { - //Remove required entryScore - //errors.bathroomScore = 'Should be between 1 and 4'; - } - } - */ - - if (data.comments && typeof data.comments !== 'string') { - errors.comments = 'Should be a string'; - } - - /* - * entryScore - if (typeof data.entryScore === 'undefined') { - //Remove required entryScore - //errors.entryScore = 'Is required'; - } else if (typeof data.entryScore !== 'number') { - errors.entryScore = 'Should be a number'; - } else if (data.entryScore < 1 || data.entryScore > 9) { - //Remove required entryScore - //errors.entryScore = 'Should be between 1 and 9'; - } - */ - - if (data.event) { - if (typeof data.event !== 'string') { - errors.event = 'Should be a string'; - } else if (!isMongoId(data.event)) { - errors.event = 'Should be a valid id'; - } - } - - if ( - typeof data.hasParking !== 'undefined' && - typeof data.hasParking !== 'boolean' - ) { - errors.hasParking = 'Should be a boolean'; - } - - if ( - typeof data.hasSecondEntry !== 'undefined' && - typeof data.hasSecondEntry !== 'boolean' - ) { - errors.hasSecondEntry = 'Should be a boolean'; - } - - if ( - typeof data.hasWellLit !== 'undefined' && - typeof data.hasWellLit !== 'boolean' - ) { - errors.hasWellLit = 'Should be a boolean'; - } - - if ( - typeof data.isQuiet !== 'undefined' && - typeof data.isQuiet !== 'boolean' - ) { - errors.isQuiet = 'Should be a boolean'; - } - - if ( - typeof data.isSpacious !== 'undefined' && - typeof data.isSpacious !== 'boolean' - ) { - errors.isSpacious = 'Should be a boolean'; - } - - if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { - errors.photo = 'Should be a string'; - } - - if (!data.place) { - errors.place = 'Is required'; - } else if (typeof data.place !== 'string') { - errors.place = 'Should be a string'; - } - - if (typeof data.steps !== 'undefined') { - if (typeof data.steps !== 'number') { - errors.steps = 'Should be a number'; - } else if (data.steps < 0 || data.steps > 3) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (data.team) { - if (typeof data.team !== 'string') { - errors.team = 'Should be a string'; - } else if (!isMongoId(data.team)) { - errors.team = 'Should be a valid id'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListReviews(queryParams) { - const errors = {}; - - //Remove bathroomScore validation - if (queryParams.bathroomScore) { - /* - const limits = queryParams.bathroomScore.split(','); - - if (limits.length !== 2) { - errors.bathroomScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 4 }) || - !isInt(limits[1], { min: 1, max: 4 }) - ) { - errors.bathroomScore = 'Both should be integers between 1 and 4'; - } - */ - } - - //Remove entryScore validation - if (queryParams.entryScore) { - /* - const limits = queryParams.entryScore.split(','); - - if (limits.length !== 2) { - errors.entryScore = 'Should be two integers split by a comma'; - } else if ( - !isInt(limits[0], { min: 1, max: 9 }) || - !isInt(limits[1], { min: 1, max: 9 }) - ) { - errors.entryScore = 'Both should be integers between 1 and 9'; - } - */ - } - - if (queryParams.event && !isMongoId(queryParams.event)) { - errors.event = 'Should be a valid Id'; - } - - if ( - queryParams.guideDog && - !isInt(queryParams.guideDog, { min: 0, max: 1 }) - ) { - errors.guideDog = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.parking && - !isInt(queryParams.parking, { min: 0, max: 1 }) - ) { - errors.parking = 'Should be an integer between 0 and 1'; - } - - if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { - errors.quiet = 'Should be an integer between 0 and 1'; - } - - if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { - errors.ramp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.secondEntry && - !isInt(queryParams.secondEntry, { min: 0, max: 1 }) - ) { - errors.secondEntry = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.spacious && - !isInt(queryParams.spacious, { min: 0, max: 1 }) - ) { - errors.spacious = 'Should be an integer between 0 and 1'; - } - - if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { - errors.steps = 'Should be an integer between 0 and 3'; - } - - if (queryParams.team && !isMongoId(queryParams.team)) { - errors.team = 'Should be a valid Id'; - } - - if (queryParams.user && !isMongoId(queryParams.user)) { - errors.user = 'Should be a valid Id'; - } - - if (queryParams.venue && !isMongoId(queryParams.venue)) { - errors.venue = 'Should be a valid Id'; - } - - if ( - queryParams.wellLit && - !isInt(queryParams.wellLit, { min: 0, max: 1 }) - ) { - errors.wellLit = 'Should be an integer between 0 and 1'; - } - - // - // new expanded fields - // - if ( - queryParams.hasPermanentRamp && - !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) - ) { - errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasPortableRamp && - !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) - ) { - errors.hasPortableRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasWideEntrance && - !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) - ) { - errors.hasWideEntrance = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleTableHeight && - !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) - ) { - errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasAccessibleElevator && - !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) - ) { - errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasInteriorRamp && - !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) - ) { - errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSwingOutDoor && - !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) - ) { - errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLargeStall && - !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) - ) { - errors.hasLargeStall = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasSupportAroundToilet && - !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) - ) { - errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; - } - - if ( - queryParams.hasLoweredSinks && - !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) - ) { - errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateEditReview(data) { + const errors = {}; + + // + // new expanded fields + // + if ( + typeof data.hasPermanentRamp !== 'undefined' && + typeof data.hasPermanentRamp !== 'boolean' + ) { + errors.hasPermanentRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasPortableRamp !== 'undefined' && + typeof data.hasPortableRamp !== 'boolean' + ) { + errors.hasPortableRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasWideEntrance !== 'undefined' && + typeof data.hasWideEntrance !== 'boolean' + ) { + errors.hasWideEntrance = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleTableHeight !== 'undefined' && + typeof data.hasAccessibleTableHeight !== 'boolean' + ) { + errors.hasAccessibleTableHeight = 'Should be a boolean'; + } + + if ( + typeof data.hasAccessibleElevator !== 'undefined' && + typeof data.hasAccessibleElevator !== 'boolean' + ) { + errors.hasAccessibleElevator = 'Should be a boolean'; + } + + if ( + typeof data.hasInteriorRamp !== 'undefined' && + typeof data.hasInteriorRamp !== 'boolean' + ) { + errors.hasInteriorRamp = 'Should be a boolean'; + } + + if ( + typeof data.hasSwingOutDoor !== 'undefined' && + typeof data.hasSwingOutDoor !== 'boolean' + ) { + errors.hasSwingOutDoor = 'Should be a boolean'; + } + + if ( + typeof data.hasLargeStall !== 'undefined' && + typeof data.hasLargeStall !== 'boolean' + ) { + errors.hasLargeStall = 'Should be a boolean'; + } + + if ( + typeof data.hasSupportAroundToilet !== 'undefined' && + typeof data.hasSupportAroundToilet !== 'boolean' + ) { + errors.hasSupportAroundToilet = 'Should be a boolean'; + } + + if ( + typeof data.hasLoweredSinks !== 'undefined' && + typeof data.hasLoweredSinks !== 'boolean' + ) { + errors.hasLoweredSinks = 'Should be a boolean'; + } + + /* + *interiorScore + if (typeof data.interiorScore !== 'undefined') { + if (typeof data.interiorScore !== 'number') { + errors.interiorScore = 'Should be a number'; + } else if (data.interiorScore < 1 || data.interiorScore > 7) { + //Remove required interiorScore + //errors.interiorScore = 'Should be between 1 and 7'; + } + } + */ + + // + //original fields + // + if ( + typeof data.allowsGuideDog !== 'undefined' && + typeof data.allowsGuideDog !== 'boolean' + ) { + errors.allowsGuideDog = 'Should be a boolean'; + } + + /* + * bathroomScore + if (typeof data.bathroomScore !== 'undefined') { + if (typeof data.bathroomScore !== 'number') { + errors.bathroomScore = 'Should be a number'; + } else if (data.bathroomScore < 1 || data.bathroomScore > 4) { + //Remove required entryScore + //errors.bathroomScore = 'Should be between 1 and 4'; + } + } + */ + + if (data.comments && typeof data.comments !== 'string') { + errors.comments = 'Should be a string'; + } + + /* + * entryScore + if (typeof data.entryScore === 'undefined') { + //Remove required entryScore + //errors.entryScore = 'Is required'; + } else if (typeof data.entryScore !== 'number') { + errors.entryScore = 'Should be a number'; + } else if (data.entryScore < 1 || data.entryScore > 9) { + //Remove required entryScore + //errors.entryScore = 'Should be between 1 and 9'; + } + */ + + if (data.event) { + if (typeof data.event !== 'string') { + errors.event = 'Should be a string'; + } else if (!isMongoId(data.event)) { + errors.event = 'Should be a valid id'; + } + } + + if ( + typeof data.hasParking !== 'undefined' && + typeof data.hasParking !== 'boolean' + ) { + errors.hasParking = 'Should be a boolean'; + } + + if ( + typeof data.hasSecondEntry !== 'undefined' && + typeof data.hasSecondEntry !== 'boolean' + ) { + errors.hasSecondEntry = 'Should be a boolean'; + } + + if ( + typeof data.hasWellLit !== 'undefined' && + typeof data.hasWellLit !== 'boolean' + ) { + errors.hasWellLit = 'Should be a boolean'; + } + + if ( + typeof data.isQuiet !== 'undefined' && + typeof data.isQuiet !== 'boolean' + ) { + errors.isQuiet = 'Should be a boolean'; + } + + if ( + typeof data.isSpacious !== 'undefined' && + typeof data.isSpacious !== 'boolean' + ) { + errors.isSpacious = 'Should be a boolean'; + } + + if (typeof data.photo !== 'undefined' && typeof data.photo !== 'string') { + errors.photo = 'Should be a string'; + } + + if (!data.place) { + errors.place = 'Is required'; + } else if (typeof data.place !== 'string') { + errors.place = 'Should be a string'; + } + + + if (data.team) { + if (typeof data.team !== 'string') { + errors.team = 'Should be a string'; + } else if (!isMongoId(data.team)) { + errors.team = 'Should be a valid id'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListReviews(queryParams) { + const errors = {}; + + //Remove bathroomScore validation + if (queryParams.bathroomScore) { + /* + const limits = queryParams.bathroomScore.split(','); + + if (limits.length !== 2) { + errors.bathroomScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 4 }) || + !isInt(limits[1], { min: 1, max: 4 }) + ) { + errors.bathroomScore = 'Both should be integers between 1 and 4'; + } + */ + } + + //Remove entryScore validation + if (queryParams.entryScore) { + /* + const limits = queryParams.entryScore.split(','); + + if (limits.length !== 2) { + errors.entryScore = 'Should be two integers split by a comma'; + } else if ( + !isInt(limits[0], { min: 1, max: 9 }) || + !isInt(limits[1], { min: 1, max: 9 }) + ) { + errors.entryScore = 'Both should be integers between 1 and 9'; + } + */ + } + + if (queryParams.event && !isMongoId(queryParams.event)) { + errors.event = 'Should be a valid Id'; + } + + if ( + queryParams.guideDog && + !isInt(queryParams.guideDog, { min: 0, max: 1 }) + ) { + errors.guideDog = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.parking && + !isInt(queryParams.parking, { min: 0, max: 1 }) + ) { + errors.parking = 'Should be an integer between 0 and 1'; + } + + if (queryParams.quiet && !isInt(queryParams.quiet, { min: 0, max: 1 })) { + errors.quiet = 'Should be an integer between 0 and 1'; + } + + if (queryParams.ramp && !isInt(queryParams.ramp, { min: 0, max: 1 })) { + errors.ramp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.secondEntry && + !isInt(queryParams.secondEntry, { min: 0, max: 1 }) + ) { + errors.secondEntry = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.spacious && + !isInt(queryParams.spacious, { min: 0, max: 1 }) + ) { + errors.spacious = 'Should be an integer between 0 and 1'; + } + + if (queryParams.steps && !isInt(queryParams.steps, { min: 0, max: 3 })) { + errors.steps = 'Should be an integer between 0 and 3'; + } + + if (queryParams.team && !isMongoId(queryParams.team)) { + errors.team = 'Should be a valid Id'; + } + + if (queryParams.user && !isMongoId(queryParams.user)) { + errors.user = 'Should be a valid Id'; + } + + if (queryParams.venue && !isMongoId(queryParams.venue)) { + errors.venue = 'Should be a valid Id'; + } + + if ( + queryParams.wellLit && + !isInt(queryParams.wellLit, { min: 0, max: 1 }) + ) { + errors.wellLit = 'Should be an integer between 0 and 1'; + } + + // + // new expanded fields + // + if ( + queryParams.hasPermanentRamp && + !isInt(queryParams.hasPermanentRamp, { min: 0, max: 1 }) + ) { + errors.hasPermanentRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasPortableRamp && + !isInt(queryParams.hasPortableRamp, { min: 0, max: 1 }) + ) { + errors.hasPortableRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasWideEntrance && + !isInt(queryParams.hasWideEntrance, { min: 0, max: 1 }) + ) { + errors.hasWideEntrance = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleTableHeight && + !isInt(queryParams.hasAccessibleTableHeight, { min: 0, max: 1 }) + ) { + errors.hasAccessibleTableHeight = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasAccessibleElevator && + !isInt(queryParams.hasAccessibleElevator, { min: 0, max: 1 }) + ) { + errors.hasAccessibleElevator = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasInteriorRamp && + !isInt(queryParams.hasInteriorRamp, { min: 0, max: 1 }) + ) { + errors.hasInteriorRamp = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSwingOutDoor && + !isInt(queryParams.hasSwingOutDoor, { min: 0, max: 1 }) + ) { + errors.hasSwingOutDoor = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLargeStall && + !isInt(queryParams.hasLargeStall, { min: 0, max: 1 }) + ) { + errors.hasLargeStall = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasSupportAroundToilet && + !isInt(queryParams.hasSupportAroundToilet, { min: 0, max: 1 }) + ) { + errors.hasSupportAroundToilet = 'Should be an integer between 0 and 1'; + } + + if ( + queryParams.hasLoweredSinks && + !isInt(queryParams.hasLoweredSinks, { min: 0, max: 1 }) + ) { + errors.hasLoweredSinks = 'Should be an integer between 0 and 1'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/reviews/vote-review.js b/src/routes/reviews/vote-review.js index dbd8b6c..e3e9472 100644 --- a/src/routes/reviews/vote-review.js +++ b/src/routes/reviews/vote-review.js @@ -1,49 +1,49 @@ -const moment = require('moment'); - -const { Review } = require('../../models/review'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const reviewId = req.params.reviewId; - - let review; - try { - review = await Review.findOne({ _id: reviewId }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Review not found' }); - } - - console.log(`Review ${reviewId} failed to be found at vote-review`); - return next(err); - } - - if (!review) { - return res.status(404).json({ general: 'Review not found' }); - } - - let addVote = true; - - if (review.voters.find(v => v.toString() === req.user.id)) { - review.voters = review.voters.filter(v => v.toString() !== req.user.id); - addVote = false; - } else { - review.voters = [...review.voters, req.user.id]; - } - - review.updatedAt = moment.utc().toDate(); - - try { - await review.save(); - } catch (err) { - console.log(`Review ${review.id} failed to be updated at vote-review`); - return next(err); - } - - return res - .status(200) - .json({ general: addVote ? 'One more vote' : 'One less vote' }); -}; +const moment = require('moment'); + +const { Review } = require('../../models/review'); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: 'You are blocked' }); + } + + const reviewId = req.params.reviewId; + + let review; + try { + review = await Review.findOne({ _id: reviewId }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Review not found' }); + } + + console.log(`Review ${reviewId} failed to be found at vote-review`); + return next(err); + } + + if (!review) { + return res.status(404).json({ general: 'Review not found' }); + } + + let addVote = true; + + if (review.voters.find((v) => v.toString() === req.user.id)) { + review.voters = review.voters.filter((v) => v.toString() !== req.user.id); + addVote = false; + } else { + review.voters = [...review.voters, req.user.id]; + } + + review.updatedAt = moment.utc().toDate(); + + try { + await review.save(); + } catch (err) { + console.log(`Review ${review.id} failed to be updated at vote-review`); + return next(err); + } + + return res + .status(200) + .json({ general: addVote ? 'One more vote' : 'One less vote' }); +}; diff --git a/src/routes/teams/create-team.js b/src/routes/teams/create-team.js index a40dc19..799bdfe 100644 --- a/src/routes/teams/create-team.js +++ b/src/routes/teams/create-team.js @@ -1,93 +1,93 @@ -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); - -const { validateCreateTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const data = { - avatar: req.body.avatar, - description: req.body.description, - name: req.body.name - }; - - const { errors, isValid } = validateCreateTeam(data); - if (!isValid) return res.status(400).json(errors); - - if (data.avatar) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at create-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - } - - data.managers = [req.user.id]; - - data.name = cleanSpaces(data.name); - - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); - } catch (err) { - console.log(`Team ${data.name} failed to be found at create-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - let team; - try { - team = await Team.create(data); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Team ${ - data.name - } failed to be created at create-team.\nData: ${JSON.stringify(data)}` - ); - return next(err); - } - - req.user.teams = [...req.user.teams, team.id]; - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at create-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: [ - { - id: req.user.id, - avatar: req.user.avatar, - name: `${req.user.firstName} ${req.user.lastName}` - } - ], - name: team.name - }; - - return res.status(201).json(dataResponse); -}; +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); + +const { validateCreateTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const data = { + avatar: req.body.avatar, + description: req.body.description, + name: req.body.name + }; + + const { errors, isValid } = validateCreateTeam(data); + if (!isValid) return res.status(400).json(errors); + + if (data.avatar) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at create-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + } + + data.managers = [req.user.id]; + + data.name = cleanSpaces(data.name); + + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ name: data.name, isArchived: false }); + } catch (err) { + console.log(`Team ${data.name} failed to be found at create-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + let team; + try { + team = await Team.create(data); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Team ${ + data.name + } failed to be created at create-team.\nData: ${JSON.stringify(data)}` + ); + return next(err); + } + + req.user.teams = [...req.user.teams, team.id]; + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at create-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: [ + { + id: req.user.id, + avatar: req.user.avatar, + name: `${req.user.firstName} ${req.user.lastName}` + } + ], + name: team.name + }; + + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/teams/delete-team.js b/src/routes/teams/delete-team.js index 0bf3431..14e4f76 100644 --- a/src/routes/teams/delete-team.js +++ b/src/routes/teams/delete-team.js @@ -1,115 +1,115 @@ -const moment = require('moment'); - -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at delete-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let archiveTeam = false; - - if (team.events && team.events.length > 0) { - const teamEventsPromises = team.events.map(e => - Event.findOne({ _id: e.toString() }) - ); - - let teamEvents; - try { - teamEvents = await Promise.all(teamEventsPromises); - } catch (err) { - console.log('A team event failed to be found at delete-team'); - return next(err); - } - - for (const event of teamEvents) { - const endDate = moment(event.endDate).utc(); - const endOfToday = moment.utc().endOf('day'); - if (endDate.isBefore(endOfToday)) { - event.teams = event.teams.filter(t => t.toString() !== team.id); - event.updatedAt = moment.utc().toDate(); - - try { - await event.save(); - } catch (err) { - console.log(`Event ${event.id} failed to be updated at delete-team`); - return next(err); - } - } else { - archiveTeam = true; - } - } - } - - const teamMembersPromises = team.members.map(m => - User.findOne({ _id: m.toString() }) - ); - - let teamMembers; - try { - teamMembers = await Promise.all(teamMembersPromises); - } catch (err) { - console.log('A team member failed to be found at delete-team'); - return next(err); - } - - for (const member of teamMembers) { - member.teams = member.teams.filter(t => t.toString() !== team.id); - member.updatedAt = moment.utc().toDate(); - - try { - await member.save(); - } catch (err) { - console.log(`Member ${member.id} failed to be updated at delete-team`); - return next(err); - } - } - - if (archiveTeam) { - team.isArchived = true; - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at delete-team`); - return next(err); - } - } else { - try { - await team.remove(); - } catch (err) { - console.log(`Team ${team.id} failed to be removed at delete-team`); - return next(err); - } - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require("moment"); + +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Team not found" }); + } + + console.log(`Team ${teamId} failed to be found at delete-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: "Team not found" }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: "Forbidden action" }); + } + + let archiveTeam = false; + + if (team.events && team.events.length > 0) { + const teamEventsPromises = team.events.map((e) => + Event.findOne({ _id: e.toString() }) + ); + + let teamEvents; + try { + teamEvents = await Promise.all(teamEventsPromises); + } catch (err) { + console.log("A team event failed to be found at delete-team"); + return next(err); + } + + for (const event of teamEvents) { + const endDate = moment(event.endDate).utc(); + const endOfToday = moment.utc().endOf("day"); + if (endDate.isBefore(endOfToday)) { + event.teams = event.teams.filter((t) => t.toString() !== team.id); + event.updatedAt = moment.utc().toDate(); + + try { + await event.save(); + } catch (err) { + console.log(`Event ${event.id} failed to be updated at delete-team`); + return next(err); + } + } else { + archiveTeam = true; + } + } + } + + const teamMembersPromises = team.members.map((m) => + User.findOne({ _id: m.toString() }) + ); + + let teamMembers; + try { + teamMembers = await Promise.all(teamMembersPromises); + } catch (err) { + console.log("A team member failed to be found at delete-team"); + return next(err); + } + + for (const member of teamMembers) { + member.teams = member.teams.filter((t) => t.toString() !== team.id); + member.updatedAt = moment.utc().toDate(); + + try { + await member.save(); + } catch (err) { + console.log(`Member ${member.id} failed to be updated at delete-team`); + return next(err); + } + } + + if (archiveTeam) { + team.isArchived = true; + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at delete-team`); + return next(err); + } + } else { + try { + await Team.deleteOne({ _id: teamId, isArchived: false }); + } catch (err) { + console.log(`Team ${team.id} failed to be removed at delete-team`); + return next(err); + } + } + + return res.status(204).json({ general: "Success" }); +}; diff --git a/src/routes/teams/edit-team.js b/src/routes/teams/edit-team.js index 0afd345..dbbedb4 100644 --- a/src/routes/teams/edit-team.js +++ b/src/routes/teams/edit-team.js @@ -1,205 +1,205 @@ -const { difference, intersection } = require('lodash'); -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { Team } = require('../../models/team'); -const { User } = require('../../models/user'); - -const { validateEditTeam } = require('./validations'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at edit-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if ( - !team.managers.find(m => m.toString() === req.user.id) && - !req.user.isAdmin - ) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = { - avatar: req.body.avatar, - description: req.body.description, - managers: req.body.managers, - members: req.body.members, - name: req.body.name - }; - const { errors, isValid } = validateEditTeam(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== team.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-team`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - team.avatar = data.avatar; - } else if (data.avatar === '') { - team.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/default.png`; - } - - team.description = data.description || team.description; - - if (data.managers) { - let managersToAdd = []; - let managersToRemove = []; - - data.managers.forEach(m => { - if (m.startsWith('-')) { - managersToRemove = [...managersToRemove, m.substring(1)]; - } else { - managersToAdd = [...managersToAdd, m]; - } - }); - - const teamManagers = team.managers.map(m => m.toString()); - - managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; - if (managersToAdd.length > 0) { - const teamMembers = team.members.map(m => m.toString()); - const notMember = managersToAdd.find(m => !teamMembers.includes(m)); - - if (notMember) { - return res - .status(400) - .json({ managers: `User ${notMember} is not a member of this team` }); - } - - team.managers = [...teamManagers, ...managersToAdd]; - team.members = team.members.filter( - m => !managersToAdd.includes(m.toString()) - ); - } - - managersToRemove = [ - ...new Set(intersection(managersToRemove, teamManagers)) - ]; - if (managersToRemove.length === team.managers.length) { - return res - .status(400) - .json({ managers: 'Should not remove all managers' }); - } - - team.managers = team.managers.filter( - m => !managersToRemove.includes(m.toString()) - ); - const teamMembers = team.members.map(m => m.toString()); - team.members = [...teamMembers, ...managersToRemove]; - } - - if (data.members) { - const teamMembers = team.members.map(m => m.toString()); - let membersToRemove = data.members.map(m => m.substring(1)); - membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; - - const getMembers = membersToRemove.map(m => - User.find({ _id: m, isArchived: false }) - ); - let members; - try { - members = await Promise.all(getMembers); - } catch (err) { - console.log(`Members failed to be found at edit-team`); - return next(err); - } - - const updateMembers = members.map((m, i) => { - m[i].teams = m[i].teams.filter(t => t.toString() !== team.id); - return m[i].save(); - }); - - try { - await Promise.all(updateMembers); - } catch (err) { - console.log(`Members failed to be updated at edit-team`); - return next(err); - } - - team.members = team.members.filter( - m => !membersToRemove.includes(m.toString()) - ); - } - - if (data.name) { - const teamName = cleanSpaces(data.name); - - if (teamName !== team.name) { - let repeatedTeam; - try { - repeatedTeam = await Team.findOne({ - name: teamName, - isArchived: false - }); - } catch (err) { - console.log(`Team ${teamName} failed to be found at edit-team`); - return next(err); - } - - if (repeatedTeam) { - return res.status(400).json({ name: 'Is already taken' }); - } - - team.name = teamName; - } - } - - team.updatedAt = moment.utc().toDate(); - - try { - await team.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log(`Team ${team.id} failed to be updated at edit-team`); - return next(err); - } - - const dataResponse = { - id: team.id, - avatar: team.avatar, - description: team.description, - managers: team.managers, - members: team.members, - name: team.name - }; - - return res.status(200).json(dataResponse); -}; +const { difference, intersection } = require('lodash'); +const moment = require('moment'); + +const { cleanSpaces } = require('../../helpers'); +const { Photo } = require('../../models/photo'); +const { Team } = require('../../models/team'); +const { User } = require('../../models/user'); + +const { validateEditTeam } = require('./validations'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at edit-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if ( + !team.managers.find((m) => m.toString() === req.user.id) && + !req.user.isAdmin + ) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const data = { + avatar: req.body.avatar, + description: req.body.description, + managers: req.body.managers, + members: req.body.members, + name: req.body.name + }; + const { errors, isValid } = validateEditTeam(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes('default') && + data.avatar !== team.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-team`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: 'Not found' }); + } + + team.avatar = data.avatar; + } else if (data.avatar === '') { + team.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/default.png`; + } + + team.description = data.description || team.description; + + if (data.managers) { + let managersToAdd = []; + let managersToRemove = []; + + data.managers.forEach((m) => { + if (m.startsWith('-')) { + managersToRemove = [...managersToRemove, m.substring(1)]; + } else { + managersToAdd = [...managersToAdd, m]; + } + }); + + const teamManagers = team.managers.map((m) => m.toString()); + + managersToAdd = [...new Set(difference(managersToAdd, teamManagers))]; + if (managersToAdd.length > 0) { + const teamMembers = team.members.map((m) => m.toString()); + const notMember = managersToAdd.find((m) => !teamMembers.includes(m)); + + if (notMember) { + return res + .status(400) + .json({ managers: `User ${notMember} is not a member of this team` }); + } + + team.managers = [...teamManagers, ...managersToAdd]; + team.members = team.members.filter( + (m) => !managersToAdd.includes(m.toString()) + ); + } + + managersToRemove = [ + ...new Set(intersection(managersToRemove, teamManagers)) + ]; + if (managersToRemove.length === team.managers.length) { + return res + .status(400) + .json({ managers: 'Should not remove all managers' }); + } + + team.managers = team.managers.filter( + (m) => !managersToRemove.includes(m.toString()) + ); + const teamMembers = team.members.map((m) => m.toString()); + team.members = [...teamMembers, ...managersToRemove]; + } + + if (data.members) { + const teamMembers = team.members.map((m) => m.toString()); + let membersToRemove = data.members.map((m) => m.substring(1)); + membersToRemove = [...new Set(intersection(membersToRemove, teamMembers))]; + + const getMembers = membersToRemove.map((m) => + User.find({ _id: m, isArchived: false }) + ); + let members; + try { + members = await Promise.all(getMembers); + } catch (err) { + console.log(`Members failed to be found at edit-team`); + return next(err); + } + + const updateMembers = members.map((m, i) => { + m[i].teams = m[i].teams.filter((t) => t.toString() !== team.id); + return m[i].save(); + }); + + try { + await Promise.all(updateMembers); + } catch (err) { + console.log(`Members failed to be updated at edit-team`); + return next(err); + } + + team.members = team.members.filter( + (m) => !membersToRemove.includes(m.toString()) + ); + } + + if (data.name) { + const teamName = cleanSpaces(data.name); + + if (teamName !== team.name) { + let repeatedTeam; + try { + repeatedTeam = await Team.findOne({ + name: teamName, + isArchived: false + }); + } catch (err) { + console.log(`Team ${teamName} failed to be found at edit-team`); + return next(err); + } + + if (repeatedTeam) { + return res.status(400).json({ name: 'Is already taken' }); + } + + team.name = teamName; + } + } + + team.updatedAt = moment.utc().toDate(); + + try { + await team.save(); + } catch (err) { + if (typeof err.errors === 'object') { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log(`Team ${team.id} failed to be updated at edit-team`); + return next(err); + } + + const dataResponse = { + id: team.id, + avatar: team.avatar, + description: team.description, + managers: team.managers, + members: team.members, + name: team.name + }; + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/get-team.js b/src/routes/teams/get-team.js index ea86094..9f3f0ca 100644 --- a/src/routes/teams/get-team.js +++ b/src/routes/teams/get-team.js @@ -1,144 +1,144 @@ -const mongoose = require('mongoose'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - const teamIdObj = mongoose.Types.ObjectId(teamId); - let team; - try { - team = await Team.aggregate([ - { - $match: { _id: teamIdObj } - }, - { - $lookup: { - from: 'users', - let: { members: '$members' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$members'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'members' - } - }, - { - $lookup: { - from: 'users', - let: { managers: '$managers' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$managers'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1, - username: 1 - } - } - ], - as: 'managers' - } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - reviewsAmount: 1, - name: 1, - members: 1, - events: 1, - managers: 1, - ranking: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at get-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const dataResponse = Object.assign({}, team[0], { - ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require('mongoose'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + const teamIdObj = new mongoose.Types.ObjectId(teamId); + let team; + try { + team = await Team.aggregate([ + { + $match: { _id: teamIdObj } + }, + { + $lookup: { + from: 'users', + let: { members: '$members' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$members'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'members' + } + }, + { + $lookup: { + from: 'users', + let: { managers: '$managers' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$managers'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1, + username: 1 + } + } + ], + as: 'managers' + } + }, + { + $lookup: { + from: 'events', + let: { events: '$events' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$events'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + endDate: 1, + name: 1, + poster: 1, + startDate: 1 + } + } + ], + as: 'events' + } + }, + { + $lookup: { + from: 'teams', + let: { reviewsAmount: '$reviewsAmount' }, + pipeline: [ + { + $match: { + $expr: { + $gt: ['$reviewsAmount', '$$reviewsAmount'] + } + } + }, + { + $count: 'ranking' + } + ], + as: 'ranking' + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + description: 1, + reviewsAmount: 1, + name: 1, + members: 1, + events: 1, + managers: 1, + ranking: 1 + } + } + ]); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at get-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + const dataResponse = Object.assign({}, team[0], { + ranking: team[0].ranking.length ? team[0].ranking[0].ranking + 1 : 1 + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/teams/index.js b/src/routes/teams/index.js index 8ffc659..83b4f3e 100644 --- a/src/routes/teams/index.js +++ b/src/routes/teams/index.js @@ -1,23 +1,23 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const createTeam = require('./create-team'); -const deleteTeam = require('./delete-team'); -const editTeam = require('./edit-team'); -const getTeam = require('./get-team'); -const joinTeam = require('./join-team'); -const leaveTeam = require('./leave-team'); -const listTeams = require('./list-teams'); - -const router = new express.Router(); - -router.get('', isAuthenticated({ isOptional: true }), listTeams); -router.post('', isAuthenticated({ isOptional: false }), createTeam); -router.get('/:teamId', getTeam); -router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); -router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); -router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); -router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const createTeam = require('./create-team'); +const deleteTeam = require('./delete-team'); +const editTeam = require('./edit-team'); +const getTeam = require('./get-team'); +const joinTeam = require('./join-team'); +const leaveTeam = require('./leave-team'); +const listTeams = require('./list-teams'); + +const router = new express.Router(); + +router.get('', isAuthenticated({ isOptional: true }), listTeams); +router.post('', isAuthenticated({ isOptional: false }), createTeam); +router.get('/:teamId', getTeam); +router.put('/:teamId', isAuthenticated({ isOptional: false }), editTeam); +router.delete('/:teamId', isAuthenticated({ isOptional: false }), deleteTeam); +router.post('/:teamId/join', isAuthenticated({ isOptional: false }), joinTeam); +router.put('/:teamId/leave', isAuthenticated({ isOptional: false }), leaveTeam); + +module.exports = router; diff --git a/src/routes/teams/join-team.js b/src/routes/teams/join-team.js index caf65ea..e847fa4 100644 --- a/src/routes/teams/join-team.js +++ b/src/routes/teams/join-team.js @@ -1,98 +1,102 @@ -const { Petition } = require('../../models/petition'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at join-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - const eventMembers = team.members.map(m => m.toString()); - if (eventMembers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - const eventManagers = team.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - return res - .status(400) - .json({ general: 'You already are a member in this team' }); - } - - let petition; - try { - petition = await Petition.findOne({ - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }); - } catch (err) { - console.log( - `Petition from user ${req.user.id} to team ${ - team.id - } failed to be found at join-team` - ); - return next(err); - } - - if (petition && petition.state === 'pending') { - return res.status(400).json({ - general: 'You already have a pending petition with this team' - }); - } - - if ( - petition && - (petition.state === 'rejected' || petition.state === 'canceled') - ) { - try { - await petition.remove(); - } catch (err) { - console.log(`Petition ${petition.id} failed to be removed at join-team`); - return next(err); - } - } - - const petitionData = { - team: team.id, - sender: req.user.id, - type: 'request-user-team' - }; - try { - await Petition.create(petitionData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `Petition failed to be created at join-team.\nData: ${JSON.stringify( - petitionData - )}` - ); - return next(err); - } - - return res.status(200).json({ general: 'Requested' }); -}; +const { Petition } = require("../../models/petition"); +const { Team } = require("../../models/team"); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Team not found" }); + } + + console.log(`Team ${teamId} failed to be found at join-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: "Team not found" }); + } + + const eventMembers = team.members.map((m) => m.toString()); + if (eventMembers.includes(req.user.id)) { + return res + .status(400) + .json({ general: "You already are a member in this team" }); + } + + const eventManagers = team.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + return res + .status(400) + .json({ general: "You already are a member in this team" }); + } + + let petition; + try { + petition = await Petition.findOne({ + team: team.id, + sender: req.user.id, + type: "request-user-team", + }); + } catch (err) { + console.log( + `Petition from user ${req.user.id} to team ${ + team.id + } failed to be found at join-team` + ); + return next(err); + } + + if (petition && petition.state === "pending") { + return res.status(400).json({ + general: "You already have a pending petition with this team", + }); + } + + if ( + petition && + (petition.state === "rejected" || petition.state === "canceled") + ) { + try { + await Petition.deleteOne({ + team: team.id, + sender: req.user.id, + type: "request-user-team", + }); + } catch (err) { + console.log(`Petition ${petition.id} failed to be removed at join-team`); + return next(err); + } + } + + const petitionData = { + team: team.id, + sender: req.user.id, + type: "request-user-team", + }; + try { + await Petition.create(petitionData); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `Petition failed to be created at join-team.\nData: ${JSON.stringify( + petitionData + )}` + ); + return next(err); + } + + return res.status(200).json({ general: "Requested" }); +}; diff --git a/src/routes/teams/leave-team.js b/src/routes/teams/leave-team.js index 8a9a954..1311c88 100644 --- a/src/routes/teams/leave-team.js +++ b/src/routes/teams/leave-team.js @@ -1,59 +1,59 @@ -const moment = require('moment'); - -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const teamId = req.params.teamId; - - let team; - try { - team = await Team.findOne({ _id: teamId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Team not found' }); - } - - console.log(`Team ${teamId} failed to be found at leave-team`); - return next(err); - } - - if (!team) { - return res.status(404).json({ general: 'Team not found' }); - } - - if (team.managers.find(m => m.toString() === req.user.id)) { - team.managers = team.managers.filter(m => m.toString() !== req.user.id); - - if (team.managers.length === 0) { - return res.status(400).json({ - general: 'You cannot leave because you are the only manager' - }); - } - } else if (team.members.find(m => m.toString() === req.user.id)) { - team.members = team.members.filter(m => m.toString() !== req.user.id); - } else { - return res.status(400).json({ general: 'You are not a member' }); - } - - const today = moment.utc(); - team.updatedAt = today.toDate(); - - try { - await team.save(); - } catch (err) { - console.log(`Team ${team.id} failed to be updated at leave-team`); - return next(err); - } - - req.user.teams = req.user.teams.filter(t => t.toString() !== team.id); - req.user.updatedAt = today.toDate(); - - try { - await req.user.save(); - } catch (err) { - console.log(`User ${req.user.id} failed to be updated at leave-team`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Team } = require('../../models/team'); + +module.exports = async (req, res, next) => { + const teamId = req.params.teamId; + + let team; + try { + team = await Team.findOne({ _id: teamId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Team not found' }); + } + + console.log(`Team ${teamId} failed to be found at leave-team`); + return next(err); + } + + if (!team) { + return res.status(404).json({ general: 'Team not found' }); + } + + if (team.managers.find((m) => m.toString() === req.user.id)) { + team.managers = team.managers.filter((m) => m.toString() !== req.user.id); + + if (team.managers.length === 0) { + return res.status(400).json({ + general: 'You cannot leave because you are the only manager' + }); + } + } else if (team.members.find((m) => m.toString() === req.user.id)) { + team.members = team.members.filter((m) => m.toString() !== req.user.id); + } else { + return res.status(400).json({ general: 'You are not a member' }); + } + + const today = moment.utc(); + team.updatedAt = today.toDate(); + + try { + await team.save(); + } catch (err) { + console.log(`Team ${team.id} failed to be updated at leave-team`); + return next(err); + } + + req.user.teams = req.user.teams.filter((t) => t.toString() !== team.id); + req.user.updatedAt = today.toDate(); + + try { + await req.user.save(); + } catch (err) { + console.log(`User ${req.user.id} failed to be updated at leave-team`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/teams/list-teams.js b/src/routes/teams/list-teams.js index a667d81..f3a9938 100644 --- a/src/routes/teams/list-teams.js +++ b/src/routes/teams/list-teams.js @@ -1,104 +1,106 @@ -const mongoose = require('mongoose'); -const { toBoolean } = require('validator'); - -const { Team } = require('../../models/team'); - -const { validateListTeams } = require('./validations'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListTeams(queryParams); - if (!isValid) return res.status(400).json(errors); - - const teamsQuery = { isArchived: false }; - - if (queryParams.keywords) { - teamsQuery.$text = { $search: queryParams.keywords }; - } - - if (queryParams.managed) { - if (!req.user) { - return res - .status(400) - .json({ general: 'You cannot use managed filter as anonymous' }); - } - - const managed = toBoolean(queryParams.managed); - if (managed) { - teamsQuery.managers = { $in: [mongoose.Types.ObjectId(req.user.id)] }; - } else { - teamsQuery.managers = { $nin: [mongoose.Types.ObjectId(req.user.id)] }; - } - } - - let sortBy = queryParams.sortBy || '-reviewsAmount'; - let page = queryParams.page ? Number(queryParams.page) - 1 : 0; - const pageLimit = Number(queryParams.pageLimit) || 12; - - let teams; - let total; - try { - [teams, total] = await Promise.all([ - Team.aggregate() - .match(teamsQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - name: 1, - reviewsAmount: 1 - }) - .sort(sortBy) - .skip(page * pageLimit) - .limit(pageLimit), - Team.find(teamsQuery).count() - ]); - } catch (err) { - console.log('Teams failed to be found or count at list-teams'); - return next(err); - } - - const getTeamsRankings = teams.map(t => - Team.find({ reviewsAmount: { $gt: t.reviewsAmount } }).count() - ); - - let teamsRankings; - try { - teamsRankings = await Promise.all(getTeamsRankings); - } catch (err) { - console.log('Teams rankings failed to be count at list-teams'); - return next(err); - } - - teams = teams.map((t, i) => ({ - id: t.id, - avatar: t.avatar, - description: t.description, - name: t.name, - ranking: teamsRankings[i] + 1, - reviewsAmount: t.reviewsAmount - })); - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be equal to or less than ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - return res.status(200).json({ - page: page + 1, - lastPage, - pageLimit, - total, - sortBy, - results: teams - }); -}; +const mongoose = require("mongoose"); +const { toBoolean } = require("validator"); + +const { Team } = require("../../models/team"); + +const { validateListTeams } = require("./validations"); + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListTeams(queryParams); + if (!isValid) return res.status(400).json(errors); + + const teamsQuery = { isArchived: false }; + + if (queryParams.keywords) { + teamsQuery.$text = { $search: queryParams.keywords }; + } + + if (queryParams.managed) { + if (!req.user) { + return res + .status(400) + .json({ general: "You cannot use managed filter as anonymous" }); + } + + const managed = toBoolean(queryParams.managed); + if (managed) { + teamsQuery.managers = { $in: [new mongoose.Types.ObjectId(req.user.id)] }; + } else { + teamsQuery.managers = { + $nin: [new mongoose.Types.ObjectId(req.user.id)], + }; + } + } + + let sortBy = queryParams.sortBy || "-reviewsAmount"; + let page = queryParams.page ? Number(queryParams.page) - 1 : 0; + const pageLimit = Number(queryParams.pageLimit) || 12; + + let teams; + let total; + try { + [teams, total] = await Promise.all([ + Team.aggregate() + .match(teamsQuery) + .project({ + _id: 0, + id: "$_id", + avatar: 1, + description: 1, + name: 1, + reviewsAmount: 1, + }) + .sort(sortBy) + .skip(page * pageLimit) + .limit(pageLimit), + Team.countDocuments(teamsQuery), + ]); + } catch (err) { + console.log("Teams failed to be found or count at list-teams"); + return next(err); + } + + const getTeamsRankings = teams.map((t) => + Team.countDocuments({ reviewsAmount: { $gt: t.reviewsAmount } }) + ); + + let teamsRankings; + try { + teamsRankings = await Promise.all(getTeamsRankings); + } catch (err) { + console.log("Teams rankings failed to be count at list-teams"); + return next(err); + } + + teams = teams.map((t, i) => ({ + id: t.id, + avatar: t.avatar, + description: t.description, + name: t.name, + ranking: teamsRankings[i] + 1, + reviewsAmount: t.reviewsAmount, + })); + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be equal to or less than ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + return res.status(200).json({ + page: page + 1, + lastPage, + pageLimit, + total, + sortBy, + results: teams, + }); +}; diff --git a/src/routes/teams/validations.js b/src/routes/teams/validations.js index 045359a..ce1f9b2 100644 --- a/src/routes/teams/validations.js +++ b/src/routes/teams/validations.js @@ -1,134 +1,134 @@ -const { isEmpty } = require('lodash'); -const { isInt, isMongoId } = require('validator'); - -module.exports = { - validateCreateTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name === 'undefined' || data.name === '') { - errors.name = 'Is required'; - } else if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditTeam(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.name !== 'undefined') { - if (typeof data.name !== 'string') { - errors.name = 'Should be a string'; - } else if (data.name === '') { - errors.name = 'Is required'; - } - } - - if (data.managers) { - if (!Array.isArray(data.managers)) { - errors.managers = 'Should be an array'; - } else { - data.managers.some(m => { - if (typeof m !== 'string') { - errors.managers = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else { - if (m.startsWith('-')) { - m = m.substring(1); - } - - if (!isMongoId(m)) { - errors.managers = `${m} should be an id`; - return true; - } - } - }); - } - } - - if (data.members) { - if (!Array.isArray(data.members)) { - errors.members = 'Should be an array'; - } else { - data.members.some(m => { - if (typeof m !== 'string') { - errors.members = 'Should only have string values'; - return true; - } else if (!m) { - errors.managers = 'Should not have empty values'; - return true; - } else if (!m.startsWith('-')) { - errors.members = `${m} should start with -`; - return true; - } else if (!isMongoId(m.substring(1))) { - errors.members = `${m} should be an id`; - return true; - } - }); - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListTeams(queryParams) { - const errors = {}; - - if ( - queryParams.managed && - queryParams.managed !== '0' && - queryParams.managed !== '1' - ) { - errors.managed = 'Should be 0 or 1'; - } - - const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - if (queryParams.page) { - if (!isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be a positive integer'; - } - } - - if (queryParams.pageLimit) { - if (!isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be a positive integer'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than 13'; - } - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); +const { isInt, isMongoId } = require('validator'); + +module.exports = { + validateCreateTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name === 'undefined' || data.name === '') { + errors.name = 'Is required'; + } else if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditTeam(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.name !== 'undefined') { + if (typeof data.name !== 'string') { + errors.name = 'Should be a string'; + } else if (data.name === '') { + errors.name = 'Is required'; + } + } + + if (data.managers) { + if (!Array.isArray(data.managers)) { + errors.managers = 'Should be an array'; + } else { + data.managers.some((m) => { + if (typeof m !== 'string') { + errors.managers = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else { + if (m.startsWith('-')) { + m = m.substring(1); + } + + if (!isMongoId(m)) { + errors.managers = `${m} should be an id`; + return true; + } + } + }); + } + } + + if (data.members) { + if (!Array.isArray(data.members)) { + errors.members = 'Should be an array'; + } else { + data.members.some((m) => { + if (typeof m !== 'string') { + errors.members = 'Should only have string values'; + return true; + } else if (!m) { + errors.managers = 'Should not have empty values'; + return true; + } else if (!m.startsWith('-')) { + errors.members = `${m} should start with -`; + return true; + } else if (!isMongoId(m.substring(1))) { + errors.members = `${m} should be an id`; + return true; + } + }); + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListTeams(queryParams) { + const errors = {}; + + if ( + queryParams.managed && + queryParams.managed !== '0' && + queryParams.managed !== '1' + ) { + errors.managed = 'Should be 0 or 1'; + } + + const sortOptions = ['name', '-name', 'reviewsAmount', '-reviewsAmount']; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + if (queryParams.page) { + if (!isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be a positive integer'; + } + } + + if (queryParams.pageLimit) { + if (!isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be a positive integer'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than 13'; + } + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/users/archive-user.js b/src/routes/users/archive-user.js index 46e3f3c..9bf62e2 100644 --- a/src/routes/users/archive-user.js +++ b/src/routes/users/archive-user.js @@ -1,101 +1,101 @@ -const moment = require('moment'); - -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at archive-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - let activateAccountTicket; - let passwordTicket; - let refreshToken; - try { - [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ - ActivationTicket.findOne({ email: user.email }), - PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) - ]); - } catch (err) { - console.log( - `Activate account ticket, password ticket or refresh token with email ${ - user.email - } failed to be found at archive-user.` - ); - return next(err); - } - - if (activateAccountTicket) { - try { - await activateAccountTicket.remove(); - } catch (err) { - console.log( - `Activate user ticket with key ${ - activateAccountTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (passwordTicket) { - try { - await passwordTicket.remove(); - } catch (err) { - console.log( - `Password ticket with key ${ - passwordTicket.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh token with key ${ - refreshToken.key - } failed to be removed at archive-user.` - ); - return next(err); - } - } - - user.isArchived = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be updated at archive-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require("moment"); + +const { ActivationTicket } = require("../../models/activation-ticket"); +const { PasswordTicket } = require("../../models/password-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); + } + + console.log(`User with Id ${userId} failed to be found at archive-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: "User not found" }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: "Forbidden action" }); + } + + let activateAccountTicket; + let passwordTicket; + let refreshToken; + try { + [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ + ActivationTicket.findOne({ email: user.email }), + PasswordTicket.findOne({ email: user.email }), + RefreshToken.findOne({ userId: user.id }), + ]); + } catch (err) { + console.log( + `Activate account ticket, password ticket or refresh token with email ${ + user.email + } failed to be found at archive-user.` + ); + return next(err); + } + + if (activateAccountTicket) { + try { + await ActivationTicket.deleteOne({ email: user.email }); + } catch (err) { + console.log( + `Activate user ticket with key ${ + activateAccountTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (passwordTicket) { + try { + await PasswordTicket.deleteOne({ email: user.email }); + } catch (err) { + console.log( + `Password ticket with key ${ + passwordTicket.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + if (refreshToken) { + try { + await RefreshToken.deleteOne({ userId: user.id }); + } catch (err) { + console.log( + `Refresh token with key ${ + refreshToken.key + } failed to be removed at archive-user.` + ); + return next(err); + } + } + + user.isArchived = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with email ${user.email} failed to be updated at archive-user.` + ); + return next(err); + } + + return res.status(200).json({ general: "Success" }); +}; diff --git a/src/routes/users/block-user.js b/src/routes/users/block-user.js index 6e93c8a..44c88ec 100644 --- a/src/routes/users/block-user.js +++ b/src/routes/users/block-user.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at block-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = true; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log(`User with Id ${user.id} failed to be updated at block-user.`); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at block-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = true; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log(`User with Id ${user.id} failed to be updated at block-user.`); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/change-password.js b/src/routes/users/change-password.js index 13b2391..db7dbed 100644 --- a/src/routes/users/change-password.js +++ b/src/routes/users/change-password.js @@ -1,64 +1,64 @@ -const moment = require('moment'); - -const { RefreshToken } = require('../../models/refresh-token'); - -const { validateChangePassword } = require('./validations'); - -module.exports = async (req, res, next) => { - if (req.user.isBlocked) { - return res.status(423).json({ general: 'You are blocked' }); - } - - const { errors, isValid } = validateChangePassword(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const oldPassword = req.body.oldPassword; - const password = req.body.password; - - const passwordMatches = req.user.comparePassword(oldPassword); - - if (!passwordMatches) { - return res.status(400).json({ oldPassword: 'Wrong password' }); - } - - let refreshToken; - try { - refreshToken = await RefreshToken.findOne({ userId: req.user.id }); - } catch (err) { - console.log( - `Refresh Token with userId ${ - req.user.id - } failed to be found at change-password.` - ); - return next(err); - } - - if (refreshToken) { - try { - await refreshToken.remove(); - } catch (err) { - console.log( - `Refresh Token with key ${ - refreshToken.key - } failed to be removed at change-password.` - ); - return next(err); - } - } - - req.user.password = password; - req.user.updatedAt = moment.utc().toDate(); - - try { - req.user.save(); - } catch (err) { - console.log( - `User with Id ${req.user.id} failed to be updated at change-password.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require("moment"); + +const { RefreshToken } = require("../../models/refresh-token"); + +const { validateChangePassword } = require("./validations"); + +module.exports = async (req, res, next) => { + if (req.user.isBlocked) { + return res.status(423).json({ general: "You are blocked" }); + } + + const { errors, isValid } = validateChangePassword(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const oldPassword = req.body.oldPassword; + const password = req.body.password; + + const passwordMatches = req.user.comparePassword(oldPassword); + + if (!passwordMatches) { + return res.status(400).json({ oldPassword: "Wrong password" }); + } + + let refreshToken; + try { + refreshToken = await RefreshToken.findOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh Token with userId ${ + req.user.id + } failed to be found at change-password.` + ); + return next(err); + } + + if (refreshToken) { + try { + await RefreshToken.deleteOne({ userId: req.user.id }); + } catch (err) { + console.log( + `Refresh Token with key ${ + refreshToken.key + } failed to be removed at change-password.` + ); + return next(err); + } + } + + req.user.password = password; + req.user.updatedAt = moment.utc().toDate(); + + try { + req.user.save(); + } catch (err) { + console.log( + `User with Id ${req.user.id} failed to be updated at change-password.` + ); + return next(err); + } + + return res.status(200).json({ general: "Success" }); +}; diff --git a/src/routes/users/create-user.js b/src/routes/users/create-user.js index 937fb97..eccfd01 100644 --- a/src/routes/users/create-user.js +++ b/src/routes/users/create-user.js @@ -1,153 +1,153 @@ -const crypto = require('crypto'); - -const moment = require('moment'); -const { pick } = require('lodash'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); - -const { validateCreateUser } = require('./validations'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const { errors, isValid } = validateCreateUser(req.body); - if (!isValid) { - return res.status(400).json(errors); - } - - const userData = pick(req.body, [ - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'password', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - userData.firstName = cleanSpaces(userData.firstName); - userData.lastName = cleanSpaces(userData.lastName); - - let usernameSent = true; - - if (!userData.username) { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}`; - usernameSent = false; - } - - let repeatedUsers; - try { - repeatedUsers = await User.find({ - $or: [{ email: userData.email }, { username: userData.username }], - isArchived: false - }); - } catch (err) { - console.log('Users failed to be found at create-user.'); - return next(err); - } - - if (repeatedUsers && repeatedUsers.length > 0) { - for (const user of repeatedUsers) { - if (user.email === userData.email) { - return res.status(400).json({ email: 'Is already taken' }); - } else if (usernameSent && user.username === userData.username) { - return res.status(400).json({ username: 'Is already taken' }); - } - - let repeatedUser; - do { - userData.username = `${slugify(userData.firstName)}-${slugify( - userData.lastName - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}`; - - try { - repeatedUser = await User.findOne({ - username: userData.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${ - userData.username - } failed to be found at create-user.` - ); - return next(err); - } - } while (repeatedUser && repeatedUser.username === userData.username); - } - } - - let user; - try { - user = await User.create(userData); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User with email ${userData.email} failed to be created at create-user.` - ); - return next(err); - } - - const refreshTokenData = { - expiresAt: moment - .utc() - .add(14, 'days') - .toDate(), - key: `${user.id}${crypto.randomBytes(40).toString('hex')}`, - userId: user.id - }; - try { - await RefreshToken.create(refreshTokenData); - } catch (err) { - console.log( - `Refresh token with userId ${ - refreshTokenData.userId - } failed to be created at create-user.` - ); - return next(err); - } - - const dataResponse = pick(user, [ - '_id', - 'description', - 'disabilities', - 'email', - 'firstName', - 'gender', - 'isSubscribed', - 'lastName', - 'phone', - 'showDisabilities', - 'showEmail', - 'showPhone', - 'username', - 'zip' - ]); - return res.status(201).json(dataResponse); -}; +const crypto = require("crypto"); + +const moment = require("moment"); +const { pick } = require("lodash"); +const randomstring = require("randomstring"); +const slugify = require("speakingurl"); + +const { cleanSpaces } = require("../../helpers"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); + +const { validateCreateUser } = require("./validations"); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: "Forbidden action" }); + } + + const { errors, isValid } = validateCreateUser(req.body); + if (!isValid) { + return res.status(400).json(errors); + } + + const userData = pick(req.body, [ + "description", + "disabilities", + "email", + "firstName", + "gender", + "isSubscribed", + "lastName", + "password", + "phone", + "showDisabilities", + "showEmail", + "showPhone", + "username", + "zip", + ]); + userData.firstName = cleanSpaces(userData.firstName); + userData.lastName = cleanSpaces(userData.lastName); + + let usernameSent = true; + + if (!userData.username) { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}`; + usernameSent = false; + } + + let repeatedUsers; + try { + repeatedUsers = await User.find({ + $or: [{ email: userData.email }, { username: userData.username }], + isArchived: false, + }); + } catch (err) { + console.log("Users failed to be found at create-user."); + return next(err); + } + + if (repeatedUsers && repeatedUsers.length > 0) { + for (const user of repeatedUsers) { + if (user.email === userData.email) { + return res.status(400).json({ email: "Is already taken" }); + } else if (usernameSent && user.username === userData.username) { + return res.status(400).json({ username: "Is already taken" }); + } + + let repeatedUser; + do { + userData.username = `${slugify(userData.firstName)}-${slugify( + userData.lastName + )}-${randomstring.generate({ + length: 5, + capitalization: "lowercase", + })}`; + + try { + repeatedUser = await User.findOne({ + username: userData.username, + isArchived: false, + }); + } catch (err) { + console.log( + `User with username ${ + userData.username + } failed to be found at create-user.` + ); + return next(err); + } + } while (repeatedUser && repeatedUser.username === userData.username); + } + } + + let user; + try { + user = await User.create(userData); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User with email ${userData.email} failed to be created at create-user.` + ); + return next(err); + } + + const refreshTokenData = { + expiresAt: moment.utc().add(14, "days").toDate(), + key: `${user.id}${crypto.randomBytes(40).toString("hex")}`, + userId: user.id, + }; + try { + await RefreshToken.create(refreshTokenData); + } catch (err) { + console.log( + `Refresh token with userId ${ + refreshTokenData.userId + } failed to be created at create-user.` + ); + return next(err); + } + + const dataResponse = pick(user, [ + "_id", + "description", + "disabilities", + "email", + "firstName", + "gender", + "isSubscribed", + "lastName", + "race", + "birthday", + "disability", + "phone", + "showDisabilities", + "showEmail", + "showPhone", + "username", + "zip", + ]); + return res.status(201).json(dataResponse); +}; diff --git a/src/routes/users/deactivate-user.js b/src/routes/users/deactivate-user.js index 880289f..642930a 100644 --- a/src/routes/users/deactivate-user.js +++ b/src/routes/users/deactivate-user.js @@ -1,9 +1,9 @@ -const moment = require('moment'); +const moment = require("moment"); -const { ActivationTicket } = require('../../models/activation-ticket'); -const { PasswordTicket } = require('../../models/password-ticket'); -const { RefreshToken } = require('../../models/refresh-token'); -const { User } = require('../../models/user'); +const { ActivationTicket } = require("../../models/activation-ticket"); +const { PasswordTicket } = require("../../models/password-ticket"); +const { RefreshToken } = require("../../models/refresh-token"); +const { User } = require("../../models/user"); module.exports = async (req, res, next) => { const userId = req.user._id; @@ -12,8 +12,8 @@ module.exports = async (req, res, next) => { try { user = await User.findOne({ _id: userId, isArchived: false }); } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); } console.log(`User with Id ${userId} failed to be found at archive-user.`); @@ -21,7 +21,7 @@ module.exports = async (req, res, next) => { } if (!user) { - return res.status(404).json({ general: 'User not found' }); + return res.status(404).json({ general: "User not found" }); } let activateAccountTicket; @@ -31,7 +31,7 @@ module.exports = async (req, res, next) => { [activateAccountTicket, passwordTicket, refreshToken] = await Promise.all([ ActivationTicket.findOne({ email: user.email }), PasswordTicket.findOne({ email: user.email }), - RefreshToken.findOne({ userId: user.id }) + RefreshToken.findOne({ userId: user.id }), ]); } catch (err) { console.log( @@ -44,7 +44,7 @@ module.exports = async (req, res, next) => { if (activateAccountTicket) { try { - await activateAccountTicket.remove(); + await ActivationTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Activate user ticket with key ${ @@ -57,7 +57,7 @@ module.exports = async (req, res, next) => { if (passwordTicket) { try { - await passwordTicket.remove(); + await PasswordTicket.deleteOne({ email: user.email }); } catch (err) { console.log( `Password ticket with key ${ @@ -70,7 +70,7 @@ module.exports = async (req, res, next) => { if (refreshToken) { try { - await refreshToken.remove(); + await RefreshToken.deleteOne({ userId: user.id }); } catch (err) { console.log( `Refresh token with key ${ @@ -93,5 +93,5 @@ module.exports = async (req, res, next) => { return next(err); } - return res.status(200).json({ general: 'Success' }); + return res.status(200).json({ general: "Success" }); }; diff --git a/src/routes/users/delete-user.js b/src/routes/users/delete-user.js index 39464d2..6b32ce3 100644 --- a/src/routes/users/delete-user.js +++ b/src/routes/users/delete-user.js @@ -1,36 +1,36 @@ -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: true }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Archived user not found' }); - } - - console.log(`User with Id ${userId} failed to be found at delete-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'Archived user not found' }); - } - - try { - await user.remove(); - } catch (err) { - console.log( - `User with email ${user.email} failed to be deleted at delete-user.` - ); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: "Forbidden action" }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: true }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "Archived user not found" }); + } + + console.log(`User with Id ${userId} failed to be found at delete-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: "Archived user not found" }); + } + + try { + await User.deleteOne({ _id: userId, isArchived: true }); + } catch (err) { + console.log( + `User with email ${user.email} failed to be deleted at delete-user.` + ); + return next(err); + } + + return res.status(204).json({ general: "Success" }); +}; diff --git a/src/routes/users/edit-user.js b/src/routes/users/edit-user.js index ae6cb80..1f43af0 100644 --- a/src/routes/users/edit-user.js +++ b/src/routes/users/edit-user.js @@ -1,160 +1,169 @@ -const moment = require('moment'); - -const { cleanSpaces } = require('../../helpers'); -const { Photo } = require('../../models/photo'); -const { User } = require('../../models/user'); - -const { validateEditUser } = require('./validations'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at edit-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - if (user.id !== req.user.id && !req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const data = req.body; - - const { errors, isValid } = validateEditUser(data); - if (!isValid) return res.status(400).json(errors); - - if ( - data.avatar && - !data.avatar.includes('default') && - data.avatar !== user.avatar - ) { - let avatar; - try { - avatar = await Photo.findOne({ url: data.avatar }); - } catch (err) { - console.log(`Avatar ${data.avatar} failed to be found at edit-user`); - return next(err); - } - - if (!avatar) { - return res.status(404).json({ avatar: 'Not found' }); - } - - user.avatar = data.avatar; - } else if (data.avatar === '') { - user.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/default.png`; - } - - user.description = data.description || user.description; - - user.disabilities = data.disabilities || user.disabilities; - - user.firstName = data.firstName - ? cleanSpaces(data.firstName) - : user.firstName; - - user.gender = data.gender || user.gender; - - user.isSubscribed = - typeof data.isSubscribed !== 'undefined' - ? data.isSubscribed - : user.isSubscribed; - - user.language = data.language || user.language; - - user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; - - user.phone = data.phone || user.phone; - - user.showDisabilities = - typeof data.showDisabilities !== 'undefined' - ? data.showDisabilities - : user.showDisabilities; - - user.showEmail = - typeof data.showEmail !== 'undefined' ? data.showEmail : user.showEmail; - - user.showPhone = - typeof data.showPhone !== 'undefined' ? data.showPhone : user.showPhone; - - if (data.username && data.username !== user.username) { - let repeatedUser; - try { - repeatedUser = await User.findOne({ - username: data.username, - isArchived: false - }); - } catch (err) { - console.log( - `User with username ${data.username} failed to be found at edit-user.` - ); - return next(err); - } - - if (repeatedUser) { - return res.status(400).json({ username: 'Is already taken' }); - } - - user.username = data.username; - } - - user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; - - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - if (typeof err.errors === 'object') { - const validationErrors = {}; - - Object.keys(err.errors).forEach(key => { - validationErrors[key] = err.errors[key].message; - }); - - return res.status(400).json(validationErrors); - } - - console.log( - `User ${ - user.id - } failed to be updated at edit-user.\nData: ${JSON.stringify( - data, - null, - 2 - )}` - ); - return next(err); - } - - const dataResponse = { - id: user.id, - avatar: user.avatar, - description: user.description, - disabilities: user.disabilities, - firstName: user.firstName, - gender: user.gender, - isSubscribed: user.isSubscribed, - lastName: user.lastName, - phone: user.phone, - showDisabilities: user.showDisabilities, - showEmail: user.showEmail, - showPhone: user.showPhone, - username: user.username, - zip: user.zip - }; - return res.status(200).json(dataResponse); -}; +const moment = require("moment"); + +const { cleanSpaces } = require("../../helpers"); +const { Photo } = require("../../models/photo"); +const { User } = require("../../models/user"); + +const { validateEditUser } = require("./validations"); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); + } + + console.log(`User with Id ${userId} failed to be found at edit-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: "User not found" }); + } + + if (user.id !== req.user.id && !req.user.isAdmin) { + return res.status(403).json({ general: "Forbidden action" }); + } + + const data = req.body; + + const { errors, isValid } = validateEditUser(data); + if (!isValid) return res.status(400).json(errors); + + if ( + data.avatar && + !data.avatar.includes("default") && + data.avatar !== user.avatar + ) { + let avatar; + try { + avatar = await Photo.findOne({ url: data.avatar }); + } catch (err) { + console.log(`Avatar ${data.avatar} failed to be found at edit-user`); + return next(err); + } + + if (!avatar) { + return res.status(404).json({ avatar: "Not found" }); + } + + user.avatar = data.avatar; + } else if (data.avatar === "") { + user.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/default.png`; + } + + user.description = data.description || user.description; + + user.disabilities = data.disabilities || user.disabilities; + user.disability = data.disability || ""; + user.birthday = data.birthday || user.birthday; + user.race = data.race || ""; + user.aboutMe = data.aboutMe || ""; + + user.firstName = data.firstName + ? cleanSpaces(data.firstName) + : user.firstName; + + user.gender = data.gender || user.gender; + + user.isSubscribed = + typeof data.isSubscribed !== "undefined" + ? data.isSubscribed + : user.isSubscribed; + + user.language = data.language || user.language; + + user.lastName = data.lastName ? cleanSpaces(data.lastName) : user.lastName; + + user.phone = data.phone || user.phone; + + user.showDisabilities = + typeof data.showDisabilities !== "undefined" + ? data.showDisabilities + : user.showDisabilities; + + user.showEmail = + typeof data.showEmail !== "undefined" ? data.showEmail : user.showEmail; + + user.showPhone = + typeof data.showPhone !== "undefined" ? data.showPhone : user.showPhone; + + if (data.username && data.username !== user.username) { + let repeatedUser; + try { + repeatedUser = await User.findOne({ + username: data.username, + isArchived: false, + }); + } catch (err) { + console.log( + `User with username ${data.username} failed to be found at edit-user.` + ); + return next(err); + } + + if (repeatedUser) { + return res.status(400).json({ username: "Is already taken" }); + } + + user.username = data.username; + } + + user.zip = data.zip ? cleanSpaces(data.zip) : user.zip; + + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + if (typeof err.errors === "object") { + const validationErrors = {}; + + Object.keys(err.errors).forEach((key) => { + validationErrors[key] = err.errors[key].message; + }); + + return res.status(400).json(validationErrors); + } + + console.log( + `User ${ + user.id + } failed to be updated at edit-user.\nData: ${JSON.stringify( + data, + null, + 2 + )}` + ); + return next(err); + } + + const dataResponse = { + id: user.id, + avatar: user.avatar, + description: user.description, + race: user?.race, + birthday: user?.birthday, + disabilities: user.disabilities, + firstName: user.firstName, + disability: user.disability, + email: user?.email, + gender: user.gender, + isSubscribed: user.isSubscribed, + lastName: user.lastName, + phone: user.phone, + showDisabilities: user.showDisabilities, + showEmail: user.showEmail, + showPhone: user.showPhone, + username: user.username, + zip: user.zip, + aboutMe:user.aboutMe + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/get-profile.js b/src/routes/users/get-profile.js index 0d83096..6afc6a3 100644 --- a/src/routes/users/get-profile.js +++ b/src/routes/users/get-profile.js @@ -1,93 +1,106 @@ -const { Event } = require('../../models/event'); -const { Team } = require('../../models/team'); - -module.exports = async (req, res, next) => { - const getUserTeams = req.user.teams.map(t => Team.findOne({ _id: t })); - let userTeams; - try { - userTeams = await Promise.all(getUserTeams); - } catch (err) { - console.log('Teams failed to be found at get-profile'); - return next(err); - } - - const teams = []; - const managedTeams = []; - userTeams.map(t => { - if (t) { - const teamManagers = t.managers.map(m => m.toString()); - if (teamManagers.includes(req.user.id)) { - managedTeams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } else { - teams.push({ - id: t.id.toString(), - avatar: t.avatar, - name: t.name - }); - } - } - }); - - const getUserEvents = req.user.events.map(e => Event.findOne({ _id: e })); - let userEvents; - try { - userEvents = await Promise.all(getUserEvents); - } catch (err) { - console.log('Events failed to be found at get-profile'); - return next(err); - } - - const events = []; - const managedEvents = []; - userEvents.map(e => { - if (e) { - const eventManagers = e.managers.map(m => m.toString()); - if (eventManagers.includes(req.user.id)) { - managedEvents.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } else { - events.push({ - id: e.id.toString(), - endDate: e.endDate, - name: e.name, - poster: e.poster, - startDate: e.startDate - }); - } - } - }); - - const userData = { - id: req.user.id, - avatar: req.user.avatar, - description: req.user.description, - disabilities: req.user.disabilities, - email: req.user.email, - events, - firstName: req.user.firstName, - gender: req.user.gender, - isSubscribed: req.user.isSubscribed, - lastName: req.user.lastName, - managedEvents, - managedTeams, - phone: req.user.phone, - reviewFieldsAmount: req.user.reviewFieldsAmount, - reviewsAmount: req.user.reviewsAmount, - showDisabilities: req.user.showDisabilities, - showEmail: req.user.showEmail, - showPhone: req.user.showPhone, - teams, - username: req.user.username, - zip: req.user.zip - }; - return res.status(200).json(userData); -}; +const { Event } = require("../../models/event"); +const { Team } = require("../../models/team"); +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + const getUserTeams = req.user.teams.map((t) => Team.findOne({ _id: t })); + let userTeams; + try { + userTeams = await Promise.all(getUserTeams); + } catch (err) { + console.log("Teams failed to be found at get-profile"); + return next(err); + } + + const teams = []; + const managedTeams = []; + userTeams.map((t) => { + if (t) { + const teamManagers = t.managers.map((m) => m.toString()); + if (teamManagers.includes(req.user.id)) { + managedTeams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name, + }); + } else { + teams.push({ + id: t.id.toString(), + avatar: t.avatar, + name: t.name, + }); + } + } + }); + + const getUserEvents = req.user.events.map((e) => Event.findOne({ _id: e })); + let userEvents; + try { + userEvents = await Promise.all(getUserEvents); + } catch (err) { + console.log("Events failed to be found at get-profile"); + return next(err); + } + + const events = []; + const managedEvents = []; + userEvents.map((e) => { + if (e) { + const eventManagers = e.managers.map((m) => m.toString()); + if (eventManagers.includes(req.user.id)) { + managedEvents.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate, + }); + } else { + events.push({ + id: e.id.toString(), + endDate: e.endDate, + name: e.name, + poster: e.poster, + startDate: e.startDate, + }); + } + } + }); + console.log(req.user.reviewsAmount, typeof req.user.reviewsAmount); + + const ranking = + (await User.countDocuments({ + reviewsAmount: { $gt: req.user.reviewsAmount ?? 0 }, + })) + 1; + + const userData = { + id: req.user.id, + avatar: req.user.avatar, + description: req.user.description, + disabilities: req.user.disabilities, + email: req.user.email, + events, + firstName: req.user.firstName, + gender: req.user.gender, + isSubscribed: req.user.isSubscribed, + lastName: req.user.lastName, + managedEvents, + managedTeams, + phone: req.user.phone, + reviewFieldsAmount: req.user.reviewFieldsAmount, + reviewsAmount: req.user.reviewsAmount, + showDisabilities: req.user.showDisabilities, + showEmail: req.user.showEmail, + showPhone: req.user.showPhone, + teams, + username: req.user.username, + zip: req.user.zip, + avatar: req.user.avatar, + race: req.user?.race, + birthday: req.user?.birthday, + disability: req.user.disability, + ranking, + aboutMe:req.user.aboutMe, + }; + return res.status(200).json(userData); +}; diff --git a/src/routes/users/get-user.js b/src/routes/users/get-user.js index a24972f..d4a3a21 100644 --- a/src/routes/users/get-user.js +++ b/src/routes/users/get-user.js @@ -1,127 +1,130 @@ -const mongoose = require('mongoose'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - const userId = req.params.userId; - - const userIdObj = mongoose.Types.ObjectId(userId); - let user; - try { - user = await User.aggregate([ - { - $match: { _id: userIdObj } - }, - { - $lookup: { - from: 'events', - let: { events: '$events' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$events'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - endDate: 1, - name: 1, - poster: 1, - startDate: 1 - } - } - ], - as: 'events' - } - }, - { - $lookup: { - from: 'teams', - let: { teams: '$teams' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$teams'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - name: 1 - } - } - ], - as: 'teams' - } - }, - { - $lookup: { - from: 'users', - let: { reviewsAmount: '$reviewsAmount' }, - pipeline: [ - { - $match: { - $expr: { - $gt: ['$reviewsAmount', '$$reviewsAmount'] - } - } - }, - { - $count: 'ranking' - } - ], - as: 'ranking' - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - description: 1, - disabilities: 1, - email: 1, - events: 1, - firstName: 1, - gender: 1, - isSubscribed: 1, - language: 1, - lastName: 1, - phone: 1, - ranking: 1, - reviewsAmount: 1, - showDisabilities: 1, - showEmail: 1, - showPhone: 1, - teams: 1, - username: 1, - zip: 1 - } - } - ]); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User ${userId} failed to be found at get-user`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - const dataResponse = Object.assign({}, user[0], { - ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1 - }); - return res.status(200).json(dataResponse); -}; +const mongoose = require("mongoose"); + +const { User } = require("../../models/user"); + +module.exports = async (req, res, next) => { + const userId = req.params.userId; + + const userIdObj = new mongoose.Types.ObjectId(userId); + let user; + try { + user = await User.aggregate([ + { + $match: { _id: userIdObj }, + }, + { + $lookup: { + from: "events", + let: { events: "$events" }, + pipeline: [ + { + $match: { + $expr: { + $in: ["$_id", "$$events"], + }, + }, + }, + { + $project: { + _id: 0, + id: "$_id", + endDate: 1, + name: 1, + poster: 1, + startDate: 1, + }, + }, + ], + as: "events", + }, + }, + { + $lookup: { + from: "teams", + let: { teams: "$teams" }, + pipeline: [ + { + $match: { + $expr: { + $in: ["$_id", "$$teams"], + }, + }, + }, + { + $project: { + _id: 0, + id: "$_id", + avatar: 1, + name: 1, + }, + }, + ], + as: "teams", + }, + }, + { + $lookup: { + from: "users", + let: { reviewsAmount: "$reviewsAmount" }, + pipeline: [ + { + $match: { + $expr: { + $gt: ["$reviewsAmount", "$$reviewsAmount"], + }, + }, + }, + { + $count: "ranking", + }, + ], + as: "ranking", + }, + }, + { + $project: { + _id: 0, + id: "$_id", + avatar: 1, + description: 1, + disabilities: 1, + email: 1, + events: 1, + firstName: 1, + gender: 1, + isSubscribed: 1, + language: 1, + lastName: 1, + phone: 1, + race: 1, + birthday: 1, + disability: 1, + ranking: 1, + reviewsAmount: 1, + showDisabilities: 1, + showEmail: 1, + showPhone: 1, + teams: 1, + username: 1, + zip: 1, + }, + }, + ]); + } catch (err) { + if (err.name === "CastError") { + return res.status(404).json({ general: "User not found" }); + } + + console.log(`User ${userId} failed to be found at get-user`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: "User not found" }); + } + + const dataResponse = Object.assign({}, user[0], { + ranking: user[0].ranking.length ? user[0].ranking[0].ranking + 1 : 1, + }); + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/index.js b/src/routes/users/index.js index ec792de..eb38e7a 100644 --- a/src/routes/users/index.js +++ b/src/routes/users/index.js @@ -1,43 +1,43 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveUser = require('./archive-user'); -const blockUser = require('./block-user'); -const changePassword = require('./change-password'); -const createUser = require('./create-user'); -const deleteUser = require('./delete-user'); -const editUser = require('./edit-user'); -const getUser = require('./get-user'); -const getProfile = require('./get-profile'); -const listUsers = require('./list-users'); -const unblockUser = require('./unblock-user'); -const deactivateUser = require('./deactivate-user'); - -const router = new express.Router(); - -router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); -router.put('/password', isAuthenticated({ isOptional: false }), changePassword); -router.get('', isAuthenticated({ isOptional: false }), listUsers); -router.post('', isAuthenticated({ isOptional: false }), createUser); -router.get('/:userId', getUser); -router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); -router.delete( - '/deactivate', - isAuthenticated({ isOptional: false }), - deactivateUser -); -router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); -router.put( - '/:userId/archive', - isAuthenticated({ isOptional: false }), - archiveUser -); -router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); -router.put( - '/:userId/unblock', - isAuthenticated({ isOptional: false }), - unblockUser -); - -module.exports = router; +const express = require('express'); + +const { isAuthenticated } = require('../../helpers'); + +const archiveUser = require('./archive-user'); +const blockUser = require('./block-user'); +const changePassword = require('./change-password'); +const createUser = require('./create-user'); +const deleteUser = require('./delete-user'); +const editUser = require('./edit-user'); +const getUser = require('./get-user'); +const getProfile = require('./get-profile'); +const listUsers = require('./list-users'); +const unblockUser = require('./unblock-user'); +const deactivateUser = require('./deactivate-user'); + +const router = new express.Router(); + +router.get('/profile', isAuthenticated({ isOptional: false }), getProfile); +router.put('/password', isAuthenticated({ isOptional: false }), changePassword); +router.get('', isAuthenticated({ isOptional: false }), listUsers); +router.post('', isAuthenticated({ isOptional: false }), createUser); +router.get('/:userId', getUser); +router.put('/:userId', isAuthenticated({ isOptional: false }), editUser); +router.delete( + '/deactivate', + isAuthenticated({ isOptional: false }), + deactivateUser +); +router.delete('/:userId', isAuthenticated({ isOptional: false }), deleteUser); +router.put( + '/:userId/archive', + isAuthenticated({ isOptional: false }), + archiveUser +); +router.put('/:userId/block', isAuthenticated({ isOptional: false }), blockUser); +router.put( + '/:userId/unblock', + isAuthenticated({ isOptional: false }), + unblockUser +); + +module.exports = router; diff --git a/src/routes/users/list-users.js b/src/routes/users/list-users.js index 543cd98..a3d7e7b 100644 --- a/src/routes/users/list-users.js +++ b/src/routes/users/list-users.js @@ -1,75 +1,75 @@ -const { User } = require('../../models/user'); - -const { validateListUsers } = require('./validations'); - -module.exports = async (req, res, next) => { - const { errors, isValid } = validateListUsers(req.query); - if (!isValid) return res.status(400).json(errors); - - const queryParams = req.query; - - const usersQuery = { isArchived: false }; - usersQuery.$text = { $search: queryParams.keywords || '' }; - - const sort = queryParams.sortBy || { - score: { $meta: 'textScore' } - }; - let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; - const pageLimit = queryParams.pageLimit - ? parseInt(queryParams.pageLimit, 10) - : 12; - - let total; - let users; - try { - [users, total] = await Promise.all([ - User.aggregate() - .match(usersQuery) - .project({ - _id: 0, - id: '$_id', - avatar: 1, - email: 1, - firstName: 1, - lastName: 1, - score: { $meta: 'textScore' }, - username: 1 - }) - .match({ score: { $gt: 1 } }) - .sort(sort) - .skip(page * pageLimit) - .limit(pageLimit), - User.find(usersQuery).count() - ]); - } catch (err) { - console.log( - `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( - usersQuery - )}` - ); - return next(err); - } - - let lastPage = Math.ceil(total / pageLimit); - if (lastPage > 0) { - page += 1; - if (page > lastPage) { - return res - .status(400) - .json({ page: `Should be less than or equal to ${lastPage}` }); - } - } else { - page = null; - lastPage = null; - } - - const dataResponse = { - page, - lastPage, - pageLimit, - total, - sortBy: queryParams.sortBy, - results: users - }; - return res.status(200).json(dataResponse); -}; +const { User } = require('../../models/user'); + +const { validateListUsers } = require('./validations'); + +module.exports = async (req, res, next) => { + const { errors, isValid } = validateListUsers(req.query); + if (!isValid) return res.status(400).json(errors); + + const queryParams = req.query; + + const usersQuery = { isArchived: false }; + usersQuery.$text = { $search: queryParams.keywords || '' }; + + const sort = queryParams.sortBy || { + score: { $meta: 'textScore' } + }; + let page = queryParams.page ? parseInt(queryParams.page, 10) - 1 : 1; + const pageLimit = queryParams.pageLimit + ? parseInt(queryParams.pageLimit, 10) + : 12; + + let total; + let users; + try { + [users, total] = await Promise.all([ + User.aggregate() + .match(usersQuery) + .project({ + _id: 0, + id: '$_id', + avatar: 1, + email: 1, + firstName: 1, + lastName: 1, + score: { $meta: 'textScore' }, + username: 1 + }) + .match({ score: { $gt: 1 } }) + .sort(sort) + .skip(page * pageLimit) + .limit(pageLimit), + User.find(usersQuery).count() + ]); + } catch (err) { + console.log( + `Users failed to be found or count at list-users.\nusersQuery: ${JSON.stringify( + usersQuery + )}` + ); + return next(err); + } + + let lastPage = Math.ceil(total / pageLimit); + if (lastPage > 0) { + page += 1; + if (page > lastPage) { + return res + .status(400) + .json({ page: `Should be less than or equal to ${lastPage}` }); + } + } else { + page = null; + lastPage = null; + } + + const dataResponse = { + page, + lastPage, + pageLimit, + total, + sortBy: queryParams.sortBy, + results: users + }; + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/users/unblock-user.js b/src/routes/users/unblock-user.js index 88a9c17..3340936 100644 --- a/src/routes/users/unblock-user.js +++ b/src/routes/users/unblock-user.js @@ -1,41 +1,41 @@ -const moment = require('moment'); - -const { User } = require('../../models/user'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const userId = req.params.userId; - - let user; - try { - user = await User.findOne({ _id: userId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'User not found' }); - } - - console.log(`User with Id ${userId} failed to be found at unblock-user.`); - return next(err); - } - - if (!user) { - return res.status(404).json({ general: 'User not found' }); - } - - user.isBlocked = false; - user.updatedAt = moment.utc().toDate(); - - try { - await user.save(); - } catch (err) { - console.log( - `User with Id ${user.id} failed to be updated at unblock-user.` - ); - return next(err); - } - - return res.status(200).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { User } = require('../../models/user'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const userId = req.params.userId; + + let user; + try { + user = await User.findOne({ _id: userId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'User not found' }); + } + + console.log(`User with Id ${userId} failed to be found at unblock-user.`); + return next(err); + } + + if (!user) { + return res.status(404).json({ general: 'User not found' }); + } + + user.isBlocked = false; + user.updatedAt = moment.utc().toDate(); + + try { + await user.save(); + } catch (err) { + console.log( + `User with Id ${user.id} failed to be updated at unblock-user.` + ); + return next(err); + } + + return res.status(200).json({ general: 'Success' }); +}; diff --git a/src/routes/users/validations.js b/src/routes/users/validations.js index 66236ae..d59b5f9 100644 --- a/src/routes/users/validations.js +++ b/src/routes/users/validations.js @@ -1,299 +1,299 @@ -const freemail = require('freemail'); -const { isEmail, isInt } = require('validator'); -const { isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { cleanSpaces } = require('../../helpers'); -const { User } = require('../../models/user'); - -module.exports = { - validateChangePassword(data) { - const errors = {}; - - if (!data.oldPassword) { - errors.oldPassword = 'Is required'; - } else if (typeof data.oldPassword !== 'string') { - errors.oldPassword = 'Should be a string'; - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should have more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should have less than 31 characters'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateCreateUser(data) { - const errors = {}; - - if (data.description) { - if (typeof data.description !== 'string') { - errors.description = 'Should be a string'; - } else if (cleanSpaces(data.description).length > 2000) { - errors.description = 'Should have less than 2001 characters'; - } - } - - if (!data.email) { - errors.email = 'Is required'; - } else if (typeof data.email !== 'string') { - errors.email = 'Should be a string'; - } else if (cleanSpaces(data.email).length > 254) { - errors.email = 'Should have less than 255 characters'; - } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { - errors.email = 'Is not a valid email'; - } - - if (!data.firstName) { - errors.firstName = 'Is required'; - } else if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { - errors.firstName = 'Should only have letters'; - } else if (cleanSpaces(data.firstName).length > 24) { - errors.firstName = 'Should have less than 25 characters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one name'; - } - } - - if (!data.lastName) { - errors.lastName = 'Is required'; - } else if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else if (cleanSpaces(data.lastName).length > 36) { - errors.lastName = 'Should have less than 37 characters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - - if (!data.password) { - errors.password = 'Is required'; - } else if (typeof data.password !== 'string') { - errors.password = 'Should be a string'; - } else if (data.password.length < 8) { - errors.password = 'Should be more than 7 characters'; - } else if (data.password.length > 30) { - errors.password = 'Should be less than 31 characters'; - } - - if (data.phone) { - if (typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } else if (cleanSpaces(data.phone).length > 50) { - errors.phone = 'Should have less than 51 characters'; - } - } - - if (data.username) { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (cleanSpaces(data.username).length > 67) { - errors.username = 'Should have less than 68 characters'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (data.zip) { - if (typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } else if (cleanSpaces(data.zip).length > 32) { - errors.zip = 'Should have less than 33 characters'; - } - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateEditUser(data) { - const errors = {}; - - if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { - errors.avatar = 'Should be a string'; - } - - if ( - typeof data.description !== 'undefined' && - typeof data.description !== 'string' - ) { - errors.description = 'Should be a string'; - } - - if (typeof data.disabilities !== 'undefined') { - if (!Array.isArray(data.disabilities)) { - errors.disabilities = 'Should be an array'; - } else { - const disabilitiesTypes = [ - 'brain', - 'cognitive', - 'hearing', - 'invisible', - 'none', - 'other', - 'physical', - 'private', - 'psychological', - 'spinal-cord', - 'vision' - ]; - data.disabilities.some(d => { - if (typeof d !== 'string') { - errors.disabilities = 'All values should be strings'; - return true; - } else if (!disabilitiesTypes.includes(d)) { - errors.disabilities = 'All values should be valid disabilities'; - return true; - } - }); - } - } - - if (typeof data.firstName !== 'undefined') { - if (typeof data.firstName !== 'string') { - errors.firstName = 'Should be a string'; - } else if (data.firstName === '') { - errors.firstName = 'Is required'; - } else if ( - /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) - ) { - errors.firstName = 'Should only have letters'; - } else { - const firstName = cleanSpaces(data.firstName); - - if (firstName.split(' ').length > 1) { - errors.firstName = 'Should only be one first name'; - } - } - } - - if (typeof data.gender !== 'undefined') { - const gendersTypes = User.schema.path('gender').enumValues; - if (typeof data.gender !== 'string') { - errors.gender = 'Should be a string'; - } else if (data.gender === '') { - errors.gender = 'Is required'; - } else if (!gendersTypes.includes(data.gender)) { - errors.gender = 'Should be a valid gender'; - } - } - - if ( - typeof data.isSubscribed !== 'undefined' && - typeof data.isSubscribed !== 'boolean' - ) { - errors.isSubscribed = 'Should be a boolean'; - } - - if (typeof data.lastName !== 'undefined') { - if (typeof data.lastName !== 'string') { - errors.lastName = 'Should be a string'; - } else if (data.lastName === '') { - errors.lastName = 'Is required'; - } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { - errors.lastName = 'Should only have letters'; - } else { - const lastName = cleanSpaces(data.lastName); - - if (lastName.split(' ').length > 1) { - errors.lastName = 'Should only be one last name'; - } - } - } - - if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { - errors.phone = 'Should be a string'; - } - - if ( - typeof data.showDisabilities !== 'undefined' && - typeof data.showDisabilities !== 'boolean' - ) { - errors.showDisabilities = 'Should be a boolean'; - } - - if ( - typeof data.showEmail !== 'undefined' && - typeof data.showEmail !== 'boolean' - ) { - errors.showEmail = 'Should be a boolean'; - } - - if ( - typeof data.showPhone !== 'undefined' && - typeof data.showPhone !== 'boolean' - ) { - errors.showPhone = 'Should be a boolean'; - } - - if (typeof data.username !== 'undefined') { - if (typeof data.username !== 'string') { - errors.username = 'Should be a string'; - } else if (data.username === '') { - errors.username = 'Is required'; - } else { - const username = slugify(data.username); - - if (username !== data.username) { - errors.username = 'Should only have lowercase letters and hyphens'; - } - } - } - - if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { - errors.zip = 'Should be a string'; - } - - return { errors, isValid: isEmpty(errors) }; - }, - validateListUsers(queryParams) { - const errors = {}; - - if (queryParams.page && !isInt(queryParams.page)) { - errors.page = 'Should be a integer'; - } else if (parseInt(queryParams.page, 10) < 1) { - errors.page = 'Should be greater than or equal to 1'; - } - - if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { - errors.pageLimit = 'Should be a integer'; - } else if (parseInt(queryParams.pageLimit, 10) < 1) { - errors.pageLimit = 'Should be greater than or equal to 1'; - } else if (parseInt(queryParams.pageLimit, 10) > 12) { - errors.pageLimit = 'Should be less than or equal to 12'; - } - - const sortOptions = [ - 'email', - '-email', - 'firstName', - '-firstName', - 'lastName', - '-lastName', - 'username', - '-username' - ]; - if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { - errors.sortBy = 'Should be a valid sort'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const freemail = require('freemail'); +const { isEmail, isInt } = require('validator'); +const { isEmpty } = require('lodash'); +const slugify = require('speakingurl'); + +const { cleanSpaces } = require('../../helpers'); +const { User } = require('../../models/user'); + +module.exports = { + validateChangePassword(data) { + const errors = {}; + + if (!data.oldPassword) { + errors.oldPassword = 'Is required'; + } else if (typeof data.oldPassword !== 'string') { + errors.oldPassword = 'Should be a string'; + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should have more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should have less than 31 characters'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateCreateUser(data) { + const errors = {}; + + if (data.description) { + if (typeof data.description !== 'string') { + errors.description = 'Should be a string'; + } else if (cleanSpaces(data.description).length > 2000) { + errors.description = 'Should have less than 2001 characters'; + } + } + + if (!data.email) { + errors.email = 'Is required'; + } else if (typeof data.email !== 'string') { + errors.email = 'Should be a string'; + } else if (cleanSpaces(data.email).length > 254) { + errors.email = 'Should have less than 255 characters'; + } else if (!isEmail(data.email) || freemail.isDisposable(data.email)) { + errors.email = 'Is not a valid email'; + } + + if (!data.firstName) { + errors.firstName = 'Is required'; + } else if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName)) { + errors.firstName = 'Should only have letters'; + } else if (cleanSpaces(data.firstName).length > 24) { + errors.firstName = 'Should have less than 25 characters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one name'; + } + } + + if (!data.lastName) { + errors.lastName = 'Is required'; + } else if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else if (cleanSpaces(data.lastName).length > 36) { + errors.lastName = 'Should have less than 37 characters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + + if (!data.password) { + errors.password = 'Is required'; + } else if (typeof data.password !== 'string') { + errors.password = 'Should be a string'; + } else if (data.password.length < 8) { + errors.password = 'Should be more than 7 characters'; + } else if (data.password.length > 30) { + errors.password = 'Should be less than 31 characters'; + } + + if (data.phone) { + if (typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } else if (cleanSpaces(data.phone).length > 50) { + errors.phone = 'Should have less than 51 characters'; + } + } + + if (data.username) { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (cleanSpaces(data.username).length > 67) { + errors.username = 'Should have less than 68 characters'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (data.zip) { + if (typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } else if (cleanSpaces(data.zip).length > 32) { + errors.zip = 'Should have less than 33 characters'; + } + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateEditUser(data) { + const errors = {}; + + if (typeof data.avatar !== 'undefined' && typeof data.avatar !== 'string') { + errors.avatar = 'Should be a string'; + } + + if ( + typeof data.description !== 'undefined' && + typeof data.description !== 'string' + ) { + errors.description = 'Should be a string'; + } + + if (typeof data.disabilities !== 'undefined') { + if (!Array.isArray(data.disabilities)) { + errors.disabilities = 'Should be an array'; + } else { + const disabilitiesTypes = [ + 'brain', + 'cognitive', + 'hearing', + 'invisible', + 'none', + 'other', + 'physical', + 'private', + 'psychological', + 'spinal-cord', + 'vision' + ]; + data.disabilities.some((d) => { + if (typeof d !== 'string') { + errors.disabilities = 'All values should be strings'; + return true; + } else if (!disabilitiesTypes.includes(d)) { + errors.disabilities = 'All values should be valid disabilities'; + return true; + } + }); + } + } + + if (typeof data.firstName !== 'undefined') { + if (typeof data.firstName !== 'string') { + errors.firstName = 'Should be a string'; + } else if (data.firstName === '') { + errors.firstName = 'Is required'; + } else if ( + /[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.firstName) + ) { + errors.firstName = 'Should only have letters'; + } else { + const firstName = cleanSpaces(data.firstName); + + if (firstName.split(' ').length > 1) { + errors.firstName = 'Should only be one first name'; + } + } + } + + if (typeof data.gender !== 'undefined') { + const gendersTypes = User.schema.path('gender').enumValues; + if (typeof data.gender !== 'string') { + errors.gender = 'Should be a string'; + } else if (data.gender === '') { + errors.gender = 'Is required'; + } else if (!gendersTypes.includes(data.gender)) { + errors.gender = 'Should be a valid gender'; + } + } + + if ( + typeof data.isSubscribed !== 'undefined' && + typeof data.isSubscribed !== 'boolean' + ) { + errors.isSubscribed = 'Should be a boolean'; + } + + if (typeof data.lastName !== 'undefined') { + if (typeof data.lastName !== 'string') { + errors.lastName = 'Should be a string'; + } else if (data.lastName === '') { + errors.lastName = 'Is required'; + } else if (/[~`!#$%^&*+=\-[\]\\';,./{}|\\":<>?\d]/g.test(data.lastName)) { + errors.lastName = 'Should only have letters'; + } else { + const lastName = cleanSpaces(data.lastName); + + if (lastName.split(' ').length > 1) { + errors.lastName = 'Should only be one last name'; + } + } + } + + if (typeof data.phone !== 'undefined' && typeof data.phone !== 'string') { + errors.phone = 'Should be a string'; + } + + if ( + typeof data.showDisabilities !== 'undefined' && + typeof data.showDisabilities !== 'boolean' + ) { + errors.showDisabilities = 'Should be a boolean'; + } + + if ( + typeof data.showEmail !== 'undefined' && + typeof data.showEmail !== 'boolean' + ) { + errors.showEmail = 'Should be a boolean'; + } + + if ( + typeof data.showPhone !== 'undefined' && + typeof data.showPhone !== 'boolean' + ) { + errors.showPhone = 'Should be a boolean'; + } + + if (typeof data.username !== 'undefined') { + if (typeof data.username !== 'string') { + errors.username = 'Should be a string'; + } else if (data.username === '') { + errors.username = 'Is required'; + } else { + const username = slugify(data.username); + + if (username !== data.username) { + errors.username = 'Should only have lowercase letters and hyphens'; + } + } + } + + if (typeof data.zip !== 'undefined' && typeof data.zip !== 'string') { + errors.zip = 'Should be a string'; + } + + return { errors, isValid: isEmpty(errors) }; + }, + validateListUsers(queryParams) { + const errors = {}; + + if (queryParams.page && !isInt(queryParams.page)) { + errors.page = 'Should be a integer'; + } else if (parseInt(queryParams.page, 10) < 1) { + errors.page = 'Should be greater than or equal to 1'; + } + + if (queryParams.pageLimit && !isInt(queryParams.pageLimit)) { + errors.pageLimit = 'Should be a integer'; + } else if (parseInt(queryParams.pageLimit, 10) < 1) { + errors.pageLimit = 'Should be greater than or equal to 1'; + } else if (parseInt(queryParams.pageLimit, 10) > 12) { + errors.pageLimit = 'Should be less than or equal to 12'; + } + + const sortOptions = [ + 'email', + '-email', + 'firstName', + '-firstName', + 'lastName', + '-lastName', + 'username', + '-username' + ]; + if (queryParams.sortBy && !sortOptions.includes(queryParams.sortBy)) { + errors.sortBy = 'Should be a valid sort'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/venues/archive-venue.js b/src/routes/venues/archive-venue.js index af8a0c6..bfaf8b9 100644 --- a/src/routes/venues/archive-venue.js +++ b/src/routes/venues/archive-venue.js @@ -1,39 +1,39 @@ -const moment = require('moment'); - -const { Venue } = require('../../models/venue'); - -module.exports = async (req, res, next) => { - if (!req.user.isAdmin) { - return res.status(403).json({ general: 'Forbidden action' }); - } - - const venueId = req.params.venueId; - - let venue; - try { - venue = await Venue.findOne({ _id: venueId, isArchived: false }); - } catch (err) { - if (err.name === 'CastError') { - return res.status(404).json({ general: 'Venue not found' }); - } - - console.log(`Venue ${venueId} failed to be found at delete-venue`); - return next(err); - } - - if (!venue) { - return res.status(404).json({ general: 'Venue not found' }); - } - - venue.isArchived = true; - venue.updatedAt = moment.utc().toDate(); - - try { - await venue.save(); - } catch (err) { - console.log(`Venue ${venue.id} failed to be updated at delete-venue`); - return next(err); - } - - return res.status(204).json({ general: 'Success' }); -}; +const moment = require('moment'); + +const { Venue } = require('../../models/venue'); + +module.exports = async (req, res, next) => { + if (!req.user.isAdmin) { + return res.status(403).json({ general: 'Forbidden action' }); + } + + const venueId = req.params.venueId; + + let venue; + try { + venue = await Venue.findOne({ _id: venueId, isArchived: false }); + } catch (err) { + if (err.name === 'CastError') { + return res.status(404).json({ general: 'Venue not found' }); + } + + console.log(`Venue ${venueId} failed to be found at delete-venue`); + return next(err); + } + + if (!venue) { + return res.status(404).json({ general: 'Venue not found' }); + } + + venue.isArchived = true; + venue.updatedAt = moment.utc().toDate(); + + try { + await venue.save(); + } catch (err) { + console.log(`Venue ${venue.id} failed to be updated at delete-venue`); + return next(err); + } + + return res.status(204).json({ general: 'Success' }); +}; diff --git a/src/routes/venues/get-venue.js b/src/routes/venues/get-venue.js index d1b3fe8..2b9c719 100644 --- a/src/routes/venues/get-venue.js +++ b/src/routes/venues/get-venue.js @@ -1,347 +1,345 @@ -const axios = require('axios'); -const { isEqual } = require('lodash'); -const slugify = require('speakingurl'); - -const { Venue } = require('../../models/venue'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const placeId = req.params.placeId; - - let response; - try { - response = await axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ - process.env.PLACES_API_KEY - }` - ); - } catch (err) { - console.log(`Place ${placeId} failed to be found at get-venue.`); - return next(err); - } - - const statusResponse = response.data.status; - if (statusResponse !== 'OK') { - return res.status(404).json({ general: 'Place not found' }); - } - - const placeData = response.data.result; - const dataResponse = {}; - dataResponse.address = placeData.formatted_address; - - let useStreetviewCover = false; - let streetViewError = false; - let streetViewResponse; - try { - streetViewResponse = await axios.get( - `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( - dataResponse.address - )}&key=${process.env.PLACES_API_KEY}` - ); - } catch (err) { - console.log(`Streetview for ${placeId} failed to be found at get-venue.`); - streetViewError = true; - } - - let streetViewPanoId; - if (!streetViewError) { - const streetViewMetadataStatus = streetViewResponse.data.status; - if (streetViewMetadataStatus == 'OK') { - useStreetviewCover = true; - streetViewPanoId = streetViewResponse.data.pano_id; - } - } - - if (useStreetviewCover) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ - process.env.PLACES_API_KEY - }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; - //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; - //seems like heading needs to be set when using pano id but not for the address - } else if (placeData.photos && placeData.photos.length > 0) { - dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; - } - - let coverPhotoLink = - //(useStreetviewCover) ? - `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ - placeData.geometry.location.lat - },${placeData.geometry.location.lng}`; - console.log('Cover photo link: ', coverPhotoLink); - - dataResponse.formattedPhone = placeData.formatted_phone_number; - dataResponse.googleRating = placeData.rating; - dataResponse.googleUrl = placeData.url; - dataResponse.internationalPhone = placeData.international_phone_number; - dataResponse.location = { - lat: placeData.geometry.location.lat, - lng: placeData.geometry.location.lng - }; - dataResponse.name = placeData.name; - dataResponse.placeId = placeId; - dataResponse.types = placeData.types; - dataResponse.website = placeData.website; - - dataResponse.allowsGuideDog = { yes: 0, no: 0 }; - //dataResponse.bathroomReviews = 0; - //dataResponse.bathroomScore = null; - //dataResponse.entryReviews = 0; - //dataResponse.entryScore = null; - dataResponse.hasParking = { yes: 0, no: 0 }; - dataResponse.hasSecondEntry = { yes: 0, no: 0 }; - dataResponse.hasWellLit = { yes: 0, no: 0 }; - dataResponse.isQuiet = { yes: 0, no: 0 }; - dataResponse.isSpacious = { yes: 0, no: 0 }; - dataResponse.steps = { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - }; - - //new expanded fields - dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; - dataResponse.hasPortableRamp = { yes: 0, no: 0 }; - dataResponse.hasWideEntrance = { yes: 0, no: 0 }; - dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; - dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; - dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; - dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; - dataResponse.hasLargeStall = { yes: 0, no: 0 }; - dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; - dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; - - dataResponse.entranceScore = 0; - dataResponse.entranceGlyphs = ''; - dataResponse.interiorScore = 0; - dataResponse.interiorGlyphs = ''; - dataResponse.restroomScore = 0; - dataResponse.restroomGlyphs = ''; - dataResponse.mapMarkerScore = 0; - - let venue; - let venueToSave; - try { - [venue, venueToSave] = await Promise.all([ - Venue.aggregate([ - { - $match: { placeId, isArchived: false } - }, - { - $lookup: { - from: 'reviews', - let: { reviews: '$reviews' }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$reviews'] - } - } - }, - { - $lookup: { - from: 'users', - let: { user: '$user' }, - pipeline: [ - { - $match: { - $expr: { - $eq: ['$_id', '$$user'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - avatar: 1, - firstName: 1, - lastName: 1 - } - } - ], - as: 'user' - } - }, - { - $project: { - _id: 0, - id: '$_id', - //bathroomScore: 1, - comments: 1, - createdAt: 1, - //entryScore: 1, - user: 1, - voters: 1 - } - } - ], - as: 'reviews' - } - }, - { - $lookup: { - from: 'photos', - let: { photos: { $ifNull: ['$photos', []] } }, - pipeline: [ - { - $match: { - $expr: { - $in: ['$_id', '$$photos'] - } - } - }, - { - $project: { - _id: 0, - id: '$_id', - url: 1 - } - } - ], - as: 'photos' - } - }, - { - $project: { - _id: 0, - id: '$_id', - address: 1, - description: 1, - allowsGuideDog: 1, - //bathroomReviews: 1, - //bathroomScore: 1, - //entryReviews: 1, - //entryScore: 1, - hasParking: 1, - hasSecondEntry: 1, - hasWellLit: 1, - isQuiet: 1, - isSpacious: 1, - location: 1, - name: 1, - photos: 1, - placeId: 1, - steps: 1, - types: 1, - reviews: 1, - hasPermanentRamp: 1, - hasPortableRamp: 1, - hasWideEntrance: 1, - hasAccessibleTableHeight: 1, - hasAccessibleElevator: 1, - hasInteriorRamp: 1, - hasSwingOutDoor: 1, - hasLargeStall: 1, - hasSupportAroundToilet: 1, - hasLoweredSinks: 1 - } - } - ]), - Venue.findOne({ placeId, isArchived: false }) - ]); - } catch (err) { - console.log( - `Venue with placeId ${placeId} failed to be found at get-venue` - ); - return next(err); - } - - if (venue && venue[0]) { - let venueHasUpdates = false; - if (venueToSave.address !== dataResponse.address) { - venueToSave.address = dataResponse.address; - venueHasUpdates = true; - } - if ( - venueToSave.location.coordinates[0] !== dataResponse.location.lng || - venueToSave.location.coordinates[1] !== dataResponse.location.lat - ) { - venueToSave.location.coordinates = [ - dataResponse.location.lng, - dataResponse.location.lat - ]; - venueHasUpdates = true; - } - if (venueToSave.name !== dataResponse.name) { - venueToSave.name = dataResponse.name; - venueHasUpdates = true; - } - if (!isEqual(venueToSave.types, dataResponse.types)) { - venueToSave.types = dataResponse.types; - venueHasUpdates = true; - } - - if (venueHasUpdates) { - try { - await venueToSave.save(); - } catch (err) { - console.log( - `Venue with id ${venueToSave.id} failed to be updated at get-venue.` - ); - return next(err); - } - } - - //TEMP: - let scoring; - //console.log('venue0: ', venue[0]); - - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); - console.log('entrance score: ', scoring); - dataResponse.entranceScore = scoring.ratingLevel; - dataResponse.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); - console.log('interior score: ', scoring); - dataResponse.interiorScore = scoring.ratingLevel; - dataResponse.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); - console.log('restroom score: ', scoring); - dataResponse.restroomScore = scoring.ratingLevel; - dataResponse.restroomGlyphs = scoring.ratingGlyphs; - - dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - dataResponse.entranceScore, - dataResponse.interiorScore, - dataResponse.restroomScore - ); - - dataResponse.id = venue[0]._id; - - dataResponse.allowsGuideDog = venue[0].allowsGuideDog; - //dataResponse.bathroomReviews = venue[0].bathroomReviews; - //dataResponse.bathroomScore = venue[0].bathroomScore; - //dataResponse.entryReviews = venue[0].entryReviews; - //dataResponse.entryScore = venue[0].entryScore; - dataResponse.hasParking = venue[0].hasParking; - dataResponse.hasSecondEntry = venue[0].hasSecondEntry; - dataResponse.hasWellLit = venue[0].hasWellLit; - dataResponse.isQuiet = venue[0].isQuiet; - dataResponse.isSpacious = venue[0].isSpacious; - dataResponse.photos = venue[0].photos; - dataResponse.steps = venue[0].steps; - //new expanded fields - dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; - dataResponse.hasPortableRamp = venue[0].hasPortableRamp; - dataResponse.hasWideEntrance = venue[0].hasWideEntrance; - dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; - dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; - dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; - dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; - dataResponse.hasLargeStall = venue[0].hasLargeStall; - dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; - dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; - - dataResponse.reviews = venue[0].reviews; - } - - return res.status(200).json(dataResponse); -}; +const axios = require('axios'); +const { isEqual } = require('lodash'); +const slugify = require('speakingurl'); + +const { Venue } = require('../../models/venue'); +const venueReviewSummary = require('../../helpers/venue-review-summary.js'); + +module.exports = async (req, res, next) => { + const placeId = req.params.placeId; + + let response; + try { + response = await axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeId}&key=${ + process.env.PLACES_API_KEY + }` + ); + } catch (err) { + console.log(`Place ${placeId} failed to be found at get-venue.`); + return next(err); + } + + const statusResponse = response.data.status; + if (statusResponse !== 'OK') { + return res.status(404).json({ general: 'Place not found' }); + } + + const placeData = response.data.result; + const dataResponse = {}; + dataResponse.address = placeData.formatted_address; + + let useStreetviewCover = false; + let streetViewError = false; + let streetViewResponse; + try { + streetViewResponse = await axios.get( + `https://maps.googleapis.com/maps/api/streetview/metadata?location=${slugify( + dataResponse.address + )}&key=${process.env.PLACES_API_KEY}` + ); + } catch (err) { + console.error(err); + console.log(`Streetview for ${placeId} failed to be found at get-venue.`); + streetViewError = true; + } + + let streetViewPanoId; + if (!streetViewError) { + const streetViewMetadataStatus = streetViewResponse.data.status; + if (streetViewMetadataStatus == 'OK') { + useStreetviewCover = true; + streetViewPanoId = streetViewResponse.data.pano_id; + } + } + + if (useStreetviewCover) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/streetview?key=${ + process.env.PLACES_API_KEY + }&size=800x400&fov=110&location=${slugify(dataResponse.address)}`; + //}&size=800x400&fov=110&heading=0&pano=${streetViewPanoId}`; + //seems like heading needs to be set when using pano id but not for the address + } else if (placeData.photos && placeData.photos.length > 0) { + dataResponse.coverPhoto = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=500&photoreference=${placeData.photos[0].photo_reference}`; + } + + let coverPhotoLink = + //(useStreetviewCover) ? + `https://www.google.com/maps/@?api=1&map_action=pano&pano=${streetViewPanoId}&viewpoint=${ + placeData.geometry.location.lat + },${placeData.geometry.location.lng}`; + console.log('Cover photo link: ', coverPhotoLink); + + dataResponse.formattedPhone = placeData.formatted_phone_number; + dataResponse.googleRating = placeData.rating; + dataResponse.googleUrl = placeData.url; + dataResponse.internationalPhone = placeData.international_phone_number; + dataResponse.location = { + lat: placeData.geometry.location.lat, + lng: placeData.geometry.location.lng + }; + dataResponse.name = placeData.name; + dataResponse.placeId = placeId; + dataResponse.types = placeData.types; + dataResponse.website = placeData.website; + + dataResponse.allowsGuideDog = { yes: 0, no: 0 }; + //dataResponse.bathroomReviews = 0; + //dataResponse.bathroomScore = null; + //dataResponse.entryReviews = 0; + //dataResponse.entryScore = null; + dataResponse.hasParking = { yes: 0, no: 0 }; + dataResponse.hasSecondEntry = { yes: 0, no: 0 }; + dataResponse.hasWellLit = { yes: 0, no: 0 }; + dataResponse.isQuiet = { yes: 0, no: 0 }; + dataResponse.isSpacious = { yes: 0, no: 0 }; + dataResponse.steps = { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0 + }; + + //new expanded fields + dataResponse.hasPermanentRamp = { yes: 0, no: 0 }; + dataResponse.hasPortableRamp = { yes: 0, no: 0 }; + dataResponse.hasWideEntrance = { yes: 0, no: 0 }; + dataResponse.hasAccessibleTableHeight = { yes: 0, no: 0 }; + dataResponse.hasAccessibleElevator = { yes: 0, no: 0 }; + dataResponse.hasInteriorRamp = { yes: 0, no: 0 }; + dataResponse.hasSwingOutDoor = { yes: 0, no: 0 }; + dataResponse.hasLargeStall = { yes: 0, no: 0 }; + dataResponse.hasSupportAroundToilet = { yes: 0, no: 0 }; + dataResponse.hasLoweredSinks = { yes: 0, no: 0 }; + + dataResponse.entranceScore = 0; + dataResponse.entranceGlyphs = ''; + dataResponse.interiorScore = 0; + dataResponse.interiorGlyphs = ''; + dataResponse.restroomScore = 0; + dataResponse.restroomGlyphs = ''; + dataResponse.mapMarkerScore = 0; + + let venue; + let venueToSave; + try { + [venue, venueToSave] = await Promise.all([ + Venue.aggregate([ + { + $match: { placeId, isArchived: false } + }, + { + $lookup: { + from: 'reviews', + let: { reviews: '$reviews' }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$reviews'] + } + } + }, + { + $lookup: { + from: 'users', + let: { user: '$user' }, + pipeline: [ + { + $match: { + $expr: { + $eq: ['$_id', '$$user'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + avatar: 1, + firstName: 1, + lastName: 1 + } + } + ], + as: 'user' + } + }, + { + $project: { + _id: 0, + id: '$_id', + //bathroomScore: 1, + comments: 1, + createdAt: 1, + //entryScore: 1, + user: 1, + voters: 1 + } + } + ], + as: 'reviews' + } + }, + { + $lookup: { + from: 'photos', + let: { photos: { $ifNull: ['$photos', []] } }, + pipeline: [ + { + $match: { + $expr: { + $in: ['$_id', '$$photos'] + } + } + }, + { + $project: { + _id: 0, + id: '$_id', + url: 1 + } + } + ], + as: 'photos' + } + }, + { + $project: { + _id: 0, + id: '$_id', + address: 1, + description: 1, + allowsGuideDog: 1, + //bathroomReviews: 1, + //bathroomScore: 1, + //entryReviews: 1, + //entryScore: 1, + hasParking: 1, + hasSecondEntry: 1, + hasWellLit: 1, + isQuiet: 1, + isSpacious: 1, + location: 1, + name: 1, + photos: 1, + placeId: 1, + steps: 1, + types: 1, + reviews: 1, + hasPermanentRamp: 1, + hasPortableRamp: 1, + hasWideEntrance: 1, + hasAccessibleTableHeight: 1, + hasAccessibleElevator: 1, + hasInteriorRamp: 1, + hasSwingOutDoor: 1, + hasLargeStall: 1, + hasSupportAroundToilet: 1, + hasLoweredSinks: 1 + } + } + ]), + Venue.findOne({ placeId, isArchived: false }) + ]); + } catch (err) { + console.log( + `Venue with placeId ${placeId} failed to be found at get-venue` + ); + return next(err); + } + + if (venue && venue[0]) { + let venueHasUpdates = false; + if (venueToSave.address !== dataResponse.address) { + venueToSave.address = dataResponse.address; + venueHasUpdates = true; + } + if ( + venueToSave.location.coordinates[0] !== dataResponse.location.lng || + venueToSave.location.coordinates[1] !== dataResponse.location.lat + ) { + venueToSave.location.coordinates = [ + dataResponse.location.lng, + dataResponse.location.lat + ]; + venueHasUpdates = true; + } + if (venueToSave.name !== dataResponse.name) { + venueToSave.name = dataResponse.name; + venueHasUpdates = true; + } + if (!isEqual(venueToSave.types, dataResponse.types)) { + venueToSave.types = dataResponse.types; + venueHasUpdates = true; + } + + if (venueHasUpdates) { + try { + await venueToSave.save(); + } catch (err) { + console.log( + `Venue with id ${venueToSave.id} failed to be updated at get-venue.` + ); + return next(err); + } + } + + //TEMP: + let scoring; + //console.log('venue0: ', venue[0]); + + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('entrance', venue[0]); + dataResponse.entranceScore = scoring.ratingLevel; + dataResponse.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('interior', venue[0]); + dataResponse.interiorScore = scoring.ratingLevel; + dataResponse.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel('restroom', venue[0]); + dataResponse.restroomScore = scoring.ratingLevel; + dataResponse.restroomGlyphs = scoring.ratingGlyphs; + + dataResponse.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + dataResponse.entranceScore, + dataResponse.interiorScore, + dataResponse.restroomScore + ); + + dataResponse.id = venue[0]._id; + + dataResponse.allowsGuideDog = venue[0].allowsGuideDog; + //dataResponse.bathroomReviews = venue[0].bathroomReviews; + //dataResponse.bathroomScore = venue[0].bathroomScore; + //dataResponse.entryReviews = venue[0].entryReviews; + //dataResponse.entryScore = venue[0].entryScore; + dataResponse.hasParking = venue[0].hasParking; + dataResponse.hasSecondEntry = venue[0].hasSecondEntry; + dataResponse.hasWellLit = venue[0].hasWellLit; + dataResponse.isQuiet = venue[0].isQuiet; + dataResponse.isSpacious = venue[0].isSpacious; + dataResponse.photos = venue[0].photos; + dataResponse.steps = venue[0].steps; + //new expanded fields + dataResponse.hasPermanentRamp = venue[0].hasPermanentRamp; + dataResponse.hasPortableRamp = venue[0].hasPortableRamp; + dataResponse.hasWideEntrance = venue[0].hasWideEntrance; + dataResponse.hasAccessibleTableHeight = venue[0].hasAccessibleTableHeight; + dataResponse.hasAccessibleElevator = venue[0].hasAccessibleElevator; + dataResponse.hasInteriorRamp = venue[0].hasInteriorRamp; + dataResponse.hasSwingOutDoor = venue[0].hasSwingOutDoor; + dataResponse.hasLargeStall = venue[0].hasLargeStall; + dataResponse.hasSupportAroundToilet = venue[0].hasSupportAroundToilet; + dataResponse.hasLoweredSinks = venue[0].hasLoweredSinks; + + dataResponse.reviews = venue[0].reviews; + } + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/index.js b/src/routes/venues/index.js index 2f35371..0675f4d 100644 --- a/src/routes/venues/index.js +++ b/src/routes/venues/index.js @@ -1,19 +1,21 @@ -const express = require('express'); - -const { isAuthenticated } = require('../../helpers'); - -const archiveVenue = require('./archive-venue'); -const getVenue = require('./get-venue'); -const listVenues = require('./list-venues'); - -const router = new express.Router(); - -router.get('', listVenues); -router.get('/:placeId', getVenue); -router.put( - '/:venueId/archive', - isAuthenticated({ isOptional: false }), - archiveVenue -); - -module.exports = router; +const express = require("express"); + +const { isAuthenticated } = require("../../helpers"); + +const archiveVenue = require("./archive-venue"); +const getVenue = require("./get-venue"); +const listVenues = require("./list-venues"); +const venuDetails = require("./venue-details"); + +const router = new express.Router(); + +router.get("", isAuthenticated({ isOptional: true }), listVenues); +router.get("/:placeId", getVenue); +router.get("/detail/:placeId", venuDetails); +router.put( + "/:venueId/archive", + isAuthenticated({ isOptional: false }), + archiveVenue +); + +module.exports = router; diff --git a/src/routes/venues/list-venues.js b/src/routes/venues/list-venues.js index 306ddd9..67140ec 100644 --- a/src/routes/venues/list-venues.js +++ b/src/routes/venues/list-venues.js @@ -1,642 +1,658 @@ -const axios = require('axios'); -const { find, isEmpty } = require('lodash'); -const slugify = require('speakingurl'); - -const { isNumber } = require('../../helpers'); -const { Venue } = require('../../models/venue'); - -const { validateListVenues } = require('./validations'); -const venueReviewSummary = require('../../helpers/venue-review-summary.js'); - -module.exports = async (req, res, next) => { - const queryParams = req.query; - - const { errors, isValid } = validateListVenues(queryParams); - if (!isValid) return res.status(400).json(errors); - - let coordinates = queryParams.location.split(','); - - //Legacy function from two-bar search, geocodes from string address - if (queryParams.address && !queryParams.page) { - console.log('in address conditional, ', queryParams); - queryParams.name = queryParams.address; - const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( - queryParams.address - )}`; - - let geocodeResponse; - try { - geocodeResponse = await axios.get( - `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` - ); - } catch (err) { - console.log( - `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = geocodeResponse.data.status; - if (statusCode === 'ZERO_RESULTS') { - return res.status(404).json({ keywords: 'Address not found' }); - } else if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - - coordinates = [ - geocodeResponse.data.results[0].geometry.location.lat, - geocodeResponse.data.results[0].geometry.location.lng - ]; - } //end address geocode - - let venuesFilters = {}; - let dbVenuesFilters = {}; - - /* - * Legacy filter string building function, - * has a critical defect condition where if - * no > yes but yes is at least 1, then there - * would be a false match. - */ - if (queryParams.entranceScore) { - venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); - //{ $gte: parseFloat(queryParams.entranceScore) }; - } - - if (queryParams.interiorScore) { - venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); - //{ $gte: parseFloat(queryParams.interiorScore) }; - } - - if (queryParams.restroomScore) { - venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); - //{ $gte: parseFloat(queryParams.restroomScore) }; - } - - if (queryParams.allowsGuideDog) { - venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); - - const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; - if (allowsGuideDog) { - dbVenuesFilters['allowsGuideDog.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['allowsGuideDog.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasParking) { - venuesFilters.hasParking = queryParams.hasParking; - - const hasParking = parseFloat(queryParams.hasParking) === 1; - if (hasParking) { - dbVenuesFilters['hasParking.yes'] = { $gte: 1 }; - } else { - dbVenuesFilters['hasParking.no'] = { $gte: 1 }; - } - } - - /* - * Not used - * - if (queryParams.hasRamp) { - const hasRamp = parseFloat(queryParams.hasRamp) === 1; - if (hasRamp) { - venuesFilters['hasRamp.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasRamp.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasSecondEntry) { - const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; - if (hasSecondEntry) { - venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; - } - } - - if (queryParams.hasWellLit) { - const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; - if (hasWellLit) { - venuesFilters['hasWellLit.yes'] = { $gte: 1 }; - } else { - venuesFilters['hasWellLit.no'] = { $gte: 1 }; - } - } - - if (queryParams.isQuiet) { - const isQuiet = parseFloat(queryParams.isQuiet) === 1; - if (isQuiet) { - venuesFilters['isQuiet.yes'] = { $gte: 1 }; - } else { - venuesFilters['isQuiet.no'] = { $gte: 1 }; - } - } - - if (queryParams.isSpacious) { - const isSpacious = parseFloat(queryParams.isSpacious) === 1; - if (isSpacious) { - venuesFilters['isSpacious.yes'] = { $gte: 1 }; - } else { - venuesFilters['isSpacious.no'] = { $gte: 1 }; - } - } - - if (queryParams.steps) { - if (parseFloat(queryParams.steps) === 0) { - venuesFilters['steps.zero'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 1) { - venuesFilters['steps.one'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 2) { - venuesFilters['steps.two'] = { $gte: 1 }; - } else if (parseFloat(queryParams.steps) === 3) { - venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; - } - } - * - */ - - let dataResponse; - - /* - * Legacy filtering function that searches solely on - * AXS Venue data and provides it's own pagination of 20 - * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH - */ - if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { - console.log('>> Performing DB search'); - /* - if (queryParams.name) { - //performs literal name match against AXS Venue name - venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; - } - */ - - dbVenuesFilters.location = { - $near: { - $geometry: { - type: 'Point', - coordinates: [coordinates[1], coordinates[0]] - }, - $maxDistance: 50000 - } - }; - - if (queryParams.type) { - dbVenuesFilters.types = queryParams.type; - } - - dbVenuesFilters.isArchived = false; - - let page = 1; - if (isNumber(queryParams.page)) { - page = queryParams.page; - } - - const pageLimit = - venuesFilters.hasOwnProperty('entranceScore') || - venuesFilters.hasOwnProperty('interiorScore') || - venuesFilters.hasOwnProperty('restroomScore') - ? 80 - : 20; - - if (page > 0) { - page -= 1; - } else { - return res - .status(400) - .json({ page: 'Should be equal to or greater than 1' }); - } - - let total; - let venues; - try { - [venues, total] = await Promise.all([ - Venue.find( - dbVenuesFilters - /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ - ) - .skip(page * pageLimit) - .limit(pageLimit), - Venue.find(dbVenuesFilters).count() - /*TODO: count is deprecated in favor of countDocuments, but that does not support $near - would need to move to GeoWithin but that does not return sorted results - */ - ]); - } catch (err) { - console.log( - `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( - dbVenuesFilters - )}` - ); - console.log(err); - return next(err); - } - - venues = venues.map(venue => - Object.assign({}, venue.toObject(), { - id: venue._id, - _id: undefined, - location: venue.coordinates - }) - ); - - //+ADDED - //Perform ratings logic on all returned venues - console.log('Raw venues count: ' + venues.length); - venues = venues.filter(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - - let passesValidation = true; - if (venuesFilters.hasOwnProperty('entranceScore')) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('interiorScore')) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('restroomScore')) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - }); - - const lastPage = Math.ceil(total / pageLimit); - let nextPage; - if (lastPage > 0) { - page += 1; - if (page > lastPage || page > 3) { - return res.status(400).json({ - page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}` - }); - } - } - - dataResponse = { - nextPage, - results: venues - }; - /* - * End legacy filter - */ - } else { - console.log('>> Performing Google search'); - - /* - * Perform Google search when there text entered or no filters selected - */ - let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; - let searchType = queryParams.name ? 'textsearch' : 'nearbysearch'; - - if (!queryParams.page) { - nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ - coordinates[1] - //}&rankby=distance`; - }`; - - if (queryParams.name) { - //nearbyParams = `${nearbyParams}&keyword=${queryParams.name}`; - nearbyParams = `${nearbyParams}&query=${queryParams.name}&radius=5000`; - } else { - //empty search, such as on load - nearbyParams = `${nearbyParams}&rankby=distance`; - } - - if (queryParams.type) { - nearbyParams = `${nearbyParams}&type=${queryParams.type}`; - } else { - nearbyParams = `${nearbyParams}&type=establishment`; - } - } else { - nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; - } - - if (queryParams.rankby) { - nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; - } - if (queryParams.opennow) { - nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; - } - if (queryParams.minprice) { - nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; - } - if (queryParams.maxprice) { - nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; - } - - let placesResponse; - try { - console.log( - 'performing google search: ' + - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - placesResponse = await axios.get( - `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}` - ); - } catch (err) { - console.log( - `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( - queryParams - )}` - ); - return next(err); - } - - const statusCode = placesResponse.data.status; - if (statusCode === 'OVER_QUERY_LIMIT') { - return next(new Error('Over query limit with Google Places API')); - } else if (statusCode === 'REQUEST_DENIED') { - return next(new Error('Request denied with Google Places API')); - } else if (statusCode === 'INVALID_REQUEST') { - return next(new Error('Invalid request with Google Places API')); - } else if (statusCode === 'UNKNOWN_ERROR') { - return next(new Error('Unknown error with Google Places API')); - } - //do we need to check for 0? - - if (placesResponse.data.results.length == 1) { - if (placesResponse.data.results[0].types[0] == 'locality') { - console.log( - 'Found a city only: ', - placesResponse.data.results[0].geometry.location - ); - //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string - } - } - - //Format Google Places results and get array of IDs - let places = []; - const placesIds = []; - placesResponse.data.results.forEach(place => { - let photo = ''; - if (place.photos) { - photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ - process.env.PLACES_API_KEY - }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; - } - - places.push({ - //address: place.vicinity, - address: place.formatted_address, - location: { - lat: place.geometry.location.lat, - lng: place.geometry.location.lng - }, - name: place.name, - photo, - placeId: place.place_id, - types: place.types - }); - placesIds.push(place.place_id); - }); - - //Use array of Google Place IDs to find AXS Venues - let venues; - try { - venues = await Venue.find({ placeId: { $in: placesIds } }); - } catch (err) { - console.log( - `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` - ); - return next(err); - } - - //Perform ratings logic on all returned venues - venues.forEach(venue => { - //console.log('In scoring assignment'); - let scoring; - //calculate entranceScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('entrance', venue); - venue.entranceScore = scoring.ratingLevel; - venue.entranceGlyphs = scoring.ratingGlyphs; - - //calculate interiorScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('interior', venue); - venue.interiorScore = scoring.ratingLevel; - venue.interiorGlyphs = scoring.ratingGlyphs; - - //calculate restroomScore, glyphs - scoring = venueReviewSummary.calculateRatingLevel('restroom', venue); - venue.restroomScore = scoring.ratingLevel; - venue.restroomGlyphs = scoring.ratingGlyphs; - - venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( - venue.entranceScore, - venue.interiorScore, - venue.restroomScore - ); - }); - - //Filter out, remove, Google Places that are not AXS Venues - // Can't use hasOwnProperty() on mongoose model objects // - if (!isEmpty(venuesFilters)) { - console.log('>> Performing secondary DB filtering'); - places = places.filter(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - //console.log('In verification of filters'); - let passesValidation = true; - if ( - passesValidation && - venuesFilters.hasOwnProperty('allowsGuideDog') - ) { - if ( - !venue.allowsGuideDog || - venue.allowsGuideDog.yes < venue.allowsGuideDog.no || - venue.allowsGuideDog.yes == 0 - ) { - passesValidation = false; - } - } - - if (passesValidation && venuesFilters.hasOwnProperty('hasParking')) { - if ( - !venue.hasParking || - venue.hasParking.yes < venue.hasParking.no || - venue.hasParking.yes == 0 - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('entranceScore') - ) { - if ( - !venue.entranceScore || - venue.entranceScore < venuesFilters.entranceScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('interiorScore') - ) { - if ( - !venue.interiorScore || - venue.interiorScore < venuesFilters.interiorScore - ) { - passesValidation = false; - } - } - - if ( - passesValidation && - venuesFilters.hasOwnProperty('restroomScore') - ) { - if ( - !venue.restroomScore || - venue.restroomScore < venuesFilters.restroomScore - ) { - passesValidation = false; - } - } - - if (passesValidation) { - return venue; - } - } - }); - } //end filtering Google results - - // - places = places.map(place => { - const venue = find(venues, venue => venue.placeId === place.placeId); - if (venue) { - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: venue.hasPermanentRamp, - hasPortableRamp: venue.hasPortableRamp, - hasWideEntrance: venue.hasWideEntrance, - hasAccessibleTableHeight: venue.hasAccessibleTableHeight, - hasAccessibleElevator: venue.hasAccessibleElevator, - hasInteriorRamp: venue.hasInteriorRamp, - hasSwingInDoor: venue.hasSwingInDoor, - hasSwingOutDoor: venue.hasSwingOutDoor, - hasLargeStall: venue.hasLargeStall, - hasSupportAroundToilet: venue.hasSupportAroundToilet, - hasLoweredSinks: venue.hasLoweredSinks, - - entranceScore: venue.entranceScore, - entranceGlyphs: venue.entranceGlyphs, - interiorScore: venue.interiorScore, - interiorGlyphs: venue.interiorGlyphs, - restroomScore: venue.restroomScore, - restroomGlyphs: venue.restroomGlyphs, - mapMarkerScore: venue.mapMarkerScore, - - //original fields - allowsGuideDog: venue.allowsGuideDog, - //_bathroomScore: venue.bathroomScore, - //_entryScore: venue.entryScore, - hasParking: venue.hasParking, - hasSecondEntry: venue.hasSecondEntry, - hasWellLit: venue.hasWellLit, - isQuiet: venue.isQuiet, - isSpacious: venue.isSpacious, - steps: venue.steps - }); - } - - //venue not found - return Object.assign({}, place, { - //new expanded fields - hasPermanentRamp: { yes: 0, no: 0 }, - hasPortableRamp: { yes: 0, no: 0 }, - hasWideEntrance: { yes: 0, no: 0 }, - hasAccessibleTableHeight: { yes: 0, no: 0 }, - hasAccessibleElevator: { yes: 0, no: 0 }, - hasInteriorRamp: { yes: 0, no: 0 }, - hasSwingInDoor: { yes: 0, no: 0 }, - hasSwingOutDoor: { yes: 0, no: 0 }, - hasLargeStall: { yes: 0, no: 0 }, - hasSupportAroundToilet: { yes: 0, no: 0 }, - hasLoweredSinks: { yes: 0, no: 0 }, - interiorScore: 0, - interiorGlyphs: 'interior', - restroomScore: 0, - restroomGlyphs: 'restroom', - entranceScore: 0, - entranceGlyphs: 'entrylg', - mapMarkerScore: 0, - - //original fields - allowsGuideDog: { yes: 0, no: 0 }, - //_bathroomReviews: 0, - //_bathroomScore: null, - //_entryReviews: 0, - //_entryScore: null, - hasParking: { yes: 0, no: 0 }, - hasSecondEntry: { yes: 0, no: 0 }, - hasWellLit: { yes: 0, no: 0 }, - isQuiet: { yes: 0, no: 0 }, - isSpacious: { yes: 0, no: 0 }, - steps: { - zero: 0, - one: 0, - two: 0, - moreThanTwo: 0 - } - }); - }); - - dataResponse = { - nextPage: placesResponse.data.next_page_token, - results: places - }; - } //ends legacy filter logic, false conditional - - return res.status(200).json(dataResponse); -}; +const axios = require("axios"); +const { find, isEmpty } = require("lodash"); +const slugify = require("speakingurl"); + +const { isNumber } = require("../../helpers"); +const { Venue } = require("../../models/venue"); + +const { validateListVenues } = require("./validations"); +const venueReviewSummary = require("../../helpers/venue-review-summary.js"); + +const milesTranslations = { + en: "Miles", // English + fr: "Milles", // French + es: "Millas", // Spanish + ja: "マイル", // Japanese +}; + +const feetTranslations = { + en: "Feet", // English + fr: "Pieds", // French + es: "Pies", // Spanish + ja: "フィート", // Japanese +}; + +function getDistanceFromLatLng(lat1, lng1, lat2, lng2) { + console.log(lat1, lng1, lat2, lng2); + const R = 6371; // Earth’s radius in km + + const dLat = (lat2 - lat1) * (Math.PI / 180); + const dLng = (lng2 - lng1) * (Math.PI / 180); + + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(lat1 * (Math.PI / 180)) * + Math.cos(lat2 * (Math.PI / 180)) * + Math.sin(dLng / 2) * + Math.sin(dLng / 2); + + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return R * c * 1000; +} + +function covertDistanceToFeet(distanceInMeter, language = "en") { + const distanceInFeet = distanceInMeter * 3.28084; + const distance = `${(distanceInFeet > 5280 ? distanceInFeet / 5280 : distanceInFeet).toFixed(distanceInFeet > 5280 ? 2 : 0)} ${ + distanceInFeet > 5280 + ? (milesTranslations[language] ?? "Miles") + : (feetTranslations[language] ?? "Feet") + }`; + return distance; +} + +module.exports = async (req, res, next) => { + const queryParams = req.query; + + const { errors, isValid } = validateListVenues(queryParams); + if (!isValid) return res.status(400).json(errors); + + let coordinates = queryParams.location.split(","); + + //Legacy function from two-bar search, geocodes from string address + if (queryParams.address && !queryParams.page) { + console.log("in address conditional, ", queryParams); + queryParams.name = queryParams.address; + const geocodeParams = `?key=${process.env.PLACES_API_KEY}&address=${slugify( + queryParams.address + )}`; + + let geocodeResponse; + try { + geocodeResponse = await axios.get( + `https://maps.googleapis.com/maps/api/geocode/json${geocodeParams}` + ); + } catch (err) { + console.log( + `Geocode failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = geocodeResponse.data.status; + if (statusCode === "ZERO_RESULTS") { + return res.status(404).json({ keywords: "Address not found" }); + } else if (statusCode === "OVER_QUERY_LIMIT") { + return next(new Error("Over query limit with Google Places API")); + } else if (statusCode === "REQUEST_DENIED") { + return next(new Error("Request denied with Google Places API")); + } else if (statusCode === "INVALID_REQUEST") { + return next(new Error("Invalid request with Google Places API")); + } else if (statusCode === "UNKNOWN_ERROR") { + return next(new Error("Unknown error with Google Places API")); + } + + coordinates = [ + geocodeResponse.data.results[0].geometry.location.lat, + geocodeResponse.data.results[0].geometry.location.lng, + ]; + } //end address geocode + + let venuesFilters = {}; + let dbVenuesFilters = {}; + + /* + * Legacy filter string building function, + * has a critical defect condition where if + * no > yes but yes is at least 1, then there + * would be a false match. + */ + if (queryParams.entranceScore) { + venuesFilters.entranceScore = parseFloat(queryParams.entranceScore); + //{ $gte: parseFloat(queryParams.entranceScore) }; + } + + if (queryParams.interiorScore) { + venuesFilters.interiorScore = parseFloat(queryParams.interiorScore); + //{ $gte: parseFloat(queryParams.interiorScore) }; + } + + if (queryParams.restroomScore) { + venuesFilters.restroomScore = parseFloat(queryParams.restroomScore); + //{ $gte: parseFloat(queryParams.restroomScore) }; + } + + if (queryParams.allowsGuideDog) { + venuesFilters.allowsGuideDog = parseFloat(queryParams.allowsGuideDog); + + const allowsGuideDog = parseFloat(queryParams.allowsGuideDog) === 1; + if (allowsGuideDog) { + dbVenuesFilters["allowsGuideDog.yes"] = { $gte: 1 }; + } else { + dbVenuesFilters["allowsGuideDog.no"] = { $gte: 1 }; + } + } + + if (queryParams.hasParking) { + venuesFilters.hasParking = queryParams.hasParking; + + const hasParking = parseFloat(queryParams.hasParking) === 1; + if (hasParking) { + dbVenuesFilters["hasParking.yes"] = { $gte: 1 }; + } else { + dbVenuesFilters["hasParking.no"] = { $gte: 1 }; + } + } + + /* + * Not used + * + if (queryParams.hasRamp) { + const hasRamp = parseFloat(queryParams.hasRamp) === 1; + if (hasRamp) { + venuesFilters['hasRamp.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasRamp.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasSecondEntry) { + const hasSecondEntry = parseFloat(queryParams.hasSecondEntry) === 1; + if (hasSecondEntry) { + venuesFilters['hasSecondEntry.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasSecondEntry.no'] = { $gte: 1 }; + } + } + + if (queryParams.hasWellLit) { + const hasWellLit = parseFloat(queryParams.hasWellLit) === 1; + if (hasWellLit) { + venuesFilters['hasWellLit.yes'] = { $gte: 1 }; + } else { + venuesFilters['hasWellLit.no'] = { $gte: 1 }; + } + } + + if (queryParams.isQuiet) { + const isQuiet = parseFloat(queryParams.isQuiet) === 1; + if (isQuiet) { + venuesFilters['isQuiet.yes'] = { $gte: 1 }; + } else { + venuesFilters['isQuiet.no'] = { $gte: 1 }; + } + } + + if (queryParams.isSpacious) { + const isSpacious = parseFloat(queryParams.isSpacious) === 1; + if (isSpacious) { + venuesFilters['isSpacious.yes'] = { $gte: 1 }; + } else { + venuesFilters['isSpacious.no'] = { $gte: 1 }; + } + } + + if (queryParams.steps) { + if (parseFloat(queryParams.steps) === 0) { + venuesFilters['steps.zero'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 1) { + venuesFilters['steps.one'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 2) { + venuesFilters['steps.two'] = { $gte: 1 }; + } else if (parseFloat(queryParams.steps) === 3) { + venuesFilters['steps.moreThanTwo'] = { $gte: 1 }; + } + } + * + */ + + let dataResponse; + + /* + * Legacy filtering function that searches solely on + * AXS Venue data and provides it's own pagination of 20 + * UPDATED 05/2020 TO SUPPORT FILTER ONLY SELF SEARCH + */ + if (!isEmpty(venuesFilters) && isEmpty(queryParams.name)) { + console.log(">> Performing DB search"); + /* + if (queryParams.name) { + //performs literal name match against AXS Venue name + venuesFilters.name = { $regex: queryParams.name, $options: 'i' }; + } + */ + + dbVenuesFilters.location = { + $near: { + $geometry: { + type: "Point", + coordinates: [coordinates[1], coordinates[0]], + }, + $maxDistance: 50000, + }, + }; + + if (queryParams.type) { + dbVenuesFilters.types = queryParams.type; + } + + dbVenuesFilters.isArchived = false; + + let page = 1; + if (isNumber(queryParams.page)) { + page = queryParams.page; + } + + const pageLimit = + "entranceScore" in venuesFilters || + "interiorScore" in venuesFilters || + "restroomScore" in venuesFilters + ? 80 + : 20; + + if (page > 0) { + page -= 1; + } else { + return res + .status(400) + .json({ page: "Should be equal to or greater than 1" }); + } + + let total; + let venues; + try { + [venues, total] = await Promise.all([ + Venue.find( + dbVenuesFilters + /*,'address allowsGuideDog hasParking hasSecondEntry hasWellLit isQuiet isSpacious location name photos placeId steps types'*/ + ) + .skip(page * pageLimit) + .limit(pageLimit), + (await Venue.find(dbVenuesFilters))?.length, + ]); + console.log({ total }); + } catch (err) { + console.log( + `Venues failed to be found or count at list-venues.\nvenuesQuery: ${JSON.stringify( + dbVenuesFilters + )}` + ); + console.log(err); + return next(err); + } + + venues = venues.map((venue) => + Object.assign({}, venue.toObject(), { + id: venue._id, + _id: undefined, + location: venue.coordinates, + }) + ); + + //+ADDED + //Perform ratings logic on all returned venues + console.log("Raw venues count: " + venues.length); + venues = venues.filter((venue) => { + //console.log('In scoring assignment'); + let scoring; + //calculate entranceScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel("entrance", venue); + venue.entranceScore = scoring.ratingLevel; + venue.entranceGlyphs = scoring.ratingGlyphs; + + //calculate interiorScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel("interior", venue); + venue.interiorScore = scoring.ratingLevel; + venue.interiorGlyphs = scoring.ratingGlyphs; + + //calculate restroomScore, glyphs + scoring = venueReviewSummary.calculateRatingLevel("restroom", venue); + venue.restroomScore = scoring.ratingLevel; + venue.restroomGlyphs = scoring.ratingGlyphs; + + venue.mapMarkerScore = venueReviewSummary.calculateMapMarkerScore( + venue.entranceScore, + venue.interiorScore, + venue.restroomScore + ); + + let passesValidation = true; + if ("entranceScore" in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && "interiorScore" in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && "restroomScore" in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + }); + + const lastPage = Math.ceil(total / pageLimit); + let nextPage; + if (lastPage > 0) { + page += 1; + if (page > lastPage || page > 3) { + return res.status(400).json({ + page: `Should be equal to or less than ${lastPage > 3 ? 3 : lastPage}`, + }); + } + } + + dataResponse = { + nextPage, + results: venues, + }; + /* + * End legacy filter + */ + } else { + console.log(">> Performing Google search"); + + /* + * Perform Google search when there text entered or no filters selected + */ + let nearbyParams = `?key=${process.env.PLACES_API_KEY}`; + let searchType = queryParams.name ? "textsearch" : "nearbysearch"; + + if (!queryParams.page) { + nearbyParams = `${nearbyParams}&location=${coordinates[0]},${ + coordinates[1] + }`; + + if (queryParams.name) { + nearbyParams = `${nearbyParams}&query=${queryParams.name}&rankby=distance`; + } else { + nearbyParams = `${nearbyParams}&rankby=distance`; + } + + if (queryParams.type) { + nearbyParams = `${nearbyParams}&type=${queryParams.type}`; + } else { + nearbyParams = `${nearbyParams}&type=establishment`; + } + } else { + nearbyParams = `${nearbyParams}&pagetoken=${queryParams.page}`; + } + if (queryParams.rankby) { + nearbyParams = `${nearbyParams}&rankby=${queryParams.rankby}`; + } + if (queryParams.opennow) { + nearbyParams = `${nearbyParams}&opennow=${queryParams.opennow}`; + } + if (queryParams.language) { + nearbyParams = `${nearbyParams}&language=${queryParams.language}`; + } + if (queryParams.minprice) { + nearbyParams = `${nearbyParams}&minprice=${queryParams.minprice}`; + } + if (queryParams.maxprice) { + nearbyParams = `${nearbyParams}&maxprice=${queryParams.maxprice}`; + } + + let placesResponse; + try { + console.log(`https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}&fields=photos,place_id`) + placesResponse = await axios.get( + `https://maps.googleapis.com/maps/api/place/${searchType}/json${nearbyParams}&fields=photos,place_id` + ); + } catch (err) { + console.log( + `Places failed to be found at list-venues.\nQuery Params: ${JSON.stringify( + queryParams + )}` + ); + return next(err); + } + + const statusCode = placesResponse.data.status; + if (statusCode === "OVER_QUERY_LIMIT") { + return next(new Error("Over query limit with Google Places API")); + } else if (statusCode === "REQUEST_DENIED") { + return next(new Error("Request denied with Google Places API")); + } else if (statusCode === "INVALID_REQUEST") { + return next(new Error("Invalid request with Google Places API")); + } else if (statusCode === "UNKNOWN_ERROR") { + return next(new Error("Unknown error with Google Places API")); + } + //do we need to check for 0? + + if (placesResponse.data.results?.length == 1) { + if (placesResponse.data.results[0].types[0] == "locality") { + console.log( + "Found a city only: ", + placesResponse.data.results[0].geometry.location + ); + //TODO: redo search with new coordinates and no query/name or change/add "places in " to the first part of the string + } + } + + //Format Google Places results and get array of IDs + let places = []; + const placesIds = []; + placesResponse.data.results.forEach((place) => { + console.log(place?.photos) + let photo = ""; + if (place.photos) { + photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=300&photoreference=${place.photos[0].photo_reference}`; + } + + places.push({ + //address: place.vicinity, + address: place.formatted_address, + location: { + lat: place.geometry.location.lat, + lng: place.geometry.location.lng, + }, + distance: covertDistanceToFeet( + getDistanceFromLatLng( + place.geometry.location.lat, + place.geometry.location.lng, + coordinates[0], + coordinates[1] + ), + queryParams.language + ), + name: place.name, + photo, + placeId: place.place_id, + types: place.types, + }); + placesIds.push(place.place_id); + }); + + // console.log("calling venues"); + //Use array of Google Place IDs to find AXS Venues + let venues; + try { + venues = await Venue.find({ placeId: { $in: placesIds } }); + } catch (err) { + console.log( + `Venues failed to be found at list-venues.\nPlaces ids: [${placesIds}]` + ); + return next(err); + } + //Perform ratings logic on all returned venues + venues.forEach((venue) => { + const entrance = venueReviewSummary.calculateEntranceScore(venue); + venue.entranceScore = entrance; + const interior = venueReviewSummary.calculateInteriorScore(venue); + venue.interiorScore = interior; + const bathroomScore = venueReviewSummary.calculateBathroomScore(venue); + venue.restroomScore = bathroomScore; + const mapScore = venueReviewSummary.calculateMapMarkerScore( + entrance, + interior, + bathroomScore + ); + venue.mapMarkerScore = mapScore; + }); + + //Filter out, remove, Google Places that are not AXS Venues + // Can't use hasOwnProperty() on mongoose model objects // + if (!isEmpty(venuesFilters)) { + places = places.filter((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + //console.log('In verification of filters'); + let passesValidation = true; + if (passesValidation && "allowsGuideDog" in venuesFilters) { + if ( + !venue.allowsGuideDog || + venue.allowsGuideDog.yes < venue.allowsGuideDog.no || + venue.allowsGuideDog.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && "hasParking" in venuesFilters) { + if ( + !venue.hasParking || + venue.hasParking.yes < venue.hasParking.no || + venue.hasParking.yes == 0 + ) { + passesValidation = false; + } + } + + if (passesValidation && "entranceScore" in venuesFilters) { + if ( + !venue.entranceScore || + venue.entranceScore < venuesFilters.entranceScore + ) { + passesValidation = false; + } + } + + if (passesValidation && "interiorScore" in venuesFilters) { + if ( + !venue.interiorScore || + venue.interiorScore < venuesFilters.interiorScore + ) { + passesValidation = false; + } + } + + if (passesValidation && "restroomScore" in venuesFilters) { + if ( + !venue.restroomScore || + venue.restroomScore < venuesFilters.restroomScore + ) { + passesValidation = false; + } + } + + if (passesValidation) { + return venue; + } + } + }); + } //end filtering Google results + + // + places = places.map((place) => { + const venue = find(venues, (venue) => venue.placeId === place.placeId); + if (venue) { + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: venue.hasPermanentRamp, + hasPortableRamp: venue.hasPortableRamp, + hasWideEntrance: venue.hasWideEntrance, + hasAccessibleTableHeight: venue.hasAccessibleTableHeight, + hasAccessibleElevator: venue.hasAccessibleElevator, + hasInteriorRamp: venue.hasInteriorRamp, + hasSwingInDoor: venue.hasSwingInDoor, + hasSwingOutDoor: venue.hasSwingOutDoor, + hasLargeStall: venue.hasLargeStall, + hasSupportAroundToilet: venue.hasSupportAroundToilet, + hasLoweredSinks: venue.hasLoweredSinks, + entranceGlyphs: venue.entranceGlyphs, + interiorGlyphs: venue.interiorGlyphs, + restroomGlyphs: venue.restroomGlyphs, + allowsGuideDog: venue.allowsGuideDog, + hasParking: venue.hasParking, + hasSecondEntry: venue.hasSecondEntry, + hasWellLit: venue.hasWellLit, + isQuiet: venue.isQuiet, + isSpacious: venue.isSpacious, + steps: venue.steps, + restroomScore: venue.restroomScore, + entranceScore: venue.entranceScore, + interiorScore: venue.interiorScore, + mapMarkerScore: venue.mapMarkerScore, + isReviewed:true + }); + } + + //venue not found + return Object.assign({}, place, { + //new expanded fields + hasPermanentRamp: { yes: 0, no: 0 }, + hasPortableRamp: { yes: 0, no: 0 }, + hasWideEntrance: { yes: 0, no: 0 }, + hasAccessibleTableHeight: { yes: 0, no: 0 }, + hasAccessibleElevator: { yes: 0, no: 0 }, + hasInteriorRamp: { yes: 0, no: 0 }, + hasSwingInDoor: { yes: 0, no: 0 }, + hasSwingOutDoor: { yes: 0, no: 0 }, + hasLargeStall: { yes: 0, no: 0 }, + hasSupportAroundToilet: { yes: 0, no: 0 }, + hasLoweredSinks: { yes: 0, no: 0 }, + interiorGlyphs: "interior", + restroomGlyphs: "restroom", + entranceGlyphs: "entrylg", + + // original fields + allowsGuideDog: { yes: 0, no: 0 }, + hasParking: { yes: 0, no: 0 }, + hasSecondEntry: { yes: 0, no: 0 }, + hasWellLit: { yes: 0, no: 0 }, + isQuiet: { yes: 0, no: 0 }, + isSpacious: { yes: 0, no: 0 }, + steps: { + zero: 0, + one: 0, + two: 0, + moreThanTwo: 0, + }, + entranceScore: 0, + interiorScore: 0, + restroomScore: 0, + mapMarkerScore: 0, + isReviewed:false + }); + }); + + dataResponse = { + nextPage: placesResponse.data.next_page_token, + results: places, + }; + } //ends legacy filter logic, false conditional + + return res.status(200).json(dataResponse); +}; diff --git a/src/routes/venues/validations.js b/src/routes/venues/validations.js index 6d393cc..d85c043 100644 --- a/src/routes/venues/validations.js +++ b/src/routes/venues/validations.js @@ -1,154 +1,154 @@ -const { isEmpty } = require('lodash'); - -const { isNumber } = require('../../helpers'); -const { placesTypes } = require('../../helpers/constants'); - -module.exports = { - validateListVenues(queryParams) { - const errors = {}; - - if (!queryParams.location) { - errors.location = 'Is required'; - } else { - const location = queryParams.location.split(','); - - if (location.length !== 2) { - errors.location = 'Should have two coordinates'; - } else if (!location[0]) { - errors.location = 'Latitude is required'; - } else if (!isNumber(location[0])) { - errors.location = 'Latitude should be a number'; - } else if ( - parseFloat(location[0]) < -90 || - parseFloat(location[0]) > 90 - ) { - errors.location = 'Latitude value out of bounds'; - } else if (!location[1]) { - errors.location = 'Longitude is required'; - } else if (!isNumber(location[1])) { - errors.location = 'Longitude should be a number'; - } else if ( - parseFloat(location[1]) < -180 || - parseFloat(location[1]) > 180 - ) { - errors.location = 'Longitude value out of bounds'; - } - } - - if (queryParams.bathroomScore) { - if (!isNumber(queryParams.bathroomScore)) { - errors.bathroomScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.bathroomScore) < 1 || - parseFloat(queryParams.bathroomScore) > 5 - ) { - errors.bathroomScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.entryScore) { - if (!isNumber(queryParams.entryScore)) { - errors.entryScore = 'Should be a number'; - } else if ( - parseFloat(queryParams.entryScore) < 1 || - parseFloat(queryParams.entryScore) > 5 - ) { - errors.entryScore = 'Should be between 1 and 5'; - } - } - - if (queryParams.allowsGuideDog) { - if (!isNumber(queryParams.allowsGuideDog)) { - errors.allowsGuideDog = 'Should be a number'; - } else if ( - parseFloat(queryParams.allowsGuideDog) !== 0 && - parseFloat(queryParams.allowsGuideDog) !== 1 - ) { - errors.allowsGuideDog = 'Should be 0 or 1'; - } - } - - if (queryParams.hasParking) { - if (!isNumber(queryParams.hasParking)) { - errors.hasParking = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasParking) !== 0 && - parseFloat(queryParams.hasParking) !== 1 - ) { - errors.hasParking = 'Should be 0 or 1'; - } - } - - if (queryParams.hasRamp) { - if (!isNumber(queryParams.hasRamp)) { - errors.hasRamp = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasRamp) !== 0 && - parseFloat(queryParams.hasRamp) !== 1 - ) { - errors.hasRamp = 'Should be 0 or 1'; - } - } - - if (queryParams.hasSecondEntry) { - if (!isNumber(queryParams.hasSecondEntry)) { - errors.hasSecondEntry = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasSecondEntry) !== 0 && - parseFloat(queryParams.hasSecondEntry) !== 1 - ) { - errors.hasSecondEntry = 'Should be 0 or 1'; - } - } - - if (queryParams.hasWellLit) { - if (!isNumber(queryParams.hasWellLit)) { - errors.hasWellLit = 'Should be a number'; - } else if ( - parseFloat(queryParams.hasWellLit) !== 0 && - parseFloat(queryParams.hasWellLit) !== 1 - ) { - errors.hasWellLit = 'Should be 0 or 1'; - } - } - - if (queryParams.isQuiet) { - if (!isNumber(queryParams.isQuiet)) { - errors.isQuiet = 'Should be a number'; - } else if ( - parseFloat(queryParams.isQuiet) !== 0 && - parseFloat(queryParams.isQuiet) !== 1 - ) { - errors.isQuiet = 'Should be 0 or 1'; - } - } - - if (queryParams.isSpacious) { - if (!isNumber(queryParams.isSpacious)) { - errors.isSpacious = 'Should be a number'; - } else if ( - parseFloat(queryParams.isSpacious) !== 0 && - parseFloat(queryParams.isSpacious) !== 1 - ) { - errors.isSpacious = 'Should be 0 or 1'; - } - } - - if (queryParams.steps) { - if (!isNumber(queryParams.steps)) { - errors.steps = 'Should be a number'; - } else if ( - parseFloat(queryParams.steps) < 0 || - parseFloat(queryParams.steps) > 3 - ) { - errors.steps = 'Should be between 0 and 3'; - } - } - - if (queryParams.type && !placesTypes.includes(queryParams.type)) { - errors.type = 'Should be a valid type'; - } - - return { errors, isValid: isEmpty(errors) }; - } -}; +const { isEmpty } = require('lodash'); + +const { isNumber } = require('../../helpers'); +const { placesTypes } = require('../../helpers/constants'); + +module.exports = { + validateListVenues(queryParams) { + const errors = {}; + + if (!queryParams.location) { + errors.location = 'Is required'; + } else { + const location = queryParams.location.split(','); + + if (location.length !== 2) { + errors.location = 'Should have two coordinates'; + } else if (!location[0]) { + errors.location = 'Latitude is required'; + } else if (!isNumber(location[0])) { + errors.location = 'Latitude should be a number'; + } else if ( + parseFloat(location[0]) < -90 || + parseFloat(location[0]) > 90 + ) { + errors.location = 'Latitude value out of bounds'; + } else if (!location[1]) { + errors.location = 'Longitude is required'; + } else if (!isNumber(location[1])) { + errors.location = 'Longitude should be a number'; + } else if ( + parseFloat(location[1]) < -180 || + parseFloat(location[1]) > 180 + ) { + errors.location = 'Longitude value out of bounds'; + } + } + + if (queryParams.bathroomScore) { + if (!isNumber(queryParams.bathroomScore)) { + errors.bathroomScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.bathroomScore) < 1 || + parseFloat(queryParams.bathroomScore) > 5 + ) { + errors.bathroomScore = 'Should be between 1 and 5'; + } + } + + if (queryParams.entryScore) { + if (!isNumber(queryParams.entryScore)) { + errors.entryScore = 'Should be a number'; + } else if ( + parseFloat(queryParams.entryScore) < 1 || + parseFloat(queryParams.entryScore) > 5 + ) { + errors.entryScore = 'Should be between 1 and 5'; + } + } + + // if (queryParams.allowsGuideDog) { + // if (!isNumber(queryParams.allowsGuideDog)) { + // errors.allowsGuideDog = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.allowsGuideDog) !== 0 && + // parseFloat(queryParams.allowsGuideDog) !== 1 + // ) { + // errors.allowsGuideDog = 'Should be 0 or 1'; + // } + // } + + if (queryParams.hasParking) { + if (!isNumber(queryParams.hasParking)) { + errors.hasParking = 'Should be a number'; + } else if ( + parseFloat(queryParams.hasParking) !== 0 && + parseFloat(queryParams.hasParking) !== 1 + ) { + errors.hasParking = 'Should be 0 or 1'; + } + } + + // if (queryParams.hasRamp) { + // if (!isNumber(queryParams.hasRamp)) { + // errors.hasRamp = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.hasRamp) !== 0 && + // parseFloat(queryParams.hasRamp) !== 1 + // ) { + // errors.hasRamp = 'Should be 0 or 1'; + // } + // } + + // if (queryParams.hasSecondEntry) { + // if (!isNumber(queryParams.hasSecondEntry)) { + // errors.hasSecondEntry = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.hasSecondEntry) !== 0 && + // parseFloat(queryParams.hasSecondEntry) !== 1 + // ) { + // errors.hasSecondEntry = 'Should be 0 or 1'; + // } + // } + + // if (queryParams.hasWellLit) { + // if (!isNumber(queryParams.hasWellLit)) { + // errors.hasWellLit = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.hasWellLit) !== 0 && + // parseFloat(queryParams.hasWellLit) !== 1 + // ) { + // errors.hasWellLit = 'Should be 0 or 1'; + // } + // } + + // if (queryParams.isQuiet) { + // if (!isNumber(queryParams.isQuiet)) { + // errors.isQuiet = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.isQuiet) !== 0 && + // parseFloat(queryParams.isQuiet) !== 1 + // ) { + // errors.isQuiet = 'Should be 0 or 1'; + // } + // } + + // if (queryParams.isSpacious) { + // if (!isNumber(queryParams.isSpacious)) { + // errors.isSpacious = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.isSpacious) !== 0 && + // parseFloat(queryParams.isSpacious) !== 1 + // ) { + // errors.isSpacious = 'Should be 0 or 1'; + // } + // } + + // if (queryParams.steps) { + // if (!isNumber(queryParams.steps)) { + // errors.steps = 'Should be a number'; + // } else if ( + // parseFloat(queryParams.steps) < 0 || + // parseFloat(queryParams.steps) > 3 + // ) { + // errors.steps = 'Should be between 0 and 3'; + // } + // } + + if (queryParams.type && !placesTypes.includes(queryParams.type)) { + errors.type = 'Should be a valid type'; + } + + return { errors, isValid: isEmpty(errors) }; + } +}; diff --git a/src/routes/venues/venue-details.js b/src/routes/venues/venue-details.js new file mode 100644 index 0000000..0178765 --- /dev/null +++ b/src/routes/venues/venue-details.js @@ -0,0 +1,75 @@ +const axios = require("axios"); +const { Venue } = require("../../models/venue"); +const { Review } = require("../../models/review"); + +module.exports = async (req, res, next) => { + const placeId = req.params.placeId; + + try { + const venue = await Venue.findOne({ + placeId, + }); + let customReviews; + // console.log("venue", venue); + + if (venue) { + customReviews = await Review.aggregate([ + { + $match: { venue: venue._id }, + }, + { + $lookup: { + from: "users", + localField: "user", + foreignField: "_id", + as: "user", + }, + }, + { $unwind: "$user" }, + { + $project: { + _id: 1, + comments: { $ifNull: ["$comments", null] }, + firstName: { $ifNull: ["$user.firstName", null] }, + lastName: { $ifNull: ["$user.lastName", null] }, + avatar: { $ifNull: ["$user.avatar", null] }, + createdAt: 1, + }, + }, + ]); + } + const googleResponse = await axios.get( + "https://maps.googleapis.com/maps/api/place/details/json", + { + params: { + place_id: placeId, + fields: + "name,photos,international_phone_number,rating,reviews,formatted_address,geometry,user_ratings_total,rating,opening_hours,website", + key: process.env.PLACES_API_KEY, + }, + } + ); + let photo; + if (googleResponse.data.result.photos) { + photo = `https://maps.googleapis.com/maps/api/place/photo?key=${ + process.env.PLACES_API_KEY + }&maxwidth=300&photoreference=${googleResponse.data.result.photos[0].photo_reference}`; + } + const googleData = { + ...googleResponse.data.result, + photo, + }; + + if (!googleData) { + return res + .status(404) + .json({ message: "Google venue details not found." }); + } + res.json({ + data: { googleData, axsReviews: customReviews }, + }); + } catch (err) { + console.log(`Place ${placeId} failed to be found at get-venue.`); + return next(err); + } +}; diff --git a/src/scripts/db/import-events.js b/src/scripts/db/import-events.js index 6ad0a17..65fa480 100644 --- a/src/scripts/db/import-events.js +++ b/src/scripts/db/import-events.js @@ -1,154 +1,154 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -const oldEventsSchema = require('./old-schemas/event'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const oldEvent = oldDb.model('events', oldEventsSchema); - - let totalOldEvents; - try { - totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); - } catch (error) { - console.log('Old events failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old events: ${totalOldEvents}`); - - console.time('createEvents'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldEvents; - try { - oldEvents = await oldEvent - .find({ name: { $ne: '' } }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old events failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Event = db.model('Event', eventSchema); - - const createEvents = []; - for (let oldEventItem of oldEvents) { - let participants = oldEventItem.members.map(member => member.user); - participants = participants.filter( - p => p.toString() !== oldEventItem.creator.toString() - ); - - const eventData = { - _id: oldEventItem.id, - createdAt: oldEventItem.created_at, - description: oldEventItem.description.substring(0, 300), - endDate: oldEventItem.event_end, - managers: [oldEventItem.creator], - name: oldEventItem.name, - participants, - participantsGoal: oldEventItem.participant_goal - ? oldEventItem.participant_goal > 1000 - ? 1000 - : oldEventItem.participant_goal - : 1, - poster: oldEventItem.image, - reviewsGoal: oldEventItem.mapping_goal - ? oldEventItem.mapping_goal > 10000 - ? 10000 - : oldEventItem.mapping_goal - : 1, - startDate: oldEventItem.event_start, - teams: oldEventItem.teams, - updatedAt: oldEventItem.updated_at, - venue: oldEventItem.location - }; - - createEvents.push(Event.create(eventData)); - } - - try { - await Promise.all(createEvents); - } catch (error) { - console.log( - `Events failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldEvents.length; - console.log(i); - } while (i < totalOldEvents); - - console.timeEnd('createEvents'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +const oldEventsSchema = require('./old-schemas/event'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const oldEvent = oldDb.model('events', oldEventsSchema); + + let totalOldEvents; + try { + totalOldEvents = await oldEvent.count({ name: { $ne: '' } }); + } catch (error) { + console.log('Old events failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old events: ${totalOldEvents}`); + + console.time('createEvents'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldEvents; + try { + oldEvents = await oldEvent + .find({ name: { $ne: '' } }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old events failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Event = db.model('Event', eventSchema); + + const createEvents = []; + for (let oldEventItem of oldEvents) { + let participants = oldEventItem.members.map((member) => member.user); + participants = participants.filter( + (p) => p.toString() !== oldEventItem.creator.toString() + ); + + const eventData = { + _id: oldEventItem.id, + createdAt: oldEventItem.created_at, + description: oldEventItem.description.substring(0, 300), + endDate: oldEventItem.event_end, + managers: [oldEventItem.creator], + name: oldEventItem.name, + participants, + participantsGoal: oldEventItem.participant_goal + ? oldEventItem.participant_goal > 1000 + ? 1000 + : oldEventItem.participant_goal + : 1, + poster: oldEventItem.image, + reviewsGoal: oldEventItem.mapping_goal + ? oldEventItem.mapping_goal > 10000 + ? 10000 + : oldEventItem.mapping_goal + : 1, + startDate: oldEventItem.event_start, + teams: oldEventItem.teams, + updatedAt: oldEventItem.updated_at, + venue: oldEventItem.location + }; + + createEvents.push(Event.create(eventData)); + } + + try { + await Promise.all(createEvents); + } catch (error) { + console.log( + `Events failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldEvents.length; + console.log(i); + } while (i < totalOldEvents); + + console.timeEnd('createEvents'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-reviews.js b/src/scripts/db/import-reviews.js index 4f36291..1e125c3 100644 --- a/src/scripts/db/import-reviews.js +++ b/src/scripts/db/import-reviews.js @@ -1,149 +1,149 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); - -const oldReviewSchema = require('./old-schemas/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldReview = oldDb.model('reviews', oldReviewSchema); - - let totalOldReviews; - try { - totalOldReviews = await OldReview.count(); - } catch (error) { - console.log('Old reviews failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old reviews: ${totalOldReviews}`); - - console.time('createReviews'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldReviews; - try { - oldReviews = await OldReview.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old reviews failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Review = db.model('Review', reviewSchema); - - const createReviews = []; - for (let oldReview of oldReviews) { - if (oldReview.venue_id && oldReview.user_id) { - const reviewData = { - _id: oldReview.id, - allowsGuideDog: oldReview.guidedog, - createdAt: oldReview.created_at, - bathroomScore: oldReview.bathroom, - entryScore: oldReview.entry, - event: oldReview.event, - hasParking: oldReview.parking, - hasRamp: oldReview.ramp, - hasSecondEntry: oldReview.secondentrance, - hasWellLit: oldReview.welllit, - isQuiet: oldReview.quiet, - isSpacious: oldReview.spacious, - steps: oldReview.steps, - team: oldReview.team, - updatedAt: oldReview.updated_at, - user: oldReview.user_id, - venue: oldReview.venue_id - }; - - if (oldReview.comment && oldReview.comment.length <= 300) { - reviewData.comments = oldReview.comment; - } - - createReviews.push(Review.create(reviewData)); - } - } - - try { - await Promise.all(createReviews); - } catch (error) { - console.log( - `Reviews failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldReviews.length; - console.log(i); - } while (i < totalOldReviews); - - console.timeEnd('createReviews'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); + +const oldReviewSchema = require('./old-schemas/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldReview = oldDb.model('reviews', oldReviewSchema); + + let totalOldReviews; + try { + totalOldReviews = await OldReview.count(); + } catch (error) { + console.log('Old reviews failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old reviews: ${totalOldReviews}`); + + console.time('createReviews'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldReviews; + try { + oldReviews = await OldReview.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old reviews failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Review = db.model('Review', reviewSchema); + + const createReviews = []; + for (let oldReview of oldReviews) { + if (oldReview.venue_id && oldReview.user_id) { + const reviewData = { + _id: oldReview.id, + allowsGuideDog: oldReview.guidedog, + createdAt: oldReview.created_at, + bathroomScore: oldReview.bathroom, + entryScore: oldReview.entry, + event: oldReview.event, + hasParking: oldReview.parking, + hasRamp: oldReview.ramp, + hasSecondEntry: oldReview.secondentrance, + hasWellLit: oldReview.welllit, + isQuiet: oldReview.quiet, + isSpacious: oldReview.spacious, + steps: oldReview.steps, + team: oldReview.team, + updatedAt: oldReview.updated_at, + user: oldReview.user_id, + venue: oldReview.venue_id + }; + + if (oldReview.comment && oldReview.comment.length <= 300) { + reviewData.comments = oldReview.comment; + } + + createReviews.push(Review.create(reviewData)); + } + } + + try { + await Promise.all(createReviews); + } catch (error) { + console.log( + `Reviews failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldReviews.length; + console.log(i); + } while (i < totalOldReviews); + + console.timeEnd('createReviews'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-teams.js b/src/scripts/db/import-teams.js index 4334d0b..b9393ce 100644 --- a/src/scripts/db/import-teams.js +++ b/src/scripts/db/import-teams.js @@ -1,270 +1,270 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { reviewSchema } = require('../../models/review'); -const { teamSchema } = require('../../models/team'); - -const oldTeamSchema = require('./old-schemas/team'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldTeam = oldDb.model('teams', oldTeamSchema); - - let totalOldTeams; - try { - totalOldTeams = await OldTeam.count(); - } catch (error) { - console.log('Old teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old teams: ${totalOldTeams}`); - - const Team = db.model('Team', teamSchema); - - console.time('createTeams'); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let oldTeams; - try { - oldTeams = await OldTeam.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createTeams = []; - const uploadTeamsAvatars = []; - for (let oldTeam of oldTeams) { - if (oldTeam.name) { - const members = oldTeam.members.filter( - m => m.toString() !== oldTeam.creator.toString() - ); - const teamData = { - _id: oldTeam.id, - createdAt: oldTeam.created_at, - events: oldTeam.events, - managers: [oldTeam.creator], - members: members, - name: - oldTeam.name.length > 35 - ? oldTeam.name.substring(0, 35) - : oldTeam.name, - updatedAt: oldTeam.updated_at - }; - - if (oldTeam.description) { - teamData.description = - oldTeam.description.length <= 300 - ? oldTeam.description - : oldTeam.description.substring(0, 300); - } - - if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { - let avatarImage; - try { - avatarImage = await jimp.read(encodeURI(oldTeam.image)); - } catch (err) { - console.log('Old team avatar image failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - if (avatarImage) { - const avatarExtension = avatarImage.getExtension(); - const avatarFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${avatarExtension}`; - - if ( - avatarExtension === 'png' || - avatarExtension === 'jpeg' || - avatarExtension === 'jpg' || - avatarExtension === 'bmp' - ) { - teamData.avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/teams/avatars/${avatarFileName}`; - avatarImage - .cover(400, 400) - .quality(85) - .getBuffer( - avatarImage.getMIME(), - async (err, avatarBuffer) => { - if (err) { - console.log('Old team avatar buffer failed to be read'); - console.log(err); - await closeConnections(db, oldDb); - } - - uploadTeamsAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: avatarBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: avatarImage.getMIME(), - Key: `teams/avatars/${avatarFileName}` - }) - .promise() - ); - } - ); - } - } - } - - createTeams.push(Team.create(teamData)); - } - } - - try { - await Promise.all([...createTeams, ...uploadTeamsAvatars]); - } catch (error) { - console.log( - `Teams failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldTeams.length; - console.log(i); - } while (i < totalOldTeams); - - console.timeEnd('createTeams'); - - const Review = db.model('Review', reviewSchema); - - let totalTeams; - try { - totalTeams = await Team.count(); - } catch (error) { - console.log('Teams failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total teams: ${totalTeams}`); - - i = 0; - page = 0; - do { - let teams; - try { - teams = await Team.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateTeams = []; - for (let team of teams) { - let teamReviews; - try { - teamReviews = await Review.find({ team: team.id }).count(); - } catch (err) { - console.log('Team reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - team.reviewsAmount = teamReviews; - updateTeams.push(team.save()); - } - - try { - await Promise.all(updateTeams); - } catch (err) { - console.log( - `Teams failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + teams.length; - console.log(i); - } while (i < totalTeams); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { reviewSchema } = require('../../models/review'); +const { teamSchema } = require('../../models/team'); + +const oldTeamSchema = require('./old-schemas/team'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldTeam = oldDb.model('teams', oldTeamSchema); + + let totalOldTeams; + try { + totalOldTeams = await OldTeam.count(); + } catch (error) { + console.log('Old teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old teams: ${totalOldTeams}`); + + const Team = db.model('Team', teamSchema); + + console.time('createTeams'); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let oldTeams; + try { + oldTeams = await OldTeam.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createTeams = []; + const uploadTeamsAvatars = []; + for (let oldTeam of oldTeams) { + if (oldTeam.name) { + const members = oldTeam.members.filter( + (m) => m.toString() !== oldTeam.creator.toString() + ); + const teamData = { + _id: oldTeam.id, + createdAt: oldTeam.created_at, + events: oldTeam.events, + managers: [oldTeam.creator], + members: members, + name: + oldTeam.name.length > 35 + ? oldTeam.name.substring(0, 35) + : oldTeam.name, + updatedAt: oldTeam.updated_at + }; + + if (oldTeam.description) { + teamData.description = + oldTeam.description.length <= 300 + ? oldTeam.description + : oldTeam.description.substring(0, 300); + } + + if (oldTeam.image && !oldTeam.image.includes('icon_team.png')) { + let avatarImage; + try { + avatarImage = await jimp.read(encodeURI(oldTeam.image)); + } catch (err) { + console.log('Old team avatar image failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + if (avatarImage) { + const avatarExtension = avatarImage.getExtension(); + const avatarFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${avatarExtension}`; + + if ( + avatarExtension === 'png' || + avatarExtension === 'jpeg' || + avatarExtension === 'jpg' || + avatarExtension === 'bmp' + ) { + teamData.avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/teams/avatars/${avatarFileName}`; + avatarImage + .cover(400, 400) + .quality(85) + .getBuffer( + avatarImage.getMIME(), + async (err, avatarBuffer) => { + if (err) { + console.log('Old team avatar buffer failed to be read'); + console.log(err); + await closeConnections(db, oldDb); + } + + uploadTeamsAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: avatarBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: avatarImage.getMIME(), + Key: `teams/avatars/${avatarFileName}` + }) + .promise() + ); + } + ); + } + } + } + + createTeams.push(Team.create(teamData)); + } + } + + try { + await Promise.all([...createTeams, ...uploadTeamsAvatars]); + } catch (error) { + console.log( + `Teams failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldTeams.length; + console.log(i); + } while (i < totalOldTeams); + + console.timeEnd('createTeams'); + + const Review = db.model('Review', reviewSchema); + + let totalTeams; + try { + totalTeams = await Team.count(); + } catch (error) { + console.log('Teams failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total teams: ${totalTeams}`); + + i = 0; + page = 0; + do { + let teams; + try { + teams = await Team.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateTeams = []; + for (let team of teams) { + let teamReviews; + try { + teamReviews = await Review.find({ team: team.id }).count(); + } catch (err) { + console.log('Team reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + team.reviewsAmount = teamReviews; + updateTeams.push(team.save()); + } + + try { + await Promise.all(updateTeams); + } catch (err) { + console.log( + `Teams failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + teams.length; + console.log(i); + } while (i < totalTeams); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-users.js b/src/scripts/db/import-users.js index ed75da7..55fdd69 100644 --- a/src/scripts/db/import-users.js +++ b/src/scripts/db/import-users.js @@ -1,275 +1,275 @@ -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); -const slugify = require('speakingurl'); - -require('dotenv').config(); - -const { cleanSpaces } = require('../../helpers'); -const { reviewSchema } = require('../../models/review'); -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - const User = db.model('User', userSchema); - - console.time('createUsers'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const createUsers = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - const userData = { - _id: oldUser.id, - createdAt: oldUser.createdAt, - description: oldUser.description - ? cleanSpaces(oldUser.description) - : '', - email: oldUser.email, - events: oldUser.events, - facebookId: oldUser.facebookAuth, - firstName: - oldUser.name.first && cleanSpaces(oldUser.name.first) - ? cleanSpaces(oldUser.name.first) - : 'first', - hashedPassword: oldUser.hash, - isSubscribed: oldUser.newsletter, - lastName: - oldUser.name.last && cleanSpaces(oldUser.name.last) - ? cleanSpaces(oldUser.name.last) - : 'last', - phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', - showEmail: oldUser.showEmail, - showPhone: oldUser.showPhone, - teams: oldUser.teams, - updatedAt: oldUser.updatedAt, - username: `${slugify(oldUser.name.first)}-${slugify( - oldUser.name.last - )}-${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}` - }; - - switch (oldUser.disabilitytype.toLowerCase()) { - case 'audio': - userData.disabilities = ['audio']; - break; - - case 'other': - userData.disabilities = ['other']; - break; - - case 'private': - userData.disabilities = ['private']; - break; - - case 'visual': - userData.disabilities = ['vision']; - break; - - case 'wheelchair': - userData.disabilities = ['physical']; - break; - - default: - userData.disabilities = ['none']; - } - - switch (oldUser.gender.toLowerCase()) { - case 'female': - userData.gender = 'female'; - break; - - case 'male': - userData.gender = 'male'; - break; - - case 'other': - userData.gender = 'other'; - break; - - case 'transgender': - userData.gender = 'transgender'; - break; - - default: - userData.gender = 'private'; - } - - if (oldUser.zip && oldUser.zip.length <= 32) { - userData.zip = oldUser.zip; - } - - createUsers.push(User.create(userData)); - } - } - - try { - await Promise.all(createUsers); - } catch (error) { - console.log( - `Users failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - console.timeEnd('createUsers'); - - const Review = db.model('Review', reviewSchema); - - let totalUsers; - try { - totalUsers = await User.count(); - } catch (error) { - console.log('Users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total users: ${totalUsers}`); - - console.time('updateReviewsAmount'); - - i = 0; - page = 0; - do { - let users; - try { - users = await User.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const updateUsers = []; - for (let user of users) { - let userReviews; - try { - userReviews = await Review.find({ user: user.id }).count(); - } catch (err) { - console.log('User reviews failed to be count'); - console.log(err); - await closeConnections(db, oldDb); - } - - user.reviewsAmount = userReviews; - updateUsers.push(user.save()); - } - - try { - await Promise.all(updateUsers); - } catch (err) { - console.log( - `Users failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + users.length; - console.log(i); - } while (i < totalUsers); - - console.timeEnd('updateReviewsAmount'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); +const slugify = require('speakingurl'); + +require('dotenv').config(); + +const { cleanSpaces } = require('../../helpers'); +const { reviewSchema } = require('../../models/review'); +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + const User = db.model('User', userSchema); + + console.time('createUsers'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const createUsers = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + const userData = { + _id: oldUser.id, + createdAt: oldUser.createdAt, + description: oldUser.description + ? cleanSpaces(oldUser.description) + : '', + email: oldUser.email, + events: oldUser.events, + facebookId: oldUser.facebookAuth, + firstName: + oldUser.name.first && cleanSpaces(oldUser.name.first) + ? cleanSpaces(oldUser.name.first) + : 'first', + hashedPassword: oldUser.hash, + isSubscribed: oldUser.newsletter, + lastName: + oldUser.name.last && cleanSpaces(oldUser.name.last) + ? cleanSpaces(oldUser.name.last) + : 'last', + phone: oldUser.phone ? cleanSpaces(oldUser.phone) : '', + showEmail: oldUser.showEmail, + showPhone: oldUser.showPhone, + teams: oldUser.teams, + updatedAt: oldUser.updatedAt, + username: `${slugify(oldUser.name.first)}-${slugify( + oldUser.name.last + )}-${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}` + }; + + switch (oldUser.disabilitytype.toLowerCase()) { + case 'audio': + userData.disabilities = ['audio']; + break; + + case 'other': + userData.disabilities = ['other']; + break; + + case 'private': + userData.disabilities = ['private']; + break; + + case 'visual': + userData.disabilities = ['vision']; + break; + + case 'wheelchair': + userData.disabilities = ['physical']; + break; + + default: + userData.disabilities = ['none']; + } + + switch (oldUser.gender.toLowerCase()) { + case 'female': + userData.gender = 'female'; + break; + + case 'male': + userData.gender = 'male'; + break; + + case 'other': + userData.gender = 'other'; + break; + + case 'transgender': + userData.gender = 'transgender'; + break; + + default: + userData.gender = 'private'; + } + + if (oldUser.zip && oldUser.zip.length <= 32) { + userData.zip = oldUser.zip; + } + + createUsers.push(User.create(userData)); + } + } + + try { + await Promise.all(createUsers); + } catch (error) { + console.log( + `Users failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + console.timeEnd('createUsers'); + + const Review = db.model('Review', reviewSchema); + + let totalUsers; + try { + totalUsers = await User.count(); + } catch (error) { + console.log('Users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total users: ${totalUsers}`); + + console.time('updateReviewsAmount'); + + i = 0; + page = 0; + do { + let users; + try { + users = await User.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const updateUsers = []; + for (let user of users) { + let userReviews; + try { + userReviews = await Review.find({ user: user.id }).count(); + } catch (err) { + console.log('User reviews failed to be count'); + console.log(err); + await closeConnections(db, oldDb); + } + + user.reviewsAmount = userReviews; + updateUsers.push(user.save()); + } + + try { + await Promise.all(updateUsers); + } catch (err) { + console.log( + `Users failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + users.length; + console.log(i); + } while (i < totalUsers); + + console.timeEnd('updateReviewsAmount'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/import-venues.js b/src/scripts/db/import-venues.js index 331c7b3..bf03081 100644 --- a/src/scripts/db/import-venues.js +++ b/src/scripts/db/import-venues.js @@ -1,182 +1,182 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { venueSchema } = require('../../models/venue'); - -const oldVenueSchema = require('./old-schemas/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldVenue = oldDb.model('venues', oldVenueSchema); - - let totalOldVenues; - try { - totalOldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }).count(); - } catch (error) { - console.log('Old venues failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old venues: ${totalOldVenues}`); - - console.time('createVenues'); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldVenues; - try { - oldVenues = await OldVenue.find({ - lngLat: { $exists: true }, - place_id: { $exists: true, $ne: '' }, - types: { $ne: [] } - }) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old venues failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const Venue = db.model('Venue', venueSchema); - - const createVenues = []; - for (let oldVenue of oldVenues) { - const addressOne = oldVenue.addr1; - const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; - const city = oldVenue.city ? `, ${oldVenue.city}` : ''; - const state = oldVenue.state ? `, ${oldVenue.state}` : ''; - const address = `${addressOne}${addressTwo}${city}${state}`; - - const bathroomScore = - oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; - const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; - - let longitude; - if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { - longitude = oldVenue.lngLat[1]; - } - let latitude; - if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { - latitude = oldVenue.lngLat[0]; - } else { - longitude = oldVenue.lngLat[0]; - latitude = oldVenue.lngLat[1]; - } - - const venueData = { - _id: oldVenue.id, - address: oldVenue.addr1 ? address : '', - allowsGuideDog: { yes: oldVenue.guidedog }, - bathroomReviews: oldVenue.b_reviews, - bathroomScore, - createdAt: oldVenue.created_at, - entryReviews: oldVenue.e_reviews, - entryScore, - hasParking: { yes: oldVenue.parking }, - hasRamp: { yes: oldVenue.ramp }, - hasSecondEntry: { yes: oldVenue.secondentrance }, - hasWellLit: { yes: oldVenue.welllit }, - isQuiet: { yes: oldVenue.quiet }, - isSpacious: { yes: oldVenue.spacious }, - location: { coordinates: [longitude, latitude] }, - name: oldVenue.name, - placeId: oldVenue.place_id, - reviews: oldVenue.reviewdata, - steps: { - zero: oldVenue.steps_0, - one: oldVenue.steps_1, - two: oldVenue.steps_2, - moreThanTwo: oldVenue.steps_3 - }, - types: oldVenue.types, - updatedAt: oldVenue.updated_at - }; - - createVenues.push(Venue.create(venueData)); - } - - try { - await Promise.all(createVenues); - } catch (error) { - console.log( - `Venues failed to be created.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - page = page + 1; - i = i + oldVenues.length; - console.log(i); - } while (i < totalOldVenues); - - console.timeEnd('createVenues'); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { venueSchema } = require('../../models/venue'); + +const oldVenueSchema = require('./old-schemas/venue'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldVenue = oldDb.model('venues', oldVenueSchema); + + let totalOldVenues; + try { + totalOldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }).count(); + } catch (error) { + console.log('Old venues failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old venues: ${totalOldVenues}`); + + console.time('createVenues'); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldVenues; + try { + oldVenues = await OldVenue.find({ + lngLat: { $exists: true }, + place_id: { $exists: true, $ne: '' }, + types: { $ne: [] } + }) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old venues failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const Venue = db.model('Venue', venueSchema); + + const createVenues = []; + for (let oldVenue of oldVenues) { + const addressOne = oldVenue.addr1; + const addressTwo = oldVenue.addr2 ? ` ${oldVenue.addr2}` : ''; + const city = oldVenue.city ? `, ${oldVenue.city}` : ''; + const state = oldVenue.state ? `, ${oldVenue.state}` : ''; + const address = `${addressOne}${addressTwo}${city}${state}`; + + const bathroomScore = + oldVenue.bathroom >= 1 ? oldVenue.bathroom : undefined; + const entryScore = oldVenue.entry >= 1 ? oldVenue.entry : undefined; + + let longitude; + if (oldVenue.lngLat[1] >= -180 && oldVenue.lngLat[1] <= 180) { + longitude = oldVenue.lngLat[1]; + } + let latitude; + if (oldVenue.lngLat[0] >= -90 && oldVenue.lngLat[0] <= 90) { + latitude = oldVenue.lngLat[0]; + } else { + longitude = oldVenue.lngLat[0]; + latitude = oldVenue.lngLat[1]; + } + + const venueData = { + _id: oldVenue.id, + address: oldVenue.addr1 ? address : '', + allowsGuideDog: { yes: oldVenue.guidedog }, + bathroomReviews: oldVenue.b_reviews, + bathroomScore, + createdAt: oldVenue.created_at, + entryReviews: oldVenue.e_reviews, + entryScore, + hasParking: { yes: oldVenue.parking }, + hasRamp: { yes: oldVenue.ramp }, + hasSecondEntry: { yes: oldVenue.secondentrance }, + hasWellLit: { yes: oldVenue.welllit }, + isQuiet: { yes: oldVenue.quiet }, + isSpacious: { yes: oldVenue.spacious }, + location: { coordinates: [longitude, latitude] }, + name: oldVenue.name, + placeId: oldVenue.place_id, + reviews: oldVenue.reviewdata, + steps: { + zero: oldVenue.steps_0, + one: oldVenue.steps_1, + two: oldVenue.steps_2, + moreThanTwo: oldVenue.steps_3 + }, + types: oldVenue.types, + updatedAt: oldVenue.updated_at + }; + + createVenues.push(Venue.create(venueData)); + } + + try { + await Promise.all(createVenues); + } catch (error) { + console.log( + `Venues failed to be created.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + page = page + 1; + i = i + oldVenues.length; + console.log(i); + } while (i < totalOldVenues); + + console.timeEnd('createVenues'); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/old-schemas/event.js b/src/scripts/db/old-schemas/event.js index cd99ce5..370e451 100644 --- a/src/scripts/db/old-schemas/event.js +++ b/src/scripts/db/old-schemas/event.js @@ -1,83 +1,83 @@ -const mongoose = require('mongoose'); - -const Schema = mongoose.Schema; -const ObjectId = Schema.ObjectId; - -const schema = new Schema({ - name: { - type: String, - required: true - }, - description: { - type: String, - required: true - }, - creator: { - type: ObjectId, - ref: 'users', - required: true - }, - approved: { - type: Boolean, - default: true - }, - event_start: { - type: Date, - required: true - }, - event_end: { - type: Date, - required: true - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - location: { - type: ObjectId, - ref: 'venues' - }, - goal: Number, - mapping_goal: Number, - participant_goal: Number, - participant_limit: Number, - type: String, - image: { - type: String, - default: '/images/icon_pin_mapathon_water.png' - }, - company: { - name: String, - address: String - }, - charity: { - name: String, - email: String, - website: String - }, - teams: [ - { - type: ObjectId, - ref: 'teams' - } - ], - members: [ - { - _id: false, - user: { - type: ObjectId, - ref: 'users' - }, - team: { - type: ObjectId, - ref: 'teams' - } - } - ] -}); - -module.exports = schema; +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; +const ObjectId = Schema.ObjectId; + +const schema = new Schema({ + name: { + type: String, + required: true + }, + description: { + type: String, + required: true + }, + creator: { + type: ObjectId, + ref: 'users', + required: true + }, + approved: { + type: Boolean, + default: true + }, + event_start: { + type: Date, + required: true + }, + event_end: { + type: Date, + required: true + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + location: { + type: ObjectId, + ref: 'venues' + }, + goal: Number, + mapping_goal: Number, + participant_goal: Number, + participant_limit: Number, + type: String, + image: { + type: String, + default: '/images/icon_pin_mapathon_water.png' + }, + company: { + name: String, + address: String + }, + charity: { + name: String, + email: String, + website: String + }, + teams: [ + { + type: ObjectId, + ref: 'teams' + } + ], + members: [ + { + _id: false, + user: { + type: ObjectId, + ref: 'users' + }, + team: { + type: ObjectId, + ref: 'teams' + } + } + ] +}); + +module.exports = schema; diff --git a/src/scripts/db/old-schemas/photo.js b/src/scripts/db/old-schemas/photo.js index d6cf920..e416234 100644 --- a/src/scripts/db/old-schemas/photo.js +++ b/src/scripts/db/old-schemas/photo.js @@ -1,37 +1,37 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - review_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'reviews' - }, - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - s3_id: String, - url: String, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + review_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'reviews' + }, + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + s3_id: String, + url: String, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/review.js b/src/scripts/db/old-schemas/review.js index 23ba9a9..2e9e45a 100644 --- a/src/scripts/db/old-schemas/review.js +++ b/src/scripts/db/old-schemas/review.js @@ -1,81 +1,81 @@ -const mongoose = require('mongoose'); - -const reviewSchema = new mongoose.Schema({ - venue_id: { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'venues' - }, - user_id: { - type: mongoose.Schema.ObjectId, - index: true - }, - team: { - type: mongoose.Schema.ObjectId, - ref: 'teams' - }, - event: { - type: mongoose.Schema.ObjectId, - ref: 'events' - }, - entry: Number, - bathroom: Number, - spacious: { - type: Boolean, - default: false - }, - quiet: { - type: Boolean, - default: false - }, - parking: { - type: Boolean, - default: false - }, - ramp: { - type: Boolean, - default: false - }, - secondentrance: { - type: Boolean, - default: false - }, - guidedog: { - type: Boolean, - default: false - }, - welllit: { - type: Boolean, - default: false - }, - comment: String, - username: String, - abuse: Number, - flag: Number, - flaggers: [ - { - type: mongoose.Schema.ObjectId, - index: true - } - ], - deleted: Boolean, - steps: Number, - votes: Number, - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - } -}); - -module.exports = reviewSchema; +const mongoose = require('mongoose'); + +const reviewSchema = new mongoose.Schema({ + venue_id: { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'venues' + }, + user_id: { + type: mongoose.Schema.ObjectId, + index: true + }, + team: { + type: mongoose.Schema.ObjectId, + ref: 'teams' + }, + event: { + type: mongoose.Schema.ObjectId, + ref: 'events' + }, + entry: Number, + bathroom: Number, + spacious: { + type: Boolean, + default: false + }, + quiet: { + type: Boolean, + default: false + }, + parking: { + type: Boolean, + default: false + }, + ramp: { + type: Boolean, + default: false + }, + secondentrance: { + type: Boolean, + default: false + }, + guidedog: { + type: Boolean, + default: false + }, + welllit: { + type: Boolean, + default: false + }, + comment: String, + username: String, + abuse: Number, + flag: Number, + flaggers: [ + { + type: mongoose.Schema.ObjectId, + index: true + } + ], + deleted: Boolean, + steps: Number, + votes: Number, + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + } +}); + +module.exports = reviewSchema; diff --git a/src/scripts/db/old-schemas/team.js b/src/scripts/db/old-schemas/team.js index be70c88..85581c3 100644 --- a/src/scripts/db/old-schemas/team.js +++ b/src/scripts/db/old-schemas/team.js @@ -1,49 +1,49 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - name: String, - goal: Number, - corporation: String, - description: String, - password: String, - image: { - type: String, - default: '/images/icon_team.png' - }, - creator: { - type: mongoose.Schema.ObjectId, - ref: 'users' - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - updated_at: { - type: Date, - default: Date.now - }, - created_at: { - type: Date, - default: Date.now - }, - members: [ - { - type: mongoose.Schema.ObjectId, - ref: 'users' - } - ], - invites: [ - { - type: mongoose.Schema.ObjectId, - ref: 'invites' - } - ], - approved: { - type: Boolean, - default: true - } -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + name: String, + goal: Number, + corporation: String, + description: String, + password: String, + image: { + type: String, + default: '/images/icon_team.png' + }, + creator: { + type: mongoose.Schema.ObjectId, + ref: 'users' + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + updated_at: { + type: Date, + default: Date.now + }, + created_at: { + type: Date, + default: Date.now + }, + members: [ + { + type: mongoose.Schema.ObjectId, + ref: 'users' + } + ], + invites: [ + { + type: mongoose.Schema.ObjectId, + ref: 'invites' + } + ], + approved: { + type: Boolean, + default: true + } +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/old-schemas/user.js b/src/scripts/db/old-schemas/user.js index 311e828..46664c3 100644 --- a/src/scripts/db/old-schemas/user.js +++ b/src/scripts/db/old-schemas/user.js @@ -1,125 +1,125 @@ -const mongoose = require('mongoose'); - -const userSchema = new mongoose.Schema({ - schema_version: Number, - name: { - first: { - type: String, - required: true - }, - last: { - type: String, - required: true - } - }, - fullName: String, - type: String, - description: String, - showEmail: { - type: Boolean, - default: true - }, - showPhone: { - type: Boolean, - default: true - }, - image: { - type: String, - default: '/images/icon_guy.png' - }, - company: { - name: String, - address: String - }, - email: { - type: String, - unique: true, - required: true - }, - phone: { - type: String - }, - location: { - type: String - }, - zip: { - type: String - }, - gender: { - type: String, - default: '' - }, - disabilitytype: { - type: String, - default: '' - }, - newsletter: { - type: Boolean, - default: true - }, - isactive: { - type: Boolean, - default: false - }, - isadmin: { - type: Boolean, - default: false - }, - salt: { - type: String - }, - hash: { - type: String - }, - token: { - type: String, - default: false - }, - activatedAt: { - type: Date - }, - createdAt: { - type: Date, - default: Date.now - }, - updatedAt: { - type: Date, - default: Date.now - }, - events: [ - { - type: mongoose.Schema.ObjectId, - ref: 'events' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ], - teams: [ - { - type: mongoose.Schema.ObjectId, - ref: 'teams' - } - ], - reset: { - createdAt: Date, - link: mongoose.Schema.ObjectId - }, - foursquareId: String, - facebookAuth: String, - foursquareVerified: { - type: Boolean, - default: false - }, - facebookVerified: { - type: Boolean, - default: false - }, - username: String -}); - -module.exports = userSchema; +const mongoose = require('mongoose'); + +const userSchema = new mongoose.Schema({ + schema_version: Number, + name: { + first: { + type: String, + required: true + }, + last: { + type: String, + required: true + } + }, + fullName: String, + type: String, + description: String, + showEmail: { + type: Boolean, + default: true + }, + showPhone: { + type: Boolean, + default: true + }, + image: { + type: String, + default: '/images/icon_guy.png' + }, + company: { + name: String, + address: String + }, + email: { + type: String, + unique: true, + required: true + }, + phone: { + type: String + }, + location: { + type: String + }, + zip: { + type: String + }, + gender: { + type: String, + default: '' + }, + disabilitytype: { + type: String, + default: '' + }, + newsletter: { + type: Boolean, + default: true + }, + isactive: { + type: Boolean, + default: false + }, + isadmin: { + type: Boolean, + default: false + }, + salt: { + type: String + }, + hash: { + type: String + }, + token: { + type: String, + default: false + }, + activatedAt: { + type: Date + }, + createdAt: { + type: Date, + default: Date.now + }, + updatedAt: { + type: Date, + default: Date.now + }, + events: [ + { + type: mongoose.Schema.ObjectId, + ref: 'events' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ], + teams: [ + { + type: mongoose.Schema.ObjectId, + ref: 'teams' + } + ], + reset: { + createdAt: Date, + link: mongoose.Schema.ObjectId + }, + foursquareId: String, + facebookAuth: String, + foursquareVerified: { + type: Boolean, + default: false + }, + facebookVerified: { + type: Boolean, + default: false + }, + username: String +}); + +module.exports = userSchema; diff --git a/src/scripts/db/old-schemas/venue.js b/src/scripts/db/old-schemas/venue.js index 490278f..fe44826 100644 --- a/src/scripts/db/old-schemas/venue.js +++ b/src/scripts/db/old-schemas/venue.js @@ -1,119 +1,119 @@ -const mongoose = require('mongoose'); - -const venueSchema = new mongoose.Schema({ - schema_version: Number, - google_id: { - type: String, - index: true - }, - google_ref: String, - place_id: { - type: String, - index: true - }, - name: String, - addr1: String, - addr2: String, - city: String, - state: String, - ph: String, - url: String, - types: Array, - ll: Array, - lngLat: { - type: Array, - index: '2d' - }, - google_rating: { - type: Number, - default: 0 - }, - google_url: String, - entry: { - type: Number, - default: 0 - }, - e_reviews: { - type: Number, - default: 0 - }, - bathroom: { - type: Number, - default: 0 - }, - b_reviews: { - type: Number, - default: 0 - }, - welllit: { - type: Number, - default: 0 - }, - spacious: { - type: Number, - default: 0 - }, - quiet: { - type: Number, - default: 0 - }, - parking: { - type: Number, - default: 0 - }, - ramp: { - type: Number, - default: 0 - }, - secondentrance: { - type: Number, - default: 0 - }, - guidedog: { - type: Number, - default: 0 - }, - steps: { - type: Number, - default: -1 - }, - steps_0: { - type: Number, - default: 0 - }, - steps_1: { - type: Number, - default: 0 - }, - steps_2: { - type: Number, - default: 0 - }, - steps_3: { - type: Number, - default: 0 - }, - created_at: { - type: Date, - default: Date.now - }, - updated_at: { - type: Date, - default: Date.now - }, - reviewdata: [ - { - type: mongoose.Schema.ObjectId, - ref: 'reviews' - } - ], - images: [ - { - type: mongoose.Schema.ObjectId, - index: true, - ref: 'photos' - } - ] -}); - -module.exports = venueSchema; +const mongoose = require('mongoose'); + +const venueSchema = new mongoose.Schema({ + schema_version: Number, + google_id: { + type: String, + index: true + }, + google_ref: String, + place_id: { + type: String, + index: true + }, + name: String, + addr1: String, + addr2: String, + city: String, + state: String, + ph: String, + url: String, + types: Array, + ll: Array, + lngLat: { + type: Array, + index: '2d' + }, + google_rating: { + type: Number, + default: 0 + }, + google_url: String, + entry: { + type: Number, + default: 0 + }, + e_reviews: { + type: Number, + default: 0 + }, + bathroom: { + type: Number, + default: 0 + }, + b_reviews: { + type: Number, + default: 0 + }, + welllit: { + type: Number, + default: 0 + }, + spacious: { + type: Number, + default: 0 + }, + quiet: { + type: Number, + default: 0 + }, + parking: { + type: Number, + default: 0 + }, + ramp: { + type: Number, + default: 0 + }, + secondentrance: { + type: Number, + default: 0 + }, + guidedog: { + type: Number, + default: 0 + }, + steps: { + type: Number, + default: -1 + }, + steps_0: { + type: Number, + default: 0 + }, + steps_1: { + type: Number, + default: 0 + }, + steps_2: { + type: Number, + default: 0 + }, + steps_3: { + type: Number, + default: 0 + }, + created_at: { + type: Date, + default: Date.now + }, + updated_at: { + type: Date, + default: Date.now + }, + reviewdata: [ + { + type: mongoose.Schema.ObjectId, + ref: 'reviews' + } + ], + images: [ + { + type: mongoose.Schema.ObjectId, + index: true, + ref: 'photos' + } + ] +}); + +module.exports = venueSchema; diff --git a/src/scripts/db/update-events-locations.js b/src/scripts/db/update-events-locations.js index 57ff40b..f5e2455 100644 --- a/src/scripts/db/update-events-locations.js +++ b/src/scripts/db/update-events-locations.js @@ -1,150 +1,150 @@ -const axios = require('axios'); -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { venueSchema } = require('../../models/venue'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Venue = db.model('Venue', venueSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Events failed to be found'); - console.log(error); - await closeConnections(db); - } - - console.log(`${events.length} events found`); - - const getVenues = events.map(e => Venue.findOne({ _id: e.venue })); - let venues; - try { - venues = await Promise.all(getVenues); - } catch (err) { - console.log('Venues failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${venues.length} venues found`); - - const getPlaces = venues.map(v => { - if (v) { - return axios.get( - `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ - v.placeId - }&key=${process.env.PLACES_API_KEY}` - ); - } - }); - let places; - try { - places = await Promise.all(getPlaces); - } catch (err) { - console.log('Places failed to be found'); - console.log(err); - await closeConnections(db); - } - - console.log(`${places.length} places found`); - - const updateEvents = []; - const removeEvents = []; - places.map((p, i) => { - if ((p && p.data && p.data.result) || venues[i]) { - const place = p && p.data && p.data.result ? p.data.result : undefined; - const event = events[i]; - event.address = place ? place.formatted_address : venues[i].address; - event.location.coordinates = place - ? [place.geometry.location.lng, place.geometry.location.lat] - : venues[i].location.coordinates; - updateEvents.push(event.save()); - } else { - const event = events[i]; - removeEvents.push(event.remove()); - } - }); - try { - await Promise.all([...updateEvents, ...removeEvents]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - console.log('Events updated'); - - page = page + 1; - i = i + events.length; - console.log(i); - - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const axios = require("axios"); +const mongoose = require("mongoose"); + +require("dotenv").config(); + +const { eventSchema } = require("../../models/event"); +const { venueSchema } = require("../../models/venue"); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000, +}; +const db = mongoose.createConnection(uri, options); + +db.on("connected", async () => { + console.log("Connection to DB established successfully"); + + const Event = db.model("Event", eventSchema); + const Venue = db.model("Venue", venueSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log("Events failed to be count"); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log("Events failed to be found"); + console.log(error); + await closeConnections(db); + } + + console.log(`${events.length} events found`); + + const getVenues = events.map((e) => Venue.findOne({ _id: e.venue })); + let venues; + try { + venues = await Promise.all(getVenues); + } catch (err) { + console.log("Venues failed to be found"); + console.log(err); + await closeConnections(db); + } + + console.log(`${venues.length} venues found`); + + const getPlaces = venues.map((v) => { + if (v) { + return axios.get( + `https://maps.googleapis.com/maps/api/place/details/json?placeid=${ + v.placeId + }&key=${process.env.PLACES_API_KEY}` + ); + } + }); + let places; + try { + places = await Promise.all(getPlaces); + } catch (err) { + console.log("Places failed to be found"); + console.log(err); + await closeConnections(db); + } + + console.log(`${places.length} places found`); + + const updateEvents = []; + const removeEvents = []; + places.map((p, i) => { + if ((p && p.data && p.data.result) || venues[i]) { + const place = p && p.data && p.data.result ? p.data.result : undefined; + const event = events[i]; + event.address = place ? place.formatted_address : venues[i].address; + event.location.coordinates = place + ? [place.geometry.location.lng, place.geometry.location.lat] + : venues[i].location.coordinates; + updateEvents.push(event.save()); + } else { + const event = events[i]; + removeEvents.push(Event.deleteOne({ _id: event?._id })); + } + }); + try { + await Promise.all([...updateEvents, ...removeEvents]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i, + })}` + ); + console.log(err); + await closeConnections(db); + } + + console.log("Events updated"); + + page = page + 1; + i = i + events.length; + console.log(i); + + try { + totalEvents = await Event.count(); + } catch (error) { + console.log("Events failed to be count"); + console.log(error); + await closeConnections(db); + } + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on("error", (err) => { + console.log("Connection to DB failed " + err); + process.exit(0); +}); + +db.on("disconnected", () => { + console.log("Connection from DB closed"); +}); diff --git a/src/scripts/db/update-events-posters.js b/src/scripts/db/update-events-posters.js index 8159465..03c2df0 100644 --- a/src/scripts/db/update-events-posters.js +++ b/src/scripts/db/update-events-posters.js @@ -1,160 +1,160 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); - -mongoose.Promise = global.Promise; - -const s3 = new aws.S3(); - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - const uploadEventsPosters = []; - for (let event of events) { - if (event.poster && !event.poster.includes('icon_guy')) { - let posterImage; - try { - posterImage = await jimp.read(encodeURI(event.poster)); - } catch (err) { - console.log('Event poster image failed to be read'); - console.log(err); - await closeConnections(db); - } - - if (posterImage) { - const posterExtension = posterImage.getExtension(); - const posterFileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${posterExtension}`; - - if ( - posterExtension === 'png' || - posterExtension === 'jpeg' || - posterExtension === 'jpg' || - posterExtension === 'bmp' - ) { - const posterMIME = posterImage.getMIME(); - if (posterMIME) { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/${posterFileName}`; - posterImage - .cover(400, 400) - .quality(85) - .getBuffer(posterMIME, async (err, posterBuffer) => { - if (err) { - console.log('Event poster buffer failed to be read'); - console.log(err); - await closeConnections(db); - } - - uploadEventsPosters.push( - s3 - .putObject({ - ACL: 'public-read', - Body: posterBuffer, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: posterImage.getMIME(), - Key: `events/posters/${posterFileName}` - }) - .promise() - ); - }); - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - } - } - } else { - event.poster = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/events/posters/default.png`; - } - updateEvents.push(event.save()); - } - - try { - await Promise.all([...updateEvents, ...uploadEventsPosters]); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); + +mongoose.Promise = global.Promise; + +const s3 = new aws.S3(); + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + const uploadEventsPosters = []; + for (let event of events) { + if (event.poster && !event.poster.includes('icon_guy')) { + let posterImage; + try { + posterImage = await jimp.read(encodeURI(event.poster)); + } catch (err) { + console.log('Event poster image failed to be read'); + console.log(err); + await closeConnections(db); + } + + if (posterImage) { + const posterExtension = posterImage.getExtension(); + const posterFileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${posterExtension}`; + + if ( + posterExtension === 'png' || + posterExtension === 'jpeg' || + posterExtension === 'jpg' || + posterExtension === 'bmp' + ) { + const posterMIME = posterImage.getMIME(); + if (posterMIME) { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/${posterFileName}`; + posterImage + .cover(400, 400) + .quality(85) + .getBuffer(posterMIME, async (err, posterBuffer) => { + if (err) { + console.log('Event poster buffer failed to be read'); + console.log(err); + await closeConnections(db); + } + + uploadEventsPosters.push( + s3 + .putObject({ + ACL: 'public-read', + Body: posterBuffer, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: posterImage.getMIME(), + Key: `events/posters/${posterFileName}` + }) + .promise() + ); + }); + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + } + } + } else { + event.poster = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/events/posters/default.png`; + } + updateEvents.push(event.save()); + } + + try { + await Promise.all([...updateEvents, ...uploadEventsPosters]); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-events-reviews.js b/src/scripts/db/update-events-reviews.js index b2e2afe..bf9950e 100644 --- a/src/scripts/db/update-events-reviews.js +++ b/src/scripts/db/update-events-reviews.js @@ -1,104 +1,104 @@ -const mongoose = require('mongoose'); - -require('dotenv').config(); - -const { eventSchema } = require('../../models/event'); -const { reviewSchema } = require('../../models/review'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db) { - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const Event = db.model('Event', eventSchema); - const Review = db.model('Review', reviewSchema); - - let totalEvents; - try { - totalEvents = await Event.count(); - } catch (error) { - console.log('Events failed to be count'); - console.log(error); - await closeConnections(db); - } - - console.log(`Total events: ${totalEvents}`); - - let i = 0; - let page = 0; - const pageLimit = 100; - do { - let events; - try { - events = await Event.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Teams failed to be found'); - console.log(error); - await closeConnections(db); - } - - const updateEvents = []; - for (let event of events) { - let eventReviews; - try { - eventReviews = await Review.find({ event: event.id }).count(); - } catch (err) { - console.log('Event reviews failed to be count'); - console.log(err); - await closeConnections(db); - } - - event.reviewsAmount = eventReviews; - updateEvents.push(event.save()); - } - - try { - await Promise.all(updateEvents); - } catch (err) { - console.log( - `Events failed to be updated.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(err); - await closeConnections(db); - } - - page = page + 1; - i = i + events.length; - console.log(i); - } while (i < totalEvents); - - await closeConnections(db); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); +const mongoose = require('mongoose'); + +require('dotenv').config(); + +const { eventSchema } = require('../../models/event'); +const { reviewSchema } = require('../../models/review'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db) { + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const Event = db.model('Event', eventSchema); + const Review = db.model('Review', reviewSchema); + + let totalEvents; + try { + totalEvents = await Event.count(); + } catch (error) { + console.log('Events failed to be count'); + console.log(error); + await closeConnections(db); + } + + console.log(`Total events: ${totalEvents}`); + + let i = 0; + let page = 0; + const pageLimit = 100; + do { + let events; + try { + events = await Event.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Teams failed to be found'); + console.log(error); + await closeConnections(db); + } + + const updateEvents = []; + for (let event of events) { + let eventReviews; + try { + eventReviews = await Review.find({ event: event.id }).count(); + } catch (err) { + console.log('Event reviews failed to be count'); + console.log(err); + await closeConnections(db); + } + + event.reviewsAmount = eventReviews; + updateEvents.push(event.save()); + } + + try { + await Promise.all(updateEvents); + } catch (err) { + console.log( + `Events failed to be updated.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(err); + await closeConnections(db); + } + + page = page + 1; + i = i + events.length; + console.log(i); + } while (i < totalEvents); + + await closeConnections(db); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); diff --git a/src/scripts/db/update-users-avatars.js b/src/scripts/db/update-users-avatars.js index 59e21c5..5df6f61 100644 --- a/src/scripts/db/update-users-avatars.js +++ b/src/scripts/db/update-users-avatars.js @@ -1,206 +1,206 @@ -const aws = require('aws-sdk'); -const jimp = require('jimp'); -const mongoose = require('mongoose'); -const randomstring = require('randomstring'); - -require('dotenv').config(); - -const { userSchema } = require('../../models/user'); - -const oldUserSchema = require('./old-schemas/user'); - -mongoose.Promise = global.Promise; - -async function closeConnections(db, oldDb) { - try { - await oldDb.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - try { - await db.close(); - } catch (error) { - console.log(error); - process.exit(0); - } - - process.exit(0); -} - -const uri = process.env.MONGODB_URI; -const options = { - useMongoClient: true, - socketTimeoutMS: 0, - keepAlive: 2000 -}; -const db = mongoose.createConnection(uri, options); - -db.on('connected', async () => { - console.log('Connection to DB established successfully'); - - const oldUri = process.env.OLD_DB_URI; - const oldDb = mongoose.createConnection(oldUri, options); - - oldDb.on('connected', async () => { - console.log('Connection to old DB established successfully'); - - const OldUser = oldDb.model('users', oldUserSchema); - - let totalOldUsers; - try { - totalOldUsers = await OldUser.count(); - } catch (error) { - console.log('Old users failed to be count'); - console.log(error); - await closeConnections(db, oldDb); - } - - console.log(`Total old users: ${totalOldUsers}`); - - let page = 0; - const pageLimit = 100; - let i = 0; - do { - let oldUsers; - try { - oldUsers = await OldUser.find({}) - .skip(page * pageLimit) - .limit(pageLimit); - } catch (error) { - console.log('Old users failed to be found'); - console.log(error); - await closeConnections(db, oldDb); - } - - const User = db.model('User', userSchema); - - const getUsersImages = []; - const usersToUpdate = []; - for (let oldUser of oldUsers) { - if (oldUser.isactive) { - if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { - getUsersImages.push(jimp.read(encodeURI(oldUser.image))); - usersToUpdate.push(oldUser.id); - } - } - } - - if (getUsersImages.length > 0) { - let usersImages; - try { - usersImages = await Promise.all(getUsersImages); - } catch (error) { - console.log( - `Old users images failed to be found.\nData: ${JSON.stringify({ - page, - i - })}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - - const usersAvatars = []; - for (let i = 0; i < usersImages.length; i++) { - usersImages[i].cover(400, 400).quality(60); - usersImages[i].getBuffer( - usersImages[i].getMIME(), - (error, bufferImage) => { - if (error) { - console.log(error); - } - - const extension = usersImages[i].getExtension(); - if ( - extension === 'png' || - extension === 'jpeg' || - extension === 'jpg' || - extension === 'bmp' - ) { - usersAvatars.push({ - body: bufferImage, - extension: extension, - mime: usersImages[i].getMIME(), - userId: usersToUpdate[i] - }); - } - } - ); - } - - const s3 = new aws.S3(); - const uploadUsersAvatars = []; - const updateUsersAvatars = []; - for (let userAvatar of usersAvatars) { - let fileName = `${Date.now()}${randomstring.generate({ - length: 5, - capitalization: 'lowercase' - })}.${userAvatar.extension}`; - - uploadUsersAvatars.push( - s3 - .putObject({ - ACL: 'public-read', - Body: userAvatar.body, - Bucket: process.env.AWS_S3_BUCKET, - ContentType: userAvatar.mime, - Key: `users/avatars/${fileName}` - }) - .promise() - ); - - let avatar = `https://s3.amazonaws.com/${ - process.env.AWS_S3_BUCKET - }/users/avatars/${fileName}`; - - updateUsersAvatars.push( - User.update({ _id: userAvatar.userId }, { $set: { avatar } }) - ); - } - - try { - await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); - } catch (error) { - console.log( - `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( - { - page, - i - } - )}` - ); - console.log(error); - await closeConnections(db, oldDb); - } - } - - page = page + 1; - i = i + oldUsers.length; - console.log(i); - } while (i < totalOldUsers); - - await closeConnections(db, oldDb); - }); - - oldDb.on('error', err => { - console.log('Connection to old DB failed ' + err); - process.exit(0); - }); - - oldDb.on('disconnected', () => { - console.log('Connection from old DB closed'); - }); -}); - -db.on('error', err => { - console.log('Connection to DB failed ' + err); - process.exit(0); -}); - -db.on('disconnected', () => { - console.log('Connection from DB closed'); -}); - -process.on('SIGINT', () => db.close()); +const aws = require('aws-sdk'); +const jimp = require('jimp'); +const mongoose = require('mongoose'); +const randomstring = require('randomstring'); + +require('dotenv').config(); + +const { userSchema } = require('../../models/user'); + +const oldUserSchema = require('./old-schemas/user'); + +mongoose.Promise = global.Promise; + +async function closeConnections(db, oldDb) { + try { + await oldDb.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + try { + await db.close(); + } catch (error) { + console.log(error); + process.exit(0); + } + + process.exit(0); +} + +const uri = process.env.MONGODB_URI; +const options = { + useMongoClient: true, + socketTimeoutMS: 0, + keepAlive: 2000 +}; +const db = mongoose.createConnection(uri, options); + +db.on('connected', async () => { + console.log('Connection to DB established successfully'); + + const oldUri = process.env.OLD_DB_URI; + const oldDb = mongoose.createConnection(oldUri, options); + + oldDb.on('connected', async () => { + console.log('Connection to old DB established successfully'); + + const OldUser = oldDb.model('users', oldUserSchema); + + let totalOldUsers; + try { + totalOldUsers = await OldUser.count(); + } catch (error) { + console.log('Old users failed to be count'); + console.log(error); + await closeConnections(db, oldDb); + } + + console.log(`Total old users: ${totalOldUsers}`); + + let page = 0; + const pageLimit = 100; + let i = 0; + do { + let oldUsers; + try { + oldUsers = await OldUser.find({}) + .skip(page * pageLimit) + .limit(pageLimit); + } catch (error) { + console.log('Old users failed to be found'); + console.log(error); + await closeConnections(db, oldDb); + } + + const User = db.model('User', userSchema); + + const getUsersImages = []; + const usersToUpdate = []; + for (let oldUser of oldUsers) { + if (oldUser.isactive) { + if (oldUser.image && !oldUser.image.includes('icon_guy.png')) { + getUsersImages.push(jimp.read(encodeURI(oldUser.image))); + usersToUpdate.push(oldUser.id); + } + } + } + + if (getUsersImages.length > 0) { + let usersImages; + try { + usersImages = await Promise.all(getUsersImages); + } catch (error) { + console.log( + `Old users images failed to be found.\nData: ${JSON.stringify({ + page, + i + })}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + + const usersAvatars = []; + for (let i = 0; i < usersImages.length; i++) { + usersImages[i].cover(400, 400).quality(60); + usersImages[i].getBuffer( + usersImages[i].getMIME(), + (error, bufferImage) => { + if (error) { + console.log(error); + } + + const extension = usersImages[i].getExtension(); + if ( + extension === 'png' || + extension === 'jpeg' || + extension === 'jpg' || + extension === 'bmp' + ) { + usersAvatars.push({ + body: bufferImage, + extension: extension, + mime: usersImages[i].getMIME(), + userId: usersToUpdate[i] + }); + } + } + ); + } + + const s3 = new aws.S3(); + const uploadUsersAvatars = []; + const updateUsersAvatars = []; + for (let userAvatar of usersAvatars) { + let fileName = `${Date.now()}${randomstring.generate({ + length: 5, + capitalization: 'lowercase' + })}.${userAvatar.extension}`; + + uploadUsersAvatars.push( + s3 + .putObject({ + ACL: 'public-read', + Body: userAvatar.body, + Bucket: process.env.AWS_S3_BUCKET, + ContentType: userAvatar.mime, + Key: `users/avatars/${fileName}` + }) + .promise() + ); + + let avatar = `https://s3.amazonaws.com/${ + process.env.AWS_S3_BUCKET + }/users/avatars/${fileName}`; + + updateUsersAvatars.push( + User.update({ _id: userAvatar.userId }, { $set: { avatar } }) + ); + } + + try { + await Promise.all([...uploadUsersAvatars, ...updateUsersAvatars]); + } catch (error) { + console.log( + `Users images failed to be uploaded or updated.\nData: ${JSON.stringify( + { + page, + i + } + )}` + ); + console.log(error); + await closeConnections(db, oldDb); + } + } + + page = page + 1; + i = i + oldUsers.length; + console.log(i); + } while (i < totalOldUsers); + + await closeConnections(db, oldDb); + }); + + oldDb.on('error', (err) => { + console.log('Connection to old DB failed ' + err); + process.exit(0); + }); + + oldDb.on('disconnected', () => { + console.log('Connection from old DB closed'); + }); +}); + +db.on('error', (err) => { + console.log('Connection to DB failed ' + err); + process.exit(0); +}); + +db.on('disconnected', () => { + console.log('Connection from DB closed'); +}); + +process.on('SIGINT', () => db.close());