mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
revert settlement in federation modul
This commit is contained in:
parent
99017802cd
commit
d403087ed1
@ -17,6 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-server-express": "^2.25.2",
|
||||
"await-semaphore": "0.1.3",
|
||||
"class-validator": "^0.13.2",
|
||||
"cors": "2.8.5",
|
||||
"cross-env": "^7.0.3",
|
||||
|
||||
@ -2,10 +2,9 @@ import { registerEnumType } from 'type-graphql'
|
||||
|
||||
export enum PendingTransactionState {
|
||||
NEW = 1,
|
||||
WAIT_ON_PENDING = 2,
|
||||
PENDING = 3,
|
||||
WAIT_ON_CONFIRM = 4,
|
||||
CONFIRMED = 5,
|
||||
PENDING = 2,
|
||||
SETTLED = 3,
|
||||
REVERTED = 4,
|
||||
}
|
||||
|
||||
registerEnumType(PendingTransactionState, {
|
||||
|
||||
@ -14,6 +14,7 @@ import { fullName } from '@/graphql/util/fullName'
|
||||
import { settlePendingReceiveTransaction } from '../util/settlePendingReceiveTransaction'
|
||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from '../const/const'
|
||||
import { checkTradingLevel } from '@/graphql/util/checkTradingLevel'
|
||||
import { revertSettledReceiveTransaction } from '../util/revertSettledReceiveTransaction'
|
||||
|
||||
@Resolver()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@ -146,7 +147,7 @@ export class SendCoinsResolver {
|
||||
linkedUserGradidoID: userSenderIdentifier,
|
||||
})
|
||||
logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx)
|
||||
if (pendingTx && pendingTx.amount === amount) {
|
||||
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
|
||||
logger.debug('XCom: revertSendCoins matching pendingTX for remove...')
|
||||
try {
|
||||
await pendingTx.remove()
|
||||
@ -193,28 +194,6 @@ export class SendCoinsResolver {
|
||||
): Promise<boolean> {
|
||||
logger.debug(`settleSendCoins() via apiVersion=1_0 ...`)
|
||||
try {
|
||||
// first check if receiver community is correct
|
||||
const homeCom = await DbCommunity.findOneByOrFail({
|
||||
communityUuid: communityReceiverIdentifier,
|
||||
})
|
||||
/*
|
||||
if (!homeCom) {
|
||||
throw new LogError(
|
||||
`settleSendCoins with wrong communityReceiverIdentifier`,
|
||||
communityReceiverIdentifier,
|
||||
)
|
||||
}
|
||||
*/
|
||||
// second check if receiver user exists in this community
|
||||
const receiverUser = await DbUser.findOneByOrFail({ gradidoID: userReceiverIdentifier })
|
||||
/*
|
||||
if (!receiverUser) {
|
||||
throw new LogError(
|
||||
`settleSendCoins with unknown userReceiverIdentifier in the community=`,
|
||||
homeCom.name,
|
||||
)
|
||||
}
|
||||
*/
|
||||
const pendingTx = await DbPendingTransaction.findOneBy({
|
||||
userCommunityUuid: communityReceiverIdentifier,
|
||||
userGradidoID: userReceiverIdentifier,
|
||||
@ -227,12 +206,15 @@ export class SendCoinsResolver {
|
||||
logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx)
|
||||
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
|
||||
logger.debug('XCom: settleSendCoins matching pendingTX for settlement...')
|
||||
try {
|
||||
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
|
||||
logger.debug('XCom: settlePendingReceiveTransaction successfully...')
|
||||
} catch (err) {
|
||||
throw new LogError('Error in settlePendingReceiveTransaction: ', err)
|
||||
}
|
||||
|
||||
const homeCom = await DbCommunity.findOneByOrFail({
|
||||
communityUuid: communityReceiverIdentifier,
|
||||
})
|
||||
const receiverUser = await DbUser.findOneByOrFail({ gradidoID: userReceiverIdentifier })
|
||||
|
||||
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
|
||||
logger.debug(`XCom: settlePendingReceiveTransaction()-1_0... successfull`)
|
||||
return true
|
||||
} else {
|
||||
logger.debug(
|
||||
'XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...',
|
||||
@ -251,10 +233,83 @@ export class SendCoinsResolver {
|
||||
userSenderName,
|
||||
)
|
||||
}
|
||||
logger.debug(`settlePendingReceiveTransaction()-1_0... successfull`)
|
||||
return true
|
||||
} catch (err) {
|
||||
throw new LogError(`Error in settlePendingReceiveTransaction: `, err)
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
async revertSettledSendCoins(
|
||||
@Args()
|
||||
{
|
||||
communityReceiverIdentifier,
|
||||
userReceiverIdentifier,
|
||||
creationDate,
|
||||
amount,
|
||||
memo,
|
||||
communitySenderIdentifier,
|
||||
userSenderIdentifier,
|
||||
userSenderName,
|
||||
}: SendCoinsArgs,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`)
|
||||
// first check if receiver community is correct
|
||||
const homeCom = await DbCommunity.findOneBy({
|
||||
communityUuid: communityReceiverIdentifier,
|
||||
})
|
||||
if (!homeCom) {
|
||||
throw new LogError(
|
||||
`revertSettledSendCoins with wrong communityReceiverIdentifier`,
|
||||
communityReceiverIdentifier,
|
||||
)
|
||||
}
|
||||
// second check if receiver user exists in this community
|
||||
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
|
||||
if (!receiverUser) {
|
||||
throw new LogError(
|
||||
`revertSettledSendCoins with unknown userReceiverIdentifier in the community=`,
|
||||
homeCom.name,
|
||||
)
|
||||
}
|
||||
const pendingTx = await DbPendingTransaction.findOneBy({
|
||||
userCommunityUuid: communityReceiverIdentifier,
|
||||
userGradidoID: userReceiverIdentifier,
|
||||
state: PendingTransactionState.SETTLED,
|
||||
typeId: TransactionTypeId.RECEIVE,
|
||||
balanceDate: creationDate,
|
||||
linkedUserCommunityUuid: communitySenderIdentifier,
|
||||
linkedUserGradidoID: userSenderIdentifier,
|
||||
})
|
||||
logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx)
|
||||
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
|
||||
logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...')
|
||||
try {
|
||||
await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx)
|
||||
logger.debug('XCom: revertSettledSendCoins pendingTX successfully')
|
||||
} catch (err) {
|
||||
throw new LogError('Error in revertSettledSendCoins of receiver: ', err)
|
||||
}
|
||||
} else {
|
||||
logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...')
|
||||
throw new LogError(
|
||||
`Can't find in revertSettledSendCoins the pending receiver TX for args=`,
|
||||
communityReceiverIdentifier,
|
||||
userReceiverIdentifier,
|
||||
PendingTransactionState.SETTLED,
|
||||
TransactionTypeId.RECEIVE,
|
||||
creationDate,
|
||||
amount,
|
||||
memo,
|
||||
communitySenderIdentifier,
|
||||
userSenderIdentifier,
|
||||
userSenderName,
|
||||
)
|
||||
}
|
||||
logger.debug(`revertSendCoins()-1_0... successfull`)
|
||||
return true
|
||||
} catch (err) {
|
||||
throw new LogError(`Error in revertSendCoins: `, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,139 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { getConnection } from '@dbTools/typeorm'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction'
|
||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
|
||||
import { PendingTransactionState } from '../enum/PendingTransactionState'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { federationLogger as logger } from '@/server/logger'
|
||||
|
||||
import { getLastTransaction } from '@/graphql/util/getLastTransaction'
|
||||
import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK'
|
||||
|
||||
export async function revertSettledReceiveTransaction(
|
||||
homeCom: DbCommunity,
|
||||
receiverUser: DbUser,
|
||||
pendingTx: DbPendingTransaction,
|
||||
): Promise<boolean> {
|
||||
// TODO: synchronisation with TRANSACTION_LOCK of backend-modul necessary!!!
|
||||
// acquire lock
|
||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('REPEATABLE READ')
|
||||
logger.debug(`start Transaction for write-access...`)
|
||||
|
||||
try {
|
||||
logger.info('X-Com: revertSettledReceiveTransaction:', homeCom, receiverUser, pendingTx)
|
||||
|
||||
// ensure that no other pendingTx with the same sender or recipient exists
|
||||
const openSenderPendingTx = await DbPendingTransaction.count({
|
||||
where: [
|
||||
{ userGradidoID: pendingTx.userGradidoID, state: PendingTransactionState.NEW },
|
||||
{ userGradidoID: pendingTx.userGradidoID, state: PendingTransactionState.SETTLED },
|
||||
{
|
||||
linkedUserGradidoID: pendingTx.linkedUserGradidoID!,
|
||||
state: PendingTransactionState.NEW,
|
||||
},
|
||||
{
|
||||
linkedUserGradidoID: pendingTx.linkedUserGradidoID!,
|
||||
state: PendingTransactionState.SETTLED,
|
||||
},
|
||||
],
|
||||
})
|
||||
const openReceiverPendingTx = await DbPendingTransaction.count({
|
||||
where: [
|
||||
{ userGradidoID: pendingTx.linkedUserGradidoID!, state: PendingTransactionState.NEW },
|
||||
{ userGradidoID: pendingTx.linkedUserGradidoID!, state: PendingTransactionState.SETTLED },
|
||||
{ linkedUserGradidoID: pendingTx.userGradidoID, state: PendingTransactionState.NEW },
|
||||
{ linkedUserGradidoID: pendingTx.userGradidoID, state: PendingTransactionState.SETTLED },
|
||||
],
|
||||
})
|
||||
if (openSenderPendingTx > 1 || openReceiverPendingTx > 1) {
|
||||
throw new LogError('There are more than 1 pending Transactions for Sender and/or Recipient')
|
||||
}
|
||||
|
||||
const lastTransaction = await getLastTransaction(receiverUser.id)
|
||||
// now the last Tx must be the equivalant to the pendingTX
|
||||
if (
|
||||
lastTransaction &&
|
||||
lastTransaction.balance === pendingTx.balance &&
|
||||
lastTransaction.balanceDate === pendingTx.balanceDate &&
|
||||
lastTransaction.userGradidoID === pendingTx.userGradidoID &&
|
||||
lastTransaction.userName === pendingTx.userName &&
|
||||
lastTransaction.amount === pendingTx.amount &&
|
||||
lastTransaction.memo === pendingTx.memo &&
|
||||
lastTransaction.linkedUserGradidoID === pendingTx.linkedUserGradidoID &&
|
||||
lastTransaction.linkedUserName === pendingTx.linkedUserName
|
||||
) {
|
||||
await queryRunner.manager.remove(dbTransaction, lastTransaction)
|
||||
logger.debug(`X-Com: revert settlement receive Transaction removed:`, lastTransaction)
|
||||
// and mark the pendingTx in the pending_transactions table as reverted
|
||||
pendingTx.state = PendingTransactionState.REVERTED
|
||||
await queryRunner.manager.save(DbPendingTransaction, pendingTx)
|
||||
|
||||
await queryRunner.commitTransaction()
|
||||
logger.info(`commit revert settlement recipient Transaction successful...`)
|
||||
} else {
|
||||
// TODO: if the last TX is not equivelant to pendingTX, the transactions must be corrected in EXPERT-MODE
|
||||
throw new LogError(
|
||||
`X-Com: missmatching transaction order for revert settlement! lastTransation=${lastTransaction} != pendingTx=${pendingTx}`,
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount)
|
||||
|
||||
await EVENT_TRANSACTION_RECEIVE(
|
||||
recipient,
|
||||
sender,
|
||||
transactionReceive,
|
||||
transactionReceive.amount,
|
||||
)
|
||||
*/
|
||||
// trigger to send transaction via dlt-connector
|
||||
// void sendTransactionsToDltConnector()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new LogError('X-Com: revert settlement recipient Transaction was not successful', e)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
releaseLock()
|
||||
}
|
||||
/*
|
||||
void sendTransactionReceivedEmail({
|
||||
firstName: recipient.firstName,
|
||||
lastName: recipient.lastName,
|
||||
email: recipient.emailContact.email,
|
||||
language: recipient.language,
|
||||
senderFirstName: sender.firstName,
|
||||
senderLastName: sender.lastName,
|
||||
senderEmail: sender.emailContact.email,
|
||||
transactionAmount: amount,
|
||||
})
|
||||
if (transactionLink) {
|
||||
void sendTransactionLinkRedeemedEmail({
|
||||
firstName: sender.firstName,
|
||||
lastName: sender.lastName,
|
||||
email: sender.emailContact.email,
|
||||
language: sender.language,
|
||||
senderFirstName: recipient.firstName,
|
||||
senderLastName: recipient.lastName,
|
||||
senderEmail: recipient.emailContact.email,
|
||||
transactionAmount: amount,
|
||||
transactionMemo: memo,
|
||||
})
|
||||
}
|
||||
logger.info(`finished executeTransaction successfully`)
|
||||
} finally {
|
||||
releaseLock()
|
||||
}
|
||||
*/
|
||||
return true
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
/* eslint-disable new-cap */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { getConnection, In } from '@dbTools/typeorm'
|
||||
import { getConnection } from '@dbTools/typeorm'
|
||||
import { Community as DbCommunity } from '@entity/Community'
|
||||
import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction'
|
||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||
@ -22,12 +22,13 @@ export async function settlePendingReceiveTransaction(
|
||||
receiverUser: DbUser,
|
||||
pendingTx: DbPendingTransaction,
|
||||
): Promise<boolean> {
|
||||
// TODO: synchronisation with TRANSACTION_LOCK of backend-modul necessary!!!
|
||||
// acquire lock
|
||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('REPEATABLE READ')
|
||||
logger.debug(`open Transaction to write...`)
|
||||
logger.debug(`start Transaction for write-access...`)
|
||||
|
||||
try {
|
||||
logger.info('X-Com: settlePendingReceiveTransaction:', homeCom, receiverUser, pendingTx)
|
||||
@ -57,6 +58,7 @@ export async function settlePendingReceiveTransaction(
|
||||
)
|
||||
}
|
||||
|
||||
// transfer the pendingTx to the transactions table
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = pendingTx.typeId
|
||||
transactionReceive.memo = pendingTx.memo
|
||||
@ -86,85 +88,12 @@ export async function settlePendingReceiveTransaction(
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
logger.debug(`receive Transaction inserted: ${dbTransaction}`)
|
||||
|
||||
/*
|
||||
// validate amount
|
||||
const receivedCallDate = new Date()
|
||||
const sendBalance = await calculateBalance(
|
||||
sender.id,
|
||||
amount.mul(-1),
|
||||
receivedCallDate,
|
||||
transactionLink,
|
||||
)
|
||||
logger.debug(`calculated Balance=${sendBalance}`)
|
||||
if (!sendBalance) {
|
||||
throw new LogError('User has not enough GDD or amount is < 0', sendBalance)
|
||||
}
|
||||
// and mark the pendingTx in the pending_transactions table as settled
|
||||
pendingTx.state = PendingTransactionState.SETTLED
|
||||
await queryRunner.manager.save(DbPendingTransaction, pendingTx)
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('REPEATABLE READ')
|
||||
logger.debug(`open Transaction to write...`)
|
||||
try {
|
||||
// transaction
|
||||
const transactionSend = new dbTransaction()
|
||||
transactionSend.typeId = TransactionTypeId.SEND
|
||||
transactionSend.memo = memo
|
||||
transactionSend.userId = sender.id
|
||||
transactionSend.userGradidoID = sender.gradidoID
|
||||
transactionSend.userName = fullName(sender.firstName, sender.lastName)
|
||||
transactionSend.linkedUserId = recipient.id
|
||||
transactionSend.linkedUserGradidoID = recipient.gradidoID
|
||||
transactionSend.linkedUserName = fullName(recipient.firstName, recipient.lastName)
|
||||
transactionSend.amount = amount.mul(-1)
|
||||
transactionSend.balance = sendBalance.balance
|
||||
transactionSend.balanceDate = receivedCallDate
|
||||
transactionSend.decay = sendBalance.decay.decay
|
||||
transactionSend.decayStart = sendBalance.decay.start
|
||||
transactionSend.previous = sendBalance.lastTransactionId
|
||||
transactionSend.transactionLinkId = transactionLink ? transactionLink.id : null
|
||||
await queryRunner.manager.insert(dbTransaction, transactionSend)
|
||||
|
||||
logger.debug(`sendTransaction inserted: ${dbTransaction}`)
|
||||
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = TransactionTypeId.RECEIVE
|
||||
transactionReceive.memo = memo
|
||||
transactionReceive.userId = recipient.id
|
||||
transactionReceive.userGradidoID = recipient.gradidoID
|
||||
transactionReceive.userName = fullName(recipient.firstName, recipient.lastName)
|
||||
transactionReceive.linkedUserId = sender.id
|
||||
transactionReceive.linkedUserGradidoID = sender.gradidoID
|
||||
transactionReceive.linkedUserName = fullName(sender.firstName, sender.lastName)
|
||||
transactionReceive.amount = amount
|
||||
const receiveBalance = await calculateBalance(recipient.id, amount, receivedCallDate)
|
||||
transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount
|
||||
transactionReceive.balanceDate = receivedCallDate
|
||||
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
|
||||
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
|
||||
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
|
||||
transactionReceive.linkedTransactionId = transactionSend.id
|
||||
transactionReceive.transactionLinkId = transactionLink ? transactionLink.id : null
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
logger.debug(`receive Transaction inserted: ${dbTransaction}`)
|
||||
|
||||
// Save linked transaction id for send
|
||||
transactionSend.linkedTransactionId = transactionReceive.id
|
||||
await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend)
|
||||
logger.debug('send Transaction updated', transactionSend)
|
||||
|
||||
if (transactionLink) {
|
||||
logger.info('transactionLink', transactionLink)
|
||||
transactionLink.redeemedAt = receivedCallDate
|
||||
transactionLink.redeemedBy = recipient.id
|
||||
await queryRunner.manager.update(
|
||||
dbTransactionLink,
|
||||
{ id: transactionLink.id },
|
||||
transactionLink,
|
||||
)
|
||||
}
|
||||
*/
|
||||
await queryRunner.commitTransaction()
|
||||
logger.info(`commit Transaction successful...`)
|
||||
logger.info(`commit recipient Transaction successful...`)
|
||||
|
||||
/*
|
||||
await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount)
|
||||
@ -180,7 +109,7 @@ export async function settlePendingReceiveTransaction(
|
||||
// void sendTransactionsToDltConnector()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new LogError('Transaction was not successful', e)
|
||||
throw new LogError('X-Com: recipient Transaction was not successful', e)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
releaseLock()
|
||||
|
||||
@ -53,13 +53,17 @@
|
||||
// "@model/*": ["src/graphql/model/*"],
|
||||
"@repository/*": ["src/typeorm/repository/*"],
|
||||
"@test/*": ["test/*"],
|
||||
/* common */
|
||||
"@common/*": ["../common/src/*"],
|
||||
"@email/*": ["../common/scr/email/*"],
|
||||
"@event/*": ["../common/src/event/*"],
|
||||
/* external */
|
||||
"@typeorm/*": ["../backend/src/typeorm/*", "../../backend/src/typeorm/*"],
|
||||
"@dbTools/*": ["../database/src/*", "../../database/build/src/*"],
|
||||
"@entity/*": ["../database/entity/*", "../../database/build/entity/*"]
|
||||
},
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */
|
||||
"typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
|
||||
@ -1529,6 +1529,11 @@ available-typed-arrays@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
||||
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
|
||||
|
||||
await-semaphore@0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/await-semaphore/-/await-semaphore-0.1.3.tgz#2b88018cc8c28e06167ae1cdff02504f1f9688d3"
|
||||
integrity sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==
|
||||
|
||||
babel-jest@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user