From 18e63749aadeece022d8d21cc0ed9184ec04a7af Mon Sep 17 00:00:00 2001 From: "Sophia (Turner)" Date: Fri, 1 Nov 2024 01:36:34 +0900 Subject: [PATCH] fix(twitter): make twitter watcher to use rettiwt-api package instead of official one (#4) --- .github/workflows/ci.yml | 2 +- .github/workflows/docker-deploy.yml | 2 +- Dockerfile | 6 +- config.schema.json | 4 +- package.json | 3 +- src/watchers/twitter/index.ts | 40 ++++---- yarn.lock | 141 +++++++++++++++++++++++----- 7 files changed, 145 insertions(+), 53 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a8608f..5e01eb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Install and Build uses: actions/setup-node@v3 with: - node-version: "18.x" + node-version: "22.x" - name: Install yarn run: | diff --git a/.github/workflows/docker-deploy.yml b/.github/workflows/docker-deploy.yml index 53c6dff..72c3bed 100644 --- a/.github/workflows/docker-deploy.yml +++ b/.github/workflows/docker-deploy.yml @@ -29,7 +29,7 @@ jobs: - name: Install and Build uses: actions/setup-node@v3 with: - node-version: "18.x" + node-version: "22.x" - name: Install yarn run: | diff --git a/Dockerfile b/Dockerfile index 288708d..9f75887 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine as builder +FROM node:22-alpine as builder RUN apk add --update --no-cache curl git openssh openssl @@ -18,7 +18,7 @@ ENV NODE_ENV ${NODE_ENV} RUN ["yarn", "build"] -FROM node:18-alpine as prod-deps +FROM node:22-alpine as prod-deps USER node WORKDIR /home/node @@ -35,7 +35,7 @@ ENV NODE_ENV ${NODE_ENV} CMD [ "node", "dist/src/index" ] -FROM node:18-alpine as production +FROM node:22-alpine as production USER node WORKDIR /home/node diff --git a/config.schema.json b/config.schema.json index e03b841..f42106a 100644 --- a/config.schema.json +++ b/config.schema.json @@ -18,7 +18,7 @@ "type": "string", "const": "twitter" }, - "bearerToken": { + "apiKey": { "type": "string" }, "username": { @@ -26,7 +26,7 @@ } }, "required": [ - "bearerToken", + "apiKey", "type", "username" ], diff --git a/package.json b/package.json index 192e9ec..955bd0d 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "@atproto/api": "^0.3.13", "@octokit/rest": "^19.0.5", "@slack/webhook": "^6.1.0", - "@twitter-api-v2/plugin-rate-limit": "^1.1.0", "@urql/core": "^3.0.5", "ajv": "^8.11.2", "better-ajv-errors": "^1.2.0", @@ -97,10 +96,10 @@ "pluralize": "^8.0.0", "pretty-ms": "^7.0.1", "reflect-metadata": "^0.1.13", + "rettiwt-api": "^4.1.4", "set-cookie-parser": "^2.5.1", "sqlite3": "^5.1.2", "strip-ansi": "^6.0.1", - "twitter-api-v2": "^1.12.9", "typeorm": "^0.3.10", "update-notifier": "^5.1.0" } diff --git a/src/watchers/twitter/index.ts b/src/watchers/twitter/index.ts index a7055a8..73eaeb7 100644 --- a/src/watchers/twitter/index.ts +++ b/src/watchers/twitter/index.ts @@ -1,29 +1,26 @@ -import { TwitterApi, TwitterApiReadOnly } from "twitter-api-v2"; -import { TwitterApiRateLimitPlugin } from "@twitter-api-v2/plugin-rate-limit"; +import { Cursor, Rettiwt, User } from "rettiwt-api"; import { BaseWatcher, BaseWatcherOptions, PartialUser } from "@watchers/base"; export interface TwitterWatcherOptions extends BaseWatcherOptions { - bearerToken: string; + apiKey: string; username: string; } export class TwitterWatcher extends BaseWatcher<"Twitter"> { - private readonly twitterClient: TwitterApiReadOnly; + private readonly twitterClient: Rettiwt; private readonly currentUserName: string; + private currentUserId: string | null = null; - public constructor({ bearerToken, username }: TwitterWatcherOptions) { + public constructor({ apiKey, username }: TwitterWatcherOptions) { super("Twitter"); - this.twitterClient = new TwitterApi(bearerToken, { plugins: [new TwitterApiRateLimitPlugin()] }).readOnly; + this.twitterClient = new Rettiwt({ apiKey }); this.currentUserName = username; } public async initialize() { - const { data } = await this.twitterClient.v2.userByUsername(this.currentUserName, { - "user.fields": ["id"], - }); - + const data = await this.twitterClient.user.details(this.currentUserName); if (!data) { throw new Error("Failed to get user id"); } @@ -37,16 +34,23 @@ export class TwitterWatcher extends BaseWatcher<"Twitter"> { throw new Error("Watcher is not initialized"); } - const followers = await this.twitterClient.v2.followers(this.currentUserId, { - max_results: 1000, - "user.fields": ["id", "name", "username", "profile_image_url"], - }); + const users: User[] = []; + let cursor: Cursor | null = null; + while (true) { + const followers = await this.twitterClient.user.followers(this.currentUserId, 100, cursor?.value); + if (!followers.next.value || followers.list.length === 0) { + break; + } + + users.push(...followers.list); + cursor = followers.next; + } - return followers.data.map(user => ({ + return users.map(user => ({ uniqueId: user.id, - displayName: user.name, - userId: user.username, - profileUrl: `https://twitter.com/${user.username}`, + displayName: user.fullName, + userId: user.userName, + profileUrl: `https://twitter.com/${user.userName}`, })); } } diff --git a/yarn.lock b/yarn.lock index 4de5fff..4bea677 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2102,11 +2102,6 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== -"@twitter-api-v2/plugin-rate-limit@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@twitter-api-v2/plugin-rate-limit/-/plugin-rate-limit-1.1.0.tgz#a80bbc86f4629575c13ab2f688dafe8b7eb05058" - integrity sha512-5nUk0w0s1yzzMe+NLN5BlKzwgl9OHkF1Makb5Xje1ntCO1H1fGq0qli80WRvcrpcwKZcSckRkXd4HEksh2LZ6g== - "@types/babel__core@^7.1.14": version "7.1.19" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" @@ -2333,6 +2328,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/validator@^13.11.8": + version "13.12.2" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5" + integrity sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA== + "@types/ws@^8.0.0": version "8.5.3" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" @@ -2511,6 +2511,13 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" @@ -2726,6 +2733,15 @@ auto-bind@~4.0.0: resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== +axios@1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.3.tgz#7f50f23b3aa246eff43c54834272346c396613f4" + integrity sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axios@^0.21.4: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -3130,6 +3146,14 @@ cardinal@^2.1.1: ansicolors "~0.3.2" redeyed "~2.1.0" +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, 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== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0, chalk@^2.3.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3139,14 +3163,6 @@ chalk@^2.0.0, chalk@^2.3.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, 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== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.1.0.tgz#c4b4a62bfb6df0eeeb5dbc52e6a9ecaff14b9976" @@ -3243,6 +3259,15 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +class-validator@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.1.tgz#ff2411ed8134e9d76acfeb14872884448be98110" + integrity sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ== + dependencies: + "@types/validator" "^13.11.8" + libphonenumber-js "^1.10.53" + validator "^13.9.0" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3417,6 +3442,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + commander@^9.0.0, commander@^9.4.0, commander@^9.4.1: version "9.4.1" resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" @@ -3535,6 +3565,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookiejar@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -4275,24 +4310,29 @@ follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.15.0: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + form-data-encoder@^1.7.1: version "1.7.2" resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== +form-data@4.0.0, form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -4704,6 +4744,14 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +https-proxy-agent@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -5870,6 +5918,11 @@ libnpmversion@^3.0.7: proc-log "^2.0.0" semver "^7.3.7" +libphonenumber-js@^1.10.53: + version "1.11.12" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.12.tgz#e108a4632048255f30b872bb1abbb3356f290fbb" + integrity sha512-QkJn9/D7zZ1ucvT++TQSvZuSA2xAWeUytU+DiEQwbPKLyrDpvbul2AFs1CGbRAPpSCCk47aRAb5DX5mmcayp4g== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -7260,6 +7313,11 @@ promzard@^0.3.0: dependencies: read "1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -7566,6 +7624,37 @@ retry@^0.13.1: resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== +rettiwt-api@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/rettiwt-api/-/rettiwt-api-4.1.4.tgz#76d0eba3c86eb3fc2c4c27f7a1ce78d52dc857de" + integrity sha512-0NXu6KOy8iPiGHreib2cu8Uf7OWGMgiyR87KT9XkLRr5eiKgbVZxdq+Rv13CYLUJhiTz3qVNYPy5ai6wZR6shg== + dependencies: + axios "1.6.3" + chalk "4.1.2" + class-validator "0.14.1" + commander "11.1.0" + https-proxy-agent "7.0.2" + rettiwt-auth "2.1.0" + rettiwt-core "4.3.3" + +rettiwt-auth@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/rettiwt-auth/-/rettiwt-auth-2.1.0.tgz#43fedd40cab5b775b92a1bef740d7b2a36553463" + integrity sha512-N3G1kX/4TFYvUumxcACHO9ngVnhM+DhpuRn2/JxWlgHuztAQShbO9ux3hfMducCqzzjdcMLPJhrEDt9fwSbpaQ== + dependencies: + axios "1.6.3" + commander "11.1.0" + cookiejar "2.1.4" + https-proxy-agent "7.0.2" + +rettiwt-core@4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/rettiwt-core/-/rettiwt-core-4.3.3.tgz#5cf00d624aef804391415e3993ead539154b7125" + integrity sha512-3GCCqsQSVn259vTSSkgL/lMQZtfmkNNffuIZfAHl/0xSzXbhTlrGySQGuRE+XU3ceESaMdQfxN7q2UhXNa8eaQ== + dependencies: + axios "1.6.3" + form-data "4.0.0" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -8355,11 +8444,6 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -twitter-api-v2@^1.12.9: - version "1.12.9" - resolved "https://registry.yarnpkg.com/twitter-api-v2/-/twitter-api-v2-1.12.9.tgz#447fc4efb693bbb7983a6dcec2de5da7e0f27648" - integrity sha512-nmKwcUiXgoEfcOtAH/hYojy0oSxbouWvvNsHVphiHSW9x9aus2Jdg9/NRB2Gzyq5G6xl+EkjUlEWwBQjp1FOfg== - 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" @@ -8640,6 +8724,11 @@ validate-npm-package-name@^4.0.0: dependencies: builtins "^5.0.0" +validator@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== + value-or-promise@1.0.11, value-or-promise@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140"