From 86faf09175ca7bec972faec1ae97cf38903d958a Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:34:13 +0400 Subject: [PATCH 01/17] chore: use global snapshot code formatting standard --- .eslintrc | 24 - .github/workflows/build.yml | 20 +- .gitignore | 1 - .prettierrc | 8 - package.json | 14 +- src/discord.ts | 20 +- src/helpers/utils.ts | 4 +- yarn.lock | 1053 ++++++++++++++++++----------------- 8 files changed, 573 insertions(+), 571 deletions(-) delete mode 100644 .eslintrc delete mode 100644 .prettierrc diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index cf1936c..0000000 --- a/.eslintrc +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": [ - "plugin:@typescript-eslint/recommended" - ], - "plugins": [ - "prettier", - "@typescript-eslint" - ], - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - "no-console": "off", - "prettier/prettier": "error", - "prefer-template": "error", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/ban-ts-ignore": "off", - "@typescript-eslint/camelcase": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/interface-name-prefix": "off" - } -} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cbe485b..20f9bf2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,13 +11,13 @@ jobs: node-version: [16.10.x] steps: - - uses: actions/checkout@v2.3.4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: yarn install, build and lint - run: | - yarn install --frozen-lockfile - yarn build - yarn lint + - uses: actions/checkout@v2.3.4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: yarn install, build and lint + run: | + yarn install --frozen-lockfile + yarn build + yarn lint diff --git a/.gitignore b/.gitignore index 76046a2..4fc37dc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ dist build .env - # Remove some common IDE working directories .idea .vscode diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 73df3c5..0000000 --- a/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "semi": true, - "singleQuote": true, - "printWidth": 100, - "tabWidth": 2, - "trailingComma": "none", - "arrowParens": "avoid" -} diff --git a/package.json b/package.json index a991ed8..58c0e89 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,15 @@ "license": "MIT", "scripts": { "lint": "eslint . --ext .ts --fix", + "typecheck": "tsc --noEmit", "build": "tsc", "dev": "nodemon src/index.ts", "start": "node dist/src/index.js" }, + "eslintConfig": { + "extends": "@snapshot-labs" + }, + "prettier": "@snapshot-labs/prettier-config", "dependencies": { "@pusher/push-notifications-server": "^1.2.5", "@snapshot-labs/snapshot.js": "^0.3.68", @@ -17,7 +22,6 @@ "cors": "^2.8.5", "discord.js": "^14.3.0", "dotenv": "^10.0.0", - "eslint": "^6.7.2", "express": "^4.17.1", "lodash.chunk": "^4.2.0", "mysql": "^2.18.1", @@ -27,11 +31,11 @@ "typescript": "^4.8.3" }, "devDependencies": { + "@snapshot-labs/eslint-config": "^0.1.0-beta.9", + "@snapshot-labs/prettier-config": "^0.1.0-beta.7", "@types/express": "^4.17.11", "@types/node": "^17.0.23", - "@typescript-eslint/eslint-plugin": "^2.33.0", - "@typescript-eslint/parser": "^2.33.0", - "eslint-plugin-prettier": "^3.1.3", - "prettier": "^1.19.1" + "eslint": "^8.28.0", + "prettier": "^2.8.0" } } diff --git a/src/discord.ts b/src/discord.ts index 45a2d79..6db2d49 100644 --- a/src/discord.ts +++ b/src/discord.ts @@ -69,16 +69,10 @@ const commands = [ .setDMPermission(false) .setDefaultMemberPermissions(0) .addChannelOption(option => - option - .setName('channel') - .setDescription('Channel to post the events') - .setRequired(true) + option.setName('channel').setDescription('Channel to post the events').setRequired(true) ) .addStringOption(option => - option - .setName('space') - .setDescription('space to subscribe to') - .setRequired(true) + option.setName('space').setDescription('space to subscribe to').setRequired(true) ) .addStringOption(option => option.setName('mention').setDescription('Mention role')), new SlashCommandBuilder() @@ -87,16 +81,10 @@ const commands = [ .setDMPermission(false) .setDefaultMemberPermissions(0) .addChannelOption(option => - option - .setName('channel') - .setDescription('Channel to post the events') - .setRequired(true) + option.setName('channel').setDescription('Channel to post the events').setRequired(true) ) .addStringOption(option => - option - .setName('space') - .setDescription('space to subscribe to') - .setRequired(true) + option.setName('space').setDescription('space to subscribe to').setRequired(true) ) ]; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 84ae4bc..0796831 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -5,7 +5,5 @@ export function shortenAddress(str = '') { } export function sha256(str) { - return createHash('sha256') - .update(str) - .digest('hex'); + return createHash('sha256').update(str).digest('hex'); } diff --git a/yarn.lock b/yarn.lock index e83c55a..be47d7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,27 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" - integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== - dependencies: - "@babel/highlight" "^7.14.5" - -"@babel/helper-validator-identifier@^7.14.5": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== - -"@babel/highlight@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -64,6 +43,38 @@ resolved "https://registry.yarnpkg.com/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz#5e5f2f24ba802aff8bc19edd822c9a11200cdf4a" integrity sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw== +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" + integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== + +"@eslint/eslintrc@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" + integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.1" + globals "^13.19.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" + +"@eslint/js@8.39.0": + version "8.39.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b" + integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng== + "@ethersproject/abi@^5.0.4", "@ethersproject/abi@^5.4.0": version "5.4.1" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.4.1.tgz#6ac28fafc9ef6f5a7a37e30356a2eb31fa05d39b" @@ -383,6 +394,25 @@ "@ethersproject/properties" "^5.4.0" "@ethersproject/strings" "^5.4.0" +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -401,6 +431,27 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@pusher/push-notifications-server@^1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@pusher/push-notifications-server/-/push-notifications-server-1.2.5.tgz#a7266941cb720b2bb32c19ed2b969c3686d54a60" @@ -431,6 +482,28 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@snapshot-labs/eslint-config-base@^0.1.0-beta.9": + version "0.1.0-beta.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/eslint-config-base/-/eslint-config-base-0.1.0-beta.9.tgz#88947ad7140ddb9efaa13d8fe7eb0568220e43ed" + integrity sha512-lfbOjFDbFV3Z2vM6fDFqq0YsrOX7LukjQnBUQwR+B0GJnxrdBdYN5iGjlhXibhwNnu77CKlwaa3eRyqZUj+idg== + dependencies: + "@typescript-eslint/eslint-plugin" "^5.44.0" + "@typescript-eslint/parser" "^5.44.0" + eslint-config-prettier "^8.5.0" + eslint-plugin-prettier "^4.2.1" + +"@snapshot-labs/eslint-config@^0.1.0-beta.9": + version "0.1.0-beta.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/eslint-config/-/eslint-config-0.1.0-beta.9.tgz#f3344cdb8cb69af522dcaba5c46180780aca22d5" + integrity sha512-AmxuCI3n6wdYDMrv5fzBnfRsKMmDSzIjdrQGBg38qkZbQoQU/78LsFp016ti0cMyGJIOEeudXZ7iavQqW3uZ/g== + dependencies: + "@snapshot-labs/eslint-config-base" "^0.1.0-beta.9" + +"@snapshot-labs/prettier-config@^0.1.0-beta.7": + version "0.1.0-beta.7" + resolved "https://registry.yarnpkg.com/@snapshot-labs/prettier-config/-/prettier-config-0.1.0-beta.7.tgz#c8e07e7e9baabee245020a72ac05835b65139823" + integrity sha512-k/FUf4VWhwLFUmKuWs2mNvmPe691hqhvCJuujD4TfbIivWysmL1TqthwfdQUrQEAQUqVQ2ZKEiGkbufp5J27eQ== + "@snapshot-labs/snapshot.js@^0.3.68": version "0.3.68" resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.3.68.tgz#bd0aa1edd4f7d7ef5f7107893f80afa058c1acc1" @@ -496,11 +569,6 @@ dependencies: "@types/node" "*" -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/express-serve-static-core@^4.17.18": version "4.17.24" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" @@ -520,10 +588,10 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/json-schema@^7.0.3": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/mime@^1": version "1.3.2" @@ -550,6 +618,11 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/serve-static@*": version "1.13.10" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" @@ -565,48 +638,89 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^2.33.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" - integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ== - dependencies: - "@typescript-eslint/experimental-utils" "2.34.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^2.33.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8" - integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.34.0" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" +"@typescript-eslint/eslint-plugin@^5.44.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.0.tgz#c0e10eeb936debe5d1c3433cf36206a95befefd0" + integrity sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/type-utils" "5.59.0" + "@typescript-eslint/utils" "5.59.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.44.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.0.tgz#0ad7cd019346cc5d150363f64869eca10ca9977c" + integrity sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w== + dependencies: + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/typescript-estree" "5.59.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.0.tgz#86501d7a17885710b6716a23be2e93fc54a4fe8c" + integrity sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ== + dependencies: + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/visitor-keys" "5.59.0" + +"@typescript-eslint/type-utils@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz#8e8d1420fc2265989fa3a0d897bde37f3851e8c9" + integrity sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.0" + "@typescript-eslint/utils" "5.59.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32" + integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA== + +"@typescript-eslint/typescript-estree@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz#8869156ee1dcfc5a95be3ed0e2809969ea28e965" + integrity sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg== + dependencies: + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/visitor-keys" "5.59.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.0.tgz#063d066b3bc4850c18872649ed0da9ee72d833d5" + integrity sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.0" + "@typescript-eslint/types" "5.59.0" + "@typescript-eslint/typescript-estree" "5.59.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.59.0": + version "5.59.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.0.tgz#a59913f2bf0baeb61b5cfcb6135d3926c3854365" + integrity sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA== + dependencies: + "@typescript-eslint/types" "5.59.0" + eslint-visitor-keys "^3.3.0" abbrev@1: version "1.1.1" @@ -621,7 +735,7 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.2.0: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -631,16 +745,16 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - acorn@^8.4.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" @@ -653,7 +767,7 @@ ajv-formats@^2.1.0: dependencies: ajv "^8.0.0" -ajv@^6.10.0, ajv@^6.10.2: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -680,13 +794,6 @@ ansi-align@^3.0.0: dependencies: string-width "^3.0.0" -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -702,13 +809,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -729,22 +829,20 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== balanced-match@^1.0.0: version "1.0.2" @@ -814,7 +912,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -859,16 +957,7 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chalk@^2.0.0, chalk@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -876,11 +965,6 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - chokidar@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -906,18 +990,6 @@ cli-boxes@^2.2.1: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -925,13 +997,6 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -939,11 +1004,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -1018,16 +1078,14 @@ cross-fetch@^3.0.6: dependencies: node-fetch "2.6.1" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" crypto-random-string@^2.0.0: version "2.0.0" @@ -1048,10 +1106,10 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -1067,7 +1125,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -1092,6 +1150,13 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + discord-api-types@^0.37.3: version "0.37.8" resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.8.tgz#715e437898e136670c8e507c08957e70afa2fed3" @@ -1195,19 +1260,24 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.5.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== -eslint-plugin-prettier@^3.1.3: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" -eslint-scope@^5.0.0: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -1215,86 +1285,78 @@ eslint-scope@^5.0.0: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + esrecurse "^4.3.0" + estraverse "^5.2.0" -eslint@^6.7.2: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== + +eslint@^8.28.0: + version "8.39.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.39.0.tgz#7fd20a295ef92d43809e914b70c39fd5a23cf3f1" + integrity sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.2" + "@eslint/js" "8.39.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.0" + espree "^9.5.1" + esquery "^1.4.2" esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^7.0.0" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +espree@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" + integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.0" -esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -1361,15 +1423,6 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1380,29 +1433,40 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: - escape-string-regexp "^1.0.5" + reusify "^1.0.4" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" file-type@^17.1.6: version "17.1.6" @@ -1433,19 +1497,26 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + locate-path "^6.0.0" + path-exists "^4.0.0" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== forwarded@0.2.0: version "0.2.0" @@ -1467,11 +1538,6 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -1486,14 +1552,21 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -glob-parent@^5.0.0, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob@^7.1.3, glob@^7.1.6: +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -1512,12 +1585,24 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: - type-fest "^0.8.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" got@^9.6.0: version "9.6.0" @@ -1541,6 +1626,11 @@ graceful-fs@^4.1.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -1600,7 +1690,7 @@ http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1617,12 +1707,12 @@ ignore-by-default@^1.0.1: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0: +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -1668,25 +1758,6 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1728,6 +1799,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-installed-globally@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -1751,7 +1829,7 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-path-inside@^3.0.2: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -1776,23 +1854,22 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +js-sdsl@^4.1.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" + integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== + js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" json-buffer@3.0.0: version "3.0.0" @@ -1866,13 +1943,20 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" + p-locate "^5.0.0" lodash.chunk@^4.2.0: version "4.2.0" @@ -1909,6 +1993,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -1929,11 +2018,6 @@ lodash.uniqwith@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz#7a0cbf65f43b5928625a9d4d0dc54b18cadc7ef3" integrity sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q== -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -1973,11 +2057,24 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + mime-db@1.49.0: version "1.49.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" @@ -1995,11 +2092,6 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -2022,18 +2114,18 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.5: +minimatch@^3.0.5, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2054,11 +2146,6 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - mysql@^2.18.1: version "2.18.1" resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" @@ -2069,6 +2156,11 @@ mysql@^2.18.1: safe-buffer "5.1.2" sqlstring "2.3.1" +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2079,11 +2171,6 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - node-fetch@2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -2141,35 +2228,37 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: - 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" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + 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.3" p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -2192,21 +2281,31 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + peek-readable@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec" @@ -2217,10 +2316,15 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prepend-http@^2.0.0: version "2.0.0" @@ -2234,21 +2338,16 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +prettier@^2.8.0: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - proxy-addr@~2.0.5: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -2287,6 +2386,11 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -2348,16 +2452,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" @@ -2394,32 +2488,24 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: - tslib "^1.9.0" + queue-microtask "^1.2.2" safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" @@ -2448,23 +2534,30 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2, semver@^7.3.4: +semver@^7.3.4: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" +semver@^7.3.7: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -2499,36 +2592,27 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: - shebang-regex "^1.0.0" + shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== sqlstring@2.3.1: version "2.3.1" @@ -2581,7 +2665,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -2602,7 +2686,7 @@ strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-json-comments@^3.0.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -2620,7 +2704,7 @@ strtok3@^7.0.0-alpha.9: "@tokenizer/token" "^0.3.0" peek-readable "^5.0.0" -supports-color@^5.3.0, supports-color@^5.5.0: +supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -2634,33 +2718,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - to-readable-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" @@ -2717,7 +2779,7 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -2727,35 +2789,25 @@ tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tsutils@^3.17.1: +tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: - prelude-ls "~1.1.2" + prelude-ls "^1.2.1" type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -2772,9 +2824,9 @@ typedarray-to-buffer@^3.1.5: is-typedarray "^1.0.0" typescript@^4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88" - integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig== + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== undefsafe@^2.0.5: version "2.0.5" @@ -2847,20 +2899,15 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" @@ -2871,7 +2918,7 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -word-wrap@~1.2.3: +word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -2900,13 +2947,6 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - ws@7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" @@ -2931,3 +2971,8 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From c8516bff73ab7ac7344c025c4b3718522d3b82c7 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:38:32 +0400 Subject: [PATCH 02/17] chore: upgrade nodes types --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 58c0e89..0778244 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@snapshot-labs/eslint-config": "^0.1.0-beta.9", "@snapshot-labs/prettier-config": "^0.1.0-beta.7", "@types/express": "^4.17.11", - "@types/node": "^17.0.23", + "@types/node": "^18.0.0", "eslint": "^8.28.0", "prettier": "^2.8.0" } diff --git a/yarn.lock b/yarn.lock index be47d7d..5898aa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -603,10 +603,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.16.tgz#0eb3cce1e37c79619943d2fd903919fc30850601" integrity sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg== -"@types/node@^17.0.23": - version "17.0.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" - integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== +"@types/node@^18.0.0": + version "18.16.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.0.tgz#4668bc392bb6938637b47e98b1f2ed5426f33316" + integrity sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ== "@types/qs@*": version "6.9.7" From 4a680f150c65c7f2522193737ba92e9c72693596 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:34:47 +0400 Subject: [PATCH 03/17] chore: Improve typescript --- package.json | 6 +++++- src/events.ts | 23 +++++++++++------------ src/helpers/beams.ts | 7 ++++--- src/helpers/mysql.ts | 11 ++++++++++- src/helpers/proposal.ts | 6 +++--- src/helpers/utils.ts | 2 +- src/index.ts | 5 ++--- src/replay.ts | 23 +++++++++++++---------- src/subscriptions.ts | 7 ++++--- src/types.ts | 33 +++++++++++++++++++++++++++++++++ yarn.lock | 38 +++++++++++++++++++++++++++++++++++++- 11 files changed, 123 insertions(+), 38 deletions(-) create mode 100644 src/types.ts diff --git a/package.json b/package.json index 0778244..b606a2d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "@pusher/push-notifications-server": "^1.2.5", "@snapshot-labs/snapshot.js": "^0.3.68", "bluebird": "^3.7.2", - "body-parser": "^1.19.0", "connection-string": "^1.0.1", "cors": "^2.8.5", "discord.js": "^14.3.0", @@ -33,8 +32,13 @@ "devDependencies": { "@snapshot-labs/eslint-config": "^0.1.0-beta.9", "@snapshot-labs/prettier-config": "^0.1.0-beta.7", + "@types/bluebird": "^3.5.38", + "@types/cors": "^2.8.13", "@types/express": "^4.17.11", + "@types/lodash.chunk": "^4.2.7", + "@types/mysql": "^2.15.21", "@types/node": "^18.0.0", + "@types/remove-markdown": "^0.3.1", "eslint": "^8.28.0", "prettier": "^2.8.0" } diff --git a/src/events.ts b/src/events.ts index e4f3e89..466fc7d 100644 --- a/src/events.ts +++ b/src/events.ts @@ -5,6 +5,7 @@ import { sendPushNotification } from './helpers/beams'; import db from './helpers/mysql'; import { sha256 } from './helpers/utils'; import { getProposal, getProposalScores } from './helpers/proposal'; +import type { Event, Subscriber } from './types'; const delay = 5; const interval = 15; @@ -12,7 +13,7 @@ const serviceEvents = parseInt(process.env.SERVICE_EVENTS || '0'); const serviceEventsSalt = parseInt(process.env.SERVICE_EVENTS_SALT || '12345'); const servicePushNotifications = parseInt(process.env.SERVICE_PUSH_NOTIFICATIONS || '0'); -export const handleCreatedEvent = async event => { +export const handleCreatedEvent = async (event: Pick) => { const { space, id } = event; const proposalId = id.replace('proposal/', '') || ''; const proposal = await getProposal(proposalId); @@ -51,14 +52,12 @@ export const handleCreatedEvent = async event => { return db.queryAsync(query, params); }; -export const handleDeletedEvent = async event => { - const { ipfs } = event; +export const handleDeletedEvent = async (event: Partial, ipfs: string) => { const ipfsData = await snapshot.utils.ipfsGet('snapshot.mypinata.cloud', ipfs); const proposalId = ipfsData.data.message.proposal; event.id = `proposal/${proposalId}`; event.event = 'proposal/deleted'; - delete event.ipfs; const query = ` DELETE FROM events WHERE id = ?; @@ -67,9 +66,9 @@ export const handleDeletedEvent = async event => { return db.queryAsync(query, [event.id, event]); }; -export async function sendEvent(event, to) { - event.token = sha256(`${to}${serviceEventsSalt}`); - event.secret = sha256(`${to}${serviceEventsSalt}`); +export async function sendEvent(event: Event, to: string) { + const token = sha256(`${to}${serviceEventsSalt}`); + const secret = sha256(`${to}${serviceEventsSalt}`); const headerSecret = sha256(`${to}${process.env.SERVICE_EVENTS_SALT}`); try { const res = await fetch(to, { @@ -78,7 +77,7 @@ export async function sendEvent(event, to) { 'Content-Type': 'application/json', Authentication: headerSecret }, - body: JSON.stringify(event) + body: JSON.stringify({ ...event, token, secret }) }); return res.text(); } catch (error) { @@ -87,7 +86,7 @@ export async function sendEvent(event, to) { } } -const sendEventToWebhookSubscribers = (event, subscribers) => { +const sendEventToWebhookSubscribers = (event: Event, subscribers: Subscriber[]) => { Promise.allSettled( subscribers .filter(subscriber => [event.space, '*'].includes(subscriber.space)) @@ -97,9 +96,9 @@ const sendEventToWebhookSubscribers = (event, subscribers) => { .catch(e => console.log('[events] Process event failed', e)); }; -async function processEvents(subscribers) { +async function processEvents(subscribers: Subscriber[]) { const ts = parseInt((Date.now() / 1e3).toFixed()) - delay; - const events = await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts]); + const events = (await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts])) as Event[]; console.log('[events] Process event start', ts, events.length); @@ -136,7 +135,7 @@ async function run() { try { const subscribers = await db.queryAsync('SELECT * FROM subscribers'); console.log('[events] Subscribers', subscribers.length); - await processEvents(subscribers); + await processEvents(subscribers as Subscriber[]); } catch (e) { console.log('[events] Failed to process', e); } diff --git a/src/helpers/beams.ts b/src/helpers/beams.ts index b6c5e59..ba0859b 100644 --- a/src/helpers/beams.ts +++ b/src/helpers/beams.ts @@ -2,14 +2,15 @@ import PushNotifications from '@pusher/push-notifications-server'; import snapshot from '@snapshot-labs/snapshot.js'; import chunk from 'lodash.chunk'; import { getProposal } from './proposal'; +import type { Event } from '../types'; const beams = new PushNotifications({ instanceId: process.env.SERVICE_PUSHER_BEAMS_INSTANCE_ID ?? '', secretKey: process.env.SERVICE_PUSHER_BEAMS_SECRET_KEY ?? '' }); -async function getSubscribers(space) { - let subscriptions: { [key: string]: any } = []; +async function getSubscribers(space: string) { + let subscriptions: { [key: string]: any }[] = []; const query = { subscriptions: { __args: { @@ -27,7 +28,7 @@ async function getSubscribers(space) { return subscriptions.map(subscription => subscription.address); } -export const sendPushNotification = async event => { +export const sendPushNotification = async (event: Event) => { const subscribedWallets = await getSubscribers(event.space); const walletsChunks = chunk(subscribedWallets, 100); const proposal = await getProposal(event.id.replace('proposal/', '')); diff --git a/src/helpers/mysql.ts b/src/helpers/mysql.ts index 44003af..ba19ddc 100644 --- a/src/helpers/mysql.ts +++ b/src/helpers/mysql.ts @@ -1,11 +1,20 @@ import mysql from 'mysql'; +// @ts-ignore import Pool from 'mysql/lib/Pool'; +// @ts-ignore import Connection from 'mysql/lib/Connection'; import bluebird from 'bluebird'; import parse from 'connection-string'; const connectionLimit = parseInt(process.env.CONNECTION_LIMIT || '5'); +type values = string | number | boolean; +type SqlRow = Record; +type SqlQueryArgs = values | Record; +interface PromisedPool { + queryAsync: (query: string, args?: SqlQueryArgs | SqlQueryArgs[]) => Promise; +} + // @ts-ignore const config = parse(process.env.DATABASE_URL); config.connectionLimit = connectionLimit; @@ -18,6 +27,6 @@ config.acquireTimeout = 60e3; config.timeout = 60e3; config.charset = 'utf8mb4'; bluebird.promisifyAll([Pool, Connection]); -const db = mysql.createPool(config); +const db: PromisedPool = mysql.createPool(config) as mysql.Pool & PromisedPool; export default db; diff --git a/src/helpers/proposal.ts b/src/helpers/proposal.ts index b61150f..965a21c 100644 --- a/src/helpers/proposal.ts +++ b/src/helpers/proposal.ts @@ -2,7 +2,7 @@ import snapshot from '@snapshot-labs/snapshot.js'; const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; -export async function getProposal(id) { +export async function getProposal(id: string) { let proposal: { [key: string]: any } | null = null; const query = { proposal: { @@ -33,11 +33,11 @@ export async function getProposal(id) { return proposal; } -export async function getProposalScores(proposalId) { +export async function getProposalScores(proposalId: string) { return snapshot.utils.getJSON(`${hubURL}/api/scores/${proposalId}`); } -export async function checkSpace(space) { +export async function checkSpace(space: string) { try { const spaceData = await snapshot.utils.getJSON(`${hubURL}/api/spaces/${space}`); return spaceData?.name; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 0796831..b2a613c 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -4,6 +4,6 @@ export function shortenAddress(str = '') { return `${str.slice(0, 6)}...${str.slice(str.length - 4)}`; } -export function sha256(str) { +export function sha256(str: string) { return createHash('sha256').update(str).digest('hex'); } diff --git a/src/index.ts b/src/index.ts index 8dedd84..51b8d0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ import 'dotenv/config'; import express from 'express'; -import bodyParser from 'body-parser'; import cors from 'cors'; import api from './api'; import './replay'; @@ -9,8 +8,8 @@ import './discord'; const app = express(); const PORT = process.env.PORT || 3000; -app.use(bodyParser.json({ limit: '8mb' })); -app.use(bodyParser.urlencoded({ limit: '8mb', extended: false })); +app.use(express.json({ limit: '8mb' })); +app.use(express.urlencoded({ limit: '8mb', extended: false })); app.use(cors({ maxAge: 86400 })); app.use('/api', api); diff --git a/src/replay.ts b/src/replay.ts index 489aba2..63a311f 100644 --- a/src/replay.ts +++ b/src/replay.ts @@ -2,6 +2,7 @@ import snapshot from '@snapshot-labs/snapshot.js'; import { EnumType } from 'json-to-graphql-query'; import db from './helpers/mysql'; import { handleCreatedEvent, handleDeletedEvent } from './events'; +import type { Message } from './types'; const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; @@ -10,7 +11,7 @@ export let last_mci = 0; async function getLastMci() { const query = 'SELECT value FROM _metadatas WHERE id = ? LIMIT 1'; const results = await db.queryAsync(query, ['last_mci']); - last_mci = parseInt(results[0].value); + last_mci = parseInt(results[0].value as string); return last_mci; } @@ -37,7 +38,7 @@ async function getNextMessages(mci: number) { try { const results = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); - return results.messages; + return results.messages as Message[]; } catch (e) { console.log('Failed to load messages', e); return; @@ -49,8 +50,8 @@ async function updateLastMci(mci: number) { await db.queryAsync(query, [mci.toString(), 'last_mci']); } -async function processMessages(messages: any[]) { - let lastMessageMci = null; +async function processMessages(messages: Message[]) { + let lastMessageMci: number | null = null; for (const message of messages) { try { if (message.type === 'proposal') { @@ -60,10 +61,12 @@ async function processMessages(messages: any[]) { if (message.type === 'delete-proposal') { console.log('New event: "delete-proposal"', message.space, message.id); - await handleDeletedEvent({ - space: message.space, - ipfs: message.ipfs - }); + await handleDeletedEvent( + { + space: message.space + }, + message.ipfs + ); } lastMessageMci = message.mci; } catch (error) { @@ -76,7 +79,7 @@ async function processMessages(messages: any[]) { await updateLastMci(lastMessageMci); console.log('[replay] Updated to MCI', lastMessageMci); } - return + return; } async function run() { @@ -92,7 +95,7 @@ async function run() { // Run again after 10sec await snapshot.utils.sleep(10e3); - return run(); + await run(); } run(); diff --git a/src/subscriptions.ts b/src/subscriptions.ts index d67ed7d..f373c67 100644 --- a/src/subscriptions.ts +++ b/src/subscriptions.ts @@ -1,13 +1,14 @@ import db from './helpers/mysql'; +import type { Subscription } from './types'; -export let subs = {}; +export let subs: Record = {}; export async function loadSubscriptions() { const results = await db.queryAsync('SELECT * FROM subscriptions'); subs = {}; results.forEach(sub => { - if (!subs[sub.space]) subs[sub.space] = []; - subs[sub.space].push(sub); + if (!subs[sub.space as string]) subs[sub.space as string] = []; + subs[sub.space as string].push(sub as Subscription); }); console.log('Subscriptions', Object.keys(subs).length); } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..74dd73c --- /dev/null +++ b/src/types.ts @@ -0,0 +1,33 @@ +export type Subscription = { + guild: string; + channel: string; + space: string; + mention: string; + created: string; + updated: string; +}; + +export type Event = { + id: string; + event: string; + space: string; + expire: number; +}; + +export type Subscriber = { + id: number; + owner: string; + url: string; + space: string; + active: number; + created: number; +}; + +export type Message = { + mci: number; + id: string; + ipfs: string; + type: string; + timestamp: number; + space: string; +}; diff --git a/yarn.lock b/yarn.lock index 5898aa0..c6a8b3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -554,6 +554,11 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@types/bluebird@^3.5.38": + version "3.5.38" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.38.tgz#7a671e66750ccd21c9fc9d264d0e1e5330bc9908" + integrity sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg== + "@types/body-parser@*": version "1.19.1" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" @@ -569,6 +574,13 @@ dependencies: "@types/node" "*" +"@types/cors@^2.8.13": + version "2.8.13" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" + integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + dependencies: + "@types/node" "*" + "@types/express-serve-static-core@^4.17.18": version "4.17.24" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" @@ -593,11 +605,30 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/lodash.chunk@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@types/lodash.chunk/-/lodash.chunk-4.2.7.tgz#df52478072f0673d9fe8d3dd43af8f490d07a56a" + integrity sha512-//tmaWHiANgToom/YYYKKqiCtlNz11fwYtMUUbaemNSbWTI+2zHtYW5nt1PHNCRWHPAJHHhn4UVFD9LKUFvatA== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.194" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" + integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/mysql@^2.15.21": + version "2.15.21" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.21.tgz#7516cba7f9d077f980100c85fd500c8210bd5e45" + integrity sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg== + dependencies: + "@types/node" "*" + "@types/node@*": version "18.7.16" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.16.tgz#0eb3cce1e37c79619943d2fd903919fc30850601" @@ -618,6 +649,11 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/remove-markdown@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@types/remove-markdown/-/remove-markdown-0.3.1.tgz#82bc3664c313f50f7c77f1bb59935f567689dc63" + integrity sha512-JpJNEJEsmmltyL2LdE8KRjJ0L2ad5vgLibqNj85clohT9AyTrfN6jvHxStPshDkmtcL/ShFu0p2tbY7DBS1mqQ== + "@types/semver@^7.3.12": version "7.3.13" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" @@ -874,7 +910,7 @@ bn.js@^4.11.9: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -body-parser@1.19.0, body-parser@^1.19.0: +body-parser@1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== From 3df8e316146512421f3e77751a58cdd62fc1444e Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 00:36:20 +0400 Subject: [PATCH 04/17] feat: add queue system --- .env.example | 1 + package.json | 1 + src/api.ts | 8 +- src/events.ts | 109 ++------------- src/index.ts | 1 - src/queue.ts | 3 + src/queues/index.ts | 54 ++++++++ src/queues/processors/channels/http.ts | 23 ++++ src/queues/processors/events.ts | 8 ++ src/queues/processors/messages.ts | 6 + src/replay.ts | 70 ++++++++-- yarn.lock | 179 +++++++++++++++++++++++++ 12 files changed, 350 insertions(+), 113 deletions(-) create mode 100644 src/queue.ts create mode 100644 src/queues/index.ts create mode 100644 src/queues/processors/channels/http.ts create mode 100644 src/queues/processors/events.ts create mode 100644 src/queues/processors/messages.ts diff --git a/.env.example b/.env.example index d625fea..d713b97 100644 --- a/.env.example +++ b/.env.example @@ -7,3 +7,4 @@ SERVICE_PUSH_NOTIFICATIONS= SERVICE_PUSHER_BEAMS_INSTANCE_ID= SERVICE_PUSHER_BEAMS_SECRET_KEY= HUB_URL= +REDIS_URL= diff --git a/package.json b/package.json index b606a2d..734ada0 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@pusher/push-notifications-server": "^1.2.5", "@snapshot-labs/snapshot.js": "^0.3.68", "bluebird": "^3.7.2", + "bullmq": "^3.12.0", "connection-string": "^1.0.1", "cors": "^2.8.5", "discord.js": "^14.3.0", diff --git a/src/api.ts b/src/api.ts index 3842977..97e05b1 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,7 +1,7 @@ import express from 'express'; -import { sendEvent } from './events'; import pkg from '../package.json'; -import { last_mci } from './replay'; +import { getLastMci } from './replay'; +import { httpChannelQueue } from './queues'; const router = express.Router(); @@ -9,7 +9,7 @@ router.get('/', async (req, res) => { return res.json({ name: pkg.name, version: pkg.version, - last_mci + last_mci: getLastMci() }); }); @@ -23,7 +23,7 @@ router.get('/test', async (req, res) => { }; try { new URL(url); - await sendEvent(event, url); + await httpChannelQueue.add('http', { event, to: url }); return res.json({ url, success: true }); } catch (e) { return res.json({ url, error: e }); diff --git a/src/events.ts b/src/events.ts index 466fc7d..47c06c0 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,102 +1,27 @@ -import fetch from 'cross-fetch'; -import snapshot from '@snapshot-labs/snapshot.js'; import { sendEventToDiscordSubscribers } from './discord'; import { sendPushNotification } from './helpers/beams'; import db from './helpers/mysql'; -import { sha256 } from './helpers/utils'; -import { getProposal, getProposalScores } from './helpers/proposal'; +import { getProposalScores } from './helpers/proposal'; +import { httpChannelQueue } from './queues'; import type { Event, Subscriber } from './types'; const delay = 5; -const interval = 15; -const serviceEvents = parseInt(process.env.SERVICE_EVENTS || '0'); -const serviceEventsSalt = parseInt(process.env.SERVICE_EVENTS_SALT || '12345'); const servicePushNotifications = parseInt(process.env.SERVICE_PUSH_NOTIFICATIONS || '0'); -export const handleCreatedEvent = async (event: Pick) => { - const { space, id } = event; - const proposalId = id.replace('proposal/', '') || ''; - const proposal = await getProposal(proposalId); - if (!proposal) { - console.log(`[events] Proposal not found ${proposalId}`); - return; - } - - const proposalEvent = { id, space }; - const ts = Date.now() / 1e3; - - let query = 'INSERT IGNORE INTO events SET ?; '; - const params = [ - { - event: 'proposal/created', - expire: proposal.created, - ...proposalEvent - } - ]; - - query += 'INSERT IGNORE INTO events SET ?; '; - params.push({ - event: 'proposal/start', - expire: proposal.start, - ...proposalEvent - }); - - if (proposal.end > ts) { - query += 'INSERT IGNORE INTO events SET ?; '; - params.push({ - event: 'proposal/end', - expire: proposal.end, - ...proposalEvent - }); - } - return db.queryAsync(query, params); -}; - -export const handleDeletedEvent = async (event: Partial, ipfs: string) => { - const ipfsData = await snapshot.utils.ipfsGet('snapshot.mypinata.cloud', ipfs); - const proposalId = ipfsData.data.message.proposal; +async function sendEventToWebhookSubscribers(event: Event) { + const subscribers = (await db.queryAsync('SELECT * FROM subscribers')) as Subscriber[]; + console.log('[events] Subscribers', subscribers.length); - event.id = `proposal/${proposalId}`; - event.event = 'proposal/deleted'; + const data = subscribers + .filter(subscriber => [event.space, '*'].includes(subscriber.space)) + .map(subscriber => ({ name: 'http', data: { event, to: subscriber.url } })); - const query = ` - DELETE FROM events WHERE id = ?; - INSERT IGNORE INTO events SET ?; - `; - return db.queryAsync(query, [event.id, event]); -}; + httpChannelQueue.addBulk(data); -export async function sendEvent(event: Event, to: string) { - const token = sha256(`${to}${serviceEventsSalt}`); - const secret = sha256(`${to}${serviceEventsSalt}`); - const headerSecret = sha256(`${to}${process.env.SERVICE_EVENTS_SALT}`); - try { - const res = await fetch(to, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authentication: headerSecret - }, - body: JSON.stringify({ ...event, token, secret }) - }); - return res.text(); - } catch (error) { - console.log('[events] Error sending event data to webhook', to, JSON.stringify(error)); - return; - } + console.log('[events] Process event queued'); } -const sendEventToWebhookSubscribers = (event: Event, subscribers: Subscriber[]) => { - Promise.allSettled( - subscribers - .filter(subscriber => [event.space, '*'].includes(subscriber.space)) - .map(subscriber => sendEvent(event, subscriber.url)) - ) - .then(() => console.log('[events] Process event done')) - .catch(e => console.log('[events] Process event failed', e)); -}; - -async function processEvents(subscribers: Subscriber[]) { +async function processEvents() { const ts = parseInt((Date.now() / 1e3).toFixed()) - delay; const events = (await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts])) as Event[]; @@ -117,7 +42,7 @@ async function processEvents(subscribers: Subscriber[]) { // TODO: handle errors and retry if (servicePushNotifications && event.event === 'proposal/start') sendPushNotification(event); sendEventToDiscordSubscribers(event.event, proposalId); - sendEventToWebhookSubscribers(event, subscribers); + sendEventToWebhookSubscribers(event); try { await db.queryAsync('DELETE FROM events WHERE id = ? AND event = ? LIMIT 1', [ @@ -131,16 +56,10 @@ async function processEvents(subscribers: Subscriber[]) { } } -async function run() { +export async function run() { try { - const subscribers = await db.queryAsync('SELECT * FROM subscribers'); - console.log('[events] Subscribers', subscribers.length); - await processEvents(subscribers as Subscriber[]); + await processEvents(); } catch (e) { console.log('[events] Failed to process', e); } - await snapshot.utils.sleep(interval * 1e3); - await run(); } - -if (serviceEvents) setTimeout(() => run(), interval * 1e3); diff --git a/src/index.ts b/src/index.ts index 51b8d0e..361b080 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,6 @@ import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import api from './api'; -import './replay'; import './discord'; const app = express(); diff --git a/src/queue.ts b/src/queue.ts new file mode 100644 index 0000000..0fb5a3c --- /dev/null +++ b/src/queue.ts @@ -0,0 +1,3 @@ +import { start } from './queues'; + +start(); diff --git a/src/queues/index.ts b/src/queues/index.ts new file mode 100644 index 0000000..3fc5b0c --- /dev/null +++ b/src/queues/index.ts @@ -0,0 +1,54 @@ +import 'dotenv/config'; +import { Queue, Worker } from 'bullmq'; +import Redis from 'ioredis'; +import messagesProcessor from './processors/messages'; +import eventsProcessor from './processors/events'; +import HttpChannelProcessor from './processors/channels/http'; + +const connection = new Redis(process.env.REDIS_URL as string); + +export const messagesQueue = new Queue('messages', { connection }); +export const eventsQueue = new Queue('events', { connection }); +export const httpChannelQueue = new Queue('channel-http', { connection }); + +let messagesWorker: Worker; +let eventsWorker: Worker; +let httpChannelWorker: Worker; + +export async function start() { + console.log('[queue] Starting queue'); + + messagesWorker = new Worker(messagesQueue.name, messagesProcessor, { connection }); + eventsWorker = new Worker(eventsQueue.name, eventsProcessor, { connection }); + httpChannelWorker = new Worker(eventsQueue.name, HttpChannelProcessor, { connection }); + + await messagesQueue.add( + 'messages-reader', + {}, + { + repeat: { + every: 10000 + } + } + ); + + await eventsQueue.add( + 'events-processor', + {}, + { + repeat: { + every: 15000 + } + } + ); +} + +async function shutdown() { + console.log('[queue] Starting queue shutdown'); + await Promise.all([messagesWorker.close(), eventsWorker.close(), httpChannelWorker.close()]); + console.log('[queue] Shutdown complete'); + process.exit(0); +} + +process.on('SIGTERM', shutdown); +process.on('SIGINT', shutdown); diff --git a/src/queues/processors/channels/http.ts b/src/queues/processors/channels/http.ts new file mode 100644 index 0000000..fc5695a --- /dev/null +++ b/src/queues/processors/channels/http.ts @@ -0,0 +1,23 @@ +import type { Job } from 'bullmq'; +import { sha256 } from '../../../helpers/utils'; + +const serviceEventsSalt = parseInt(process.env.SERVICE_EVENTS_SALT || '12345'); + +export default async (job: Job) => { + const { event, to } = job.data; + + try { + const res = await fetch(to, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authentication: sha256(`${to}${serviceEventsSalt}`) + }, + body: JSON.stringify(event) + }); + return res.text(); + } catch (error) { + console.log('[events] Error sending event data to webhook', to, JSON.stringify(error)); + return; + } +}; diff --git a/src/queues/processors/events.ts b/src/queues/processors/events.ts new file mode 100644 index 0000000..5198358 --- /dev/null +++ b/src/queues/processors/events.ts @@ -0,0 +1,8 @@ +import { run } from '../../events'; + +export default async () => { + if (process.env.SERVICE_EVENT || '0') { + console.log('[queue] Running "events" processor'); + await run(); + } +}; diff --git a/src/queues/processors/messages.ts b/src/queues/processors/messages.ts new file mode 100644 index 0000000..7b5b2e9 --- /dev/null +++ b/src/queues/processors/messages.ts @@ -0,0 +1,6 @@ +import { run } from '../../replay'; + +export default async () => { + console.log('[queue] Running "messages" processor'); + await run(); +}; diff --git a/src/replay.ts b/src/replay.ts index 63a311f..d3f2743 100644 --- a/src/replay.ts +++ b/src/replay.ts @@ -1,18 +1,68 @@ import snapshot from '@snapshot-labs/snapshot.js'; import { EnumType } from 'json-to-graphql-query'; import db from './helpers/mysql'; -import { handleCreatedEvent, handleDeletedEvent } from './events'; -import type { Message } from './types'; +import { getProposal } from './helpers/proposal'; +import type { Message, Event } from './types'; const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; -export let last_mci = 0; +const handleCreatedEvent = async (event: Pick) => { + const { space, id } = event; + const proposalId = id.replace('proposal/', '') || ''; + const proposal = await getProposal(proposalId); + if (!proposal) { + console.log(`[events] Proposal not found ${proposalId}`); + return; + } -async function getLastMci() { + const proposalEvent = { id, space }; + const ts = Date.now() / 1e3; + + let query = 'INSERT IGNORE INTO events SET ?; '; + const params = [ + { + event: 'proposal/created', + expire: proposal.created, + ...proposalEvent + } + ]; + + query += 'INSERT IGNORE INTO events SET ?; '; + params.push({ + event: 'proposal/start', + expire: proposal.start, + ...proposalEvent + }); + + if (proposal.end > ts) { + query += 'INSERT IGNORE INTO events SET ?; '; + params.push({ + event: 'proposal/end', + expire: proposal.end, + ...proposalEvent + }); + } + return db.queryAsync(query, params); +}; + +const handleDeletedEvent = async (event: Partial, ipfs: string) => { + const ipfsData = await snapshot.utils.ipfsGet('snapshot.mypinata.cloud', ipfs); + const proposalId = ipfsData.data.message.proposal; + + event.id = `proposal/${proposalId}`; + event.event = 'proposal/deleted'; + + const query = ` + DELETE FROM events WHERE id = ?; + INSERT IGNORE INTO events SET ?; + `; + return db.queryAsync(query, [event.id, event]); +}; + +export async function getLastMci() { const query = 'SELECT value FROM _metadatas WHERE id = ? LIMIT 1'; const results = await db.queryAsync(query, ['last_mci']); - last_mci = parseInt(results[0].value as string); - return last_mci; + return parseInt(results[0].value as string); } async function getNextMessages(mci: number) { @@ -82,7 +132,7 @@ async function processMessages(messages: Message[]) { return; } -async function run() { +export async function run() { // Check latest indexed MCI from db const lastMci = await getLastMci(); console.log('[replay] Last MCI', lastMci); @@ -92,10 +142,4 @@ async function run() { if (messages && messages.length > 0) { await processMessages(messages); } - - // Run again after 10sec - await snapshot.utils.sleep(10e3); - await run(); } - -run(); diff --git a/yarn.lock b/yarn.lock index c6a8b3f..9b00357 100644 --- a/yarn.lock +++ b/yarn.lock @@ -413,6 +413,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@ioredis/commands@^1.1.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -431,6 +436,36 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38" + integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3" + integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367" + integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399" + integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f" + integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" + integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -948,6 +983,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -965,6 +1007,20 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +bullmq@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/bullmq/-/bullmq-3.12.0.tgz#5a3e9ac40e4d623c27f7cdd214a69fd4122270da" + integrity sha512-h5SMgKXfHe6wKzEEdKTO4zUkOV1TkyQagw3WVOaz+6XWuaWv4EhCAOIkzPAajI7ZNF9c+YwSRY3bQjXmxI0f9Q== + dependencies: + cron-parser "^4.6.0" + glob "^8.0.3" + ioredis "^5.3.2" + lodash "^4.17.21" + msgpackr "^1.6.2" + semver "^7.3.7" + tslib "^2.0.0" + uuid "^9.0.0" + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -1033,6 +1089,11 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cluster-key-slot@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1107,6 +1168,13 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cron-parser@^4.6.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.8.1.tgz#47062ea63d21d78c10ddedb08ea4c5b6fc2750fb" + integrity sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ== + dependencies: + luxon "^3.2.1" + cross-fetch@^3.0.6: version "3.1.4" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" @@ -1171,6 +1239,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -1614,6 +1687,17 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-dirs@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" @@ -1794,6 +1878,21 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ioredis@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.2.tgz#9139f596f62fc9c72d873353ac5395bcf05709f7" + integrity sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA== + dependencies: + "@ioredis/commands" "^1.1.1" + cluster-key-slot "^1.1.0" + debug "^4.3.4" + denque "^2.1.0" + lodash.defaults "^4.2.0" + lodash.isarguments "^3.1.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1999,11 +2098,21 @@ lodash.chunk@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc" integrity sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -2054,6 +2163,11 @@ lodash.uniqwith@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz#7a0cbf65f43b5928625a9d4d0dc54b18cadc7ef3" integrity sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -2071,6 +2185,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +luxon@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.3.0.tgz#d73ab5b5d2b49a461c47cedbc7e73309b4805b48" + integrity sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg== + make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -2157,6 +2276,13 @@ minimatch@^3.0.5, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -2182,6 +2308,27 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d" + integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A== + dependencies: + node-gyp-build-optional-packages "5.0.7" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" + +msgpackr@^1.6.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.5.tgz#8cadfb935357680648f33699d0e833c9179dbfeb" + integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg== + optionalDependencies: + msgpackr-extract "^3.0.1" + mysql@^2.18.1: version "2.18.1" resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" @@ -2212,6 +2359,11 @@ node-fetch@2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-gyp-build-optional-packages@5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" + integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== + nodemon@^2.0.15: version "2.0.15" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e" @@ -2488,6 +2640,18 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" @@ -2655,6 +2819,11 @@ sqlstring@2.3.1: resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" integrity sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A= +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -2820,6 +2989,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + tslib@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" @@ -2930,6 +3104,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" From 0d60d9bd75800573617f76bde1c739846bdacaf9 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 00:48:46 +0400 Subject: [PATCH 05/17] feat: add retry strategy to channel's queue --- src/queues/index.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/queues/index.ts b/src/queues/index.ts index 3fc5b0c..ddf2cbb 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -9,7 +9,16 @@ const connection = new Redis(process.env.REDIS_URL as string); export const messagesQueue = new Queue('messages', { connection }); export const eventsQueue = new Queue('events', { connection }); -export const httpChannelQueue = new Queue('channel-http', { connection }); +export const httpChannelQueue = new Queue('channel-http', { + connection, + defaultJobOptions: { + attempts: 5, + backoff: { + type: 'exponential', + delay: 10000 + } + } +}); let messagesWorker: Worker; let eventsWorker: Worker; From e4f6f2fb6c56655907cb4709ff0935388482baad Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 12:16:38 +0400 Subject: [PATCH 06/17] fix: rename channels to notifications --- src/api.ts | 4 ++-- src/events.ts | 4 ++-- src/queues/index.ts | 6 +++--- src/queues/processors/{channels => notifications}/http.ts | 0 4 files changed, 7 insertions(+), 7 deletions(-) rename src/queues/processors/{channels => notifications}/http.ts (100%) diff --git a/src/api.ts b/src/api.ts index 97e05b1..338ca9b 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,7 +1,7 @@ import express from 'express'; import pkg from '../package.json'; import { getLastMci } from './replay'; -import { httpChannelQueue } from './queues'; +import { httpNotificationsQueue } from './queues'; const router = express.Router(); @@ -23,7 +23,7 @@ router.get('/test', async (req, res) => { }; try { new URL(url); - await httpChannelQueue.add('http', { event, to: url }); + await httpNotificationsQueue.add('http', { event, to: url }); return res.json({ url, success: true }); } catch (e) { return res.json({ url, error: e }); diff --git a/src/events.ts b/src/events.ts index 47c06c0..60e7942 100644 --- a/src/events.ts +++ b/src/events.ts @@ -2,7 +2,7 @@ import { sendEventToDiscordSubscribers } from './discord'; import { sendPushNotification } from './helpers/beams'; import db from './helpers/mysql'; import { getProposalScores } from './helpers/proposal'; -import { httpChannelQueue } from './queues'; +import { httpNotificationsQueue } from './queues'; import type { Event, Subscriber } from './types'; const delay = 5; @@ -16,7 +16,7 @@ async function sendEventToWebhookSubscribers(event: Event) { .filter(subscriber => [event.space, '*'].includes(subscriber.space)) .map(subscriber => ({ name: 'http', data: { event, to: subscriber.url } })); - httpChannelQueue.addBulk(data); + httpNotificationsQueue.addBulk(data); console.log('[events] Process event queued'); } diff --git a/src/queues/index.ts b/src/queues/index.ts index ddf2cbb..d07930a 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -3,13 +3,13 @@ import { Queue, Worker } from 'bullmq'; import Redis from 'ioredis'; import messagesProcessor from './processors/messages'; import eventsProcessor from './processors/events'; -import HttpChannelProcessor from './processors/channels/http'; +import HttpNotificationsProcessor from './processors/notifications/http'; const connection = new Redis(process.env.REDIS_URL as string); export const messagesQueue = new Queue('messages', { connection }); export const eventsQueue = new Queue('events', { connection }); -export const httpChannelQueue = new Queue('channel-http', { +export const httpNotificationsQueue = new Queue('notifications-http', { connection, defaultJobOptions: { attempts: 5, @@ -29,7 +29,7 @@ export async function start() { messagesWorker = new Worker(messagesQueue.name, messagesProcessor, { connection }); eventsWorker = new Worker(eventsQueue.name, eventsProcessor, { connection }); - httpChannelWorker = new Worker(eventsQueue.name, HttpChannelProcessor, { connection }); + httpChannelWorker = new Worker(eventsQueue.name, HttpNotificationsProcessor, { connection }); await messagesQueue.add( 'messages-reader', diff --git a/src/queues/processors/channels/http.ts b/src/queues/processors/notifications/http.ts similarity index 100% rename from src/queues/processors/channels/http.ts rename to src/queues/processors/notifications/http.ts From cc94596bcc6a28827801caad2cb2db9e4240c1ec Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:18:34 +0400 Subject: [PATCH 07/17] feat: migrate push notifications to queue --- src/discord.ts | 2 +- src/events.ts | 45 +++++++-- src/helpers/beams.ts | 57 +++-------- src/helpers/proposal.ts | 47 --------- src/helpers/snapshot.ts | 101 ++++++++++++++++++++ src/queues/index.ts | 26 ++++- src/queues/processors/notifications/push.ts | 8 ++ src/replay.ts | 40 +------- src/types.ts | 20 ++++ 9 files changed, 205 insertions(+), 141 deletions(-) delete mode 100644 src/helpers/proposal.ts create mode 100644 src/helpers/snapshot.ts create mode 100644 src/queues/processors/notifications/push.ts diff --git a/src/discord.ts b/src/discord.ts index 6db2d49..268c77d 100644 --- a/src/discord.ts +++ b/src/discord.ts @@ -17,7 +17,7 @@ import db from './helpers/mysql'; import removeMd from 'remove-markdown'; import { shortenAddress } from './helpers/utils'; import { subs, loadSubscriptions } from './subscriptions'; -import { checkSpace, getProposal } from './helpers/proposal'; +import { checkSpace, getProposal } from './helpers/snapshot'; const CLIENT_ID = process.env.DISCORD_CLIENT_ID || ''; const token = process.env.DISCORD_TOKEN || ''; diff --git a/src/events.ts b/src/events.ts index 60e7942..fd8d1a6 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,14 +1,14 @@ +import chunk from 'lodash.chunk'; import { sendEventToDiscordSubscribers } from './discord'; -import { sendPushNotification } from './helpers/beams'; import db from './helpers/mysql'; -import { getProposalScores } from './helpers/proposal'; +import { getProposalScores, getProposal, getSubscribers } from './helpers/snapshot'; import { httpNotificationsQueue } from './queues'; -import type { Event, Subscriber } from './types'; +import { pushNotificationsQueue } from './queues'; +import type { Event, Subscriber, Proposal } from './types'; -const delay = 5; -const servicePushNotifications = parseInt(process.env.SERVICE_PUSH_NOTIFICATIONS || '0'); +const DELAY = 5; -async function sendEventToWebhookSubscribers(event: Event) { +async function queueHttpNotifications(event: Event) { const subscribers = (await db.queryAsync('SELECT * FROM subscribers')) as Subscriber[]; console.log('[events] Subscribers', subscribers.length); @@ -21,8 +21,26 @@ async function sendEventToWebhookSubscribers(event: Event) { console.log('[events] Process event queued'); } +async function queuePushNotifications(event: Event, proposal: Proposal) { + if ( + parseInt(process.env.SERVICE_PUSH_NOTIFICATIONS || '0') !== 0 || + event.event !== 'proposal/start' + ) { + return; + } + + const subscribedWallets = await getSubscribers(event.space); + const walletsChunks = chunk(subscribedWallets, 100); + + const data = walletsChunks.map(chunk => { + return { name: 'push', data: { event, proposalTitle: proposal.title, to: chunk } }; + }); + + pushNotificationsQueue.addBulk(data); +} + async function processEvents() { - const ts = parseInt((Date.now() / 1e3).toFixed()) - delay; + const ts = parseInt((Date.now() / 1e3).toFixed()) - DELAY; const events = (await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts])) as Event[]; console.log('[events] Process event start', ts, events.length); @@ -38,18 +56,25 @@ async function processEvents() { } } + const proposal = await getProposal(event.id.replace('proposal/', '')); + if (!proposal) { + console.log('[events] Proposal not found', event.id); + return; + } + // Send event to discord subscribers and webhook subscribers and then delete event from db // TODO: handle errors and retry - if (servicePushNotifications && event.event === 'proposal/start') sendPushNotification(event); + queuePushNotifications(event, proposal); + queueHttpNotifications(event); + sendEventToDiscordSubscribers(event.event, proposalId); - sendEventToWebhookSubscribers(event); try { await db.queryAsync('DELETE FROM events WHERE id = ? AND event = ? LIMIT 1', [ event.id, event.event ]); - console.log(`[events] Event sent ${event.id} ${event.event}`); + console.log(`[events] Events jobs queued ${event.id} ${event.event}`); } catch (e) { console.log('[events]', e); } diff --git a/src/helpers/beams.ts b/src/helpers/beams.ts index ba0859b..fc6a3a6 100644 --- a/src/helpers/beams.ts +++ b/src/helpers/beams.ts @@ -1,53 +1,22 @@ import PushNotifications from '@pusher/push-notifications-server'; -import snapshot from '@snapshot-labs/snapshot.js'; -import chunk from 'lodash.chunk'; -import { getProposal } from './proposal'; import type { Event } from '../types'; -const beams = new PushNotifications({ - instanceId: process.env.SERVICE_PUSHER_BEAMS_INSTANCE_ID ?? '', - secretKey: process.env.SERVICE_PUSHER_BEAMS_SECRET_KEY ?? '' -}); - -async function getSubscribers(space: string) { - let subscriptions: { [key: string]: any }[] = []; - const query = { - subscriptions: { - __args: { - where: { space } - }, - address: true - } - }; +export const sendPushNotification = async (event: Event, proposalTitle: string, to: string[]) => { try { - const result = await snapshot.utils.subgraphRequest('https://hub.snapshot.org/graphql', query); - subscriptions = result.subscriptions || []; - } catch (error) { - console.log('[events] Snapshot hub error:', error); - } - return subscriptions.map(subscription => subscription.address); -} + const beams = new PushNotifications({ + instanceId: process.env.SERVICE_PUSHER_BEAMS_INSTANCE_ID ?? '', + secretKey: process.env.SERVICE_PUSHER_BEAMS_SECRET_KEY ?? '' + }); -export const sendPushNotification = async (event: Event) => { - const subscribedWallets = await getSubscribers(event.space); - const walletsChunks = chunk(subscribedWallets, 100); - const proposal = await getProposal(event.id.replace('proposal/', '')); - if (!proposal) { - console.log('[events] Proposal not found', event.id); - return; - } - try { - for await (const walletsChunk of walletsChunks) { - await beams.publishToInterests(walletsChunk, { - web: { - notification: { - title: event.space, - body: proposal.title, - deep_link: `${process.env.SNAPSHOT_URI}/#/${event.space}/${event.id}` - } + await beams.publishToInterests(to, { + web: { + notification: { + title: event.space, + body: proposalTitle, + deep_link: `${process.env.SNAPSHOT_URI}/#/${event.space}/${event.id}` } - }); - } + } + }); } catch (e) { console.log('[events] Error sending push notification', e); } diff --git a/src/helpers/proposal.ts b/src/helpers/proposal.ts deleted file mode 100644 index 965a21c..0000000 --- a/src/helpers/proposal.ts +++ /dev/null @@ -1,47 +0,0 @@ -import snapshot from '@snapshot-labs/snapshot.js'; - -const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; - -export async function getProposal(id: string) { - let proposal: { [key: string]: any } | null = null; - const query = { - proposal: { - __args: { - id - }, - space: { - id: true, - name: true, - avatar: true - }, - id: true, - type: true, - author: true, - title: true, - body: true, - choices: true, - start: true, - end: true, - snapshot: true - } - }; - const result = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); - if (result.errors) { - throw new Error(`[events] Errors in subgraph request for proposal id: ${id}`); - } - proposal = result.proposal || null; - return proposal; -} - -export async function getProposalScores(proposalId: string) { - return snapshot.utils.getJSON(`${hubURL}/api/scores/${proposalId}`); -} - -export async function checkSpace(space: string) { - try { - const spaceData = await snapshot.utils.getJSON(`${hubURL}/api/spaces/${space}`); - return spaceData?.name; - } catch (error) { - return false; - } -} diff --git a/src/helpers/snapshot.ts b/src/helpers/snapshot.ts new file mode 100644 index 0000000..74d5c56 --- /dev/null +++ b/src/helpers/snapshot.ts @@ -0,0 +1,101 @@ +import snapshot from '@snapshot-labs/snapshot.js'; +import { EnumType } from 'json-to-graphql-query'; +import type { Proposal, Message } from '../types'; + +const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; + +export async function getProposal(id: string) { + const query = { + proposal: { + __args: { + id + }, + space: { + id: true, + name: true, + avatar: true + }, + id: true, + type: true, + author: true, + title: true, + body: true, + choices: true, + start: true, + end: true, + created: true, + snapshot: true + } + }; + const result = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); + if (result.errors) { + throw new Error(`[events] Errors in subgraph request for proposal id: ${id}`); + } + return result.proposal as Proposal; +} + +export async function getProposalScores(proposalId: string) { + return snapshot.utils.getJSON(`${hubURL}/api/scores/${proposalId}`); +} + +export async function checkSpace(space: string) { + try { + const spaceData = await snapshot.utils.getJSON(`${hubURL}/api/spaces/${space}`); + return spaceData?.name; + } catch (error) { + return false; + } +} + +export async function getNextMessages(mci: number) { + const query = { + messages: { + __args: { + first: 10, + where: { + type_in: ['proposal', 'delete-proposal'], + mci_gt: mci + }, + orderBy: 'mci', + orderDirection: new EnumType('asc') + }, + mci: true, + id: true, + ipfs: true, + type: true, + timestamp: true, + space: true + } + }; + + try { + const results = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); + return results.messages as Message[]; + } catch (e) { + console.log('Failed to load messages', e); + return []; + } +} + +export async function getSubscribers(space: string) { + let subscriptions: { [key: string]: any }[] = []; + const query = { + subscriptions: { + __args: { + where: { space } + }, + address: true + } + }; + try { + const result = await snapshot.utils.subgraphRequest('https://hub.snapshot.org/graphql', query); + subscriptions = result.subscriptions || []; + } catch (error) { + console.log('[events] Snapshot hub error:', error); + } + return subscriptions.map(subscription => subscription.address as string); +} + +export async function getIpfsData(ipfs: string) { + return await snapshot.utils.ipfsGet('snapshot.mypinata.cloud', ipfs); +} diff --git a/src/queues/index.ts b/src/queues/index.ts index d07930a..6f7611a 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -4,6 +4,7 @@ import Redis from 'ioredis'; import messagesProcessor from './processors/messages'; import eventsProcessor from './processors/events'; import HttpNotificationsProcessor from './processors/notifications/http'; +import PushNotificationsProcessor from './processors/notifications/push'; const connection = new Redis(process.env.REDIS_URL as string); @@ -19,17 +20,33 @@ export const httpNotificationsQueue = new Queue('notifications-http', { } } }); +export const pushNotificationsQueue = new Queue('notifications-push', { + connection, + defaultJobOptions: { + attempts: 3, + backoff: { + type: 'exponential', + delay: 10000 + } + } +}); let messagesWorker: Worker; let eventsWorker: Worker; let httpChannelWorker: Worker; +let pushChannelWorker: Worker; export async function start() { console.log('[queue] Starting queue'); messagesWorker = new Worker(messagesQueue.name, messagesProcessor, { connection }); eventsWorker = new Worker(eventsQueue.name, eventsProcessor, { connection }); - httpChannelWorker = new Worker(eventsQueue.name, HttpNotificationsProcessor, { connection }); + httpChannelWorker = new Worker(httpNotificationsQueue.name, HttpNotificationsProcessor, { + connection + }); + pushChannelWorker = new Worker(pushNotificationsQueue.name, PushNotificationsProcessor, { + connection + }); await messagesQueue.add( 'messages-reader', @@ -54,7 +71,12 @@ export async function start() { async function shutdown() { console.log('[queue] Starting queue shutdown'); - await Promise.all([messagesWorker.close(), eventsWorker.close(), httpChannelWorker.close()]); + await Promise.all([ + messagesWorker.close(), + eventsWorker.close(), + httpChannelWorker.close(), + pushChannelWorker.close() + ]); console.log('[queue] Shutdown complete'); process.exit(0); } diff --git a/src/queues/processors/notifications/push.ts b/src/queues/processors/notifications/push.ts new file mode 100644 index 0000000..a509c54 --- /dev/null +++ b/src/queues/processors/notifications/push.ts @@ -0,0 +1,8 @@ +import type { Job } from 'bullmq'; +import { sendPushNotification } from '../../../helpers/beams'; + +export default async (job: Job) => { + const { event, to, proposalTitle } = job.data; + + sendPushNotification(event, proposalTitle, to); +}; diff --git a/src/replay.ts b/src/replay.ts index d3f2743..bc8705f 100644 --- a/src/replay.ts +++ b/src/replay.ts @@ -1,11 +1,7 @@ -import snapshot from '@snapshot-labs/snapshot.js'; -import { EnumType } from 'json-to-graphql-query'; import db from './helpers/mysql'; -import { getProposal } from './helpers/proposal'; +import { getProposal, getNextMessages, getIpfsData } from './helpers/snapshot'; import type { Message, Event } from './types'; -const hubURL = process.env.HUB_URL || 'https://hub.snapshot.org'; - const handleCreatedEvent = async (event: Pick) => { const { space, id } = event; const proposalId = id.replace('proposal/', '') || ''; @@ -46,7 +42,7 @@ const handleCreatedEvent = async (event: Pick) => { }; const handleDeletedEvent = async (event: Partial, ipfs: string) => { - const ipfsData = await snapshot.utils.ipfsGet('snapshot.mypinata.cloud', ipfs); + const ipfsData = await getIpfsData(ipfs); const proposalId = ipfsData.data.message.proposal; event.id = `proposal/${proposalId}`; @@ -65,36 +61,6 @@ export async function getLastMci() { return parseInt(results[0].value as string); } -async function getNextMessages(mci: number) { - const query = { - messages: { - __args: { - first: 10, - where: { - type_in: ['proposal', 'delete-proposal'], - mci_gt: mci - }, - orderBy: 'mci', - orderDirection: new EnumType('asc') - }, - mci: true, - id: true, - ipfs: true, - type: true, - timestamp: true, - space: true - } - }; - - try { - const results = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); - return results.messages as Message[]; - } catch (e) { - console.log('Failed to load messages', e); - return; - } -} - async function updateLastMci(mci: number) { const query = 'UPDATE _metadatas SET value = ? WHERE id = ? LIMIT 1'; await db.queryAsync(query, [mci.toString(), 'last_mci']); @@ -139,7 +105,7 @@ export async function run() { // Load next messages after latest indexed MCI const messages = await getNextMessages(lastMci); - if (messages && messages.length > 0) { + if (messages.length > 0) { await processMessages(messages); } } diff --git a/src/types.ts b/src/types.ts index 74dd73c..54a496c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,3 +31,23 @@ export type Message = { timestamp: number; space: string; }; + +type Space = { + id: string; + name: string; + avatar: string; +}; + +export type Proposal = { + space: Space; + id: string; + type: string; + author: string; + title: string; + body: string; + choices: string[]; + start: number; + end: number; + created: number; + snapshot: string; +}; From 2ead45d497a4c6e0585bc50d4a7af12252548f00 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:02:32 +0400 Subject: [PATCH 08/17] feat: move discord events to queue --- src/events.ts | 17 ++++++++++------- src/queues/index.ts | 18 +++++++++++++++++- src/queues/processors/notifications/discord.ts | 9 +++++++++ src/queues/processors/notifications/http.ts | 5 +++-- src/queues/processors/notifications/push.ts | 9 +++++++-- 5 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 src/queues/processors/notifications/discord.ts diff --git a/src/events.ts b/src/events.ts index fd8d1a6..bdf6c09 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,9 +1,11 @@ import chunk from 'lodash.chunk'; -import { sendEventToDiscordSubscribers } from './discord'; import db from './helpers/mysql'; import { getProposalScores, getProposal, getSubscribers } from './helpers/snapshot'; -import { httpNotificationsQueue } from './queues'; -import { pushNotificationsQueue } from './queues'; +import { + httpNotificationsQueue, + pushNotificationsQueue, + discordNotificationsQueue +} from './queues'; import type { Event, Subscriber, Proposal } from './types'; const DELAY = 5; @@ -39,6 +41,10 @@ async function queuePushNotifications(event: Event, proposal: Proposal) { pushNotificationsQueue.addBulk(data); } +async function queueDiscordNotifications(event: Event, proposal: Proposal) { + discordNotificationsQueue.add('discord', { event, proposalId: proposal.id }); +} + async function processEvents() { const ts = parseInt((Date.now() / 1e3).toFixed()) - DELAY; const events = (await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts])) as Event[]; @@ -62,12 +68,9 @@ async function processEvents() { return; } - // Send event to discord subscribers and webhook subscribers and then delete event from db - // TODO: handle errors and retry queuePushNotifications(event, proposal); queueHttpNotifications(event); - - sendEventToDiscordSubscribers(event.event, proposalId); + queueDiscordNotifications(event, proposal); try { await db.queryAsync('DELETE FROM events WHERE id = ? AND event = ? LIMIT 1', [ diff --git a/src/queues/index.ts b/src/queues/index.ts index 6f7611a..f3688d0 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -5,6 +5,7 @@ import messagesProcessor from './processors/messages'; import eventsProcessor from './processors/events'; import HttpNotificationsProcessor from './processors/notifications/http'; import PushNotificationsProcessor from './processors/notifications/push'; +import DiscordNotificationsProcessor from './processors/notifications/discord'; const connection = new Redis(process.env.REDIS_URL as string); @@ -30,11 +31,22 @@ export const pushNotificationsQueue = new Queue('notifications-push', { } } }); +export const discordNotificationsQueue = new Queue('notifications-discord', { + connection, + defaultJobOptions: { + attempts: 3, + backoff: { + type: 'exponential', + delay: 10000 + } + } +}); let messagesWorker: Worker; let eventsWorker: Worker; let httpChannelWorker: Worker; let pushChannelWorker: Worker; +let discordChannelWorker: Worker; export async function start() { console.log('[queue] Starting queue'); @@ -47,6 +59,9 @@ export async function start() { pushChannelWorker = new Worker(pushNotificationsQueue.name, PushNotificationsProcessor, { connection }); + discordChannelWorker = new Worker(discordNotificationsQueue.name, DiscordNotificationsProcessor, { + connection + }); await messagesQueue.add( 'messages-reader', @@ -75,7 +90,8 @@ async function shutdown() { messagesWorker.close(), eventsWorker.close(), httpChannelWorker.close(), - pushChannelWorker.close() + pushChannelWorker.close(), + discordChannelWorker.close() ]); console.log('[queue] Shutdown complete'); process.exit(0); diff --git a/src/queues/processors/notifications/discord.ts b/src/queues/processors/notifications/discord.ts new file mode 100644 index 0000000..22c195e --- /dev/null +++ b/src/queues/processors/notifications/discord.ts @@ -0,0 +1,9 @@ +import { sendEventToDiscordSubscribers } from '../../../discord'; +import type { Job } from 'bullmq'; +import type { Event, Proposal } from '../../../types'; + +export default async (job: Job) => { + const { event, proposalId }: { event: Event; proposalId: Proposal['id'] } = job.data; + + sendEventToDiscordSubscribers(event.event, proposalId); +}; diff --git a/src/queues/processors/notifications/http.ts b/src/queues/processors/notifications/http.ts index fc5695a..4c639e9 100644 --- a/src/queues/processors/notifications/http.ts +++ b/src/queues/processors/notifications/http.ts @@ -1,10 +1,11 @@ -import type { Job } from 'bullmq'; import { sha256 } from '../../../helpers/utils'; +import type { Job } from 'bullmq'; +import type { Event, Subscriber } from '../../../types'; const serviceEventsSalt = parseInt(process.env.SERVICE_EVENTS_SALT || '12345'); export default async (job: Job) => { - const { event, to } = job.data; + const { event, to }: { event: Event; to: Subscriber['url'] } = job.data; try { const res = await fetch(to, { diff --git a/src/queues/processors/notifications/push.ts b/src/queues/processors/notifications/push.ts index a509c54..1ba1fe0 100644 --- a/src/queues/processors/notifications/push.ts +++ b/src/queues/processors/notifications/push.ts @@ -1,8 +1,13 @@ -import type { Job } from 'bullmq'; import { sendPushNotification } from '../../../helpers/beams'; +import type { Job } from 'bullmq'; +import type { Event, Proposal } from '../../../types'; export default async (job: Job) => { - const { event, to, proposalTitle } = job.data; + const { + event, + to, + proposalTitle + }: { event: Event; to: string[]; proposalTitle: Proposal['title'] } = job.data; sendPushNotification(event, proposalTitle, to); }; From 61b55993d8f3488d8098f14dc8fc860344aaee80 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:54:04 +0400 Subject: [PATCH 09/17] fix: raise error on all non-2xx response status Will retry all HTTP request not-returning a 2xx status code --- src/queues/processors/notifications/http.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/queues/processors/notifications/http.ts b/src/queues/processors/notifications/http.ts index 4c639e9..0004722 100644 --- a/src/queues/processors/notifications/http.ts +++ b/src/queues/processors/notifications/http.ts @@ -8,7 +8,7 @@ export default async (job: Job) => { const { event, to }: { event: Event; to: Subscriber['url'] } = job.data; try { - const res = await fetch(to, { + const response = await fetch(to, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -16,9 +16,19 @@ export default async (job: Job) => { }, body: JSON.stringify(event) }); - return res.text(); - } catch (error) { - console.log('[events] Error sending event data to webhook', to, JSON.stringify(error)); - return; + + if (response.status < 200 || response.status >= 300) { + throw new Error(`Code ${response.status}: ${response.statusText}`); + } + + return true; + } catch (error: any) { + console.log( + '[events] Error sending event data to webhook, will retry or fail', + to, + error.toString(), + JSON.stringify(error) + ); + throw error; } }; From db8fb625a18801523970b2a604bf9732d0f85743 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:45:50 +0400 Subject: [PATCH 10/17] feat: handle errors and retry on push notification errors --- .env.example | 1 + src/helpers/beams.ts | 28 +++++++++------------ src/queues/processors/notifications/push.ts | 12 ++++++++- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.env.example b/.env.example index d713b97..710c444 100644 --- a/.env.example +++ b/.env.example @@ -7,4 +7,5 @@ SERVICE_PUSH_NOTIFICATIONS= SERVICE_PUSHER_BEAMS_INSTANCE_ID= SERVICE_PUSHER_BEAMS_SECRET_KEY= HUB_URL= +SNAPSHOT_URI= REDIS_URL= diff --git a/src/helpers/beams.ts b/src/helpers/beams.ts index fc6a3a6..724b74e 100644 --- a/src/helpers/beams.ts +++ b/src/helpers/beams.ts @@ -2,22 +2,18 @@ import PushNotifications from '@pusher/push-notifications-server'; import type { Event } from '../types'; export const sendPushNotification = async (event: Event, proposalTitle: string, to: string[]) => { - try { - const beams = new PushNotifications({ - instanceId: process.env.SERVICE_PUSHER_BEAMS_INSTANCE_ID ?? '', - secretKey: process.env.SERVICE_PUSHER_BEAMS_SECRET_KEY ?? '' - }); + const beams = new PushNotifications({ + instanceId: process.env.SERVICE_PUSHER_BEAMS_INSTANCE_ID ?? '', + secretKey: process.env.SERVICE_PUSHER_BEAMS_SECRET_KEY ?? '' + }); - await beams.publishToInterests(to, { - web: { - notification: { - title: event.space, - body: proposalTitle, - deep_link: `${process.env.SNAPSHOT_URI}/#/${event.space}/${event.id}` - } + await beams.publishToInterests(to, { + web: { + notification: { + title: event.space, + body: proposalTitle, + deep_link: `${process.env.SNAPSHOT_URI}/#/${event.space}/${event.id}` } - }); - } catch (e) { - console.log('[events] Error sending push notification', e); - } + } + }); }; diff --git a/src/queues/processors/notifications/push.ts b/src/queues/processors/notifications/push.ts index 1ba1fe0..2b98698 100644 --- a/src/queues/processors/notifications/push.ts +++ b/src/queues/processors/notifications/push.ts @@ -9,5 +9,15 @@ export default async (job: Job) => { proposalTitle }: { event: Event; to: string[]; proposalTitle: Proposal['title'] } = job.data; - sendPushNotification(event, proposalTitle, to); + try { + await sendPushNotification(event, proposalTitle, to); + } catch (error: any) { + console.log( + '[worker:push] Error sending notification, will retry or fail', + to, + error.toString(), + JSON.stringify(error) + ); + throw error; + } }; From 139eeaa6a4db59b8147ff0321a0e80935df7e49d Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 21:04:55 +0400 Subject: [PATCH 11/17] fix: fix missing field for NOT NULL column --- src/discord.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/discord.ts b/src/discord.ts index 45a2d79..a39c840 100644 --- a/src/discord.ts +++ b/src/discord.ts @@ -229,9 +229,9 @@ async function snapshotCommandHandler(interaction, commandType) { const spaceExist = await checkSpace(space); if (!spaceExist) return interaction.reply(`Space not found: ${inlineCode(space)}`); - const subscription = [interaction.guildId, channelId, space, mention || '', ts]; + const subscription = [interaction.guildId, channelId, space, mention || '', ts, ts]; await db.queryAsync( - `INSERT INTO subscriptions (guild, channel, space, mention, created) VALUES (?, ?, ?, ?, ?) + `INSERT INTO subscriptions (guild, channel, space, mention, created, updated) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE guild = ?, channel = ?, space = ?, mention = ?, updated = ?`, [...subscription, ...subscription] ); From 237435cbd9a931a33f5e00daa9ec0a79cb8a2ab3 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:11:49 +0400 Subject: [PATCH 12/17] chore: improve console logging --- src/events.ts | 38 ++++++++++--------- src/helpers/snapshot.ts | 4 +- src/queues/index.ts | 14 +++---- src/queues/processors/events.ts | 2 +- src/queues/processors/notifications/http.ts | 2 +- .../processors/{messages.ts => replay.ts} | 2 +- src/replay.ts | 20 ++++++---- 7 files changed, 45 insertions(+), 37 deletions(-) rename src/queues/processors/{messages.ts => replay.ts} (58%) diff --git a/src/events.ts b/src/events.ts index bdf6c09..8c42626 100644 --- a/src/events.ts +++ b/src/events.ts @@ -11,16 +11,15 @@ import type { Event, Subscriber, Proposal } from './types'; const DELAY = 5; async function queueHttpNotifications(event: Event) { + console.log(`[events] -- [queue][http]: Start`); const subscribers = (await db.queryAsync('SELECT * FROM subscribers')) as Subscriber[]; - console.log('[events] Subscribers', subscribers.length); const data = subscribers .filter(subscriber => [event.space, '*'].includes(subscriber.space)) .map(subscriber => ({ name: 'http', data: { event, to: subscriber.url } })); httpNotificationsQueue.addBulk(data); - - console.log('[events] Process event queued'); + console.log(`[events] -- [queue][http]: End, queued ${subscribers.length} jobs`); } async function queuePushNotifications(event: Event, proposal: Proposal) { @@ -31,6 +30,7 @@ async function queuePushNotifications(event: Event, proposal: Proposal) { return; } + console.log(`[events] -- [queue][push]: Start`); const subscribedWallets = await getSubscribers(event.space); const walletsChunks = chunk(subscribedWallets, 100); @@ -39,33 +39,35 @@ async function queuePushNotifications(event: Event, proposal: Proposal) { }); pushNotificationsQueue.addBulk(data); + console.log(`[events] -- [queue][push]: End, queued ${walletsChunks.length} jobs`); } async function queueDiscordNotifications(event: Event, proposal: Proposal) { + console.log(`[events] -- [queue][discord]: Start`); discordNotificationsQueue.add('discord', { event, proposalId: proposal.id }); + console.log(`[events] -- [queue][discord]: End, queued 1 job`); } async function processEvents() { const ts = parseInt((Date.now() / 1e3).toFixed()) - DELAY; const events = (await db.queryAsync('SELECT * FROM events WHERE expire <= ?', [ts])) as Event[]; - - console.log('[events] Process event start', ts, events.length); + console.log(`[events] - PROCESS: Process ${events.length} events, at ${ts}`); for (const event of events) { const proposalId = event.id.replace('proposal/', ''); if (event.event === 'proposal/end') { try { const scores = await getProposalScores(proposalId); - console.log('[events] Stored scores on proposal/end', proposalId, scores); + console.log('[events] - Stored scores on proposal/end', proposalId, scores); } catch (e) { - console.log('[events] getProposalScores failed:', e); + console.log('[events] - getProposalScores failed:', e); } } - const proposal = await getProposal(event.id.replace('proposal/', '')); + const proposal = await getProposal(proposalId); if (!proposal) { - console.log('[events] Proposal not found', event.id); - return; + console.log('[events] - Proposal not found', proposalId); + continue; } queuePushNotifications(event, proposal); @@ -77,17 +79,19 @@ async function processEvents() { event.id, event.event ]); - console.log(`[events] Events jobs queued ${event.id} ${event.event}`); + console.log(`[events] - Popping events ${event.id} ${event.event} from the DB`); } catch (e) { - console.log('[events]', e); + console.log( + `[events] - Error while popping events ${event.id} ${event.event} from the DB`, + e + ); } } + console.log('[events] - PROCESS: End'); } export async function run() { - try { - await processEvents(); - } catch (e) { - console.log('[events] Failed to process', e); - } + console.log('[events] RUN: Start'); + await processEvents(); + console.log('[events] RUN: End'); } diff --git a/src/helpers/snapshot.ts b/src/helpers/snapshot.ts index 74d5c56..853024e 100644 --- a/src/helpers/snapshot.ts +++ b/src/helpers/snapshot.ts @@ -29,7 +29,7 @@ export async function getProposal(id: string) { }; const result = await snapshot.utils.subgraphRequest(`${hubURL}/graphql`, query); if (result.errors) { - throw new Error(`[events] Errors in subgraph request for proposal id: ${id}`); + throw new Error(`Errors in subgraph request for proposal id: ${id}`); } return result.proposal as Proposal; } @@ -91,7 +91,7 @@ export async function getSubscribers(space: string) { const result = await snapshot.utils.subgraphRequest('https://hub.snapshot.org/graphql', query); subscriptions = result.subscriptions || []; } catch (error) { - console.log('[events] Snapshot hub error:', error); + console.log('Snapshot hub error:', error); } return subscriptions.map(subscription => subscription.address as string); } diff --git a/src/queues/index.ts b/src/queues/index.ts index f3688d0..17af1ff 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -1,7 +1,7 @@ import 'dotenv/config'; import { Queue, Worker } from 'bullmq'; import Redis from 'ioredis'; -import messagesProcessor from './processors/messages'; +import replayProcessor from './processors/replay'; import eventsProcessor from './processors/events'; import HttpNotificationsProcessor from './processors/notifications/http'; import PushNotificationsProcessor from './processors/notifications/push'; @@ -9,7 +9,7 @@ import DiscordNotificationsProcessor from './processors/notifications/discord'; const connection = new Redis(process.env.REDIS_URL as string); -export const messagesQueue = new Queue('messages', { connection }); +export const replayQueue = new Queue('replay', { connection }); export const eventsQueue = new Queue('events', { connection }); export const httpNotificationsQueue = new Queue('notifications-http', { connection, @@ -42,7 +42,7 @@ export const discordNotificationsQueue = new Queue('notifications-discord', { } }); -let messagesWorker: Worker; +let replayWorker: Worker; let eventsWorker: Worker; let httpChannelWorker: Worker; let pushChannelWorker: Worker; @@ -51,7 +51,7 @@ let discordChannelWorker: Worker; export async function start() { console.log('[queue] Starting queue'); - messagesWorker = new Worker(messagesQueue.name, messagesProcessor, { connection }); + replayWorker = new Worker(replayQueue.name, replayProcessor, { connection }); eventsWorker = new Worker(eventsQueue.name, eventsProcessor, { connection }); httpChannelWorker = new Worker(httpNotificationsQueue.name, HttpNotificationsProcessor, { connection @@ -63,8 +63,8 @@ export async function start() { connection }); - await messagesQueue.add( - 'messages-reader', + await replayQueue.add( + 'replay', {}, { repeat: { @@ -87,7 +87,7 @@ export async function start() { async function shutdown() { console.log('[queue] Starting queue shutdown'); await Promise.all([ - messagesWorker.close(), + replayWorker.close(), eventsWorker.close(), httpChannelWorker.close(), pushChannelWorker.close(), diff --git a/src/queues/processors/events.ts b/src/queues/processors/events.ts index 5198358..08feb70 100644 --- a/src/queues/processors/events.ts +++ b/src/queues/processors/events.ts @@ -2,7 +2,7 @@ import { run } from '../../events'; export default async () => { if (process.env.SERVICE_EVENT || '0') { - console.log('[queue] Running "events" processor'); + console.log('[queue] == Running "events" processor =='); await run(); } }; diff --git a/src/queues/processors/notifications/http.ts b/src/queues/processors/notifications/http.ts index 0004722..6fda94a 100644 --- a/src/queues/processors/notifications/http.ts +++ b/src/queues/processors/notifications/http.ts @@ -24,7 +24,7 @@ export default async (job: Job) => { return true; } catch (error: any) { console.log( - '[events] Error sending event data to webhook, will retry or fail', + '[worker:http] Error sending notification, will retry or fail', to, error.toString(), JSON.stringify(error) diff --git a/src/queues/processors/messages.ts b/src/queues/processors/replay.ts similarity index 58% rename from src/queues/processors/messages.ts rename to src/queues/processors/replay.ts index 7b5b2e9..248314d 100644 --- a/src/queues/processors/messages.ts +++ b/src/queues/processors/replay.ts @@ -1,6 +1,6 @@ import { run } from '../../replay'; export default async () => { - console.log('[queue] Running "messages" processor'); + console.log('[queue] == Running "replay" processor =='); await run(); }; diff --git a/src/replay.ts b/src/replay.ts index bc8705f..1f6c4bf 100644 --- a/src/replay.ts +++ b/src/replay.ts @@ -3,11 +3,12 @@ import { getProposal, getNextMessages, getIpfsData } from './helpers/snapshot'; import type { Message, Event } from './types'; const handleCreatedEvent = async (event: Pick) => { + console.log(`[relay] -- Inserting new event in DB`); const { space, id } = event; const proposalId = id.replace('proposal/', '') || ''; const proposal = await getProposal(proposalId); if (!proposal) { - console.log(`[events] Proposal not found ${proposalId}`); + console.log(`[relay] -- Proposal not found ${proposalId}`); return; } @@ -42,6 +43,7 @@ const handleCreatedEvent = async (event: Pick) => { }; const handleDeletedEvent = async (event: Partial, ipfs: string) => { + console.log(`[relay] -- Removing deleted event from DB`); const ipfsData = await getIpfsData(ipfs); const proposalId = ipfsData.data.message.proposal; @@ -67,16 +69,18 @@ async function updateLastMci(mci: number) { } async function processMessages(messages: Message[]) { + console.log(`[replay] - PROCESS: Process ${messages.length} messages`); let lastMessageMci: number | null = null; + for (const message of messages) { try { if (message.type === 'proposal') { - console.log('New event: "proposal"', message.space, message.id); + console.log('[replay] - New event: "proposal"', message.space, message.id); await handleCreatedEvent({ id: `proposal/${message.id}`, space: message.space }); } if (message.type === 'delete-proposal') { - console.log('New event: "delete-proposal"', message.space, message.id); + console.log('[replay] - New event: "delete-proposal"', message.space, message.id); await handleDeletedEvent( { space: message.space @@ -91,21 +95,21 @@ async function processMessages(messages: Message[]) { } } if (lastMessageMci !== null) { - // Store latest message MCI await updateLastMci(lastMessageMci); - console.log('[replay] Updated to MCI', lastMessageMci); + console.log(`[replay] - Updated lastMCI to ${lastMessageMci}`); } - return; + console.log('[replay] - PROCESS: End'); } export async function run() { // Check latest indexed MCI from db const lastMci = await getLastMci(); - console.log('[replay] Last MCI', lastMci); + console.log(`[replay] RUN: Start from MCI ${lastMci}`); - // Load next messages after latest indexed MCI const messages = await getNextMessages(lastMci); + console.log(`[replay] Found ${messages.length} new messages`); if (messages.length > 0) { await processMessages(messages); } + console.log('[replay] RUN: End'); } From 6e71d34f248e27df1d189b1e004c44409d991b54 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:41:34 +0400 Subject: [PATCH 13/17] fix: start discord bot explicitly --- src/discord.ts | 11 ++++------- src/index.ts | 1 - src/queue.ts | 7 +++++-- src/queues/index.ts | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/discord.ts b/src/discord.ts index a408079..e8cfa94 100644 --- a/src/discord.ts +++ b/src/discord.ts @@ -88,9 +88,9 @@ const commands = [ ) ]; -const rest = new REST({ version: '10' }).setToken(token); +export async function start() { + const rest = new REST({ version: '10' }).setToken(token); -(async () => { try { console.log('Started refreshing application (/) commands.'); await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands }); @@ -98,10 +98,9 @@ const rest = new REST({ version: '10' }).setToken(token); } catch (error) { console.error(error); } -})(); - -client.login(token); + client.login(token); +} export const setActivity = (message, url?) => { try { client.user.setActivity(message, { type: 'WATCHING', url }); @@ -346,5 +345,3 @@ export const sendEventToDiscordSubscribers = async (event, proposalId) => { } return { success: true }; }; - -export default client; diff --git a/src/index.ts b/src/index.ts index 361b080..6377238 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,6 @@ import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import api from './api'; -import './discord'; const app = express(); const PORT = process.env.PORT || 3000; diff --git a/src/queue.ts b/src/queue.ts index 0fb5a3c..24034aa 100644 --- a/src/queue.ts +++ b/src/queue.ts @@ -1,3 +1,6 @@ -import { start } from './queues'; +import 'dotenv/config'; +import { start as startQueue } from './queues'; +import { start as startDiscord } from './discord'; -start(); +startQueue(); +startDiscord(); diff --git a/src/queues/index.ts b/src/queues/index.ts index 17af1ff..0e85074 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -1,4 +1,3 @@ -import 'dotenv/config'; import { Queue, Worker } from 'bullmq'; import Redis from 'ioredis'; import replayProcessor from './processors/replay'; From 1e6ad81a09b2c80840898f16db6ca3b572169524 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:42:00 +0400 Subject: [PATCH 14/17] fix: events from unknown proposal should be removed --- src/events.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/events.ts b/src/events.ts index 8c42626..638c41e 100644 --- a/src/events.ts +++ b/src/events.ts @@ -67,13 +67,12 @@ async function processEvents() { const proposal = await getProposal(proposalId); if (!proposal) { console.log('[events] - Proposal not found', proposalId); - continue; + } else { + queuePushNotifications(event, proposal); + queueHttpNotifications(event); + queueDiscordNotifications(event, proposal); } - queuePushNotifications(event, proposal); - queueHttpNotifications(event); - queueDiscordNotifications(event, proposal); - try { await db.queryAsync('DELETE FROM events WHERE id = ? AND event = ? LIMIT 1', [ event.id, From e7b59b80e4f959a7db69ed645f212e152c63b50c Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:53:11 +0400 Subject: [PATCH 15/17] feat: retry on discord errors --- src/discord.ts | 12 ++++++------ src/queues/processors/notifications/discord.ts | 11 ++++++++++- src/{queue.ts => runner.ts} | 0 3 files changed, 16 insertions(+), 7 deletions(-) rename src/{queue.ts => runner.ts} (100%) diff --git a/src/discord.ts b/src/discord.ts index e8cfa94..7fe84eb 100644 --- a/src/discord.ts +++ b/src/discord.ts @@ -89,17 +89,17 @@ const commands = [ ]; export async function start() { - const rest = new REST({ version: '10' }).setToken(token); - try { + const rest = new REST({ version: '10' }).setToken(token); + console.log('Started refreshing application (/) commands.'); await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands }); console.log('Successfully reloaded application (/) commands.'); - } catch (error) { - console.error(error); - } - client.login(token); + client.login(token); + } catch (e) { + console.log('Unable to start discord bot', e); + } } export const setActivity = (message, url?) => { try { diff --git a/src/queues/processors/notifications/discord.ts b/src/queues/processors/notifications/discord.ts index 22c195e..37e0444 100644 --- a/src/queues/processors/notifications/discord.ts +++ b/src/queues/processors/notifications/discord.ts @@ -5,5 +5,14 @@ import type { Event, Proposal } from '../../../types'; export default async (job: Job) => { const { event, proposalId }: { event: Event; proposalId: Proposal['id'] } = job.data; - sendEventToDiscordSubscribers(event.event, proposalId); + try { + sendEventToDiscordSubscribers(event.event, proposalId); + } catch (error: any) { + console.log( + '[worker:discord] Error sending notification, will retry or fail', + error.toString(), + JSON.stringify(error) + ); + throw error; + } }; diff --git a/src/queue.ts b/src/runner.ts similarity index 100% rename from src/queue.ts rename to src/runner.ts From 77fede944712d634981913c01246a2ac4749e110 Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:58:01 +0400 Subject: [PATCH 16/17] fix: fix deprecation warning --- src/queues/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queues/index.ts b/src/queues/index.ts index 0e85074..f62e615 100644 --- a/src/queues/index.ts +++ b/src/queues/index.ts @@ -6,7 +6,7 @@ import HttpNotificationsProcessor from './processors/notifications/http'; import PushNotificationsProcessor from './processors/notifications/push'; import DiscordNotificationsProcessor from './processors/notifications/discord'; -const connection = new Redis(process.env.REDIS_URL as string); +const connection = new Redis(process.env.REDIS_URL as string, { maxRetriesPerRequest: null }); export const replayQueue = new Queue('replay', { connection }); export const eventsQueue = new Queue('events', { connection }); From e3c97234aa1dcaff16596cc9bdfcac10920b6c1f Mon Sep 17 00:00:00 2001 From: Wan Qi Chen <495709+wa0x6e@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:03:19 +0400 Subject: [PATCH 17/17] feat: run express and background task in different processes --- package.json | 5 ++- yarn.lock | 102 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 734ada0..d5a2e07 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "lint": "eslint . --ext .ts --fix", "typecheck": "tsc --noEmit", "build": "tsc", - "dev": "nodemon src/index.ts", - "start": "node dist/src/index.js" + "dev": "concurrently --n express,runner \"nodemon src/index.ts\" \"nodemon src/runner.ts\"", + "start": "concurrently --n express,runner \"node dist/src/index.js\" \"node dist/src/runner.js\"" }, "eslintConfig": { "extends": "@snapshot-labs" @@ -18,6 +18,7 @@ "@snapshot-labs/snapshot.js": "^0.3.68", "bluebird": "^3.7.2", "bullmq": "^3.12.0", + "concurrently": "^8.0.1", "connection-string": "^1.0.1", "cors": "^2.8.5", "discord.js": "^14.3.0", diff --git a/yarn.lock b/yarn.lock index 9b00357..b87ab2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1049,7 +1049,7 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1082,6 +1082,15 @@ cli-boxes@^2.2.1: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -1111,6 +1120,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +concurrently@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.0.1.tgz#80c0591920a9fa3e68ba0dd8aa6eac8487eb904c" + integrity sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA== + dependencies: + chalk "^4.1.2" + date-fns "^2.29.3" + lodash "^4.17.21" + rxjs "^7.8.0" + shell-quote "^1.8.0" + spawn-command "0.0.2-1" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.1" + configstore@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -1196,6 +1220,11 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +date-fns@^2.29.3: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1359,6 +1388,11 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -1647,6 +1681,11 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -2671,6 +2710,11 @@ remove-markdown@^0.3.0: resolved "https://registry.yarnpkg.com/remove-markdown/-/remove-markdown-0.3.0.tgz#5e4b667493a93579728f3d52ecc1db9ca505dc98" integrity sha1-XktmdJOpNXlyjz1S7MHbnKUF3Jg= +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -2707,6 +2751,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -2804,6 +2855,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.8.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -2814,6 +2870,11 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +spawn-command@0.0.2-1: + version "0.0.2-1" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" + integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== + sqlstring@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" @@ -2847,7 +2908,7 @@ string-width@^4.0.0, string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string-width@^4.2.2: +string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2923,6 +2984,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2960,6 +3028,11 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + ts-mixer@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ts-mixer/-/ts-mixer-6.0.1.tgz#7c2627fb98047eb5f3c7f2fee39d1521d18fe87a" @@ -2989,7 +3062,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0: +tslib@^2.0.0, tslib@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== @@ -3177,11 +3250,34 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.1: + version "17.7.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" + integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"