diff --git a/deployment/features/deployment.yaml b/deployment/features/deployment.yaml index d790edb..0765b2d 100644 --- a/deployment/features/deployment.yaml +++ b/deployment/features/deployment.yaml @@ -14,10 +14,10 @@ spec: app: subid-back- spec: imagePullSecrets: - - name: dockerhub + - name: dockerhub containers: - name: subid-back- - image: + image: imagePullPolicy: IfNotPresent ports: - containerPort: 3001 @@ -37,6 +37,15 @@ spec: value: redis-master.default - name: REDIS_PORT value: '6379' + + - name: AGGREGATOR_REDIS_HOST + value: redis-aggregation-datasource-subquery-master.default + - name: AGGREGATOR_REDIS_PASSWORD + value: 2KK6RWECApEZJjmd + - name: AGGREGATOR_REDIS_PREFIX + value: aggregator_queue_datasource-subquery + - name: AGGREGATOR_REDIS_PORT + value: '6379' envFrom: - secretRef: name: subid-back-secret diff --git a/package.json b/package.json index cc55f05..2eda49a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "devDependencies": { "@subsocial/config": "0.7.7", "@types/bn.js": "^5.1.0", + "@types/bull": "^4.10.0", "@types/connect-timeout": "^0.0.34", "@types/cors": "^2.8.6", "@types/express": "^4.17.3", @@ -45,6 +46,7 @@ "@polkawallet/bridge": "0.1.3", "@subsocial/api": "0.8.14", "axios": "^0.26.0", + "bull": "^4.11.4", "connect-timeout": "^1.9.0", "cors": "^2.8.5", "dayjs": "^1.10.4", diff --git a/src/constant/graphQlClients.ts b/src/constant/graphQlClients.ts index b5bc611..e4b0061 100644 --- a/src/constant/graphQlClients.ts +++ b/src/constant/graphQlClients.ts @@ -4,17 +4,30 @@ import { RelayChain } from '../services/crowdloan/types' export const subsocialGraphQlClient = new GraphQLClient(SUBSOCIAL_GRAPHQL_CLIENT) -export const soonsocialGraphQlClient = new GraphQLClient('https://squid.subsquid.io/soonsocial/graphql') +export const soonsocialGraphQlClient = new GraphQLClient( + 'https://squid.subsquid.io/soonsocial/graphql' +) -export const contributionsClientByRelay: Record = { +export const txAggregatorGraphQlClient = new GraphQLClient( + 'https://tx-aggregation.subsocial.network/graphql' +) + +export const contributionsClientByRelay: Record< + RelayChain, + { client: GraphQLClient; addressPrefix: number } +> = { kusama: { - client: new GraphQLClient('https://squid.subsquid.io/kusama-explorer/graphql', { timeout: 4000 }), + client: new GraphQLClient('https://squid.subsquid.io/kusama-explorer/graphql', { + timeout: 4000 + }), addressPrefix: 2 }, polkadot: { - client: new GraphQLClient('https://squid.subsquid.io/polkadot-explorer/graphql', { timeout: 4000 }), + client: new GraphQLClient('https://squid.subsquid.io/polkadot-explorer/graphql', { + timeout: 4000 + }), addressPrefix: 0 } } -export const quartzClient = new GraphQLClient(QUARTZ_GRAPHQL_CLIENT) \ No newline at end of file +export const quartzClient = new GraphQLClient(QUARTZ_GRAPHQL_CLIENT) diff --git a/src/routes/index.ts b/src/routes/index.ts index b1e9a82..17a39d7 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -18,6 +18,7 @@ import createFeesRouter from './fees' import { Connections } from '../connections' import createCreatorStakingRouter from './creatorStaking' import { isDef } from '@subsocial/utils'; +import createTxHistoryRouter from './txHistory' export const createRoutes = (apis: Connections) => { const router = Router() @@ -79,7 +80,7 @@ export const createRoutes = (apis: Connections) => { const result = balances.map((balance: any) => { const { status, value } = balance - return status === 'fulfilled' && value + return status === 'fulfilled' ? value : undefined }) res.send(result.filter(isDef)) @@ -151,6 +152,7 @@ export const createRoutes = (apis: Connections) => { router.use('/staking/collator', asyncErrorHandler(createCollatorStakingRouter(apis.mixedApis))) router.use('/staking/validator', asyncErrorHandler(createValidatorStakingRouter(apis))) router.use('/staking/creator', asyncErrorHandler(createCreatorStakingRouter(apis))) + router.use('/tx', asyncErrorHandler(createTxHistoryRouter())) router.use('/fees', asyncErrorHandler(createFeesRouter(apis.mixedApis))) diff --git a/src/routes/txHistory/index.ts b/src/routes/txHistory/index.ts new file mode 100644 index 0000000..01e39d0 --- /dev/null +++ b/src/routes/txHistory/index.ts @@ -0,0 +1,34 @@ +import { Router } from 'express' +import { getAccountTxHistory, getAccountTxHistoryWithQueue } from '../../services/txHistory' + +const createTxHistoryRouter = () => { + const router = Router() + + router.get('/history/queue', async function (req, res) { + const { address, pageSize, offset } = req.query + const txs = await getAccountTxHistoryWithQueue({ + address: address as string, + pageSize: parseInt(pageSize as string), + offset: parseInt(offset as string), + }) + + res.send(txs) + }) + + router.get('/history', async function (req, res) { + const { address, pageSize, offset, networks, events } = req.query + const txs = await getAccountTxHistory({ + address: address as string, + pageSize: parseInt(pageSize as string), + offset: parseInt(offset as string), + networks: networks as string[], + events: events as string[], + }) + + res.send(txs) + }) + + return router +} + +export default createTxHistoryRouter diff --git a/src/server.ts b/src/server.ts index 3154105..6b4b592 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,7 @@ import express from 'express' import cors from 'cors' import timeout from 'connect-timeout' -import { reqTimeoutSecs, allowedOrigins, port } from './constant/env' +import { reqTimeoutSecs, port, allowedOrigins } from './constant/env' import { newLogger } from '@subsocial/utils' import { createRoutes } from './routes' @@ -36,7 +36,7 @@ export const startHttpServer = (apis: Connections) => { }) ) - // For localhost testing + // For localhost testing // app.use( // cors((req, callback) => { // const origin = req.method === 'GET' ? '*' : '*' diff --git a/src/services/identity/getIdentityFromSquid.ts b/src/services/identity/getIdentityFromSquid.ts index e4f1285..8a4ccbb 100644 --- a/src/services/identity/getIdentityFromSquid.ts +++ b/src/services/identity/getIdentityFromSquid.ts @@ -4,7 +4,10 @@ import { identitiesInfoCache } from '.' import { toGenericAccountId } from '../utils' import { u8aToHex } from '@polkadot/util' import { getIdentityFromChain } from './getIdentityFromChain' -import { ApiPromise } from '@polkadot/api'; +import { ApiPromise } from '@polkadot/api' +import { newLogger } from '@subsocial/utils' + +const log = newLogger('Identity') const GET_IDENTITY = gql` query GetIdentity($ids: [String!]) { @@ -94,8 +97,8 @@ export const tryToGetIdentityFromSquid = async ( ) => { try { await getIdentityFromSquid(accounts, chain) - } catch { - console.error('Failed to get identity from squid, trying to get from chain') + } catch (e) { + log.warn('Failed to get identity from squid, trying to get from chain', e) await getIdentityFromChain(api, accounts, chain) } } diff --git a/src/services/txHistory/index.ts b/src/services/txHistory/index.ts new file mode 100644 index 0000000..1cbf3c7 --- /dev/null +++ b/src/services/txHistory/index.ts @@ -0,0 +1,110 @@ +import { gql } from 'graphql-request' +import { u8aToHex } from '@polkadot/util' +import { decodeAddress, isEthereumAddress } from '@polkadot/util-crypto' +import { getOrCreateQueue } from './queue' +import { txAggregatorGraphQlClient } from '../../constant/graphQlClients' + +const ADD_QUEUE_JOB_NAME = 'REFRESH_TX_HISTORY_FOR_ACCOUNT_ON_DEMAND' + +const buildGetAccountTxHistoryQuery = (networks?: string[], events?: string[]) => { + const networkFilterValues = networks ? ', blockchainTag: $networks' : '' + const networkFilterParams = networks ? ', $networks: [BlockchainTag!]' : '' + + const eventFilterValues = events ? ', txKind: $txKind' : '' + const eventFilterParams = events ? ', $txKind: [TransactionKind!]' : '' + + return gql` + query getAccountTxHistory($address: String!, $pageSize: Int!, $offset: Int! ${networkFilterParams}${eventFilterParams}) { + accountTxHistory( + args: { where: { publicKey: $address ${networkFilterValues}${eventFilterValues} }, pageSize: $pageSize, offset: $offset } + ) { + data { + id + txKind + blockchainTag + amount + senderOrTargetPublicKey + timestamp + success + transaction { + transferNative { + extrinsicHash + } + } + } + } + } + ` +} + +type GetAccountTransactionsWithQueue = { + address: string + pageSize: number + offset: number +} + +type GetAccountTransactions = GetAccountTransactionsWithQueue & { + networks?: string[] + events?: string[] +} + +export const getAccountTxHistory = async ({ + address, + pageSize, + offset, + networks, + events +}: GetAccountTransactions) => { + const networkFilterValues = networks + ? { networks: networks.map((network) => network.toUpperCase()) } + : {} + const eventsFilterValues = events ? { txKind: events.map((event) => event.toUpperCase()) } : {} + + const query = buildGetAccountTxHistoryQuery(networks, events) + + const txs = await txAggregatorGraphQlClient.request(query, { + address, + pageSize, + offset, + ...networkFilterValues, + ...eventsFilterValues + }) + + return txs?.accountTxHistory?.data +} + +export const getAccountTxHistoryWithQueue = async (props: GetAccountTransactionsWithQueue) => { + const txs = await getAccountTxHistory(props) + + const address = props.address + + const jobId = `${address}-${ADD_QUEUE_JOB_NAME}` + const queue = getOrCreateQueue() + const jobByAddress = await queue.getJob(jobId) + + let actualData = false + + if (jobByAddress) { + const jobState = await jobByAddress.getState() + + if (jobState === 'completed') { + jobByAddress.remove() + + actualData = true + } + } else { + const taskPayload = { + publicKey: isEthereumAddress(address) ? address : u8aToHex(decodeAddress(address)) + } + + queue.add(ADD_QUEUE_JOB_NAME, taskPayload, { + attempts: 5, + jobId, + removeOnComplete: false, + removeOnFail: true, + priority: 1 + }) + } + + return { txs, actualData } +} diff --git a/src/services/txHistory/queue.ts b/src/services/txHistory/queue.ts new file mode 100644 index 0000000..da1c17b --- /dev/null +++ b/src/services/txHistory/queue.ts @@ -0,0 +1,30 @@ +import Queue from 'bull' + +let queue = null + +export const getOrCreateQueue = () => { + if (!queue) { + const host = process.env.AGGREGATOR_REDIS_HOST + const password = process.env.AGGREGATOR_REDIS_PASSWORD + const port = process.env.AGGREGATOR_REDIS_PORT as unknown as number + + const aggregatorRedisConfig = { + host, + password, + port + } + + queue = new Queue('ACCOUNT_AGGREGATION_FLOW', { + redis: aggregatorRedisConfig, + prefix: process.env.AGGREGATOR_REDIS_PREFIX, + settings: { + lockDuration: 20000, // Check for stalled jobs each 2 min + lockRenewTime: 10000, + stalledInterval: 20 * 60 * 1000, + maxStalledCount: 1 + } + }) + } + + return queue +} diff --git a/yarn.lock b/yarn.lock index f93df1a..500aff9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -651,6 +651,36 @@ dependencies: lodash.merge "^4.6.2" +"@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== + "@noble/curves@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -2047,6 +2077,13 @@ "@types/connect" "*" "@types/node" "*" +"@types/bull@^4.10.0": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@types/bull/-/bull-4.10.0.tgz#176d7677af2a3df034df4b71daefd63c50a3e438" + integrity sha512-RkYW8K2H3J76HT6twmHYbzJ0GtLDDotpLP9ah9gtiA7zfF6peBH1l5fEiK0oeIZ3/642M7Jcb9sPmor8Vf4w6g== + dependencies: + bull "*" + "@types/caseless@*": version "0.12.2" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" @@ -2471,6 +2508,19 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" +bull@*, bull@^4.11.4: + version "4.11.4" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.11.4.tgz#e504fedb946a427cad67a387efb807d601201e16" + integrity sha512-6rPnFkUbN/eWhzGF65mcYM2HWDl2rp0fTidZ8en64Zwplioe/QxpdiWfLLtXX4Yy25piPly4f96wHR0NquiyyQ== + dependencies: + cron-parser "^4.2.1" + get-port "^5.1.1" + ioredis "^5.3.2" + lodash "^4.17.21" + msgpackr "^1.5.2" + semver "^7.5.2" + uuid "^8.3.0" + busboy@^0.2.11: version "0.2.14" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" @@ -2676,6 +2726,13 @@ create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" +cron-parser@^4.2.1: + version "4.9.0" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.9.0.tgz#0340694af3e46a0894978c6f52a6dbb5c0f11ad5" + integrity sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q== + dependencies: + luxon "^3.2.1" + cross-fetch@^3.0.6, cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" @@ -3277,6 +3334,11 @@ get-iterator@^1.0.2: resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" @@ -3919,6 +3981,13 @@ longest-streak@^2.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lru-cache@^7.14.1: version "7.14.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" @@ -3929,6 +3998,11 @@ lru-cache@~7.8.2: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.8.2.tgz#db4d3bbcc05b2e7a2ae063f57fdb42d8d45f1773" integrity sha512-tVtvt+EqoUgjtIPD3rXSJCSf5izSRJShgnzUeK59T+wxZ9LrFEP3GxhX/Mhf8Rl7kk4ngd4vZaV+5sEibhvQ+A== +luxon@^3.2.1: + version "3.4.3" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.3.tgz#8ddf0358a9492267ffec6a13675fbaab5551315d" + integrity sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg== + markdown-table@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" @@ -4204,6 +4278,27 @@ ms@2.1.3, 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.2: + 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.5.2: + version "1.9.9" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.9.9.tgz#ec71e37beb8729280847f683cb0a340eb35ce70f" + integrity sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A== + optionalDependencies: + msgpackr-extract "^3.0.2" + multer@^1.4.2: version "1.4.4" resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" @@ -4316,6 +4411,11 @@ node-fetch@^3.3.2: version "2.6.7" resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz#1b5d62978f2ed07b99444f64f0df39f960a6d34d" +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== + node-gyp-build@^4.3.0: version "4.6.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" @@ -4813,6 +4913,13 @@ semver@^5.7.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^7.5.2: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + semver@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -5215,7 +5322,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^8.3.2: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -5332,6 +5439,11 @@ yaeti@^0.0.6: resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== +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== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"